diff --git a/bridge_ui/src/components/TokenSelectors/SolanaSourceTokenSelector.tsx b/bridge_ui/src/components/TokenSelectors/SolanaSourceTokenSelector.tsx index 711f38b1..6fdcdaab 100644 --- a/bridge_ui/src/components/TokenSelectors/SolanaSourceTokenSelector.tsx +++ b/bridge_ui/src/components/TokenSelectors/SolanaSourceTokenSelector.tsx @@ -163,7 +163,7 @@ export default function SolanaSourceTokenSelector( }} getOptionLabel={(option) => { const symbol = getSymbol(option); - return `${symbol ? symbol : "Unknown"} ( Account: ${shortenAddress( + return `${symbol ? symbol : "Unknown"} (Account: ${shortenAddress( option.publicKey )}, Mint: ${shortenAddress(option.mintKey)})`; }} diff --git a/bridge_ui/src/components/Transfer/Recovery.tsx b/bridge_ui/src/components/Transfer/Recovery.tsx index 2d76fb39..84bae94b 100644 --- a/bridge_ui/src/components/Transfer/Recovery.tsx +++ b/bridge_ui/src/components/Transfer/Recovery.tsx @@ -3,11 +3,14 @@ import { CHAIN_ID_BSC, CHAIN_ID_ETH, CHAIN_ID_SOLANA, + CHAIN_ID_TERRA, getEmitterAddressEth, getEmitterAddressSolana, + getEmitterAddressTerra, getSignedVAA, parseSequenceFromLogEth, parseSequenceFromLogSolana, + parseSequenceFromLogTerra, } from "@certusone/wormhole-sdk"; import { Box, @@ -26,6 +29,7 @@ import { import { Restore } from "@material-ui/icons"; 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 { useCallback, useEffect, useMemo, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; @@ -50,6 +54,8 @@ import { ETH_TOKEN_BRIDGE_ADDRESS, SOLANA_HOST, SOL_TOKEN_BRIDGE_ADDRESS, + TERRA_HOST, + TERRA_TOKEN_BRIDGE_ADDRESS, WORMHOLE_RPC_HOST, } from "../../utils/consts"; import KeyAndBalance from "../KeyAndBalance"; @@ -104,6 +110,31 @@ async function solana(tx: string) { return ""; } +async function terra(tx: string) { + try { + const lcd = new LCDClient(TERRA_HOST); + const info = await lcd.tx.txInfo(tx); + const sequence = parseSequenceFromLogTerra(info); + if (!sequence) { + throw new Error("Sequence not found"); + } + const emitterAddress = await getEmitterAddressTerra( + TERRA_TOKEN_BRIDGE_ADDRESS + ); + console.log(emitterAddress); + const { vaaBytes } = await getSignedVAA( + WORMHOLE_RPC_HOST, + CHAIN_ID_TERRA, + emitterAddress, + sequence + ); + return uint8ArrayToHex(vaaBytes); + } catch (e) { + console.error(e); + } + return ""; +} + // 0 u256 amount // 32 [u8; 32] token_address // 64 u16 token_chain @@ -153,6 +184,13 @@ function RecoveryDialogContent({ onClose }: { onClose: () => void }) { setRecoverySignedVAA(vaa); } })(); + } else if (recoverySourceChain === CHAIN_ID_TERRA) { + (async () => { + const vaa = await terra(recoverySourceTx); + if (!cancelled) { + setRecoverySignedVAA(vaa); + } + })(); } return () => { cancelled = true; @@ -236,9 +274,7 @@ function RecoveryDialogContent({ onClose }: { onClose: () => void }) { fullWidth margin="normal" > - {CHAINS.filter( - (x) => x.id === CHAIN_ID_ETH || x.id === CHAIN_ID_SOLANA - ).map(({ id, name }) => ( + {CHAINS.map(({ id, name }) => ( {name} diff --git a/bridge_ui/src/hooks/useHandleAttest.ts b/bridge_ui/src/hooks/useHandleAttest.ts index 61536224..febf51d8 100644 --- a/bridge_ui/src/hooks/useHandleAttest.ts +++ b/bridge_ui/src/hooks/useHandleAttest.ts @@ -71,6 +71,7 @@ async function eth( dispatch(setSignedVAAHex(uint8ArrayToHex(vaaBytes))); enqueueSnackbar("Fetched Signed VAA", { variant: "success" }); } catch (e) { + console.error(e); enqueueSnackbar(parseError(e), { variant: "error" }); dispatch(setIsSending(false)); } @@ -114,6 +115,7 @@ async function solana( dispatch(setSignedVAAHex(uint8ArrayToHex(vaaBytes))); enqueueSnackbar("Fetched Signed VAA", { variant: "success" }); } catch (e) { + console.error(e); enqueueSnackbar(parseError(e), { variant: "error" }); dispatch(setIsSending(false)); } @@ -127,14 +129,17 @@ async function terra( ) { dispatch(setIsSending(true)); try { - const infoMaybe = await attestFromTerra( + const result = await attestFromTerra( TERRA_TOKEN_BRIDGE_ADDRESS, wallet, asset ); - const info = await waitForTerraExecution(wallet, infoMaybe); + const info = await waitForTerraExecution(result); enqueueSnackbar("Transaction confirmed", { variant: "success" }); const sequence = parseSequenceFromLogTerra(info); + if (!sequence) { + throw new Error("Sequence not found"); + } const emitterAddress = await getEmitterAddressTerra( TERRA_TOKEN_BRIDGE_ADDRESS ); @@ -148,6 +153,7 @@ async function terra( enqueueSnackbar("Fetched Signed VAA", { variant: "success" }); } catch (e) { console.error(e); + enqueueSnackbar(parseError(e), { variant: "error" }); dispatch(setIsSending(false)); } } diff --git a/bridge_ui/src/hooks/useHandleTransfer.ts b/bridge_ui/src/hooks/useHandleTransfer.ts index 758983d6..359b45e7 100644 --- a/bridge_ui/src/hooks/useHandleTransfer.ts +++ b/bridge_ui/src/hooks/useHandleTransfer.ts @@ -49,7 +49,9 @@ import { TERRA_TOKEN_BRIDGE_ADDRESS, } from "../utils/consts"; import { getSignedVAAWithRetry } from "../utils/getSignedVAAWithRetry"; +import parseError from "../utils/parseError"; import { signSendAndConfirm } from "../utils/solana"; +import { waitForTerraExecution } from "../utils/terra"; import useTransferTargetAddressHex from "./useTransferTargetAddress"; async function eth( @@ -86,6 +88,7 @@ async function eth( enqueueSnackbar("Fetched Signed VAA", { variant: "success" }); } catch (e) { console.error(e); + enqueueSnackbar(parseError(e), { variant: "error" }); dispatch(setIsSending(false)); } } @@ -148,6 +151,7 @@ async function solana( enqueueSnackbar("Fetched Signed VAA", { variant: "success" }); } catch (e) { console.error(e); + enqueueSnackbar(parseError(e), { variant: "error" }); dispatch(setIsSending(false)); } } @@ -177,10 +181,15 @@ async function terra( msgs: [...msgs], memo: "Wormhole - Initiate Transfer", }); - enqueueSnackbar("Transaction confirmed", { variant: "success" }); console.log(result); - const sequence = parseSequenceFromLogTerra(result); + const info = await waitForTerraExecution(result); + console.log(info); + enqueueSnackbar("Transaction confirmed", { variant: "success" }); + const sequence = parseSequenceFromLogTerra(info); console.log(sequence); + if (!sequence) { + throw new Error("Sequence not found"); + } const emitterAddress = await getEmitterAddressTerra( TERRA_TOKEN_BRIDGE_ADDRESS ); @@ -195,6 +204,7 @@ async function terra( dispatch(setSignedVAAHex(uint8ArrayToHex(vaaBytes))); } catch (e) { console.error(e); + enqueueSnackbar(parseError(e), { variant: "error" }); dispatch(setIsSending(false)); } } diff --git a/bridge_ui/src/utils/getSignedVAAWithRetry.ts b/bridge_ui/src/utils/getSignedVAAWithRetry.ts index 01862519..58f97616 100644 --- a/bridge_ui/src/utils/getSignedVAAWithRetry.ts +++ b/bridge_ui/src/utils/getSignedVAAWithRetry.ts @@ -17,7 +17,7 @@ export async function getSignedVAAWithRetry( sequence ); } catch (e) { - console.log(e); + console.error(e); } } return result; diff --git a/bridge_ui/src/utils/terra.ts b/bridge_ui/src/utils/terra.ts index 0c66c2a5..effa1454 100644 --- a/bridge_ui/src/utils/terra.ts +++ b/bridge_ui/src/utils/terra.ts @@ -1,18 +1,17 @@ -import { - TxResult, - ConnectedWallet as TerraConnectedWallet, -} from "@terra-money/wallet-provider"; import { LCDClient } from "@terra-money/terra.js"; +import { TxResult } from "@terra-money/wallet-provider"; +import { TERRA_HOST } from "./consts"; -// TODO: Loop txInfo for timed out transactions. -// lcd.tx.txInfo(transaction.result.txhash); -export async function waitForTerraExecution( - wallet: TerraConnectedWallet, - transaction: TxResult -) { - new LCDClient({ - URL: wallet.network.lcd, - chainID: "columbus-4", - }); - return transaction; +export async function waitForTerraExecution(transaction: TxResult) { + const lcd = new LCDClient(TERRA_HOST); + let info; + while (!info) { + await new Promise((resolve) => setTimeout(resolve, 1000)); + try { + info = await lcd.tx.txInfo(transaction.result.txhash); + } catch (e) { + console.error(e); + } + } + return info; } diff --git a/sdk/js/src/bridge/parseSequenceFromLog.ts b/sdk/js/src/bridge/parseSequenceFromLog.ts index 5655e781..a43ee22f 100644 --- a/sdk/js/src/bridge/parseSequenceFromLog.ts +++ b/sdk/js/src/bridge/parseSequenceFromLog.ts @@ -1,6 +1,6 @@ import { TransactionResponse } from "@solana/web3.js"; +import { TxInfo } from "@terra-money/terra.js"; import { ContractReceipt } from "ethers"; -import { TxResult } from "@terra-money/wallet-provider"; import { Implementation__factory } from "../ethers-contracts"; export function parseSequenceFromLogEth( @@ -17,21 +17,21 @@ export function parseSequenceFromLogEth( return sequence.toString(); } -export function parseSequenceFromLogTerra(result: TxResult): string { +export function parseSequenceFromLogTerra(info: TxInfo): string { // Scan for the Sequence attribute in all the outputs of the transaction. // TODO: Make this not horrible. let sequence = ""; - const jsonLog = JSON.parse(result.result.raw_log); + const jsonLog = JSON.parse(info.raw_log); jsonLog.map((row: any) => { - row.events.map((event: any) => { - event.attributes.map((attribute: any) => { - if(attribute.key === "message.sequence") { - sequence = attribute.value; - } - }); + row.events.map((event: any) => { + event.attributes.map((attribute: any) => { + if (attribute.key === "message.sequence") { + sequence = attribute.value; + } }); + }); }); - console.log('Terra Sequence: ', sequence); + console.log("Terra Sequence: ", sequence); return sequence.toString(); }