Skip to content

Commit

Permalink
feat: SuperchainWETH redesign (#101)
Browse files Browse the repository at this point in the history
* feat: add superchain erc20 bridge (#61)

* feat: add superchain erc20 bridge

* fix: interfaces and versions

* refactor: optimism superchain erc20 redesign (#62)

* refactor: use oz upgradeable erc20 as dependency

* chore: update interfaces

* fix: tests based on changes

* refactor: remove op as dependency

* feat: add check for supererc20 bridge on modifier

* chore: update tests and interfaces

* chore: update stack vars name on test

* chore: remove empty gitmodules file

* chore: update superchain weth errors

* test: add superchain erc20 bridge tests (#65)

* test: add superchain erc20 bridge tests

* test: add optimism superchain erc20 beacon tests

* test: remove unnecessary test

* test: tests fixes

* test: tests fixes

* chore: update missing bridge on natspec (#69)

* chore: update missing bridge on natspec

* fix: natspecs

---------

Co-authored-by: agusduha <agusnduha@gmail.com>

* fix: remove superchain erc20 base (#70)

* refactor: update isuperchainweth (#71)


---------

Co-authored-by: agusduha <agusnduha@gmail.com>

* feat: rename mint/burn and add SuperchainERC20 (#74)

* refactor: rename mint and burn functions on superchain erc20

* chore: rename optimism superchain erc20 to superchain erc20

* feat: create optimism superchain erc20 contract

* chore: update natspec and errors

* fix: superchain erc20 tests

* refactor: make superchain erc20 abstract

* refactor: move storage and erc20 metadata functions to implementation

* chore: update interfaces

* chore: update superchain erc20 events

* fix: tests

* fix: natspecs

* fix: add semmver lock and snapshots

* fix: remove unused imports

* fix: natspecs

---------

Co-authored-by: 0xDiscotech <131301107+0xDiscotech@users.noreply.github.com>

* fix: refactor zero check (#76)

* fix: pre pr

* fix: semver natspec check failure (#79)

* fix: semver natspec check failure

* fix: ignore mock contracts in semver natspec script

* fix: error message

* feat: add crosschain erc20 interface (#80)

* feat: add crosschain erc20 interface

* fix: refactor interfaces

* fix: superchain bridge natspec (#83)

* fix: superchain weth natspec (#84)

Co-authored-by: 0xng <ng@defi.sucks>
Co-authored-by: 0xParticle <particle@defi.sucks>
Co-authored-by: gotzenx <78360669+gotzenx@users.noreply.github.com>

* fix: stop inheriting superchain interfaces (#85)

* fix: stop inheriting superchain interfaces

* fix: move events and erros into the implementation

* fix: make superchainERC20 inherits from crosschainERC20

* fix: superchain bridge rename (#86)

* fix: fee vault compiler error (#87)

* fix: remove unused imports

* fix: refactor common errors (#90)

* fix: refactor common errors

* fix: remove unused version

* fix: reuse unauthorized error (#92)

* fix: superchain erc20 factory conflicts

* fix: rename crosschain functions (#94)

* feat: superweth redesign

* fix: pr fixes

* fix: fixes post merge

---------

Co-authored-by: Disco <131301107+0xDiscotech@users.noreply.github.com>
Co-authored-by: 0xng <ng@defi.sucks>
Co-authored-by: 0xParticle <particle@defi.sucks>
Co-authored-by: gotzenx <78360669+gotzenx@users.noreply.github.com>
  • Loading branch information
5 people authored Oct 17, 2024
1 parent 527bf6c commit 79dd15c
Show file tree
Hide file tree
Showing 7 changed files with 262 additions and 456 deletions.
4 changes: 2 additions & 2 deletions packages/contracts-bedrock/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@
"sourceCodeHash": "0xaf2458e48dcadcafa8940cde7368549eae2280eef91247600d864ddac20f5d82"
},
"src/L2/SuperchainWETH.sol": {
"initCodeHash": "0x50f6ea9bfe650fcf792e98e44b1bf66c036fd0e6d4b753da680253d7d8609816",
"sourceCodeHash": "0x82d03262decf52d5954d40bca8703f96a0f3ba7accf6c1d75292856c2f34cf8f"
"initCodeHash": "0x76a6baa0823ca75f32a94ba49592f07129e762f9459be305b95b12475d8a5fce",
"sourceCodeHash": "0xbb6196751e8d1f0c7281bd824f0cb024dda726d65701def59cc3cb6d2bcbe6b3"
},
"src/L2/WETH.sol": {
"initCodeHash": "0xfb253765520690623f177941c2cd9eba23e4c6d15063bccdd5e98081329d8956",
Expand Down
129 changes: 45 additions & 84 deletions packages/contracts-bedrock/snapshots/abi/SuperchainWETH.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,42 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_from",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "crosschainBurn",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "crosschainMint",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
Expand Down Expand Up @@ -107,52 +143,6 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "dst",
"type": "address"
},
{
"internalType": "uint256",
"name": "wad",
"type": "uint256"
}
],
"name": "relayERC20",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "dst",
"type": "address"
},
{
"internalType": "uint256",
"name": "wad",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "chainId",
"type": "uint256"
}
],
"name": "sendERC20",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
Expand Down Expand Up @@ -289,28 +279,22 @@
{
"indexed": true,
"internalType": "address",
"name": "dst",
"name": "from",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "wad",
"name": "amount",
"type": "uint256"
}
],
"name": "Deposit",
"name": "CrosschainBurnt",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
Expand All @@ -322,15 +306,9 @@
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "source",
"type": "uint256"
}
],
"name": "RelayERC20",
"name": "CrosschainMinted",
"type": "event"
},
{
Expand All @@ -339,29 +317,17 @@
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"name": "dst",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "destination",
"name": "wad",
"type": "uint256"
}
],
"name": "SendERC20",
"name": "Deposit",
"type": "event"
},
{
Expand Down Expand Up @@ -410,17 +376,12 @@
},
{
"inputs": [],
"name": "CallerNotL2ToL2CrossDomainMessenger",
"type": "error"
},
{
"inputs": [],
"name": "InvalidCrossDomainSender",
"name": "NotCustomGasToken",
"type": "error"
},
{
"inputs": [],
"name": "NotCustomGasToken",
"name": "Unauthorized",
"type": "error"
}
]
95 changes: 43 additions & 52 deletions packages/contracts-bedrock/src/L2/SuperchainWETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,27 @@ import { Predeploys } from "src/libraries/Predeploys.sol";

// Interfaces
import { ISemver } from "src/universal/interfaces/ISemver.sol";
import { IL2ToL2CrossDomainMessenger } from "src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol";
import { IL1Block } from "src/L2/interfaces/IL1Block.sol";
import { IETHLiquidity } from "src/L2/interfaces/IETHLiquidity.sol";
import { ISuperchainWETH } from "src/L2/interfaces/ISuperchainWETH.sol";
import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol";
import { Unauthorized, NotCustomGasToken } from "src/libraries/errors/CommonErrors.sol";

/// @custom:proxied true
/// @custom:predeploy 0x4200000000000000000000000000000000000024
/// @title SuperchainWETH
/// @notice SuperchainWETH is a version of WETH that can be freely transfrered between chains
/// within the superchain. SuperchainWETH can be converted into native ETH on chains that
/// do not use a custom gas token.
contract SuperchainWETH is WETH98, ISuperchainWETH, ISemver {
contract SuperchainWETH is WETH98, ICrosschainERC20, ISemver {
/// @notice A modifier that only allows the SuperchainTokenBridge to call
modifier onlySuperchainTokenBridge() {
if (msg.sender != Predeploys.SUPERCHAIN_TOKEN_BRIDGE) revert Unauthorized();
_;
}

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

/// @inheritdoc WETH98
function deposit() public payable override {
Expand All @@ -37,63 +43,48 @@ contract SuperchainWETH is WETH98, ISuperchainWETH, ISemver {
super.withdraw(wad);
}

/// @inheritdoc ISuperchainWETH
function sendERC20(address dst, uint256 wad, uint256 chainId) public {
// Burn from user's balance.
_burn(msg.sender, wad);

// Burn to ETHLiquidity contract.
if (!IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).isCustomGasToken()) {
IETHLiquidity(Predeploys.ETH_LIQUIDITY).burn{ value: wad }();
}

// Send message to other chain.
IL2ToL2CrossDomainMessenger(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER).sendMessage({
_destination: chainId,
_target: address(this),
_message: abi.encodeCall(this.relayERC20, (msg.sender, dst, wad))
});
/// @notice Mints WETH to an address.
/// @param _guy The address to mint WETH to.
/// @param _wad The amount of WETH to mint.
function _mint(address _guy, uint256 _wad) internal {
balanceOf[_guy] += _wad;
emit Transfer(address(0), _guy, _wad);
}

// Emit event.
emit SendERC20(msg.sender, dst, wad, chainId);
/// @notice Burns WETH from an address.
/// @param _guy The address to burn WETH from.
/// @param _wad The amount of WETH to burn.
function _burn(address _guy, uint256 _wad) internal {
require(balanceOf[_guy] >= _wad);
balanceOf[_guy] -= _wad;
emit Transfer(_guy, address(0), _wad);
}

/// @inheritdoc ISuperchainWETH
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 CallerNotL2ToL2CrossDomainMessenger();
if (messenger.crossDomainMessageSender() != address(this)) revert InvalidCrossDomainSender();
/// @notice Allows the SuperchainTokenBridge to mint tokens.
/// @param _to Address to mint tokens to.
/// @param _amount Amount of tokens to mint.
function crosschainMint(address _to, uint256 _amount) external onlySuperchainTokenBridge {
_mint(_to, _amount);

// Mint from ETHLiquidity contract.
if (!IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).isCustomGasToken()) {
IETHLiquidity(Predeploys.ETH_LIQUIDITY).mint(wad);
IETHLiquidity(Predeploys.ETH_LIQUIDITY).mint(_amount);
}

// Get source chain ID.
uint256 source = messenger.crossDomainMessageSource();

// Mint to user's balance.
_mint(dst, wad);

// Emit event.
emit RelayERC20(from, dst, wad, source);
emit CrosschainMinted(_to, _amount);
}

/// @notice Mints WETH to an address.
/// @param guy The address to mint WETH to.
/// @param wad The amount of WETH to mint.
function _mint(address guy, uint256 wad) internal {
balanceOf[guy] += wad;
emit Transfer(address(0), guy, wad);
}
/// @notice Allows the SuperchainTokenBridge to burn tokens.
/// @param _from Address to burn tokens from.
/// @param _amount Amount of tokens to burn.
function crosschainBurn(address _from, uint256 _amount) external onlySuperchainTokenBridge {
_burn(_from, _amount);

/// @notice Burns WETH from an address.
/// @param guy The address to burn WETH from.
/// @param wad The amount of WETH to burn.
function _burn(address guy, uint256 wad) internal {
require(balanceOf[guy] >= wad);
balanceOf[guy] -= wad;
emit Transfer(guy, address(0), wad);
// Burn to ETHLiquidity contract.
if (!IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).isCustomGasToken()) {
IETHLiquidity(Predeploys.ETH_LIQUIDITY).burn{ value: _amount }();
}

emit CrosschainBurnt(_from, _amount);
}
}
41 changes: 5 additions & 36 deletions packages/contracts-bedrock/src/L2/interfaces/ISuperchainWETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,12 @@
pragma solidity ^0.8.0;

import { IWETH } from "src/universal/interfaces/IWETH.sol";
import { ICrosschainERC20 } from "src/L2/interfaces/ICrosschainERC20.sol";
import { ISemver } from "src/universal/interfaces/ISemver.sol";

interface ISuperchainWETH {
/// @notice Thrown when attempting a deposit or withdrawal and the chain uses a custom gas token.
interface ISuperchainWETH is IWETH, ICrosschainERC20, ISemver {
error Unauthorized();
error NotCustomGasToken();

/// @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 Emitted whenever tokens are successfully relayed on this chain.
/// @param from Address of the msg.sender of sendERC20 on the source chain.
/// @param to Address of the recipient.
/// @param amount Amount of tokens relayed.
/// @param source Chain ID of the source chain.
event RelayERC20(address indexed from, address indexed to, uint256 amount, uint256 source);

/// @notice Emitted when tokens are sent from one chain to another.
/// @param from Address of the sender.
/// @param to Address of the recipient.
/// @param amount Number of tokens sent.
/// @param destination Chain ID of the destination chain.
event SendERC20(address indexed from, address indexed to, uint256 amount, uint256 destination);

/// @notice Sends tokens to some target address on another chain.
/// @param _dst Address to send tokens to.
/// @param _wad Amount of tokens to send.
/// @param _chainId Chain ID of the destination chain.
function sendERC20(address _dst, uint256 _wad, uint256 _chainId) external;

/// @notice Relays tokens received from another chain.
/// @param _from Address of the msg.sender of sendERC20 on the source chain.
/// @param _dst Address to relay tokens to.
/// @param _wad Amount of tokens to relay.
function relayERC20(address _from, address _dst, uint256 _wad) external;
function __constructor__() external;
}

interface ISuperchainWETHERC20 is IWETH, ISuperchainWETH { }
Loading

0 comments on commit 79dd15c

Please sign in to comment.