From 350244e8e4303c00ddbe8c95e440efca76ad653d Mon Sep 17 00:00:00 2001 From: Chase Moran Date: Fri, 15 Oct 2021 12:30:49 -0400 Subject: [PATCH] bridge_ui: add bsc migration support Change-Id: Ia11a78be9318406ab72d7c9a58c6e74699379cff --- bridge_ui/src/App.js | 19 ++++++-- ...umQuickMigrate.tsx => EvmQuickMigrate.tsx} | 47 +++++++++---------- .../{EthereumWorkflow.tsx => EvmWorkflow.tsx} | 16 ++++--- bridge_ui/src/components/Migration/index.tsx | 17 +++---- .../EthereumSourceTokenSelector.tsx | 13 +++-- bridge_ui/src/components/Transfer/Source.tsx | 16 ++++++- bridge_ui/src/utils/consts.ts | 30 ++++++++++++ 7 files changed, 108 insertions(+), 50 deletions(-) rename bridge_ui/src/components/Migration/{EthereumQuickMigrate.tsx => EvmQuickMigrate.tsx} (89%) rename bridge_ui/src/components/Migration/{EthereumWorkflow.tsx => EvmWorkflow.tsx} (95%) diff --git a/bridge_ui/src/App.js b/bridge_ui/src/App.js index 563d7400..0bfa4f84 100644 --- a/bridge_ui/src/App.js +++ b/bridge_ui/src/App.js @@ -1,4 +1,8 @@ -import { CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk"; +import { + CHAIN_ID_BSC, + CHAIN_ID_ETH, + CHAIN_ID_SOLANA, +} from "@certusone/wormhole-sdk"; import { AppBar, Button, @@ -28,7 +32,7 @@ import Attest from "./components/Attest"; import Footer from "./components/Footer"; import Home from "./components/Home"; import Migration from "./components/Migration"; -import EthereumQuickMigrate from "./components/Migration/EthereumQuickMigrate"; +import EvmQuickMigrate from "./components/Migration/EvmQuickMigrate"; import NFT from "./components/NFT"; import NFTOriginVerifier from "./components/NFTOriginVerifier"; import Recovery from "./components/Recovery"; @@ -124,6 +128,7 @@ function App() { const isBeta = useBetaContext(); const isHomepage = useRouteMatch({ path: "/", exact: true }); const isStats = useRouteMatch({ path: "/stats", exact: true }); + const isMigrate = useRouteMatch({ path: "/migrate" }); const isOriginVerifier = useRouteMatch({ path: "/nft-origin-verifier", exact: true, @@ -244,7 +249,7 @@ function App() { ) : null}
- {isHomepage || isOriginVerifier || isStats ? null : ( + {isHomepage || isOriginVerifier || isStats || isMigrate ? null : ( + + + - + + + + diff --git a/bridge_ui/src/components/Migration/EthereumQuickMigrate.tsx b/bridge_ui/src/components/Migration/EvmQuickMigrate.tsx similarity index 89% rename from bridge_ui/src/components/Migration/EthereumQuickMigrate.tsx rename to bridge_ui/src/components/Migration/EvmQuickMigrate.tsx index 339772b3..c18191eb 100644 --- a/bridge_ui/src/components/Migration/EthereumQuickMigrate.tsx +++ b/bridge_ui/src/components/Migration/EvmQuickMigrate.tsx @@ -1,7 +1,4 @@ -import { - CHAIN_ID_ETH, - TokenImplementation__factory, -} from "@certusone/wormhole-sdk"; +import { ChainId, TokenImplementation__factory } from "@certusone/wormhole-sdk"; import { Signer } from "@ethersproject/abstract-signer"; import { BigNumber } from "@ethersproject/bignumber"; import { @@ -20,7 +17,7 @@ import { useEthereumProvider } from "../../contexts/EthereumProviderContext"; import useEthereumMigratorInformation from "../../hooks/useEthereumMigratorInformation"; import useIsWalletReady from "../../hooks/useIsWalletReady"; import { COLORS } from "../../muiTheme"; -import { ETH_MIGRATION_ASSET_MAP } from "../../utils/consts"; +import { CHAINS, getMigrationAssetMap } from "../../utils/consts"; import ButtonWithLoader from "../ButtonWithLoader"; import EthereumSignerKey from "../EthereumSignerKey"; import ShowTx from "../ShowTx"; @@ -89,10 +86,12 @@ export const compareWithDecimalOffset = ( } }; -function EthereumMigrationLineItem({ +function EvmMigrationLineItem({ + chainId, migratorAddress, onLoadComplete, }: { + chainId: ChainId; migratorAddress: string; onLoadComplete: () => void; }) { @@ -175,7 +174,7 @@ function EthereumMigrationLineItem({ Successfully migrated your tokens. They will become available once this transaction confirms. - +
); @@ -189,10 +188,7 @@ function EthereumMigrationLineItem({ {poolInfo.data.fromWalletBalance} - +
@@ -207,10 +203,7 @@ function EthereumMigrationLineItem({ {poolInfo.data.fromWalletBalance} - +
getMigrationAssetMap(chainId), [chainId]); const eligibleTokens = useMemo( - () => Array.from(ETH_MIGRATION_ASSET_MAP.keys()), - [] + () => Array.from(migrationMap.keys()), + [migrationMap] ); const [migrators, setMigrators] = useState(null); const [migratorsError, setMigratorsError] = useState(""); @@ -297,8 +291,7 @@ export default function EthereumQuickMigrate() { const migratorAddresses = []; for (const tokenAddress of result.keys()) { if (result.get(tokenAddress) && result.get(tokenAddress)?.gt(0)) { - const migratorAddress = - ETH_MIGRATION_ASSET_MAP.get(tokenAddress); + const migratorAddress = migrationMap.get(tokenAddress); if (migratorAddress) { migratorAddresses.push(migratorAddress); } @@ -323,15 +316,18 @@ export default function EthereumQuickMigrate() { cancelled = true; }; } - }, [isReady, signer, signerAddress, eligibleTokens]); + }, [isReady, signer, signerAddress, eligibleTokens, migrationMap]); const hasEligibleAssets = migrators && migrators.length > 0; + const chainName = CHAINS[chainId]?.name; const content = (
- This page allows you to convert certain wrapped tokens on Ethereum into - Wormhole V2 tokens. + {`This page allows you to convert certain wrapped tokens ${ + chainName ? "on " + chainName : "" + } into + Wormhole V2 tokens.`} {!isReady ? ( @@ -351,8 +347,9 @@ export default function EthereumQuickMigrate() {
{migrators?.map((address) => { return ( - diff --git a/bridge_ui/src/components/Migration/EthereumWorkflow.tsx b/bridge_ui/src/components/Migration/EvmWorkflow.tsx similarity index 95% rename from bridge_ui/src/components/Migration/EthereumWorkflow.tsx rename to bridge_ui/src/components/Migration/EvmWorkflow.tsx index ee9ef2d2..06a4ac56 100644 --- a/bridge_ui/src/components/Migration/EthereumWorkflow.tsx +++ b/bridge_ui/src/components/Migration/EvmWorkflow.tsx @@ -1,4 +1,4 @@ -import { CHAIN_ID_ETH } from "@certusone/wormhole-sdk"; +import { ChainId } from "@certusone/wormhole-sdk"; import { CircularProgress, makeStyles, @@ -27,15 +27,17 @@ const useStyles = makeStyles((theme) => ({ }, })); -export default function EthereumWorkflow({ +export default function EvmWorkflow({ + chainId, migratorAddress, }: { + chainId: ChainId; migratorAddress: string; }) { const classes = useStyles(); const { enqueueSnackbar } = useSnackbar(); const { signer, signerAddress } = useEthereumProvider(); - const { isReady } = useIsWalletReady(CHAIN_ID_ETH); + const { isReady } = useIsWalletReady(chainId); const [toggleRefresh, setToggleRefresh] = useState(false); const forceRefresh = useCallback( () => setToggleRefresh((prevState) => !prevState), @@ -144,20 +146,20 @@ export default function EthereumWorkflow({ //TODO tokenName const toTokenPretty = ( ); const fromTokenPretty = ( ); const poolPretty = ( - + ); const fatalError = poolInfo.error @@ -218,7 +220,7 @@ export default function EthereumWorkflow({ Successfully migrated your tokens! They will be available once this transaction confirms. - + ) : null} diff --git a/bridge_ui/src/components/Migration/index.tsx b/bridge_ui/src/components/Migration/index.tsx index d45968e0..d1e03412 100644 --- a/bridge_ui/src/components/Migration/index.tsx +++ b/bridge_ui/src/components/Migration/index.tsx @@ -7,10 +7,7 @@ import { } from "@material-ui/core"; import { PublicKey } from "@solana/web3.js"; import { RouteComponentProps } from "react-router-dom"; -import { - ETH_MIGRATION_ASSET_MAP, - MIGRATION_ASSET_MAP, -} from "../../utils/consts"; +import { getMigrationAssetMap, MIGRATION_ASSET_MAP } from "../../utils/consts"; import SolanaWorkflow from "./SolanaWorkflow"; import { withRouter } from "react-router"; import { COLORS } from "../../muiTheme"; @@ -18,8 +15,9 @@ import { ChainId, CHAIN_ID_ETH, CHAIN_ID_SOLANA, + CHAIN_ID_BSC, } from "@certusone/wormhole-sdk"; -import EthereumWorkflow from "./EthereumWorkflow"; +import EvmWorkflow from "./EvmWorkflow"; const useStyles = makeStyles(() => ({ mainPaper: { @@ -91,7 +89,8 @@ const SolanaRoot: React.FC = (props) => { const EthereumRoot: React.FC = (props) => { const legacyAsset: string = props.match.params.legacyAsset; - const targetPool = ETH_MIGRATION_ASSET_MAP.get(legacyAsset); + const assetMap = getMigrationAssetMap(props.chainId); + const targetPool = assetMap.get(legacyAsset); let content = null; if (!legacyAsset || !targetPool) { @@ -101,7 +100,9 @@ const EthereumRoot: React.FC = (props) => { ); } else { - content = ; + content = ( + + ); } return content; @@ -113,7 +114,7 @@ const MigrationRoot: React.FC = (props) => { if (props.chainId === CHAIN_ID_SOLANA) { content = ; - } else if (props.chainId === CHAIN_ID_ETH) { + } else if (props.chainId === CHAIN_ID_ETH || props.chainId === CHAIN_ID_BSC) { content = ; } diff --git a/bridge_ui/src/components/TokenSelectors/EthereumSourceTokenSelector.tsx b/bridge_ui/src/components/TokenSelectors/EthereumSourceTokenSelector.tsx index 162ec836..24bf74e1 100644 --- a/bridge_ui/src/components/TokenSelectors/EthereumSourceTokenSelector.tsx +++ b/bridge_ui/src/components/TokenSelectors/EthereumSourceTokenSelector.tsx @@ -13,7 +13,7 @@ import { CovalentData } from "../../hooks/useGetSourceParsedTokenAccounts"; import { DataWrapper } from "../../store/helpers"; import { ParsedTokenAccount } from "../../store/transferSlice"; import { - ETH_MIGRATION_ASSET_MAP, + getMigrationAssetMap, WORMHOLE_V1_ETH_ADDRESS, } from "../../utils/consts"; import { @@ -94,8 +94,9 @@ const isWormholev1 = (provider: any, address: string, chainId: ChainId) => { return connection.isWrappedAsset(address); }; -const isMigrationEligible = (address: string) => { - return !!ETH_MIGRATION_ASSET_MAP.get(address); +const isMigrationEligible = (chainId: ChainId, address: string) => { + const assetMap = getMigrationAssetMap(chainId); + return !!assetMap.get(address); }; type EthereumSourceTokenSelectorProps = { @@ -110,6 +111,7 @@ type EthereumSourceTokenSelectorProps = { }; const renderAccount = ( + chainId: ChainId, account: ParsedTokenAccount, covalentData: CovalentData | undefined, classes: any @@ -150,7 +152,9 @@ const renderAccount = (
); - return isMigrationEligible(account.mintKey) ? migrationRender : content; + return isMigrationEligible(chainId, account.mintKey) + ? migrationRender + : content; }; const renderNFTAccount = ( @@ -534,6 +538,7 @@ export default function EthereumSourceTokenSelector( classes ) : renderAccount( + chainId, option, covalent?.data?.find( (x) => x.contract_address === option.mintKey diff --git a/bridge_ui/src/components/Transfer/Source.tsx b/bridge_ui/src/components/Transfer/Source.tsx index 250d1357..fba9496e 100644 --- a/bridge_ui/src/components/Transfer/Source.tsx +++ b/bridge_ui/src/components/Transfer/Source.tsx @@ -1,4 +1,8 @@ -import { CHAIN_ID_ETH, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk"; +import { + CHAIN_ID_BSC, + CHAIN_ID_ETH, + CHAIN_ID_SOLANA, +} from "@certusone/wormhole-sdk"; import { Button, makeStyles, MenuItem, TextField } from "@material-ui/core"; import { useCallback } from "react"; import { useDispatch, useSelector } from "react-redux"; @@ -21,6 +25,7 @@ import { } from "../../store/transferSlice"; import { BETA_CHAINS, + BSC_MIGRATION_ASSET_MAP, CHAINS, ETH_MIGRATION_ASSET_MAP, MIGRATION_ASSET_MAP, @@ -56,7 +61,12 @@ function Source() { sourceChain === CHAIN_ID_ETH && !!parsedTokenAccount && !!ETH_MIGRATION_ASSET_MAP.get(parsedTokenAccount.mintKey); - const isMigrationAsset = isSolanaMigration || isEthereumMigration; + const isBscMigration = + sourceChain === CHAIN_ID_BSC && + !!parsedTokenAccount && + !!BSC_MIGRATION_ASSET_MAP.get(parsedTokenAccount.mintKey); + const isMigrationAsset = + isSolanaMigration || isEthereumMigration || isBscMigration; const uiAmountString = useSelector(selectTransferSourceBalanceString); const amount = useSelector(selectTransferAmount); const error = useSelector(selectTransferSourceError); @@ -70,6 +80,8 @@ function Source() { ); } else if (sourceChain === CHAIN_ID_ETH) { history.push(`/migrate/Ethereum/${parsedTokenAccount?.mintKey}`); + } else if (sourceChain === CHAIN_ID_BSC) { + history.push(`/migrate/BinanceSmartChain/${parsedTokenAccount?.mintKey}`); } }, [history, parsedTokenAccount, sourceChain]); const handleSourceChange = useCallback( diff --git a/bridge_ui/src/utils/consts.ts b/bridge_ui/src/utils/consts.ts index 6e9ffd37..521f8195 100644 --- a/bridge_ui/src/utils/consts.ts +++ b/bridge_ui/src/utils/consts.ts @@ -5,6 +5,7 @@ import { CHAIN_ID_SOLANA, CHAIN_ID_TERRA, } from "@certusone/wormhole-sdk"; +import { ChainID } from "@certusone/wormhole-sdk/lib/proto/publicrpc/v1/publicrpc"; import { clusterApiUrl } from "@solana/web3.js"; import { getAddress } from "ethers/lib/utils"; @@ -464,4 +465,33 @@ export const ETH_MIGRATION_ASSET_MAP = new Map( ] ); +export const BSC_MIGRATION_ASSET_MAP = new Map( + CLUSTER === "mainnet" + ? [] + : CLUSTER === "testnet" + ? [] + : [ + // [ + // "0x2D8BE6BF0baA74e0A907016679CaE9190e80dD0A", + // "0x4bf3A7dFB3b76b5B3E169ACE65f888A4b4FCa5Ee", + // ], + // [ + // "0x68d1569d1a6968f194b4d93f8d0b416c123a599f", + // "0xFcCeD5E997E7fb1D0594518D3eD57245bB8ed17E", + // ], + ] +); + +export const getMigrationAssetMap = (chainId: ChainID) => { + if (chainId === CHAIN_ID_BSC) { + return BSC_MIGRATION_ASSET_MAP; + } else if (chainId === CHAIN_ID_ETH) { + return ETH_MIGRATION_ASSET_MAP; + } else if (chainId === CHAIN_ID_SOLANA) { + return MIGRATION_ASSET_MAP; + } else { + return new Map(); + } +}; + export const SUPPORTED_TERRA_TOKENS = ["uluna", "uusd"];