Skip to content

Commit

Permalink
Merge pull request #319 from kleros/test/integration-arbitrum-to-gnosis
Browse files Browse the repository at this point in the history
Test/integration arbitrum to gnosis
  • Loading branch information
jaybuidl authored Nov 20, 2024
2 parents e22031e + 46247de commit 9f97125
Show file tree
Hide file tree
Showing 9 changed files with 1,247 additions and 48 deletions.
56 changes: 43 additions & 13 deletions contracts/deploy/01-outbox/01-arb-to-gnosis-outbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,17 @@ const paramsByChainId = {
sequencerLimit: 86400, // 24 hours
},
HARDHAT: {
deposit: parseEther("5"), // 120 xDAI budget for timeout
deposit: parseEther("10"),
// Average happy path wait time is 22.5 mins, assume no censorship
epochPeriod: 600, // 10 min
challengePeriod: 600, // 10 min (assume no sequencer backdating)
numEpochTimeout: 24, // 6 hours
minChallengePeriod: 600, // 10 min (assume no sequencer backdating)
numEpochTimeout: 21600, // 6 hours
claimDelay: 2,
amb: ethers.constants.AddressZero,
routerAddress: ethers.constants.AddressZero,
maxMissingBlocks: 10000000000000,
routerChainId: 31337,
sequencerLimit: 86400, // 24 hours
sequencerLimit: 864,
},
};

Expand All @@ -56,8 +56,15 @@ const deployOutbox: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const { providers } = ethers;

// fallback to hardhat node signers on local network
const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
const chainId = Number(await getChainId());
const [namedAccounts, signers, rawChainId] = await Promise.all([
getNamedAccounts(),
hre.ethers.getSigners(),
getChainId(),
]);

const deployer = namedAccounts.deployer ?? signers[0].address;
const chainId = Number(rawChainId);

console.log("deploying to chainId %s with deployer %s", chainId, deployer);

const routerNetworks = {
Expand All @@ -84,27 +91,50 @@ const deployOutbox: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
// ----------------------------------------------------------------------------------------------
const hardhatDeployer = async () => {
let nonce = await ethers.provider.getTransactionCount(deployer);
nonce += 4; // SenderGatewayToEthereum deploy tx will be the 5th after this, same network for both sender/receiver.

const routerAddress = getContractAddress(deployer, nonce);
console.log("calculated future router for nonce %d: %s", nonce, routerAddress);
const routerAddress = getContractAddress(deployer, nonce + 10);
console.log("calculated future router for nonce %d: %s", nonce + 10, routerAddress);

const senderGatewayAddress = getContractAddress(deployer, nonce + 6); // with the current order of transaction ,nonce for sender gateway would be 14.
console.log("calculated future SenderGatewayToGnosis address for nonce %d: %s", nonce + 6, senderGatewayAddress);

await deploy("VeaOutboxGnosisMock", {
const ambMock = await deploy("MockAMB", {
from: deployer,
args: [],
log: true,
});

const wethMock = await deploy("MockWETH", {
from: deployer,
args: [],
log: true,
});

const veaOutbox = await deploy("VeaOutboxArbToGnosis", {
from: deployer,
contract: "VeaOutboxArbToGnosis",
args: [
deposit,
epochPeriod,
minChallengePeriod,
numEpochTimeout,
amb,
ethers.constants.AddressZero,
ambMock.address,
routerAddress,
sequencerLimit,
maxMissingBlocks,
routerChainId,
WETH,
wethMock.address,
],
log: true,
});

await deploy("ArbToGnosisReceiverGateway", {
from: deployer,
contract: "ReceiverGatewayMock",
args: [veaOutbox.address, senderGatewayAddress],
gasLimit: 4000000,
log: true,
});
};

// ----------------------------------------------------------------------------------------------
Expand Down
73 changes: 53 additions & 20 deletions contracts/deploy/02-inbox/02-arb-to-gnosis-inbox.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import getContractAddress from "../../deploy-helpers/getContractAddress";
import { ethers } from "hardhat";

enum SenderChains {
ARBITRUM = 42161,
ARBITRUM_SEPOLIA = 421614,
HARDHAT = 31337,
}

const paramsByChainId = {
ARBITRUM: {
epochPeriod: 3600, // 1 hours
Expand All @@ -19,38 +21,69 @@ const paramsByChainId = {
},
};

// TODO: use deterministic deployments
const deployInbox: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const { ethers, deployments, getNamedAccounts, getChainId, config } = hre;
const { deploy } = deployments;
const chainId = Number(await getChainId());
const { providers } = ethers;

const deployer = (await getNamedAccounts()).deployer;
console.log("deployer: %s", deployer);
// fallback to hardhat node signers on local network
const [namedAccounts, signers, rawChainId] = await Promise.all([
getNamedAccounts(),
hre.ethers.getSigners(),
getChainId(),
]);

const deployer = namedAccounts.deployer ?? signers[0].address;
const chainId = Number(rawChainId);

console.log("deploying to chainId %s with deployer %s", chainId, deployer);

const { epochPeriod } = paramsByChainId[SenderChains[chainId]];

const routerNetworks = {
ARBITRUM: config.networks.mainnet,
ARBITRUM_SEPOLIA: config.networks.sepolia,
HARDHAT: config.networks.localhost,
};
// Hack to predict the deployment address on the sender chain.
// TODO: use deterministic deployments

// ----------------------------------------------------------------------------------------------
const hardhatDeployer = async () => {
let nonce = await ethers.provider.getTransactionCount(deployer);

const arbitrumBridgeAddress = getContractAddress(deployer, nonce + 5);

const routerChainProvider = new providers.JsonRpcProvider(routerNetworks[SenderChains[chainId]].url);
let nonceRouter = await routerChainProvider.getTransactionCount(deployer);
const arbSysMock = await deploy("ArbSysMock", {
from: deployer,
contract: "ArbSysMockWithBridge",
args: [arbitrumBridgeAddress],
log: true,
});

const routerAddress = getContractAddress(deployer, nonceRouter);
console.log("calculated future router for nonce %d: %s", nonceRouter, routerAddress);
const routerAddress = getContractAddress(deployer, nonce + 6);
console.log("calculated future router for nonce %d: %s", nonce + 6, routerAddress);

await deploy("VeaInboxArbToGnosis" + (chainId === 42161 ? "" : "Testnet"), {
contract: "VeaInboxArbToGnosis",
from: deployer,
args: [epochPeriod, routerAddress],
log: true,
});
const receiverGateway = await deployments.get("ArbToGnosisReceiverGateway");
const veaInbox = await deploy("VeaInboxArbToGnosis", {
from: deployer,
contract: "VeaInboxArbToGnosisMock",
args: [epochPeriod, routerAddress, arbSysMock.address],
log: true,
});

await deploy("ArbToGnosisSenderGateway", {
from: deployer,
contract: "SenderGatewayMock",
args: [veaInbox.address, receiverGateway.address],
gasLimit: 4000000,
log: true,
});
};

// ----------------------------------------------------------------------------------------------
const liveDeployer = async () => {};

// ----------------------------------------------------------------------------------------------
if (chainId === 31337) {
await hardhatDeployer();
} else {
await liveDeployer();
}
};

deployInbox.tags = ["ArbToGnosisInbox"];
Expand Down
40 changes: 33 additions & 7 deletions contracts/deploy/03-routers/03-arb-to-gnosis-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,50 @@ const paramsByChainId = {
const deployRouter: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const { deployments, getNamedAccounts, getChainId } = hre;
const { deploy } = deployments;
const chainId = Number(await getChainId());

// fallback to hardhat node signers on local network
const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
console.log("deployer: %s", deployer);
const [namedAccounts, signers, rawChainId] = await Promise.all([
getNamedAccounts(),
hre.ethers.getSigners(),
getChainId(),
]);

const deployer = namedAccounts.deployer ?? signers[0].address;
const chainId = Number(rawChainId);

console.log("deploying to chainId %s with deployer %s", chainId, deployer);

const { arbitrumBridge, amb } = paramsByChainId[RouterChains[chainId]];

// ----------------------------------------------------------------------------------------------
const hardhatDeployer = async () => {
const veaOutbox = await deployments.get("VeaOutboxArbToGnosis");
const veaInbox = await deployments.get("VeaInboxArbToGnosis");
const [veaOutbox, veaInbox, amb] = await Promise.all([
deployments.get("VeaOutboxArbToGnosis"),
deployments.get("VeaInboxArbToGnosis"),
deployments.get("MockAMB"),
]);

const sequencerInbox = await deploy("SequencerInboxMock", {
from: deployer,
contract: "SequencerInboxMock",
args: ["10"],
});
const outbox = await deploy("OutboxMock", {
from: deployer,
args: [veaInbox.address],
log: true,
});

const arbitrumBridge = await deploy("BridgeMock", {
from: deployer,
contract: "BridgeMock",
args: [outbox.address, sequencerInbox.address],
});

const router = await deploy("RouterArbToGnosis", {
from: deployer,
contract: "RouterArbToGnosis",
args: [arbitrumBridge, amb, veaInbox.address, veaOutbox.address],
args: [arbitrumBridge.address, amb.address, veaInbox.address, veaOutbox.address],
});
};

Expand Down Expand Up @@ -73,7 +100,6 @@ const deployRouter: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
deployRouter.tags = ["ArbToGnosisRouter"];
deployRouter.skip = async ({ getChainId }) => {
const chainId = Number(await getChainId());
console.log(chainId);
return !RouterChains[chainId];
};
deployRouter.runAtTheEnd = true;
Expand Down
39 changes: 39 additions & 0 deletions contracts/src/test/ArbToGnosis/VeaInboxArbToGnosisMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MIT

/// @custom:authors: [@madhurMongia]
/// @custom:reviewers: []
/// @custom:auditors: []
/// @custom:bounties: []
/// @custom:deployments: []

pragma solidity 0.8.24;

import "../../arbitrumToGnosis/VeaInboxArbToGnosis.sol";
import "../../canonical/arbitrum/IArbSys.sol";
import "../../interfaces/routers/IRouterToGnosis.sol";

contract VeaInboxArbToGnosisMock is VeaInboxArbToGnosis {
IArbSys public immutable mockArbSys;

constructor(
uint256 _epochPeriod,
address _routerArbToGnosis,
IArbSys _mockArbSys
) VeaInboxArbToGnosis(_epochPeriod, _routerArbToGnosis) {
mockArbSys = _mockArbSys;
}

// Override sendSnapshot to use the mock ArbSys
function sendSnapshot(uint256 _epoch, uint256 _gasLimit, Claim memory _claim) external override {
unchecked {
require(_epoch < block.timestamp / epochPeriod, "Can only send past epoch snapshot.");
}

bytes memory data = abi.encodeCall(IRouterToGnosis.route, (_epoch, snapshots[_epoch], _gasLimit, _claim));

// Use the mock ArbSys instead of the constant ARB_SYS
bytes32 ticketID = bytes32(mockArbSys.sendTxToL1(routerArbToGnosis, data));

emit SnapshotSent(_epoch, ticketID);
}
}
27 changes: 27 additions & 0 deletions contracts/src/test/bridge-mocks/arbitrum/ArbSysMockWithBridge.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT

/// @custom:authors: [@madhurMongia]
/// @custom:reviewers: []
/// @custom:auditors: []
/// @custom:bounties: []
/// @custom:deployments: []

pragma solidity 0.8.24;

import "../../../canonical/arbitrum/IArbSys.sol";
import "./BridgeMock.sol";

contract ArbSysMockWithBridge is IArbSys {
BridgeMock public immutable bridge;

constructor(BridgeMock _bridge) {
bridge = _bridge;
}

function sendTxToL1(
address destination,
bytes calldata calldataForL1
) external payable returns (uint256 _withdrawal_ID) {
return bridge.executeL1Message(destination, calldataForL1);
}
}
15 changes: 14 additions & 1 deletion contracts/src/test/bridge-mocks/arbitrum/BridgeMock.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT

/// @custom:authors: [@hrishibhat]
/// @custom:authors: [@hrishibhat,@madhurMongia]
/// @custom:reviewers: []
/// @custom:auditors: []
/// @custom:bounties: []
Expand All @@ -27,4 +27,17 @@ contract BridgeMock is IBridge {
if (index == 0) return sequencerInbox;
return address(0);
}

function executeL1Message(address destination, bytes calldata data) external returns (uint256) {
// Simulate the bridge calling the destination contract
(bool success, bytes memory returnData) = destination.call(data);

if (!success) {
assembly {
revert(add(returnData, 32), mload(returnData))
}
}

return 0;
}
}
Loading

0 comments on commit 9f97125

Please sign in to comment.