remove nested sdk
This commit is contained in:
parent
03f09c9a1a
commit
7c2c68be3b
|
@ -1,3 +0,0 @@
|
|||
lib
|
||||
node_modules
|
||||
src/ethers-contracts
|
File diff suppressed because it is too large
Load Diff
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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)",
|
||||
];
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
|
@ -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"
|
|
@ -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"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue