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: SuperchainWETH redesign #12514

Merged
Show file tree
Hide file tree
Changes from 4 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
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": "0x09c7efed7d6c8ae5981f6e7a75c7b8c675f73d679265d15a010844ad9b41fa9b",
"sourceCodeHash": "0x8d7612a71deaadfb324c4136673df96019211292ff54494fa4b7724e2e5dd22a"
},
"src/L2/WETH.sol": {
"initCodeHash": "0xfb253765520690623f177941c2cd9eba23e4c6d15063bccdd5e98081329d8956",
Expand Down
131 changes: 46 additions & 85 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 @@ -249,7 +239,7 @@
"inputs": [
{
"internalType": "uint256",
"name": "wad",
"name": "_amount",
"type": "uint256"
}
],
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"
}
]
94 changes: 41 additions & 53 deletions packages/contracts-bedrock/src/L2/SuperchainWETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@ 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 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 @@ -32,68 +32,56 @@ contract SuperchainWETH is WETH98, ISuperchainWETH, ISemver {
}

/// @inheritdoc WETH98
function withdraw(uint256 wad) public override {
function withdraw(uint256 _amount) public override {
if (IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).isCustomGasToken()) revert NotCustomGasToken();
super.withdraw(wad);
super.withdraw(_amount);
}

/// @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 _to The address to mint WETH to.
/// @param _amount The amount of WETH to mint.
function _mint(address _to, uint256 _amount) internal {
balanceOf[_to] += _amount;
emit Transfer(address(0), _to, _amount);
}

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

/// @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 {
if (msg.sender != Predeploys.SUPERCHAIN_TOKEN_BRIDGE) revert Unauthorized();

_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();
emit CrosschainMinted(_to, _amount);
}

// Mint to user's balance.
_mint(dst, 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 {
if (msg.sender != Predeploys.SUPERCHAIN_TOKEN_BRIDGE) revert Unauthorized();

// Emit event.
emit RelayERC20(from, dst, wad, source);
}
_burn(_from, _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);
}
// Burn to ETHLiquidity contract.
if (!IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).isCustomGasToken()) {
IETHLiquidity(Predeploys.ETH_LIQUIDITY).burn{ value: _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);
emit CrosschainBurnt(_from, _amount);
}
}
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