sdk/js: Terra2 integration tests
This commit is contained in:
parent
52e66964b0
commit
3028b81d63
|
@ -36,7 +36,7 @@ const interateToStandardTransactionCount = async () => {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = async function(callback) {
|
module.exports = async function (callback) {
|
||||||
try {
|
try {
|
||||||
const accounts = await web3.eth.getAccounts();
|
const accounts = await web3.eth.getAccounts();
|
||||||
|
|
||||||
|
@ -61,6 +61,10 @@ module.exports = async function(callback) {
|
||||||
from: accounts[0],
|
from: accounts[0],
|
||||||
gas: 1000000,
|
gas: 1000000,
|
||||||
});
|
});
|
||||||
|
await token.methods.mint(accounts[2], "1000000000000000000000").send({
|
||||||
|
from: accounts[0],
|
||||||
|
gas: 1000000,
|
||||||
|
});
|
||||||
|
|
||||||
const nftAddress = (
|
const nftAddress = (
|
||||||
await ERC721.new(
|
await ERC721.new(
|
||||||
|
|
|
@ -7,6 +7,8 @@ const ci = !!process.env.CI;
|
||||||
export const ETH_NODE_URL = ci ? "ws://eth-devnet:8545" : "ws://localhost:8545";
|
export const ETH_NODE_URL = ci ? "ws://eth-devnet:8545" : "ws://localhost:8545";
|
||||||
export const ETH_PRIVATE_KEY =
|
export const ETH_PRIVATE_KEY =
|
||||||
"0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d";
|
"0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d";
|
||||||
|
export const ETH_PRIVATE_KEY2 =
|
||||||
|
"0x6370fd033278c143179d81c5526140625662b8daa446c22ee2d73db3707e620c"; // account 2
|
||||||
export const ETH_CORE_BRIDGE_ADDRESS =
|
export const ETH_CORE_BRIDGE_ADDRESS =
|
||||||
"0xC89Ce4735882C9F0f0FE26686c53074E09B0D550";
|
"0xC89Ce4735882C9F0f0FE26686c53074E09B0D550";
|
||||||
export const ETH_TOKEN_BRIDGE_ADDRESS =
|
export const ETH_TOKEN_BRIDGE_ADDRESS =
|
||||||
|
@ -31,12 +33,19 @@ export const TERRA_CHAIN_ID = "localterra";
|
||||||
export const TERRA_GAS_PRICES_URL = ci
|
export const TERRA_GAS_PRICES_URL = ci
|
||||||
? "http://terra-fcd:3060/v1/txs/gas_prices"
|
? "http://terra-fcd:3060/v1/txs/gas_prices"
|
||||||
: "http://localhost:3060/v1/txs/gas_prices";
|
: "http://localhost:3060/v1/txs/gas_prices";
|
||||||
|
export const TERRA2_GAS_PRICES_URL = ci
|
||||||
|
? "http://terra2-fcd:3060/v1/txs/gas_prices"
|
||||||
|
: "http://localhost:3061/v1/txs/gas_prices";
|
||||||
export const TERRA_CORE_BRIDGE_ADDRESS =
|
export const TERRA_CORE_BRIDGE_ADDRESS =
|
||||||
"terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5";
|
"terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5";
|
||||||
export const TERRA_TOKEN_BRIDGE_ADDRESS =
|
export const TERRA_TOKEN_BRIDGE_ADDRESS =
|
||||||
"terra10pyejy66429refv3g35g2t7am0was7ya7kz2a4";
|
"terra10pyejy66429refv3g35g2t7am0was7ya7kz2a4";
|
||||||
|
export const TERRA2_TOKEN_BRIDGE_ADDRESS =
|
||||||
|
"terra1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrquka9l6";
|
||||||
export const TERRA_PRIVATE_KEY =
|
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";
|
"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 TERRA2_PRIVATE_KEY =
|
||||||
|
"symbol force gallery make bulk round subway violin worry mixture penalty kingdom boring survey tool fringe patrol sausage hard admit remember broken alien absorb"; // test3
|
||||||
export const TEST_ERC20 = "0x2D8BE6BF0baA74e0A907016679CaE9190e80dD0A";
|
export const TEST_ERC20 = "0x2D8BE6BF0baA74e0A907016679CaE9190e80dD0A";
|
||||||
export const TEST_SOLANA_TOKEN = "2WDq7wSs9zYrpx2kbHDA4RUTRch2CCTP6ZWaH4GNfnQQ";
|
export const TEST_SOLANA_TOKEN = "2WDq7wSs9zYrpx2kbHDA4RUTRch2CCTP6ZWaH4GNfnQQ";
|
||||||
export const WORMHOLE_RPC_HOSTS = ci
|
export const WORMHOLE_RPC_HOSTS = ci
|
||||||
|
|
|
@ -105,9 +105,9 @@ export async function transferFromEthToSolana(): Promise<string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function waitForTerraExecution(
|
export async function waitForTerraExecution(
|
||||||
transaction: string
|
transaction: string,
|
||||||
|
lcd: LCDClient
|
||||||
): Promise<TxInfo | undefined> {
|
): Promise<TxInfo | undefined> {
|
||||||
const lcd = new LCDClient(TERRA_HOST);
|
|
||||||
let done: boolean = false;
|
let done: boolean = false;
|
||||||
let info;
|
let info;
|
||||||
while (!done) {
|
while (!done) {
|
||||||
|
|
|
@ -1180,7 +1180,7 @@ describe("Integration Tests", () => {
|
||||||
fee: feeEstimate,
|
fee: feeEstimate,
|
||||||
});
|
});
|
||||||
const result = await lcd.tx.broadcast(executeTx);
|
const result = await lcd.tx.broadcast(executeTx);
|
||||||
const info = await waitForTerraExecution(result.txhash);
|
const info = await waitForTerraExecution(result.txhash, lcd);
|
||||||
if (!info) {
|
if (!info) {
|
||||||
throw new Error("info not found");
|
throw new Error("info not found");
|
||||||
}
|
}
|
||||||
|
@ -1316,7 +1316,7 @@ describe("Integration Tests", () => {
|
||||||
fee: feeEstimate,
|
fee: feeEstimate,
|
||||||
});
|
});
|
||||||
const result = await lcd.tx.broadcast(executeTx);
|
const result = await lcd.tx.broadcast(executeTx);
|
||||||
const info = await waitForTerraExecution(result.txhash);
|
const info = await waitForTerraExecution(result.txhash, lcd);
|
||||||
if (!info) {
|
if (!info) {
|
||||||
throw new Error("info not found");
|
throw new Error("info not found");
|
||||||
}
|
}
|
||||||
|
@ -1559,7 +1559,7 @@ describe("Integration Tests", () => {
|
||||||
fee: feeEstimate,
|
fee: feeEstimate,
|
||||||
});
|
});
|
||||||
let result = await lcd.tx.broadcast(executeTx);
|
let result = await lcd.tx.broadcast(executeTx);
|
||||||
let info = await waitForTerraExecution(result.txhash);
|
let info = await waitForTerraExecution(result.txhash, lcd);
|
||||||
if (!info) {
|
if (!info) {
|
||||||
throw new Error("info not found");
|
throw new Error("info not found");
|
||||||
}
|
}
|
||||||
|
@ -1678,7 +1678,7 @@ describe("Integration Tests", () => {
|
||||||
fee: feeEstimate,
|
fee: feeEstimate,
|
||||||
});
|
});
|
||||||
result = await lcd.tx.broadcast(executeTx);
|
result = await lcd.tx.broadcast(executeTx);
|
||||||
info = await waitForTerraExecution(result.txhash);
|
info = await waitForTerraExecution(result.txhash, lcd);
|
||||||
if (!info) {
|
if (!info) {
|
||||||
throw new Error("info not found");
|
throw new Error("info not found");
|
||||||
}
|
}
|
||||||
|
@ -2390,7 +2390,10 @@ describe("Integration Tests", () => {
|
||||||
fee: feeEstimate,
|
fee: feeEstimate,
|
||||||
});
|
});
|
||||||
const attestResult = await lcd.tx.broadcast(executeAttest);
|
const attestResult = await lcd.tx.broadcast(executeAttest);
|
||||||
const attestInfo = await waitForTerraExecution(attestResult.txhash);
|
const attestInfo = await waitForTerraExecution(
|
||||||
|
attestResult.txhash,
|
||||||
|
lcd
|
||||||
|
);
|
||||||
if (!attestInfo) {
|
if (!attestInfo) {
|
||||||
throw new Error("info not found");
|
throw new Error("info not found");
|
||||||
}
|
}
|
||||||
|
@ -2471,7 +2474,7 @@ describe("Integration Tests", () => {
|
||||||
fee: feeEstimate,
|
fee: feeEstimate,
|
||||||
});
|
});
|
||||||
const txResult = await lcd.tx.broadcast(executeTx);
|
const txResult = await lcd.tx.broadcast(executeTx);
|
||||||
const txInfo = await waitForTerraExecution(txResult.txhash);
|
const txInfo = await waitForTerraExecution(txResult.txhash, lcd);
|
||||||
if (!txInfo) {
|
if (!txInfo) {
|
||||||
throw new Error("info not found");
|
throw new Error("info not found");
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
import { beforeAll, afterAll, expect, test } from "@jest/globals";
|
||||||
|
import {
|
||||||
|
isTxError,
|
||||||
|
LCDClient,
|
||||||
|
MnemonicKey,
|
||||||
|
Msg,
|
||||||
|
Wallet,
|
||||||
|
} from "@terra-money/terra.js";
|
||||||
|
import { ethers } from "ethers";
|
||||||
|
import { parseUnits } from "ethers/lib/utils";
|
||||||
|
import {
|
||||||
|
createWrappedOnEth,
|
||||||
|
createWrappedOnTerra,
|
||||||
|
getEmitterAddressEth,
|
||||||
|
getEmitterAddressTerra,
|
||||||
|
getIsTransferCompletedTerra,
|
||||||
|
parseSequenceFromLogEth,
|
||||||
|
parseSequenceFromLogTerra,
|
||||||
|
redeemOnEth,
|
||||||
|
redeemOnTerra,
|
||||||
|
updateWrappedOnEth,
|
||||||
|
} from "../..";
|
||||||
|
import { tryNativeToUint8Array } from "../../utils";
|
||||||
|
import { CHAIN_ID_ETH, CHAIN_ID_TERRA2 } from "../../utils/consts";
|
||||||
|
import { attestFromEth, attestFromTerra } from "../attest";
|
||||||
|
import { approveEth, transferFromEth, transferFromTerra } from "../transfer";
|
||||||
|
import {
|
||||||
|
ETH_CORE_BRIDGE_ADDRESS,
|
||||||
|
ETH_NODE_URL,
|
||||||
|
ETH_PRIVATE_KEY2,
|
||||||
|
ETH_TOKEN_BRIDGE_ADDRESS,
|
||||||
|
TERRA2_GAS_PRICES_URL,
|
||||||
|
TERRA2_TOKEN_BRIDGE_ADDRESS,
|
||||||
|
TERRA2_PRIVATE_KEY,
|
||||||
|
TEST_ERC20,
|
||||||
|
} from "./consts";
|
||||||
|
import { getSignedVAABySequence, waitForTerraExecution } from "./helpers";
|
||||||
|
|
||||||
|
const lcd = new LCDClient({
|
||||||
|
URL: !!process.env.CI ? "http://terra2-terrad:1317" : "http://localhost:1318",
|
||||||
|
chainID: "localterra",
|
||||||
|
});
|
||||||
|
const terraWallet = lcd.wallet(
|
||||||
|
new MnemonicKey({ mnemonic: TERRA2_PRIVATE_KEY })
|
||||||
|
);
|
||||||
|
const terraWalletAddress = terraWallet.key.accAddress;
|
||||||
|
|
||||||
|
const provider = new ethers.providers.WebSocketProvider(ETH_NODE_URL);
|
||||||
|
const signer = new ethers.Wallet(ETH_PRIVATE_KEY2, provider);
|
||||||
|
const ethEmitterAddress = getEmitterAddressEth(ETH_TOKEN_BRIDGE_ADDRESS);
|
||||||
|
const ethTransferAmount = parseUnits("1", 18);
|
||||||
|
|
||||||
|
let ethWalletAddress: string;
|
||||||
|
let terraEmitterAddress: string;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
ethWalletAddress = await signer.getAddress();
|
||||||
|
terraEmitterAddress = await getEmitterAddressTerra(
|
||||||
|
TERRA2_TOKEN_BRIDGE_ADDRESS
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
provider.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
const terraBroadcastAndWaitForExecution = async (
|
||||||
|
msgs: Msg[],
|
||||||
|
wallet: Wallet
|
||||||
|
) => {
|
||||||
|
const tx = await wallet.createAndSignTx({
|
||||||
|
msgs,
|
||||||
|
});
|
||||||
|
const txResult = await lcd.tx.broadcast(tx);
|
||||||
|
if (isTxError(txResult)) {
|
||||||
|
throw new Error("tx error");
|
||||||
|
}
|
||||||
|
const txInfo = await waitForTerraExecution(txResult.txhash, lcd);
|
||||||
|
if (!txInfo) {
|
||||||
|
throw new Error("tx info not found");
|
||||||
|
}
|
||||||
|
return txInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
const terraBroadcastTxAndGetSignedVaa = async (msgs: Msg[], wallet: Wallet) => {
|
||||||
|
const txInfo = await terraBroadcastAndWaitForExecution(msgs, wallet);
|
||||||
|
const txSequence = parseSequenceFromLogTerra(txInfo);
|
||||||
|
if (!txSequence) {
|
||||||
|
throw new Error("tx sequence not found");
|
||||||
|
}
|
||||||
|
return await getSignedVAABySequence(
|
||||||
|
CHAIN_ID_TERRA2,
|
||||||
|
txSequence,
|
||||||
|
terraEmitterAddress
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ethParseLogAndGetSignedVaa = async (receipt: ethers.ContractReceipt) => {
|
||||||
|
const sequence = parseSequenceFromLogEth(receipt, ETH_CORE_BRIDGE_ADDRESS);
|
||||||
|
return await getSignedVAABySequence(
|
||||||
|
CHAIN_ID_ETH,
|
||||||
|
sequence,
|
||||||
|
ethEmitterAddress
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
test("Attest and transfer token from Terra2 to Ethereum", async () => {
|
||||||
|
// Attest
|
||||||
|
const attestMsg = await attestFromTerra(
|
||||||
|
TERRA2_TOKEN_BRIDGE_ADDRESS,
|
||||||
|
terraWalletAddress,
|
||||||
|
"uluna"
|
||||||
|
);
|
||||||
|
const attestSignedVaa = await terraBroadcastTxAndGetSignedVaa(
|
||||||
|
[attestMsg],
|
||||||
|
terraWallet
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await createWrappedOnEth(ETH_TOKEN_BRIDGE_ADDRESS, signer, attestSignedVaa);
|
||||||
|
} catch {
|
||||||
|
await updateWrappedOnEth(ETH_TOKEN_BRIDGE_ADDRESS, signer, attestSignedVaa);
|
||||||
|
}
|
||||||
|
// Transfer
|
||||||
|
const transferMsgs = await transferFromTerra(
|
||||||
|
terraWalletAddress,
|
||||||
|
TERRA2_TOKEN_BRIDGE_ADDRESS,
|
||||||
|
"uluna",
|
||||||
|
"1000000",
|
||||||
|
CHAIN_ID_ETH,
|
||||||
|
tryNativeToUint8Array(ethWalletAddress, CHAIN_ID_ETH)
|
||||||
|
);
|
||||||
|
const transferSignedVaa = await terraBroadcastTxAndGetSignedVaa(
|
||||||
|
transferMsgs,
|
||||||
|
terraWallet
|
||||||
|
);
|
||||||
|
await redeemOnEth(ETH_TOKEN_BRIDGE_ADDRESS, signer, transferSignedVaa);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Attest and transfer token from Ethereum to Terra2", async () => {
|
||||||
|
// Attest
|
||||||
|
const attestReceipt = await attestFromEth(
|
||||||
|
ETH_TOKEN_BRIDGE_ADDRESS,
|
||||||
|
signer,
|
||||||
|
TEST_ERC20
|
||||||
|
);
|
||||||
|
const attestSignedVaa = await ethParseLogAndGetSignedVaa(attestReceipt);
|
||||||
|
const createWrappedMsg = await createWrappedOnTerra(
|
||||||
|
TERRA2_TOKEN_BRIDGE_ADDRESS,
|
||||||
|
terraWalletAddress,
|
||||||
|
attestSignedVaa
|
||||||
|
);
|
||||||
|
await terraBroadcastAndWaitForExecution([createWrappedMsg], terraWallet);
|
||||||
|
// Transfer
|
||||||
|
await approveEth(
|
||||||
|
ETH_TOKEN_BRIDGE_ADDRESS,
|
||||||
|
TEST_ERC20,
|
||||||
|
signer,
|
||||||
|
ethTransferAmount
|
||||||
|
);
|
||||||
|
const transferReceipt = await transferFromEth(
|
||||||
|
ETH_TOKEN_BRIDGE_ADDRESS,
|
||||||
|
signer,
|
||||||
|
TEST_ERC20,
|
||||||
|
ethTransferAmount,
|
||||||
|
CHAIN_ID_TERRA2,
|
||||||
|
tryNativeToUint8Array(terraWalletAddress, CHAIN_ID_TERRA2)
|
||||||
|
);
|
||||||
|
const transferSignedVaa = await ethParseLogAndGetSignedVaa(transferReceipt);
|
||||||
|
const redeemMsg = await redeemOnTerra(
|
||||||
|
TERRA2_TOKEN_BRIDGE_ADDRESS,
|
||||||
|
terraWalletAddress,
|
||||||
|
transferSignedVaa
|
||||||
|
);
|
||||||
|
await terraBroadcastAndWaitForExecution([redeemMsg], terraWallet);
|
||||||
|
expect(
|
||||||
|
await getIsTransferCompletedTerra(
|
||||||
|
TERRA2_TOKEN_BRIDGE_ADDRESS,
|
||||||
|
transferSignedVaa,
|
||||||
|
lcd,
|
||||||
|
TERRA2_GAS_PRICES_URL
|
||||||
|
)
|
||||||
|
).toBe(true);
|
||||||
|
});
|
Loading…
Reference in New Issue