This commit is contained in:
Joe Howarth 2023-01-17 15:41:15 -07:00
parent cd1ee566c0
commit c119f88024
16 changed files with 4 additions and 10332 deletions

View File

@ -11,6 +11,7 @@ WORKDIR /usr/src/app
# Install app dependencies
# COPY . /src
COPY ../sdk ../sdk
COPY . .
CMD [ "npm", "run", "k8s-testnet" ]

View File

@ -1,4 +0,0 @@
#! /usr/bin/sh
cp -r ../sdk ./sdk
cp ../ethereum/ts-scripts/config/testnet/contracts.json .

View File

@ -2,4 +2,4 @@ bash deploy-redis.sh
kubectl apply -f ./spy-service.yaml
source ../../pkeys.sh
bash inject-private-keys.sh
kubectl apply -k .
bash simple-gr.sh

View File

@ -0,0 +1,2 @@
cp ../../ethereum/ts-scripts/config/testnet/contracts.json ./k8s-testnet/contracts.json
kubectl apply -k .

View File

@ -1,3 +0,0 @@
lib
node_modules
src/ethers-contracts

File diff suppressed because it is too large Load Diff

View File

@ -1,34 +0,0 @@
{
"name": "generic-relayer-sdk",
"version": "1.0.0",
"description": "",
"main": "networks.js",
"devDependencies": {
"@openzeppelin/contracts": "^4.7.3",
"@poanet/solidity-flattener": "^3.0.8",
"@types/chai": "^4.3.3",
"@types/mocha": "^9.1.1",
"chai": "^4.3.6",
"ethers": "^5.7.1",
"mocha": "^10.0.0",
"ts-mocha": "^10.0.0"
},
"scripts": {
"clean": "rm -rf node_modules src/ethers-contracts",
"build": "bash scripts/make_ethers_types.sh",
"test": "ts-mocha src/__tests__/*.ts --timeout 60000"
},
"author": "",
"license": "ISC",
"dependencies": {
"@certusone/wormhole-sdk": "^0.9.6",
"@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
"@typechain/ethers-v5": "^10.1.0",
"dotenv": "^16.0.2",
"elliptic": "^6.5.4",
"jsonfile": "^6.1.0",
"solc": "^0.8.17",
"ts-node": "^10.9.1",
"typescript": "^4.8.3"
}
}

View File

@ -1,6 +0,0 @@
#!/bin/bash
SRC=$(dirname $0)/../../ethereum/build
DST=$(dirname $0)/../src/ethers-contracts
typechain --target=ethers-v5 --out-dir=$DST $SRC/*/*.json

View File

@ -1,222 +0,0 @@
import { expect } from "chai";
import { ethers } from "ethers";
import {
BSC_FORGE_BROADCAST,
BSC_RPC,
WORMHOLE_RPCS,
ETH_FORGE_BROADCAST,
ETH_RPC,
DEPLOYER_PRIVATE_KEY,
ZERO_ADDRESS_BYTES,
TARGET_GAS_LIMIT,
} from "./helpers/consts";
import { RelayerArgs } from "./helpers/structs";
import {
makeCoreRelayerFromForgeBroadcast,
makeGasOracleFromForgeBroadcast,
makeMockRelayerIntegrationFromForgeBroadcast,
resolvePath,
} from "./helpers/utils";
import {
CHAIN_ID_BSC,
CHAIN_ID_ETH,
getSignedBatchVAAWithRetry,
tryNativeToUint8Array,
tryNativeToHexString,
} from "@certusone/wormhole-sdk";
import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
describe("ETH <> BSC Generic Relayer Integration Test", () => {
const ethProvider = new ethers.providers.StaticJsonRpcProvider(ETH_RPC);
const bscProvider = new ethers.providers.StaticJsonRpcProvider(BSC_RPC);
// core relayers
const ethCoreRelayer = makeCoreRelayerFromForgeBroadcast(
resolvePath(ETH_FORGE_BROADCAST),
new ethers.Wallet(DEPLOYER_PRIVATE_KEY, ethProvider)
);
const bscCoreRelayer = makeCoreRelayerFromForgeBroadcast(
resolvePath(BSC_FORGE_BROADCAST),
new ethers.Wallet(DEPLOYER_PRIVATE_KEY, bscProvider)
);
// relayer integrators
const ethRelayerIntegrator = makeMockRelayerIntegrationFromForgeBroadcast(
resolvePath(ETH_FORGE_BROADCAST),
new ethers.Wallet(DEPLOYER_PRIVATE_KEY, ethProvider)
);
const bscRelayerIntegrator = makeMockRelayerIntegrationFromForgeBroadcast(
resolvePath(BSC_FORGE_BROADCAST),
new ethers.Wallet(DEPLOYER_PRIVATE_KEY, bscProvider)
);
// gas oracles
const ownedGasOracles = [
// eth
makeGasOracleFromForgeBroadcast(
resolvePath(ETH_FORGE_BROADCAST),
new ethers.Wallet(DEPLOYER_PRIVATE_KEY, ethProvider)
),
// bsc
makeGasOracleFromForgeBroadcast(
resolvePath(BSC_FORGE_BROADCAST),
new ethers.Wallet(DEPLOYER_PRIVATE_KEY, bscProvider)
),
];
const readonlyGasOracles = [
// eth
makeGasOracleFromForgeBroadcast(resolvePath(ETH_FORGE_BROADCAST), ethProvider),
// bsc
makeGasOracleFromForgeBroadcast(resolvePath(BSC_FORGE_BROADCAST), bscProvider),
];
const ethPrice = ethers.utils.parseUnits("2000.00", 8);
const bscPrice = ethers.utils.parseUnits("400.00", 8);
before("Setup Gas Oracle Prices And Register Relayer Contracts", async () => {
// now fetch gas prices from each provider
const gasPrices = await Promise.all(ownedGasOracles.map((oracle) => oracle.provider.getGasPrice()));
const updates = [
{
chainId: CHAIN_ID_ETH,
gasPrice: gasPrices.at(0)!,
nativeCurrencyPrice: ethPrice,
},
{
chainId: CHAIN_ID_BSC,
gasPrice: gasPrices.at(1)!,
nativeCurrencyPrice: bscPrice,
},
];
const oracleTxs = await Promise.all(
ownedGasOracles.map((oracle) => oracle.updatePrices(updates).then((tx: ethers.ContractTransaction) => tx.wait()))
);
// query the core relayer contracts to see if relayers have been registered
const registeredCoreRelayerOnBsc = await bscCoreRelayer.registeredRelayer(CHAIN_ID_ETH);
const registeredCoreRelayerOnEth = await ethCoreRelayer.registeredRelayer(CHAIN_ID_BSC);
// register the core relayer contracts
if (registeredCoreRelayerOnBsc == ZERO_ADDRESS_BYTES) {
await bscCoreRelayer
.registerChain(CHAIN_ID_ETH, tryNativeToUint8Array(ethCoreRelayer.address, CHAIN_ID_ETH))
.then((tx) => tx.wait());
}
if (registeredCoreRelayerOnEth == ZERO_ADDRESS_BYTES) {
await ethCoreRelayer
.registerChain(CHAIN_ID_BSC, tryNativeToUint8Array(bscCoreRelayer.address, CHAIN_ID_BSC))
.then((tx) => tx.wait());
}
});
describe("Send from Ethereum and Deliver to BSC", () => {
// batch Vaa payloads to relay to the target contract
let batchVaaPayloads: ethers.utils.BytesLike[] = [];
// save the batch VAA info
let batchToBscReceipt: ethers.ContractReceipt;
let batchVaaFromEth: ethers.utils.BytesLike;
it("Check Gas Oracles", async () => {
const chainIds = await Promise.all(readonlyGasOracles.map((oracle) => oracle.chainId()));
expect(chainIds.at(0)).is.not.undefined;
expect(chainIds.at(0)!).to.equal(CHAIN_ID_ETH);
expect(chainIds.at(1)).is.not.undefined;
expect(chainIds.at(1)!).to.equal(CHAIN_ID_BSC);
const ethPrices = await Promise.all(readonlyGasOracles.map((oracle) => oracle.gasPrice(CHAIN_ID_ETH)));
const bscPrices = await Promise.all(readonlyGasOracles.map((oracle) => oracle.gasPrice(CHAIN_ID_BSC)));
for (let i = 0; i < 2; ++i) {
expect(ethPrices.at(i)).is.not.undefined;
expect(ethPrices.at(i)?.toString()).to.equal("20000000000");
expect(bscPrices.at(i)).is.not.undefined;
expect(bscPrices.at(i)?.toString()).to.equal("20000000000");
}
});
it("Generate batch VAA with delivery instructions on Ethereum", async () => {
// estimate the relayer cost to relay a batch to BSC
const estimatedGasCost = await ethRelayerIntegrator.estimateRelayCosts(CHAIN_ID_BSC, TARGET_GAS_LIMIT);
// create an array of messages to deliver to the BSC target contract
batchVaaPayloads = [
ethers.utils.hexlify(ethers.utils.toUtf8Bytes("SuperCoolCrossChainStuff0")),
ethers.utils.hexlify(ethers.utils.toUtf8Bytes("SuperCoolCrossChainStuff1")),
ethers.utils.hexlify(ethers.utils.toUtf8Bytes("SuperCoolCrossChainStuff2")),
ethers.utils.hexlify(ethers.utils.toUtf8Bytes("SuperCoolCrossChainStuff3")),
];
const batchVaaConsistencyLevels = [15, 15, 15, 15];
// create relayerArgs interface to call the mock integration contract with
const relayerArgs: RelayerArgs = {
nonce: 69,
targetChainId: CHAIN_ID_BSC,
targetAddress: bscRelayerIntegrator.address,
targetGasLimit: TARGET_GAS_LIMIT,
consistencyLevel: batchVaaConsistencyLevels[0],
};
// call the mock integration contract and send the batch VAA
batchToBscReceipt = await ethRelayerIntegrator
.sendBatchToTargetChain(batchVaaPayloads, batchVaaConsistencyLevels, relayerArgs, {
value: estimatedGasCost,
})
.then((tx) => tx.wait());
});
it("Fetch batch VAA from Ethereum", async () => {
// fetch the batch VAA with getSignedBatchVAAWithRetry
const batchVaaRes = await getSignedBatchVAAWithRetry(
WORMHOLE_RPCS,
CHAIN_ID_ETH,
batchToBscReceipt.transactionHash,
{
transport: NodeHttpTransport(),
}
);
batchVaaFromEth = batchVaaRes.batchVaaBytes;
});
it("Wait for off-chain relayer to deliver the batch VAA to BSC", async () => {
// parse the batch VAA
const parsedBatch = await ethRelayerIntegrator.parseWormholeBatch(batchVaaFromEth);
// Check to see if the batch VAA was delivered by querying the contract
// for the first payload sent in the batch.
let isBatchDelivered: boolean = false;
const targetVm3 = await ethRelayerIntegrator.parseWormholeObservation(parsedBatch.observations[0]);
while (!isBatchDelivered) {
// query the contract to see if the batch was delivered
const storedPayload = await bscRelayerIntegrator.getPayload(targetVm3.hash);
if (storedPayload == targetVm3.payload) {
isBatchDelivered = true;
}
}
// confirm that the remaining payloads are stored in the contract
for (const observation of parsedBatch.observations) {
const vm3 = await bscRelayerIntegrator.parseWormholeObservation(observation);
// skip delivery instructions VM
if (vm3.emitterAddress == "0x" + tryNativeToHexString(ethCoreRelayer.address, CHAIN_ID_ETH)) {
continue;
}
// query the contract to see if the batch was delivered
const storedPayload = await bscRelayerIntegrator.getPayload(vm3.hash);
expect(storedPayload).to.equal(vm3.payload);
// clear the payload from the mock integration contract
await bscRelayerIntegrator.clearPayload(vm3.hash);
const emptyStoredPayload = await bscRelayerIntegrator.getPayload(vm3.hash);
expect(emptyStoredPayload).to.equal("0x");
}
});
});
});

View File

@ -1,27 +0,0 @@
// rpc
export const ETH_RPC = "http://localhost:8545";
export const BSC_RPC = "http://localhost:8546";
export const WORMHOLE_RPCS = ["http://localhost:7071"];
export const ETH_EVM_CHAINID = 1337;
export const BSC_EVM_CHAINID = 1397;
// evm wallets
export const DEPLOYER_PRIVATE_KEY = "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d"; // account 0
export const EVM_PRIVATE_KEY = "0x6370fd033278c143179d81c5526140625662b8daa446c22ee2d73db3707e620c"; // account 2
// io
export const ETHEREUM_ROOT = `${__dirname}/../../../../ethereum`; // holy parent directories, batman
export const ETH_FORGE_BROADCAST = `${ETHEREUM_ROOT}/broadcast/deploy_contracts.sol/${ETH_EVM_CHAINID}/run-latest.json`;
export const BSC_FORGE_BROADCAST = `${ETHEREUM_ROOT}/broadcast/deploy_contracts.sol/${BSC_EVM_CHAINID}/run-latest.json`;
// misc
export const ZERO_ADDRESS_BYTES = "0x0000000000000000000000000000000000000000000000000000000000000000";
// the amount of gas that the target relayer contract will invoke the wormhole receiver with
export const TARGET_GAS_LIMIT = 500000; // evm gas units
// wormhole event ABIs
export const WORMHOLE_MESSAGE_EVENT_ABI = [
"event LogMessagePublished(address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel)",
];

View File

@ -1,24 +0,0 @@
import { ethers } from "ethers";
export interface RelayerArgs {
nonce: number;
targetChainId: number;
targetAddress: string;
targetGasLimit: number;
consistencyLevel: number;
}
export interface TargetDeliveryParameters {
encodedVM: ethers.utils.BytesLike;
deliveryIndex: number;
targetCallGasOverride: ethers.BigNumber;
}
export interface DeliveryStatus {
payloadId: number;
batchHash: ethers.utils.BytesLike;
emitterAddress: ethers.utils.BytesLike;
sequence: number;
deliveryCount: number;
deliverySuccess: number;
}

View File

@ -1,136 +0,0 @@
import {ethers} from "ethers";
import fs from "fs";
import path from "path";
import {DeliveryStatus} from "./structs";
import {WORMHOLE_RPCS, WORMHOLE_MESSAGE_EVENT_ABI} from "./consts";
import {NodeHttpTransport} from "@improbable-eng/grpc-web-node-http-transport";
import {ChainId, getEmitterAddressEth, getSignedVAAWithRetry} from "@certusone/wormhole-sdk";
import {
GasOracle,
GasOracle__factory,
MockRelayerIntegration,
MockRelayerIntegration__factory,
CoreRelayer,
CoreRelayer__factory,
} from "../../";
export function makeGasOracleFromForgeBroadcast(
broadcastPath: string,
signerOrProvider: ethers.Signer | ethers.providers.Provider
): GasOracle {
const address = getContractAddressFromForgeBroadcast(broadcastPath, "GasOracle");
return GasOracle__factory.connect(address, signerOrProvider);
}
export function makeMockRelayerIntegrationFromForgeBroadcast(
broadcastPath: string,
signerOrProvider: ethers.Signer | ethers.providers.Provider
): MockRelayerIntegration {
const address = getContractAddressFromForgeBroadcast(broadcastPath, "MockRelayerIntegration");
return MockRelayerIntegration__factory.connect(address, signerOrProvider);
}
export function makeCoreRelayerFromForgeBroadcast(
broadcastPath: string,
signerOrProvider: ethers.Signer | ethers.providers.Provider
): CoreRelayer {
const address = getContractAddressFromForgeBroadcast(broadcastPath, "ERC1967Proxy");
return CoreRelayer__factory.connect(address, signerOrProvider);
}
function readForgeBroadcast(broadcastPath: string): any {
if (!fs.existsSync(broadcastPath)) {
throw new Error("broadcastPath does not exist");
}
return JSON.parse(fs.readFileSync(broadcastPath, "utf8"));
}
function getContractAddressFromForgeBroadcast(broadcastPath: string, contractName: string) {
const transactions: any[] = readForgeBroadcast(broadcastPath).transactions;
const result = transactions.find((tx) => tx.contractName == contractName && tx.transactionType == "CREATE");
if (result == undefined) {
throw new Error("transaction.find == undefined");
}
return result.contractAddress;
}
export function resolvePath(fp: string) {
return path.resolve(fp);
}
export async function parseWormholeEventsFromReceipt(
receipt: ethers.ContractReceipt
): Promise<ethers.utils.LogDescription[]> {
// create the wormhole message interface
const wormholeMessageInterface = new ethers.utils.Interface(WORMHOLE_MESSAGE_EVENT_ABI);
// loop through the logs and parse the events that were emitted
const logDescriptions: ethers.utils.LogDescription[] = await Promise.all(
receipt.logs.map(async (log) => {
return wormholeMessageInterface.parseLog(log);
})
);
return logDescriptions;
}
export async function getSignedVaaFromReceiptOnEth(
receipt: ethers.ContractReceipt,
emitterChainId: ChainId,
contractAddress: ethers.BytesLike
): Promise<Uint8Array> {
const messageEvents = await parseWormholeEventsFromReceipt(receipt);
// grab the sequence from the parsed message log
if (messageEvents.length !== 1) {
throw Error("more than one message found in log");
}
const sequence = messageEvents[0].args.sequence;
// fetch the signed VAA
const result = await getSignedVAAWithRetry(
WORMHOLE_RPCS,
emitterChainId,
getEmitterAddressEth(contractAddress),
sequence.toString(),
{
transport: NodeHttpTransport(),
}
);
return result.vaaBytes;
}
export function parseDeliveryStatusVaa(payload: ethers.BytesLike): DeliveryStatus {
// confirm that the payload is formatted correctly
let index: number = 0;
// interface that we will parse the bytes into
let deliveryStatus: DeliveryStatus = {} as DeliveryStatus;
// grab the payloadID = 2
deliveryStatus.payloadId = parseInt(ethers.utils.hexDataSlice(payload, index, index + 1));
index += 1;
// delivery batch hash
deliveryStatus.batchHash = ethers.utils.hexDataSlice(payload, index, index + 32);
index += 32;
// deliveryId emitter address
deliveryStatus.emitterAddress = ethers.utils.hexDataSlice(payload, index, index + 32);
index += 32;
// deliveryId sequence
deliveryStatus.sequence = parseInt(ethers.utils.hexDataSlice(payload, index, index + 8));
index += 8;
// delivery count
deliveryStatus.deliveryCount = parseInt(ethers.utils.hexDataSlice(payload, index, index + 2));
index += 2;
// grab the success boolean
deliveryStatus.deliverySuccess = parseInt(ethers.utils.hexDataSlice(payload, index, index + 1));
index += 1;
return deliveryStatus;
}

View File

@ -1,203 +0,0 @@
import { expect } from "chai";
import { ethers } from "ethers";
import {
BSC_FORGE_BROADCAST,
BSC_RPC,
WORMHOLE_RPCS,
ETH_FORGE_BROADCAST,
ETH_RPC,
DEPLOYER_PRIVATE_KEY,
ZERO_ADDRESS_BYTES,
TARGET_GAS_LIMIT,
} from "../__tests__/helpers/consts";
import { DeliveryStatus, RelayerArgs, TargetDeliveryParameters } from "../__tests__/helpers/structs";
import {
makeCoreRelayerFromForgeBroadcast,
makeGasOracleFromForgeBroadcast,
makeMockRelayerIntegrationFromForgeBroadcast,
resolvePath,
getSignedVaaFromReceiptOnEth,
parseDeliveryStatusVaa,
} from "../__tests__/helpers/utils";
import { CHAIN_ID_BSC, CHAIN_ID_ETH, tryNativeToHexString, getSignedBatchVAAWithRetry } from "@certusone/wormhole-sdk";
import { NodeHttpTransport } from "@improbable-eng/grpc-web-node-http-transport";
async function main() {
const ethProvider = new ethers.providers.StaticJsonRpcProvider(ETH_RPC);
const bscProvider = new ethers.providers.StaticJsonRpcProvider(BSC_RPC);
// core relayers
const ethCoreRelayer = makeCoreRelayerFromForgeBroadcast(
resolvePath(ETH_FORGE_BROADCAST),
new ethers.Wallet(DEPLOYER_PRIVATE_KEY, ethProvider)
);
const bscCoreRelayer = makeCoreRelayerFromForgeBroadcast(
resolvePath(BSC_FORGE_BROADCAST),
new ethers.Wallet(DEPLOYER_PRIVATE_KEY, bscProvider)
);
// relayer integrators
const ethRelayerIntegrator = makeMockRelayerIntegrationFromForgeBroadcast(
resolvePath(ETH_FORGE_BROADCAST),
new ethers.Wallet(DEPLOYER_PRIVATE_KEY, ethProvider)
);
const bscRelayerIntegrator = makeMockRelayerIntegrationFromForgeBroadcast(
resolvePath(BSC_FORGE_BROADCAST),
new ethers.Wallet(DEPLOYER_PRIVATE_KEY, bscProvider)
);
// gas oracles
const ownedGasOracles = [
// eth
makeGasOracleFromForgeBroadcast(
resolvePath(ETH_FORGE_BROADCAST),
new ethers.Wallet(DEPLOYER_PRIVATE_KEY, ethProvider)
),
// bsc
makeGasOracleFromForgeBroadcast(
resolvePath(BSC_FORGE_BROADCAST),
new ethers.Wallet(DEPLOYER_PRIVATE_KEY, bscProvider)
),
];
// setup gas oracles and register if needed
{
const ethPrice = ethers.utils.parseUnits("2000.00", 8);
const bscPrice = ethers.utils.parseUnits("400.00", 8);
// now fetch gas prices from each provider
const gasPrices = await Promise.all(ownedGasOracles.map((oracle) => oracle.provider.getGasPrice()));
const updates = [
{
chainId: CHAIN_ID_ETH,
gasPrice: gasPrices.at(0)!,
nativeCurrencyPrice: ethPrice,
},
{
chainId: CHAIN_ID_BSC,
gasPrice: gasPrices.at(1)!,
nativeCurrencyPrice: bscPrice,
},
];
const oracleTxs = await Promise.all(
ownedGasOracles.map((oracle) => oracle.updatePrices(updates).then((tx: ethers.ContractTransaction) => tx.wait()))
);
// query the core relayer contracts to see if relayers have been registered
const registeredCoreRelayerOnBsc = await bscCoreRelayer.registeredRelayer(CHAIN_ID_ETH);
const registeredCoreRelayerOnEth = await ethCoreRelayer.registeredRelayer(CHAIN_ID_BSC);
// register the core relayer contracts
if (registeredCoreRelayerOnBsc == ZERO_ADDRESS_BYTES) {
const bscRegistrationTx = await bscCoreRelayer.registerChain(
CHAIN_ID_ETH,
"0x" + tryNativeToHexString(ethCoreRelayer.address, CHAIN_ID_ETH)
);
await bscRegistrationTx.wait();
}
if (registeredCoreRelayerOnEth == ZERO_ADDRESS_BYTES) {
const ethRegistrationTx = await ethCoreRelayer.registerChain(
CHAIN_ID_BSC,
"0x" + tryNativeToHexString(bscCoreRelayer.address, CHAIN_ID_BSC)
);
await ethRegistrationTx.wait();
}
// Query the mock relayer integration contracts to see if trusted mock relayer
// integration contracts have been registered.
const trustedSenderOnBsc = await bscRelayerIntegrator.trustedSender(CHAIN_ID_ETH);
const trustedSenderOnEth = await ethRelayerIntegrator.trustedSender(CHAIN_ID_BSC);
// register the trusted mock relayer integration contracts
if (trustedSenderOnBsc == ZERO_ADDRESS_BYTES) {
const bscRegistrationTx = await bscRelayerIntegrator.registerTrustedSender(
CHAIN_ID_ETH,
"0x" + tryNativeToHexString(ethRelayerIntegrator.address, CHAIN_ID_ETH)
);
await bscRegistrationTx.wait();
}
if (trustedSenderOnEth == ZERO_ADDRESS_BYTES) {
const ethRegistrationTx = await ethRelayerIntegrator.registerTrustedSender(
CHAIN_ID_BSC,
"0x" + tryNativeToHexString(bscRelayerIntegrator.address, CHAIN_ID_BSC)
);
await ethRegistrationTx.wait();
}
}
{
// batch Vaa payloads to relay to the target contract
let batchVaaPayloads: ethers.utils.BytesLike[] = [];
// REVIEW: these should be removed when the off-chain relayer is implemented
let batchToBscReceipt: ethers.ContractReceipt;
let targetDeliveryParamsOnBsc: TargetDeliveryParameters = {} as TargetDeliveryParameters;
{
// estimate the relayer cost to relay a batch to BSC
const estimatedGasCost: ethers.BigNumber = await ethRelayerIntegrator.estimateRelayCosts(
CHAIN_ID_BSC,
TARGET_GAS_LIMIT
);
// create an array of messages to deliver to the BSC target contract
batchVaaPayloads = [
ethers.utils.hexlify(ethers.utils.toUtf8Bytes("SuperCoolCrossChainStuff0")),
ethers.utils.hexlify(ethers.utils.toUtf8Bytes("SuperCoolCrossChainStuff1")),
ethers.utils.hexlify(ethers.utils.toUtf8Bytes("SuperCoolCrossChainStuff2")),
ethers.utils.hexlify(ethers.utils.toUtf8Bytes("SuperCoolCrossChainStuff3")),
];
const batchVaaConsistencyLevels = [15, 15, 15, 15];
// create relayerArgs interface to call the mock integration contract with
const relayerArgs: RelayerArgs = {
nonce: 69,
targetChainId: CHAIN_ID_BSC,
targetAddress: bscRelayerIntegrator.address,
targetGasLimit: TARGET_GAS_LIMIT,
consistencyLevel: batchVaaConsistencyLevels[0],
deliveryListIndices: [] as number[], // no indices specified for full batch delivery
};
// call the mock integration contract and send the batch VAA
const tx = await ethRelayerIntegrator.sendBatchToTargetChain(
batchVaaPayloads,
batchVaaConsistencyLevels,
relayerArgs,
{
value: estimatedGasCost,
}
);
batchToBscReceipt = await tx.wait();
console.log("emitterChain", CHAIN_ID_ETH, "emitterAddress", ethCoreRelayer.address);
console.log("transaction", batchToBscReceipt.transactionHash);
}
{
// fetch the batch VAA with getSignedBatchVAAWithRetry
const batchVaaRes = await getSignedBatchVAAWithRetry(
WORMHOLE_RPCS,
CHAIN_ID_ETH,
batchToBscReceipt.transactionHash,
{
transport: NodeHttpTransport(),
}
);
const batchVaaFromEth: ethers.utils.BytesLike = batchVaaRes.batchVaaBytes;
console.log("vaa", Buffer.from(batchVaaFromEth as Uint8Array).toString("hex"));
// parse the batch VAA
const parsedBatch = await ethRelayerIntegrator.parseBatchVM(batchVaaFromEth);
console.log("parsed", parsedBatch);
}
}
}
main();

View File

@ -1,8 +0,0 @@
export type { CoreRelayer } from "./ethers-contracts/CoreRelayer"
export { CoreRelayer__factory } from "./ethers-contracts/factories/CoreRelayer__factory"
export type { MockRelayerIntegration } from "./ethers-contracts/MockRelayerIntegration"
export { MockRelayerIntegration__factory } from "./ethers-contracts/factories/MockRelayerIntegration__factory"
export type { IWormhole } from "./ethers-contracts/IWormhole"
export { IWormhole__factory } from "./ethers-contracts/factories/IWormhole__factory"
export type { RelayProvider } from "./ethers-contracts/RelayProvider"
export { RelayProvider__factory } from "./ethers-contracts/factories/RelayProvider__factory"

View File

@ -1,13 +0,0 @@
{
"compilerOptions": {
"types": ["mocha", "chai"],
"typeRoots": ["./node_modules/@types"],
"lib": ["es2020"],
"module": "CommonJS",
"target": "es2020",
"esModuleInterop": true,
"strict": true,
"resolveJsonModule": true,
"moduleResolution": "node"
}
}