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

refactor: optimism superchain erc20 redesign #62

Merged
merged 6 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 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": "0x4fd71b5352b78d51d39625b6defa77a75be53067b32f3cba86bd17a46917adf9",
"sourceCodeHash": "0xad3934ea533544b3c130c80be26201354af85f9166cb2ce54d96e5e383ebb5c1"
"initCodeHash": "0x9b48e5b8271d9b5d4407bf1a7327842844b4bd858123ffa6da0c55ad9d3b9d8e",
"sourceCodeHash": "0xaf5702655736e9c4b480a0bb4f0f2220f09834b2292f8e5419b5b245e0a20300"
},
"src/L2/OptimismSuperchainERC20Beacon.sol": {
"initCodeHash": "0x99ce8095b23c124850d866cbc144fee6cee05dbc6bb5d83acadfe00b90cf42c7",
Expand All @@ -136,8 +136,8 @@
"sourceCodeHash": "0xb11ce94fd6165d8ca86eebafc7235e0875380d1a5d4e8b267ff0c6477083b21c"
},
"src/L2/SuperchainWETH.sol": {
"initCodeHash": "0xd8766c7ab41d34d935febf5b48289f947804634bde38f8e346075b9f2d867275",
"sourceCodeHash": "0x6c1691c0fb5c86f1fd67e23495725c2cd86567556602e8cc0f28104ad6114bf4"
"initCodeHash": "0x702ff6dc90e7e02085e95e3510590cce9bf44a7ea06bfbb8f7a47e203a8809b2",
"sourceCodeHash": "0x823ded4da0dc1f44bc87b5e46d0a1c90c76f76e0f36c294c5410c4755886c925"
},
"src/L2/WETH.sol": {
"initCodeHash": "0xfb253765520690623f177941c2cd9eba23e4c6d15063bccdd5e98081329d8956",
Expand Down
120 changes: 1 addition & 119 deletions packages/contracts-bedrock/snapshots/abi/OptimismSuperchainERC20.json
Original file line number Diff line number Diff line change
Expand Up @@ -236,29 +236,6 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_from",
"type": "address"
},
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "relayERC20",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "remoteToken",
Expand All @@ -272,29 +249,6 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_chainId",
"type": "uint256"
}
],
"name": "sendERC20",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down Expand Up @@ -482,68 +436,6 @@
"name": "Mint",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "source",
"type": "uint256"
}
],
"name": "RelayERC20",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "destination",
"type": "uint256"
}
],
"name": "SendERC20",
"type": "event"
},
{
"anonymous": false,
"inputs": [
Expand Down Expand Up @@ -579,11 +471,6 @@
"name": "AllowanceUnderflow",
"type": "error"
},
{
"inputs": [],
"name": "CallerNotL2ToL2CrossDomainMessenger",
"type": "error"
},
{
"inputs": [],
"name": "InsufficientAllowance",
Expand All @@ -594,11 +481,6 @@
"name": "InsufficientBalance",
"type": "error"
},
{
"inputs": [],
"name": "InvalidCrossDomainSender",
"type": "error"
},
{
"inputs": [],
"name": "InvalidInitialization",
Expand All @@ -616,7 +498,7 @@
},
{
"inputs": [],
"name": "OnlyBridge",
"name": "OnlyAuthorizedBridge",
"type": "error"
},
{
Expand Down
12 changes: 11 additions & 1 deletion packages/contracts-bedrock/snapshots/abi/SuperchainWETH.json
Original file line number Diff line number Diff line change
Expand Up @@ -408,14 +408,24 @@
"name": "Withdrawal",
"type": "event"
},
{
"inputs": [],
"name": "CallerNotL2ToL2CrossDomainMessenger",
"type": "error"
},
{
"inputs": [],
"name": "InvalidCrossDomainSender",
"type": "error"
},
Comment on lines +411 to +420
Copy link
Member

Choose a reason for hiding this comment

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

Hmm the weth contract does not use these errors

idk if there is a better way to omit them, or maybe replace the current ones with these because they are more explicit, wdyt?

Copy link
Author

Choose a reason for hiding this comment

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

I'm up to replace them since they're way more explicit

{
"inputs": [],
"name": "NotCustomGasToken",
"type": "error"
},
{
"inputs": [],
"name": "Unauthorized",
"name": "ZeroAddress",
"type": "error"
}
]
31 changes: 10 additions & 21 deletions packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@ import { IOptimismSuperchainERC20Extension } from "src/L2/interfaces/IOptimismSu
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";
import { ERC165 } from "@openzeppelin/contracts-v5/utils/introspection/ERC165.sol";

/// @notice Thrown when attempting to mint or burn tokens and the function caller is not the StandardBridge.
error OnlyBridge();

/// @custom:proxied true
/// @title OptimismSuperchainERC20
Expand All @@ -21,16 +17,7 @@ error OnlyBridge();
/// 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
IOptimismSuperchainERC20Extension,
SuperchainERC20,
ISemver,
Initializable,
ERC165
{
/// @notice Address of the StandardBridge Predeploy.
address internal constant BRIDGE = Predeploys.L2_STANDARD_BRIDGE;

contract OptimismSuperchainERC20 is ERC20, Initializable, ERC165, IOptimismSuperchainERC20Extension, ISemver {
/// @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 @@ -57,14 +44,16 @@ contract OptimismSuperchainERC20 is
}

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

/// @notice Semantic version.
/// @custom:semver 1.0.0-beta.2
string public constant version = "1.0.0-beta.2";
/// @custom:semver 1.0.0-beta.3
string public constant version = "1.0.0-beta.3";

/// @notice Constructs the OptimismSuperchainERC20 contract.
constructor() {
Expand Down Expand Up @@ -95,7 +84,7 @@ contract OptimismSuperchainERC20 is
/// @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 onlyBridge {
function mint(address _to, uint256 _amount) external virtual onlyAuthorizedBridge {
if (_to == address(0)) revert ZeroAddress();

_mint(_to, _amount);
Expand All @@ -106,7 +95,7 @@ contract OptimismSuperchainERC20 is
/// @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 onlyBridge {
function burn(address _from, uint256 _amount) external virtual onlyAuthorizedBridge {
if (_from == address(0)) revert ZeroAddress();

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

import { ISuperchainERC20Extensions, ISuperchainERC20Errors } from "src/L2/interfaces/ISuperchainERC20.sol";
import { ISuperchainERC20Extensions } from "src/L2/interfaces/ISuperchainERC20.sol";
import { ERC20 } from "@solady/tokens/ERC20.sol";
import { IL2ToL2CrossDomainMessenger } from "src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";
Expand All @@ -10,7 +10,7 @@ import { Predeploys } from "src/libraries/Predeploys.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. It builds on top of the L2ToL2CrossDomainMessenger for
/// both replay protection and domain binding.
abstract contract SuperchainERC20 is ISuperchainERC20Extensions, ISuperchainERC20Errors, ERC20 {
abstract contract SuperchainERC20 is ERC20, ISuperchainERC20Extensions {
/// @notice Address of the L2ToL2CrossDomainMessenger Predeploy.
address internal constant MESSENGER = Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER;

Expand Down
8 changes: 4 additions & 4 deletions packages/contracts-bedrock/src/L2/SuperchainWETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import { IETHLiquidity } from "src/L2/interfaces/IETHLiquidity.sol";
/// do not use a custom gas token.
contract SuperchainWETH is WETH98, ISuperchainERC20Extensions, ISemver {
/// @notice Semantic version.
/// @custom:semver 1.0.0-beta.4
string public constant version = "1.0.0-beta.4";
/// @custom:semver 1.0.0-beta.5
string public constant version = "1.0.0-beta.5";

/// @inheritdoc WETH98
function deposit() public payable override {
Expand Down Expand Up @@ -61,8 +61,8 @@ contract SuperchainWETH is WETH98, ISuperchainERC20Extensions, ISemver {
function relayERC20(address from, address dst, uint256 wad) external {
// Receive message from other chain.
IL2ToL2CrossDomainMessenger messenger = IL2ToL2CrossDomainMessenger(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER);
if (msg.sender != address(messenger)) revert Unauthorized();
if (messenger.crossDomainMessageSender() != address(this)) revert Unauthorized();
if (msg.sender != address(messenger)) revert CallerNotL2ToL2CrossDomainMessenger();
if (messenger.crossDomainMessageSender() != address(this)) revert InvalidCrossDomainSender();

// Mint from ETHLiquidity contract.
if (!IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).isCustomGasToken()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,23 @@ pragma solidity ^0.8.0;

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

/// @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();
}

/// @title IOptimismSuperchainERC20Extension
/// @notice This interface is available on the OptimismSuperchainERC20 contract.
/// We declare it as a separate interface so that it can be used in
/// custom implementations of SuperchainERC20.
interface IOptimismSuperchainERC20Extension is ISuperchainERC20Extensions, ISuperchainERC20Errors {
interface IOptimismSuperchainERC20Extension is 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 Down
33 changes: 16 additions & 17 deletions packages/contracts-bedrock/src/L2/interfaces/ISuperchainERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,25 @@ 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 relay a message and the function caller (msg.sender) is not
/// L2ToL2CrossDomainMessenger.
error CallerNotL2ToL2CrossDomainMessenger();

/// @notice Thrown when attempting to relay a message and the cross domain message sender is not `address(this)`
error InvalidCrossDomainSender();

/// @notice Thrown when attempting to perform an operation and the account is the zero address.
error ZeroAddress();
}

/// @title ISuperchainERC20Extensions
/// @notice Interface for the extensions to the ERC20 standard that are used by SuperchainERC20.
/// Exists in case developers are already importing the ERC20 interface separately and
/// importing the full SuperchainERC20 interface would cause conflicting imports.
interface ISuperchainERC20Extensions {
interface ISuperchainERC20Extensions is ISuperchainERC20Errors {
/// @notice Emitted when tokens are sent from one chain to another.
/// @param from Address of the sender.
/// @param to Address of the recipient.
Expand Down Expand Up @@ -36,21 +50,6 @@ interface ISuperchainERC20Extensions {
function relayERC20(address _from, address _to, uint256 _amount) external;
}

/// @title ISuperchainERC20Errors
/// @notice Interface containing the errors added in the SuperchainERC20 implementation.
interface ISuperchainERC20Errors {
/// @notice Thrown when attempting to relay a message and the function caller (msg.sender) is not
/// L2ToL2CrossDomainMessenger.
error CallerNotL2ToL2CrossDomainMessenger();

/// @notice Thrown when attempting to relay a message and the cross domain message sender is not this
/// SuperchainERC20.
error InvalidCrossDomainSender();

/// @notice Thrown when attempting to perform an operation and the account is the zero address.
error ZeroAddress();
}

/// @title ISuperchainERC20
/// @notice Combines Solady's ERC20 interface with the SuperchainERC20Extensions interface.
interface ISuperchainERC20 is IERC20Solady, ISuperchainERC20Extensions, ISuperchainERC20Errors { }
Copy link
Member

@agusduha agusduha Sep 25, 2024

Choose a reason for hiding this comment

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

Same here, but leaving it as it is because it uses solady

interface ISuperchainERC20 is IERC20Solady, ISuperchainERC20Extensions { }
Loading