From 26b6ee22bb62c5fda9fdf4acb493312b28016b66 Mon Sep 17 00:00:00 2001 From: Evan Gray Date: Sat, 18 Sep 2021 13:04:43 -0400 Subject: [PATCH] bridge_ui: QoL improvements Change-Id: I4221ff5d7757e099b8dad55de6ca2765137e5e38 --- bridge_ui/src/components/ButtonWithLoader.tsx | 2 +- bridge_ui/src/components/NFT/Recovery.tsx | 23 ++- bridge_ui/src/components/NFT/Send.tsx | 2 +- bridge_ui/src/components/ShowTx.tsx | 11 +- .../src/components/Transfer/AddToMetamask.tsx | 69 +++++++++ .../src/components/Transfer/Recovery.tsx | 146 +++++++++++++----- .../src/components/Transfer/RedeemPreview.tsx | 2 + bridge_ui/src/components/Transfer/Send.tsx | 4 +- bridge_ui/src/components/Transfer/Source.tsx | 13 +- .../src/components/Transfer/SourcePreview.tsx | 22 ++- .../Transfer/TokenBlacklistWarning.tsx | 22 +++ bridge_ui/src/hooks/useHandleAttest.ts | 2 +- .../src/hooks/useTokenBlacklistWarning.ts | 11 +- bridge_ui/src/utils/consts.ts | 8 +- bridge_ui/src/utils/getSignedVAAWithRetry.ts | 10 +- 15 files changed, 268 insertions(+), 79 deletions(-) create mode 100644 bridge_ui/src/components/Transfer/AddToMetamask.tsx create mode 100644 bridge_ui/src/components/Transfer/TokenBlacklistWarning.tsx diff --git a/bridge_ui/src/components/ButtonWithLoader.tsx b/bridge_ui/src/components/ButtonWithLoader.tsx index be00a62e8..836f7cdf8 100644 --- a/bridge_ui/src/components/ButtonWithLoader.tsx +++ b/bridge_ui/src/components/ButtonWithLoader.tsx @@ -63,7 +63,7 @@ export default function ButtonWithLoader({ ) : null} {error ? ( - + {error} ) : null} diff --git a/bridge_ui/src/components/NFT/Recovery.tsx b/bridge_ui/src/components/NFT/Recovery.tsx index 40773507f..d4908bc42 100644 --- a/bridge_ui/src/components/NFT/Recovery.tsx +++ b/bridge_ui/src/components/NFT/Recovery.tsx @@ -5,7 +5,6 @@ import { CHAIN_ID_SOLANA, getEmitterAddressEth, getEmitterAddressSolana, - getSignedVAA, parseSequenceFromLogEth, parseSequenceFromLogSolana, } from "@certusone/wormhole-sdk"; @@ -31,11 +30,11 @@ import { BigNumber, ethers } from "ethers"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { useEthereumProvider } from "../../contexts/EthereumProviderContext"; +import { setSignedVAAHex, setStep, setTargetChain } from "../../store/nftSlice"; import { selectNFTSignedVAAHex, selectNFTSourceChain, } from "../../store/selectors"; -import { setSignedVAAHex, setStep, setTargetChain } from "../../store/nftSlice"; import { hexToNativeString, hexToUint8Array, @@ -49,9 +48,9 @@ import { SOL_NFT_BRIDGE_ADDRESS, WORMHOLE_RPC_HOSTS, } from "../../utils/consts"; -import KeyAndBalance from "../KeyAndBalance"; +import { getSignedVAAWithRetry } from "../../utils/getSignedVAAWithRetry"; import { METADATA_REPLACE } from "../../utils/metaplex"; -import { getNextRpcHost } from "../../utils/getSignedVAAWithRetry"; +import KeyAndBalance from "../KeyAndBalance"; const useStyles = makeStyles((theme) => ({ fab: { @@ -66,11 +65,11 @@ async function eth(provider: ethers.providers.Web3Provider, tx: string) { const receipt = await provider.getTransactionReceipt(tx); const sequence = parseSequenceFromLogEth(receipt, ETH_BRIDGE_ADDRESS); const emitterAddress = getEmitterAddressEth(ETH_NFT_BRIDGE_ADDRESS); - const { vaaBytes } = await getSignedVAA( - WORMHOLE_RPC_HOSTS[getNextRpcHost()], + const { vaaBytes } = await getSignedVAAWithRetry( CHAIN_ID_ETH, emitterAddress, - sequence.toString() + sequence.toString(), + WORMHOLE_RPC_HOSTS.length ); return uint8ArrayToHex(vaaBytes); } catch (e) { @@ -90,11 +89,11 @@ async function solana(tx: string) { const emitterAddress = await getEmitterAddressSolana( SOL_NFT_BRIDGE_ADDRESS ); - const { vaaBytes } = await getSignedVAA( - WORMHOLE_RPC_HOSTS[getNextRpcHost()], + const { vaaBytes } = await getSignedVAAWithRetry( CHAIN_ID_SOLANA, emitterAddress, - sequence.toString() + sequence.toString(), + WORMHOLE_RPC_HOSTS.length ); return uint8ArrayToHex(vaaBytes); } catch (e) { @@ -199,10 +198,10 @@ function RecoveryDialogContent({ setRecoverySourceChain(event.target.value); }, []); const handleSourceTxChange = useCallback((event) => { - setRecoverySourceTx(event.target.value); + setRecoverySourceTx(event.target.value.trim()); }, []); const handleSignedVAAChange = useCallback((event) => { - setRecoverySignedVAA(event.target.value); + setRecoverySignedVAA(event.target.value.trim()); }, []); useEffect(() => { let cancelled = false; diff --git a/bridge_ui/src/components/NFT/Send.tsx b/bridge_ui/src/components/NFT/Send.tsx index 7c9658963..72ae83b38 100644 --- a/bridge_ui/src/components/NFT/Send.tsx +++ b/bridge_ui/src/components/NFT/Send.tsx @@ -40,7 +40,7 @@ function Send() { Transfer the NFT to the Wormhole Token Bridge. - + This will initiate the transfer on {CHAINS_BY_ID[sourceChain].name} and wait for finalization. If you navigate away from this page before completing Step 4, you will have to perform the recovery workflow to diff --git a/bridge_ui/src/components/ShowTx.tsx b/bridge_ui/src/components/ShowTx.tsx index d1ad3cb56..06142c3d2 100644 --- a/bridge_ui/src/components/ShowTx.tsx +++ b/bridge_ui/src/components/ShowTx.tsx @@ -25,7 +25,10 @@ export default function ShowTx({ tx: Transaction; }) { const classes = useStyles(); - const showExplorerLink = CLUSTER === "testnet" || CLUSTER === "mainnet"; + const showExplorerLink = + CLUSTER === "testnet" || + CLUSTER === "mainnet" || + (CLUSTER === "devnet" && chainId === CHAIN_ID_SOLANA); const explorerAddress = chainId === CHAIN_ID_ETH ? `https://${CLUSTER === "testnet" ? "goerli." : ""}etherscan.io/tx/${ @@ -33,7 +36,11 @@ export default function ShowTx({ }` : chainId === CHAIN_ID_SOLANA ? `https://explorer.solana.com/tx/${tx?.id}${ - CLUSTER === "testnet" ? "?cluster=testnet" : "" + CLUSTER === "testnet" + ? "?cluster=testnet" + : CLUSTER === "devnet" + ? "?cluster=custom&customUrl=http%3A%2F%2Flocalhost%3A8899" + : "" }` : undefined; const explorerName = chainId === CHAIN_ID_ETH ? "Etherscan" : "Explorer"; diff --git a/bridge_ui/src/components/Transfer/AddToMetamask.tsx b/bridge_ui/src/components/Transfer/AddToMetamask.tsx new file mode 100644 index 000000000..cb3af2f04 --- /dev/null +++ b/bridge_ui/src/components/Transfer/AddToMetamask.tsx @@ -0,0 +1,69 @@ +import { CHAIN_ID_ETH } from "@certusone/wormhole-sdk"; +import { Button, makeStyles } from "@material-ui/core"; +import detectEthereumProvider from "@metamask/detect-provider"; +import { useCallback } from "react"; +import { useSelector } from "react-redux"; +import { useEthereumProvider } from "../../contexts/EthereumProviderContext"; +import { + selectTransferTargetAsset, + selectTransferTargetChain, +} from "../../store/selectors"; +import { + ethTokenToParsedTokenAccount, + getEthereumToken, +} from "../../utils/ethereum"; + +const useStyles = makeStyles((theme) => ({ + addButton: { + display: "block", + margin: `${theme.spacing(1)}px auto 0px`, + }, +})); + +export default function AddToMetamask() { + const classes = useStyles(); + const targetChain = useSelector(selectTransferTargetChain); + const targetAsset = useSelector(selectTransferTargetAsset); + const { provider, signerAddress } = useEthereumProvider(); + const handleClick = useCallback(() => { + if (provider && targetAsset && signerAddress) { + (async () => { + try { + const token = await getEthereumToken(targetAsset, provider); + const { symbol, decimals } = await ethTokenToParsedTokenAccount( + token, + signerAddress + ); + const ethereum = (await detectEthereumProvider()) as any; + ethereum.request({ + method: "wallet_watchAsset", + params: { + type: "ERC20", // In the future, other standards will be supported + options: { + address: targetAsset, // The address of the token contract + symbol, // A ticker symbol or shorthand, up to 5 characters + decimals, // The number of token decimals + // image: string; // A string url of the token logo + }, + }, + }); + } catch (e) { + console.error(e); + } + })(); + } + }, [provider, targetAsset, signerAddress]); + return provider && + signerAddress && + targetAsset && + targetChain === CHAIN_ID_ETH ? ( + + ) : null; +} diff --git a/bridge_ui/src/components/Transfer/Recovery.tsx b/bridge_ui/src/components/Transfer/Recovery.tsx index 63b988967..cb1d3aba9 100644 --- a/bridge_ui/src/components/Transfer/Recovery.tsx +++ b/bridge_ui/src/components/Transfer/Recovery.tsx @@ -7,7 +7,6 @@ import { getEmitterAddressEth, getEmitterAddressSolana, getEmitterAddressTerra, - getSignedVAA, parseSequenceFromLogEth, parseSequenceFromLogSolana, parseSequenceFromLogTerra, @@ -15,6 +14,7 @@ import { import { Box, Button, + CircularProgress, Dialog, DialogActions, DialogContent, @@ -32,6 +32,7 @@ import { Alert } from "@material-ui/lab"; import { Connection } from "@solana/web3.js"; import { LCDClient } from "@terra-money/terra.js"; import { BigNumber, ethers } from "ethers"; +import { useSnackbar } from "notistack"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import { useEthereumProvider } from "../../contexts/EthereumProviderContext"; @@ -59,7 +60,8 @@ import { TERRA_TOKEN_BRIDGE_ADDRESS, WORMHOLE_RPC_HOSTS, } from "../../utils/consts"; -import { getNextRpcHost } from "../../utils/getSignedVAAWithRetry"; +import { getSignedVAAWithRetry } from "../../utils/getSignedVAAWithRetry"; +import parseError from "../../utils/parseError"; import KeyAndBalance from "../KeyAndBalance"; const useStyles = makeStyles((theme) => ({ @@ -70,25 +72,30 @@ const useStyles = makeStyles((theme) => ({ }, })); -async function eth(provider: ethers.providers.Web3Provider, tx: string) { +async function eth( + provider: ethers.providers.Web3Provider, + tx: string, + enqueueSnackbar: any +) { try { const receipt = await provider.getTransactionReceipt(tx); const sequence = parseSequenceFromLogEth(receipt, ETH_BRIDGE_ADDRESS); const emitterAddress = getEmitterAddressEth(ETH_TOKEN_BRIDGE_ADDRESS); - const { vaaBytes } = await getSignedVAA( - WORMHOLE_RPC_HOSTS[getNextRpcHost()], + const { vaaBytes } = await getSignedVAAWithRetry( CHAIN_ID_ETH, emitterAddress, - sequence.toString() + sequence.toString(), + WORMHOLE_RPC_HOSTS.length ); - return uint8ArrayToHex(vaaBytes); + return { vaa: uint8ArrayToHex(vaaBytes), error: null }; } catch (e) { console.error(e); + enqueueSnackbar(parseError(e), { variant: "error" }); + return { vaa: null, error: parseError(e) }; } - return ""; } -async function solana(tx: string) { +async function solana(tx: string, enqueueSnackbar: any) { try { const connection = new Connection(SOLANA_HOST, "confirmed"); const info = await connection.getTransaction(tx); @@ -99,20 +106,21 @@ async function solana(tx: string) { const emitterAddress = await getEmitterAddressSolana( SOL_TOKEN_BRIDGE_ADDRESS ); - const { vaaBytes } = await getSignedVAA( - WORMHOLE_RPC_HOSTS[getNextRpcHost()], + const { vaaBytes } = await getSignedVAAWithRetry( CHAIN_ID_SOLANA, emitterAddress, - sequence.toString() + sequence.toString(), + WORMHOLE_RPC_HOSTS.length ); - return uint8ArrayToHex(vaaBytes); + return { vaa: uint8ArrayToHex(vaaBytes), error: null }; } catch (e) { console.error(e); + enqueueSnackbar(parseError(e), { variant: "error" }); + return { vaa: null, error: parseError(e) }; } - return ""; } -async function terra(tx: string) { +async function terra(tx: string, enqueueSnackbar: any) { try { const lcd = new LCDClient(TERRA_HOST); const info = await lcd.tx.txInfo(tx); @@ -123,17 +131,18 @@ async function terra(tx: string) { const emitterAddress = await getEmitterAddressTerra( TERRA_TOKEN_BRIDGE_ADDRESS ); - const { vaaBytes } = await getSignedVAA( - WORMHOLE_RPC_HOSTS[getNextRpcHost()], + const { vaaBytes } = await getSignedVAAWithRetry( CHAIN_ID_TERRA, emitterAddress, - sequence + sequence, + WORMHOLE_RPC_HOSTS.length ); - return uint8ArrayToHex(vaaBytes); + return { vaa: uint8ArrayToHex(vaaBytes), error: null }; } catch (e) { console.error(e); + enqueueSnackbar(parseError(e), { variant: "error" }); + return { vaa: null, error: parseError(e) }; } - return ""; } // 0 u256 amount @@ -159,12 +168,16 @@ function RecoveryDialogContent({ onClose: () => void; disabled: boolean; }) { + const { enqueueSnackbar } = useSnackbar(); const dispatch = useDispatch(); const { provider } = useEthereumProvider(); const currentSourceChain = useSelector(selectTransferSourceChain); const [recoverySourceChain, setRecoverySourceChain] = useState(currentSourceChain); const [recoverySourceTx, setRecoverySourceTx] = useState(""); + const [recoverySourceTxIsLoading, setRecoverySourceTxIsLoading] = + useState(false); + const [recoverySourceTxError, setRecoverySourceTxError] = useState(""); const currentSignedVAA = useSelector(selectTransferSignedVAAHex); const [recoverySignedVAA, setRecoverySignedVAA] = useState(currentSignedVAA); const [recoveryParsedVAA, setRecoveryParsedVAA] = useState(null); @@ -178,24 +191,55 @@ function RecoveryDialogContent({ if (recoverySourceTx) { let cancelled = false; if (recoverySourceChain === CHAIN_ID_ETH && provider) { + setRecoverySourceTxError(""); + setRecoverySourceTxIsLoading(true); (async () => { - const vaa = await eth(provider, recoverySourceTx); + const { vaa, error } = await eth( + provider, + recoverySourceTx, + enqueueSnackbar + ); if (!cancelled) { - setRecoverySignedVAA(vaa); + setRecoverySourceTxIsLoading(false); + if (vaa) { + setRecoverySignedVAA(vaa); + } + if (error) { + setRecoverySourceTxError(error); + } } })(); } else if (recoverySourceChain === CHAIN_ID_SOLANA) { + setRecoverySourceTxError(""); + setRecoverySourceTxIsLoading(true); (async () => { - const vaa = await solana(recoverySourceTx); + const { vaa, error } = await solana( + recoverySourceTx, + enqueueSnackbar + ); if (!cancelled) { - setRecoverySignedVAA(vaa); + setRecoverySourceTxIsLoading(false); + if (vaa) { + setRecoverySignedVAA(vaa); + } + if (error) { + setRecoverySourceTxError(error); + } } })(); } else if (recoverySourceChain === CHAIN_ID_TERRA) { + setRecoverySourceTxError(""); + setRecoverySourceTxIsLoading(true); (async () => { - const vaa = await terra(recoverySourceTx); + const { vaa, error } = await terra(recoverySourceTx, enqueueSnackbar); if (!cancelled) { - setRecoverySignedVAA(vaa); + setRecoverySourceTxIsLoading(false); + if (vaa) { + setRecoverySignedVAA(vaa); + } + if (error) { + setRecoverySourceTxError(error); + } } })(); } @@ -203,7 +247,7 @@ function RecoveryDialogContent({ cancelled = true; }; } - }, [recoverySourceChain, recoverySourceTx, provider]); + }, [recoverySourceChain, recoverySourceTx, provider, enqueueSnackbar]); useEffect(() => { setRecoverySignedVAA(currentSignedVAA); }, [currentSignedVAA]); @@ -212,10 +256,10 @@ function RecoveryDialogContent({ setRecoverySourceChain(event.target.value); }, []); const handleSourceTxChange = useCallback((event) => { - setRecoverySourceTx(event.target.value); + setRecoverySourceTx(event.target.value.trim()); }, []); const handleSignedVAAChange = useCallback((event) => { - setRecoverySignedVAA(event.target.value); + setRecoverySignedVAA(event.target.value.trim()); }, []); useEffect(() => { let cancelled = false; @@ -292,23 +336,45 @@ function RecoveryDialogContent({ ) : null} - - or + + + or + + + {recoverySourceTxIsLoading ? ( + + + + ) : null} - diff --git a/bridge_ui/src/components/Transfer/RedeemPreview.tsx b/bridge_ui/src/components/Transfer/RedeemPreview.tsx index 7885f83c3..4948c0883 100644 --- a/bridge_ui/src/components/Transfer/RedeemPreview.tsx +++ b/bridge_ui/src/components/Transfer/RedeemPreview.tsx @@ -8,6 +8,7 @@ import { import { reset } from "../../store/transferSlice"; import ButtonWithLoader from "../ButtonWithLoader"; import ShowTx from "../ShowTx"; +import AddToMetamask from "./AddToMetamask"; const useStyles = makeStyles((theme) => ({ description: { @@ -37,6 +38,7 @@ export default function RedeemPreview() { {explainerString} {redeemTx ? : null} + Transfer More Tokens! diff --git a/bridge_ui/src/components/Transfer/Send.tsx b/bridge_ui/src/components/Transfer/Send.tsx index 4fe2d00b0..b21a7c81b 100644 --- a/bridge_ui/src/components/Transfer/Send.tsx +++ b/bridge_ui/src/components/Transfer/Send.tsx @@ -21,6 +21,7 @@ import { import { CHAINS_BY_ID } from "../../utils/consts"; import ButtonWithLoader from "../ButtonWithLoader"; import KeyAndBalance from "../KeyAndBalance"; +import ShowTx from "../ShowTx"; import StepDescription from "../StepDescription"; import TransactionProgress from "../TransactionProgress"; import WaitingForWalletMessage from "./WaitingForWalletMessage"; @@ -111,7 +112,7 @@ function Send() { Transfer the tokens to the Wormhole Token Bridge. - + This will initiate the transfer on {CHAINS_BY_ID[sourceChain].name} and wait for finalization. If you navigate away from this page before completing Step 4, you will have to perform the recovery workflow to @@ -153,6 +154,7 @@ function Send() { )} + {transferTx ? : null} ({ transferField: { @@ -55,10 +55,6 @@ function Source({ const isSourceComplete = useSelector(selectTransferIsSourceComplete); const shouldLockFields = useSelector(selectTransferShouldLockFields); const { isReady, statusMessage } = useIsWalletReady(sourceChain); - const tokenBlacklistWarning = useTokenBlacklistWarning( - sourceChain, - parsedTokenAccount?.mintKey - ); const handleMigrationClick = useCallback(() => { parsedTokenAccount?.mintKey && history.push("/migrate/" + parsedTokenAccount.mintKey); @@ -124,6 +120,11 @@ function Source({ ) : ( <> + {hasParsedTokenAccount ? ( Next diff --git a/bridge_ui/src/components/Transfer/SourcePreview.tsx b/bridge_ui/src/components/Transfer/SourcePreview.tsx index c729c4043..1a52e7fdb 100644 --- a/bridge_ui/src/components/Transfer/SourcePreview.tsx +++ b/bridge_ui/src/components/Transfer/SourcePreview.tsx @@ -7,6 +7,7 @@ import { } from "../../store/selectors"; import { CHAINS_BY_ID } from "../../utils/consts"; import { shortenAddress } from "../../utils/solana"; +import TokenBlacklistWarning from "./TokenBlacklistWarning"; const useStyles = makeStyles((theme) => ({ description: { @@ -35,12 +36,19 @@ export default function SourcePreview() { : "Step complete."; return ( - - {explainerString} - + <> + + {explainerString} + + + ); } diff --git a/bridge_ui/src/components/Transfer/TokenBlacklistWarning.tsx b/bridge_ui/src/components/Transfer/TokenBlacklistWarning.tsx new file mode 100644 index 000000000..2fba68454 --- /dev/null +++ b/bridge_ui/src/components/Transfer/TokenBlacklistWarning.tsx @@ -0,0 +1,22 @@ +import { ChainId } from "@certusone/wormhole-sdk"; +import { Alert } from "@material-ui/lab"; +import useTokenBlacklistWarning from "../../hooks/useTokenBlacklistWarning"; + +export default function TokenBlacklistWarning({ + sourceChain, + tokenAddress, + symbol, +}: { + sourceChain: ChainId; + tokenAddress: string | undefined; + symbol: string | undefined; +}) { + const tokenBlacklistWarning = useTokenBlacklistWarning( + sourceChain, + tokenAddress, + symbol + ); + return tokenBlacklistWarning ? ( + {tokenBlacklistWarning} + ) : null; +} diff --git a/bridge_ui/src/hooks/useHandleAttest.ts b/bridge_ui/src/hooks/useHandleAttest.ts index ab7325d42..d4eb74d9a 100644 --- a/bridge_ui/src/hooks/useHandleAttest.ts +++ b/bridge_ui/src/hooks/useHandleAttest.ts @@ -21,7 +21,7 @@ import { import { useSnackbar } from "notistack"; import { useCallback, useMemo } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { Signer } from "../../../sdk/js/node_modules/ethers/lib"; +import { Signer } from "ethers"; import { useEthereumProvider } from "../contexts/EthereumProviderContext"; import { useSolanaWallet } from "../contexts/SolanaWalletContext"; import { diff --git a/bridge_ui/src/hooks/useTokenBlacklistWarning.ts b/bridge_ui/src/hooks/useTokenBlacklistWarning.ts index ad5e34560..6bd01c718 100644 --- a/bridge_ui/src/hooks/useTokenBlacklistWarning.ts +++ b/bridge_ui/src/hooks/useTokenBlacklistWarning.ts @@ -11,7 +11,8 @@ import { export default function useTokenBlacklistWarning( chainId: ChainId, - tokenAddress: string | undefined + tokenAddress: string | undefined, + symbol: string | undefined ) { return useMemo( () => @@ -20,8 +21,12 @@ export default function useTokenBlacklistWarning( SOLANA_TOKENS_THAT_EXIST_ELSEWHERE.includes(tokenAddress)) || (chainId === CHAIN_ID_ETH && ETH_TOKENS_THAT_EXIST_ELSEWHERE.includes(tokenAddress))) - ? "This token exists on multiple chains! Bridging the token via Wormhole will produce a wrapped version which might have no liquidity on the target chain." + ? `Bridging ${ + symbol ? symbol : "the token" + } via Wormhole will not produce native ${ + symbol ? symbol : "assets" + }. It will produce a wrapped version which might have no liquidity or utility on the target chain.` : undefined, - [chainId, tokenAddress] + [chainId, tokenAddress, symbol] ); } diff --git a/bridge_ui/src/utils/consts.ts b/bridge_ui/src/utils/consts.ts index 8a6b1a3bd..4622f2dca 100644 --- a/bridge_ui/src/utils/consts.ts +++ b/bridge_ui/src/utils/consts.ts @@ -197,11 +197,12 @@ export const SOLANA_TOKENS_THAT_EXIST_ELSEWHERE = [ "ArUkYE2XDKzqy77PRRGjo4wREWwqk6RXTfM9NeqzPvjU", // renDOGE "E99CQ2gFMmbiyK2bwiaFNWUUmwz4r8k2CVEFxwuvQ7ue", // renZEC "De2bU64vsXKU9jq4bCjeDxNRGPn8nr3euaTK8jBYmD3J", // renFIL + "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", // USDT ]; export const ETH_TOKENS_THAT_EXIST_ELSEWHERE = [ - getAddress("0x476c5E26a75bd202a9683ffD34359C0CC15be0fF"), // SRM - getAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), // USDC - getAddress("0x818fc6c2ec5986bc6e2cbf00939d90556ab12ce5"), // KIN + getAddress("0x476c5E26a75bd202a9683ffD34359C0CC15be0fF"), // SRM + getAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"), // USDC + getAddress("0x818fc6c2ec5986bc6e2cbf00939d90556ab12ce5"), // KIN getAddress("0xeb4c2781e4eba804ce9a9803c67d0893436bb27d"), // renBTC getAddress("0x52d87F22192131636F93c5AB18d0127Ea52CB641"), // renLUNA getAddress("0x459086f2376525bdceba5bdda135e4e9d3fef5bf"), // renBCH @@ -209,6 +210,7 @@ export const ETH_TOKENS_THAT_EXIST_ELSEWHERE = [ getAddress("0x3832d2F059E55934220881F831bE501D180671A7"), // renDOGE getAddress("0x1c5db575e2ff833e46a2e9864c22f4b22e0b37c2"), // renZEC getAddress("0xD5147bc8e386d91Cc5DBE72099DAC6C9b99276F5"), // renFIL + getAddress("0xdac17f958d2ee523a2206206994597c13d831ec7"), // USDT ]; export const MIGRATION_PROGRAM_ADDRESS = diff --git a/bridge_ui/src/utils/getSignedVAAWithRetry.ts b/bridge_ui/src/utils/getSignedVAAWithRetry.ts index 11394d944..e3e85fabb 100644 --- a/bridge_ui/src/utils/getSignedVAAWithRetry.ts +++ b/bridge_ui/src/utils/getSignedVAAWithRetry.ts @@ -9,10 +9,13 @@ export const getNextRpcHost = () => export async function getSignedVAAWithRetry( emitterChain: ChainId, emitterAddress: string, - sequence: string + sequence: string, + retryAttempts?: number ) { let result; + let attempts = 0; while (!result) { + attempts++; await new Promise((resolve) => setTimeout(resolve, 1000)); try { result = await getSignedVAA( @@ -22,7 +25,10 @@ export async function getSignedVAAWithRetry( sequence ); } catch (e) { - console.log(e); + console.log(`Attempt ${attempts}: `, e); + if (retryAttempts !== undefined && attempts > retryAttempts) { + throw e; + } } } return result;