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
Merged
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",
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
"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;
};
mani99brar marked this conversation as resolved.
Show resolved Hide resolved

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);
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
const epochPeriod = 1800; // 30 min
const network = "devnet";
await setupExitHandlers(chainId, shutdownManager);
while (!shutdownManager.getIsShuttingDown()) {
let nonce = await initialize(chainId, network);
// This is libghtbulb switch address in arbitrum sepolia
const sender = process.env.DEVNET_SENDER;
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
nonce = await relayAllFrom(chainId, nonce, sender);
if (nonce != null) await updateStateFile(chainId, Math.floor(Date.now() / 1000), nonce, network);
mani99brar marked this conversation as resolved.
Show resolved Hide resolved

// 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> {
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));
if (require.main === module) {
const shutdownManager = new ShutdownManager(false);
start(shutdownManager);
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
}
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);

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);
}
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
}

if (require.main === module) {
const shutdownManager = new ShutdownManager(false);
start(shutdownManager);
}
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
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(veaInboxAddress: string, privateKey: string, web3ProviderURL: string, chainId: number) {
const bridges = getBridgeConfig(chainId);
switch (bridges.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}`);
}
mani99brar marked this conversation as resolved.
Show resolved Hide resolved
}

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
Loading