Commit 232c54d4 authored by AgusDuha's avatar AgusDuha Committed by GitHub

feat: introduce OptimismSuperchainERC20Factory (#11617)

* test: add L2 standard bridge interop unit tests (#13)

* test: add L2 standard bridge interop unit tests

* fix: add tests natspec

* fix: unit tests fixes

* fix: super to legacy tests failing

* fix: mock and expect mint and burn

* fix: add generic factory interface (#14)

* test: add L2 standard bridge interop unit tests

* fix: add tests natspec

* fix: add generic factory interface

* feat: modify OptimismMintableERC20Factory for convert (#17)

* test: add L2 standard bridge interop unit tests

* fix: add tests natspec

* fix: add generic factory interface

* feat: modify OptimismMintableERC20Factory for convert

* fix: use only a public function for create3

* feat: rollback interop factory, modify legacy one

* fix: delete local token return variable

* fix: PR fixes

* feat: add superchain erc20 factory implementation (#23)

* feat: add superchain erc20 factory implementation

* fix: remove createX comments

* test: add superchain erc20 factory tests (#25)

* test: add superchain erc20 factory tests

* test: add erc20 asserts

* test: fix expect emit

* fix: remove comments

* feat: add constructor to superchain ERC20 beacon (#34)

* test: remove factory predeploy etch

----------
Co-authored-by: default avatar0xng <ng@defi.sucks>
Co-authored-by: default avatar0xParticle <particle@defi.sucks>
Co-authored-by: default avatargotzenx <78360669+gotzenx@users.noreply.github.com>

* fix: set an arbitrary address for superchain erc20 impl

* fix: deploy a proxy for the beacon on genesis (#45)


---------
Co-authored-by: default avatar0xng <ng@defi.sucks>

* fix: conflicts and imports

* fix: interfaces

* chore: add .testdata

* fix: adding back .testdata to gitignore

* fix: new conflicts from ci improvements

---------
Co-authored-by: default avatar0xng <ng@defi.sucks>
Co-authored-by: default avatar0xParticle <particle@defi.sucks>
Co-authored-by: default avatargotzenx <78360669+gotzenx@users.noreply.github.com>
Co-authored-by: default avatarDisco <131301107+0xDiscotech@users.noreply.github.com>
parent 97aa08a6
...@@ -6,12 +6,12 @@ GasBenchMark_L1Block_SetValuesEcotone:test_setL1BlockValuesEcotone_benchmark() ( ...@@ -6,12 +6,12 @@ GasBenchMark_L1Block_SetValuesEcotone:test_setL1BlockValuesEcotone_benchmark() (
GasBenchMark_L1Block_SetValuesEcotone_Warm:test_setL1BlockValuesEcotone_benchmark() (gas: 7597) GasBenchMark_L1Block_SetValuesEcotone_Warm:test_setL1BlockValuesEcotone_benchmark() (gas: 7597)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 369242) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 369242)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2967382) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2967382)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 564356) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 564362)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4076571) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4076577)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 467019) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 467019)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 3512701) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 3512701)
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 72618) GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 72618)
GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 92973) GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 92970)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 68312) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 68312)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 68943) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 68943)
GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 155610) GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 155607)
\ No newline at end of file \ No newline at end of file
...@@ -154,6 +154,10 @@ abstract contract Artifacts { ...@@ -154,6 +154,10 @@ abstract contract Artifacts {
return payable(Predeploys.SCHEMA_REGISTRY); return payable(Predeploys.SCHEMA_REGISTRY);
} else if (digest == keccak256(bytes("EAS"))) { } else if (digest == keccak256(bytes("EAS"))) {
return payable(Predeploys.EAS); return payable(Predeploys.EAS);
} else if (digest == keccak256(bytes("OptimismSuperchainERC20Factory"))) {
return payable(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY);
} else if (digest == keccak256(bytes("OptimismSuperchainERC20Beacon"))) {
return payable(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON);
} }
return payable(address(0)); return payable(address(0));
} }
......
...@@ -22,6 +22,7 @@ import { L2ERC721Bridge } from "src/L2/L2ERC721Bridge.sol"; ...@@ -22,6 +22,7 @@ import { L2ERC721Bridge } from "src/L2/L2ERC721Bridge.sol";
import { SequencerFeeVault } from "src/L2/SequencerFeeVault.sol"; import { SequencerFeeVault } from "src/L2/SequencerFeeVault.sol";
import { BaseFeeVault } from "src/L2/BaseFeeVault.sol"; import { BaseFeeVault } from "src/L2/BaseFeeVault.sol";
import { L1FeeVault } from "src/L2/L1FeeVault.sol"; import { L1FeeVault } from "src/L2/L1FeeVault.sol";
import { OptimismSuperchainERC20Beacon } from "src/L2/OptimismSuperchainERC20Beacon.sol";
import { OptimismMintableERC721Factory } from "src/universal/OptimismMintableERC721Factory.sol"; import { OptimismMintableERC721Factory } from "src/universal/OptimismMintableERC721Factory.sol";
import { CrossDomainMessenger } from "src/universal/CrossDomainMessenger.sol"; import { CrossDomainMessenger } from "src/universal/CrossDomainMessenger.sol";
import { StandardBridge } from "src/universal/StandardBridge.sol"; import { StandardBridge } from "src/universal/StandardBridge.sol";
...@@ -262,6 +263,8 @@ contract L2Genesis is Deployer { ...@@ -262,6 +263,8 @@ contract L2Genesis is Deployer {
setL2ToL2CrossDomainMessenger(); // 23 setL2ToL2CrossDomainMessenger(); // 23
setSuperchainWETH(); // 24 setSuperchainWETH(); // 24
setETHLiquidity(); // 25 setETHLiquidity(); // 25
setOptimismSuperchainERC20Factory(); // 26
setOptimismSuperchainERC20Beacon(); // 27
} }
} }
...@@ -513,6 +516,29 @@ contract L2Genesis is Deployer { ...@@ -513,6 +516,29 @@ contract L2Genesis is Deployer {
_setImplementationCode(Predeploys.SUPERCHAIN_WETH); _setImplementationCode(Predeploys.SUPERCHAIN_WETH);
} }
/// @notice This predeploy is following the safety invariant #1.
/// This contract has no initializer.
function setOptimismSuperchainERC20Factory() internal {
_setImplementationCode(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY);
}
/// @notice This predeploy is following the safety invariant #2.
function setOptimismSuperchainERC20Beacon() internal {
address superchainERC20Impl = Predeploys.OPTIMISM_SUPERCHAIN_ERC20;
console.log("Setting %s implementation at: %s", "OptimismSuperchainERC20", superchainERC20Impl);
vm.etch(superchainERC20Impl, vm.getDeployedCode("OptimismSuperchainERC20.sol:OptimismSuperchainERC20"));
OptimismSuperchainERC20Beacon beacon = new OptimismSuperchainERC20Beacon(superchainERC20Impl);
address beaconImpl = Predeploys.predeployToCodeNamespace(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON);
console.log("Setting %s implementation at: %s", "OptimismSuperchainERC20Beacon", beaconImpl);
vm.etch(beaconImpl, address(beacon).code);
/// Reset so its not included state dump
vm.etch(address(beacon), "");
vm.resetNonce(address(beacon));
}
/// @notice Sets all the preinstalls. /// @notice Sets all the preinstalls.
/// Warning: the creator-accounts of the preinstall contracts have 0 nonce values. /// Warning: the creator-accounts of the preinstall contracts have 0 nonce values.
/// When performing a regular user-initiated contract-creation of a preinstall, /// When performing a regular user-initiated contract-creation of a preinstall,
......
...@@ -119,6 +119,14 @@ ...@@ -119,6 +119,14 @@
"initCodeHash": "0xdd16dbc0ccbbac53ec2d4273f06334960a907a9f20b7c40300833227ee31d0de", "initCodeHash": "0xdd16dbc0ccbbac53ec2d4273f06334960a907a9f20b7c40300833227ee31d0de",
"sourceCodeHash": "0x910d43a17800df64dbc104f69ef1f900ca761cec4949c01d1c1126fde5268349" "sourceCodeHash": "0x910d43a17800df64dbc104f69ef1f900ca761cec4949c01d1c1126fde5268349"
}, },
"src/L2/OptimismSuperchainERC20Beacon.sol": {
"initCodeHash": "0x99ce8095b23c124850d866cbc144fee6cee05dbc6bb5d83acadfe00b90cf42c7",
"sourceCodeHash": "0x5e58b7c867fafa49fe39d68d83875425e9cf94f05f2835bdcdaa08fc8bc6b68e"
},
"src/L2/OptimismSuperchainERC20Factory.sol": {
"initCodeHash": "0x98011045722178751e4a1112892f7d9a11bc1f5e42ac18205b6d30a1f1476d24",
"sourceCodeHash": "0x9e72b2a77d82fcf3963734232ba9faff9d63962594a032041c2561f0a9f1b0b5"
},
"src/L2/SequencerFeeVault.sol": { "src/L2/SequencerFeeVault.sol": {
"initCodeHash": "0x2e6551705e493bacba8cffe22e564d5c401ae5bb02577a5424e0d32784e13e74", "initCodeHash": "0x2e6551705e493bacba8cffe22e564d5c401ae5bb02577a5424e0d32784e13e74",
"sourceCodeHash": "0xd56922cb04597dea469c65e5a49d4b3c50c171e603601e6f41da9517cae0b11a" "sourceCodeHash": "0xd56922cb04597dea469c65e5a49d4b3c50c171e603601e6f41da9517cae0b11a"
......
[
{
"inputs": [
{
"internalType": "address",
"name": "_implementation",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "implementation",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "version",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
}
]
\ No newline at end of file
[
{
"inputs": [
{
"internalType": "address",
"name": "_remoteToken",
"type": "address"
},
{
"internalType": "string",
"name": "_name",
"type": "string"
},
{
"internalType": "string",
"name": "_symbol",
"type": "string"
},
{
"internalType": "uint8",
"name": "_decimals",
"type": "uint8"
}
],
"name": "deploy",
"outputs": [
{
"internalType": "address",
"name": "_superchainERC20",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "superchainToken",
"type": "address"
}
],
"name": "deployments",
"outputs": [
{
"internalType": "address",
"name": "remoteToken",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "version",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "superchainToken",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "remoteToken",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "deployer",
"type": "address"
}
],
"name": "OptimismSuperchainERC20Created",
"type": "event"
}
]
\ No newline at end of file
[
{
"bytes": "32",
"label": "deployments",
"offset": 0,
"slot": "0",
"type": "mapping(address => address)"
}
]
\ No newline at end of file
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { IBeacon } from "@openzeppelin/contracts/proxy/beacon/IBeacon.sol";
import { ISemver } from "src/universal/interfaces/ISemver.sol";
/// @custom:proxied
/// @custom:predeployed 0x4200000000000000000000000000000000000027
/// @title OptimismSuperchainERC20Beacon
/// @notice OptimismSuperchainERC20Beacon is the beacon proxy for the OptimismSuperchainERC20 implementation.
contract OptimismSuperchainERC20Beacon is IBeacon, ISemver {
/// @notice Address of the OptimismSuperchainERC20 implementation.
address internal immutable IMPLEMENTATION;
/// @notice Semantic version.
/// @custom:semver 1.0.0-beta.1
string public constant version = "1.0.0-beta.1";
constructor(address _implementation) {
IMPLEMENTATION = _implementation;
}
/// @inheritdoc IBeacon
function implementation() external view override returns (address) {
return IMPLEMENTATION;
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
import { IOptimismERC20Factory } from "src/L2/interfaces/IOptimismERC20Factory.sol";
import { ISemver } from "src/universal/interfaces/ISemver.sol";
import { OptimismSuperchainERC20 } from "src/L2/OptimismSuperchainERC20.sol";
import { Predeploys } from "src/libraries/Predeploys.sol";
import { BeaconProxy } from "@openzeppelin/contracts-v5/proxy/beacon/BeaconProxy.sol";
import { CREATE3 } from "@rari-capital/solmate/src/utils/CREATE3.sol";
/// @custom:proxied
/// @custom:predeployed 0x4200000000000000000000000000000000000026
/// @title OptimismSuperchainERC20Factory
/// @notice OptimismSuperchainERC20Factory is a factory contract that deploys OptimismSuperchainERC20 Beacon Proxies
/// using CREATE3.
contract OptimismSuperchainERC20Factory is IOptimismERC20Factory, ISemver {
/// @notice Mapping of the deployed OptimismSuperchainERC20 to the remote token address.
/// This is used to keep track of the token deployments.
mapping(address superchainToken => address remoteToken) public deployments;
/// @notice Emitted when an OptimismSuperchainERC20 is deployed.
/// @param superchainToken Address of the SuperchainERC20 deployment.
/// @param remoteToken Address of the corresponding token on the remote chain.
/// @param deployer Address of the account that deployed the token.
event OptimismSuperchainERC20Created(
address indexed superchainToken, address indexed remoteToken, address deployer
);
/// @notice Semantic version.
/// @custom:semver 1.0.0-beta.1
string public constant version = "1.0.0-beta.1";
/// @notice Deploys a OptimismSuperchainERC20 Beacon Proxy using CREATE3.
/// @param _remoteToken Address of the remote token.
/// @param _name Name of the OptimismSuperchainERC20.
/// @param _symbol Symbol of the OptimismSuperchainERC20.
/// @param _decimals Decimals of the OptimismSuperchainERC20.
/// @return _superchainERC20 Address of the OptimismSuperchainERC20 deployment.
function deploy(
address _remoteToken,
string memory _name,
string memory _symbol,
uint8 _decimals
)
external
returns (address _superchainERC20)
{
bytes memory initCallData =
abi.encodeCall(OptimismSuperchainERC20.initialize, (_remoteToken, _name, _symbol, _decimals));
bytes memory creationCode = bytes.concat(
type(BeaconProxy).creationCode, abi.encode(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON, initCallData)
);
bytes32 salt = keccak256(abi.encode(_remoteToken, _name, _symbol, _decimals));
_superchainERC20 = CREATE3.deploy({ salt: salt, creationCode: creationCode, value: 0 });
deployments[_superchainERC20] = _remoteToken;
emit OptimismSuperchainERC20Created(_superchainERC20, _remoteToken, msg.sender);
}
}
...@@ -95,10 +95,16 @@ library Predeploys { ...@@ -95,10 +95,16 @@ library Predeploys {
/// @notice Address of the ETHLiquidity predeploy. /// @notice Address of the ETHLiquidity predeploy.
address internal constant ETH_LIQUIDITY = 0x4200000000000000000000000000000000000025; address internal constant ETH_LIQUIDITY = 0x4200000000000000000000000000000000000025;
/// TODO: Add correct predeploy address for OptimismSuperchainERC20Factory
/// @notice Address of the OptimismSuperchainERC20Factory predeploy. /// @notice Address of the OptimismSuperchainERC20Factory predeploy.
address internal constant OPTIMISM_SUPERCHAIN_ERC20_FACTORY = 0x4200000000000000000000000000000000000026; address internal constant OPTIMISM_SUPERCHAIN_ERC20_FACTORY = 0x4200000000000000000000000000000000000026;
/// @notice Address of the OptimismSuperchainERC20Beacon predeploy.
address internal constant OPTIMISM_SUPERCHAIN_ERC20_BEACON = 0x4200000000000000000000000000000000000027;
// TODO: Precalculate the address of the implementation contract
/// @notice Arbitrary address of the OptimismSuperchainERC20 implementation contract.
address internal constant OPTIMISM_SUPERCHAIN_ERC20 = 0xB9415c6cA93bdC545D4c5177512FCC22EFa38F28;
/// @notice Returns the name of the predeploy at the given address. /// @notice Returns the name of the predeploy at the given address.
function getName(address _addr) internal pure returns (string memory out_) { function getName(address _addr) internal pure returns (string memory out_) {
require(isPredeployNamespace(_addr), "Predeploys: address must be a predeploy"); require(isPredeployNamespace(_addr), "Predeploys: address must be a predeploy");
...@@ -128,6 +134,7 @@ library Predeploys { ...@@ -128,6 +134,7 @@ library Predeploys {
if (_addr == SUPERCHAIN_WETH) return "SuperchainWETH"; if (_addr == SUPERCHAIN_WETH) return "SuperchainWETH";
if (_addr == ETH_LIQUIDITY) return "ETHLiquidity"; if (_addr == ETH_LIQUIDITY) return "ETHLiquidity";
if (_addr == OPTIMISM_SUPERCHAIN_ERC20_FACTORY) return "OptimismSuperchainERC20Factory"; if (_addr == OPTIMISM_SUPERCHAIN_ERC20_FACTORY) return "OptimismSuperchainERC20Factory";
if (_addr == OPTIMISM_SUPERCHAIN_ERC20_BEACON) return "OptimismSuperchainERC20Beacon";
revert("Predeploys: unnamed predeploy"); revert("Predeploys: unnamed predeploy");
} }
...@@ -146,7 +153,8 @@ library Predeploys { ...@@ -146,7 +153,8 @@ library Predeploys {
|| _addr == L1_FEE_VAULT || _addr == SCHEMA_REGISTRY || _addr == EAS || _addr == GOVERNANCE_TOKEN || _addr == L1_FEE_VAULT || _addr == SCHEMA_REGISTRY || _addr == EAS || _addr == GOVERNANCE_TOKEN
|| (_useInterop && _addr == CROSS_L2_INBOX) || (_useInterop && _addr == L2_TO_L2_CROSS_DOMAIN_MESSENGER) || (_useInterop && _addr == CROSS_L2_INBOX) || (_useInterop && _addr == L2_TO_L2_CROSS_DOMAIN_MESSENGER)
|| (_useInterop && _addr == SUPERCHAIN_WETH) || (_useInterop && _addr == ETH_LIQUIDITY) || (_useInterop && _addr == SUPERCHAIN_WETH) || (_useInterop && _addr == ETH_LIQUIDITY)
|| (_useInterop && _addr == OPTIMISM_SUPERCHAIN_ERC20_FACTORY); || (_useInterop && _addr == OPTIMISM_SUPERCHAIN_ERC20_FACTORY)
|| (_useInterop && _addr == OPTIMISM_SUPERCHAIN_ERC20_BEACON);
} }
function isPredeployNamespace(address _addr) internal pure returns (bool) { function isPredeployNamespace(address _addr) internal pure returns (bool) {
......
...@@ -19,9 +19,6 @@ import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol ...@@ -19,9 +19,6 @@ import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol
import { IOptimismMintableERC20 } from "src/universal/interfaces/IOptimismMintableERC20.sol"; import { IOptimismMintableERC20 } from "src/universal/interfaces/IOptimismMintableERC20.sol";
import { ILegacyMintableERC20 } from "src/universal/OptimismMintableERC20.sol"; import { ILegacyMintableERC20 } from "src/universal/OptimismMintableERC20.sol";
// TODO: Replace Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY with optimismSuperchainERC20Factory
import { Predeploys } from "src/libraries/Predeploys.sol";
contract L2StandardBridgeInterop_Test is Bridge_Initializer { contract L2StandardBridgeInterop_Test is Bridge_Initializer {
/// @notice Emitted when a conversion is made. /// @notice Emitted when a conversion is made.
event Converted(address indexed from, address indexed to, address indexed caller, uint256 amount); event Converted(address indexed from, address indexed to, address indexed caller, uint256 amount);
...@@ -30,10 +27,6 @@ contract L2StandardBridgeInterop_Test is Bridge_Initializer { ...@@ -30,10 +27,6 @@ contract L2StandardBridgeInterop_Test is Bridge_Initializer {
function setUp() public virtual override { function setUp() public virtual override {
super.enableInterop(); super.enableInterop();
super.setUp(); super.setUp();
// TODO: Remove it once the `OptimismSuperchainERC20Factory` is added to predeploys.
// Ensure OPTIMISM_SUPERCHAIN_ERC20_FACTORY's code is not empty.
vm.etch(Predeploys.predeployToCodeNamespace(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY), address(this).code);
} }
/// @notice Helper function to setup a mock and expect a call to it. /// @notice Helper function to setup a mock and expect a call to it.
...@@ -146,7 +139,7 @@ contract L2StandardBridgeInterop_LegacyToSuper_Test is L2StandardBridgeInterop_T ...@@ -146,7 +139,7 @@ contract L2StandardBridgeInterop_LegacyToSuper_Test is L2StandardBridgeInterop_T
_mockDeployments(address(l2OptimismMintableERC20Factory), _from, _remoteToken); _mockDeployments(address(l2OptimismMintableERC20Factory), _from, _remoteToken);
// Mock the superchain factory to return address(0) // Mock the superchain factory to return address(0)
_mockDeployments(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY, _to, address(0)); _mockDeployments(address(l2OptimismSuperchainERC20Factory), _to, address(0));
// Expect the revert with `InvalidSuperchainERC20Address` selector // Expect the revert with `InvalidSuperchainERC20Address` selector
vm.expectRevert(InvalidSuperchainERC20Address.selector); vm.expectRevert(InvalidSuperchainERC20Address.selector);
...@@ -177,7 +170,7 @@ contract L2StandardBridgeInterop_LegacyToSuper_Test is L2StandardBridgeInterop_T ...@@ -177,7 +170,7 @@ contract L2StandardBridgeInterop_LegacyToSuper_Test is L2StandardBridgeInterop_T
_mockDeployments(address(l2OptimismMintableERC20Factory), _from, _fromRemoteToken); _mockDeployments(address(l2OptimismMintableERC20Factory), _from, _fromRemoteToken);
// Mock the superchain factory to return `_toRemoteToken` // Mock the superchain factory to return `_toRemoteToken`
_mockDeployments(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY, _to, _toRemoteToken); _mockDeployments(address(l2OptimismSuperchainERC20Factory), _to, _toRemoteToken);
// Expect the revert with `InvalidTokenPair` selector // Expect the revert with `InvalidTokenPair` selector
vm.expectRevert(InvalidTokenPair.selector); vm.expectRevert(InvalidTokenPair.selector);
...@@ -204,7 +197,7 @@ contract L2StandardBridgeInterop_LegacyToSuper_Test is L2StandardBridgeInterop_T ...@@ -204,7 +197,7 @@ contract L2StandardBridgeInterop_LegacyToSuper_Test is L2StandardBridgeInterop_T
// Mock the legacy and superchain factory to return `_remoteToken` // Mock the legacy and superchain factory to return `_remoteToken`
_mockDeployments(address(l2OptimismMintableERC20Factory), _from, _remoteToken); _mockDeployments(address(l2OptimismMintableERC20Factory), _from, _remoteToken);
_mockDeployments(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY, _to, _remoteToken); _mockDeployments(address(l2OptimismSuperchainERC20Factory), _to, _remoteToken);
// Expect the `Converted` event to be emitted // Expect the `Converted` event to be emitted
vm.expectEmit(address(l2StandardBridge)); vm.expectEmit(address(l2StandardBridge));
...@@ -300,7 +293,7 @@ contract L2StandardBridgeInterop_SuperToLegacy_Test is L2StandardBridgeInterop_T ...@@ -300,7 +293,7 @@ contract L2StandardBridgeInterop_SuperToLegacy_Test is L2StandardBridgeInterop_T
_mockDeployments(address(l2OptimismMintableERC20Factory), _to, _remoteToken); _mockDeployments(address(l2OptimismMintableERC20Factory), _to, _remoteToken);
// Mock the superchain factory to return address(0) // Mock the superchain factory to return address(0)
_mockDeployments(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY, _from, address(0)); _mockDeployments(address(l2OptimismSuperchainERC20Factory), _from, address(0));
// Expect the revert with `InvalidSuperchainERC20Address` selector // Expect the revert with `InvalidSuperchainERC20Address` selector
vm.expectRevert(InvalidSuperchainERC20Address.selector); vm.expectRevert(InvalidSuperchainERC20Address.selector);
...@@ -331,7 +324,7 @@ contract L2StandardBridgeInterop_SuperToLegacy_Test is L2StandardBridgeInterop_T ...@@ -331,7 +324,7 @@ contract L2StandardBridgeInterop_SuperToLegacy_Test is L2StandardBridgeInterop_T
_mockDeployments(address(l2OptimismMintableERC20Factory), _to, _fromRemoteToken); _mockDeployments(address(l2OptimismMintableERC20Factory), _to, _fromRemoteToken);
// Mock the superchain factory to return `_toRemoteToken` // Mock the superchain factory to return `_toRemoteToken`
_mockDeployments(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY, _from, _toRemoteToken); _mockDeployments(address(l2OptimismSuperchainERC20Factory), _from, _toRemoteToken);
// Expect the revert with `InvalidTokenPair` selector // Expect the revert with `InvalidTokenPair` selector
vm.expectRevert(InvalidTokenPair.selector); vm.expectRevert(InvalidTokenPair.selector);
...@@ -358,7 +351,7 @@ contract L2StandardBridgeInterop_SuperToLegacy_Test is L2StandardBridgeInterop_T ...@@ -358,7 +351,7 @@ contract L2StandardBridgeInterop_SuperToLegacy_Test is L2StandardBridgeInterop_T
// Mock the legacy and superchain factory to return `_remoteToken` // Mock the legacy and superchain factory to return `_remoteToken`
_mockDeployments(address(l2OptimismMintableERC20Factory), _to, _remoteToken); _mockDeployments(address(l2OptimismMintableERC20Factory), _to, _remoteToken);
_mockDeployments(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY, _from, _remoteToken); _mockDeployments(address(l2OptimismSuperchainERC20Factory), _from, _remoteToken);
// Expect the `Converted` event to be emitted // Expect the `Converted` event to be emitted
vm.expectEmit(address(l2StandardBridge)); vm.expectEmit(address(l2StandardBridge));
......
...@@ -3,6 +3,7 @@ pragma solidity 0.8.25; ...@@ -3,6 +3,7 @@ pragma solidity 0.8.25;
// Testing utilities // Testing utilities
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
// Libraries // Libraries
import { Predeploys } from "src/libraries/Predeploys.sol"; import { Predeploys } from "src/libraries/Predeploys.sol";
...@@ -11,6 +12,8 @@ import { IL2ToL2CrossDomainMessenger } from "src/L2/interfaces/IL2ToL2CrossDomai ...@@ -11,6 +12,8 @@ import { IL2ToL2CrossDomainMessenger } from "src/L2/interfaces/IL2ToL2CrossDomai
import { ERC1967Proxy } from "@openzeppelin/contracts-v5/proxy/ERC1967/ERC1967Proxy.sol"; import { ERC1967Proxy } from "@openzeppelin/contracts-v5/proxy/ERC1967/ERC1967Proxy.sol";
import { Initializable } from "@openzeppelin/contracts-v5/proxy/utils/Initializable.sol"; import { Initializable } from "@openzeppelin/contracts-v5/proxy/utils/Initializable.sol";
import { IERC165 } from "@openzeppelin/contracts-v5/utils/introspection/IERC165.sol"; import { IERC165 } from "@openzeppelin/contracts-v5/utils/introspection/IERC165.sol";
import { IBeacon } from "@openzeppelin/contracts-v5/proxy/beacon/IBeacon.sol";
import { BeaconProxy } from "@openzeppelin/contracts-v5/proxy/beacon/BeaconProxy.sol";
// Target contract // Target contract
import { import {
...@@ -40,9 +43,32 @@ contract OptimismSuperchainERC20Test is Test { ...@@ -40,9 +43,32 @@ contract OptimismSuperchainERC20Test is Test {
/// @notice Sets up the test suite. /// @notice Sets up the test suite.
function setUp() public { function setUp() public {
superchainERC20Impl = new OptimismSuperchainERC20(); superchainERC20Impl = new OptimismSuperchainERC20();
// Deploy the OptimismSuperchainERC20Beacon contract
_deployBeacon();
superchainERC20 = _deploySuperchainERC20Proxy(REMOTE_TOKEN, NAME, SYMBOL, DECIMALS); superchainERC20 = _deploySuperchainERC20Proxy(REMOTE_TOKEN, NAME, SYMBOL, DECIMALS);
} }
/// @notice Deploy the OptimismSuperchainERC20Beacon predeploy contract
function _deployBeacon() internal {
// Deploy the OptimismSuperchainERC20Beacon implementation
address _addr = Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON;
address _impl = Predeploys.predeployToCodeNamespace(_addr);
vm.etch(_impl, vm.getDeployedCode("OptimismSuperchainERC20Beacon.sol:OptimismSuperchainERC20Beacon"));
// Deploy the ERC1967Proxy contract at the Predeploy
bytes memory code = vm.getDeployedCode("universal/Proxy.sol:Proxy");
vm.etch(_addr, code);
EIP1967Helper.setAdmin(_addr, Predeploys.PROXY_ADMIN);
EIP1967Helper.setImplementation(_addr, _impl);
// Mock implementation address
vm.mockCall(
_impl, abi.encodeWithSelector(IBeacon.implementation.selector), abi.encode(address(superchainERC20Impl))
);
}
/// @notice Helper function to deploy a proxy of the OptimismSuperchainERC20 contract. /// @notice Helper function to deploy a proxy of the OptimismSuperchainERC20 contract.
function _deploySuperchainERC20Proxy( function _deploySuperchainERC20Proxy(
address _remoteToken, address _remoteToken,
...@@ -55,9 +81,8 @@ contract OptimismSuperchainERC20Test is Test { ...@@ -55,9 +81,8 @@ contract OptimismSuperchainERC20Test is Test {
{ {
return OptimismSuperchainERC20( return OptimismSuperchainERC20(
address( address(
// TODO: Use the SuperchainERC20 Beacon Proxy new BeaconProxy(
new ERC1967Proxy( Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON,
address(superchainERC20Impl),
abi.encodeCall(OptimismSuperchainERC20.initialize, (_remoteToken, _name, _symbol, _decimals)) abi.encodeCall(OptimismSuperchainERC20.initialize, (_remoteToken, _name, _symbol, _decimals))
) )
) )
......
// SPDX-License-Identifier: MIT
pragma solidity 0.8.25;
// Testing utilities
import { Test } from "forge-std/Test.sol";
import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
// Libraries
import { Predeploys } from "src/libraries/Predeploys.sol";
import { CREATE3, Bytes32AddressLib } from "@rari-capital/solmate/src/utils/CREATE3.sol";
import { IBeacon } from "@openzeppelin/contracts-v5/proxy/beacon/IBeacon.sol";
// Target contract
import { OptimismSuperchainERC20Factory, OptimismSuperchainERC20 } from "src/L2/OptimismSuperchainERC20Factory.sol";
/// @title OptimismSuperchainERC20FactoryTest
/// @notice Contract for testing the OptimismSuperchainERC20Factory contract.
contract OptimismSuperchainERC20FactoryTest is Test {
using Bytes32AddressLib for bytes32;
OptimismSuperchainERC20 public superchainERC20Impl;
OptimismSuperchainERC20Factory public superchainERC20Factory;
/// @notice Sets up the test suite.
function setUp() public {
superchainERC20Impl = new OptimismSuperchainERC20();
// Deploy the OptimismSuperchainERC20Beacon contract
_deployBeacon();
superchainERC20Factory = new OptimismSuperchainERC20Factory();
}
/// @notice Deploy the OptimismSuperchainERC20Beacon predeploy contract
function _deployBeacon() internal {
// Deploy the OptimismSuperchainERC20Beacon implementation
address _addr = Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON;
address _impl = Predeploys.predeployToCodeNamespace(_addr);
vm.etch(_impl, vm.getDeployedCode("OptimismSuperchainERC20Beacon.sol:OptimismSuperchainERC20Beacon"));
// Deploy the ERC1967Proxy contract at the Predeploy
bytes memory code = vm.getDeployedCode("universal/Proxy.sol:Proxy");
vm.etch(_addr, code);
EIP1967Helper.setAdmin(_addr, Predeploys.PROXY_ADMIN);
EIP1967Helper.setImplementation(_addr, _impl);
// Mock implementation address
vm.mockCall(
_impl, abi.encodeWithSelector(IBeacon.implementation.selector), abi.encode(address(superchainERC20Impl))
);
}
/// @notice Test that calling `deploy` with valid parameters succeeds.
function test_deploy_succeeds(
address _caller,
address _remoteToken,
string memory _name,
string memory _symbol,
uint8 _decimals
)
public
{
// Arrange
bytes32 salt = keccak256(abi.encode(_remoteToken, _name, _symbol, _decimals));
address deployment = _calculateTokenAddress(salt, address(superchainERC20Factory));
vm.expectEmit(address(superchainERC20Factory));
emit OptimismSuperchainERC20Factory.OptimismSuperchainERC20Created(deployment, _remoteToken, _caller);
// Act
vm.prank(_caller);
address addr = superchainERC20Factory.deploy(_remoteToken, _name, _symbol, _decimals);
// Assert
assertTrue(addr == deployment);
assertTrue(OptimismSuperchainERC20(deployment).decimals() == _decimals);
assertTrue(OptimismSuperchainERC20(deployment).remoteToken() == _remoteToken);
assertEq(OptimismSuperchainERC20(deployment).name(), _name);
assertEq(OptimismSuperchainERC20(deployment).symbol(), _symbol);
assertEq(superchainERC20Factory.deployments(deployment), _remoteToken);
}
/// @notice Test that calling `deploy` with the same parameters twice reverts.
function test_deploy_sameTwice_reverts(
address _caller,
address _remoteToken,
string memory _name,
string memory _symbol,
uint8 _decimals
)
external
{
// Arrange
vm.prank(_caller);
superchainERC20Factory.deploy(_remoteToken, _name, _symbol, _decimals);
vm.expectRevert(bytes("DEPLOYMENT_FAILED"));
// Act
vm.prank(_caller);
superchainERC20Factory.deploy(_remoteToken, _name, _symbol, _decimals);
}
/// @notice Precalculates the address of the token contract using CREATE3.
function _calculateTokenAddress(bytes32 _salt, address _deployer) internal pure returns (address) {
address proxy =
keccak256(abi.encodePacked(bytes1(0xFF), _deployer, _salt, CREATE3.PROXY_BYTECODE_HASH)).fromLast20Bytes();
return keccak256(abi.encodePacked(hex"d694", proxy, hex"01")).fromLast20Bytes();
}
}
...@@ -150,8 +150,8 @@ contract L2GenesisTest is Test { ...@@ -150,8 +150,8 @@ contract L2GenesisTest is Test {
// 2 predeploys do not have proxies // 2 predeploys do not have proxies
assertEq(getCodeCount(_path, "Proxy.sol:Proxy"), Predeploys.PREDEPLOY_COUNT - 2); assertEq(getCodeCount(_path, "Proxy.sol:Proxy"), Predeploys.PREDEPLOY_COUNT - 2);
// 22 proxies have the implementation set if useInterop is true and 17 if useInterop is false // 23 proxies have the implementation set if useInterop is true and 17 if useInterop is false
assertEq(getPredeployCountWithSlotSet(_path, Constants.PROXY_IMPLEMENTATION_ADDRESS), _useInterop ? 22 : 17); assertEq(getPredeployCountWithSlotSet(_path, Constants.PROXY_IMPLEMENTATION_ADDRESS), _useInterop ? 23 : 17);
// All proxies except 2 have the proxy 1967 admin slot set to the proxy admin // All proxies except 2 have the proxy 1967 admin slot set to the proxy admin
assertEq( assertEq(
......
...@@ -7,26 +7,21 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; ...@@ -7,26 +7,21 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
import { Predeploys } from "src/libraries/Predeploys.sol"; import { Predeploys } from "src/libraries/Predeploys.sol";
/// @title PredeploysTest /// @title PredeploysTest
contract PredeploysTest is CommonTest { contract PredeploysBaseTest is CommonTest {
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
/// Internal helpers /// Internal helpers
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
/// @dev Returns true if the address is a predeploy that is active (i.e. embedded in L2 genesis). /// @dev Returns true if the address is an interop predeploy.
function _isPredeploy(address _addr) internal pure returns (bool) { function _isInterop(address _addr) internal pure returns (bool) {
return _addr == Predeploys.L2_TO_L1_MESSAGE_PASSER || _addr == Predeploys.L2_CROSS_DOMAIN_MESSENGER return _addr == Predeploys.CROSS_L2_INBOX || _addr == Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER
|| _addr == Predeploys.L2_STANDARD_BRIDGE || _addr == Predeploys.L2_ERC721_BRIDGE || _addr == Predeploys.SUPERCHAIN_WETH || _addr == Predeploys.ETH_LIQUIDITY
|| _addr == Predeploys.SEQUENCER_FEE_WALLET || _addr == Predeploys.OPTIMISM_MINTABLE_ERC20_FACTORY || _addr == Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY || _addr == Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON;
|| _addr == Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY || _addr == Predeploys.L1_BLOCK_ATTRIBUTES
|| _addr == Predeploys.GAS_PRICE_ORACLE || _addr == Predeploys.DEPLOYER_WHITELIST || _addr == Predeploys.WETH
|| _addr == Predeploys.L1_BLOCK_NUMBER || _addr == Predeploys.LEGACY_MESSAGE_PASSER
|| _addr == Predeploys.PROXY_ADMIN || _addr == Predeploys.BASE_FEE_VAULT || _addr == Predeploys.L1_FEE_VAULT
|| _addr == Predeploys.GOVERNANCE_TOKEN || _addr == Predeploys.SCHEMA_REGISTRY || _addr == Predeploys.EAS;
} }
/// @dev Returns true if the address is not proxied. /// @dev Returns true if the address is a predeploy that has a different code in the interop mode.
function _notProxied(address _addr) internal pure returns (bool) { function _interopCodeDiffer(address _addr) internal pure returns (bool) {
return _addr == Predeploys.GOVERNANCE_TOKEN || _addr == Predeploys.WETH; return _addr == Predeploys.L1_BLOCK_ATTRIBUTES || _addr == Predeploys.L2_STANDARD_BRIDGE;
} }
/// @dev Returns true if the account is not meant to be in the L2 genesis anymore. /// @dev Returns true if the account is not meant to be in the L2 genesis anymore.
...@@ -34,22 +29,17 @@ contract PredeploysTest is CommonTest { ...@@ -34,22 +29,17 @@ contract PredeploysTest is CommonTest {
return _addr == Predeploys.L1_MESSAGE_SENDER; return _addr == Predeploys.L1_MESSAGE_SENDER;
} }
/// @dev Returns true if the predeploy is initializable.
function _isInitializable(address _addr) internal pure returns (bool) { function _isInitializable(address _addr) internal pure returns (bool) {
return !( return _addr == Predeploys.L2_CROSS_DOMAIN_MESSENGER || _addr == Predeploys.L2_STANDARD_BRIDGE
_addr == Predeploys.LEGACY_MESSAGE_PASSER || _addr == Predeploys.DEPLOYER_WHITELIST || _addr == Predeploys.L2_ERC721_BRIDGE || _addr == Predeploys.OPTIMISM_MINTABLE_ERC20_FACTORY;
|| _addr == Predeploys.GAS_PRICE_ORACLE || _addr == Predeploys.SEQUENCER_FEE_WALLET
|| _addr == Predeploys.BASE_FEE_VAULT || _addr == Predeploys.L1_FEE_VAULT
|| _addr == Predeploys.L1_BLOCK_NUMBER || _addr == Predeploys.L1_BLOCK_ATTRIBUTES
|| _addr == Predeploys.L2_TO_L1_MESSAGE_PASSER || _addr == Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY
|| _addr == Predeploys.PROXY_ADMIN || _addr == Predeploys.SCHEMA_REGISTRY || _addr == Predeploys.EAS
|| _addr == Predeploys.GOVERNANCE_TOKEN
);
} }
/// @dev Returns true if the predeploy uses immutables.
function _usesImmutables(address _addr) internal pure returns (bool) { function _usesImmutables(address _addr) internal pure returns (bool) {
return _addr == Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY || _addr == Predeploys.SEQUENCER_FEE_WALLET return _addr == Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY || _addr == Predeploys.SEQUENCER_FEE_WALLET
|| _addr == Predeploys.BASE_FEE_VAULT || _addr == Predeploys.L1_FEE_VAULT || _addr == Predeploys.EAS || _addr == Predeploys.BASE_FEE_VAULT || _addr == Predeploys.L1_FEE_VAULT || _addr == Predeploys.EAS
|| _addr == Predeploys.GOVERNANCE_TOKEN; || _addr == Predeploys.GOVERNANCE_TOKEN || _addr == Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON;
} }
function test_predeployToCodeNamespace() external pure { function test_predeployToCodeNamespace() external pure {
...@@ -67,9 +57,7 @@ contract PredeploysTest is CommonTest { ...@@ -67,9 +57,7 @@ contract PredeploysTest is CommonTest {
); );
} }
/// @dev Tests that the predeploy addresses are set correctly. They have code function _test_predeploys(bool _useInterop) internal {
/// and the proxied accounts have the correct admin.
function test_predeploys_succeeds() external {
uint256 count = 2048; uint256 count = 2048;
uint160 prefix = uint160(0x420) << 148; uint160 prefix = uint160(0x420) << 148;
...@@ -77,23 +65,25 @@ contract PredeploysTest is CommonTest { ...@@ -77,23 +65,25 @@ contract PredeploysTest is CommonTest {
for (uint256 i = 0; i < count; i++) { for (uint256 i = 0; i < count; i++) {
address addr = address(prefix | uint160(i)); address addr = address(prefix | uint160(i));
bytes memory code = addr.code;
assertTrue(code.length > 0);
address implAddr = Predeploys.predeployToCodeNamespace(addr); address implAddr = Predeploys.predeployToCodeNamespace(addr);
if (_isOmitted(addr)) { if (_isOmitted(addr)) {
assertEq(implAddr.code.length, 0, "must have no code"); assertEq(implAddr.code.length, 0, "must have no code");
continue; continue;
} }
bool isPredeploy = _isPredeploy(addr);
bool isPredeploy = Predeploys.isSupportedPredeploy(addr, _useInterop);
bytes memory code = addr.code;
if (isPredeploy) assertTrue(code.length > 0);
bool proxied = Predeploys.notProxied(addr) == false;
if (!isPredeploy) { if (!isPredeploy) {
// All of the predeploys, even if inactive, have their admin set to the proxy admin // All of the predeploys, even if inactive, have their admin set to the proxy admin
assertEq(EIP1967Helper.getAdmin(addr), Predeploys.PROXY_ADMIN, "Admin mismatch"); if (proxied) assertEq(EIP1967Helper.getAdmin(addr), Predeploys.PROXY_ADMIN, "Admin mismatch");
continue; continue;
} }
bool proxied = _notProxied(addr) == false;
string memory cname = Predeploys.getName(addr); string memory cname = Predeploys.getName(addr);
assertNotEq(cname, "", "must have a name"); assertNotEq(cname, "", "must have a name");
...@@ -118,7 +108,7 @@ contract PredeploysTest is CommonTest { ...@@ -118,7 +108,7 @@ contract PredeploysTest is CommonTest {
string.concat("Implementation mismatch for ", vm.toString(addr)) string.concat("Implementation mismatch for ", vm.toString(addr))
); );
assertNotEq(implAddr.code.length, 0, "predeploy implementation account must have code"); assertNotEq(implAddr.code.length, 0, "predeploy implementation account must have code");
if (!_usesImmutables(addr)) { if (!_usesImmutables(addr) && !_interopCodeDiffer(addr)) {
// can't check bytecode if it's modified with immutables in genesis. // can't check bytecode if it's modified with immutables in genesis.
assertEq(implAddr.code, supposedCode, "proxy implementation contract should match contract source"); assertEq(implAddr.code, supposedCode, "proxy implementation contract should match contract source");
} }
...@@ -129,3 +119,25 @@ contract PredeploysTest is CommonTest { ...@@ -129,3 +119,25 @@ contract PredeploysTest is CommonTest {
} }
} }
} }
contract PredeploysTest is PredeploysBaseTest {
/// @dev Tests that the predeploy addresses are set correctly. They have code
/// and the proxied accounts have the correct admin.
function test_predeploys_succeeds() external {
_test_predeploys(false);
}
}
contract PredeploysInteropTest is PredeploysBaseTest {
/// @notice Test setup. Enabling interop to get all predeploys.
function setUp() public virtual override {
super.enableInterop();
super.setUp();
}
/// @dev Tests that the predeploy addresses are set correctly. They have code
/// and the proxied accounts have the correct admin. Using interop.
function test_predeploys_succeeds() external {
_test_predeploys(true);
}
}
...@@ -51,6 +51,7 @@ import { IProtocolVersions } from "src/L1/interfaces/IProtocolVersions.sol"; ...@@ -51,6 +51,7 @@ import { IProtocolVersions } from "src/L1/interfaces/IProtocolVersions.sol";
import { IL1ERC721Bridge } from "src/L1/interfaces/IL1ERC721Bridge.sol"; import { IL1ERC721Bridge } from "src/L1/interfaces/IL1ERC721Bridge.sol";
import { IOptimismMintableERC20Factory } from "src/universal/interfaces/IOptimismMintableERC20Factory.sol"; import { IOptimismMintableERC20Factory } from "src/universal/interfaces/IOptimismMintableERC20Factory.sol";
import { IAddressManager } from "src/legacy/interfaces/IAddressManager.sol"; import { IAddressManager } from "src/legacy/interfaces/IAddressManager.sol";
import { IOptimismERC20Factory } from "src/L2/interfaces/IOptimismERC20Factory.sol";
/// @title Setup /// @title Setup
/// @dev This contact is responsible for setting up the contracts in state. It currently /// @dev This contact is responsible for setting up the contracts in state. It currently
...@@ -109,6 +110,10 @@ contract Setup { ...@@ -109,6 +110,10 @@ contract Setup {
SuperchainWETH superchainWeth = SuperchainWETH(payable(Predeploys.SUPERCHAIN_WETH)); SuperchainWETH superchainWeth = SuperchainWETH(payable(Predeploys.SUPERCHAIN_WETH));
ETHLiquidity ethLiquidity = ETHLiquidity(Predeploys.ETH_LIQUIDITY); ETHLiquidity ethLiquidity = ETHLiquidity(Predeploys.ETH_LIQUIDITY);
// TODO: Replace with OptimismSuperchainERC20Factory when updating pragmas
IOptimismERC20Factory l2OptimismSuperchainERC20Factory =
IOptimismERC20Factory(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY);
/// @dev Deploys the Deploy contract without including its bytecode in the bytecode /// @dev Deploys the Deploy contract without including its bytecode in the bytecode
/// of this contract by fetching the bytecode dynamically using `vm.getCode()`. /// of this contract by fetching the bytecode dynamically using `vm.getCode()`.
/// If the Deploy bytecode is included in this contract, then it will double /// If the Deploy bytecode is included in this contract, then it will double
...@@ -227,6 +232,8 @@ contract Setup { ...@@ -227,6 +232,8 @@ contract Setup {
labelPredeploy(Predeploys.WETH); labelPredeploy(Predeploys.WETH);
labelPredeploy(Predeploys.SUPERCHAIN_WETH); labelPredeploy(Predeploys.SUPERCHAIN_WETH);
labelPredeploy(Predeploys.ETH_LIQUIDITY); labelPredeploy(Predeploys.ETH_LIQUIDITY);
labelPredeploy(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY);
labelPredeploy(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON);
// L2 Preinstalls // L2 Preinstalls
labelPreinstall(Preinstalls.MultiCall3); labelPreinstall(Preinstalls.MultiCall3);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment