Skip to content
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

feat: rename mint/burn and add SuperchainERC20 #74

Merged
merged 10 commits into from
Oct 1, 2024
12 changes: 8 additions & 4 deletions packages/contracts-bedrock/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@
"sourceCodeHash": "0x4b806cc85cead74c8df34ab08f4b6c6a95a1a387a335ec8a7cb2de4ea4e1cf41"
},
"src/L2/OptimismSuperchainERC20.sol": {
"initCodeHash": "0x749dacbd29aad60c71c1e1878b21854c796759fb7a5ddc549b96ab9e39bb62b8",
"sourceCodeHash": "0xd067ddabbeb6fe1c3886100b16c905b57dfd44f5e6e893323217fe4e642285d4"
"initCodeHash": "0xfdb4acd9496a7d3949f71e7e98786ff909730a8ad62d33cf7e29765dceecc6db",
"sourceCodeHash": "0x2502433e4b622e1697ca071f91a95b08fa40fdb03bfd958c44b2033a47df2010"
},
"src/L2/OptimismSuperchainERC20Beacon.sol": {
"initCodeHash": "0x99ce8095b23c124850d866cbc144fee6cee05dbc6bb5d83acadfe00b90cf42c7",
Expand All @@ -131,9 +131,13 @@
"initCodeHash": "0x2e6551705e493bacba8cffe22e564d5c401ae5bb02577a5424e0d32784e13e74",
"sourceCodeHash": "0xd56922cb04597dea469c65e5a49d4b3c50c171e603601e6f41da9517cae0b11a"
},
"src/L2/SuperchainERC20.sol": {
"initCodeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
"sourceCodeHash": "0xddd32f6332510e63d8c98d70321e058b71eda02e6b32a9b6e41540c58d1e653e"
},
"src/L2/SuperchainERC20Bridge.sol": {
"initCodeHash": "0x802574bf35587e9a8dc2416e91b9fd1411c75d219545b8b55d25a75452459b10",
"sourceCodeHash": "0xb11ce94fd6165d8ca86eebafc7235e0875380d1a5d4e8b267ff0c6477083b21c"
"initCodeHash": "0x77d3173e1f269f6bf57f85685abecb4979a7d7d3c672c7afa2a648b66228122f",
"sourceCodeHash": "0xf0749a0b9366a06981d2a8f66a55ce1a37e3d5d7dd77704f618741c18cd79009"
},
"src/L2/SuperchainWETH.sol": {
"initCodeHash": "0xf30071df59d85e0e8a552845031aca8d6f0261762e1b4ea1b28ff30379eaa20e",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,42 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_from",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "__superchainBurn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "__superchainMint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down Expand Up @@ -436,6 +472,44 @@
"name": "Mint",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "SuperchainBurn",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "SuperchainMint",
"type": "event"
},
{
"anonymous": false,
"inputs": [
Expand Down Expand Up @@ -498,7 +572,12 @@
},
{
"inputs": [],
"name": "OnlyAuthorizedBridge",
"name": "OnlyL2StandardBridge",
"type": "error"
},
{
"inputs": [],
"name": "OnlySuperchainERC20Bridge",
"type": "error"
},
{
Expand Down
26 changes: 12 additions & 14 deletions packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
pragma solidity 0.8.25;

import { IOptimismSuperchainERC20Extension } from "src/L2/interfaces/IOptimismSuperchainERC20.sol";
import { IL2ToL2CrossDomainMessenger } from "src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol";
import { ISemver } from "src/universal/interfaces/ISemver.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";
import { ERC165 } from "@openzeppelin/contracts-v5/utils/introspection/ERC165.sol";
import { ERC20 } from "@solady/tokens/ERC20.sol";
import { SuperchainERC20 } from "src/L2/SuperchainERC20.sol";
import { Initializable } from "@openzeppelin/contracts-v5/proxy/utils/Initializable.sol";

/// @custom:proxied true
Expand All @@ -17,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 ERC20, Initializable, ERC165, IOptimismSuperchainERC20Extension, ISemver {
contract OptimismSuperchainERC20 is SuperchainERC20, Initializable, ERC165, IOptimismSuperchainERC20Extension {
/// @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 =
Expand All @@ -43,17 +41,17 @@ contract OptimismSuperchainERC20 is ERC20, Initializable, ERC165, IOptimismSuper
}
}

/// @notice A modifier that only allows the bridge to call
modifier onlyAuthorizedBridge() {
if (msg.sender != Predeploys.L2_STANDARD_BRIDGE && msg.sender != Predeploys.SUPERCHAIN_ERC20_BRIDGE) {
revert OnlyAuthorizedBridge();
/// @notice A modifier that only allows the L2StandardBridge to call
modifier onlyL2StandardBridge() {
if (msg.sender != Predeploys.L2_STANDARD_BRIDGE) {
revert OnlyL2StandardBridge();
}
_;
}

/// @notice Semantic version.
/// @custom:semver 1.0.0-beta.5
string public constant version = "1.0.0-beta.5";
/// @custom:semver 1.0.0-beta.6
string public constant override version = "1.0.0-beta.6";

/// @notice Constructs the OptimismSuperchainERC20 contract.
constructor() {
Expand Down Expand Up @@ -81,21 +79,21 @@ contract OptimismSuperchainERC20 is ERC20, Initializable, ERC165, IOptimismSuper
_storage.decimals = _decimals;
}

/// @notice Allows the L2StandardBridge and SuperchainERC20Bridge to mint tokens.
/// @notice Allows the L2StandardBridge to mint tokens.
/// @param _to Address to mint tokens to.
/// @param _amount Amount of tokens to mint.
function mint(address _to, uint256 _amount) external virtual onlyAuthorizedBridge {
function mint(address _to, uint256 _amount) external virtual onlyL2StandardBridge {
if (_to == address(0)) revert ZeroAddress();

_mint(_to, _amount);

emit Mint(_to, _amount);
}

/// @notice Allows the L2StandardBridge and SuperchainERC20Bridge to burn tokens.
/// @notice Allows the L2StandardBridge to burn tokens.
/// @param _from Address to burn tokens from.
/// @param _amount Amount of tokens to burn.
function burn(address _from, uint256 _amount) external virtual onlyAuthorizedBridge {
function burn(address _from, uint256 _amount) external virtual onlyL2StandardBridge {
if (_from == address(0)) revert ZeroAddress();

_burn(_from, _amount);
Expand Down
47 changes: 47 additions & 0 deletions packages/contracts-bedrock/src/L2/SuperchainERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;

import { ISuperchainERC20Extension } 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";

/// @title SuperchainERC20
/// @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 {
/// @notice A modifier that only allows the SuperchainERC20Bridge to call
modifier onlySuperchainERC20Bridge() {
if (msg.sender != Predeploys.SUPERCHAIN_ERC20_BRIDGE) revert OnlySuperchainERC20Bridge();
_;
}

/// @notice Semantic version.
/// @custom:semver 1.0.0-beta.1
function version() external pure virtual returns (string memory) {
return "1.0.0-beta.1";
}

/// @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 {
if (_to == address(0)) revert ZeroAddress();

_mint(_to, _amount);

emit SuperchainMint(_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 {
if (_from == address(0)) revert ZeroAddress();

_burn(_from, _amount);

emit SuperchainBurn(_from, _amount);
}
}
6 changes: 3 additions & 3 deletions packages/contracts-bedrock/src/L2/SuperchainERC20Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Predeploys } from "src/libraries/Predeploys.sol";

// Interfaces
import { ISuperchainERC20Bridge } from "src/L2/interfaces/ISuperchainERC20Bridge.sol";
import { IMintableAndBurnableERC20 } from "src/L2/interfaces/IMintableAndBurnableERC20.sol";
import { ISuperchainERC20 } from "src/L2/interfaces/ISuperchainERC20.sol";
import { IL2ToL2CrossDomainMessenger } from "src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol";

/// @custom:proxied true
Expand All @@ -29,7 +29,7 @@ contract SuperchainERC20Bridge is ISuperchainERC20Bridge {
/// @param _amount Amount of tokens to send.
/// @param _chainId Chain ID of the destination chain.
function sendERC20(address _token, address _to, uint256 _amount, uint256 _chainId) external {
IMintableAndBurnableERC20(_token).burn(msg.sender, _amount);
ISuperchainERC20(_token).__superchainBurn(msg.sender, _amount);

bytes memory message = abi.encodeCall(this.relayERC20, (_token, msg.sender, _to, _amount));
IL2ToL2CrossDomainMessenger(MESSENGER).sendMessage(_chainId, address(this), message);
Expand All @@ -51,7 +51,7 @@ contract SuperchainERC20Bridge is ISuperchainERC20Bridge {

uint256 source = IL2ToL2CrossDomainMessenger(MESSENGER).crossDomainMessageSource();

IMintableAndBurnableERC20(_token).mint(_to, _amount);
ISuperchainERC20(_token).__superchainMint(_to, _amount);

emit RelayERC20(_token, _from, _to, _amount, source);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ pragma solidity ^0.8.0;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IStandardBridge } from "src/universal/interfaces/IStandardBridge.sol";
import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMessenger.sol";

interface IMintableAndBurnable is IERC20 {
function mint(address, uint256) external;
function burn(address, uint256) external;
}
import { IMintableAndBurnableERC20 } from "src/L2/interfaces/IMintableAndBurnableERC20.sol";

interface IL2StandardBridgeInterop is IStandardBridge {
error InvalidDecimals();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,19 @@
pragma solidity ^0.8.0;

// Interfaces
import { ISuperchainERC20, ISuperchainERC20Extension } from "src/L2/interfaces/ISuperchainERC20.sol";
import { IERC20Solady } from "src/vendor/interfaces/IERC20Solady.sol";

/// @title IOptimismSuperchainERC20Errors
/// @notice Interface containing the errors added in the OptimismSuperchainERC20 implementation.
/// @title ISuperchainERC20Errors
/// @notice Interface containing the errors added in the SuperchainERC20 implementation.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// @title ISuperchainERC20Errors
/// @notice Interface containing the errors added in the SuperchainERC20 implementation.
/// @title IOptimismSuperchainERC20Errors
/// @notice Interface containing the errors added in the OptimismSuperchainERC20 implementation.

interface IOptimismSuperchainERC20Errors {
/// @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 StandardBridge or the
/// SuperchainERC20Bridge.
error OnlyAuthorizedBridge();
/// @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 IOptimismSuperchainERC20Errors {
/// @title ISuperchainERC20Extension
/// @notice This interface is available on the SuperchainERC20 contract.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// @title ISuperchainERC20Extension
/// @notice This interface is available on the SuperchainERC20 contract.
/// @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 amount Amount of tokens minted.
Expand All @@ -42,6 +39,6 @@ interface IOptimismSuperchainERC20Extension is IOptimismSuperchainERC20Errors {
function remoteToken() external view returns (address);
}

/// @title IOptimismSuperchainERC20
/// @notice Combines Solady's ERC20 interface with the OptimismSuperchainERC20Extension interface.
/// @title ISuperchainERC20
/// @notice Combines Solady's ERC20 interface with the SuperchainERC20Extension interface.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// @title ISuperchainERC20
/// @notice Combines Solady's ERC20 interface with the SuperchainERC20Extension interface.
/// @title IOptimismSuperchainERC20
/// @notice Combines Solady's ERC20 interface with the IOptimismSuperchainERC20Extension interface.

interface IOptimismSuperchainERC20 is IERC20Solady, IOptimismSuperchainERC20Extension { }
43 changes: 43 additions & 0 deletions packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Interfaces
import { IERC20Solady } from "src/vendor/interfaces/IERC20Solady.sol";

/// @title ISuperchainERC20Errors
/// @notice Interface containing the errors added in the SuperchainERC20 implementation.
interface ISuperchainERC20Errors {
/// @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 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 SuperchainMint(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 SuperchainBurn(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 { }
Loading