Skip to content

Commit

Permalink
adds ArbitrumCrossDomainForwarder foundry tests
Browse files Browse the repository at this point in the history
  • Loading branch information
chris-de-leon-cll committed Jan 6, 2024
1 parent e9b0e56 commit edd4bfc
Showing 1 changed file with 197 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {ArbitrumCrossDomainForwarder} from "../../../dev/arbitrum/ArbitrumCrossDomainForwarder.sol";
import {Greeter} from "../../../../../v0.8/tests/Greeter.sol";
import {L2EPTest} from "../L2EPTest.t.sol";

// Use this command from the /contracts directory to run this test file:
//
// FOUNDRY_PROFILE=l2ep forge test -vvv --match-path ./src/v0.8/l2ep/test/v1_0_0/arbitrum/ArbitrumCrossDomainForwarder.t.sol
//
contract ArbitrumCrossDomainForwarderTest is L2EPTest {
/// Helper variables
address internal s_strangerAddr = vm.addr(0x1);
address internal s_l1OwnerAddr = vm.addr(0x2);
address internal s_crossDomainMessengerAddr = toArbitrumL2AliasAddress(s_l1OwnerAddr);
address internal s_newOwnerCrossDomainMessengerAddr = toArbitrumL2AliasAddress(s_strangerAddr);

/// Contracts
ArbitrumCrossDomainForwarder internal s_arbitrumCrossDomainForwarder;
Greeter internal s_greeter;

/// Events
event L1OwnershipTransferRequested(address indexed from, address indexed to);
event L1OwnershipTransferred(address indexed from, address indexed to);

/// Setup
function setUp() public {
// Deploys contracts
vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr);
s_arbitrumCrossDomainForwarder = new ArbitrumCrossDomainForwarder(s_l1OwnerAddr);
s_greeter = new Greeter(address(s_arbitrumCrossDomainForwarder));
vm.stopPrank();
}

/// @param l1Address - Address on L1
/// @return an Arbitrum L2 address
function toArbitrumL2AliasAddress(address l1Address) public pure returns (address) {
return address(uint160(l1Address) + uint160(0x1111000000000000000000000000000000001111));
}
}

contract Constructor is ArbitrumCrossDomainForwarderTest {
/// @notice it should set the owner correctly
function test_Owner() public {
assertEq(s_arbitrumCrossDomainForwarder.owner(), s_l1OwnerAddr);
}

/// @notice it should set the l1Owner correctly
function test_L1Owner() public {
assertEq(s_arbitrumCrossDomainForwarder.l1Owner(), s_l1OwnerAddr);
}

/// @notice it should set the crossdomain messenger correctly
function test_CrossDomainMessenger() public {
assertEq(s_arbitrumCrossDomainForwarder.crossDomainMessenger(), s_crossDomainMessengerAddr);
}

/// @notice it should set the typeAndVersion correctly
function test_TypeAndVersion() public {
assertEq(s_arbitrumCrossDomainForwarder.typeAndVersion(), "ArbitrumCrossDomainForwarder 1.0.0");
}
}

contract Forward is ArbitrumCrossDomainForwarderTest {
/// @notice it should not be callable by unknown address
function test_NotCallableByUnknownAddress() public {
vm.startPrank(s_strangerAddr, s_strangerAddr);
vm.expectRevert("Sender is not the L2 messenger");
s_arbitrumCrossDomainForwarder.forward(address(s_greeter), abi.encode(""));
vm.stopPrank();
}

/// @notice it should be callable by crossdomain messenger address / L1 owner
function test_Forward() public {
// Sets msg.sender and tx.origin
vm.startPrank(s_crossDomainMessengerAddr, s_crossDomainMessengerAddr);

// Defines the cross domain message to send
string memory greeting = "hello";

// Sends the message
s_arbitrumCrossDomainForwarder.forward(
address(s_greeter),
abi.encodeWithSelector(s_greeter.setGreeting.selector, greeting)
);

// Checks that the greeter got the message
assertEq(s_greeter.greeting(), greeting);

// Resets msg.sender and tx.origin
vm.stopPrank();
}

/// @notice it should revert when contract call reverts
function test_ForwardRevert() public {
// Sets msg.sender and tx.origin
vm.startPrank(s_crossDomainMessengerAddr, s_crossDomainMessengerAddr);

// Sends an invalid message
vm.expectRevert("Invalid greeting length");
s_arbitrumCrossDomainForwarder.forward(
address(s_greeter),
abi.encodeWithSelector(s_greeter.setGreeting.selector, "")
);

// Resets msg.sender and tx.origin
vm.stopPrank();
}
}

contract TransferL1Ownership is ArbitrumCrossDomainForwarderTest {
/// @notice it should not be callable by non-owners
function test_NotCallableByNonOwners() public {
vm.startPrank(s_strangerAddr, s_strangerAddr);
vm.expectRevert("Sender is not the L2 messenger");
s_arbitrumCrossDomainForwarder.transferL1Ownership(s_strangerAddr);
vm.stopPrank();
}

/// @notice it should not be callable by L2 owner
function test_NotCallableByL2Owner() public {
vm.startPrank(s_l1OwnerAddr, s_l1OwnerAddr);
assertEq(s_arbitrumCrossDomainForwarder.owner(), s_l1OwnerAddr);
vm.expectRevert("Sender is not the L2 messenger");
s_arbitrumCrossDomainForwarder.transferL1Ownership(s_strangerAddr);
vm.stopPrank();
}

/// @notice it should be callable by current L1 owner
function test_CallableByL1Owner() public {
// Sets msg.sender and tx.origin
vm.startPrank(s_crossDomainMessengerAddr, s_crossDomainMessengerAddr);

// Defines the cross domain message to send
vm.expectEmit(false, false, false, true);
emit L1OwnershipTransferRequested(s_arbitrumCrossDomainForwarder.l1Owner(), s_strangerAddr);

// Sends the message
s_arbitrumCrossDomainForwarder.transferL1Ownership(s_strangerAddr);

// Resets msg.sender and tx.origin
vm.stopPrank();
}

/// @notice it should be callable by current L1 owner to zero address
function test_CallableByL1OwnerOrZeroAddress() public {
// Sets msg.sender and tx.origin
vm.startPrank(s_crossDomainMessengerAddr, s_crossDomainMessengerAddr);

// Defines the cross domain message to send
vm.expectEmit(false, false, false, true);
emit L1OwnershipTransferRequested(s_arbitrumCrossDomainForwarder.l1Owner(), address(0));

// Sends the message
s_arbitrumCrossDomainForwarder.transferL1Ownership(address(0));

// Resets msg.sender and tx.origin
vm.stopPrank();
}
}

contract AcceptL1Ownership is ArbitrumCrossDomainForwarderTest {
/// @notice it should not be callable by non pending-owners
function test_NotCallableByNonPendingOwners() public {
// Sets msg.sender and tx.origin
vm.startPrank(s_crossDomainMessengerAddr, s_crossDomainMessengerAddr);

// Sends the message
vm.expectRevert("Must be proposed L1 owner");
s_arbitrumCrossDomainForwarder.acceptL1Ownership();

// Resets msg.sender and tx.origin
vm.stopPrank();
}

/// @notice it should be callable by pending L1 owner
function test_CallableByPendingL1Owner() public {
// Request ownership transfer
vm.startPrank(s_crossDomainMessengerAddr, s_crossDomainMessengerAddr);
s_arbitrumCrossDomainForwarder.transferL1Ownership(s_strangerAddr);

// Prepares expected event payload
vm.expectEmit(false, false, false, true);
emit L1OwnershipTransferred(s_l1OwnerAddr, s_strangerAddr);

// Accepts ownership transfer request
vm.startPrank(s_newOwnerCrossDomainMessengerAddr, s_newOwnerCrossDomainMessengerAddr);
s_arbitrumCrossDomainForwarder.acceptL1Ownership();

// Asserts that the ownership was actually transferred
assertEq(s_arbitrumCrossDomainForwarder.l1Owner(), s_strangerAddr);

// Resets msg.sender and tx.origin
vm.stopPrank();
}
}

0 comments on commit edd4bfc

Please sign in to comment.