bridge_ui: terra recovery

Change-Id: I0ae0da49a1d30f2f1a01b3dfd2cdf38f8667d6bf
This commit is contained in:
Evan Gray 2021-08-31 11:49:40 -04:00
parent ba9112ff14
commit 7b4a7ea17c
7 changed files with 85 additions and 34 deletions

View File

@ -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)})`;
}}

View File

@ -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 }) => (
<MenuItem key={id} value={id}>
{name}
</MenuItem>

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -17,7 +17,7 @@ export async function getSignedVAAWithRetry(
sequence
);
} catch (e) {
console.log(e);
console.error(e);
}
}
return result;

View File

@ -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;
}

View File

@ -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") {
if (attribute.key === "message.sequence") {
sequence = attribute.value;
}
});
});
});
console.log('Terra Sequence: ', sequence);
console.log("Terra Sequence: ", sequence);
return sequence.toString();
}