forked from ethereum-optimism/optimism
-
Notifications
You must be signed in to change notification settings - Fork 3
test: add superchain erc20 bridge tests #65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
agusduha
merged 6 commits into
sc/superchain-erc20-redesign
from
test/superchain-erc20-bridge
Sep 27, 2024
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
f119054
test: add superchain erc20 bridge tests
agusduha bb0afae
Merge branch 'sc/superchain-erc20-redesign' into test/superchain-erc2…
agusduha 774432b
test: add optimism superchain erc20 beacon tests
agusduha cc7b06b
test: remove unnecessary test
agusduha 2694a4a
test: tests fixes
agusduha 7292db9
test: tests fixes
agusduha File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
packages/contracts-bedrock/src/L2/interfaces/IOptimismSuperchainERC20Factory.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.0; | ||
|
|
||
| import { IOptimismERC20Factory } from "./IOptimismERC20Factory.sol"; | ||
|
|
||
| /// @title IOptimismSuperchainERC20Factory | ||
| /// @notice Interface for OptimismSuperchainERC20Factory. | ||
| interface IOptimismSuperchainERC20Factory is IOptimismERC20Factory { | ||
| /// @notice Deploys a OptimismSuperchainERC20 Beacon Proxy using CREATE3. | ||
| /// @param _remoteToken Address of the remote token. | ||
| /// @param _name Name of the OptimismSuperchainERC20. | ||
| /// @param _symbol Symbol of the OptimismSuperchainERC20. | ||
| /// @param _decimals Decimals of the OptimismSuperchainERC20. | ||
| /// @return _superchainERC20 Address of the OptimismSuperchainERC20 deployment. | ||
| function deploy( | ||
| address _remoteToken, | ||
| string memory _name, | ||
| string memory _symbol, | ||
| uint8 _decimals | ||
| ) | ||
| external | ||
| returns (address _superchainERC20); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
179 changes: 179 additions & 0 deletions
179
packages/contracts-bedrock/test/L2/SuperchainERC20Bridge.t.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,179 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity 0.8.15; | ||
|
|
||
| // Testing utilities | ||
| import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; | ||
|
|
||
| // Libraries | ||
| import { Predeploys } from "src/libraries/Predeploys.sol"; | ||
| import { IL2ToL2CrossDomainMessenger } from "src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol"; | ||
|
|
||
| // Target contract | ||
| import { ISuperchainERC20Bridge } from "src/L2/interfaces/ISuperchainERC20Bridge.sol"; | ||
| import { IOptimismSuperchainERC20 } from "src/L2/interfaces/IOptimismSuperchainERC20.sol"; | ||
| import { IOptimismSuperchainERC20Factory } from "src/L2/interfaces/IOptimismSuperchainERC20Factory.sol"; | ||
|
|
||
| /// @title SuperchainERC20BridgeTest | ||
| /// @notice Contract for testing the SuperchainERC20Bridge contract. | ||
| contract SuperchainERC20BridgeTest is Bridge_Initializer { | ||
| address internal constant ZERO_ADDRESS = address(0); | ||
| string internal constant NAME = "SuperchainERC20"; | ||
| string internal constant SYMBOL = "SCE"; | ||
| address internal constant REMOTE_TOKEN = address(0x123); | ||
|
|
||
| event Transfer(address indexed from, address indexed to, uint256 value); | ||
|
|
||
| event SendERC20( | ||
| address indexed token, address indexed from, address indexed to, uint256 amount, uint256 destination | ||
| ); | ||
|
|
||
| event RelayERC20(address indexed token, address indexed from, address indexed to, uint256 amount, uint256 source); | ||
|
|
||
| IOptimismSuperchainERC20 public superchainERC20; | ||
|
|
||
| /// @notice Sets up the test suite. | ||
| function setUp() public override { | ||
| super.enableInterop(); | ||
| super.setUp(); | ||
|
|
||
| superchainERC20 = IOptimismSuperchainERC20( | ||
| IOptimismSuperchainERC20Factory(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY).deploy( | ||
| REMOTE_TOKEN, NAME, SYMBOL, 18 | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| /// @notice Helper function to setup a mock and expect a call to it. | ||
| function _mockAndExpect(address _receiver, bytes memory _calldata, bytes memory _returned) internal { | ||
| vm.mockCall(_receiver, _calldata, _returned); | ||
| vm.expectCall(_receiver, _calldata); | ||
| } | ||
|
|
||
| /// @notice Tests the `sendERC20` function burns the sender tokens, sends the message, and emits the `SendERC20` | ||
| /// event. | ||
| function testFuzz_sendERC20_succeeds(address _sender, address _to, uint256 _amount, uint256 _chainId) external { | ||
| // Ensure `_sender` is not the zero address | ||
| vm.assume(_sender != ZERO_ADDRESS); | ||
|
|
||
| // Mint some tokens to the sender so then they can be sent | ||
| vm.prank(Predeploys.SUPERCHAIN_ERC20_BRIDGE); | ||
| superchainERC20.mint(_sender, _amount); | ||
|
|
||
| // Get the total supply and balance of `_sender` before the send to compare later on the assertions | ||
| uint256 _totalSupplyBefore = superchainERC20.totalSupply(); | ||
| uint256 _senderBalanceBefore = superchainERC20.balanceOf(_sender); | ||
|
|
||
| // Look for the emit of the `Transfer` event | ||
| vm.expectEmit(address(superchainERC20)); | ||
| emit Transfer(_sender, ZERO_ADDRESS, _amount); | ||
|
|
||
| // Look for the emit of the `SendERC20` event | ||
| vm.expectEmit(address(superchainERC20Bridge)); | ||
| emit SendERC20(address(superchainERC20), _sender, _to, _amount, _chainId); | ||
|
|
||
| // Mock the call over the `sendMessage` function and expect it to be called properly | ||
| bytes memory _message = | ||
| abi.encodeCall(superchainERC20Bridge.relayERC20, (address(superchainERC20), _sender, _to, _amount)); | ||
| _mockAndExpect( | ||
| Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, | ||
| abi.encodeWithSelector( | ||
| IL2ToL2CrossDomainMessenger.sendMessage.selector, _chainId, address(superchainERC20Bridge), _message | ||
| ), | ||
| abi.encode("") | ||
| ); | ||
|
|
||
| // Call the `sendERC20` function | ||
| vm.prank(_sender); | ||
| superchainERC20Bridge.sendERC20(address(superchainERC20), _to, _amount, _chainId); | ||
|
|
||
| // Check the total supply and balance of `_sender` after the send were updated correctly | ||
| assertEq(superchainERC20.totalSupply(), _totalSupplyBefore - _amount); | ||
| assertEq(superchainERC20.balanceOf(_sender), _senderBalanceBefore - _amount); | ||
| } | ||
|
|
||
| /// @notice Tests the `relayERC20` function reverts when the caller is not the L2ToL2CrossDomainMessenger. | ||
| function testFuzz_relayERC20_notMessenger_reverts( | ||
| address _token, | ||
| address _caller, | ||
| address _to, | ||
| uint256 _amount | ||
| ) | ||
| public | ||
| { | ||
| // Ensure the caller is not the messenger | ||
| vm.assume(_caller != Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER); | ||
|
|
||
| // Expect the revert with `CallerNotL2ToL2CrossDomainMessenger` selector | ||
| vm.expectRevert(ISuperchainERC20Bridge.CallerNotL2ToL2CrossDomainMessenger.selector); | ||
|
|
||
| // Call the `relayERC20` function with the non-messenger caller | ||
| vm.prank(_caller); | ||
| superchainERC20Bridge.relayERC20(_token, _caller, _to, _amount); | ||
| } | ||
|
|
||
| /// @notice Tests the `relayERC20` function reverts when the `crossDomainMessageSender` that sent the message is not | ||
| /// the same SuperchainERC20Bridge. | ||
| function testFuzz_relayERC20_notCrossDomainSender_reverts( | ||
| address _token, | ||
| address _crossDomainMessageSender, | ||
| address _to, | ||
| uint256 _amount | ||
| ) | ||
| public | ||
| { | ||
| vm.assume(_crossDomainMessageSender != address(superchainERC20Bridge)); | ||
|
|
||
| // Mock the call over the `crossDomainMessageSender` function setting a wrong sender | ||
| vm.mockCall( | ||
| Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, | ||
| abi.encodeWithSelector(IL2ToL2CrossDomainMessenger.crossDomainMessageSender.selector), | ||
| abi.encode(_crossDomainMessageSender) | ||
| ); | ||
|
|
||
| // Expect the revert with `InvalidCrossDomainSender` selector | ||
| vm.expectRevert(ISuperchainERC20Bridge.InvalidCrossDomainSender.selector); | ||
|
|
||
| // Call the `relayERC20` function with the sender caller | ||
| vm.prank(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER); | ||
| superchainERC20Bridge.relayERC20(_token, _crossDomainMessageSender, _to, _amount); | ||
| } | ||
|
|
||
| /// @notice Tests the `relayERC20` mints the proper amount and emits the `RelayERC20` event. | ||
| function testFuzz_relayERC20_succeeds(address _from, address _to, uint256 _amount, uint256 _source) public { | ||
| vm.assume(_to != ZERO_ADDRESS); | ||
|
|
||
| // Mock the call over the `crossDomainMessageSender` function setting the same address as value | ||
| _mockAndExpect( | ||
| Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, | ||
| abi.encodeWithSelector(IL2ToL2CrossDomainMessenger.crossDomainMessageSender.selector), | ||
| abi.encode(address(superchainERC20Bridge)) | ||
| ); | ||
|
|
||
| // Mock the call over the `crossDomainMessageSource` function setting the source chain ID as value | ||
| _mockAndExpect( | ||
| Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, | ||
| abi.encodeWithSelector(IL2ToL2CrossDomainMessenger.crossDomainMessageSource.selector), | ||
| abi.encode(_source) | ||
| ); | ||
|
|
||
| // Get the total supply and balance of `_to` before the relay to compare later on the assertions | ||
| uint256 _totalSupplyBefore = superchainERC20.totalSupply(); | ||
| uint256 _toBalanceBefore = superchainERC20.balanceOf(_to); | ||
|
|
||
| // Look for the emit of the `Transfer` event | ||
| vm.expectEmit(address(superchainERC20)); | ||
| emit Transfer(ZERO_ADDRESS, _to, _amount); | ||
|
|
||
| // Look for the emit of the `RelayERC20` event | ||
| vm.expectEmit(address(superchainERC20Bridge)); | ||
| emit RelayERC20(address(superchainERC20), _from, _to, _amount, _source); | ||
|
|
||
| // Call the `relayERC20` function with the messenger caller | ||
| vm.prank(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER); | ||
| superchainERC20Bridge.relayERC20(address(superchainERC20), _from, _to, _amount); | ||
|
|
||
| // Check the total supply and balance of `_to` after the relay were updated correctly | ||
| assertEq(superchainERC20.totalSupply(), _totalSupplyBefore + _amount); | ||
| assertEq(superchainERC20.balanceOf(_to), _toBalanceBefore + _amount); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.