diff --git a/bridge_ui/src/components/Attest/Source.tsx b/bridge_ui/src/components/Attest/Source.tsx index 519d7c21..b82de2e6 100644 --- a/bridge_ui/src/components/Attest/Source.tsx +++ b/bridge_ui/src/components/Attest/Source.tsx @@ -1,7 +1,6 @@ -import { makeStyles, MenuItem, TextField } from "@material-ui/core"; +import { makeStyles, TextField } from "@material-ui/core"; import { useCallback } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { useBetaContext } from "../../contexts/BetaContext"; import { incrementStep, setSourceAsset, @@ -13,8 +12,9 @@ import { selectAttestSourceAsset, selectAttestSourceChain, } from "../../store/selectors"; -import { BETA_CHAINS, CHAINS } from "../../utils/consts"; +import { CHAINS } from "../../utils/consts"; import ButtonWithLoader from "../ButtonWithLoader"; +import ChainSelect from "../ChainSelect"; import KeyAndBalance from "../KeyAndBalance"; import LowBalanceWarning from "../LowBalanceWarning"; @@ -27,7 +27,6 @@ const useStyles = makeStyles((theme) => ({ function Source() { const classes = useStyles(); const dispatch = useDispatch(); - const isBeta = useBetaContext(); const sourceChain = useSelector(selectAttestSourceChain); const sourceAsset = useSelector(selectAttestSourceAsset); const isSourceComplete = useSelector(selectAttestIsSourceComplete); @@ -49,22 +48,15 @@ function Source() { }, [dispatch]); return ( <> - - {CHAINS.filter(({ id }) => - isBeta ? true : !BETA_CHAINS.includes(id) - ).map(({ id, name }) => ( - - {name} - - ))} - + chains={CHAINS} + /> ({ function Target() { const classes = useStyles(); const dispatch = useDispatch(); - const isBeta = useBetaContext(); const sourceChain = useSelector(selectAttestSourceChain); const chains = useMemo( () => CHAINS.filter((c) => c.id !== sourceChain), @@ -47,22 +46,15 @@ function Target() { }, [dispatch]); return ( <> - - {chains - .filter(({ id }) => (isBeta ? true : !BETA_CHAINS.includes(id))) - .map(({ id, name }) => ( - - {name} - - ))} - + chains={chains} + /> diff --git a/bridge_ui/src/components/ChainSelect.tsx b/bridge_ui/src/components/ChainSelect.tsx new file mode 100644 index 00000000..37afa8cd --- /dev/null +++ b/bridge_ui/src/components/ChainSelect.tsx @@ -0,0 +1,56 @@ +import { + ListItemIcon, + ListItemText, + makeStyles, + MenuItem, + OutlinedTextFieldProps, + TextField, +} from "@material-ui/core"; +import clsx from "clsx"; +import { useMemo } from "react"; +import { useBetaContext } from "../contexts/BetaContext"; +import { BETA_CHAINS, ChainInfo } from "../utils/consts"; + +const useStyles = makeStyles((theme) => ({ + select: { + "& .MuiSelect-root": { + display: "flex", + alignItems: "center", + }, + }, + listItemIcon: { + minWidth: 40, + }, + icon: { + height: 24, + maxWidth: 24, + }, +})); + +const createChainMenuItem = ({ id, name, logo }: ChainInfo, classes: any) => ( + + + {name} + + {name} + +); + +interface ChainSelectProps extends OutlinedTextFieldProps { + chains: ChainInfo[]; +} + +export default function ChainSelect({ chains, ...rest }: ChainSelectProps) { + const classes = useStyles(); + const isBeta = useBetaContext(); + const filteredChains = useMemo( + () => + chains.filter(({ id }) => (isBeta ? true : !BETA_CHAINS.includes(id))), + [chains, isBeta] + ); + return ( + + {filteredChains.map((chain) => createChainMenuItem(chain, classes))} + + ); +} diff --git a/bridge_ui/src/components/NFT/Source.tsx b/bridge_ui/src/components/NFT/Source.tsx index 2e01c9e5..ba931fc2 100644 --- a/bridge_ui/src/components/NFT/Source.tsx +++ b/bridge_ui/src/components/NFT/Source.tsx @@ -1,10 +1,9 @@ -import { Button, makeStyles, MenuItem, TextField } from "@material-ui/core"; +import { Button, makeStyles } from "@material-ui/core"; import { VerifiedUser } from "@material-ui/icons"; import { Alert } from "@material-ui/lab"; import { useCallback } from "react"; import { useDispatch, useSelector } from "react-redux"; import { Link } from "react-router-dom"; -import { useBetaContext } from "../../contexts/BetaContext"; import useIsWalletReady from "../../hooks/useIsWalletReady"; import { incrementStep, setSourceChain } from "../../store/nftSlice"; import { @@ -14,9 +13,10 @@ import { selectNFTSourceChain, selectNFTSourceError, } from "../../store/selectors"; -import { BETA_CHAINS, CHAINS_WITH_NFT_SUPPORT } from "../../utils/consts"; +import { CHAINS_WITH_NFT_SUPPORT } from "../../utils/consts"; import { isEVMChain } from "../../utils/ethereum"; import ButtonWithLoader from "../ButtonWithLoader"; +import ChainSelect from "../ChainSelect"; import KeyAndBalance from "../KeyAndBalance"; import LowBalanceWarning from "../LowBalanceWarning"; import StepDescription from "../StepDescription"; @@ -31,7 +31,6 @@ const useStyles = makeStyles((theme) => ({ function Source() { const classes = useStyles(); const dispatch = useDispatch(); - const isBeta = useBetaContext(); const sourceChain = useSelector(selectNFTSourceChain); const uiAmountString = useSelector(selectNFTSourceBalanceString); const error = useSelector(selectNFTSourceError); @@ -66,22 +65,15 @@ function Source() { - - {CHAINS_WITH_NFT_SUPPORT.filter(({ id }) => - isBeta ? true : !BETA_CHAINS.includes(id) - ).map(({ id, name }) => ( - - {name} - - ))} - + chains={CHAINS_WITH_NFT_SUPPORT} + /> {isEVMChain(sourceChain) ? ( Only NFTs which implement ERC-721 are supported. diff --git a/bridge_ui/src/components/NFT/Target.tsx b/bridge_ui/src/components/NFT/Target.tsx index 4ed834dd..177f418c 100644 --- a/bridge_ui/src/components/NFT/Target.tsx +++ b/bridge_ui/src/components/NFT/Target.tsx @@ -3,13 +3,12 @@ import { hexToNativeString, hexToUint8Array, } from "@certusone/wormhole-sdk"; -import { makeStyles, MenuItem, TextField, Typography } from "@material-ui/core"; +import { makeStyles, TextField, Typography } from "@material-ui/core"; import { Alert } from "@material-ui/lab"; import { PublicKey } from "@solana/web3.js"; import { BigNumber, ethers } from "ethers"; import { useCallback, useMemo } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { useBetaContext } from "../../contexts/BetaContext"; import useIsWalletReady from "../../hooks/useIsWalletReady"; import useSyncTargetAddress from "../../hooks/useSyncTargetAddress"; import { EthGasEstimateSummary } from "../../hooks/useTransactionFees"; @@ -27,13 +26,10 @@ import { selectNFTTargetChain, selectNFTTargetError, } from "../../store/selectors"; -import { - BETA_CHAINS, - CHAINS_BY_ID, - CHAINS_WITH_NFT_SUPPORT, -} from "../../utils/consts"; +import { CHAINS_BY_ID, CHAINS_WITH_NFT_SUPPORT } from "../../utils/consts"; import { isEVMChain } from "../../utils/ethereum"; import ButtonWithLoader from "../ButtonWithLoader"; +import ChainSelect from "../ChainSelect"; import KeyAndBalance from "../KeyAndBalance"; import LowBalanceWarning from "../LowBalanceWarning"; import StepDescription from "../StepDescription"; @@ -51,7 +47,6 @@ const useStyles = makeStyles((theme) => ({ function Target() { const classes = useStyles(); const dispatch = useDispatch(); - const isBeta = useBetaContext(); const sourceChain = useSelector(selectNFTSourceChain); const chains = useMemo( () => CHAINS_WITH_NFT_SUPPORT.filter((c) => c.id !== sourceChain), @@ -94,21 +89,14 @@ function Target() { return ( <> Select a recipient chain and address. - - {chains - .filter(({ id }) => (isBeta ? true : !BETA_CHAINS.includes(id))) - .map(({ id, name }) => ( - - {name} - - ))} - + chains={chains} + /> ({ @@ -169,7 +168,6 @@ async function terra(tx: string, enqueueSnackbar: any) { export default function Recovery() { const classes = useStyles(); - const isBeta = useBetaContext(); const { push } = useHistory(); const { enqueueSnackbar } = useSnackbar(); const dispatch = useDispatch(); @@ -352,7 +350,7 @@ export default function Recovery() { Token NFT - - {(isNFT ? CHAINS_WITH_NFT_SUPPORT : CHAINS) - .filter(({ id }) => (isBeta ? true : !BETA_CHAINS.includes(id))) - .map(({ id, name }) => ( - - {name} - - ))} - + chains={isNFT ? CHAINS_WITH_NFT_SUPPORT : CHAINS} + /> {isEVMChain(recoverySourceChain) ? ( ) : null} diff --git a/bridge_ui/src/components/Transfer/Source.tsx b/bridge_ui/src/components/Transfer/Source.tsx index a677f6c4..56bfec27 100644 --- a/bridge_ui/src/components/Transfer/Source.tsx +++ b/bridge_ui/src/components/Transfer/Source.tsx @@ -4,11 +4,10 @@ import { CHAIN_ID_SOLANA, } from "@certusone/wormhole-sdk"; import { getAddress } from "@ethersproject/address"; -import { Button, makeStyles, MenuItem, TextField } from "@material-ui/core"; +import { Button, makeStyles, TextField } from "@material-ui/core"; import { useCallback } from "react"; import { useDispatch, useSelector } from "react-redux"; import { useHistory } from "react-router"; -import { useBetaContext } from "../../contexts/BetaContext"; import useIsWalletReady from "../../hooks/useIsWalletReady"; import { selectTransferAmount, @@ -25,13 +24,13 @@ import { setSourceChain, } from "../../store/transferSlice"; import { - BETA_CHAINS, BSC_MIGRATION_ASSET_MAP, CHAINS, ETH_MIGRATION_ASSET_MAP, MIGRATION_ASSET_MAP, } from "../../utils/consts"; import ButtonWithLoader from "../ButtonWithLoader"; +import ChainSelect from "../ChainSelect"; import KeyAndBalance from "../KeyAndBalance"; import LowBalanceWarning from "../LowBalanceWarning"; import StepDescription from "../StepDescription"; @@ -47,7 +46,6 @@ const useStyles = makeStyles((theme) => ({ function Source() { const classes = useStyles(); const dispatch = useDispatch(); - const isBeta = useBetaContext(); const history = useHistory(); const sourceChain = useSelector(selectTransferSourceChain); const parsedTokenAccount = useSelector( @@ -105,22 +103,15 @@ function Source() { Select tokens to send through the Wormhole Token Bridge. - - {CHAINS.filter(({ id }) => - isBeta ? true : !BETA_CHAINS.includes(id) - ).map(({ id, name }) => ( - - {name} - - ))} - + chains={CHAINS} + /> {isReady || uiAmountString ? (
diff --git a/bridge_ui/src/components/Transfer/Target.tsx b/bridge_ui/src/components/Transfer/Target.tsx index b1013095..ac64471a 100644 --- a/bridge_ui/src/components/Transfer/Target.tsx +++ b/bridge_ui/src/components/Transfer/Target.tsx @@ -1,9 +1,8 @@ import { CHAIN_ID_SOLANA, hexToNativeString } from "@certusone/wormhole-sdk"; -import { makeStyles, MenuItem, TextField, Typography } from "@material-ui/core"; +import { makeStyles, Typography } from "@material-ui/core"; import { Alert } from "@material-ui/lab"; import { useCallback, useMemo } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { useBetaContext } from "../../contexts/BetaContext"; import useIsWalletReady from "../../hooks/useIsWalletReady"; import useMetadata from "../../hooks/useMetadata"; import useSyncTargetAddress from "../../hooks/useSyncTargetAddress"; @@ -21,9 +20,10 @@ import { UNREGISTERED_ERROR_MESSAGE, } from "../../store/selectors"; import { incrementStep, setTargetChain } from "../../store/transferSlice"; -import { BETA_CHAINS, CHAINS, CHAINS_BY_ID } from "../../utils/consts"; +import { CHAINS, CHAINS_BY_ID } from "../../utils/consts"; import { isEVMChain } from "../../utils/ethereum"; import ButtonWithLoader from "../ButtonWithLoader"; +import ChainSelect from "../ChainSelect"; import KeyAndBalance from "../KeyAndBalance"; import LowBalanceWarning from "../LowBalanceWarning"; import SmartAddress from "../SmartAddress"; @@ -76,7 +76,6 @@ export const useTargetInfo = () => { function Target() { const classes = useStyles(); const dispatch = useDispatch(); - const isBeta = useBetaContext(); const sourceChain = useSelector(selectTransferSourceChain); const chains = useMemo( () => CHAINS.filter((c) => c.id !== sourceChain), @@ -115,22 +114,15 @@ function Target() { return ( <> Select a recipient chain and address. - - {chains - .filter(({ id }) => (isBeta ? true : !BETA_CHAINS.includes(id))) - .map(({ id, name }) => ( - - {name} - - ))} - + chains={chains} + /> {readableTargetAddress ? ( <> diff --git a/bridge_ui/src/utils/consts.ts b/bridge_ui/src/utils/consts.ts index c8e7360d..933487c3 100644 --- a/bridge_ui/src/utils/consts.ts +++ b/bridge_ui/src/utils/consts.ts @@ -7,6 +7,10 @@ import { } from "@certusone/wormhole-sdk"; import { clusterApiUrl } from "@solana/web3.js"; import { getAddress } from "ethers/lib/utils"; +import bscIcon from "../icons/bsc.svg"; +import ethIcon from "../icons/eth.svg"; +import solanaIcon from "../icons/solana.svg"; +import terraIcon from "../icons/terra.svg"; export type Cluster = "devnet" | "testnet" | "mainnet"; export const CLUSTER: Cluster = @@ -18,6 +22,7 @@ export const CLUSTER: Cluster = export interface ChainInfo { id: ChainId; name: string; + logo: string; } export const CHAINS = CLUSTER === "mainnet" @@ -25,18 +30,22 @@ export const CHAINS = { id: CHAIN_ID_BSC, name: "Binance Smart Chain", + logo: bscIcon, }, { id: CHAIN_ID_ETH, name: "Ethereum", + logo: ethIcon, }, { id: CHAIN_ID_SOLANA, name: "Solana", + logo: solanaIcon, }, { id: CHAIN_ID_TERRA, name: "Terra", + logo: terraIcon, }, ] : CLUSTER === "testnet" @@ -44,32 +53,34 @@ export const CHAINS = { id: CHAIN_ID_ETH, name: "Ethereum", + logo: ethIcon, }, { id: CHAIN_ID_SOLANA, name: "Solana", + logo: solanaIcon, }, - // { - // id: CHAIN_ID_TERRA, - // name: "Terra", - // }, ] : [ { id: CHAIN_ID_BSC, name: "Binance Smart Chain", + logo: bscIcon, }, { id: CHAIN_ID_ETH, name: "Ethereum", + logo: ethIcon, }, { id: CHAIN_ID_SOLANA, name: "Solana", + logo: solanaIcon, }, { id: CHAIN_ID_TERRA, name: "Terra", + logo: terraIcon, }, ]; export const BETA_CHAINS = CLUSTER === "mainnet" ? [CHAIN_ID_TERRA] : [];