Skip to content

Commit 232c54d

Browse files
agusduha0xng0xPartigotzenx0xDiscotech
authored
feat: introduce OptimismSuperchainERC20Factory (ethereum-optimism#11617)
* test: add L2 standard bridge interop unit tests (ethereum-optimism#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 (ethereum-optimism#14) * test: add L2 standard bridge interop unit tests * fix: add tests natspec * fix: add generic factory interface * feat: modify OptimismMintableERC20Factory for convert (ethereum-optimism#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 (ethereum-optimism#23) * feat: add superchain erc20 factory implementation * fix: remove createX comments * test: add superchain erc20 factory tests (ethereum-optimism#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 (ethereum-optimism#34) * test: remove factory predeploy etch ---------- Co-authored-by: 0xng <[email protected]> Co-authored-by: 0xParticle <[email protected]> Co-authored-by: gotzenx <[email protected]> * fix: set an arbitrary address for superchain erc20 impl * fix: deploy a proxy for the beacon on genesis (ethereum-optimism#45) --------- Co-authored-by: 0xng <[email protected]> * fix: conflicts and imports * fix: interfaces * chore: add .testdata * fix: adding back .testdata to gitignore * fix: new conflicts from ci improvements --------- Co-authored-by: 0xng <[email protected]> Co-authored-by: 0xParticle <[email protected]> Co-authored-by: gotzenx <[email protected]> Co-authored-by: Disco <[email protected]>
1 parent 97aa08a commit 232c54d

17 files changed

+483
-58
lines changed

packages/contracts-bedrock/.gas-snapshot

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ GasBenchMark_L1Block_SetValuesEcotone:test_setL1BlockValuesEcotone_benchmark() (
66
GasBenchMark_L1Block_SetValuesEcotone_Warm:test_setL1BlockValuesEcotone_benchmark() (gas: 7597)
77
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 369242)
88
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2967382)
9-
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 564356)
10-
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4076571)
9+
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 564362)
10+
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4076577)
1111
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 467019)
1212
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 3512701)
1313
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 72618)
14-
GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 92973)
14+
GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 92970)
1515
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 68312)
1616
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 68943)
17-
GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 155610)
17+
GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 155607)

packages/contracts-bedrock/scripts/Artifacts.s.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ abstract contract Artifacts {
154154
return payable(Predeploys.SCHEMA_REGISTRY);
155155
} else if (digest == keccak256(bytes("EAS"))) {
156156
return payable(Predeploys.EAS);
157+
} else if (digest == keccak256(bytes("OptimismSuperchainERC20Factory"))) {
158+
return payable(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY);
159+
} else if (digest == keccak256(bytes("OptimismSuperchainERC20Beacon"))) {
160+
return payable(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON);
157161
}
158162
return payable(address(0));
159163
}

packages/contracts-bedrock/scripts/L2Genesis.s.sol

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { L2ERC721Bridge } from "src/L2/L2ERC721Bridge.sol";
2222
import { SequencerFeeVault } from "src/L2/SequencerFeeVault.sol";
2323
import { BaseFeeVault } from "src/L2/BaseFeeVault.sol";
2424
import { L1FeeVault } from "src/L2/L1FeeVault.sol";
25+
import { OptimismSuperchainERC20Beacon } from "src/L2/OptimismSuperchainERC20Beacon.sol";
2526
import { OptimismMintableERC721Factory } from "src/universal/OptimismMintableERC721Factory.sol";
2627
import { CrossDomainMessenger } from "src/universal/CrossDomainMessenger.sol";
2728
import { StandardBridge } from "src/universal/StandardBridge.sol";
@@ -262,6 +263,8 @@ contract L2Genesis is Deployer {
262263
setL2ToL2CrossDomainMessenger(); // 23
263264
setSuperchainWETH(); // 24
264265
setETHLiquidity(); // 25
266+
setOptimismSuperchainERC20Factory(); // 26
267+
setOptimismSuperchainERC20Beacon(); // 27
265268
}
266269
}
267270

@@ -513,6 +516,29 @@ contract L2Genesis is Deployer {
513516
_setImplementationCode(Predeploys.SUPERCHAIN_WETH);
514517
}
515518

519+
/// @notice This predeploy is following the safety invariant #1.
520+
/// This contract has no initializer.
521+
function setOptimismSuperchainERC20Factory() internal {
522+
_setImplementationCode(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY);
523+
}
524+
525+
/// @notice This predeploy is following the safety invariant #2.
526+
function setOptimismSuperchainERC20Beacon() internal {
527+
address superchainERC20Impl = Predeploys.OPTIMISM_SUPERCHAIN_ERC20;
528+
console.log("Setting %s implementation at: %s", "OptimismSuperchainERC20", superchainERC20Impl);
529+
vm.etch(superchainERC20Impl, vm.getDeployedCode("OptimismSuperchainERC20.sol:OptimismSuperchainERC20"));
530+
531+
OptimismSuperchainERC20Beacon beacon = new OptimismSuperchainERC20Beacon(superchainERC20Impl);
532+
address beaconImpl = Predeploys.predeployToCodeNamespace(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON);
533+
534+
console.log("Setting %s implementation at: %s", "OptimismSuperchainERC20Beacon", beaconImpl);
535+
vm.etch(beaconImpl, address(beacon).code);
536+
537+
/// Reset so its not included state dump
538+
vm.etch(address(beacon), "");
539+
vm.resetNonce(address(beacon));
540+
}
541+
516542
/// @notice Sets all the preinstalls.
517543
/// Warning: the creator-accounts of the preinstall contracts have 0 nonce values.
518544
/// When performing a regular user-initiated contract-creation of a preinstall,

packages/contracts-bedrock/semver-lock.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@
119119
"initCodeHash": "0xdd16dbc0ccbbac53ec2d4273f06334960a907a9f20b7c40300833227ee31d0de",
120120
"sourceCodeHash": "0x910d43a17800df64dbc104f69ef1f900ca761cec4949c01d1c1126fde5268349"
121121
},
122+
"src/L2/OptimismSuperchainERC20Beacon.sol": {
123+
"initCodeHash": "0x99ce8095b23c124850d866cbc144fee6cee05dbc6bb5d83acadfe00b90cf42c7",
124+
"sourceCodeHash": "0x5e58b7c867fafa49fe39d68d83875425e9cf94f05f2835bdcdaa08fc8bc6b68e"
125+
},
126+
"src/L2/OptimismSuperchainERC20Factory.sol": {
127+
"initCodeHash": "0x98011045722178751e4a1112892f7d9a11bc1f5e42ac18205b6d30a1f1476d24",
128+
"sourceCodeHash": "0x9e72b2a77d82fcf3963734232ba9faff9d63962594a032041c2561f0a9f1b0b5"
129+
},
122130
"src/L2/SequencerFeeVault.sol": {
123131
"initCodeHash": "0x2e6551705e493bacba8cffe22e564d5c401ae5bb02577a5424e0d32784e13e74",
124132
"sourceCodeHash": "0xd56922cb04597dea469c65e5a49d4b3c50c171e603601e6f41da9517cae0b11a"
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[
2+
{
3+
"inputs": [
4+
{
5+
"internalType": "address",
6+
"name": "_implementation",
7+
"type": "address"
8+
}
9+
],
10+
"stateMutability": "nonpayable",
11+
"type": "constructor"
12+
},
13+
{
14+
"inputs": [],
15+
"name": "implementation",
16+
"outputs": [
17+
{
18+
"internalType": "address",
19+
"name": "",
20+
"type": "address"
21+
}
22+
],
23+
"stateMutability": "view",
24+
"type": "function"
25+
},
26+
{
27+
"inputs": [],
28+
"name": "version",
29+
"outputs": [
30+
{
31+
"internalType": "string",
32+
"name": "",
33+
"type": "string"
34+
}
35+
],
36+
"stateMutability": "view",
37+
"type": "function"
38+
}
39+
]
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
[
2+
{
3+
"inputs": [
4+
{
5+
"internalType": "address",
6+
"name": "_remoteToken",
7+
"type": "address"
8+
},
9+
{
10+
"internalType": "string",
11+
"name": "_name",
12+
"type": "string"
13+
},
14+
{
15+
"internalType": "string",
16+
"name": "_symbol",
17+
"type": "string"
18+
},
19+
{
20+
"internalType": "uint8",
21+
"name": "_decimals",
22+
"type": "uint8"
23+
}
24+
],
25+
"name": "deploy",
26+
"outputs": [
27+
{
28+
"internalType": "address",
29+
"name": "_superchainERC20",
30+
"type": "address"
31+
}
32+
],
33+
"stateMutability": "nonpayable",
34+
"type": "function"
35+
},
36+
{
37+
"inputs": [
38+
{
39+
"internalType": "address",
40+
"name": "superchainToken",
41+
"type": "address"
42+
}
43+
],
44+
"name": "deployments",
45+
"outputs": [
46+
{
47+
"internalType": "address",
48+
"name": "remoteToken",
49+
"type": "address"
50+
}
51+
],
52+
"stateMutability": "view",
53+
"type": "function"
54+
},
55+
{
56+
"inputs": [],
57+
"name": "version",
58+
"outputs": [
59+
{
60+
"internalType": "string",
61+
"name": "",
62+
"type": "string"
63+
}
64+
],
65+
"stateMutability": "view",
66+
"type": "function"
67+
},
68+
{
69+
"anonymous": false,
70+
"inputs": [
71+
{
72+
"indexed": true,
73+
"internalType": "address",
74+
"name": "superchainToken",
75+
"type": "address"
76+
},
77+
{
78+
"indexed": true,
79+
"internalType": "address",
80+
"name": "remoteToken",
81+
"type": "address"
82+
},
83+
{
84+
"indexed": false,
85+
"internalType": "address",
86+
"name": "deployer",
87+
"type": "address"
88+
}
89+
],
90+
"name": "OptimismSuperchainERC20Created",
91+
"type": "event"
92+
}
93+
]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[
2+
{
3+
"bytes": "32",
4+
"label": "deployments",
5+
"offset": 0,
6+
"slot": "0",
7+
"type": "mapping(address => address)"
8+
}
9+
]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.15;
3+
4+
import { IBeacon } from "@openzeppelin/contracts/proxy/beacon/IBeacon.sol";
5+
import { ISemver } from "src/universal/interfaces/ISemver.sol";
6+
7+
/// @custom:proxied
8+
/// @custom:predeployed 0x4200000000000000000000000000000000000027
9+
/// @title OptimismSuperchainERC20Beacon
10+
/// @notice OptimismSuperchainERC20Beacon is the beacon proxy for the OptimismSuperchainERC20 implementation.
11+
contract OptimismSuperchainERC20Beacon is IBeacon, ISemver {
12+
/// @notice Address of the OptimismSuperchainERC20 implementation.
13+
address internal immutable IMPLEMENTATION;
14+
15+
/// @notice Semantic version.
16+
/// @custom:semver 1.0.0-beta.1
17+
string public constant version = "1.0.0-beta.1";
18+
19+
constructor(address _implementation) {
20+
IMPLEMENTATION = _implementation;
21+
}
22+
23+
/// @inheritdoc IBeacon
24+
function implementation() external view override returns (address) {
25+
return IMPLEMENTATION;
26+
}
27+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.25;
3+
4+
import { IOptimismERC20Factory } from "src/L2/interfaces/IOptimismERC20Factory.sol";
5+
import { ISemver } from "src/universal/interfaces/ISemver.sol";
6+
import { OptimismSuperchainERC20 } from "src/L2/OptimismSuperchainERC20.sol";
7+
import { Predeploys } from "src/libraries/Predeploys.sol";
8+
import { BeaconProxy } from "@openzeppelin/contracts-v5/proxy/beacon/BeaconProxy.sol";
9+
import { CREATE3 } from "@rari-capital/solmate/src/utils/CREATE3.sol";
10+
11+
/// @custom:proxied
12+
/// @custom:predeployed 0x4200000000000000000000000000000000000026
13+
/// @title OptimismSuperchainERC20Factory
14+
/// @notice OptimismSuperchainERC20Factory is a factory contract that deploys OptimismSuperchainERC20 Beacon Proxies
15+
/// using CREATE3.
16+
contract OptimismSuperchainERC20Factory is IOptimismERC20Factory, ISemver {
17+
/// @notice Mapping of the deployed OptimismSuperchainERC20 to the remote token address.
18+
/// This is used to keep track of the token deployments.
19+
mapping(address superchainToken => address remoteToken) public deployments;
20+
21+
/// @notice Emitted when an OptimismSuperchainERC20 is deployed.
22+
/// @param superchainToken Address of the SuperchainERC20 deployment.
23+
/// @param remoteToken Address of the corresponding token on the remote chain.
24+
/// @param deployer Address of the account that deployed the token.
25+
event OptimismSuperchainERC20Created(
26+
address indexed superchainToken, address indexed remoteToken, address deployer
27+
);
28+
29+
/// @notice Semantic version.
30+
/// @custom:semver 1.0.0-beta.1
31+
string public constant version = "1.0.0-beta.1";
32+
33+
/// @notice Deploys a OptimismSuperchainERC20 Beacon Proxy using CREATE3.
34+
/// @param _remoteToken Address of the remote token.
35+
/// @param _name Name of the OptimismSuperchainERC20.
36+
/// @param _symbol Symbol of the OptimismSuperchainERC20.
37+
/// @param _decimals Decimals of the OptimismSuperchainERC20.
38+
/// @return _superchainERC20 Address of the OptimismSuperchainERC20 deployment.
39+
function deploy(
40+
address _remoteToken,
41+
string memory _name,
42+
string memory _symbol,
43+
uint8 _decimals
44+
)
45+
external
46+
returns (address _superchainERC20)
47+
{
48+
bytes memory initCallData =
49+
abi.encodeCall(OptimismSuperchainERC20.initialize, (_remoteToken, _name, _symbol, _decimals));
50+
51+
bytes memory creationCode = bytes.concat(
52+
type(BeaconProxy).creationCode, abi.encode(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_BEACON, initCallData)
53+
);
54+
55+
bytes32 salt = keccak256(abi.encode(_remoteToken, _name, _symbol, _decimals));
56+
_superchainERC20 = CREATE3.deploy({ salt: salt, creationCode: creationCode, value: 0 });
57+
58+
deployments[_superchainERC20] = _remoteToken;
59+
60+
emit OptimismSuperchainERC20Created(_superchainERC20, _remoteToken, msg.sender);
61+
}
62+
}

0 commit comments

Comments
 (0)