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