diff --git a/op-bindings/predeploys/addresses.go b/op-bindings/predeploys/addresses.go index 17742f3a21cb885a4d546bed673305e3b993533a..1a33a519f002ea49feaced1af8eed85dbf0c8648 100644 --- a/op-bindings/predeploys/addresses.go +++ b/op-bindings/predeploys/addresses.go @@ -5,7 +5,6 @@ import "github.com/ethereum/go-ethereum/common" const ( L2ToL1MessagePasser = "0x4200000000000000000000000000000000000016" DeployerWhitelist = "0x4200000000000000000000000000000000000002" - LegacyERC20ETH = "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000" WETH9 = "0x4200000000000000000000000000000000000006" L2CrossDomainMessenger = "0x4200000000000000000000000000000000000007" L2StandardBridge = "0x4200000000000000000000000000000000000010" @@ -26,7 +25,6 @@ const ( var ( L2ToL1MessagePasserAddr = common.HexToAddress(L2ToL1MessagePasser) DeployerWhitelistAddr = common.HexToAddress(DeployerWhitelist) - LegacyERC20ETHAddr = common.HexToAddress(LegacyERC20ETH) WETH9Addr = common.HexToAddress(WETH9) L2CrossDomainMessengerAddr = common.HexToAddress(L2CrossDomainMessenger) L2StandardBridgeAddr = common.HexToAddress(L2StandardBridge) @@ -49,27 +47,17 @@ var ( // IsProxied returns true for predeploys that will sit behind a proxy contract func IsProxied(predeployAddr common.Address) bool { switch predeployAddr { - case LegacyERC20ETHAddr: case WETH9Addr: case GovernanceTokenAddr: - case ProxyAdminAddr: default: return true } return false } -// IsDeprecated returns true for predeploys we should skip in post-bedrock genesis generation -func IsDeprecated(predeployAddr common.Address) bool { - // TODO: confirm if we can safely add the remaining deprecated predeploys here - // (see https://github.com/ethereum-optimism/optimism/blob/develop/specs/predeploys.md#overview) - return predeployAddr == LegacyERC20ETHAddr -} - func init() { Predeploys["L2ToL1MessagePasser"] = &L2ToL1MessagePasserAddr Predeploys["DeployerWhitelist"] = &DeployerWhitelistAddr - Predeploys["LegacyERC20ETH"] = &LegacyERC20ETHAddr Predeploys["WETH9"] = &WETH9Addr Predeploys["L2CrossDomainMessenger"] = &L2CrossDomainMessengerAddr Predeploys["L2StandardBridge"] = &L2StandardBridgeAddr diff --git a/op-chain-ops/genesis/layer_two.go b/op-chain-ops/genesis/layer_two.go index a6d1971f9d89d75b73d5da6874fc6e670daf9980..effd4477e33e60d52e8a1147e797d0efd418e098 100644 --- a/op-chain-ops/genesis/layer_two.go +++ b/op-chain-ops/genesis/layer_two.go @@ -1,84 +1,30 @@ package genesis import ( - "errors" "fmt" - "math/big" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" - "github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/predeploys" "github.com/ethereum-optimism/optimism/op-chain-ops/immutables" "github.com/ethereum-optimism/optimism/op-chain-ops/state" ) -// BuildL2DeveloperGenesis will build the developer Optimism Genesis -// Block. Suitable for devnets. -func BuildL2DeveloperGenesis(config *DeployConfig, l1StartBlock *types.Block) (*core.Genesis, error) { +// BuildL2DeveloperGenesis will build the L2 genesis block. +func BuildL2Genesis(config *DeployConfig, l1StartBlock *types.Block) (*core.Genesis, error) { genspec, err := NewL2Genesis(config, l1StartBlock) if err != nil { return nil, err } db := state.NewMemoryStateDB(genspec) - if config.FundDevAccounts { FundDevAccounts(db) - } - SetPrecompileBalances(db) - - storage, err := NewL2StorageConfig(config, l1StartBlock) - if err != nil { - return nil, err - } - - immutable, err := NewL2ImmutableConfig(config, l1StartBlock) - if err != nil { - return nil, err - } - - if err := SetL2Proxies(db); err != nil { - return nil, err - } - - if err := SetImplementations(db, storage, immutable); err != nil { - return nil, err + SetPrecompileBalances(db) } - if err := SetDevOnlyL2Implementations(db, storage, immutable); err != nil { - return nil, err - } - - return db.Genesis(), nil -} - -// BuildL2MainnetGenesis will build an L2 Genesis suitable for a Superchain mainnet that does not -// require a pre-bedrock migration & supports optional governance token predeploy. Details: -// -// - Creates proxies for predeploys in the address space: -// [0x4200000000000000000000000000000000000000, 0x4200000000000000000000000000000000000800) -// -// - All predeploy proxies owned by the ProxyAdmin -// -// - Predeploys as per the spec except for no LegacyERC20ETH predeploy at -// 0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000 -// -// - optional governance token at 0x4200000000000000000000000000000000000042 if -// config.EnableGovernance is true (& otherwise a no-impl proxy remains at this address) -// -// - no accounts are pre-funded -func BuildL2MainnetGenesis(config *DeployConfig, l1StartBlock *types.Block) (*core.Genesis, error) { - genspec, err := NewL2Genesis(config, l1StartBlock) - if err != nil { - return nil, err - } - - db := state.NewMemoryStateDB(genspec) - storage, err := NewL2StorageConfig(config, l1StartBlock) if err != nil { return nil, err @@ -90,20 +36,10 @@ func BuildL2MainnetGenesis(config *DeployConfig, l1StartBlock *types.Block) (*co } // Set up the proxies - depBytecode, err := bindings.GetDeployedBytecode("Proxy") + err = setProxies(db, predeploys.ProxyAdminAddr, bigL2PredeployNamespace, 2048) if err != nil { return nil, err } - if len(depBytecode) == 0 { - return nil, errors.New("Proxy has empty bytecode") - } - for i := uint64(0); i <= 2048; i++ { - bigAddr := new(big.Int).Or(bigL2PredeployNamespace, new(big.Int).SetUint64(i)) - addr := common.BigToAddress(bigAddr) - db.CreateAccount(addr) - db.SetCode(addr, depBytecode) - db.SetState(addr, AdminSlot, predeploys.ProxyAdminAddr.Hash()) - } // Set up the implementations deployResults, err := immutables.BuildOptimism(immutable) @@ -112,9 +48,6 @@ func BuildL2MainnetGenesis(config *DeployConfig, l1StartBlock *types.Block) (*co } for name, predeploy := range predeploys.Predeploys { addr := *predeploy - if predeploys.IsDeprecated(addr) { - continue - } if addr == predeploys.GovernanceTokenAddr && !config.EnableGovernance { // there is no governance token configured, so skip the governance token predeploy log.Warn("Governance is not enabled, skipping governance token predeploy.") diff --git a/op-chain-ops/genesis/layer_two_test.go b/op-chain-ops/genesis/layer_two_test.go index f6a970ecbb3006566d06e9fc432e09bc46981459..5d2727d5be5f38eed1c444deb6ffcf85e04aac49 100644 --- a/op-chain-ops/genesis/layer_two_test.go +++ b/op-chain-ops/genesis/layer_two_test.go @@ -28,80 +28,8 @@ func init() { var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") -func TestBuildL2DeveloperGenesis(t *testing.T) { - config, err := genesis.NewDeployConfig("./testdata/test-deploy-config-devnet-l1.json") - require.Nil(t, err) - - backend := backends.NewSimulatedBackend( - core.GenesisAlloc{ - crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)}, - }, - 15000000, - ) - block, err := backend.BlockByNumber(context.Background(), common.Big0) - require.NoError(t, err) - - gen, err := genesis.BuildL2DeveloperGenesis(config, block) - require.Nil(t, err) - require.NotNil(t, gen) - - proxyBytecode, err := bindings.GetDeployedBytecode("Proxy") - require.NoError(t, err) - - for name, address := range predeploys.Predeploys { - addr := *address - - account, ok := gen.Alloc[addr] - require.Equal(t, true, ok) - require.Greater(t, len(account.Code), 0) - - if name == "GovernanceToken" || name == "LegacyERC20ETH" || name == "ProxyAdmin" || name == "WETH9" { - continue - } - - adminSlot, ok := account.Storage[genesis.AdminSlot] - require.Equal(t, true, ok, name) - require.Equal(t, predeploys.ProxyAdminAddr.Hash(), adminSlot) - require.Equal(t, proxyBytecode, account.Code) - } - require.Equal(t, 2343, len(gen.Alloc)) - - if writeFile { - file, _ := json.MarshalIndent(gen, "", " ") - _ = os.WriteFile("genesis.json", file, 0644) - } -} - -func TestBuildL2DeveloperGenesisDevAccountsFunding(t *testing.T) { - config, err := genesis.NewDeployConfig("./testdata/test-deploy-config-devnet-l1.json") - require.Nil(t, err) - config.FundDevAccounts = false - - err = config.InitDeveloperDeployedAddresses() - require.NoError(t, err) - - backend := backends.NewSimulatedBackend( - core.GenesisAlloc{ - crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)}, - }, - 15000000, - ) - block, err := backend.BlockByNumber(context.Background(), common.Big0) - require.NoError(t, err) - - gen, err := genesis.BuildL2DeveloperGenesis(config, block) - require.NoError(t, err) - require.Equal(t, 2321, len(gen.Alloc)) -} - -// Tests the BuildL2MainnetGenesis factory. enableGovernance is used to override enableGovernance -// config option. When false, the test confirms the governance token predeploy address instead -// holds a proxy contract. -func testBuildL2Genesis(t *testing.T, enableGovernance bool) { - config, err := genesis.NewDeployConfig("./testdata/test-deploy-config-devnet-l1.json") - require.Nil(t, err) - config.EnableGovernance = enableGovernance - +// Tests the BuildL2MainnetGenesis factory with the provided config. +func testBuildL2Genesis(t *testing.T, config *genesis.DeployConfig) *core.Genesis { backend := backends.NewSimulatedBackend( core.GenesisAlloc{ crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000000000)}, @@ -111,7 +39,7 @@ func testBuildL2Genesis(t *testing.T, enableGovernance bool) { block, err := backend.BlockByNumber(context.Background(), common.Big0) require.NoError(t, err) - gen, err := genesis.BuildL2MainnetGenesis(config, block) + gen, err := genesis.BuildL2Genesis(config, block) require.Nil(t, err) require.NotNil(t, gen) @@ -122,17 +50,12 @@ func testBuildL2Genesis(t *testing.T, enableGovernance bool) { addr := *predeploy account, ok := gen.Alloc[addr] - if predeploys.IsDeprecated(addr) && !predeploys.IsProxied(addr) { - // deprecated, non-proxied predeploys should have no account - require.Equal(t, false, ok, name) - continue - } require.Equal(t, true, ok, name) require.Greater(t, len(account.Code), 0) adminSlot, ok := account.Storage[genesis.AdminSlot] isProxy := predeploys.IsProxied(addr) || - (!enableGovernance && addr == predeploys.GovernanceTokenAddr) + (!config.EnableGovernance && addr == predeploys.GovernanceTokenAddr) if isProxy { require.Equal(t, true, ok, name) require.Equal(t, predeploys.ProxyAdminAddr.Hash(), adminSlot) @@ -142,18 +65,39 @@ func testBuildL2Genesis(t *testing.T, enableGovernance bool) { require.NotEqual(t, proxyBytecode, account.Code, name) } } - require.Equal(t, 2063, len(gen.Alloc)) if writeFile { file, _ := json.MarshalIndent(gen, "", " ") _ = os.WriteFile("genesis.json", file, 0644) } + return gen +} + +func TestBuildL2DeveloperGenesis(t *testing.T) { + config, err := genesis.NewDeployConfig("./testdata/test-deploy-config-devnet-l1.json") + require.Nil(t, err) + config.EnableGovernance = false + config.FundDevAccounts = true + err = config.InitDeveloperDeployedAddresses() + require.NoError(t, err) + gen := testBuildL2Genesis(t, config) + require.Equal(t, 2342, len(gen.Alloc)) } func TestBuildL2MainnetGenesis(t *testing.T) { - testBuildL2Genesis(t, true) + config, err := genesis.NewDeployConfig("./testdata/test-deploy-config-devnet-l1.json") + require.Nil(t, err) + config.EnableGovernance = true + config.FundDevAccounts = false + gen := testBuildL2Genesis(t, config) + require.Equal(t, 2064, len(gen.Alloc)) } func TestBuildL2MainnetNoGovernanceGenesis(t *testing.T) { - testBuildL2Genesis(t, false) + config, err := genesis.NewDeployConfig("./testdata/test-deploy-config-devnet-l1.json") + require.Nil(t, err) + config.EnableGovernance = false + config.FundDevAccounts = false + gen := testBuildL2Genesis(t, config) + require.Equal(t, 2064, len(gen.Alloc)) } diff --git a/op-chain-ops/genesis/setters.go b/op-chain-ops/genesis/setters.go index 1712eba125a3af50e9ac144c5fb926434aa9971f..c0988571cf556f178463b27bd82f6a9234d78b0c 100644 --- a/op-chain-ops/genesis/setters.go +++ b/op-chain-ops/genesis/setters.go @@ -2,12 +2,10 @@ package genesis import ( "errors" - "fmt" "math/big" "github.com/ethereum-optimism/optimism/op-bindings/bindings" - "github.com/ethereum-optimism/optimism/op-bindings/predeploys" "github.com/ethereum-optimism/optimism/op-chain-ops/immutables" "github.com/ethereum-optimism/optimism/op-chain-ops/state" "github.com/ethereum/go-ethereum/common" @@ -15,19 +13,6 @@ import ( "github.com/ethereum/go-ethereum/log" ) -// UntouchableCodeHashes contains code hashes of all the contracts -// that should not be touched by the migration process. -type ChainHashMap map[uint64]common.Hash - -var ( - // UntouchablePredeploys are addresses in the predeploy namespace - // that should not be touched by the migration process. - UntouchablePredeploys = map[common.Address]bool{ - predeploys.GovernanceTokenAddr: true, - predeploys.WETH9Addr: true, - } -) - // FundDevAccounts will fund each of the development accounts. func FundDevAccounts(db vm.StateDB) { for _, account := range DevAccounts { @@ -36,14 +21,6 @@ func FundDevAccounts(db vm.StateDB) { } } -// SetL2Proxies will set each of the proxies in the state. It requires -// a Proxy and ProxyAdmin deployment present so that the Proxy bytecode -// can be set in state and the ProxyAdmin can be set as the admin of the -// Proxy. -func SetL2Proxies(db vm.StateDB) error { - return setProxies(db, predeploys.ProxyAdminAddr, bigL2PredeployNamespace, 2048) -} - // SetL1Proxies will set each of the proxies in the state. It requires // a Proxy and ProxyAdmin deployment present so that the Proxy bytecode // can be set in state and the ProxyAdmin can be set as the admin of the @@ -65,11 +42,6 @@ func setProxies(db vm.StateDB, proxyAdminAddr common.Address, namespace *big.Int bigAddr := new(big.Int).Or(namespace, new(big.Int).SetUint64(i)) addr := common.BigToAddress(bigAddr) - if UntouchablePredeploys[addr] { - log.Info("Skipping setting proxy", "address", addr) - continue - } - if !db.Exist(addr) { db.CreateAccount(addr) } @@ -82,87 +54,6 @@ func setProxies(db vm.StateDB, proxyAdminAddr common.Address, namespace *big.Int return nil } -func SetLegacyETH(db vm.StateDB, storage state.StorageConfig, immutable immutables.ImmutableConfig) error { - deployResults, err := immutables.BuildOptimism(immutable) - if err != nil { - return err - } - - return setupPredeploy(db, deployResults, storage, "LegacyERC20ETH", predeploys.LegacyERC20ETHAddr, predeploys.LegacyERC20ETHAddr) -} - -// SetImplementations will set the implementations of the contracts in the state -// and configure the proxies to point to the implementations. It also sets -// the appropriate storage values for each contract at the proxy address. -func SetImplementations(db vm.StateDB, storage state.StorageConfig, immutable immutables.ImmutableConfig) error { - deployResults, err := immutables.BuildOptimism(immutable) - if err != nil { - return err - } - - for name, address := range predeploys.Predeploys { - if UntouchablePredeploys[*address] { - continue - } - - if *address == predeploys.LegacyERC20ETHAddr { - continue - } - - codeAddr, err := AddressToCodeNamespace(*address) - if err != nil { - return fmt.Errorf("error converting to code namespace: %w", err) - } - - if !db.Exist(codeAddr) { - db.CreateAccount(codeAddr) - } - - db.SetState(*address, ImplementationSlot, codeAddr.Hash()) - - if err := setupPredeploy(db, deployResults, storage, name, *address, codeAddr); err != nil { - return err - } - - code := db.GetCode(codeAddr) - if len(code) == 0 { - return fmt.Errorf("code not set for %s", name) - } - } - return nil -} - -func SetDevOnlyL2Implementations(db vm.StateDB, storage state.StorageConfig, immutable immutables.ImmutableConfig) error { - deployResults, err := immutables.BuildOptimism(immutable) - if err != nil { - return err - } - - for name, address := range predeploys.Predeploys { - if !UntouchablePredeploys[*address] { - continue - } - - db.CreateAccount(*address) - - if err := setupPredeploy(db, deployResults, storage, name, *address, *address); err != nil { - return err - } - - code := db.GetCode(*address) - if len(code) == 0 { - return fmt.Errorf("code not set for %s", name) - } - } - - db.CreateAccount(predeploys.LegacyERC20ETHAddr) - if err := setupPredeploy(db, deployResults, storage, "LegacyERC20ETH", predeploys.LegacyERC20ETHAddr, predeploys.LegacyERC20ETHAddr); err != nil { - return fmt.Errorf("error setting up legacy eth: %w", err) - } - - return nil -} - // SetPrecompileBalances will set a single wei at each precompile address. // This is an optimization to make calling them cheaper. This should only // be used for devnets. diff --git a/op-e2e/e2eutils/setup.go b/op-e2e/e2eutils/setup.go index d1f12f0d5b69cad891d4e5d77ea4e8b3cbab9294..f45cc70b0270e7cd209cc91d11a6031fc8ae4328 100644 --- a/op-e2e/e2eutils/setup.go +++ b/op-e2e/e2eutils/setup.go @@ -185,7 +185,7 @@ func Setup(t require.TestingT, deployParams *DeployParams, alloc *AllocParams) * l1Block := l1Genesis.ToBlock() - l2Genesis, err := genesis.BuildL2DeveloperGenesis(deployConf, l1Block) + l2Genesis, err := genesis.BuildL2Genesis(deployConf, l1Block) require.NoError(t, err, "failed to create l2 genesis") if alloc.PrefundTestUsers { for _, addr := range deployParams.Addresses.All() { diff --git a/op-e2e/op_geth.go b/op-e2e/op_geth.go index 0798b8e930025a722793ff7f37d1098d821d9a4f..d25044762a1ceab22db1c08dd5aabb1e2592022e 100644 --- a/op-e2e/op_geth.go +++ b/op-e2e/op_geth.go @@ -53,7 +53,7 @@ func NewOpGeth(t *testing.T, ctx context.Context, cfg *SystemConfig) (*OpGeth, e require.Nil(t, err) l1Block := l1Genesis.ToBlock() - l2Genesis, err := genesis.BuildL2DeveloperGenesis(cfg.DeployConfig, l1Block) + l2Genesis, err := genesis.BuildL2Genesis(cfg.DeployConfig, l1Block) require.Nil(t, err) l2GenesisBlock := l2Genesis.ToBlock() diff --git a/op-e2e/setup.go b/op-e2e/setup.go index 92fc0415565644e921d10e2eb61c16d6d8b3864a..ab1bdd2202358b2b36cd1dad233b1c5aea7faf49 100644 --- a/op-e2e/setup.go +++ b/op-e2e/setup.go @@ -359,7 +359,7 @@ func (cfg SystemConfig) Start(_opts ...SystemConfigOption) (*System, error) { } l1Block := l1Genesis.ToBlock() - l2Genesis, err := genesis.BuildL2DeveloperGenesis(cfg.DeployConfig, l1Block) + l2Genesis, err := genesis.BuildL2Genesis(cfg.DeployConfig, l1Block) if err != nil { return nil, err } diff --git a/op-node/cmd/genesis/cmd.go b/op-node/cmd/genesis/cmd.go index 7908b44c235be3bd7916f548fdf7db1f238bb086..ac3597b8491477d4c5994f625fb4e99c726e4310 100644 --- a/op-node/cmd/genesis/cmd.go +++ b/op-node/cmd/genesis/cmd.go @@ -61,7 +61,7 @@ var Subcommands = cli.Commands{ } l1StartBlock := l1Genesis.ToBlock() - l2Genesis, err := genesis.BuildL2DeveloperGenesis(config, l1StartBlock) + l2Genesis, err := genesis.BuildL2Genesis(config, l1StartBlock) if err != nil { return err } @@ -144,7 +144,7 @@ var Subcommands = cli.Commands{ } // Build the developer L2 genesis block - l2Genesis, err := genesis.BuildL2DeveloperGenesis(config, l1StartBlock) + l2Genesis, err := genesis.BuildL2Genesis(config, l1StartBlock) if err != nil { return fmt.Errorf("error creating l2 developer genesis: %w", err) } diff --git a/packages/contracts-bedrock/tasks/check-l2.ts b/packages/contracts-bedrock/tasks/check-l2.ts index 5054563003b55124818c9c22ac39eab96b5ea755..26200a776c5cd8f5320a6a221c581248d1c6a405 100644 --- a/packages/contracts-bedrock/tasks/check-l2.ts +++ b/packages/contracts-bedrock/tasks/check-l2.ts @@ -465,46 +465,6 @@ const check = { await checkProxy(hre, 'L1Block', signer.provider) await assertProxy(hre, 'L1Block', signer.provider) }, - // LegacyERC20ETH - // - not behind a proxy - // - check name - // - check symbol - // - check decimals - // - check BRIDGE - // - check REMOTE_TOKEN - // - totalSupply should be set to 0 - LegacyERC20ETH: async (hre: HardhatRuntimeEnvironment, signer: Signer) => { - const LegacyERC20ETH = await hre.ethers.getContractAt( - 'LegacyERC20ETH', - predeploys.LegacyERC20ETH, - signer - ) - - const name = await LegacyERC20ETH.name() - assert(name === 'Ether') - console.log(` - name: ${name}`) - - const symbol = await LegacyERC20ETH.symbol() - assert(symbol === 'ETH') - console.log(` - symbol: ${symbol}`) - - const decimals = await LegacyERC20ETH.decimals() - assert(decimals === 18) - console.log(` - decimals: ${decimals}`) - - const BRIDGE = await LegacyERC20ETH.BRIDGE() - assert(BRIDGE === predeploys.L2StandardBridge) - - const REMOTE_TOKEN = await LegacyERC20ETH.REMOTE_TOKEN() - assert(REMOTE_TOKEN === hre.ethers.constants.AddressZero) - - const totalSupply = await LegacyERC20ETH.totalSupply() - assert(totalSupply.eq(0)) - console.log(` - totalSupply: ${totalSupply}`) - - await checkProxy(hre, 'LegacyERC20ETH', signer.provider) - // No proxy at this address, don't call assertProxy - }, // WETH9 // - check name // - check symbol diff --git a/specs/predeploys.md b/specs/predeploys.md index 1a06916146243d60a1ae8d1d4cbcd90553fbaac3..3213b7b4078db848af5894cfe8bf94c52334463a 100644 --- a/specs/predeploys.md +++ b/specs/predeploys.md @@ -62,7 +62,7 @@ or `Bedrock`. Deprecated contracts should not be used. | L2ToL1MessagePasser | 0x4200000000000000000000000000000000000016 | Bedrock | No | Yes | | L2ERC721Bridge | 0x4200000000000000000000000000000000000014 | Legacy | No | Yes | | OptimismMintableERC721Factory | 0x4200000000000000000000000000000000000017 | Bedrock | No | Yes | -| ProxyAdmin | 0x4200000000000000000000000000000000000018 | Bedrock | No | No | +| ProxyAdmin | 0x4200000000000000000000000000000000000018 | Bedrock | No | Yes | | BaseFeeVault | 0x4200000000000000000000000000000000000019 | Bedrock | No | Yes | | L1FeeVault | 0x420000000000000000000000000000000000001a | Bedrock | No | Yes |