Skip to content

Commit 3d8a8c3

Browse files
committed
test(arbToGno): mock contract for native bridges and tokens
1 parent b3902bb commit 3d8a8c3

File tree

5 files changed

+174
-8
lines changed

5 files changed

+174
-8
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
/// @custom:authors: [@madhurMongia]
4+
/// @custom:reviewers: []
5+
/// @custom:auditors: []
6+
/// @custom:bounties: []
7+
/// @custom:deployments: []
8+
9+
pragma solidity 0.8.24;
10+
11+
import "../../arbitrumToGnosis/VeaInboxArbToGnosis.sol";
12+
import "../../canonical/arbitrum/IArbSys.sol";
13+
import "../../interfaces/routers/IRouterToGnosis.sol";
14+
15+
contract VeaInboxArbToGnosisMock is VeaInboxArbToGnosis {
16+
IArbSys public immutable mockArbSys;
17+
18+
constructor(
19+
uint256 _epochPeriod,
20+
address _routerArbToGnosis,
21+
IArbSys _mockArbSys
22+
) VeaInboxArbToGnosis(_epochPeriod, _routerArbToGnosis) {
23+
mockArbSys = _mockArbSys;
24+
}
25+
26+
// Override sendSnapshot to use the mock ArbSys
27+
function sendSnapshot(uint256 _epoch, uint256 _gasLimit, Claim memory _claim) external override {
28+
unchecked {
29+
require(_epoch < block.timestamp / epochPeriod, "Can only send past epoch snapshot.");
30+
}
31+
32+
bytes memory data = abi.encodeCall(IRouterToGnosis.route, (_epoch, snapshots[_epoch], _gasLimit, _claim));
33+
34+
// Use the mock ArbSys instead of the constant ARB_SYS
35+
bytes32 ticketID = bytes32(mockArbSys.sendTxToL1(routerArbToGnosis, data));
36+
37+
emit SnapshotSent(_epoch, ticketID);
38+
}
39+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
/// @custom:authors: [@madhurMongia]
4+
/// @custom:reviewers: []
5+
/// @custom:auditors: []
6+
/// @custom:bounties: []
7+
/// @custom:deployments: []
8+
9+
pragma solidity 0.8.24;
10+
11+
import "../../../canonical/arbitrum/IArbSys.sol";
12+
import "./BridgeMock.sol";
13+
14+
contract ArbSysMockWithBridge is IArbSys {
15+
BridgeMock public immutable bridge;
16+
17+
constructor(BridgeMock _bridge) {
18+
bridge = _bridge;
19+
}
20+
21+
function sendTxToL1(
22+
address destination,
23+
bytes calldata calldataForL1
24+
) external payable returns (uint256 _withdrawal_ID) {
25+
return bridge.executeL1Message(destination, calldataForL1);
26+
}
27+
}

contracts/src/test/bridge-mocks/arbitrum/BridgeMock.sol

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: MIT
22

3-
/// @custom:authors: [@hrishibhat]
3+
/// @custom:authors: [@hrishibhat,@madhurMongia]
44
/// @custom:reviewers: []
55
/// @custom:auditors: []
66
/// @custom:bounties: []
@@ -27,4 +27,17 @@ contract BridgeMock is IBridge {
2727
if (index == 0) return sequencerInbox;
2828
return address(0);
2929
}
30+
31+
function executeL1Message(address destination, bytes calldata data) external returns (uint256) {
32+
// Simulate the bridge calling the destination contract
33+
(bool success, bytes memory returnData) = destination.call(data);
34+
35+
if (!success) {
36+
assembly {
37+
revert(add(returnData, 32), mload(returnData))
38+
}
39+
}
40+
41+
return 0;
42+
}
3043
}

contracts/src/test/bridge-mocks/gnosis/MockAMB.sol

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pragma solidity 0.8.24;
55
import "../../../canonical/gnosis-chain/IAMB.sol";
66

77
contract MockAMB is IAMB {
8-
event MockedEvent(bytes32 indexed messageId, bytes encodedData);
8+
event MockedEvent(bytes32 indexed messageId, bytes encodedData, bytes _data);
99

1010
address public messageSender;
1111
uint256 public maxGasPerTx;
@@ -34,8 +34,14 @@ contract MockAMB is IAMB {
3434
messageSender = _sender;
3535
messageId = _messageId;
3636
transactionHash = _messageId;
37-
messageSourceChainId = bytes32(uint256(1337));
38-
(bool status, ) = _contract.call{gas: _gas}(_data);
37+
messageSourceChainId = bytes32(uint256(31337));
38+
(bool status, bytes memory returnData) = _contract.call{gas: _gas}(_data);
39+
40+
if (!status) {
41+
assembly {
42+
revert(add(returnData, 32), mload(returnData))
43+
}
44+
}
3945
messageSender = address(0);
4046
messageId = bytes32(0);
4147
transactionHash = bytes32(0);
@@ -64,7 +70,7 @@ contract MockAMB is IAMB {
6470
uint256 _dataType
6571
) internal returns (bytes32) {
6672
require(messageId == bytes32(0));
67-
bytes32 bridgeId = keccak256(abi.encodePacked(uint16(1337), address(this))) &
73+
bytes32 bridgeId = keccak256(abi.encodePacked(uint16(31337), address(this))) &
6874
0x00000000ffffffffffffffffffffffffffffffffffffffff0000000000000000;
6975

7076
bytes32 _messageId = bytes32(uint256(0x11223344 << 224)) | bridgeId | bytes32(uint256(nonce));
@@ -77,12 +83,12 @@ contract MockAMB is IAMB {
7783
uint8(2),
7884
uint8(2),
7985
uint8(_dataType),
80-
uint16(1337),
81-
uint16(1338),
86+
uint16(31337),
87+
uint16(31337),
8288
_data
8389
);
8490

85-
emit MockedEvent(_messageId, eventData);
91+
emit MockedEvent(_messageId, eventData, _data);
8692
return _messageId;
8793
}
8894

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
/// @custom:authors: [@madhurMongia]
4+
/// @custom:reviewers: []
5+
/// @custom:auditors: []
6+
/// @custom:bounties: []
7+
/// @custom:deployments: []
8+
9+
pragma solidity ^0.8.0;
10+
11+
contract MockWETH {
12+
string public name = "Wrapped Ether";
13+
string public symbol = "WETH";
14+
uint8 public decimals = 18;
15+
16+
event Approval(address indexed src, address indexed guy, uint wad);
17+
event Transfer(address indexed src, address indexed dst, uint wad);
18+
event Deposit(address indexed dst, uint wad);
19+
event Withdrawal(address indexed src, uint wad);
20+
21+
mapping(address => uint) public balanceOf;
22+
mapping(address => mapping(address => uint)) public allowance;
23+
24+
receive() external payable {
25+
deposit();
26+
}
27+
28+
function deposit() public payable {
29+
balanceOf[msg.sender] += msg.value;
30+
emit Deposit(msg.sender, msg.value);
31+
}
32+
33+
function withdraw(uint wad) public {
34+
require(balanceOf[msg.sender] >= wad, "WETH: insufficient balance");
35+
balanceOf[msg.sender] -= wad;
36+
payable(msg.sender).transfer(wad);
37+
emit Withdrawal(msg.sender, wad);
38+
}
39+
40+
function totalSupply() public view returns (uint) {
41+
return address(this).balance;
42+
}
43+
44+
function approve(address guy, uint wad) public returns (bool) {
45+
allowance[msg.sender][guy] = wad;
46+
emit Approval(msg.sender, guy, wad);
47+
return true;
48+
}
49+
50+
function transfer(address dst, uint wad) public returns (bool) {
51+
return transferFrom(msg.sender, dst, wad);
52+
}
53+
54+
function transferFrom(address src, address dst, uint wad) public returns (bool) {
55+
require(balanceOf[src] >= wad, "WETH: insufficient balance");
56+
57+
if (src != msg.sender && allowance[src][msg.sender] != type(uint).max) {
58+
require(allowance[src][msg.sender] >= wad, "WETH: insufficient allowance");
59+
allowance[src][msg.sender] -= wad;
60+
}
61+
62+
balanceOf[src] -= wad;
63+
balanceOf[dst] += wad;
64+
65+
emit Transfer(src, dst, wad);
66+
67+
return true;
68+
}
69+
70+
// This function is added for convenience in testing
71+
function mintMock(address to, uint256 amount) public {
72+
balanceOf[to] += amount;
73+
emit Transfer(address(0), to, amount);
74+
}
75+
76+
function burn(uint wad) public {
77+
require(balanceOf[msg.sender] >= wad, "WETH: insufficient balance");
78+
balanceOf[msg.sender] -= wad;
79+
emit Transfer(msg.sender, address(0), wad);
80+
}
81+
}

0 commit comments

Comments
 (0)