sdk/js: Added getIsTransferCompleted
Change-Id: I034595b800ee2b881b9c2a9ab16d6e2a8e4a42e2
This commit is contained in:
parent
0888297b82
commit
70c173af75
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "@certusone/wormhole-sdk",
|
||||
"version": "0.0.8",
|
||||
"version": "0.1.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@certusone/wormhole-sdk",
|
||||
"version": "0.0.8",
|
||||
"version": "0.1.1",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@improbable-eng/grpc-web": "^0.14.0",
|
||||
|
@ -14,6 +14,7 @@
|
|||
"@solana/web3.js": "^1.24.0",
|
||||
"@terra-money/terra.js": "^2.0.14",
|
||||
"@terra-money/wallet-provider": "^2.2.0",
|
||||
"axios": "^0.24.0",
|
||||
"bech32": "^2.0.0",
|
||||
"js-base64": "^3.6.1",
|
||||
"protobufjs": "^6.11.2",
|
||||
|
@ -2370,6 +2371,14 @@
|
|||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@terra-money/terra.js/node_modules/axios": {
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@terra-money/wallet-provider": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@terra-money/wallet-provider/-/wallet-provider-2.2.0.tgz",
|
||||
|
@ -2948,11 +2957,11 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||
"version": "0.24.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
|
||||
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.10.0"
|
||||
"follow-redirects": "^1.14.4"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-jest": {
|
||||
|
@ -4201,9 +4210,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.2.tgz",
|
||||
"integrity": "sha512-yLR6WaE2lbF0x4K2qE2p9PEXKLDjUjnR/xmjS3wHAYxtlsI9MLLBJUZirAHKzUZDGLxje7w/cXR49WOUo4rbsA==",
|
||||
"version": "1.14.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
|
||||
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
|
@ -10224,6 +10233,16 @@
|
|||
"tmp": "^0.2.1",
|
||||
"utf-8-validate": "^5.0.5",
|
||||
"ws": "^7.4.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": {
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@terra-money/wallet-provider": {
|
||||
|
@ -10736,11 +10755,11 @@
|
|||
"dev": true
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||
"integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==",
|
||||
"version": "0.24.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
|
||||
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.10.0"
|
||||
"follow-redirects": "^1.14.4"
|
||||
}
|
||||
},
|
||||
"babel-jest": {
|
||||
|
@ -11741,9 +11760,9 @@
|
|||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.2.tgz",
|
||||
"integrity": "sha512-yLR6WaE2lbF0x4K2qE2p9PEXKLDjUjnR/xmjS3wHAYxtlsI9MLLBJUZirAHKzUZDGLxje7w/cXR49WOUo4rbsA=="
|
||||
"version": "1.14.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
|
||||
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA=="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "3.0.1",
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
"@solana/web3.js": "^1.24.0",
|
||||
"@terra-money/terra.js": "^2.0.14",
|
||||
"@terra-money/wallet-provider": "^2.2.0",
|
||||
"axios": "^0.24.0",
|
||||
"bech32": "^2.0.0",
|
||||
"js-base64": "^3.6.1",
|
||||
"protobufjs": "^6.11.2",
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import { importCoreWasm } from "../solana/wasm";
|
||||
import { ethers } from "ethers";
|
||||
import { uint8ArrayToHex } from "..";
|
||||
|
||||
export async function getSignedVAAHash(signedVAA: Uint8Array) {
|
||||
const { parse_vaa } = await importCoreWasm();
|
||||
const parsedVAA = parse_vaa(signedVAA);
|
||||
const body = [
|
||||
ethers.utils.defaultAbiCoder.encode(["uint32"], [parsedVAA.timestamp]).substring(2 + (64 - 8)),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint32"], [parsedVAA.nonce]).substring(2 + (64 - 8)),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint16"], [parsedVAA.emitter_chain]).substring(2 + (64 - 4)),
|
||||
ethers.utils.defaultAbiCoder.encode(["bytes32"], [parsedVAA.emitter_address]).substring(2),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint64"], [parsedVAA.sequence]).substring(2 + (64 - 16)),
|
||||
ethers.utils.defaultAbiCoder.encode(["uint8"], [parsedVAA.consistency_level]).substring(2 + (64 - 2)),
|
||||
uint8ArrayToHex(parsedVAA.payload),
|
||||
];
|
||||
return ethers.utils.solidityKeccak256(["bytes"], [ethers.utils.solidityKeccak256(["bytes"], ["0x" + body.join("")])]);
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
export * from "./getClaimAddress";
|
||||
export * from "./getEmitterAddress";
|
||||
export * from "./getSignedVAAHash";
|
||||
export * from "./parseSequenceFromLog";
|
||||
|
|
|
@ -20,6 +20,15 @@ export const SOLANA_CORE_BRIDGE_ADDRESS =
|
|||
"Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o";
|
||||
export const SOLANA_TOKEN_BRIDGE_ADDRESS =
|
||||
"B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE";
|
||||
export const TERRA_NODE_URL = "http://localhost:1317";
|
||||
export const TERRA_CHAIN_ID = "localterra";
|
||||
export const TERRA_GAS_PRICES_URL = "http://localhost:3060/v1/txs/gas_prices";
|
||||
export const TERRA_CORE_BRIDGE_ADDRESS =
|
||||
"terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5";
|
||||
export const TERRA_TOKEN_BRIDGE_ADDRESS =
|
||||
"terra10pyejy66429refv3g35g2t7am0was7ya7kz2a4";
|
||||
export const TERRA_PRIVATE_KEY =
|
||||
"notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius";
|
||||
export const TEST_ERC20 = "0x2D8BE6BF0baA74e0A907016679CaE9190e80dD0A";
|
||||
export const TEST_SOLANA_TOKEN = "2WDq7wSs9zYrpx2kbHDA4RUTRch2CCTP6ZWaH4GNfnQQ";
|
||||
export const WORMHOLE_RPC_HOSTS = ["http://localhost:7071"];
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import { parseUnits } from "@ethersproject/units";
|
||||
import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
|
||||
import { describe, jest, test } from "@jest/globals";
|
||||
import { describe, expect, jest, test } from "@jest/globals";
|
||||
import {
|
||||
ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||
Token,
|
||||
TOKEN_PROGRAM_ID,
|
||||
} from "@solana/spl-token";
|
||||
import { Connection, Keypair, PublicKey, Transaction } from "@solana/web3.js";
|
||||
import { LCDClient, MnemonicKey } from "@terra-money/terra.js";
|
||||
import axios from "axios";
|
||||
import { ethers } from "ethers";
|
||||
import {
|
||||
approveEth,
|
||||
|
@ -14,11 +16,16 @@ import {
|
|||
attestFromSolana,
|
||||
CHAIN_ID_ETH,
|
||||
CHAIN_ID_SOLANA,
|
||||
CHAIN_ID_TERRA,
|
||||
createWrappedOnEth,
|
||||
createWrappedOnSolana,
|
||||
createWrappedOnTerra,
|
||||
getEmitterAddressEth,
|
||||
getEmitterAddressSolana,
|
||||
getForeignAssetSolana,
|
||||
getIsTransferCompletedEth,
|
||||
getIsTransferCompletedSolana,
|
||||
getIsTransferCompletedTerra,
|
||||
hexToUint8Array,
|
||||
nativeToHexString,
|
||||
parseSequenceFromLogEth,
|
||||
|
@ -26,6 +33,7 @@ import {
|
|||
postVaaSolana,
|
||||
redeemOnEth,
|
||||
redeemOnSolana,
|
||||
redeemOnTerra,
|
||||
transferFromEth,
|
||||
transferFromSolana,
|
||||
} from "../..";
|
||||
|
@ -40,6 +48,11 @@ import {
|
|||
SOLANA_HOST,
|
||||
SOLANA_PRIVATE_KEY,
|
||||
SOLANA_TOKEN_BRIDGE_ADDRESS,
|
||||
TERRA_CHAIN_ID,
|
||||
TERRA_GAS_PRICES_URL,
|
||||
TERRA_NODE_URL,
|
||||
TERRA_PRIVATE_KEY,
|
||||
TERRA_TOKEN_BRIDGE_ADDRESS,
|
||||
TEST_ERC20,
|
||||
TEST_SOLANA_TOKEN,
|
||||
WORMHOLE_RPC_HOSTS,
|
||||
|
@ -51,7 +64,6 @@ jest.setTimeout(60000);
|
|||
|
||||
// TODO: setup keypair and provider/signer before, destroy provider after
|
||||
// TODO: make the repeatable (can't attest an already attested token)
|
||||
// TODO: add Terra
|
||||
|
||||
describe("Integration Tests", () => {
|
||||
describe("Ethereum to Solana", () => {
|
||||
|
@ -223,6 +235,13 @@ describe("Integration Tests", () => {
|
|||
payerAddress,
|
||||
Buffer.from(signedVAA)
|
||||
);
|
||||
expect(
|
||||
await getIsTransferCompletedSolana(
|
||||
SOLANA_TOKEN_BRIDGE_ADDRESS,
|
||||
signedVAA,
|
||||
connection
|
||||
)
|
||||
).toBe(false);
|
||||
// redeem tokens on solana
|
||||
const transaction = await redeemOnSolana(
|
||||
connection,
|
||||
|
@ -237,6 +256,13 @@ describe("Integration Tests", () => {
|
|||
transaction.serialize()
|
||||
);
|
||||
await connection.confirmTransaction(txid);
|
||||
expect(
|
||||
await getIsTransferCompletedSolana(
|
||||
SOLANA_TOKEN_BRIDGE_ADDRESS,
|
||||
signedVAA,
|
||||
connection
|
||||
)
|
||||
).toBe(true);
|
||||
provider.destroy();
|
||||
done();
|
||||
} catch (e) {
|
||||
|
@ -377,7 +403,21 @@ describe("Integration Tests", () => {
|
|||
transport: NodeHttpTransport(),
|
||||
}
|
||||
);
|
||||
expect(
|
||||
await getIsTransferCompletedEth(
|
||||
ETH_TOKEN_BRIDGE_ADDRESS,
|
||||
provider,
|
||||
signedVAA
|
||||
)
|
||||
).toBe(false);
|
||||
await redeemOnEth(ETH_TOKEN_BRIDGE_ADDRESS, signer, signedVAA);
|
||||
expect(
|
||||
await getIsTransferCompletedEth(
|
||||
ETH_TOKEN_BRIDGE_ADDRESS,
|
||||
provider,
|
||||
signedVAA
|
||||
)
|
||||
).toBe(true);
|
||||
provider.destroy();
|
||||
done();
|
||||
} catch (e) {
|
||||
|
@ -390,4 +430,178 @@ describe("Integration Tests", () => {
|
|||
});
|
||||
// TODO: it has increased balance
|
||||
});
|
||||
describe("Ethereum to Terra", () => {
|
||||
test("Attest Ethereum ERC-20 to Terra", (done) => {
|
||||
(async () => {
|
||||
try {
|
||||
// create a signer for Eth
|
||||
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
|
||||
const signer = new ethers.Wallet(ETH_PRIVATE_KEY, provider);
|
||||
// attest the test token
|
||||
const receipt = await attestFromEth(
|
||||
ETH_TOKEN_BRIDGE_ADDRESS,
|
||||
signer,
|
||||
TEST_ERC20
|
||||
);
|
||||
// get the sequence from the logs (needed to fetch the vaa)
|
||||
const sequence = parseSequenceFromLogEth(
|
||||
receipt,
|
||||
ETH_CORE_BRIDGE_ADDRESS
|
||||
);
|
||||
const emitterAddress = getEmitterAddressEth(ETH_TOKEN_BRIDGE_ADDRESS);
|
||||
// poll until the guardian(s) witness and sign the vaa
|
||||
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
|
||||
WORMHOLE_RPC_HOSTS,
|
||||
CHAIN_ID_ETH,
|
||||
emitterAddress,
|
||||
sequence,
|
||||
{
|
||||
transport: NodeHttpTransport(),
|
||||
}
|
||||
);
|
||||
const lcd = new LCDClient({
|
||||
URL: TERRA_NODE_URL,
|
||||
chainID: TERRA_CHAIN_ID,
|
||||
});
|
||||
const mk = new MnemonicKey({
|
||||
mnemonic: TERRA_PRIVATE_KEY,
|
||||
});
|
||||
const wallet = lcd.wallet(mk);
|
||||
const msg = await createWrappedOnTerra(
|
||||
TERRA_TOKEN_BRIDGE_ADDRESS,
|
||||
wallet.key.accAddress,
|
||||
signedVAA
|
||||
);
|
||||
const gasPrices = await axios
|
||||
.get(TERRA_GAS_PRICES_URL)
|
||||
.then((result) => result.data);
|
||||
const feeEstimate = await lcd.tx.estimateFee(
|
||||
wallet.key.accAddress,
|
||||
[msg],
|
||||
{
|
||||
feeDenoms: ["uluna"],
|
||||
gasPrices,
|
||||
}
|
||||
);
|
||||
const tx = await wallet.createAndSignTx({
|
||||
msgs: [msg],
|
||||
memo: "test",
|
||||
feeDenoms: ["uluna"],
|
||||
gasPrices,
|
||||
fee: feeEstimate,
|
||||
});
|
||||
await lcd.tx.broadcast(tx);
|
||||
provider.destroy();
|
||||
done();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
done(
|
||||
"An error occurred while trying to attest from Ethereum to Terra"
|
||||
);
|
||||
}
|
||||
})();
|
||||
});
|
||||
// TODO: it is attested
|
||||
test("Send Ethereum ERC-20 to Terra", (done) => {
|
||||
(async () => {
|
||||
try {
|
||||
// create a signer for Eth
|
||||
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
|
||||
const signer = new ethers.Wallet(ETH_PRIVATE_KEY, provider);
|
||||
const amount = parseUnits("1", 18);
|
||||
// approve the bridge to spend tokens
|
||||
await approveEth(
|
||||
ETH_TOKEN_BRIDGE_ADDRESS,
|
||||
TEST_ERC20,
|
||||
signer,
|
||||
amount
|
||||
);
|
||||
const lcd = new LCDClient({
|
||||
URL: TERRA_NODE_URL,
|
||||
chainID: TERRA_CHAIN_ID,
|
||||
});
|
||||
const mk = new MnemonicKey({
|
||||
mnemonic: TERRA_PRIVATE_KEY,
|
||||
});
|
||||
const wallet = lcd.wallet(mk);
|
||||
// transfer tokens
|
||||
const receipt = await transferFromEth(
|
||||
ETH_TOKEN_BRIDGE_ADDRESS,
|
||||
signer,
|
||||
TEST_ERC20,
|
||||
amount,
|
||||
CHAIN_ID_TERRA,
|
||||
hexToUint8Array(
|
||||
nativeToHexString(wallet.key.accAddress, CHAIN_ID_TERRA) || ""
|
||||
)
|
||||
);
|
||||
// get the sequence from the logs (needed to fetch the vaa)
|
||||
const sequence = parseSequenceFromLogEth(
|
||||
receipt,
|
||||
ETH_CORE_BRIDGE_ADDRESS
|
||||
);
|
||||
const emitterAddress = getEmitterAddressEth(ETH_TOKEN_BRIDGE_ADDRESS);
|
||||
// poll until the guardian(s) witness and sign the vaa
|
||||
const { vaaBytes: signedVAA } = await getSignedVAAWithRetry(
|
||||
WORMHOLE_RPC_HOSTS,
|
||||
CHAIN_ID_ETH,
|
||||
emitterAddress,
|
||||
sequence,
|
||||
{
|
||||
transport: NodeHttpTransport(),
|
||||
}
|
||||
);
|
||||
expect(
|
||||
await getIsTransferCompletedTerra(
|
||||
TERRA_TOKEN_BRIDGE_ADDRESS,
|
||||
signedVAA,
|
||||
wallet.key.accAddress,
|
||||
lcd,
|
||||
TERRA_GAS_PRICES_URL
|
||||
)
|
||||
).toBe(false);
|
||||
const msg = await redeemOnTerra(
|
||||
TERRA_TOKEN_BRIDGE_ADDRESS,
|
||||
wallet.key.accAddress,
|
||||
signedVAA
|
||||
);
|
||||
const gasPrices = await axios
|
||||
.get(TERRA_GAS_PRICES_URL)
|
||||
.then((result) => result.data);
|
||||
const feeEstimate = await lcd.tx.estimateFee(
|
||||
wallet.key.accAddress,
|
||||
[msg],
|
||||
{
|
||||
memo: "localhost",
|
||||
feeDenoms: ["uluna"],
|
||||
gasPrices,
|
||||
}
|
||||
);
|
||||
const tx = await wallet.createAndSignTx({
|
||||
msgs: [msg],
|
||||
memo: "localhost",
|
||||
feeDenoms: ["uluna"],
|
||||
gasPrices,
|
||||
fee: feeEstimate,
|
||||
});
|
||||
await lcd.tx.broadcast(tx);
|
||||
expect(
|
||||
await getIsTransferCompletedTerra(
|
||||
TERRA_TOKEN_BRIDGE_ADDRESS,
|
||||
signedVAA,
|
||||
wallet.key.accAddress,
|
||||
lcd,
|
||||
TERRA_GAS_PRICES_URL
|
||||
)
|
||||
).toBe(true);
|
||||
provider.destroy();
|
||||
done();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
done("An error occurred while trying to send from Ethereum to Terra");
|
||||
}
|
||||
})();
|
||||
});
|
||||
// TODO: it has increased balance
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
import { ethers } from "ethers";
|
||||
import { Bridge__factory } from "../ethers-contracts";
|
||||
import { getSignedVAAHash } from "../bridge";
|
||||
import { importCoreWasm } from "../solana/wasm";
|
||||
import { Connection, PublicKey } from "@solana/web3.js";
|
||||
import { LCDClient } from "@terra-money/terra.js";
|
||||
import axios from "axios";
|
||||
import { redeemOnTerra } from ".";
|
||||
|
||||
export async function getIsTransferCompletedEth(
|
||||
tokenBridgeAddress: string,
|
||||
provider: ethers.providers.Provider,
|
||||
signedVAA: Uint8Array
|
||||
) {
|
||||
const tokenBridge = Bridge__factory.connect(tokenBridgeAddress, provider);
|
||||
const signedVAAHash = await getSignedVAAHash(signedVAA);
|
||||
return await tokenBridge.isTransferCompleted(signedVAAHash);
|
||||
}
|
||||
|
||||
export async function getIsTransferCompletedTerra(
|
||||
tokenBridgeAddress: string,
|
||||
signedVAA: Uint8Array,
|
||||
walletAddress: string,
|
||||
client: LCDClient,
|
||||
gasPriceUrl: string
|
||||
) {
|
||||
const msg = await redeemOnTerra(tokenBridgeAddress, walletAddress, signedVAA);
|
||||
// TODO: remove gasPriceUrl and just use the client's gas prices
|
||||
const gasPrices = await axios.get(gasPriceUrl).then((result) => result.data);
|
||||
try {
|
||||
await client.tx.estimateFee(walletAddress, [msg], {
|
||||
memo: "already redeemed calculation",
|
||||
feeDenoms: ["uluna"],
|
||||
gasPrices,
|
||||
});
|
||||
} catch (e) {
|
||||
// redeemed if the VAA was already executed
|
||||
return e.response.data.error.includes("VaaAlreadyExecuted");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function getIsTransferCompletedSolana(
|
||||
tokenBridgeAddress: string,
|
||||
signedVAA: Uint8Array,
|
||||
connection: Connection
|
||||
) {
|
||||
const { claim_address } = await importCoreWasm();
|
||||
const claimAddress = await claim_address(tokenBridgeAddress, signedVAA);
|
||||
const claimInfo = await connection.getAccountInfo(
|
||||
new PublicKey(claimAddress),
|
||||
"confirmed"
|
||||
);
|
||||
return !!claimInfo;
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
export * from "./attest";
|
||||
export * from "./createWrapped";
|
||||
export * from "./getForeignAsset";
|
||||
export * from "./getIsTransferCompleted";
|
||||
export * from "./getIsWrappedAsset";
|
||||
export * from "./getOriginalAsset";
|
||||
export * from "./redeem";
|
||||
|
|
Loading…
Reference in New Issue