Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions contracts/src/utils/TransactionBatcher.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Adapted from https://github.com/daostack/web3-transaction-batcher/blob/1b88d2ea062f8f2d9fdfdf9bbe85d2bbef780151/contracts/Batcher.sol

contract TransactionBatcher {
function batchSend(address[] memory targets, uint256[] memory values, bytes[] memory datas) public payable {
for (uint256 i = 0; i < targets.length; i++) {
(bool success, ) = targets[i].call{value: values[i]}(datas[i]);
if (!success) revert("transaction failed"); // All the calls must succeed.
}
}

function batchSendUnchecked(
address[] memory targets,
uint256[] memory values,
bytes[] memory datas
) public payable {
for (uint256 i = 0; i < targets.length; i++) {
targets[i].call{value: values[i]}(datas[i]); // Intentionally ignoring return value.
}
}
}
28 changes: 14 additions & 14 deletions relayer-cli/.env.dist
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
PRIVATE_KEY=

# Devnet Sender Address
DEVNET_SENDER=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
### Sender Address
# Zero address is used for allowing all senders.
# No senders are used to disable network.
SENDER_ADDRESSES_DEVNET=0x906dE43dBef27639b1688Ac46532a16dc07Ce410,0x123456789abcdef123456789abcdef1234567890
SENDER_ADDRESSES_TESTNET=0x0000000000000000000000000000000000000000
SENDER_ADDRESS_MAINNET=

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

VEAOUTBOX_CHAIN_ID=1115111
VEAOUTBOX_CHAINS=11155111,10200


VEAINBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
VEAINBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS=0xAb53e341121448Ae259Da8fa17f216Cb0e21199C
VEAOUTBOX_ARBSEPOLIA_TO_SEPOLIA_ADDRESS=0x906dE43dBef27639b1688Ac46532a16dc07Ce410
VEAOUTBOX_ARBSEPOLIA_TO_CHIADO_ADDRESS=0xAb53e341121448Ae259Da8fa17f216Cb0e21199C
# Subgraph endpoint, Example: "85918/vea-inbox-arb-sepolia-devnet/version/latest"
RELAYER_SUBGRAPH="61738/vea-inbox-arb-sepolia/version/latest"

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

TRANSACTION_BATCHER_CONTRACT_ADDRESS_SEPOLIA=0xe7953da7751063d0a41ba727c32c762d3523ade8
TRANSACTION_BATCHER_CONTRACT_ADDRESS_CHIADO=0xcC0a08D4BCC5f91ee9a1587608f7a2975EA75d73

STATE_DIR="/home/user/vea/relayer-cli/state"
# Ensure the path ends with a trailing slash ("/")
STATE_DIR="/home/user/vea/relayer-cli/state/"
14 changes: 6 additions & 8 deletions relayer-cli/ecosystem.config.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
module.exports = {
apps: [
{
name: "devnet-relayer",
script: "yarn",
args: "start-devnet-relayer",
interpreter: "/bin/bash",
log_date_format: "YYYY-MM-DD HH:mm Z",
watch: false,
autorestart: false,
name: "vea-relayer",
script: "./src/relayer.ts",
interpreter: "../node_modules/.bin/ts-node",
interpreter_args: "--project tsconfig.json -r tsconfig-paths/register",
cwd: process.cwd(),
env: {
NODE_ENV: "development",
TS_NODE_PROJECT: "./tsconfig.json",
},
},
],
Expand Down
3 changes: 3 additions & 0 deletions relayer-cli/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ const config: Config = {
testEnvironment: "node",
collectCoverage: true,
collectCoverageFrom: ["**/*.ts"],
moduleNameMapper: {
"^consts/(.*)$": "<rootDir>/src/consts/$1",
},
};

export default config;
11 changes: 4 additions & 7 deletions relayer-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,14 @@
},
"scripts": {
"test": "jest --coverage",
"start-devnet-relayer": "npx ts-node ./src/devnetRelayExample.ts",
"start-testnet-relayer": "npx ts-node ./src/testnetRelayer.ts"
"start-relayer": "ts-node ./src/relayer.ts"
},
"dependencies": {
"@kleros/vea-contracts": "workspace:^",
"@typechain/ethers-v5": "^11.1.2",
"@typechain/ethers-v6": "^0.5.1",
"dotenv": "^16.4.5",
"pm2": "^5.2.2",
"typescript": "^4.9.5",
"web3": "^1.10.4",
"web3-batched-send": "^1.0.3"
"pm2": "^6.0.5",
"typescript": "^4.9.5"
},
"devDependencies": {
"@types/jest": "^29.5.14",
Expand Down
89 changes: 58 additions & 31 deletions relayer-cli/src/consts/bridgeRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,88 @@
// 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";
import veaInboxArbToEthDevnet from "@kleros/vea-contracts/deployments/arbitrumSepolia/VeaInboxArbToEthDevnet.json";
import veaOutboxArbToEthDevnet from "@kleros/vea-contracts/deployments/sepolia/VeaOutboxArbToEthDevnet.json";
import veaInboxArbToEthTestnet from "@kleros/vea-contracts/deployments/arbitrumSepolia/VeaInboxArbToEthTestnet.json";
import veaOutboxArbToEthTestnet from "@kleros/vea-contracts/deployments/sepolia/VeaOutboxArbToEthTestnet.json";

import veaInboxArbToGnosisDevnet from "@kleros/vea-contracts/deployments/arbitrumSepolia/VeaInboxArbToGnosisDevnet.json";
import veaOutboxArbToGnosisDevnet from "@kleros/vea-contracts/deployments/chiado/VeaOutboxArbToGnosisDevnet.json";

import veaInboxArbToGnosisTestnet from "@kleros/vea-contracts/deployments/arbitrumSepolia/VeaInboxArbToGnosisTestnet.json";
import veaOutboxArbToGnosisTestnet from "@kleros/vea-contracts/deployments/chiado/VeaOutboxArbToGnosisTestnet.json";

interface IBridge {
chainId: number;
chain: string;
epochPeriod: number;
veaInboxAddress: string;
veaOutboxAddress: string;
batcher: string;
veaContracts: { [key in Network]: VeaContracts };
batcherAddress: string;
rpcOutbox: string;
veaOutboxContract: any;
}

type VeaContracts = {
veaInbox: any;
veaOutbox: any;
};

enum Network {
DEVNET = "devnet",
TESTNET = "testnet",
}

const arbToEthContracts: { [key in Network]: VeaContracts } = {
[Network.DEVNET]: {
veaInbox: veaInboxArbToEthDevnet,
veaOutbox: veaOutboxArbToEthDevnet,
},
[Network.TESTNET]: {
veaInbox: veaInboxArbToEthTestnet,
veaOutbox: veaOutboxArbToEthTestnet,
},
};

const arbToGnosisContracts: { [key in Network]: VeaContracts } = {
[Network.DEVNET]: {
veaInbox: veaInboxArbToGnosisDevnet,
veaOutbox: veaOutboxArbToGnosisDevnet,
},
[Network.TESTNET]: {
veaInbox: veaInboxArbToGnosisTestnet,
veaOutbox: veaOutboxArbToGnosisTestnet,
},
};

// Using destination chainId to get the route configuration.
const bridges: { [chainId: number]: IBridge } = {
11155111: {
chainId: 11155111,
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,
veaContracts: arbToEthContracts,
batcherAddress: process.env.TRANSACTION_BATCHER_CONTRACT_SEPOLIA!,
rpcOutbox: process.env.RPC_SEPOLIA!,
},
10200: {
chainId: 10200,
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,
veaContracts: arbToGnosisContracts,
batcherAddress: process.env.TRANSACTION_BATCHER_CONTRACT_CHIADO!,
rpcOutbox: process.env.RPC_CHIADO!,
},
};

// Getters
const getBridgeConfig = (chainId: number): IBridge | undefined => {
return bridges[chainId];
const getBridgeConfig = (chainId: number): IBridge => {
const bridge = bridges[chainId];
if (!bridge) throw new Error(`Unsupported chainId: ${chainId}`);
return bridge;
};

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");
}
const bridge = bridges[chainId];
if (!bridge.epochPeriod) throw new Error(`Unsupported chainId: ${chainId}`);
return bridge.epochPeriod;
};

export { getBridgeConfig, getInboxSubgraph, getEpochPeriod };
export { getBridgeConfig, getEpochPeriod, Network };
29 changes: 0 additions & 29 deletions relayer-cli/src/devnetRelayExample.ts

This file was deleted.

95 changes: 95 additions & 0 deletions relayer-cli/src/relayer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
require("dotenv").config();
import { EventEmitter } from "node:events";
import { ethers } from "ethers";
import { relayBatch, relayAllFrom } from "./utils/relay";
import {
initialize as initializeNonce,
updateStateFile,
delay,
setupExitHandlers,
ShutdownManager,
getNetworkConfig,
RelayerNetworkConfig,
} from "./utils/relayerHelpers";
import { initialize as initializeEmitter } from "./utils/logger";
import { BotEvents } from "./utils/botEvents";
import { getEpochPeriod, Network } from "./consts/bridgeRoutes";

interface RelayerConfig {
networkConfigs: RelayerNetworkConfig[];
shutdownManager: ShutdownManager;
emitter: EventEmitter;
}

/**
* Start the relayer
* @param config.networkConfigs The network configurations retrieved from the env.
* @param config.shutdownManager The shutdown manager
* @param config.emitter The event emitter
*/
export async function start({ networkConfigs, shutdownManager, emitter }: RelayerConfig) {
initializeEmitter(emitter);
let delayAmount = 7200 * 1000; // 2 hours in ms
while (!shutdownManager.getIsShuttingDown()) {
for (const networkConfig of networkConfigs) {
delayAmount = await processNetworkConfig(networkConfig, shutdownManager, emitter, delayAmount);
}
emitter.emit(BotEvents.WAITING, delayAmount);
await delay(delayAmount);
}
}

/**
* Process the network configuration
* @param networkConfig The network configuration
* @param shutdownManager The shutdown manager
* @param emitter The event emitter
* @param currentDelay The current delay
* @returns The new delay
*/
async function processNetworkConfig(
networkConfig: RelayerNetworkConfig,
shutdownManager: ShutdownManager,
emitter: EventEmitter,
currentDelay: number
): Promise<number> {
const { chainId, network, senders } = networkConfig;
emitter.emit(BotEvents.STARTED, chainId, network);
const maxBatchSize = 10; // 10 messages per batch

await setupExitHandlers(chainId, shutdownManager, network, emitter);

let nonce = await initializeNonce(chainId, network, emitter);
if (nonce == null) return currentDelay;

const toRelayAll = senders[0] === ethers.ZeroAddress;
nonce = toRelayAll
? await relayBatch({ chainId, network, nonce, maxBatchSize, emitter })
: await relayAllFrom(chainId, network, nonce, senders, emitter);

if (nonce == null) return currentDelay;

await updateStateFile(chainId, Math.floor(Date.now() / 1000), nonce, network, emitter);

if (network === Network.DEVNET) {
return 1000 * 10; // 10 seconds for devnet
} else {
const currentTS = Math.floor(Date.now() / 1000);
const epochPeriod = getEpochPeriod(chainId);
const timeLeft = (epochPeriod - (Math.floor(currentTS / 1000) % epochPeriod)) * 1000 + 100 * 1000;
return Math.min(currentDelay, timeLeft);
}
}

if (require.main === module) {
const emitter = new EventEmitter();
const shutdownManager = new ShutdownManager(false);
const networkConfigs = getNetworkConfig();
const testnetRelayerConfig: RelayerConfig = {
networkConfigs,
shutdownManager,
emitter,
};

start(testnetRelayerConfig);
}
Loading