From 99d06337676c4a701c9e05c237b5730843e6f1a0 Mon Sep 17 00:00:00 2001 From: agusduha Date: Thu, 3 Oct 2024 15:15:22 -0300 Subject: [PATCH 1/2] feat: add crosschain erc20 interface --- packages/contracts-bedrock/semver-lock.json | 8 ++--- .../abi/OptimismSuperchainERC20.json | 36 +++++++++---------- .../src/L2/SuperchainERC20.sol | 13 +++---- .../src/L2/SuperchainERC20Bridge.sol | 4 +-- .../src/L2/interfaces/ICrosschainERC20.sol | 26 ++++++++++++++ .../interfaces/IOptimismSuperchainERC20.sol | 2 +- .../src/L2/interfaces/ISuperchainERC20.sol | 23 ++---------- .../test/L2/SuperchainERC20.t.sol | 31 ++++++++-------- .../test/L2/SuperchainERC20Bridge.t.sol | 2 +- .../fuzz/Protocol.unguided.t.sol | 4 +-- .../handlers/Protocol.t.sol | 2 +- 11 files changed, 80 insertions(+), 71 deletions(-) create mode 100644 packages/contracts-bedrock/src/L2/interfaces/ICrosschainERC20.sol diff --git a/packages/contracts-bedrock/semver-lock.json b/packages/contracts-bedrock/semver-lock.json index adae1ff092bf..c8b0991ed9fb 100644 --- a/packages/contracts-bedrock/semver-lock.json +++ b/packages/contracts-bedrock/semver-lock.json @@ -116,7 +116,7 @@ "sourceCodeHash": "0xfea53344596d735eff3be945ed1300dc75a6f8b7b2c02c0043af5b0036f5f239" }, "src/L2/OptimismSuperchainERC20.sol": { - "initCodeHash": "0xc6452d9aef6d76bdc789f3cddac6862658a481c619e6a2e7a74f6d61147f927b", + "initCodeHash": "0x964c826693c6633dc5eff6d4b059a30043775af46b06e42367aff91b904498da", "sourceCodeHash": "0x4463e49c98ceb3327bd768579341d1e0863c8c3925d4b533fbc0f7951306261f" }, "src/L2/OptimismSuperchainERC20Beacon.sol": { @@ -133,11 +133,11 @@ }, "src/L2/SuperchainERC20.sol": { "initCodeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "sourceCodeHash": "0x9bc2e208774eb923894dbe391a5038a6189d7d36c202f4bf3e2c4dd332b0adf0" + "sourceCodeHash": "0x770764a897f76912ff5ad315ab7101f7777b8be47f21021d56cb9572b9efa458" }, "src/L2/SuperchainERC20Bridge.sol": { - "initCodeHash": "0xea7eb314f96cd2520a58012ff7cc376c82c5a95612187ff6bb96ace4f095ebc4", - "sourceCodeHash": "0x83188d878ce0b2890a7f7f41d09a8807f94a126e0ea274f0dac8b93f77217d3b" + "initCodeHash": "0xf85225ea25a87ba670b6ce0172a4814fda712d1c8a174fd4e8ce72b1cebcc2a0", + "sourceCodeHash": "0x66b56c0ac0d49b6da84da01a318f43418ef486e5fb40ae0af487568fde8566fb" }, "src/L2/SuperchainWETH.sol": { "initCodeHash": "0x5db03c5c4cd6ea9e4b3e74e28f50d04fd3e130af5109b34fa208808fa9ba7742", diff --git a/packages/contracts-bedrock/snapshots/abi/OptimismSuperchainERC20.json b/packages/contracts-bedrock/snapshots/abi/OptimismSuperchainERC20.json index 7c24b3fe0065..6c71001ad3a5 100644 --- a/packages/contracts-bedrock/snapshots/abi/OptimismSuperchainERC20.json +++ b/packages/contracts-bedrock/snapshots/abi/OptimismSuperchainERC20.json @@ -30,7 +30,7 @@ "type": "uint256" } ], - "name": "__superchainBurn", + "name": "__crosschainBurn", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -48,7 +48,7 @@ "type": "uint256" } ], - "name": "__superchainMint", + "name": "__crosschainMint", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -440,19 +440,6 @@ "name": "Burn", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" - } - ], - "name": "Initialized", - "type": "event" - }, { "anonymous": false, "inputs": [ @@ -469,7 +456,7 @@ "type": "uint256" } ], - "name": "Mint", + "name": "CrosschainBurnt", "type": "event" }, { @@ -488,7 +475,20 @@ "type": "uint256" } ], - "name": "SuperchainBurnt", + "name": "CrosschainMinted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "version", + "type": "uint64" + } + ], + "name": "Initialized", "type": "event" }, { @@ -507,7 +507,7 @@ "type": "uint256" } ], - "name": "SuperchainMinted", + "name": "Mint", "type": "event" }, { diff --git a/packages/contracts-bedrock/src/L2/SuperchainERC20.sol b/packages/contracts-bedrock/src/L2/SuperchainERC20.sol index 6c48b231baaf..0093806af701 100644 --- a/packages/contracts-bedrock/src/L2/SuperchainERC20.sol +++ b/packages/contracts-bedrock/src/L2/SuperchainERC20.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import { ISuperchainERC20Extension } from "src/L2/interfaces/ISuperchainERC20.sol"; +import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol"; +import { ISuperchainERC20Errors } from "src/L2/interfaces/ISuperchainERC20.sol"; import { ISemver } from "src/universal/interfaces/ISemver.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { ERC20 } from "@solady/tokens/ERC20.sol"; @@ -10,7 +11,7 @@ import { ERC20 } from "@solady/tokens/ERC20.sol"; /// @notice SuperchainERC20 is a standard extension of the base ERC20 token contract that unifies ERC20 token /// bridging to make it fungible across the Superchain. This construction allows the SuperchainERC20Bridge to /// burn and mint tokens. -abstract contract SuperchainERC20 is ERC20, ISuperchainERC20Extension, ISemver { +abstract contract SuperchainERC20 is ERC20, ICrosschainERC20, ISuperchainERC20Errors, ISemver { /// @notice A modifier that only allows the SuperchainERC20Bridge to call modifier onlySuperchainERC20Bridge() { if (msg.sender != Predeploys.SUPERCHAIN_ERC20_BRIDGE) revert OnlySuperchainERC20Bridge(); @@ -26,18 +27,18 @@ abstract contract SuperchainERC20 is ERC20, ISuperchainERC20Extension, ISemver { /// @notice Allows the SuperchainERC20Bridge to mint tokens. /// @param _to Address to mint tokens to. /// @param _amount Amount of tokens to mint. - function __superchainMint(address _to, uint256 _amount) external virtual onlySuperchainERC20Bridge { + function __crosschainMint(address _to, uint256 _amount) external virtual onlySuperchainERC20Bridge { _mint(_to, _amount); - emit SuperchainMinted(_to, _amount); + emit CrosschainMinted(_to, _amount); } /// @notice Allows the SuperchainERC20Bridge to burn tokens. /// @param _from Address to burn tokens from. /// @param _amount Amount of tokens to burn. - function __superchainBurn(address _from, uint256 _amount) external virtual onlySuperchainERC20Bridge { + function __crosschainBurn(address _from, uint256 _amount) external virtual onlySuperchainERC20Bridge { _burn(_from, _amount); - emit SuperchainBurnt(_from, _amount); + emit CrosschainBurnt(_from, _amount); } } diff --git a/packages/contracts-bedrock/src/L2/SuperchainERC20Bridge.sol b/packages/contracts-bedrock/src/L2/SuperchainERC20Bridge.sol index 9d13de80f4ca..2046efb2d0f1 100644 --- a/packages/contracts-bedrock/src/L2/SuperchainERC20Bridge.sol +++ b/packages/contracts-bedrock/src/L2/SuperchainERC20Bridge.sol @@ -31,7 +31,7 @@ contract SuperchainERC20Bridge is ISuperchainERC20Bridge { function sendERC20(address _token, address _to, uint256 _amount, uint256 _chainId) external { if (_to == address(0)) revert ZeroAddress(); - ISuperchainERC20(_token).__superchainBurn(msg.sender, _amount); + ISuperchainERC20(_token).__crosschainBurn(msg.sender, _amount); bytes memory message = abi.encodeCall(this.relayERC20, (_token, msg.sender, _to, _amount)); IL2ToL2CrossDomainMessenger(MESSENGER).sendMessage(_chainId, address(this), message); @@ -53,7 +53,7 @@ contract SuperchainERC20Bridge is ISuperchainERC20Bridge { uint256 source = IL2ToL2CrossDomainMessenger(MESSENGER).crossDomainMessageSource(); - ISuperchainERC20(_token).__superchainMint(_to, _amount); + ISuperchainERC20(_token).__crosschainMint(_to, _amount); emit RelayERC20(_token, _from, _to, _amount, source); } diff --git a/packages/contracts-bedrock/src/L2/interfaces/ICrosschainERC20.sol b/packages/contracts-bedrock/src/L2/interfaces/ICrosschainERC20.sol new file mode 100644 index 000000000000..ba9af02f4cd2 --- /dev/null +++ b/packages/contracts-bedrock/src/L2/interfaces/ICrosschainERC20.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title ICrosschainERC20 +/// @notice This interface is a standard for crosschain ERC20 transfers. +interface ICrosschainERC20 { + /// @notice Emitted whenever tokens are minted by a crosschain transfer. + /// @param account Address of the account tokens are being minted for. + /// @param amount Amount of tokens minted. + event CrosschainMinted(address indexed account, uint256 amount); + + /// @notice Emitted whenever tokens are burned by a crosschain transfer. + /// @param account Address of the account tokens are being burned from. + /// @param amount Amount of tokens burned. + event CrosschainBurnt(address indexed account, uint256 amount); + + /// @notice Allows to mint tokens through a crosschain transfer. + /// @param _to Address to mint tokens to. + /// @param _amount Amount of tokens to mint. + function __crosschainMint(address _to, uint256 _amount) external; + + /// @notice Allows to burn tokens through a crosschain transfer. + /// @param _from Address to burn tokens from. + /// @param _amount Amount of tokens to burn. + function __crosschainBurn(address _from, uint256 _amount) external; +} diff --git a/packages/contracts-bedrock/src/L2/interfaces/IOptimismSuperchainERC20.sol b/packages/contracts-bedrock/src/L2/interfaces/IOptimismSuperchainERC20.sol index a887ecf0e030..dd32d14c1a4f 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/IOptimismSuperchainERC20.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IOptimismSuperchainERC20.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; // Interfaces -import { ISuperchainERC20, ISuperchainERC20Extension } from "src/L2/interfaces/ISuperchainERC20.sol"; +import { ISuperchainERC20Extension } from "src/L2/interfaces/ISuperchainERC20.sol"; import { IERC20Solady } from "src/vendor/interfaces/IERC20Solady.sol"; /// @title IOptimismSuperchainERC20Errors diff --git a/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol b/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol index 47341c559719..f65e102de0e1 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; // Interfaces +import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol"; import { IERC20Solady } from "src/vendor/interfaces/IERC20Solady.sol"; /// @title ISuperchainERC20Errors @@ -13,27 +14,7 @@ interface ISuperchainERC20Errors { /// @title ISuperchainERC20Extension /// @notice This interface is available on the SuperchainERC20 contract. -interface ISuperchainERC20Extension is ISuperchainERC20Errors { - /// @notice Emitted whenever tokens are minted for by the SuperchainERC20Bridge. - /// @param account Address of the account tokens are being minted for. - /// @param amount Amount of tokens minted. - event SuperchainMinted(address indexed account, uint256 amount); - - /// @notice Emitted whenever tokens are burned by the SuperchainERC20Bridge. - /// @param account Address of the account tokens are being burned from. - /// @param amount Amount of tokens burned. - event SuperchainBurnt(address indexed account, uint256 amount); - - /// @notice Allows the SuperchainERC20Bridge to mint tokens. - /// @param _to Address to mint tokens to. - /// @param _amount Amount of tokens to mint. - function __superchainMint(address _to, uint256 _amount) external; - - /// @notice Allows the SuperchainERC20Bridge to burn tokens. - /// @param _from Address to burn tokens from. - /// @param _amount Amount of tokens to burn. - function __superchainBurn(address _from, uint256 _amount) external; -} +interface ISuperchainERC20Extension is ICrosschainERC20, ISuperchainERC20Errors { } /// @title ISuperchainERC20 /// @notice Combines Solady's ERC20 interface with the SuperchainERC20Extension interface. diff --git a/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol b/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol index 30b758a38e6d..eba6201c9756 100644 --- a/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol +++ b/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol @@ -16,7 +16,8 @@ import { IBeacon } from "@openzeppelin/contracts-v5/proxy/beacon/IBeacon.sol"; import { BeaconProxy } from "@openzeppelin/contracts-v5/proxy/beacon/BeaconProxy.sol"; // Target contract -import { SuperchainERC20, ISuperchainERC20Extension } from "src/L2/SuperchainERC20.sol"; +import { SuperchainERC20 } from "src/L2/SuperchainERC20.sol"; +import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol"; import { ISuperchainERC20Errors } from "src/L2/interfaces/ISuperchainERC20.sol"; import { SuperchainERC20Implementation_MockContract } from "test/mocks/SuperchainERC20Implementation.sol"; @@ -41,7 +42,7 @@ contract SuperchainERC20Test is Test { } /// @notice Tests the `mint` function reverts when the caller is not the bridge. - function testFuzz___superchainMint_callerNotBridge_reverts(address _caller, address _to, uint256 _amount) public { + function testFuzz___crosschainMint_callerNotBridge_reverts(address _caller, address _to, uint256 _amount) public { // Ensure the caller is not the bridge vm.assume(_caller != SUPERCHAIN_ERC20_BRIDGE); @@ -50,11 +51,11 @@ contract SuperchainERC20Test is Test { // Call the `mint` function with the non-bridge caller vm.prank(_caller); - superchainERC20.__superchainMint(_to, _amount); + superchainERC20.__crosschainMint(_to, _amount); } /// @notice Tests the `mint` succeeds and emits the `Mint` event. - function testFuzz___superchainMint_succeeds(address _to, uint256 _amount) public { + function testFuzz___crosschainMint_succeeds(address _to, uint256 _amount) public { // Ensure `_to` is not the zero address vm.assume(_to != ZERO_ADDRESS); @@ -66,13 +67,13 @@ contract SuperchainERC20Test is Test { vm.expectEmit(address(superchainERC20)); emit IERC20.Transfer(ZERO_ADDRESS, _to, _amount); - // Look for the emit of the `SuperchainMinted` event + // Look for the emit of the `CrosschainMinted` event vm.expectEmit(address(superchainERC20)); - emit ISuperchainERC20Extension.SuperchainMinted(_to, _amount); + emit ICrosschainERC20.CrosschainMinted(_to, _amount); // Call the `mint` function with the bridge caller vm.prank(SUPERCHAIN_ERC20_BRIDGE); - superchainERC20.__superchainMint(_to, _amount); + superchainERC20.__crosschainMint(_to, _amount); // Check the total supply and balance of `_to` after the mint were updated correctly assertEq(superchainERC20.totalSupply(), _totalSupplyBefore + _amount); @@ -80,7 +81,7 @@ contract SuperchainERC20Test is Test { } /// @notice Tests the `burn` function reverts when the caller is not the bridge. - function testFuzz___superchainBurn_callerNotBridge_reverts( + function testFuzz___crosschainBurn_callerNotBridge_reverts( address _caller, address _from, uint256 _amount @@ -95,17 +96,17 @@ contract SuperchainERC20Test is Test { // Call the `burn` function with the non-bridge caller vm.prank(_caller); - superchainERC20.__superchainBurn(_from, _amount); + superchainERC20.__crosschainBurn(_from, _amount); } - /// @notice Tests the `burn` burns the amount and emits the `SuperchainBurnt` event. - function testFuzz___superchainBurn_succeeds(address _from, uint256 _amount) public { + /// @notice Tests the `burn` burns the amount and emits the `CrosschainBurnt` event. + function testFuzz___crosschainBurn_succeeds(address _from, uint256 _amount) public { // Ensure `_from` is not the zero address vm.assume(_from != ZERO_ADDRESS); // Mint some tokens to `_from` so then they can be burned vm.prank(SUPERCHAIN_ERC20_BRIDGE); - superchainERC20.__superchainMint(_from, _amount); + superchainERC20.__crosschainMint(_from, _amount); // Get the total supply and balance of `_from` before the burn to compare later on the assertions uint256 _totalSupplyBefore = superchainERC20.totalSupply(); @@ -115,13 +116,13 @@ contract SuperchainERC20Test is Test { vm.expectEmit(address(superchainERC20)); emit IERC20.Transfer(_from, ZERO_ADDRESS, _amount); - // Look for the emit of the `SuperchainBurnt` event + // Look for the emit of the `CrosschainBurnt` event vm.expectEmit(address(superchainERC20)); - emit ISuperchainERC20Extension.SuperchainBurnt(_from, _amount); + emit ICrosschainERC20.CrosschainBurnt(_from, _amount); // Call the `burn` function with the bridge caller vm.prank(SUPERCHAIN_ERC20_BRIDGE); - superchainERC20.__superchainBurn(_from, _amount); + superchainERC20.__crosschainBurn(_from, _amount); // Check the total supply and balance of `_from` after the burn were updated correctly assertEq(superchainERC20.totalSupply(), _totalSupplyBefore - _amount); diff --git a/packages/contracts-bedrock/test/L2/SuperchainERC20Bridge.t.sol b/packages/contracts-bedrock/test/L2/SuperchainERC20Bridge.t.sol index 7ec72e508dad..fbeb75d77660 100644 --- a/packages/contracts-bedrock/test/L2/SuperchainERC20Bridge.t.sol +++ b/packages/contracts-bedrock/test/L2/SuperchainERC20Bridge.t.sol @@ -67,7 +67,7 @@ contract SuperchainERC20BridgeTest is Bridge_Initializer { // Mint some tokens to the sender so then they can be sent vm.prank(Predeploys.SUPERCHAIN_ERC20_BRIDGE); - superchainERC20.__superchainMint(_sender, _amount); + superchainERC20.__crosschainMint(_sender, _amount); // Get the total supply and balance of `_sender` before the send to compare later on the assertions uint256 _totalSupplyBefore = superchainERC20.totalSupply(); diff --git a/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/fuzz/Protocol.unguided.t.sol b/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/fuzz/Protocol.unguided.t.sol index db7c2243a1cd..2ead177276f8 100644 --- a/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/fuzz/Protocol.unguided.t.sol +++ b/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/fuzz/Protocol.unguided.t.sol @@ -17,7 +17,7 @@ contract ProtocolUnguided is ProtocolHandler, CompatibleAssert { bytes32 salt = MESSENGER.superTokenInitDeploySalts(token); amount = bound(amount, 0, type(uint256).max - OptimismSuperchainERC20(token).totalSupply()); vm.prank(sender); - try OptimismSuperchainERC20(token).__superchainMint(to, amount) { + try OptimismSuperchainERC20(token).__crosschainMint(to, amount) { compatibleAssert(sender == BRIDGE); (, uint256 currentValue) = ghost_totalSupplyAcrossChains.tryGet(salt); ghost_totalSupplyAcrossChains.set(salt, currentValue + amount); @@ -33,7 +33,7 @@ contract ProtocolUnguided is ProtocolHandler, CompatibleAssert { bytes32 salt = MESSENGER.superTokenInitDeploySalts(token); uint256 senderBalance = OptimismSuperchainERC20(token).balanceOf(sender); vm.prank(sender); - try OptimismSuperchainERC20(token).__superchainBurn(from, amount) { + try OptimismSuperchainERC20(token).__crosschainBurn(from, amount) { compatibleAssert(sender == BRIDGE); (, uint256 currentValue) = ghost_totalSupplyAcrossChains.tryGet(salt); ghost_totalSupplyAcrossChains.set(salt, currentValue - amount); diff --git a/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/handlers/Protocol.t.sol b/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/handlers/Protocol.t.sol index 9dbd5d5fc4a8..91aa9a81c619 100644 --- a/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/handlers/Protocol.t.sol +++ b/packages/contracts-bedrock/test/invariants/OptimismSuperchainERC20/handlers/Protocol.t.sol @@ -79,7 +79,7 @@ contract ProtocolHandler is TestBase, StdUtils, Actors { index = bound(index, 0, allSuperTokens.length - 1); address addr = allSuperTokens[index]; vm.prank(BRIDGE); - OptimismSuperchainERC20(addr).__superchainMint(currentActor(), amount); + OptimismSuperchainERC20(addr).__crosschainMint(currentActor(), amount); // currentValue will be zero if key is not present (, uint256 currentValue) = ghost_totalSupplyAcrossChains.tryGet(MESSENGER.superTokenInitDeploySalts(addr)); ghost_totalSupplyAcrossChains.set(MESSENGER.superTokenInitDeploySalts(addr), currentValue + amount); From ea1a2e09c3a2ad5b1b3db754080df0021c3ed907 Mon Sep 17 00:00:00 2001 From: agusduha Date: Thu, 3 Oct 2024 16:55:36 -0300 Subject: [PATCH 2/2] fix: refactor interfaces --- packages/contracts-bedrock/semver-lock.json | 4 +-- .../abi/OptimismSuperchainERC20.json | 8 +++--- .../src/L2/OptimismSuperchainERC20.sol | 7 +++--- .../src/L2/SuperchainERC20.sol | 5 ++-- .../src/L2/interfaces/ICrosschainERC20.sol | 22 ++++++++-------- .../interfaces/IOptimismSuperchainERC20.sol | 25 ++++++------------- .../src/L2/interfaces/ISuperchainERC20.sol | 17 +++---------- .../test/L2/OptimismSuperchainERC20.t.sol | 25 ++++++++----------- .../L2/OptimismSuperchainERC20Factory.t.sol | 7 +++--- .../test/L2/SuperchainERC20.t.sol | 6 ++--- .../test/L2/SuperchainERC20Bridge.t.sol | 17 +++++++------ 11 files changed, 60 insertions(+), 83 deletions(-) diff --git a/packages/contracts-bedrock/semver-lock.json b/packages/contracts-bedrock/semver-lock.json index c8b0991ed9fb..22cc1486d02e 100644 --- a/packages/contracts-bedrock/semver-lock.json +++ b/packages/contracts-bedrock/semver-lock.json @@ -117,7 +117,7 @@ }, "src/L2/OptimismSuperchainERC20.sol": { "initCodeHash": "0x964c826693c6633dc5eff6d4b059a30043775af46b06e42367aff91b904498da", - "sourceCodeHash": "0x4463e49c98ceb3327bd768579341d1e0863c8c3925d4b533fbc0f7951306261f" + "sourceCodeHash": "0xf5cb8307067f2ef7aa540b9e0a4828cde76f783c7fb95c7d3f84c6d723f9d316" }, "src/L2/OptimismSuperchainERC20Beacon.sol": { "initCodeHash": "0x99ce8095b23c124850d866cbc144fee6cee05dbc6bb5d83acadfe00b90cf42c7", @@ -133,7 +133,7 @@ }, "src/L2/SuperchainERC20.sol": { "initCodeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "sourceCodeHash": "0x770764a897f76912ff5ad315ab7101f7777b8be47f21021d56cb9572b9efa458" + "sourceCodeHash": "0x4debbf83ad569eae88fb1e70db5f45fb85eed609fd464bd180611756116e04ae" }, "src/L2/SuperchainERC20Bridge.sol": { "initCodeHash": "0xf85225ea25a87ba670b6ce0172a4814fda712d1c8a174fd4e8ce72b1cebcc2a0", diff --git a/packages/contracts-bedrock/snapshots/abi/OptimismSuperchainERC20.json b/packages/contracts-bedrock/snapshots/abi/OptimismSuperchainERC20.json index 6c71001ad3a5..5c0d8bcb8074 100644 --- a/packages/contracts-bedrock/snapshots/abi/OptimismSuperchainERC20.json +++ b/packages/contracts-bedrock/snapshots/abi/OptimismSuperchainERC20.json @@ -427,7 +427,7 @@ { "indexed": true, "internalType": "address", - "name": "account", + "name": "from", "type": "address" }, { @@ -446,7 +446,7 @@ { "indexed": true, "internalType": "address", - "name": "account", + "name": "from", "type": "address" }, { @@ -465,7 +465,7 @@ { "indexed": true, "internalType": "address", - "name": "account", + "name": "to", "type": "address" }, { @@ -497,7 +497,7 @@ { "indexed": true, "internalType": "address", - "name": "account", + "name": "to", "type": "address" }, { diff --git a/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol b/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol index 92616f72ac63..017b5060d90f 100644 --- a/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol +++ b/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import { IOptimismSuperchainERC20Extension } from "src/L2/interfaces/IOptimismSuperchainERC20.sol"; +import { IOptimismSuperchainERC20 } from "src/L2/interfaces/IOptimismSuperchainERC20.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { ERC165 } from "@openzeppelin/contracts-v5/utils/introspection/ERC165.sol"; import { SuperchainERC20 } from "src/L2/SuperchainERC20.sol"; @@ -15,7 +15,7 @@ import { Initializable } from "@openzeppelin/contracts-v5/proxy/utils/Initializa /// OptimismSuperchainERC20 token, turning it fungible and interoperable across the superchain. Likewise, it /// also enables the inverse conversion path. /// Moreover, it builds on top of the L2ToL2CrossDomainMessenger for both replay protection and domain binding. -contract OptimismSuperchainERC20 is SuperchainERC20, Initializable, ERC165, IOptimismSuperchainERC20Extension { +contract OptimismSuperchainERC20 is SuperchainERC20, Initializable, ERC165, IOptimismSuperchainERC20 { /// @notice Storage slot that the OptimismSuperchainERC20Metadata struct is stored at. /// keccak256(abi.encode(uint256(keccak256("optimismSuperchainERC20.metadata")) - 1)) & ~bytes32(uint256(0xff)); bytes32 internal constant OPTIMISM_SUPERCHAIN_ERC20_METADATA_SLOT = @@ -130,7 +130,6 @@ contract OptimismSuperchainERC20 is SuperchainERC20, Initializable, ERC165, IOpt /// @param _interfaceId Interface ID to check. /// @return Whether or not the interface is supported by this contract. function supportsInterface(bytes4 _interfaceId) public view virtual override returns (bool) { - return - _interfaceId == type(IOptimismSuperchainERC20Extension).interfaceId || super.supportsInterface(_interfaceId); + return _interfaceId == type(IOptimismSuperchainERC20).interfaceId || super.supportsInterface(_interfaceId); } } diff --git a/packages/contracts-bedrock/src/L2/SuperchainERC20.sol b/packages/contracts-bedrock/src/L2/SuperchainERC20.sol index 0093806af701..c2ef27ebc273 100644 --- a/packages/contracts-bedrock/src/L2/SuperchainERC20.sol +++ b/packages/contracts-bedrock/src/L2/SuperchainERC20.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol"; -import { ISuperchainERC20Errors } from "src/L2/interfaces/ISuperchainERC20.sol"; +import { ISuperchainERC20 } from "src/L2/interfaces/ISuperchainERC20.sol"; import { ISemver } from "src/universal/interfaces/ISemver.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { ERC20 } from "@solady/tokens/ERC20.sol"; @@ -11,7 +10,7 @@ import { ERC20 } from "@solady/tokens/ERC20.sol"; /// @notice SuperchainERC20 is a standard extension of the base ERC20 token contract that unifies ERC20 token /// bridging to make it fungible across the Superchain. This construction allows the SuperchainERC20Bridge to /// burn and mint tokens. -abstract contract SuperchainERC20 is ERC20, ICrosschainERC20, ISuperchainERC20Errors, ISemver { +abstract contract SuperchainERC20 is ERC20, ISuperchainERC20, ISemver { /// @notice A modifier that only allows the SuperchainERC20Bridge to call modifier onlySuperchainERC20Bridge() { if (msg.sender != Predeploys.SUPERCHAIN_ERC20_BRIDGE) revert OnlySuperchainERC20Bridge(); diff --git a/packages/contracts-bedrock/src/L2/interfaces/ICrosschainERC20.sol b/packages/contracts-bedrock/src/L2/interfaces/ICrosschainERC20.sol index ba9af02f4cd2..c156b79dc609 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/ICrosschainERC20.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/ICrosschainERC20.sol @@ -2,24 +2,24 @@ pragma solidity ^0.8.0; /// @title ICrosschainERC20 -/// @notice This interface is a standard for crosschain ERC20 transfers. +/// @notice Defines the interface for crosschain ERC20 transfers. interface ICrosschainERC20 { - /// @notice Emitted whenever tokens are minted by a crosschain transfer. - /// @param account Address of the account tokens are being minted for. - /// @param amount Amount of tokens minted. - event CrosschainMinted(address indexed account, uint256 amount); + /// @notice Emitted when a crosschain transfer mints tokens. + /// @param to Address of the account tokens are being minted for. + /// @param amount Amount of tokens minted. + event CrosschainMinted(address indexed to, uint256 amount); - /// @notice Emitted whenever tokens are burned by a crosschain transfer. - /// @param account Address of the account tokens are being burned from. - /// @param amount Amount of tokens burned. - event CrosschainBurnt(address indexed account, uint256 amount); + /// @notice Emitted when a crosschain transfer burns tokens. + /// @param from Address of the account tokens are being burned from. + /// @param amount Amount of tokens burned. + event CrosschainBurnt(address indexed from, uint256 amount); - /// @notice Allows to mint tokens through a crosschain transfer. + /// @notice Mint tokens through a crosschain transfer. /// @param _to Address to mint tokens to. /// @param _amount Amount of tokens to mint. function __crosschainMint(address _to, uint256 _amount) external; - /// @notice Allows to burn tokens through a crosschain transfer. + /// @notice Burn tokens through a crosschain transfer. /// @param _from Address to burn tokens from. /// @param _amount Amount of tokens to burn. function __crosschainBurn(address _from, uint256 _amount) external; diff --git a/packages/contracts-bedrock/src/L2/interfaces/IOptimismSuperchainERC20.sol b/packages/contracts-bedrock/src/L2/interfaces/IOptimismSuperchainERC20.sol index dd32d14c1a4f..e8d87d91e4b4 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/IOptimismSuperchainERC20.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IOptimismSuperchainERC20.sol @@ -2,31 +2,26 @@ pragma solidity ^0.8.0; // Interfaces -import { ISuperchainERC20Extension } from "src/L2/interfaces/ISuperchainERC20.sol"; -import { IERC20Solady } from "src/vendor/interfaces/IERC20Solady.sol"; +import { ISuperchainERC20 } from "src/L2/interfaces/ISuperchainERC20.sol"; -/// @title IOptimismSuperchainERC20Errors -/// @notice Interface containing the errors added in the OptimismSuperchainERC20 implementation. -interface IOptimismSuperchainERC20Errors { +/// @title IOptimismSuperchainERC20 +/// @notice This interface is available on the OptimismSuperchainERC20 contract. +interface IOptimismSuperchainERC20 is ISuperchainERC20 { /// @notice Thrown when attempting to perform an operation and the account is the zero address. error ZeroAddress(); /// @notice Thrown when attempting to mint or burn tokens and the function caller is not the L2StandardBridge error OnlyL2StandardBridge(); -} -/// @title IOptimismSuperchainERC20Extension -/// @notice This interface is available on the OptimismSuperchainERC20 contract. -interface IOptimismSuperchainERC20Extension is ISuperchainERC20Extension, IOptimismSuperchainERC20Errors { /// @notice Emitted whenever tokens are minted for an account. - /// @param account Address of the account tokens are being minted for. + /// @param to Address of the account tokens are being minted for. /// @param amount Amount of tokens minted. - event Mint(address indexed account, uint256 amount); + event Mint(address indexed to, uint256 amount); /// @notice Emitted whenever tokens are burned from an account. - /// @param account Address of the account tokens are being burned from. + /// @param from Address of the account tokens are being burned from. /// @param amount Amount of tokens burned. - event Burn(address indexed account, uint256 amount); + event Burn(address indexed from, uint256 amount); /// @notice Allows the L2StandardBridge and SuperchainERC20Bridge to mint tokens. /// @param _to Address to mint tokens to. @@ -41,7 +36,3 @@ interface IOptimismSuperchainERC20Extension is ISuperchainERC20Extension, IOptim /// @notice Returns the address of the corresponding version of this token on the remote chain. function remoteToken() external view returns (address); } - -/// @title IOptimismSuperchainERC20 -/// @notice Combines Solady's ERC20 interface with the IOptimismSuperchainERC20Extension interface. -interface IOptimismSuperchainERC20 is IERC20Solady, IOptimismSuperchainERC20Extension { } diff --git a/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol b/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol index f65e102de0e1..cc96520355f9 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol @@ -3,21 +3,10 @@ pragma solidity ^0.8.0; // Interfaces import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol"; -import { IERC20Solady } from "src/vendor/interfaces/IERC20Solady.sol"; -/// @title ISuperchainERC20Errors -/// @notice Interface containing the errors added in the SuperchainERC20 implementation. -interface ISuperchainERC20Errors { +/// @title ISuperchainERC20 +/// @notice This interface is available on the SuperchainERC20 contract. +interface ISuperchainERC20 is ICrosschainERC20 { /// @notice Thrown when attempting to mint or burn tokens and the function caller is not the SuperchainERC20Bridge. error OnlySuperchainERC20Bridge(); } - -/// @title ISuperchainERC20Extension -/// @notice This interface is available on the SuperchainERC20 contract. -interface ISuperchainERC20Extension is ICrosschainERC20, ISuperchainERC20Errors { } - -/// @title ISuperchainERC20 -/// @notice Combines Solady's ERC20 interface with the SuperchainERC20Extension interface. -interface ISuperchainERC20 is IERC20Solady, ISuperchainERC20Extension { - function __constructor__() external; -} diff --git a/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20.t.sol b/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20.t.sol index 239c785b51c0..a1cf30510a1c 100644 --- a/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20.t.sol +++ b/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20.t.sol @@ -16,10 +16,7 @@ import { BeaconProxy } from "@openzeppelin/contracts-v5/proxy/beacon/BeaconProxy // Target contract import { OptimismSuperchainERC20 } from "src/L2/OptimismSuperchainERC20.sol"; -import { - IOptimismSuperchainERC20Extension, - IOptimismSuperchainERC20Errors -} from "src/L2/interfaces/IOptimismSuperchainERC20.sol"; +import { IOptimismSuperchainERC20 } from "src/L2/interfaces/IOptimismSuperchainERC20.sol"; /// @title OptimismSuperchainERC20Test /// @notice Contract for testing the OptimismSuperchainERC20 contract. @@ -122,7 +119,7 @@ contract OptimismSuperchainERC20Test is Test { vm.assume(_caller != L2_BRIDGE); // Expect the revert with `OnlyL2StandardBridge` selector - vm.expectRevert(IOptimismSuperchainERC20Errors.OnlyL2StandardBridge.selector); + vm.expectRevert(IOptimismSuperchainERC20.OnlyL2StandardBridge.selector); // Call the `mint` function with the non-bridge caller vm.prank(_caller); @@ -132,7 +129,7 @@ contract OptimismSuperchainERC20Test is Test { /// @notice Tests the `mint` function reverts when the amount is zero. function testFuzz_mint_zeroAddressTo_reverts(uint256 _amount) public { // Expect the revert with `ZeroAddress` selector - vm.expectRevert(IOptimismSuperchainERC20Errors.ZeroAddress.selector); + vm.expectRevert(IOptimismSuperchainERC20.ZeroAddress.selector); // Call the `mint` function with the zero address vm.prank(L2_BRIDGE); @@ -145,8 +142,8 @@ contract OptimismSuperchainERC20Test is Test { vm.assume(_to != ZERO_ADDRESS); // Get the total supply and balance of `_to` before the mint to compare later on the assertions - uint256 _totalSupplyBefore = optimismSuperchainERC20.totalSupply(); - uint256 _toBalanceBefore = optimismSuperchainERC20.balanceOf(_to); + uint256 _totalSupplyBefore = IERC20(address(optimismSuperchainERC20)).totalSupply(); + uint256 _toBalanceBefore = IERC20(address(optimismSuperchainERC20)).balanceOf(_to); // Look for the emit of the `Transfer` event vm.expectEmit(address(optimismSuperchainERC20)); @@ -154,7 +151,7 @@ contract OptimismSuperchainERC20Test is Test { // Look for the emit of the `Mint` event vm.expectEmit(address(optimismSuperchainERC20)); - emit IOptimismSuperchainERC20Extension.Mint(_to, _amount); + emit IOptimismSuperchainERC20.Mint(_to, _amount); // Call the `mint` function with the bridge caller vm.prank(L2_BRIDGE); @@ -171,7 +168,7 @@ contract OptimismSuperchainERC20Test is Test { vm.assume(_caller != L2_BRIDGE); // Expect the revert with `OnlyL2StandardBridge` selector - vm.expectRevert(IOptimismSuperchainERC20Errors.OnlyL2StandardBridge.selector); + vm.expectRevert(IOptimismSuperchainERC20.OnlyL2StandardBridge.selector); // Call the `burn` function with the non-bridge caller vm.prank(_caller); @@ -181,7 +178,7 @@ contract OptimismSuperchainERC20Test is Test { /// @notice Tests the `burn` function reverts when the amount is zero. function testFuzz_burn_zeroAddressFrom_reverts(uint256 _amount) public { // Expect the revert with `ZeroAddress` selector - vm.expectRevert(IOptimismSuperchainERC20Errors.ZeroAddress.selector); + vm.expectRevert(IOptimismSuperchainERC20.ZeroAddress.selector); // Call the `burn` function with the zero address vm.prank(L2_BRIDGE); @@ -207,7 +204,7 @@ contract OptimismSuperchainERC20Test is Test { // Look for the emit of the `Burn` event vm.expectEmit(address(optimismSuperchainERC20)); - emit IOptimismSuperchainERC20Extension.Burn(_from, _amount); + emit IOptimismSuperchainERC20.Burn(_from, _amount); // Call the `burn` function with the bridge caller vm.prank(L2_BRIDGE); @@ -245,14 +242,14 @@ contract OptimismSuperchainERC20Test is Test { /// @notice Tests that the `supportsInterface` function returns true for the `ISuperchainERC20` interface. function test_supportInterface_succeeds() public view { assertTrue(optimismSuperchainERC20.supportsInterface(type(IERC165).interfaceId)); - assertTrue(optimismSuperchainERC20.supportsInterface(type(IOptimismSuperchainERC20Extension).interfaceId)); + assertTrue(optimismSuperchainERC20.supportsInterface(type(IOptimismSuperchainERC20).interfaceId)); } /// @notice Tests that the `supportsInterface` function returns false for any other interface than the /// `ISuperchainERC20` one. function testFuzz_supportInterface_returnFalse(bytes4 _interfaceId) public view { vm.assume(_interfaceId != type(IERC165).interfaceId); - vm.assume(_interfaceId != type(IOptimismSuperchainERC20Extension).interfaceId); + vm.assume(_interfaceId != type(IOptimismSuperchainERC20).interfaceId); assertFalse(optimismSuperchainERC20.supportsInterface(_interfaceId)); } } diff --git a/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20Factory.t.sol b/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20Factory.t.sol index 3636317156a7..8d3a6d4f10bc 100644 --- a/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20Factory.t.sol +++ b/packages/contracts-bedrock/test/L2/OptimismSuperchainERC20Factory.t.sol @@ -11,6 +11,7 @@ import { CREATE3, Bytes32AddressLib } from "@rari-capital/solmate/src/utils/CREA // Target contract import { IOptimismSuperchainERC20 } from "src/L2/interfaces/IOptimismSuperchainERC20.sol"; import { IOptimismSuperchainERC20Factory } from "src/L2/interfaces/IOptimismSuperchainERC20Factory.sol"; +import { IERC20Metadata } from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol"; /// @title OptimismSuperchainERC20FactoryTest /// @notice Contract for testing the OptimismSuperchainERC20Factory contract. @@ -50,10 +51,10 @@ contract OptimismSuperchainERC20FactoryTest is Bridge_Initializer { // Assert assertTrue(addr == deployment); - assertTrue(IOptimismSuperchainERC20(deployment).decimals() == _decimals); + assertTrue(IERC20Metadata(deployment).decimals() == _decimals); assertTrue(IOptimismSuperchainERC20(deployment).remoteToken() == _remoteToken); - assertEq(IOptimismSuperchainERC20(deployment).name(), _name); - assertEq(IOptimismSuperchainERC20(deployment).symbol(), _symbol); + assertEq(IERC20Metadata(deployment).name(), _name); + assertEq(IERC20Metadata(deployment).symbol(), _symbol); assertEq(l2OptimismSuperchainERC20Factory.deployments(deployment), _remoteToken); } diff --git a/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol b/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol index eba6201c9756..976f5799200a 100644 --- a/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol +++ b/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol @@ -18,7 +18,7 @@ import { BeaconProxy } from "@openzeppelin/contracts-v5/proxy/beacon/BeaconProxy // Target contract import { SuperchainERC20 } from "src/L2/SuperchainERC20.sol"; import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol"; -import { ISuperchainERC20Errors } from "src/L2/interfaces/ISuperchainERC20.sol"; +import { ISuperchainERC20 } from "src/L2/interfaces/ISuperchainERC20.sol"; import { SuperchainERC20Implementation_MockContract } from "test/mocks/SuperchainERC20Implementation.sol"; /// @title SuperchainERC20Test @@ -47,7 +47,7 @@ contract SuperchainERC20Test is Test { vm.assume(_caller != SUPERCHAIN_ERC20_BRIDGE); // Expect the revert with `OnlySuperchainERC20Bridge` selector - vm.expectRevert(ISuperchainERC20Errors.OnlySuperchainERC20Bridge.selector); + vm.expectRevert(ISuperchainERC20.OnlySuperchainERC20Bridge.selector); // Call the `mint` function with the non-bridge caller vm.prank(_caller); @@ -92,7 +92,7 @@ contract SuperchainERC20Test is Test { vm.assume(_caller != SUPERCHAIN_ERC20_BRIDGE); // Expect the revert with `OnlySuperchainERC20Bridge` selector - vm.expectRevert(ISuperchainERC20Errors.OnlySuperchainERC20Bridge.selector); + vm.expectRevert(ISuperchainERC20.OnlySuperchainERC20Bridge.selector); // Call the `burn` function with the non-bridge caller vm.prank(_caller); diff --git a/packages/contracts-bedrock/test/L2/SuperchainERC20Bridge.t.sol b/packages/contracts-bedrock/test/L2/SuperchainERC20Bridge.t.sol index fbeb75d77660..b6ccc681068f 100644 --- a/packages/contracts-bedrock/test/L2/SuperchainERC20Bridge.t.sol +++ b/packages/contracts-bedrock/test/L2/SuperchainERC20Bridge.t.sol @@ -12,6 +12,7 @@ import { IL2ToL2CrossDomainMessenger } from "src/L2/interfaces/IL2ToL2CrossDomai import { ISuperchainERC20Bridge } from "src/L2/interfaces/ISuperchainERC20Bridge.sol"; import { ISuperchainERC20 } from "src/L2/interfaces/ISuperchainERC20.sol"; import { IOptimismSuperchainERC20Factory } from "src/L2/interfaces/IOptimismSuperchainERC20Factory.sol"; +import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; /// @title SuperchainERC20BridgeTest /// @notice Contract for testing the SuperchainERC20Bridge contract. @@ -70,8 +71,8 @@ contract SuperchainERC20BridgeTest is Bridge_Initializer { superchainERC20.__crosschainMint(_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); + uint256 _totalSupplyBefore = IERC20(address(superchainERC20)).totalSupply(); + uint256 _senderBalanceBefore = IERC20(address(superchainERC20)).balanceOf(_sender); // Look for the emit of the `Transfer` event vm.expectEmit(address(superchainERC20)); @@ -97,8 +98,8 @@ contract SuperchainERC20BridgeTest is Bridge_Initializer { 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); + assertEq(IERC20(address(superchainERC20)).totalSupply(), _totalSupplyBefore - _amount); + assertEq(IERC20(address(superchainERC20)).balanceOf(_sender), _senderBalanceBefore - _amount); } /// @notice Tests the `relayERC20` function reverts when the caller is not the L2ToL2CrossDomainMessenger. @@ -167,8 +168,8 @@ contract SuperchainERC20BridgeTest is Bridge_Initializer { ); // 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); + uint256 _totalSupplyBefore = IERC20(address(superchainERC20)).totalSupply(); + uint256 _toBalanceBefore = IERC20(address(superchainERC20)).balanceOf(_to); // Look for the emit of the `Transfer` event vm.expectEmit(address(superchainERC20)); @@ -183,7 +184,7 @@ contract SuperchainERC20BridgeTest is Bridge_Initializer { 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); + assertEq(IERC20(address(superchainERC20)).totalSupply(), _totalSupplyBefore + _amount); + assertEq(IERC20(address(superchainERC20)).balanceOf(_to), _toBalanceBefore + _amount); } }