Skip to content

Commit 62f36b8

Browse files
committed
Merge branch 'dev' into feat(validator)/claimer
2 parents 30b174d + d1058b1 commit 62f36b8

20 files changed

+833
-2641
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
// Adapted from https://github.com/daostack/web3-transaction-batcher/blob/1b88d2ea062f8f2d9fdfdf9bbe85d2bbef780151/contracts/Batcher.sol
5+
6+
contract TransactionBatcher {
7+
function batchSend(address[] memory targets, uint256[] memory values, bytes[] memory datas) public payable {
8+
for (uint256 i = 0; i < targets.length; i++) {
9+
(bool success, ) = targets[i].call{value: values[i]}(datas[i]);
10+
if (!success) revert("transaction failed"); // All the calls must succeed.
11+
}
12+
}
13+
14+
function batchSendUnchecked(
15+
address[] memory targets,
16+
uint256[] memory values,
17+
bytes[] memory datas
18+
) public payable {
19+
for (uint256 i = 0; i < targets.length; i++) {
20+
targets[i].call{value: values[i]}(datas[i]); // Intentionally ignoring return value.
21+
}
22+
}
23+
}

relayer-cli/.env.dist

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
PRIVATE_KEY=
22

3-
# Devnet Sender Address
4-
DEVNET_SENDER=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
3+
### Sender Address
4+
# Zero address is used for allowing all senders.
5+
# No senders are used to disable network.
6+
SENDER_ADDRESSES_DEVNET=0x906dE43dBef27639b1688Ac46532a16dc07Ce410,0x123456789abcdef123456789abcdef1234567890
7+
SENDER_ADDRESSES_TESTNET=0x0000000000000000000000000000000000000000
8+
SENDER_ADDRESS_MAINNET=
59

610
RPC_CHIADO=https://rpc.chiadochain.net
711
RPC_SEPOLIA=
812

9-
VEAOUTBOX_CHAIN_ID=1115111
13+
VEAOUTBOX_CHAINS=11155111,10200
1014

1115

12-
VEAINBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
13-
VEAINBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS=0xAb53e341121448Ae259Da8fa17f216Cb0e21199C
14-
VEAOUTBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
15-
VEAOUTBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS=0xAb53e341121448Ae259Da8fa17f216Cb0e21199C
16+
# Subgraph endpoint, Example: "85918/vea-inbox-arb-sepolia-devnet/version/latest"
17+
RELAYER_SUBGRAPH="61738/vea-inbox-arb-sepolia/version/latest"
1618

17-
# Subgraph endpoints, Example: "85918/vea-inbox-arb-sepolia-devnet/version/latest"
18-
VEAINBOX_ARBSEPOLIA_TO_SEPOLIA_SUBGRAPH=11111/your-subgraph/version/your-version
19-
VEAINBOX_ARBSEPOLIA_TO_CHIADO_SUBGRAPH=11111/your-subgraph/version/your-version
19+
# Transaction Batcher Contract Addresses
20+
TRANSACTION_BATCHER_CONTRACT_SEPOLIA=0xe7953da7751063d0a41ba727c32c762d3523ade8
21+
TRANSACTION_BATCHER_CONTRACT_CHIADO=0xcC0a08D4BCC5f91ee9a1587608f7a2975EA75d73
2022

21-
TRANSACTION_BATCHER_CONTRACT_ADDRESS_SEPOLIA=0xe7953da7751063d0a41ba727c32c762d3523ade8
22-
TRANSACTION_BATCHER_CONTRACT_ADDRESS_CHIADO=0xcC0a08D4BCC5f91ee9a1587608f7a2975EA75d73
23-
24-
STATE_DIR="/home/user/vea/relayer-cli/state"
23+
# Ensure the path ends with a trailing slash ("/")
24+
STATE_DIR="/home/user/vea/relayer-cli/state/"

relayer-cli/ecosystem.config.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
module.exports = {
22
apps: [
33
{
4-
name: "devnet-relayer",
5-
script: "yarn",
6-
args: "start-devnet-relayer",
7-
interpreter: "/bin/bash",
8-
log_date_format: "YYYY-MM-DD HH:mm Z",
9-
watch: false,
10-
autorestart: false,
4+
name: "vea-relayer",
5+
script: "./src/relayer.ts",
6+
interpreter: "../node_modules/.bin/ts-node",
7+
interpreter_args: "--project tsconfig.json -r tsconfig-paths/register",
8+
cwd: process.cwd(),
119
env: {
12-
NODE_ENV: "development",
10+
TS_NODE_PROJECT: "./tsconfig.json",
1311
},
1412
},
1513
],

relayer-cli/jest.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ const config: Config = {
55
testEnvironment: "node",
66
collectCoverage: true,
77
collectCoverageFrom: ["**/*.ts"],
8+
moduleNameMapper: {
9+
"^consts/(.*)$": "<rootDir>/src/consts/$1",
10+
},
811
};
912

1013
export default config;

relayer-cli/package.json

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,14 @@
1010
},
1111
"scripts": {
1212
"test": "jest --coverage",
13-
"start-devnet-relayer": "npx ts-node ./src/devnetRelayExample.ts",
14-
"start-testnet-relayer": "npx ts-node ./src/testnetRelayer.ts"
13+
"start-relayer": "ts-node ./src/relayer.ts"
1514
},
1615
"dependencies": {
1716
"@kleros/vea-contracts": "workspace:^",
18-
"@typechain/ethers-v5": "^11.1.2",
17+
"@typechain/ethers-v6": "^0.5.1",
1918
"dotenv": "^16.4.5",
20-
"pm2": "^5.2.2",
21-
"typescript": "^4.9.5",
22-
"web3": "^1.10.4",
23-
"web3-batched-send": "^1.0.3"
19+
"pm2": "^6.0.5",
20+
"typescript": "^4.9.5"
2421
},
2522
"devDependencies": {
2623
"@types/jest": "^29.5.14",
Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,88 @@
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";
3+
import veaInboxArbToEthDevnet from "@kleros/vea-contracts/deployments/arbitrumSepolia/VeaInboxArbToEthDevnet.json";
4+
import veaOutboxArbToEthDevnet from "@kleros/vea-contracts/deployments/sepolia/VeaOutboxArbToEthDevnet.json";
5+
import veaInboxArbToEthTestnet from "@kleros/vea-contracts/deployments/arbitrumSepolia/VeaInboxArbToEthTestnet.json";
6+
import veaOutboxArbToEthTestnet from "@kleros/vea-contracts/deployments/sepolia/VeaOutboxArbToEthTestnet.json";
7+
8+
import veaInboxArbToGnosisDevnet from "@kleros/vea-contracts/deployments/arbitrumSepolia/VeaInboxArbToGnosisDevnet.json";
9+
import veaOutboxArbToGnosisDevnet from "@kleros/vea-contracts/deployments/chiado/VeaOutboxArbToGnosisDevnet.json";
10+
11+
import veaInboxArbToGnosisTestnet from "@kleros/vea-contracts/deployments/arbitrumSepolia/VeaInboxArbToGnosisTestnet.json";
12+
import veaOutboxArbToGnosisTestnet from "@kleros/vea-contracts/deployments/chiado/VeaOutboxArbToGnosisTestnet.json";
513

614
interface IBridge {
715
chainId: number;
816
chain: string;
917
epochPeriod: number;
10-
veaInboxAddress: string;
11-
veaOutboxAddress: string;
12-
batcher: string;
18+
veaContracts: { [key in Network]: VeaContracts };
19+
batcherAddress: string;
1320
rpcOutbox: string;
14-
veaOutboxContract: any;
1521
}
1622

23+
type VeaContracts = {
24+
veaInbox: any;
25+
veaOutbox: any;
26+
};
27+
28+
enum Network {
29+
DEVNET = "devnet",
30+
TESTNET = "testnet",
31+
}
32+
33+
const arbToEthContracts: { [key in Network]: VeaContracts } = {
34+
[Network.DEVNET]: {
35+
veaInbox: veaInboxArbToEthDevnet,
36+
veaOutbox: veaOutboxArbToEthDevnet,
37+
},
38+
[Network.TESTNET]: {
39+
veaInbox: veaInboxArbToEthTestnet,
40+
veaOutbox: veaOutboxArbToEthTestnet,
41+
},
42+
};
43+
44+
const arbToGnosisContracts: { [key in Network]: VeaContracts } = {
45+
[Network.DEVNET]: {
46+
veaInbox: veaInboxArbToGnosisDevnet,
47+
veaOutbox: veaOutboxArbToGnosisDevnet,
48+
},
49+
[Network.TESTNET]: {
50+
veaInbox: veaInboxArbToGnosisTestnet,
51+
veaOutbox: veaOutboxArbToGnosisTestnet,
52+
},
53+
};
54+
1755
// Using destination chainId to get the route configuration.
1856
const bridges: { [chainId: number]: IBridge } = {
1957
11155111: {
2058
chainId: 11155111,
2159
chain: "sepolia",
2260
epochPeriod: 7200,
23-
veaInboxAddress: process.env.VEAINBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS,
24-
veaOutboxAddress: process.env.VEAOUTBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS,
25-
batcher: process.env.TRANSACTION_BATCHER_CONTRACT_ADDRESS_SEPOLIA,
26-
rpcOutbox: process.env.RPC_SEPOLIA,
27-
veaOutboxContract: veaOutboxArbToEthContract,
61+
veaContracts: arbToEthContracts,
62+
batcherAddress: process.env.TRANSACTION_BATCHER_CONTRACT_SEPOLIA!,
63+
rpcOutbox: process.env.RPC_SEPOLIA!,
2864
},
2965
10200: {
3066
chainId: 10200,
3167
chain: "chiado",
3268
epochPeriod: 3600,
33-
veaInboxAddress: process.env.VEAINBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS,
34-
veaOutboxAddress: process.env.VEAOUTBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS,
35-
batcher: process.env.TRANSACTION_BATCHER_CONTRACT_ADDRESS_CHIADO,
36-
rpcOutbox: process.env.RPC_CHIADO,
37-
veaOutboxContract: veaOutboxArbToGnosisContract,
69+
veaContracts: arbToGnosisContracts,
70+
batcherAddress: process.env.TRANSACTION_BATCHER_CONTRACT_CHIADO!,
71+
rpcOutbox: process.env.RPC_CHIADO!,
3872
},
3973
};
4074

4175
// Getters
42-
const getBridgeConfig = (chainId: number): IBridge | undefined => {
43-
return bridges[chainId];
76+
const getBridgeConfig = (chainId: number): IBridge => {
77+
const bridge = bridges[chainId];
78+
if (!bridge) throw new Error(`Unsupported chainId: ${chainId}`);
79+
return bridge;
4480
};
4581

4682
const getEpochPeriod = (chainId: number): number => {
47-
return bridges[chainId].epochPeriod;
48-
};
49-
50-
const getInboxSubgraph = (chainId: number): string => {
51-
switch (chainId) {
52-
case 11155111:
53-
return process.env.VEAINBOX_ARBSEPOLIA_TO_SEPOLIA_SUBGRAPH;
54-
case 10200:
55-
return process.env.VEAINBOX_ARBSEPOLIA_TO_CHIADO_SUBGRAPH;
56-
default:
57-
throw new Error("Invalid chainId");
58-
}
83+
const bridge = bridges[chainId];
84+
if (!bridge.epochPeriod) throw new Error(`Unsupported chainId: ${chainId}`);
85+
return bridge.epochPeriod;
5986
};
6087

61-
export { getBridgeConfig, getInboxSubgraph, getEpochPeriod };
88+
export { getBridgeConfig, getEpochPeriod, Network };

relayer-cli/src/devnetRelayExample.ts

Lines changed: 0 additions & 29 deletions
This file was deleted.

relayer-cli/src/relayer.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
require("dotenv").config();
2+
import { EventEmitter } from "node:events";
3+
import { ethers } from "ethers";
4+
import { relayBatch, relayAllFrom } from "./utils/relay";
5+
import {
6+
initialize as initializeNonce,
7+
updateStateFile,
8+
delay,
9+
setupExitHandlers,
10+
ShutdownManager,
11+
getNetworkConfig,
12+
RelayerNetworkConfig,
13+
} from "./utils/relayerHelpers";
14+
import { initialize as initializeEmitter } from "./utils/logger";
15+
import { BotEvents } from "./utils/botEvents";
16+
import { getEpochPeriod, Network } from "./consts/bridgeRoutes";
17+
18+
interface RelayerConfig {
19+
networkConfigs: RelayerNetworkConfig[];
20+
shutdownManager: ShutdownManager;
21+
emitter: EventEmitter;
22+
}
23+
24+
/**
25+
* Start the relayer
26+
* @param config.networkConfigs The network configurations retrieved from the env.
27+
* @param config.shutdownManager The shutdown manager
28+
* @param config.emitter The event emitter
29+
*/
30+
export async function start({ networkConfigs, shutdownManager, emitter }: RelayerConfig) {
31+
initializeEmitter(emitter);
32+
let delayAmount = 7200 * 1000; // 2 hours in ms
33+
while (!shutdownManager.getIsShuttingDown()) {
34+
for (const networkConfig of networkConfigs) {
35+
delayAmount = await processNetworkConfig(networkConfig, shutdownManager, emitter, delayAmount);
36+
}
37+
emitter.emit(BotEvents.WAITING, delayAmount);
38+
await delay(delayAmount);
39+
}
40+
}
41+
42+
/**
43+
* Process the network configuration
44+
* @param networkConfig The network configuration
45+
* @param shutdownManager The shutdown manager
46+
* @param emitter The event emitter
47+
* @param currentDelay The current delay
48+
* @returns The new delay
49+
*/
50+
async function processNetworkConfig(
51+
networkConfig: RelayerNetworkConfig,
52+
shutdownManager: ShutdownManager,
53+
emitter: EventEmitter,
54+
currentDelay: number
55+
): Promise<number> {
56+
const { chainId, network, senders } = networkConfig;
57+
emitter.emit(BotEvents.STARTED, chainId, network);
58+
const maxBatchSize = 10; // 10 messages per batch
59+
60+
await setupExitHandlers(chainId, shutdownManager, network, emitter);
61+
62+
let nonce = await initializeNonce(chainId, network, emitter);
63+
if (nonce == null) return currentDelay;
64+
65+
const toRelayAll = senders[0] === ethers.ZeroAddress;
66+
nonce = toRelayAll
67+
? await relayBatch({ chainId, network, nonce, maxBatchSize, emitter })
68+
: await relayAllFrom(chainId, network, nonce, senders, emitter);
69+
70+
if (nonce == null) return currentDelay;
71+
72+
await updateStateFile(chainId, Math.floor(Date.now() / 1000), nonce, network, emitter);
73+
74+
if (network === Network.DEVNET) {
75+
return 1000 * 10; // 10 seconds for devnet
76+
} else {
77+
const currentTS = Math.floor(Date.now() / 1000);
78+
const epochPeriod = getEpochPeriod(chainId);
79+
const timeLeft = (epochPeriod - (Math.floor(currentTS / 1000) % epochPeriod)) * 1000 + 100 * 1000;
80+
return Math.min(currentDelay, timeLeft);
81+
}
82+
}
83+
84+
if (require.main === module) {
85+
const emitter = new EventEmitter();
86+
const shutdownManager = new ShutdownManager(false);
87+
const networkConfigs = getNetworkConfig();
88+
const testnetRelayerConfig: RelayerConfig = {
89+
networkConfigs,
90+
shutdownManager,
91+
emitter,
92+
};
93+
94+
start(testnetRelayerConfig);
95+
}

0 commit comments

Comments
 (0)