Skip to content

Commit

Permalink
refactor integration tests to make it easier to add many domains
Browse files Browse the repository at this point in the history
  • Loading branch information
hexonaut committed Jun 27, 2024
1 parent 9374feb commit 44110d8
Show file tree
Hide file tree
Showing 13 changed files with 195 additions and 189 deletions.
42 changes: 10 additions & 32 deletions test/ArbitrumOneCrosschainTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,55 +7,33 @@ import { ArbitrumBridgeTesting } from 'lib/xchain-helpers/src/testing/bridges/Ar
import { ArbitrumForwarder } from 'lib/xchain-helpers/src/forwarders/ArbitrumForwarder.sol';
import { ArbitrumReceiver } from 'lib/xchain-helpers/src/receivers/ArbitrumReceiver.sol';

contract ArbitrumOneCrosschainPayload is CrosschainPayload {

constructor(IPayload _targetPayload, address _bridgeReceiver)
CrosschainPayload(_targetPayload, _bridgeReceiver) {}

function execute() external override {
ArbitrumForwarder.sendMessageL1toL2(
ArbitrumForwarder.L1_CROSS_DOMAIN_ARBITRUM_ONE,
bridgeReceiver,
encodeCrosschainExecutionMessage(),
1_000_000,
1 gwei,
block.basefee + 10 gwei
);
}

}
import { ArbitrumCrosschainPayload } from './payloads/ArbitrumCrosschainPayload.sol';

contract ArbitrumOneCrosschainTest is CrosschainTestBase {

using DomainHelpers for *;
using ArbitrumBridgeTesting for *;

function deployCrosschainPayload(IPayload targetPayload, address bridgeReceiver)
public override returns (IPayload)
internal override returns (IPayload)
{
return IPayload(new ArbitrumOneCrosschainPayload(targetPayload, bridgeReceiver));
return IPayload(new ArbitrumCrosschainPayload(ArbitrumForwarder.L1_CROSS_DOMAIN_ARBITRUM_ONE, targetPayload, bridgeReceiver));
}

function setUp() public {
function setupDomain() internal override {
remote = getChain('arbitrum_one').createFork();
bridge = ArbitrumBridgeTesting.createNativeBridge(
getChain('mainnet').createFork(),
getChain('arbitrum_one').createFork()
mainnet,
remote
);

bridge.destination.selectFork();
bridgeExecutor = new Executor(
defaultL2BridgeExecutorArgs.delay,
defaultL2BridgeExecutorArgs.gracePeriod
);
remote.selectFork();
bridgeReceiver = address(new ArbitrumReceiver(
defaultL2BridgeExecutorArgs.ethereumGovernanceExecutor,
address(bridgeExecutor)
vm.computeCreateAddress(address(this), 3)
));
bridgeExecutor.grantRole(bridgeExecutor.SUBMISSION_ROLE(), bridgeReceiver);
bridgeExecutor.grantRole(bridgeExecutor.GUARDIAN_ROLE(), defaultL2BridgeExecutorArgs.guardian);
bridgeExecutor.revokeRole(bridgeExecutor.DEFAULT_ADMIN_ROLE(), address(this));

bridge.source.selectFork();
mainnet.selectFork();
vm.deal(L1_EXECUTOR, 0.01 ether);
}

Expand Down
40 changes: 9 additions & 31 deletions test/BaseChainCrosschainTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,53 +7,31 @@ import { OptimismBridgeTesting } from 'lib/xchain-helpers/src/testing/bridges/Op
import { OptimismForwarder } from 'lib/xchain-helpers/src/forwarders/OptimismForwarder.sol';
import { OptimismReceiver } from 'lib/xchain-helpers/src/receivers/OptimismReceiver.sol';

contract BaseChainCrosschainPayload is CrosschainPayload {

constructor(IPayload _targetPayload, address _bridgeReceiver)
CrosschainPayload(_targetPayload, _bridgeReceiver) {}

function execute() external override {
OptimismForwarder.sendMessageL1toL2(
OptimismForwarder.L1_CROSS_DOMAIN_BASE,
bridgeReceiver,
encodeCrosschainExecutionMessage(),
1_000_000
);
}

}
import { OptimismCrosschainPayload } from './payloads/OptimismCrosschainPayload.sol';

contract BaseChainCrosschainTest is CrosschainTestBase {

using DomainHelpers for *;
using OptimismBridgeTesting for *;

function deployCrosschainPayload(IPayload targetPayload, address bridgeReceiver)
public override returns (IPayload)
internal override returns (IPayload)
{
return IPayload(new BaseChainCrosschainPayload(targetPayload, bridgeReceiver));
return IPayload(new OptimismCrosschainPayload(OptimismForwarder.L1_CROSS_DOMAIN_BASE, targetPayload, bridgeReceiver));
}

function setUp() public {
function setupDomain() internal override {
remote = getChain('base').createFork();
bridge = OptimismBridgeTesting.createNativeBridge(
getChain('mainnet').createFork(),
getChain('base').createFork()
mainnet,
remote
);

bridge.destination.selectFork();
bridgeExecutor = new Executor(
defaultL2BridgeExecutorArgs.delay,
defaultL2BridgeExecutorArgs.gracePeriod
);
remote.selectFork();
bridgeReceiver = address(new OptimismReceiver(
defaultL2BridgeExecutorArgs.ethereumGovernanceExecutor,
address(bridgeExecutor)
vm.computeCreateAddress(address(this), 2)
));
bridgeExecutor.grantRole(bridgeExecutor.SUBMISSION_ROLE(), bridgeReceiver);
bridgeExecutor.grantRole(bridgeExecutor.GUARDIAN_ROLE(), defaultL2BridgeExecutorArgs.guardian);
bridgeExecutor.revokeRole(bridgeExecutor.DEFAULT_ADMIN_ROLE(), address(this));

bridge.source.selectFork();
}

function relayMessagesAcrossBridge() internal override {
Expand Down
92 changes: 41 additions & 51 deletions test/CrosschainTestBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,92 +3,82 @@ pragma solidity ^0.8.0;

import 'forge-std/Test.sol';

import { Domain } from 'lib/xchain-helpers/src/testing/Domain.sol';
import { Bridge } from 'lib/xchain-helpers/src/testing/Bridge.sol';
import { DomainHelpers } from 'lib/xchain-helpers/src/testing/Domain.sol';

import { IExecutor } from 'src/interfaces/IExecutor.sol';
import { Executor } from 'src/Executor.sol';

import { IL1Executor } from './interfaces/IL1Executor.sol';
import { IPayload } from './interfaces/IPayload.sol';
import { IPayload } from './payloads/IPayload.sol';

import { PayloadWithEmit } from './mocks/PayloadWithEmit.sol';
import { ReconfigurationPayload } from './mocks/ReconfigurationPayload.sol';

interface IL1Executor {
function exec(address target, bytes calldata args)
external
payable
returns (bytes memory out);
}

struct L2BridgeExecutorArguments {
address ethereumGovernanceExecutor;
uint256 delay;
uint256 gracePeriod;
address guardian;
}

abstract contract CrosschainPayload is IPayload {

IPayload immutable targetPayload;
address immutable bridgeReceiver;

constructor(IPayload _targetPayload, address _bridgeReceiver) {
targetPayload = _targetPayload;
bridgeReceiver = _bridgeReceiver;
}

function execute() external virtual;

function encodeCrosschainExecutionMessage() internal view returns (bytes memory) {
address[] memory targets = new address[](1);
targets[0] = address(targetPayload);
uint256[] memory values = new uint256[](1);
values[0] = 0;
string[] memory signatures = new string[](1);
signatures[0] = 'execute()';
bytes[] memory calldatas = new bytes[](1);
calldatas[0] = '';
bool[] memory withDelegatecalls = new bool[](1);
withDelegatecalls[0] = true;

return abi.encodeWithSelector(
IExecutor.queue.selector,
targets,
values,
signatures,
calldatas,
withDelegatecalls
);
}

}

abstract contract CrosschainTestBase is Test {

using DomainHelpers for *;

event TestEvent();

address public constant L1_EXECUTOR = 0x3300f198988e4C9C63F75dF86De36421f06af8c4;
address public constant L1_PAUSE_PROXY = 0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB;
address public GUARDIAN = makeAddr('guardian');
address constant L1_EXECUTOR = 0x3300f198988e4C9C63F75dF86De36421f06af8c4;
address constant L1_PAUSE_PROXY = 0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB;
address GUARDIAN = makeAddr('guardian');

L2BridgeExecutorArguments public defaultL2BridgeExecutorArgs = L2BridgeExecutorArguments({
L2BridgeExecutorArguments defaultL2BridgeExecutorArgs = L2BridgeExecutorArguments({
ethereumGovernanceExecutor: L1_EXECUTOR,
delay: 600,
gracePeriod: 1200,
guardian: GUARDIAN
});

Bridge public bridge;
Domain mainnet;
Domain remote;
Bridge bridge;

Executor bridgeExecutor;
address bridgeReceiver;

function setUp() public {
mainnet = getChain("mainnet").createFork();

setupDomain();

remote.selectFork();

Executor public bridgeExecutor;
address public bridgeReceiver;
bridgeExecutor = new Executor(
defaultL2BridgeExecutorArgs.delay,
defaultL2BridgeExecutorArgs.gracePeriod
);
bridgeExecutor.grantRole(bridgeExecutor.SUBMISSION_ROLE(), bridgeReceiver);
bridgeExecutor.grantRole(bridgeExecutor.GUARDIAN_ROLE(), defaultL2BridgeExecutorArgs.guardian);
bridgeExecutor.revokeRole(bridgeExecutor.DEFAULT_ADMIN_ROLE(), address(this));
}

function deployCrosschainPayload(IPayload targetPayload, address bridgeReceiver) public virtual returns (IPayload);
function deployCrosschainPayload(IPayload targetPayload, address bridgeReceiver) internal virtual returns (IPayload);
function relayMessagesAcrossBridge() internal virtual;
function setupDomain() internal virtual;

function preparePayloadExecution() public {
bridge.destination.selectFork();
function preparePayloadExecution() internal {
remote.selectFork();

IPayload targetPayload = IPayload(new PayloadWithEmit());

bridge.source.selectFork();
mainnet.selectFork();

IPayload crosschainPayload = deployCrosschainPayload(
targetPayload,
Expand Down Expand Up @@ -304,7 +294,7 @@ abstract contract CrosschainTestBase is Test {
}

function test_selfReconfiguration() public {
bridge.destination.selectFork();
remote.selectFork();

L2BridgeExecutorArguments memory newL2BridgeExecutorParams = L2BridgeExecutorArguments({
ethereumGovernanceExecutor: defaultL2BridgeExecutorArgs.ethereumGovernanceExecutor,
Expand Down Expand Up @@ -337,7 +327,7 @@ abstract contract CrosschainTestBase is Test {
newL2BridgeExecutorParams.guardian
));

bridge.source.selectFork();
mainnet.selectFork();

IPayload crosschainPayload = deployCrosschainPayload(
reconfigurationPayload,
Expand Down
38 changes: 8 additions & 30 deletions test/GnosisCrosschainTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,57 +4,35 @@ pragma solidity ^0.8.0;
import './CrosschainTestBase.sol';

import { AMBBridgeTesting } from 'lib/xchain-helpers/src/testing/bridges/AMBBridgeTesting.sol';
import { AMBForwarder } from 'lib/xchain-helpers/src/forwarders/AMBForwarder.sol';
import { AMBReceiver } from 'lib/xchain-helpers/src/receivers/AMBReceiver.sol';

contract GnosisCrosschainPayload is CrosschainPayload {

constructor(IPayload _targetPayload, address _bridgeReceiver)
CrosschainPayload(_targetPayload, _bridgeReceiver) {}

function execute() external override {
AMBForwarder.sendMessageEthereumToGnosisChain(
bridgeReceiver,
encodeCrosschainExecutionMessage(),
1_000_000
);
}

}
import { GnosisCrosschainPayload } from './payloads/GnosisCrosschainPayload.sol';

contract GnosisCrosschainTest is CrosschainTestBase {

using DomainHelpers for *;
using AMBBridgeTesting for *;

function deployCrosschainPayload(IPayload targetPayload, address bridgeReceiver)
public override returns (IPayload)
internal override returns (IPayload)
{
return IPayload(new GnosisCrosschainPayload(targetPayload, bridgeReceiver));
}

function setUp() public {
function setupDomain() internal override {
remote = getChain('gnosis_chain').createFork();
bridge = AMBBridgeTesting.createGnosisBridge(
getChain('mainnet').createFork(),
getChain('gnosis_chain').createFork()
mainnet,
remote
);

bridge.destination.selectFork();
bridgeExecutor = new Executor(
defaultL2BridgeExecutorArgs.delay,
defaultL2BridgeExecutorArgs.gracePeriod
);
remote.selectFork();
bridgeReceiver = address(new AMBReceiver(
AMBBridgeTesting.getGnosisMessengerFromChainAlias(bridge.destination.chain.chainAlias),
bytes32(uint256(1)), // Ethereum chainid
defaultL2BridgeExecutorArgs.ethereumGovernanceExecutor,
address(bridgeExecutor)
vm.computeCreateAddress(address(this), 2)
));
bridgeExecutor.grantRole(bridgeExecutor.SUBMISSION_ROLE(), bridgeReceiver);
bridgeExecutor.grantRole(bridgeExecutor.GUARDIAN_ROLE(), defaultL2BridgeExecutorArgs.guardian);
bridgeExecutor.revokeRole(bridgeExecutor.DEFAULT_ADMIN_ROLE(), address(this));

bridge.source.selectFork();
}

function relayMessagesAcrossBridge() internal override {
Expand Down
Loading

0 comments on commit 44110d8

Please sign in to comment.