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: introduce OptimismSuperchainERC20 #11256

Merged
merged 22 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@
[submodule "packages/contracts-bedrock/lib/automate"]
path = packages/contracts-bedrock/lib/automate
url = https://github.com/gelatodigital/automate
[submodule "packages/contracts-bedrock/lib/openzeppelin-contracts-v5"]
path = packages/contracts-bedrock/lib/openzeppelin-contracts-v5
url = https://github.com/OpenZeppelin/openzeppelin-contracts
1 change: 1 addition & 0 deletions packages/contracts-bedrock/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ optimizer_runs = 999999
remappings = [
'@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts',
'@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts',
'@openzeppelin/contracts-v5/=lib/openzeppelin-contracts-v5/contracts',
'@rari-capital/solmate/=lib/solmate',
'@lib-keccak/=lib/lib-keccak/contracts/lib',
'@solady/=lib/solady/src',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# `OptimismSuperchainERC20` Invariants

## Calls to sendERC20 should always succeed as long as the actor has enough balance. Actor's balance should also not increase out of nowhere.
**Test:** [`OptimismSuperchainERC20.t.sol#L150`](../test/invariants/OptimismSuperchainERC20.t.sol#L150)
**Test:** [`OptimismSuperchainERC20.t.sol#L177`](../test/invariants/OptimismSuperchainERC20.t.sol#L177)

4 changes: 2 additions & 2 deletions packages/contracts-bedrock/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@
"sourceCodeHash": "0x1f14aafab2cb15970cccedb461b72218fca8afa6ffd0ac696a9e28ff1415a068"
},
"src/L2/OptimismSuperchainERC20.sol": {
"initCodeHash": "0x3ca4452dc167b6705a017016c9f1bf7f765cf871efdac56707735d6b9354d5e8",
"sourceCodeHash": "0x99861db89dde9af91df484816d35b4fd29b612d08cb6ef242699f627756602c4"
"initCodeHash": "0xbfa1d35644a8b97c657101289e64b92b8faeed0b0090195eb871da2de4583bb3",
"sourceCodeHash": "0x56bed1f02792ef9513fe209552e964c983a8f29dbcb2b8a76910fdae929f30ff"
},
"src/L2/SequencerFeeVault.sol": {
"initCodeHash": "0xb94145f571e92ee615c6fe903b6568e8aac5fe760b6b65148ffc45d2fb0f5433",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,22 +119,22 @@
"inputs": [
{
"internalType": "address",
"name": "__remoteToken",
"name": "_remoteToken",
"type": "address"
},
{
"internalType": "string",
"name": "__name",
"name": "_name",
"type": "string"
},
{
"internalType": "string",
"name": "__symbol",
"name": "_symbol",
"type": "string"
},
{
"internalType": "uint8",
"name": "__decimals",
"name": "_decimals",
"type": "uint8"
}
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1 @@
[
{
"bytes": "20",
"label": "_remoteToken",
"offset": 0,
"slot": "0",
"type": "address"
},
{
"bytes": "32",
"label": "_name",
"offset": 0,
"slot": "1",
"type": "string"
},
{
"bytes": "32",
"label": "_symbol",
"offset": 0,
"slot": "2",
"type": "string"
},
{
"bytes": "1",
"label": "_decimals",
"offset": 0,
"slot": "3",
"type": "uint8"
}
]
[]
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,6 @@ interface IOptimismSuperchainERC20 {
/// @param _amount Amount of tokens to relay.
function relayERC20(address _from, address _to, uint256 _amount) external;

/// @notice Returns the address of the corresponding remote token.
/// @notice Returns the address of the corresponding version of this token on the remote chain.
function remoteToken() external view returns (address);
}
69 changes: 41 additions & 28 deletions packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ERC20 } from "@solady/tokens/ERC20.sol";
import { IL2ToL2CrossDomainMessenger } from "src/L2/IL2ToL2CrossDomainMessenger.sol";
import { ISemver } from "src/universal/ISemver.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";
import { Initializable } from "@solady/utils/Initializable.sol";
import { Initializable } from "@openzeppelin/contracts-v5/proxy/utils/Initializable.sol";

/// @notice Thrown when attempting to relay a message and the function caller (msg.sender) is not
/// L2ToL2CrossDomainMessenger.
Expand Down Expand Up @@ -37,17 +37,29 @@ contract OptimismSuperchainERC20 is IOptimismSuperchainERC20, ERC20, ISemver, In
/// @notice Address of the StandardBridge Predeploy.
address internal constant BRIDGE = Predeploys.L2_STANDARD_BRIDGE;

/// @notice Address of the corresponding version of this token on the remote chain.
address private _remoteToken;

/// @notice Name of the token
string private _name;

/// @notice Symbol of the token
string private _symbol;
/// @notice Storage slot that the OptimismSuperchainERC20Metadata struct is stored at.
bytes32 internal constant OPTIMISM_SUPERCHAIN_ERC20_METADATA_SLOT =
tynes marked this conversation as resolved.
Show resolved Hide resolved
bytes32(uint256(keccak256("optimismSuperchainERC20Metadata")) - 1);

/// @notice Storage struct for the OptimismSuperchainERC20 metadata.
struct OptimismSuperchainERC20Metadata {
/// @notice Address of the corresponding version of this token on the remote chain.
address remoteToken;
/// @notice Name of the token
string name;
/// @notice Symbol of the token
string symbol;
/// @notice Decimals of the token
uint8 decimals;
}

/// @notice Decimals of the token
uint8 private _decimals;
/// @notice Returns the storage for the OptimismSuperchainERC20Metadata.
function _getMetadataStorage() private pure returns (OptimismSuperchainERC20Metadata storage _storage) {
bytes32 _slot = OPTIMISM_SUPERCHAIN_ERC20_METADATA_SLOT;
assembly {
_storage.slot := _slot
}
}

/// @notice A modifier that only allows the bridge to call
modifier onlyBridge() {
Expand All @@ -65,23 +77,24 @@ contract OptimismSuperchainERC20 is IOptimismSuperchainERC20, ERC20, ISemver, In
}

/// @notice Initializes the contract.
/// @param __remoteToken Address of the corresponding remote token.
/// @param __name ERC20 name.
/// @param __symbol ERC20 symbol.
/// @param __decimals ERC20 decimals.
/// @param _remoteToken Address of the corresponding remote token.
/// @param _name ERC20 name.
/// @param _symbol ERC20 symbol.
/// @param _decimals ERC20 decimals.
function initialize(
address __remoteToken,
string memory __name,
string memory __symbol,
uint8 __decimals
address _remoteToken,
string memory _name,
string memory _symbol,
uint8 _decimals
)
external
initializer
{
_remoteToken = __remoteToken;
_name = __name;
_symbol = __symbol;
_decimals = __decimals;
OptimismSuperchainERC20Metadata storage _storage = _getMetadataStorage();
_storage.remoteToken = _remoteToken;
_storage.name = _name;
_storage.symbol = _symbol;
_storage.decimals = _decimals;
}

/// @notice Allows the L2StandardBridge to mint tokens.
Expand Down Expand Up @@ -140,19 +153,19 @@ contract OptimismSuperchainERC20 is IOptimismSuperchainERC20, ERC20, ISemver, In
emit RelayedERC20(_from, _to, _amount, _source);
}

/// @notice Returns the address of the corresponding remote token.
/// @notice Returns the address of the corresponding version of this token on the remote chain.
function remoteToken() public view override returns (address) {
return _remoteToken;
return _getMetadataStorage().remoteToken;
}

/// @notice Returns the name of the token.
function name() public view virtual override returns (string memory) {
return _name;
return _getMetadataStorage().name;
}

/// @notice Returns the symbol of the token.
function symbol() public view virtual override returns (string memory) {
return _symbol;
return _getMetadataStorage().symbol;
}

/// @notice Returns the number of decimals used to get its user representation.
Expand All @@ -162,7 +175,7 @@ contract OptimismSuperchainERC20 is IOptimismSuperchainERC20, ERC20, ISemver, In
/// no way affects any of the arithmetic of the contract, including
/// {IERC20-balanceOf} and {IERC20-transfer}.
function decimals() public view override returns (uint8) {
return _decimals;
return _getMetadataStorage().decimals;
}

/// @notice ERC165 interface check function.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { stdStorage, StdStorage } from "forge-std/Test.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IL2ToL2CrossDomainMessenger } from "src/L2/IL2ToL2CrossDomainMessenger.sol";
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { Initializable } from "@solady/utils/Initializable.sol";
import { Initializable } from "@openzeppelin/contracts-v5/proxy/utils/Initializable.sol";

// Target contract
import {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,8 @@ contract Initializer_Test is Bridge_Initializer {
// Ensure that all L1, L2 `Initializable` contracts are accounted for, in addition to
// OptimismMintableERC20FactoryImpl, OptimismMintableERC20FactoryProxy, OptimismPortal2,
// DisputeGameFactoryImpl, DisputeGameFactoryProxy, DelayedWETHImpl, DelayedWETHProxy.
assertEq(_getNumInitializable() + 1, contracts.length);
// Omitting OptimismSuperchainERC20 due to using OZ v5 Initializable.
assertEq(_getNumInitializable(), contracts.length);
tynes marked this conversation as resolved.
Show resolved Hide resolved

// Attempt to re-initialize all contracts within the `contracts` array.
for (uint256 i; i < contracts.length; i++) {
Expand Down