Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: implement rainbowkit #71

Merged
merged 10 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22,555 changes: 14,331 additions & 8,224 deletions web/package-lock.json

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
"@keplr-wallet/stores": "^0.12.22",
"@keplr-wallet/types": "^0.12.22",
"@keplr-wallet/unit": "^0.12.22",
"@rainbow-me/rainbowkit": "^2.2.0",
"@tanstack/react-query": "^5.61.0",
"@types/node": "^16.18.56",
"@types/react-dom": "^18.3.1",
"@types/uuid": "^9.0.8",
Expand All @@ -27,6 +29,8 @@
"typescript": "^5.7.2",
"util": "^0.12.5",
"uuid": "^9.0.1",
"viem": "^2.21.49",
"wagmi": "^2.13.0",
"web-vitals": "^2.1.4"
},
"overrides": {
Expand All @@ -37,7 +41,7 @@
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --transformIgnorePatterns \"/node_modules/(?!(@cosmjs|axios)/)\"",
"test": "react-app-rewired test --transformIgnorePatterns \"/node_modules/(?!(@cosmjs|axios|@rainbow-me/rainbowkit|wagmi|@wagmi)/)\"",
"test-cov": "CI=true react-scripts test --coverage",
"eject": "react-scripts eject",
"format": "biome format --write .",
Expand All @@ -46,11 +50,7 @@
"lint-apply-unsafe": "biome lint --apply-unsafe ./src ./public"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"production": [">0.2%", "not dead", "not op_mini all"],
"development": [
"last 1 chrome version",
"last 1 firefox version",
Expand Down
Binary file removed web/public/astria-blocks.png
Binary file not shown.
Binary file removed web/public/icon-192x192.png
Binary file not shown.
Binary file removed web/public/icon-512x512.png
Binary file not shown.
42 changes: 29 additions & 13 deletions web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,41 @@ import type React from "react";
import { Route, Routes } from "react-router-dom";
import BridgePage from "pages/BridgePage/BridgePage";
import Layout from "pages/Layout";
import { ConfigContextProvider } from "config";
import { EthWalletContextProvider } from "features/EthWallet";
import { useConfig } from "config";
import { NotificationsContextProvider } from "features/Notifications";

import { getDefaultConfig, RainbowKitProvider } from "@rainbow-me/rainbowkit";
import { evmChainsToRainbowKitChains } from "./config/chainConfigs/types.ts";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { WagmiProvider } from "wagmi";

/**
* App component with routes.
*/
export default function App(): React.ReactElement {
const { evmChains } = useConfig();

const rainbowKitConfig = getDefaultConfig({
appName: "Flame Bridge",
projectId: "YOUR_PROJECT_ID", // TODO
chains: evmChainsToRainbowKitChains(evmChains),
});

const queryClient = new QueryClient();

return (
<ConfigContextProvider>
<NotificationsContextProvider>
<EthWalletContextProvider>
<Routes>
<Route element={<Layout />}>
<Route index element={<BridgePage />} />
</Route>
</Routes>
</EthWalletContextProvider>
</NotificationsContextProvider>
</ConfigContextProvider>
<NotificationsContextProvider>
<WagmiProvider config={rainbowKitConfig}>
<QueryClientProvider client={queryClient}>
<RainbowKitProvider>
<Routes>
<Route element={<Layout />}>
<Route index element={<BridgePage />} />
</Route>
</Routes>
</RainbowKitProvider>
</QueryClientProvider>
</WagmiProvider>
</NotificationsContextProvider>
);
}
14 changes: 8 additions & 6 deletions web/src/components/DepositCard/DepositCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ export default function DepositCard(): React.ReactElement {
Address: {fromAddress}
</p>
)}
{fromAddress && !isLoadingIbcBalance && (
{fromAddress && selectedIbcCurrency && !isLoadingIbcBalance && (
<p className="mt-2 has-text-grey-lighter has-text-weight-semibold">
Balance: {ibcBalance}
</p>
Expand Down Expand Up @@ -404,11 +404,13 @@ export default function DepositCard(): React.ReactElement {
<i className="fas fa-pen-to-square" />
</p>
)}
{evmAccountAddress && !isLoadingEvmBalance && (
<p className="mt-2 has-text-grey-lighter has-text-weight-semibold">
Balance: {evmBalance}
</p>
)}
{evmAccountAddress &&
selectedEvmChain &&
!isLoadingEvmBalance && (
<p className="mt-2 has-text-grey-lighter has-text-weight-semibold">
Balance: {evmBalance}
</p>
)}
{evmAccountAddress && isLoadingEvmBalance && (
<p className="mt-2 has-text-grey-lighter has-text-weight-semibold">
Balance: <i className="fas fa-spinner fa-pulse" />
Expand Down
19 changes: 11 additions & 8 deletions web/src/components/WithdrawCard/WithdrawCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ import AnimatedArrowSpacer from "components/AnimatedDownArrowSpacer/AnimatedDown
import Dropdown from "components/Dropdown/Dropdown";
import {
AddERC20ToWalletButton,
getAstriaWithdrawerService,
useEthWallet,
createWithdrawerService,
useEvmChainSelection,
} from "features/EthWallet";
import { useIbcChainSelection } from "features/KeplrWallet";
import { NotificationType, useNotifications } from "features/Notifications";
import { useConfig as useWagmiConfig } from "wagmi";

export default function WithdrawCard(): React.ReactElement {
const { evmChains, ibcChains } = useConfig();
const wagmiConfig = useWagmiConfig();
const { addNotification } = useNotifications();
const { provider } = useEthWallet();

const {
evmAccountAddress: fromAddress,
Expand Down Expand Up @@ -164,7 +164,7 @@ export default function WithdrawCard(): React.ReactElement {
}

const recipientAddress = recipientAddressOverride || ibcAccountAddress;
if (!provider || !fromAddress || !recipientAddress) {
if (!fromAddress || !recipientAddress) {
addNotification({
toastOpts: {
toastType: NotificationType.WARNING,
Expand Down Expand Up @@ -194,13 +194,16 @@ export default function WithdrawCard(): React.ReactElement {
selectedEvmCurrency.erc20ContractAddress ||
selectedEvmCurrency.nativeTokenWithdrawerContractAddress ||
"";
const withdrawerSvc = getAstriaWithdrawerService(
provider,
if (!contractAddress) {
throw new Error("No contract address found");
}
const withdrawerSvc = createWithdrawerService(
wagmiConfig,
contractAddress,
Boolean(selectedEvmCurrency.erc20ContractAddress),
);
await withdrawerSvc.withdrawToIbcChain(
fromAddress,
selectedEvmChain.chainId,
recipientAddress,
amount,
selectedEvmCurrency.coinDecimals,
Expand Down Expand Up @@ -325,7 +328,7 @@ export default function WithdrawCard(): React.ReactElement {
Address: {fromAddress}
</p>
)}
{fromAddress && !isLoadingEvmBalance && (
{fromAddress && selectedEvmCurrency && !isLoadingEvmBalance && (
<p className="mt-2 has-text-grey-lighter has-text-weight-semibold">
Balance: {evmBalance}
</p>
Expand Down
14 changes: 9 additions & 5 deletions web/src/config/chainConfigs/ChainConfigsDawn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ const NeutronChainInfo: IbcChainInfo = {
// Coin denomination to be displayed to the user.
coinDenom: "dTIA",
// Actual denom (i.e. uatom, uscrt) used by the blockchain.
coinMinimalDenom: "factory/neutron1tkr6mtll5e2z53ze2urnc3ld3tq3dam2rchezc5lg9c237ft66gqtw94jm/drop",
coinMinimalDenom:
"factory/neutron1tkr6mtll5e2z53ze2urnc3ld3tq3dam2rchezc5lg9c237ft66gqtw94jm/drop",
// # of decimal points to convert minimal denomination to user-facing denomination.
coinDecimals: 6,
// (Optional) Keplr can show the fiat value of the coin if a coingecko id is provided.
Expand Down Expand Up @@ -223,7 +224,8 @@ const NeutronChainInfo: IbcChainInfo = {
// Coin denomination to be displayed to the user.
coinDenom: "dTIA",
// Actual denom (i.e. uatom, uscrt) used by the blockchain.
coinMinimalDenom: "factory/neutron1tkr6mtll5e2z53ze2urnc3ld3tq3dam2rchezc5lg9c237ft66gqtw94jm/drop",
coinMinimalDenom:
"factory/neutron1tkr6mtll5e2z53ze2urnc3ld3tq3dam2rchezc5lg9c237ft66gqtw94jm/drop",
// # of decimal points to convert minimal denomination to user-facing denomination.
coinDecimals: 6,
// (Optional) Keplr can show the fiat value of the coin if a coingecko id is provided.
Expand All @@ -240,7 +242,8 @@ const NeutronChainInfo: IbcChainInfo = {
// Coin denomination to be displayed to the user.
coinDenom: "dTIA",
// Actual denom (i.e. nria, uscrt) used by the blockchain.
coinMinimalDenom: "factory/neutron1tkr6mtll5e2z53ze2urnc3ld3tq3dam2rchezc5lg9c237ft66gqtw94jm/drop",
coinMinimalDenom:
"factory/neutron1tkr6mtll5e2z53ze2urnc3ld3tq3dam2rchezc5lg9c237ft66gqtw94jm/drop",
// # of decimal points to convert minimal denomination to user-facing denomination.
coinDecimals: 6,
// (Optional) Keplr can show the fiat value of the coin if a coingecko id is provided.
Expand Down Expand Up @@ -290,12 +293,13 @@ const FlameChainInfo: EvmChainInfo = {
},
{
coinDenom: "dTIA",
coinMinimalDenom: "factory/neutron1tkr6mtll5e2z53ze2urnc3ld3tq3dam2rchezc5lg9c237ft66gqtw94jm/drop",
coinMinimalDenom:
"factory/neutron1tkr6mtll5e2z53ze2urnc3ld3tq3dam2rchezc5lg9c237ft66gqtw94jm/drop",
coinDecimals: 18,
erc20ContractAddress: "0x0F0C3207a9fE9B7e8AaE4bb83E865C91A13Fd8a7",
ibcWithdrawalFeeWei: "10000000000000000",
iconClass: "i-celestia",
}
},
],
iconClass: "i-flame",
};
Expand Down
4 changes: 2 additions & 2 deletions web/src/config/chainConfigs/ChainConfigsDusk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ const FlameChainInfo: EvmChainInfo = {
// address of erc20 contract on dusk-11
erc20ContractAddress: "0xa4f59B3E97EC22a2b949cB5b6E8Cd6135437E857",
// this value would only exist for native tokens
nativeTokenWithdrawerContractAddress: "",
// nativeTokenWithdrawerContractAddress: "",
ibcWithdrawalFeeWei: "10000000000000000",
iconClass: "i-noble",
},
Expand All @@ -213,7 +213,7 @@ const FlameChainInfo: EvmChainInfo = {
// NOTE - there is not actually a contract for this fakeTIA.
// just using this for testing the UI.
erc20ContractAddress: "0xFc83F6A786728F448481B7D7d5C0659A92a62C4d",
nativeTokenWithdrawerContractAddress: "",
// nativeTokenWithdrawerContractAddress: "",
ibcWithdrawalFeeWei: "10000000000000000",
iconClass: "i-celestia",
},
Expand Down
2 changes: 2 additions & 0 deletions web/src/config/chainConfigs/ChainConfigsLocal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ export const ibcChains: IbcChains = {
const FlameChainInfo: EvmChainInfo = {
chainId: 912559,
chainName: "Flame (local)",
rpcUrls: ["http://localhost:8545"], // TODO
currencies: [
{
coinDenom: "RIA",
Expand All @@ -204,6 +205,7 @@ const FlameChainInfo: EvmChainInfo = {
const FakeChainInfo: EvmChainInfo = {
chainId: 912559,
chainName: "FakeChain (local)",
rpcUrls: ["http://localhost:8545"], // TODO
currencies: [
{
coinDenom: "FAKE",
Expand Down
54 changes: 51 additions & 3 deletions web/src/config/chainConfigs/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ChainInfo } from "@keplr-wallet/types";
import type { Chain } from "@rainbow-me/rainbowkit";

/**
* Represents information about an IBC chain.
Expand Down Expand Up @@ -51,10 +52,57 @@ export type EvmChainInfo = {
chainId: number;
chainName: string;
currencies: EvmCurrency[];
rpcUrls?: string[];
rpcUrls: string[];
iconClass?: string;
blockExplorerUrl?: string;
};

/**
* Converts an EvmChainInfo object to a Chain object for use with RainbowKit.
* @param evmChain
*/
export function evmChainToRainbowKitChain(evmChain: EvmChainInfo): Chain {
const nativeCurrency = evmChain.currencies[0];
const chain: Chain = {
id: evmChain.chainId,
name: evmChain.chainName,
rpcUrls: {
default: { http: evmChain.rpcUrls },
},
nativeCurrency: {
name: nativeCurrency.coinDenom,
symbol: nativeCurrency.coinDenom,
decimals: nativeCurrency.coinDecimals,
},
};

if (evmChain.blockExplorerUrl) {
chain.blockExplorers = {
default: {
name: evmChain.chainName,
url: evmChain.blockExplorerUrl,
},
};
}

return chain;
}

/**
* Converts a map of EVM chains to an array of Chain objects for use with RainbowKit.
* @param evmChains
*/
export function evmChainsToRainbowKitChains(
evmChains: EvmChains,
): readonly [Chain, ...Chain[]] {
if (!evmChains || Object.keys(evmChains).length === 0) {
throw new Error("At least one chain must be provided");
}
return Object.values(evmChains).map((evmChain) =>
evmChainToRainbowKitChain(evmChain),
) as [Chain, ...Chain[]];
}

/**
* Represents information about a currency used in an EVM chain.
*/
Expand All @@ -63,9 +111,9 @@ export type EvmCurrency = {
coinMinimalDenom: string;
coinDecimals: number;
// contract address if this is a ERC20 token
erc20ContractAddress?: string;
erc20ContractAddress?: `0x${string}`;
// contract address if this a native token
nativeTokenWithdrawerContractAddress?: string;
nativeTokenWithdrawerContractAddress?: `0x${string}`;
// fee needed to pay for the ibc withdrawal, 18 decimals
ibcWithdrawalFeeWei: string;
iconClass?: string;
Expand Down
1 change: 1 addition & 0 deletions web/src/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ describe("Chain Configs", () => {
"Test EVM Chain": {
chainId: 1234,
chainName: "Test EVM Chain",
rpcUrls: ["https://rpc.test.com"],
currencies: [
{
coinDenom: "TEST",
Expand Down
Loading