Skip to content

Commit b00c1ed

Browse files
authored
Merge pull request #344 from kleros/feat/arbSep-to-sep-testnet
feat/arb-sep-to-sep-testnet
2 parents 9f97125 + da4383c commit b00c1ed

17 files changed

+2872
-369
lines changed

contracts/deployments/arbitrumSepolia/VeaInboxArbToEthTestnet.json

+443
Large diffs are not rendered by default.

contracts/deployments/sepolia/VeaOutboxArbToEthTestnet.json

+1,426
Large diffs are not rendered by default.

contracts/test/integration/ArbToEth.ts

+305-61
Large diffs are not rendered by default.

relayer-cli/.env.dist

+6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
PRIVATE_KEY=
22

3+
# Devnet Sender Address
4+
DEVNET_SENDER=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
5+
36
RPC_CHIADO=https://rpc.chiadochain.net
47
RPC_SEPOLIA=
58

9+
VEAOUTBOX_CHAIN_ID=1115111
10+
11+
612
VEAINBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
713
VEAINBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS=0xAb53e341121448Ae259Da8fa17f216Cb0e21199C
814
VEAOUTBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS=0x906dE43dBef27639b1688Ac46532a16dc07Ce410

relayer-cli/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"yarn": "4.2.2"
1111
},
1212
"scripts": {
13-
"start-devnet-relayer": "npx ts-node ./src/devnetRelayExample.ts"
13+
"start-devnet-relayer": "npx ts-node ./src/devnetRelayExample.ts",
14+
"start-testnet-relayer": "npx ts-node ./src/testnetRelayer.ts"
1415
},
1516
"dependencies": {
1617
"@kleros/vea-contracts": "workspace:^",
+24-8
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,61 @@
11
// File for handling contants and configurations
22
require("dotenv").config();
3+
import veaOutboxArbToEthContract from "@kleros/vea-contracts/deployments/sepolia/VeaOutboxArbToEthTestnet.json";
4+
import veaOutboxArbToGnosisContract from "@kleros/vea-contracts/deployments/chiado/VeaOutboxArbToGnosisTestnet.json";
35

46
interface IBridge {
57
chainId: number;
6-
veaInbox: string;
7-
veaOutbox: string;
8+
chain: string;
9+
epochPeriod: number;
10+
veaInboxAddress: string;
11+
veaOutboxAddress: string;
812
batcher: string;
913
rpcOutbox: string;
14+
veaOutboxContract: any;
1015
}
1116

1217
// Using destination chainId to get the route configuration.
1318
const bridges: { [chainId: number]: IBridge } = {
1419
11155111: {
1520
chainId: 11155111,
16-
veaInbox: process.env.VEAINBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS,
17-
veaOutbox: process.env.VEAOUTBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS,
21+
chain: "sepolia",
22+
epochPeriod: 7200,
23+
veaInboxAddress: process.env.VEAINBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS,
24+
veaOutboxAddress: process.env.VEAOUTBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS,
1825
batcher: process.env.TRANSACTION_BATCHER_CONTRACT_ADDRESS_SEPOLIA,
1926
rpcOutbox: process.env.RPC_SEPOLIA,
27+
veaOutboxContract: veaOutboxArbToEthContract,
2028
},
2129
10200: {
2230
chainId: 10200,
23-
veaInbox: process.env.VEAINBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS,
24-
veaOutbox: process.env.VEAOUTBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS,
31+
chain: "chiado",
32+
epochPeriod: 3600,
33+
veaInboxAddress: process.env.VEAINBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS,
34+
veaOutboxAddress: process.env.VEAOUTBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS,
2535
batcher: process.env.TRANSACTION_BATCHER_CONTRACT_ADDRESS_CHIADO,
2636
rpcOutbox: process.env.RPC_CHIADO,
37+
veaOutboxContract: veaOutboxArbToGnosisContract,
2738
},
2839
};
2940

41+
// Getters
3042
const getBridgeConfig = (chainId: number): IBridge | undefined => {
3143
return bridges[chainId];
3244
};
3345

46+
const getEpochPeriod = (chainId: number): number => {
47+
return bridges[chainId].epochPeriod;
48+
};
49+
3450
const getInboxSubgraph = (chainId: number): string => {
3551
switch (chainId) {
3652
case 11155111:
3753
return process.env.VEAINBOX_ARBSEPOLIA_TO_SEPOLIA_SUBGRAPH;
3854
case 10200:
3955
return process.env.VEAINBOX_ARBSEPOLIA_TO_CHIADO_SUBGRAPH;
4056
default:
41-
throw new Error("Invalid chainid");
57+
throw new Error("Invalid chainId");
4258
}
4359
};
4460

45-
export { getBridgeConfig, getInboxSubgraph };
61+
export { getBridgeConfig, getInboxSubgraph, getEpochPeriod };

relayer-cli/src/devnetRelayExample.ts

+16-75
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,26 @@
11
import { relayAllFrom } from "./utils/relay";
2-
import * as fs from "fs";
2+
import { initialize, ShutdownManager, updateStateFile, setupExitHandlers, delay } from "./utils/relayerHelpers";
3+
4+
export async function start(shutdownManager: ShutdownManager = new ShutdownManager()) {
5+
const chainId = parseInt(process.env.VEAOUTBOX_CHAIN_ID);
6+
const epochPeriod = 1800; // 30 min
7+
const network = "devnet";
8+
await setupExitHandlers(chainId, shutdownManager, network);
9+
while (!shutdownManager.getIsShuttingDown()) {
10+
let nonce = await initialize(chainId, network);
11+
// This is libghtbulb switch address in arbitrum sepolia
12+
const sender = process.env.DEVNET_SENDER;
13+
nonce = await relayAllFrom(chainId, nonce, sender);
14+
if (nonce != null) await updateStateFile(chainId, Math.floor(Date.now() / 1000), nonce, network);
315

4-
// let chain_ids = [5, 10200];
5-
let chain_ids = [11155111];
6-
const epochPeriod = 1800; // 30 min
7-
["SIGINT", "SIGTERM", "SIGQUIT", "EXIT", "MODULE_NOT_FOUND"].forEach((signal) =>
8-
process.on(signal, async () => {
9-
console.log("exit");
10-
for (const chain_id of chain_ids) {
11-
const lock_file_name = "./src/state/" + chain_id + ".pid";
12-
if (fs.existsSync(lock_file_name)) {
13-
fs.unlinkSync(lock_file_name);
14-
}
15-
}
16-
process.exit(0);
17-
})
18-
);
19-
20-
(async () => {
21-
while (1) {
22-
for (const chain_id of chain_ids) {
23-
let nonce = await initialize(chain_id);
24-
// This is libghtbulb switch address in arbitrum sepolia
25-
const sender = "0x28d6D503F4c5734cD926E96b63C61527d975B382";
26-
nonce = await relayAllFrom(chain_id, nonce, sender);
27-
if (nonce != null) await updateStateFile(chain_id, Math.floor(Date.now() / 1000), nonce);
28-
}
2916
const currentTS = Math.floor(Date.now() / 1000);
3017
const delayAmount = (epochPeriod - (currentTS % epochPeriod)) * 1000 + 100 * 1000;
3118
console.log("waiting for the next epoch. . .", Math.floor(delayAmount / 1000), "seconds");
3219
await delay(delayAmount);
3320
}
34-
})();
35-
36-
async function initialize(chain_id: number): Promise<number> {
37-
if (chain_id !== 11155111) throw new Error("Invalid chainid");
38-
39-
const lock_file_name = "./src/state/" + chain_id + ".pid";
40-
41-
if (fs.existsSync(lock_file_name)) {
42-
console.log("Skipping chain with process already running, delete pid file to force", chain_id);
43-
throw new Error("Already running");
44-
}
45-
fs.writeFileSync(lock_file_name, process.pid.toString(), { encoding: "utf8" });
46-
47-
// STATE_DIR is absolute path of the directory where the state files are stored
48-
// STATE_DIR must have trailing slash
49-
const state_file = process.env.STATE_DIR + chain_id + ".json";
50-
if (!fs.existsSync(state_file)) {
51-
// No state file so initialize starting now
52-
const tsnow = Math.floor(Date.now() / 1000);
53-
await updateStateFile(chain_id, tsnow, 0);
54-
}
55-
56-
// print pwd for debugging
57-
console.log(process.cwd());
58-
var chain_state = require(state_file);
59-
60-
let nonce = 0;
61-
if ("nonce" in chain_state) {
62-
nonce = chain_state["nonce"];
63-
}
64-
65-
return nonce;
66-
}
67-
68-
async function updateStateFile(chain_id: number, createdTimestamp: number, nonceFrom: number) {
69-
const chain_state_file = "./src/state/" + chain_id + ".json";
70-
const json = {
71-
ts: createdTimestamp,
72-
nonce: nonceFrom,
73-
};
74-
fs.writeFileSync(chain_state_file, JSON.stringify(json), { encoding: "utf8" });
75-
for (const chain_id of chain_ids) {
76-
const lock_file_name = "./src/state/" + chain_id + ".pid";
77-
if (fs.existsSync(lock_file_name)) {
78-
fs.unlinkSync(lock_file_name);
79-
}
80-
}
8121
}
8222

83-
function delay(ms: number) {
84-
return new Promise((resolve) => setTimeout(resolve, ms));
23+
if (require.main === module) {
24+
const shutdownManager = new ShutdownManager(false);
25+
start(shutdownManager);
8526
}

relayer-cli/src/state/11155111.json

-4
This file was deleted.

relayer-cli/src/testnetRelayer.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
require("dotenv").config();
2+
import { relayBatch } from "utils/relay";
3+
import { initialize, updateStateFile, delay, setupExitHandlers, ShutdownManager } from "utils/relayerHelpers";
4+
import { getEpochPeriod } from "consts/bridgeRoutes";
5+
6+
export async function start(shutdownManager: ShutdownManager = new ShutdownManager()) {
7+
const network = "testnet";
8+
const chainId = parseInt(process.env.VEAOUTBOX_CHAIN_ID);
9+
const epochPeriod = getEpochPeriod(chainId);
10+
const batchSize = 10; // 10 messages per batch
11+
12+
await setupExitHandlers(chainId, shutdownManager, network);
13+
14+
while (!shutdownManager.getIsShuttingDown()) {
15+
let nonce = await initialize(chainId, network);
16+
nonce = await relayBatch(chainId, nonce, batchSize);
17+
if (nonce != null) await updateStateFile(chainId, Math.floor(Date.now() / 1000), nonce, network);
18+
const currentTS = Math.floor(Date.now() / 1000);
19+
const delayAmount = (epochPeriod - (currentTS % epochPeriod)) * 1000 + 100 * 1000;
20+
console.log("waiting for the next epoch. . .", Math.floor(delayAmount / 1000), "seconds");
21+
await delay(delayAmount);
22+
}
23+
}
24+
25+
if (require.main === module) {
26+
const shutdownManager = new ShutdownManager(false);
27+
start(shutdownManager);
28+
}

relayer-cli/src/utils/ethers.ts

+57-21
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import { JsonRpcProvider } from "@ethersproject/providers";
33
import {
44
VeaOutboxArbToEth__factory,
55
VeaOutboxArbToEthDevnet__factory,
6-
VeaOutboxArbToGnosisDevnet__factory,
76
VeaInboxArbToEth__factory,
7+
VeaInboxArbToGnosis__factory,
8+
VeaOutboxArbToGnosis__factory,
89
} from "@kleros/vea-contracts/typechain-types";
10+
import { getBridgeConfig } from "consts/bridgeRoutes";
911

1012
function getWallet(privateKey: string, web3ProviderURL: string) {
1113
return new Wallet(privateKey, new JsonRpcProvider(web3ProviderURL));
@@ -15,20 +17,61 @@ function getWalletRPC(privateKey: string, rpc: JsonRpcProvider) {
1517
return new Wallet(privateKey, rpc);
1618
}
1719

18-
function getVeaInboxArbToEth(veaInboxAddress: string, privateKey: string, web3ProviderURL: string) {
19-
return VeaInboxArbToEth__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
20+
// Using destination chainId as identifier, Ex: Arbitrum One (42161) -> Ethereum Mainnet (1): Use "1" as chainId
21+
function getVeaInbox(veaInboxAddress: string, privateKey: string, web3ProviderURL: string, chainId: number) {
22+
const bridge = getBridgeConfig(chainId);
23+
switch (bridge.chain) {
24+
case "sepolia":
25+
case "mainnet":
26+
return VeaInboxArbToEth__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
27+
case "chiado":
28+
case "gnosis":
29+
return VeaInboxArbToGnosis__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
30+
default:
31+
throw new Error(`Unsupported chainId: ${chainId}`);
32+
}
2033
}
2134

22-
function getVeaInboxArbToEthProvider(veaInboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
23-
return VeaInboxArbToEth__factory.connect(veaInboxAddress, getWalletRPC(privateKey, rpc));
35+
function getVeaInboxProvider(veaInboxAddress: string, privateKey: string, rpc: JsonRpcProvider, chainId: number) {
36+
const bridges = getBridgeConfig(chainId);
37+
switch (bridges.chain) {
38+
case "sepolia":
39+
case "mainnet":
40+
return VeaInboxArbToEth__factory.connect(veaInboxAddress, getWalletRPC(privateKey, rpc));
41+
case "chiado":
42+
case "gnosis":
43+
return VeaInboxArbToGnosis__factory.connect(veaInboxAddress, getWalletRPC(privateKey, rpc));
44+
default:
45+
throw new Error(`Unsupported chainId: ${chainId}`);
46+
}
2447
}
2548

26-
function getVeaOutboxArbToEthProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
27-
return VeaOutboxArbToEth__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
49+
function getVeaOutbox(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string, chainId: number) {
50+
const bridge = getBridgeConfig(chainId);
51+
switch (bridge.chain) {
52+
case "sepolia":
53+
case "mainnet":
54+
return VeaOutboxArbToEth__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
55+
case "chiado":
56+
case "gnosis":
57+
return VeaOutboxArbToGnosis__factory.connect(veaInboxAddress, getWallet(privateKey, web3ProviderURL));
58+
default:
59+
throw new Error(`Unsupported chainId: ${chainId}`);
60+
}
2861
}
2962

30-
function getVeaOutboxArbToEth(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string) {
31-
return VeaOutboxArbToEth__factory.connect(veaOutboxAddress, getWallet(privateKey, web3ProviderURL));
63+
function getVeaOutboxProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider, chainId: number) {
64+
const bridges = getBridgeConfig(chainId);
65+
switch (bridges.chain) {
66+
case "sepolia":
67+
case "mainnet":
68+
return VeaOutboxArbToEth__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
69+
case "chiado":
70+
case "gnosis":
71+
return VeaOutboxArbToGnosis__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
72+
default:
73+
throw new Error(`Unsupported chainId: ${chainId}`);
74+
}
3275
}
3376

3477
function getVeaOutboxArbToEthDevnetProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
@@ -39,19 +82,12 @@ function getVeaOutboxArbToEthDevnet(veaOutboxAddress: string, privateKey: string
3982
return VeaOutboxArbToEthDevnet__factory.connect(veaOutboxAddress, getWallet(privateKey, web3ProviderURL));
4083
}
4184

42-
function getVeaOutboxArbToGnosisProvider(veaOutboxAddress: string, privateKey: string, rpc: JsonRpcProvider) {
43-
return VeaOutboxArbToGnosisDevnet__factory.connect(veaOutboxAddress, getWalletRPC(privateKey, rpc));
44-
}
45-
46-
function getVeaOutboxArbToGnosis(veaOutboxAddress: string, privateKey: string, web3ProviderURL: string) {
47-
return VeaOutboxArbToGnosisDevnet__factory.connect(veaOutboxAddress, getWallet(privateKey, web3ProviderURL));
48-
}
49-
5085
export {
51-
getVeaOutboxArbToEth,
5286
getWalletRPC,
5387
getVeaOutboxArbToEthDevnetProvider,
54-
getVeaInboxArbToEth,
55-
getVeaInboxArbToEthProvider,
56-
getVeaOutboxArbToEthProvider,
88+
getVeaOutbox,
89+
getVeaInbox,
90+
getVeaOutboxProvider,
91+
getVeaInboxProvider,
92+
getVeaOutboxArbToEthDevnet,
5793
};

0 commit comments

Comments
 (0)