Skip to content

Commit

Permalink
Merge pull request #344 from kleros/feat/arbSep-to-sep-testnet
Browse files Browse the repository at this point in the history
feat/arb-sep-to-sep-testnet
  • Loading branch information
jaybuidl authored Nov 28, 2024
2 parents 9f97125 + da4383c commit b00c1ed
Show file tree
Hide file tree
Showing 17 changed files with 2,872 additions and 369 deletions.
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.

6 changes: 6 additions & 0 deletions relayer-cli/.env.dist
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
PRIVATE_KEY=

# Devnet Sender Address
DEVNET_SENDER=0x906dE43dBef27639b1688Ac46532a16dc07Ce410

RPC_CHIADO=https://rpc.chiadochain.net
RPC_SEPOLIA=

VEAOUTBOX_CHAIN_ID=1115111


VEAINBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
VEAINBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS=0xAb53e341121448Ae259Da8fa17f216Cb0e21199C
VEAOUTBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
Expand Down
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",
"start-testnet-relayer": "npx ts-node ./src/testnetRelayer.ts"
},
"dependencies": {
"@kleros/vea-contracts": "workspace:^",
Expand Down
32 changes: 24 additions & 8 deletions relayer-cli/src/consts/bridgeRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,61 @@
// File for handling contants and configurations
require("dotenv").config();
import veaOutboxArbToEthContract from "@kleros/vea-contracts/deployments/sepolia/VeaOutboxArbToEthTestnet.json";
import veaOutboxArbToGnosisContract from "@kleros/vea-contracts/deployments/chiado/VeaOutboxArbToGnosisTestnet.json";

interface IBridge {
chainId: number;
veaInbox: string;
veaOutbox: string;
chain: string;
epochPeriod: number;
veaInboxAddress: string;
veaOutboxAddress: string;
batcher: string;
rpcOutbox: string;
veaOutboxContract: any;
}

// Using destination chainId to get the route configuration.
const bridges: { [chainId: number]: IBridge } = {
11155111: {
chainId: 11155111,
veaInbox: process.env.VEAINBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS,
veaOutbox: process.env.VEAOUTBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS,
chain: "sepolia",
epochPeriod: 7200,
veaInboxAddress: process.env.VEAINBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS,
veaOutboxAddress: process.env.VEAOUTBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS,
batcher: process.env.TRANSACTION_BATCHER_CONTRACT_ADDRESS_SEPOLIA,
rpcOutbox: process.env.RPC_SEPOLIA,
veaOutboxContract: veaOutboxArbToEthContract,
},
10200: {
chainId: 10200,
veaInbox: process.env.VEAINBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS,
veaOutbox: process.env.VEAOUTBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS,
chain: "chiado",
epochPeriod: 3600,
veaInboxAddress: process.env.VEAINBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS,
veaOutboxAddress: process.env.VEAOUTBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS,
batcher: process.env.TRANSACTION_BATCHER_CONTRACT_ADDRESS_CHIADO,
rpcOutbox: process.env.RPC_CHIADO,
veaOutboxContract: veaOutboxArbToGnosisContract,
},
};

// Getters
const getBridgeConfig = (chainId: number): IBridge | undefined => {
return bridges[chainId];
};

const getEpochPeriod = (chainId: number): number => {
return bridges[chainId].epochPeriod;
};

const getInboxSubgraph = (chainId: number): string => {
switch (chainId) {
case 11155111:
return process.env.VEAINBOX_ARBSEPOLIA_TO_SEPOLIA_SUBGRAPH;
case 10200:
return process.env.VEAINBOX_ARBSEPOLIA_TO_CHIADO_SUBGRAPH;
default:
throw new Error("Invalid chainid");
throw new Error("Invalid chainId");
}
};

export { getBridgeConfig, getInboxSubgraph };
export { getBridgeConfig, getInboxSubgraph, getEpochPeriod };
91 changes: 16 additions & 75 deletions relayer-cli/src/devnetRelayExample.ts
Original file line number Diff line number Diff line change
@@ -1,85 +1,26 @@
import { relayAllFrom } from "./utils/relay";
import * as fs from "fs";
import { initialize, ShutdownManager, updateStateFile, setupExitHandlers, delay } from "./utils/relayerHelpers";

export async function start(shutdownManager: ShutdownManager = new ShutdownManager()) {
const chainId = parseInt(process.env.VEAOUTBOX_CHAIN_ID);
const epochPeriod = 1800; // 30 min
const network = "devnet";
await setupExitHandlers(chainId, shutdownManager, network);
while (!shutdownManager.getIsShuttingDown()) {
let nonce = await initialize(chainId, network);
// This is libghtbulb switch address in arbitrum sepolia
const sender = process.env.DEVNET_SENDER;
nonce = await relayAllFrom(chainId, nonce, sender);
if (nonce != null) await updateStateFile(chainId, Math.floor(Date.now() / 1000), nonce, network);

// let chain_ids = [5, 10200];
let chain_ids = [11155111];
const epochPeriod = 1800; // 30 min
["SIGINT", "SIGTERM", "SIGQUIT", "EXIT", "MODULE_NOT_FOUND"].forEach((signal) =>
process.on(signal, async () => {
console.log("exit");
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);
}
}
process.exit(0);
})
);

(async () => {
while (1) {
for (const chain_id of chain_ids) {
let nonce = await initialize(chain_id);
// This is libghtbulb switch address in arbitrum sepolia
const sender = "0x28d6D503F4c5734cD926E96b63C61527d975B382";
nonce = await relayAllFrom(chain_id, nonce, sender);
if (nonce != null) await updateStateFile(chain_id, Math.floor(Date.now() / 1000), nonce);
}
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);
}
})();

async function initialize(chain_id: number): Promise<number> {
if (chain_id !== 11155111) throw new Error("Invalid chainid");

const lock_file_name = "./src/state/" + chain_id + ".pid";

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" });

// 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));
if (require.main === module) {
const shutdownManager = new ShutdownManager(false);
start(shutdownManager);
}
4 changes: 0 additions & 4 deletions relayer-cli/src/state/11155111.json

This file was deleted.

28 changes: 28 additions & 0 deletions relayer-cli/src/testnetRelayer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require("dotenv").config();
import { relayBatch } from "utils/relay";
import { initialize, updateStateFile, delay, setupExitHandlers, ShutdownManager } from "utils/relayerHelpers";
import { getEpochPeriod } from "consts/bridgeRoutes";

export async function start(shutdownManager: ShutdownManager = new ShutdownManager()) {
const network = "testnet";
const chainId = parseInt(process.env.VEAOUTBOX_CHAIN_ID);
const epochPeriod = getEpochPeriod(chainId);
const batchSize = 10; // 10 messages per batch

await setupExitHandlers(chainId, shutdownManager, network);

while (!shutdownManager.getIsShuttingDown()) {
let nonce = await initialize(chainId, network);
nonce = await relayBatch(chainId, nonce, batchSize);
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);
}
}

if (require.main === module) {
const shutdownManager = new ShutdownManager(false);
start(shutdownManager);
}
78 changes: 57 additions & 21 deletions relayer-cli/src/utils/ethers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { JsonRpcProvider } from "@ethersproject/providers";
import {
VeaOutboxArbToEth__factory,
VeaOutboxArbToEthDevnet__factory,
VeaOutboxArbToGnosisDevnet__factory,
VeaInboxArbToEth__factory,
VeaInboxArbToGnosis__factory,
VeaOutboxArbToGnosis__factory,
} from "@kleros/vea-contracts/typechain-types";
import { getBridgeConfig } from "consts/bridgeRoutes";

function getWallet(privateKey: string, web3ProviderURL: string) {
return new Wallet(privateKey, new JsonRpcProvider(web3ProviderURL));
Expand All @@ -15,20 +17,61 @@ 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) {
const bridge = getBridgeConfig(chainId);
switch (bridge.chain) {
case "sepolia":
case "mainnet":
return VeaInboxArbToEth__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
case "chiado":
case "gnosis":
return VeaInboxArbToGnosis__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
default:
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) {
const bridges = getBridgeConfig(chainId);
switch (bridges.chain) {
case "sepolia":
case "mainnet":
return VeaInboxArbToEth__factory.connect(veaInboxAddress, getWalletRPC(privateKey, rpc));
case "chiado":
case "gnosis":
return VeaInboxArbToGnosis__factory.connect(veaInboxAddress, getWalletRPC(privateKey, rpc));
default:
throw new Error(`Unsupported chainId: ${chainId}`);
}
}

function getVeaOutboxArbToEthProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
return VeaOutboxArbToEth__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
function getVeaOutbox(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string, chainId: number) {
const bridge = getBridgeConfig(chainId);
switch (bridge.chain) {
case "sepolia":
case "mainnet":
return VeaOutboxArbToEth__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
case "chiado":
case "gnosis":
return VeaOutboxArbToGnosis__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
default:
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) {
const bridges = getBridgeConfig(chainId);
switch (bridges.chain) {
case "sepolia":
case "mainnet":
return VeaOutboxArbToEth__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
case "chiado":
case "gnosis":
return VeaOutboxArbToGnosis__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
default:
throw new Error(`Unsupported chainId: ${chainId}`);
}
}

function getVeaOutboxArbToEthDevnetProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
Expand All @@ -39,19 +82,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,
};
Loading

0 comments on commit b00c1ed

Please sign in to comment.