Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat/arb-sep-to-sep-testnet #344

Merged
merged 15 commits into from
Nov 28, 2024
443 changes: 443 additions & 0 deletions contracts/deployments/arbitrumSepolia/VeaInboxArbToEthTestnet.json

Large diffs are not rendered by default.

1,426 changes: 1,426 additions & 0 deletions contracts/deployments/sepolia/VeaOutboxArbToEthTestnet.json

Large diffs are not rendered by default.

366 changes: 305 additions & 61 deletions contracts/test/integration/ArbToEth.ts

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion relayer-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"yarn": "4.2.2"
},
"scripts": {
"start-devnet-relayer": "npx ts-node ./src/devnetRelayExample.ts"
"start-devnet-relayer": "npx ts-node ./src/devnetRelayExample.ts",
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
"start-testnet-sepolia": "npx ts-node ./src/testnet/arbSepToSepRelayer.ts"
},
"dependencies": {
"@kleros/vea-contracts": "workspace:^",
Expand Down
57 changes: 7 additions & 50 deletions relayer-cli/src/devnetRelayExample.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { relayAllFrom } from "./utils/relay";
import * as fs from "fs";
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
import { initialize, updateStateFile } from "./utils/relayerHelpers";

// let chain_ids = [5, 10200];
let chain_ids = [11155111];
const epochPeriod = 1800; // 30 min
const _contract = require("@kleros/vea-contracts/deployments/sepolia/VeaOutboxArbToEthDevnet.json");
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
const network = "devnet";

["SIGINT", "SIGTERM", "SIGQUIT", "EXIT", "MODULE_NOT_FOUND"].forEach((signal) =>
process.on(signal, async () => {
console.log("exit");
Expand All @@ -20,11 +24,11 @@ const epochPeriod = 1800; // 30 min
(async () => {
while (1) {
for (const chain_id of chain_ids) {
let nonce = await initialize(chain_id);
let nonce = await initialize(chain_id, network);
// This is libghtbulb switch address in arbitrum sepolia
const sender = "0x28d6D503F4c5734cD926E96b63C61527d975B382";
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
nonce = await relayAllFrom(chain_id, nonce, sender);
if (nonce != null) await updateStateFile(chain_id, Math.floor(Date.now() / 1000), nonce);
nonce = await relayAllFrom(chain_id, nonce, sender, _contract);
if (nonce != null) await updateStateFile(chain_id, Math.floor(Date.now() / 1000), nonce, network);
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
}
const currentTS = Math.floor(Date.now() / 1000);
const delayAmount = (epochPeriod - (currentTS % epochPeriod)) * 1000 + 100 * 1000;
Expand All @@ -33,53 +37,6 @@ const epochPeriod = 1800; // 30 min
}
})();

async function initialize(chain_id: number): Promise<number> {
fcanela marked this conversation as resolved.
Show resolved Hide resolved
if (chain_id !== 11155111) throw new Error("Invalid chainid");

const lock_file_name = "./src/state/" + chain_id + ".pid";
fcanela marked this conversation as resolved.
Show resolved Hide resolved

if (fs.existsSync(lock_file_name)) {
console.log("Skipping chain with process already running, delete pid file to force", chain_id);
throw new Error("Already running");
}
fs.writeFileSync(lock_file_name, process.pid.toString(), { encoding: "utf8" });
fcanela marked this conversation as resolved.
Show resolved Hide resolved

// STATE_DIR is absolute path of the directory where the state files are stored
// STATE_DIR must have trailing slash
const state_file = process.env.STATE_DIR + chain_id + ".json";
if (!fs.existsSync(state_file)) {
// No state file so initialize starting now
const tsnow = Math.floor(Date.now() / 1000);
await updateStateFile(chain_id, tsnow, 0);
}

// print pwd for debugging
console.log(process.cwd());
var chain_state = require(state_file);

let nonce = 0;
if ("nonce" in chain_state) {
nonce = chain_state["nonce"];
}

return nonce;
}

async function updateStateFile(chain_id: number, createdTimestamp: number, nonceFrom: number) {
const chain_state_file = "./src/state/" + chain_id + ".json";
const json = {
ts: createdTimestamp,
nonce: nonceFrom,
};
fs.writeFileSync(chain_state_file, JSON.stringify(json), { encoding: "utf8" });
for (const chain_id of chain_ids) {
const lock_file_name = "./src/state/" + chain_id + ".pid";
if (fs.existsSync(lock_file_name)) {
fs.unlinkSync(lock_file_name);
}
}
}

function delay(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
34 changes: 34 additions & 0 deletions relayer-cli/src/testnet/arbSepToChiadoRelayer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as fs from "fs";
require("dotenv").config();
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
import { relayBatch } from "utils/relay";
import { initialize, updateStateFile, delay } from "utils/relayerHelpers";
const _contract = require("@kleros/vea-contracts/deployments/chiado/VeaOutboxArbToGnosisTestnet.json");
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
mani99brar marked this conversation as resolved.
Show resolved Hide resolved

const chainId = 10200;
const epochPeriod = 7200; // 3 hrs
const batchSize = 10; // 10 messages per batch
const network = "testnet";

["SIGINT", "SIGTERM", "SIGQUIT", "EXIT", "MODULE_NOT_FOUND"].forEach((signal) =>
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
process.on(signal, async () => {
console.log("exit");
const lock_file_name = "./src/state/" + chainId + ".pid";
if (fs.existsSync(lock_file_name)) {
fs.unlinkSync(lock_file_name);
}
process.exit(0);
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
})
);

(async () => {
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
while (true) {
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
let nonce = await initialize(chainId, network);
console.log("chain_id", chainId, "nonce", nonce);
nonce = await relayBatch(chainId, nonce, batchSize, _contract);
if (nonce != null) await updateStateFile(chainId, Math.floor(Date.now() / 1000), nonce, network);
const currentTS = Math.floor(Date.now() / 1000);
const delayAmount = (epochPeriod - (currentTS % epochPeriod)) * 1000 + 100 * 1000;
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
console.log("waiting for the next epoch. . .", Math.floor(delayAmount / 1000), "seconds");
await delay(delayAmount);
}
})();
34 changes: 34 additions & 0 deletions relayer-cli/src/testnet/arbSepToSepRelayer.ts
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as fs from "fs";
require("dotenv").config();
import { relayBatch } from "utils/relay";
import { initialize, updateStateFile, delay } from "utils/relayerHelpers";

const _contract = require("@kleros/vea-contracts/deployments/sepolia/VeaOutboxArbToEthTestnet.json");
const network = "testnet";

let chainId = 11155111;
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
const epochPeriod = 7200; // 3 hrs
const batchSize = 10; // 10 messages per batch

["SIGINT", "SIGTERM", "SIGQUIT", "EXIT", "MODULE_NOT_FOUND"].forEach((signal) =>
process.on(signal, async () => {
console.log("exit");
const lock_file_name = "./src/state/" + chainId + ".pid";
if (fs.existsSync(lock_file_name)) {
fs.unlinkSync(lock_file_name);
}
process.exit(0);
})
);

(async () => {
while (true) {
let nonce = await initialize(chainId, network);
nonce = await relayBatch(chainId, nonce, batchSize, _contract);
if (nonce != null) await updateStateFile(chainId, Math.floor(Date.now() / 1000), nonce, network);
const currentTS = Math.floor(Date.now() / 1000);
const delayAmount = (epochPeriod - (currentTS % epochPeriod)) * 1000 + 100 * 1000;
console.log("waiting for the next epoch. . .", Math.floor(delayAmount / 1000), "seconds");
await delay(delayAmount);
}
})();
59 changes: 38 additions & 21 deletions relayer-cli/src/utils/ethers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { JsonRpcProvider } from "@ethersproject/providers";
import {
VeaOutboxArbToEth__factory,
VeaOutboxArbToEthDevnet__factory,
VeaOutboxArbToGnosisDevnet__factory,
VeaInboxArbToEth__factory,
VeaInboxArbToGnosis__factory,
VeaOutboxArbToGnosis__factory,
} from "@kleros/vea-contracts/typechain-types";

function getWallet(privateKey: string, web3ProviderURL: string) {
Expand All @@ -15,20 +16,43 @@ function getWalletRPC(privateKey: string, rpc: JsonRpcProvider) {
return new Wallet(privateKey, rpc);
}

function getVeaInboxArbToEth(veaInboxAddress: string, privateKey: string, web3ProviderURL: string) {
return VeaInboxArbToEth__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
// Using destination chainId as identifier, Ex: Arbitrum One (42161) -> Ethereum Mainnet (1): Use "1" as chainId
function getVeaInbox(veaInboxAddress: string, privateKey: string, web3ProviderURL: string, chainId: number) {
if (chainId == 11155111) {
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
return VeaInboxArbToEth__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
} else if (chainId == 10200) {
return VeaInboxArbToGnosis__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
} else {
throw new Error(`Unsupported chainId: ${chainId}`);
}
}

function getVeaInboxArbToEthProvider(veaInboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
return VeaInboxArbToEth__factory.connect(veaInboxAddress, getWalletRPC(privateKey, rpc));
function getVeaInboxProvider(veaInboxAddress: string, privateKey: string, rpc: JsonRpcProvider, chainId: number) {
if (chainId == 11155111) {
return VeaInboxArbToEth__factory.connect(veaInboxAddress, getWalletRPC(privateKey, rpc));
} else if (chainId == 10200) {
return VeaInboxArbToGnosis__factory.connect(veaInboxAddress, getWalletRPC(privateKey, rpc));
}
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
}

function getVeaOutboxArbToEthProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
return VeaOutboxArbToEth__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
function getVeaOutbox(veaInboxAddress: string, privateKey: string, web3ProviderURL: string, chainId: number) {
if (chainId == 11155111) {
return VeaOutboxArbToEth__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
} else if (chainId == 10200) {
return VeaOutboxArbToGnosis__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
} else {
throw new Error(`Unsupported chainId: ${chainId}`);
}
}

function getVeaOutboxArbToEth(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string) {
return VeaOutboxArbToEth__factory.connect(veaOutboxAddress, getWallet(privateKey, web3ProviderURL));
function getVeaOutboxProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider, chainId: number) {
if (chainId == 11155111) {
return VeaOutboxArbToEth__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
} else if (chainId == 10200) {
return VeaOutboxArbToGnosis__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
} else {
throw new Error(`Unsupported chainId: ${chainId}`);
}
}

function getVeaOutboxArbToEthDevnetProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
Expand All @@ -39,19 +63,12 @@ function getVeaOutboxArbToEthDevnet(veaOutboxAddress: string, privateKey: string
return VeaOutboxArbToEthDevnet__factory.connect(veaOutboxAddress, getWallet(privateKey, web3ProviderURL));
}

function getVeaOutboxArbToGnosisProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
return VeaOutboxArbToGnosisDevnet__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
}

function getVeaOutboxArbToGnosis(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string) {
return VeaOutboxArbToGnosisDevnet__factory.connect(veaOutboxAddress, getWallet(privateKey, web3ProviderURL));
}

export {
getVeaOutboxArbToEth,
getWalletRPC,
getVeaOutboxArbToEthDevnetProvider,
getVeaInboxArbToEth,
getVeaInboxArbToEthProvider,
getVeaOutboxArbToEthProvider,
getVeaOutbox,
getVeaInbox,
getVeaOutboxProvider,
getVeaInboxProvider,
getVeaOutboxArbToEthDevnet,
};
61 changes: 36 additions & 25 deletions relayer-cli/src/utils/relay.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { getProofAtCount, getMessageDataToRelay } from "./proof";
import { getVeaOutboxArbToEth } from "./ethers";
import { getVeaOutbox } from "./ethers";
import request from "graphql-request";
import { VeaOutboxArbToEth } from "@kleros/vea-contracts/typechain-types";
import { VeaOutboxArbToEth, VeaOutboxArbToGnosis } from "@kleros/vea-contracts/typechain-types";
import { getBridgeConfig, getInboxSubgraph } from "../consts/bridgeRoutes";
const fs = require("fs");

require("dotenv").config();

const Web3 = require("web3");
const _batchedSend = require("web3-batched-send");
const _contract = require("@kleros/vea-contracts/deployments/sepolia/VeaOutboxArbToEthDevnet.json");

const getCount = async (veaOutbox: VeaOutboxArbToEth, chainid: number): Promise<number> => {
const getCount = async (veaOutbox: VeaOutboxArbToEth | VeaOutboxArbToGnosis, chainid: number): Promise<number> => {
const subgraph = getInboxSubgraph(chainid);
const stateRoot = await veaOutbox.stateRoot();

Expand All @@ -31,8 +30,7 @@ const getCount = async (veaOutbox: VeaOutboxArbToEth, chainid: number): Promise<

const relay = async (chainid: number, nonce: number) => {
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
const routeParams = getBridgeConfig(chainid);

const veaOutbox = getVeaOutboxArbToEth(routeParams.veaOutbox, process.env.PRIVATE_KEY, routeParams.rpcOutbox);
const veaOutbox = getVeaOutbox(routeParams.veaOutbox, process.env.PRIVATE_KEY, routeParams.rpcOutbox, chainid);
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
const count = await getCount(veaOutbox, chainid);

const proof = await getProofAtCount(chainid, nonce, count);
Expand All @@ -42,32 +40,45 @@ const relay = async (chainid: number, nonce: number) => {
await txn.wait();
};

const relayBatch = async (chainid: number, nonce: number, iterations: number) => {
const relayBatch = async (chainid: number, nonce: number, maxBatchSize: number, _contract: any) => {
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
const routeParams = getBridgeConfig(chainid);

const web3 = new Web3(routeParams.rpcOutbox);
const batchedSend = _batchedSend(web3, routeParams.rpcOutbox, process.env.PRIVATE_KEY, 0);

const batchedSend = _batchedSend(web3, routeParams.batcher, process.env.PRIVATE_KEY, 0);
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
const contract = new web3.eth.Contract(_contract.abi, routeParams.veaOutbox);
const veaOutbox = getVeaOutboxArbToEth(routeParams.veaOutbox, process.env.PRIVATE_KEY, routeParams.rpcOutbox);
const veaOutbox = getVeaOutbox(routeParams.veaOutbox, process.env.PRIVATE_KEY, routeParams.rpcOutbox, chainid);
const count = await getCount(veaOutbox, chainid);

let txns = [];

for (let i = 0; i < iterations; i++) {
const proof = await getProofAtCount(chainid, nonce + i, count);
const [to, data] = await getMessageDataToRelay(chainid, nonce + i);
txns.push({
args: [proof, nonce + i, to, data],
method: contract.methods.sendMessage,
to: contract.options.address,
});
while (nonce < count) {
let batchMessages = 0;
let txns = [];
while (batchMessages < maxBatchSize && nonce < count) {
const isMsgRelayed = await veaOutbox.isMsgRelayed(nonce);
if (isMsgRelayed) {
nonce++;
continue;
}
const proof = await getProofAtCount(chainid, nonce, count);
const [to, data] = await getMessageDataToRelay(chainid, nonce);
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
txns.push({
args: [proof, nonce, to, data],
method: contract.methods.sendMessage,
to: contract.options.address,
});
batchMessages += 1;
nonce++;
}
if (batchMessages > 0) {
try {
await batchedSend(txns);
} catch (error) {
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
console.error(`Unable to execute messgae batch(${batchMessages} msgs) from nonce:${nonce} `, error);
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

await batchedSend(txns);
return nonce;
};

const relayAllFrom = async (chainid: number, nonce: number, msgSender: string): Promise<number> => {
const relayAllFrom = async (chainid: number, nonce: number, msgSender: string, _contract: any): Promise<number> => {
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
const routeParams = getBridgeConfig(chainid);

const web3 = new Web3(routeParams.rpcOutbox);
Expand All @@ -80,7 +91,7 @@ const relayAllFrom = async (chainid: number, nonce: number, msgSender: string):
);

const contract = new web3.eth.Contract(_contract.abi, routeParams.veaOutbox);
const veaOutbox = getVeaOutboxArbToEth(routeParams.veaOutbox, process.env.PRIVATE_KEY, routeParams.rpcOutbox);
const veaOutbox = getVeaOutbox(routeParams.veaOutbox, process.env.PRIVATE_KEY, routeParams.rpcOutbox, chainid);
const count = await getCount(veaOutbox, chainid);

if (!count) return null;
Expand Down
Loading
Loading