diff --git a/packages/contracts-bedrock/semver-lock.json b/packages/contracts-bedrock/semver-lock.json index adae1ff092bf..22cc1486d02e 100644 --- a/packages/contracts-bedrock/semver-lock.json +++ b/packages/contracts-bedrock/semver-lock.json @@ -116,8 +116,8 @@ "sourceCodeHash": "0xfea53344596d735eff3be945ed1300dc75a6f8b7b2c02c0043af5b0036f5f239" }, "src/L2/OptimismSuperchainERC20.sol": { - "initCodeHash": "0xc6452d9aef6d76bdc789f3cddac6862658a481c619e6a2e7a74f6d61147f927b", - "sourceCodeHash": "0x4463e49c98ceb3327bd768579341d1e0863c8c3925d4b533fbc0f7951306261f" + "initCodeHash": "0x964c826693c6633dc5eff6d4b059a30043775af46b06e42367aff91b904498da", + "sourceCodeHash": "0xf5cb8307067f2ef7aa540b9e0a4828cde76f783c7fb95c7d3f84c6d723f9d316" }, "src/L2/OptimismSuperchainERC20Beacon.sol": { "initCodeHash": "0x99ce8095b23c124850d866cbc144fee6cee05dbc6bb5d83acadfe00b90cf42c7", @@ -133,11 +133,11 @@ }, "src/L2/SuperchainERC20.sol": { "initCodeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", - "sourceCodeHash": "0x9bc2e208774eb923894dbe391a5038a6189d7d36c202f4bf3e2c4dd332b0adf0" + "sourceCodeHash": "0x4debbf83ad569eae88fb1e70db5f45fb85eed609fd464bd180611756116e04ae" }, "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..5c0d8bcb8074 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" @@ -427,7 +427,7 @@ { "indexed": true, "internalType": "address", - "name": "account", + "name": "from", "type": "address" }, { @@ -443,14 +443,20 @@ { "anonymous": false, "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, { "indexed": false, - "internalType": "uint64", - "name": "version", - "type": "uint64" + "internalType": "uint256", + "name": "amount", + "type": "uint256" } ], - "name": "Initialized", + "name": "CrosschainBurnt", "type": "event" }, { @@ -459,7 +465,7 @@ { "indexed": true, "internalType": "address", - "name": "account", + "name": "to", "type": "address" }, { @@ -469,26 +475,20 @@ "type": "uint256" } ], - "name": "Mint", + "name": "CrosschainMinted", "type": "event" }, { "anonymous": false, "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, { "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" + "internalType": "uint64", + "name": "version", + "type": "uint64" } ], - "name": "SuperchainBurnt", + "name": "Initialized", "type": "event" }, { @@ -497,7 +497,7 @@ { "indexed": true, "internalType": "address", - "name": "account", + "name": "to", "type": "address" }, { @@ -507,7 +507,7 @@ "type": "uint256" } ], - "name": "SuperchainMinted", + "name": "Mint", "type": "event" }, { 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 6c48b231baaf..c2ef27ebc273 100644 --- a/packages/contracts-bedrock/src/L2/SuperchainERC20.sol +++ b/packages/contracts-bedrock/src/L2/SuperchainERC20.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import { ISuperchainERC20Extension } 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"; @@ -10,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, ISuperchainERC20Extension, 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(); @@ -26,18 +26,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..c156b79dc609 --- /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 Defines the interface for crosschain ERC20 transfers. +interface ICrosschainERC20 { + /// @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 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 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 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..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 { ISuperchainERC20, 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 47341c559719..cc96520355f9 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol @@ -2,41 +2,11 @@ pragma solidity ^0.8.0; // Interfaces -import { IERC20Solady } from "src/vendor/interfaces/IERC20Solady.sol"; +import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.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 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; -} - -/// @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 30b758a38e6d..976f5799200a 100644 --- a/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol +++ b/packages/contracts-bedrock/test/L2/SuperchainERC20.t.sol @@ -16,8 +16,9 @@ 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 { ISuperchainERC20Errors } from "src/L2/interfaces/ISuperchainERC20.sol"; +import { SuperchainERC20 } from "src/L2/SuperchainERC20.sol"; +import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol"; +import { ISuperchainERC20 } from "src/L2/interfaces/ISuperchainERC20.sol"; import { SuperchainERC20Implementation_MockContract } from "test/mocks/SuperchainERC20Implementation.sol"; /// @title SuperchainERC20Test @@ -41,20 +42,20 @@ 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); // 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); - 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 @@ -91,21 +92,21 @@ 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); - 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..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. @@ -67,11 +68,11 @@ 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(); - 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); } } 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);