Commit db3e90e6 authored by Mark Tyneway's avatar Mark Tyneway

op-chain-ops: rewrite checkl2 in go

Migrate away from the hh version of check-l2 to a go implementation.
The go implementation is much faster so this will help to reduce time
in CI. It also removes the final dep on hh in the contracts-bedrock
package.
parent d6b7236b
......@@ -861,8 +861,8 @@ jobs:
make devnet-up-deploy
- run:
name: Check L2 config
command: npx hardhat check-l2 --network devnetL1 --l2-rpc-url http://localhost:9545 --l1-rpc-url http://localhost:8545
working_directory: packages/contracts-bedrock
command: go run cmd/check-l2/main.go --l2-rpc-url http://localhost:9545 --l1-rpc-url http://localhost:8545
working_directory: op-chain-ops
- run:
name: Deposit ERC20 through the bridge
command: timeout 8m npx hardhat deposit-erc20 --network devnetL1 --l1-contracts-json-path ../../.devnet/sdk-addresses.json
......@@ -907,13 +907,8 @@ jobs:
make devnet-up
- run:
name: Check L2 config
command: |
npx hardhat check-l2 \
--network devnetL1 \
--l2-rpc-url http://localhost:9545 \
--l1-rpc-url http://localhost:8545 \
--l2-output-oracle-address 0x6900000000000000000000000000000000000000
working_directory: packages/contracts-bedrock
command: go run cmd/check-l2/main.go --l2-rpc-url http://localhost:9545 --l1-rpc-url http://localhost:8545
working_directory: op-chain-ops
- run:
name: Deposit ERC20 through the bridge
command: timeout 10m npx hardhat deposit-erc20 --network devnetL1
......
package main
import (
// "errors"
"bytes"
"context"
"errors"
"fmt"
"golang.org/x/sync/errgroup"
"math/big"
"os"
"github.com/mattn/go-isatty"
"github.com/urfave/cli/v2"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum-optimism/optimism/op-chain-ops/util"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
)
var defaultCrossDomainMessageSender = common.HexToAddress("0x000000000000000000000000000000000000dead")
// Default script for checking that L2 has been configured correctly. This should be extended in the future
// to pull in L1 deploy artifacts and assert that the L2 state is consistent with the L1 state.
func main() {
log.Root().SetHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(isatty.IsTerminal(os.Stderr.Fd()))))
flags := []cli.Flag{}
flags = append(flags, util.ClientsFlags...)
flags = append(flags, util.AddressesFlags...)
app := &cli.App{
Name: "check-l2",
Usage: "Check that an OP Stack L2 has been configured correctly",
Flags: flags,
Action: func(ctx *cli.Context) error {
clients, err := util.NewClients(ctx)
if err != nil {
return err
}
log.Info("Checking predeploy proxy config")
g := new(errgroup.Group)
// All admin slots should be set
count := uint64(2048)
for i := uint64(0); i < count; i++ {
i := i
if i%4 == 0 {
log.Info("Checking proxy", "index", i, "total", count)
if err := g.Wait(); err != nil {
return err
}
}
g.Go(func() error {
return checkPredeploy(clients.L2Client, i)
})
}
if err := g.Wait(); err != nil {
return err
}
log.Info("All predeploy proxies are set correctly")
// Check that all of the predeploy proxies are set
for name := range predeploys.Predeploys {
log.Info("Checking predeploy", "name", name)
if err := checkPredeployConfig(clients.L2Client, name); err != nil {
return err
}
}
return nil
},
}
if err := app.Run(os.Args); err != nil {
log.Crit("error indexing state", "err", err)
}
}
func checkPredeployConfig(client *ethclient.Client, name string) error {
predeploy := predeploys.Predeploys[name]
if predeploy == nil {
return fmt.Errorf("unknown predeploy %s", name)
}
p := *predeploy
g := new(errgroup.Group)
if predeploys.IsProxied(p) {
g.Go(func() error {
impl, err := getEIP1967ImplementationAddress(client, p)
if err != nil {
return err
}
standardImpl, err := genesis.AddressToCodeNamespace(p)
if err != nil {
return err
}
if impl != standardImpl {
log.Warn("%s does not have the standard implementation", name)
}
implCode, err := client.CodeAt(context.Background(), impl, nil)
if err != nil {
return err
}
if len(implCode) == 0 {
return fmt.Errorf("%s implementation is not deployed", name)
}
return nil
})
g.Go(func() error {
proxyCode, err := client.CodeAt(context.Background(), p, nil)
if err != nil {
return err
}
proxy, err := bindings.GetDeployedBytecode("Proxy")
if err != nil {
return err
}
if !bytes.Equal(proxyCode, proxy) {
return fmt.Errorf("%s does not have the standard proxy code", name)
}
return nil
})
}
//
g.Go(func() error {
switch p {
case predeploys.LegacyMessagePasserAddr:
contract, err := bindings.NewLegacyMessagePasser(p, client)
if err != nil {
return err
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("LegacyMessagePasser version", "version", version)
case predeploys.DeployerWhitelistAddr:
contract, err := bindings.NewDeployerWhitelist(p, client)
if err != nil {
return err
}
owner, err := contract.Owner(&bind.CallOpts{})
if err != nil {
return err
}
if owner != (common.Address{}) {
return fmt.Errorf("DeployerWhitelist owner should be set to address(0)")
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("DeployerWhitelist version", "version", version)
case predeploys.L2CrossDomainMessengerAddr:
slot, err := client.StorageAt(context.Background(), p, common.Hash{31: 0xcc}, nil)
if err != nil {
return err
}
addr := common.BytesToAddress(slot)
if addr != defaultCrossDomainMessageSender {
return fmt.Errorf("Expected xDomainMsgSender to be %s, got %s", defaultCrossDomainMessageSender, addr)
}
contract, err := bindings.NewL2CrossDomainMessenger(p, client)
if err != nil {
return err
}
otherMessenger, err := contract.OTHERMESSENGER(&bind.CallOpts{})
if err != nil {
return err
}
if otherMessenger == (common.Address{}) {
return errors.New("OTHERMESSENGER should not be address(0)")
}
log.Info("L2CrossDomainMessenger", "OTHERMESSENGER", otherMessenger.Hex())
l1CrossDomainMessenger, err := contract.L1CrossDomainMessenger(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "l1CrossDomainMessenger", l1CrossDomainMessenger.Hex())
messageVersion, err := contract.MESSAGEVERSION(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "MESSAGE_VERSION", messageVersion)
minGasCallDataOverhead, err := contract.MINGASCALLDATAOVERHEAD(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "MIN_GAS_CALLDATA_OVERHEAD", minGasCallDataOverhead)
relayConstantOverhead, err := contract.RELAYCONSTANTOVERHEAD(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "RELAY_CONSTANT_OVERHEAD", relayConstantOverhead)
minGasDynamicsOverheadDenominator, err := contract.MINGASDYNAMICOVERHEADDENOMINATOR(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR", minGasDynamicsOverheadDenominator)
minGasDynamicsOverheadNumerator, err := contract.MINGASDYNAMICOVERHEADNUMERATOR(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR", minGasDynamicsOverheadNumerator)
relayCallOverhead, err := contract.RELAYCALLOVERHEAD(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "RELAY_CALL_OVERHEAD", relayCallOverhead)
relayReservedGas, err := contract.RELAYRESERVEDGAS(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "RELAY_RESERVED_GAS", relayReservedGas)
relayGasCheckBuffer, err := contract.RELAYGASCHECKBUFFER(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger", "RELAY_GAS_CHECK_BUFFER", relayGasCheckBuffer)
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2CrossDomainMessenger version", "version", version)
case predeploys.GasPriceOracleAddr:
contract, err := bindings.NewGasPriceOracle(p, client)
if err != nil {
return err
}
decimals, err := contract.DECIMALS(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("GasPriceOracle", "DECIMALS", decimals)
if decimals.Cmp(big.NewInt(6)) != 0 {
return fmt.Errorf("GasPriceOracle decimals should be 6, got %v", decimals)
}
version, err := contract.Version(&bind.CallOpts{})
log.Info("GasPriceOracle version", "version", version)
case predeploys.L2StandardBridgeAddr:
contract, err := bindings.NewL2StandardBridge(p, client)
if err != nil {
return err
}
otherBridge, err := contract.OTHERBRIDGE(&bind.CallOpts{})
if err != nil {
return err
}
if otherBridge == (common.Address{}) {
return errors.New("OTHERBRIDGE should not be address(0)")
}
log.Info("L2StandardBridge", "OTHERBRIDGE", otherBridge.Hex())
messenger, err := contract.MESSENGER(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2StandardBridge", "MESSENGER", messenger.Hex())
if messenger != predeploys.L2CrossDomainMessengerAddr {
return fmt.Errorf("L2StandardBridge MESSENGER should be %s, got %s", predeploys.L2CrossDomainMessengerAddr, messenger)
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2StandardBridge version", "version", version)
case predeploys.SequencerFeeVaultAddr:
contract, err := bindings.NewSequencerFeeVault(p, client)
if err != nil {
return err
}
recipient, err := contract.RECIPIENT(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("SequencerFeeVault", "RECIPIENT", recipient.Hex())
if recipient == (common.Address{}) {
return errors.New("RECIPIENT should not be address(0)")
}
l1FeeWallet, err := contract.L1FeeWallet(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("SequencerFeeVault", "l1FeeWallet", l1FeeWallet.Hex())
minWithdrawalAmount, err := contract.MINWITHDRAWALAMOUNT(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("SequencerFeeVault", "MIN_WITHDRAWAL_AMOUNT", minWithdrawalAmount)
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("SequencerFeeVault version", "version", version)
case predeploys.OptimismMintableERC20FactoryAddr:
contract, err := bindings.NewOptimismMintableERC20Factory(p, client)
if err != nil {
return err
}
bridge, err := contract.BRIDGE(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("OptimismMintableERC20Factory", "BRIDGE", bridge.Hex())
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("OptimismMintableERC20Factory version", "version", version)
case predeploys.L1BlockNumberAddr:
contract, err := bindings.NewL1BlockNumber(p, client)
if err != nil {
return err
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L1BlockNumber version", "version", version)
case predeploys.L1BlockAddr:
contract, err := bindings.NewL1Block(p, client)
if err != nil {
return err
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L1Block version", "version", version)
case predeploys.WETH9Addr:
contract, err := bindings.NewWETH9(p, client)
if err != nil {
return err
}
name, err := contract.Name(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("WETH9", "name", name)
if name != "Wrapped Ether" {
return fmt.Errorf("WETH9 name should be 'Wrapped Ether', got %s", name)
}
symbol, err := contract.Symbol(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("WETH9", "symbol", symbol)
if symbol != "WETH" {
return fmt.Errorf("WETH9 symbol should be 'WETH', got %s", symbol)
}
decimals, err := contract.Decimals(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("WETH9", "decimals", decimals)
if decimals != 18 {
return fmt.Errorf("WETH9 decimals should be 18, got %d", decimals)
}
case predeploys.GovernanceTokenAddr:
code, err := client.CodeAt(context.Background(), predeploys.GovernanceTokenAddr, nil)
if err != nil {
return err
}
if len(code) > 0 {
// This should also check the owner
contract, err := bindings.NewERC20(p, client)
if err != nil {
return err
}
name, err := contract.Name(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("GovernanceToken", "name", name)
symbol, err := contract.Symbol(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("GovernanceToken", "symbol", symbol)
totalSupply, err := contract.TotalSupply(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("GovernanceToken", "totalSupply", totalSupply)
} else {
log.Info("No code at GovernanceToken")
}
case predeploys.L2ERC721BridgeAddr:
contract, err := bindings.NewL2ERC721Bridge(p, client)
if err != nil {
return err
}
messenger, err := contract.MESSENGER(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2ERC721Bridge", "MESSENGER", messenger.Hex())
if messenger == (common.Address{}) {
return errors.New("L2ERC721Bridge.MESSENGER is zero address")
}
otherBridge, err := contract.OTHERBRIDGE(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2ERC721Bridge", "OTHERBRIDGE", otherBridge.Hex())
if otherBridge == (common.Address{}) {
return errors.New("L2ERC721Bridge.OTHERBRIDGE is zero address")
}
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2ERC721Bridge version", "version", version)
case predeploys.OptimismMintableERC721FactoryAddr:
contract, err := bindings.NewOptimismMintableERC721Factory(p, client)
if err != nil {
return err
}
bridge, err := contract.BRIDGE(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("OptimismMintableERC721Factory", "BRIDGE", bridge.Hex())
if bridge == (common.Address{}) {
return errors.New("OptimismMintableERC721Factory.BRIDGE is zero address")
}
remoteChainID, err := contract.REMOTECHAINID(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("OptimismMintableERC721Factory", "REMOTE_CHAIN_ID", remoteChainID)
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("OptimismMintableERC721Factory version", "version", version)
case predeploys.ProxyAdminAddr:
contract, err := bindings.NewProxyAdmin(p, client)
if err != nil {
return err
}
owner, err := contract.Owner(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("ProxyAdmin", "owner", owner.Hex())
if owner == (common.Address{}) {
return errors.New("ProxyAdmin.owner is zero address")
}
addressManager, err := contract.AddressManager(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("ProxyAdmin", "addressManager", addressManager.Hex())
case predeploys.BaseFeeVaultAddr:
contract, err := bindings.NewBaseFeeVault(p, client)
if err != nil {
return err
}
recipient, err := contract.RECIPIENT(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("BaseFeeVault", "RECIPIENT", recipient.Hex())
if recipient == (common.Address{}) {
return errors.New("RECIPIENT should not be address(0)")
}
minWithdrawalAmount, err := contract.MINWITHDRAWALAMOUNT(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("BaseFeeVault", "MIN_WITHDRAWAL_AMOUNT", minWithdrawalAmount)
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("BaseFeeVault version", "version", version)
case predeploys.L1FeeVaultAddr:
contract, err := bindings.NewL1FeeVault(p, client)
if err != nil {
return err
}
recipient, err := contract.RECIPIENT(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L1FeeVault", "RECIPIENT", recipient.Hex())
if recipient == (common.Address{}) {
return errors.New("RECIPIENT should not be address(0)")
}
minWithdrawalAmount, err := contract.MINWITHDRAWALAMOUNT(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L1FeeVault", "MIN_WITHDRAWAL_AMOUNT", minWithdrawalAmount)
version, err := contract.Version(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L1FeeVault version", "version", version)
case predeploys.L2ToL1MessagePasserAddr:
contract, err := bindings.NewL2ToL1MessagePasser(p, client)
if err != nil {
return err
}
messageVersion, err := contract.MESSAGEVERSION(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2ToL1MessagePasser", "MESSAGE_VERSION", messageVersion)
messageNonce, err := contract.MessageNonce(&bind.CallOpts{})
if err != nil {
return err
}
log.Info("L2ToL1MessagePasser", "MESSAGE_NONCE", messageNonce)
}
return nil
})
if err := g.Wait(); err != nil {
return err
}
// foo
return nil
}
func getEIP1967AdminAddress(client *ethclient.Client, addr common.Address) (common.Address, error) {
slot, err := client.StorageAt(context.Background(), addr, util.EIP1967AdminSlot, nil)
if err != nil {
return common.Address{}, err
}
admin := common.BytesToAddress(slot)
return admin, nil
}
func getEIP1967ImplementationAddress(client *ethclient.Client, addr common.Address) (common.Address, error) {
slot, err := client.StorageAt(context.Background(), addr, util.EIP1967ImplementationSlot, nil)
if err != nil {
return common.Address{}, err
}
impl := common.BytesToAddress(slot)
return impl, nil
}
func checkPredeploy(client *ethclient.Client, i uint64) error {
bigAddr := new(big.Int).Or(genesis.BigL2PredeployNamespace, new(big.Int).SetUint64(i))
addr := common.BigToAddress(bigAddr)
if !predeploys.IsProxied(addr) {
return nil
}
admin, err := getEIP1967AdminAddress(client, addr)
if err != nil {
return err
}
if admin != predeploys.ProxyAdminAddr {
return fmt.Errorf("%s does not have correct proxy admin set", addr)
}
return nil
}
......@@ -21,7 +21,7 @@ var (
// l1PredeployNamespace represents the namespace of L1 predeploys
l1PredeployNamespace = common.HexToAddress("0x6900000000000000000000000000000000000000")
// bigL2PredeployNamespace represents the predeploy namespace as a big.Int
bigL2PredeployNamespace = new(big.Int).SetBytes(l2PredeployNamespace.Bytes())
BigL2PredeployNamespace = new(big.Int).SetBytes(l2PredeployNamespace.Bytes())
// bigL1PredeployNamespace represents the predeploy namespace as a big.Int
bigL1PredeployNamespace = new(big.Int).SetBytes(l1PredeployNamespace.Bytes())
// bigCodeNamespace represents the predeploy namespace as a big.Int
......
......@@ -36,7 +36,7 @@ func BuildL2Genesis(config *DeployConfig, l1StartBlock *types.Block) (*core.Gene
}
// Set up the proxies
err = setProxies(db, predeploys.ProxyAdminAddr, bigL2PredeployNamespace, 2048)
err = setProxies(db, predeploys.ProxyAdminAddr, BigL2PredeployNamespace, 2048)
if err != nil {
return nil, err
}
......
package util
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/ethereum/go-ethereum/rpc"
"github.com/urfave/cli/v2"
)
var (
// EIP1976ImplementationSlot
EIP1967ImplementationSlot = common.HexToHash("0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc")
// EIP1967AdminSlot
EIP1967AdminSlot = common.HexToHash("0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103")
)
// clients represents a set of initialized RPC clients
type Clients struct {
L1Client *ethclient.Client
L2Client *ethclient.Client
L1RpcClient *rpc.Client
L2RpcClient *rpc.Client
L1GethClient *gethclient.Client
L2GethClient *gethclient.Client
}
// NewClients will create new RPC clients from a CLI context
func NewClients(ctx *cli.Context) (*Clients, error) {
clients := Clients{}
l1RpcURL := ctx.String("l1-rpc-url")
if l1RpcURL != "" {
l1Client, err := ethclient.Dial(l1RpcURL)
if err != nil {
return nil, fmt.Errorf("cannot dial L1: %w", err)
}
clients.L1Client = l1Client
l1RpcClient, err := rpc.DialContext(context.Background(), l1RpcURL)
if err != nil {
return nil, err
}
clients.L1RpcClient = l1RpcClient
clients.L1GethClient = gethclient.New(l1RpcClient)
}
l2RpcURL := ctx.String("l2-rpc-url")
if l2RpcURL != "" {
l2Client, err := ethclient.Dial(l2RpcURL)
if err != nil {
return nil, fmt.Errorf("cannot dial L2: %w", err)
}
clients.L2Client = l2Client
l2RpcClient, err := rpc.DialContext(context.Background(), l2RpcURL)
if err != nil {
return nil, err
}
clients.L2RpcClient = l2RpcClient
clients.L2GethClient = gethclient.New(l2RpcClient)
}
return &clients, nil
}
// ClientsFlags represent the flags associated with creating RPC clients.
var ClientsFlags = []cli.Flag{
&cli.StringFlag{
Name: "l1-rpc-url",
Required: true,
Usage: "L1 RPC URL",
EnvVars: []string{"L1_RPC_URL"},
},
&cli.StringFlag{
Name: "l2-rpc-url",
Required: true,
Usage: "L2 RPC URL",
EnvVars: []string{"L2_RPC_URL"},
},
}
// Addresses represents the address values of various contracts. The values can
// be easily populated via a [cli.Context].
type Addresses struct {
AddressManager common.Address
OptimismPortal common.Address
L1StandardBridge common.Address
L1CrossDomainMessenger common.Address
CanonicalTransactionChain common.Address
StateCommitmentChain common.Address
}
// AddressesFlags represent the flags associated with address parsing.
var AddressesFlags = []cli.Flag{
&cli.StringFlag{
Name: "address-manager-address",
Usage: "AddressManager address",
EnvVars: []string{"ADDRESS_MANAGER_ADDRESS"},
},
&cli.StringFlag{
Name: "optimism-portal-address",
Usage: "OptimismPortal address",
EnvVars: []string{"OPTIMISM_PORTAL_ADDRESS"},
},
&cli.StringFlag{
Name: "l1-standard-bridge-address",
Usage: "L1StandardBridge address",
EnvVars: []string{"L1_STANDARD_BRIDGE_ADDRESS"},
},
&cli.StringFlag{
Name: "l1-crossdomain-messenger-address",
Usage: "L1CrossDomainMessenger address",
EnvVars: []string{"L1_CROSSDOMAIN_MESSENGER_ADDRESS"},
},
&cli.StringFlag{
Name: "canonical-transaction-chain-address",
Usage: "CanonicalTransactionChain address",
EnvVars: []string{"CANONICAL_TRANSACTION_CHAIN_ADDRESS"},
},
&cli.StringFlag{
Name: "state-commitment-chain-address",
Usage: "StateCommitmentChain address",
EnvVars: []string{"STATE_COMMITMENT_CHAIN_ADDRESS"},
},
}
// NewAddresses populates an Addresses struct given a [cli.Context].
// This is useful for writing scripts that interact with smart contracts.
func NewAddresses(ctx *cli.Context) (*Addresses, error) {
var addresses Addresses
var err error
addresses.AddressManager, err = parseAddress(ctx, "address-manager-address")
if err != nil {
return nil, err
}
addresses.OptimismPortal, err = parseAddress(ctx, "optimism-portal-address")
if err != nil {
return nil, err
}
addresses.L1StandardBridge, err = parseAddress(ctx, "l1-standard-bridge-address")
if err != nil {
return nil, err
}
addresses.L1CrossDomainMessenger, err = parseAddress(ctx, "l1-crossdomain-messenger-address")
if err != nil {
return nil, err
}
addresses.CanonicalTransactionChain, err = parseAddress(ctx, "canonical-transaction-chain-address")
if err != nil {
return nil, err
}
addresses.StateCommitmentChain, err = parseAddress(ctx, "state-commitment-chain-address")
if err != nil {
return nil, err
}
return &addresses, nil
}
// parseAddress will parse a [common.Address] from a [cli.Context] and return
// an error if the configured address is not correct.
func parseAddress(ctx *cli.Context, name string) (common.Address, error) {
value := ctx.String(name)
if value == "" {
return common.Address{}, nil
}
if !common.IsHexAddress(value) {
return common.Address{}, fmt.Errorf("invalid address: %s", value)
}
return common.HexToAddress(value), nil
}
import assert from 'assert'
import { task, types } from 'hardhat/config'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import { Contract, providers, Wallet, Signer, BigNumber } from 'ethers'
import { predeploys } from '../src'
// expectedSemver is the semver version of the contracts
// deployed at bedrock deployment
const expectedSemver = '1.0.0'
const implSlot =
'0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc'
const adminSlot =
'0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103'
const prefix = '0x420000000000000000000000000000000000'
const logLoud = () => {
console.log(' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
}
const yell = (msg: string) => {
logLoud()
console.log(msg)
logLoud()
}
// checkPredeploys will ensure that all of the predeploys are set
const checkPredeploys = async (
hre: HardhatRuntimeEnvironment,
provider: providers.Provider
) => {
console.log('Checking predeploys are configured correctly')
const admin = hre.ethers.utils.hexConcat([
'0x000000000000000000000000',
predeploys.ProxyAdmin,
])
// We only check predeploys 0x420..00 through 0x420..FF on the mainnet network to
// reduce the probability of an RPC timeout. After the migration, all predeploys
// from 0x420..00 through 0x420..07FF should be checked.
const maxCheck = hre.network.name === 'mainnet' ? 256 : 2048
const codeReq = []
const slotReq = []
// First loop for requests
for (let i = 0; i < maxCheck; i++) {
const num = hre.ethers.utils.hexZeroPad('0x' + i.toString(16), 2)
const addr = hre.ethers.utils.getAddress(
hre.ethers.utils.hexConcat([prefix, num])
)
codeReq.push(provider.getCode(addr))
slotReq.push(provider.getStorageAt(addr, adminSlot))
}
// Wait for all requests to finish
// The `JsonRpcBatchProvider` will batch requests in the background.
const codeRes = await Promise.all(codeReq)
const slotRes = await Promise.all(slotReq)
// Second loop for response checks
for (let i = 0; i < maxCheck; i++) {
const num = hre.ethers.utils.hexZeroPad('0x' + i.toString(16), 2)
const addr = hre.ethers.utils.getAddress(
hre.ethers.utils.hexConcat([prefix, num])
)
if (codeRes[i] === '0x') {
throw new Error(`no code found at ${addr}`)
}
if (
addr === predeploys.GovernanceToken ||
addr === predeploys.ProxyAdmin ||
addr === predeploys.WETH9
) {
continue
}
if (slotRes[i] !== admin) {
throw new Error(`incorrect admin slot in ${addr}`)
}
if (i % (maxCheck / 4) === 0) {
console.log(`Checked through ${addr}`)
}
}
}
// assertSemver will ensure that the semver is the correct version
const assertSemver = async (
contract: Contract,
name: string,
override?: string
) => {
const version = await contract.version()
let target = expectedSemver
if (override) {
target = override
}
if (version !== target) {
throw new Error(
`${name}: version mismatch. Got ${version}, expected ${target}`
)
}
console.log(` - version: ${version}`)
}
// checkProxy will print out the proxy slots
const checkProxy = async (
_hre: HardhatRuntimeEnvironment,
name: string,
provider: providers.Provider
) => {
const address = predeploys[name]
if (!address) {
throw new Error(`unknown contract name: ${name}`)
}
const impl = await provider.getStorageAt(address, implSlot)
const admin = await provider.getStorageAt(address, adminSlot)
console.log(` - EIP-1967 implementation slot: ${impl}`)
console.log(` - EIP-1967 admin slot: ${admin}`)
}
// assertProxy will require the proxy is set
const assertProxy = async (
hre: HardhatRuntimeEnvironment,
name: string,
provider: providers.Provider
) => {
const address = predeploys[name]
if (!address) {
throw new Error(`unknown contract name: ${name}`)
}
const code = await provider.getCode(address)
const deployInfo = await hre.artifacts.readArtifact('Proxy')
if (code !== deployInfo.deployedBytecode) {
throw new Error(`${address}: code mismatch`)
}
const impl = await provider.getStorageAt(address, implSlot)
const implAddress = '0x' + impl.slice(26)
const implCode = await provider.getCode(implAddress)
if (implCode === '0x') {
throw new Error('No code at implementation')
}
}
// checks to make sure that the genesis magic value
// was set correctly
const checkGenesisMagic = async (
hre: HardhatRuntimeEnvironment,
l2Provider: providers.Provider,
args
) => {
const magic = '0x' + Buffer.from('BEDROCK').toString('hex')
let startingBlockNumber: number
// We have a connection to the L1 chain, fetch the remote value
if (args.l1RpcUrl !== '') {
const l1Provider = new hre.ethers.providers.StaticJsonRpcProvider(
args.l1RpcUrl
)
// Get the address if it was passed in via CLI
// Otherwise get the address from a hardhat deployment file
let address: string
if (args.l2OutputOracleAddress !== '') {
address = args.l2OutputOracleAddress
} else {
const Deployment__L2OutputOracle = await hre.deployments.get(
'L2OutputOracleProxy'
)
address = Deployment__L2OutputOracle.address
}
const abi = {
inputs: [],
name: 'startingBlockNumber',
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
stateMutability: 'view',
type: 'function',
}
const L2OutputOracle = new hre.ethers.Contract(address, [abi], l1Provider)
// In the migration, the L2OutputOracle proxy is not yet initialized when we
// want to run this script. Fall back on the local config if we get an error
// fetching the starting block number.
try {
startingBlockNumber = await L2OutputOracle.startingBlockNumber()
} catch (e) {
console.log(`Error fetching startingBlockNumber:\n${e.message}`)
console.log('Falling back to local config.')
startingBlockNumber = hre.deployConfig.l2OutputOracleStartingBlockNumber
}
} else {
// We do not have a connection to the L1 chain, use the local config
// The `--network` flag must be set to the L1 network
startingBlockNumber = hre.deployConfig.l2OutputOracleStartingBlockNumber
}
// ensure that the starting block number is a number
startingBlockNumber = BigNumber.from(startingBlockNumber).toNumber()
const block = await l2Provider.getBlock(startingBlockNumber)
const extradata = block.extraData
if (extradata !== magic) {
throw new Error(
`magic value in extradata does not match: got ${extradata}, expected ${magic}`
)
}
}
const check = {
// LegacyMessagePasser
// - check version
// - is behind a proxy
LegacyMessagePasser: async (
hre: HardhatRuntimeEnvironment,
signer: Signer
) => {
const LegacyMessagePasser = await hre.ethers.getContractAt(
'LegacyMessagePasser',
predeploys.LegacyMessagePasser,
signer
)
await assertSemver(LegacyMessagePasser, 'LegacyMessagePasser', '1.0.1')
await checkProxy(hre, 'LegacyMessagePasser', signer.provider)
await assertProxy(hre, 'LegacyMessagePasser', signer.provider)
},
// DeployerWhitelist
// - check version
// - is behind a proxy
// - owner is `address(0)`
DeployerWhitelist: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
const DeployerWhitelist = await hre.ethers.getContractAt(
'DeployerWhitelist',
predeploys.DeployerWhitelist,
signer
)
await assertSemver(DeployerWhitelist, 'DeployerWhitelist', '1.0.1')
const owner = await DeployerWhitelist.owner()
assert(owner === hre.ethers.constants.AddressZero)
console.log(` - owner: ${owner}`)
await checkProxy(hre, 'DeployerWhitelist', signer.provider)
await assertProxy(hre, 'DeployerWhitelist', signer.provider)
},
// L2CrossDomainMessenger
// - check version
// - check OTHER_MESSENGER
// - check l1CrossDomainMessenger (legacy)
// - is behind a proxy
// - check owner
// - check initialized
L2CrossDomainMessenger: async (
hre: HardhatRuntimeEnvironment,
signer: Signer
) => {
const L2CrossDomainMessenger = await hre.ethers.getContractAt(
'L2CrossDomainMessenger',
predeploys.L2CrossDomainMessenger,
signer
)
await assertSemver(
L2CrossDomainMessenger,
'L2CrossDomainMessenger',
'1.4.1'
)
const xDomainMessageSenderSlot = await signer.provider.getStorageAt(
predeploys.L2CrossDomainMessenger,
204
)
const xDomainMessageSender = '0x' + xDomainMessageSenderSlot.slice(26)
assert(
xDomainMessageSender === '0x000000000000000000000000000000000000dead'
)
const otherMessenger = await L2CrossDomainMessenger.OTHER_MESSENGER()
assert(otherMessenger !== hre.ethers.constants.AddressZero)
yell(` - OTHER_MESSENGER: ${otherMessenger}`)
const l1CrossDomainMessenger =
await L2CrossDomainMessenger.l1CrossDomainMessenger()
yell(` - l1CrossDomainMessenger: ${l1CrossDomainMessenger}`)
await checkProxy(hre, 'L2CrossDomainMessenger', signer.provider)
await assertProxy(hre, 'L2CrossDomainMessenger', signer.provider)
const MESSAGE_VERSION = await L2CrossDomainMessenger.MESSAGE_VERSION()
console.log(` - MESSAGE_VERSION: ${MESSAGE_VERSION}`)
const MIN_GAS_CALLDATA_OVERHEAD =
await L2CrossDomainMessenger.MIN_GAS_CALLDATA_OVERHEAD()
console.log(` - MIN_GAS_CALLDATA_OVERHEAD: ${MIN_GAS_CALLDATA_OVERHEAD}`)
const RELAY_CONSTANT_OVERHEAD =
await L2CrossDomainMessenger.RELAY_CONSTANT_OVERHEAD()
console.log(` - RELAY_CONSTANT_OVERHEAD: ${RELAY_CONSTANT_OVERHEAD}`)
const MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR =
await L2CrossDomainMessenger.MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR()
console.log(
` - MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR: ${MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR}`
)
const MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR =
await L2CrossDomainMessenger.MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR()
console.log(
` - MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR: ${MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR}`
)
const RELAY_CALL_OVERHEAD =
await L2CrossDomainMessenger.RELAY_CALL_OVERHEAD()
console.log(` - RELAY_CALL_OVERHEAD: ${RELAY_CALL_OVERHEAD}`)
const RELAY_RESERVED_GAS = await L2CrossDomainMessenger.RELAY_RESERVED_GAS()
console.log(` - RELAY_RESERVED_GAS: ${RELAY_RESERVED_GAS}`)
const RELAY_GAS_CHECK_BUFFER =
await L2CrossDomainMessenger.RELAY_GAS_CHECK_BUFFER()
console.log(` - RELAY_GAS_CHECK_BUFFER: ${RELAY_GAS_CHECK_BUFFER}`)
const slot = await signer.provider.getStorageAt(
predeploys.L2CrossDomainMessenger,
0
)
const spacer = '0x' + slot.slice(26)
console.log(` - legacy spacer: ${spacer}`)
const initialized = '0x' + slot.slice(24, 26)
assert(initialized === '0x01')
console.log(` - initialized: ${initialized}`)
},
// GasPriceOracle
// - check version
// - check decimals
GasPriceOracle: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
const GasPriceOracle = await hre.ethers.getContractAt(
'GasPriceOracle',
predeploys.GasPriceOracle,
signer
)
await assertSemver(GasPriceOracle, 'GasPriceOracle', '1.0.1')
const decimals = await GasPriceOracle.decimals()
assert(decimals.eq(6))
console.log(` - decimals: ${decimals.toNumber()}`)
await checkProxy(hre, 'GasPriceOracle', signer.provider)
await assertProxy(hre, 'GasPriceOracle', signer.provider)
},
// L2StandardBridge
// - check version
L2StandardBridge: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
const L2StandardBridge = await hre.ethers.getContractAt(
'L2StandardBridge',
predeploys.L2StandardBridge,
signer
)
await assertSemver(L2StandardBridge, 'L2StandardBridge', '1.1.1')
const OTHER_BRIDGE = await L2StandardBridge.OTHER_BRIDGE()
assert(OTHER_BRIDGE !== hre.ethers.constants.AddressZero)
yell(` - OTHER_BRIDGE: ${OTHER_BRIDGE}`)
const MESSENGER = await L2StandardBridge.MESSENGER()
assert(MESSENGER === predeploys.L2CrossDomainMessenger)
await checkProxy(hre, 'L2StandardBridge', signer.provider)
await assertProxy(hre, 'L2StandardBridge', signer.provider)
},
// SequencerFeeVault
// - check version
// - check RECIPIENT
// - check l1FeeWallet (legacy)
SequencerFeeVault: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
const SequencerFeeVault = await hre.ethers.getContractAt(
'SequencerFeeVault',
predeploys.SequencerFeeVault,
signer
)
await assertSemver(SequencerFeeVault, 'SequencerFeeVault', '1.2.1')
const RECIPIENT = await SequencerFeeVault.RECIPIENT()
assert(RECIPIENT !== hre.ethers.constants.AddressZero)
yell(` - RECIPIENT: ${RECIPIENT}`)
const l1FeeWallet = await SequencerFeeVault.l1FeeWallet()
assert(l1FeeWallet !== hre.ethers.constants.AddressZero)
console.log(` - l1FeeWallet: ${l1FeeWallet}`)
const MIN_WITHDRAWAL_AMOUNT =
await SequencerFeeVault.MIN_WITHDRAWAL_AMOUNT()
console.log(` - MIN_WITHDRAWAL_AMOUNT: ${MIN_WITHDRAWAL_AMOUNT}`)
const WITHDRAWAL_NETWORK = await SequencerFeeVault.WITHDRAWAL_NETWORK()
assert(WITHDRAWAL_NETWORK < 2)
console.log(` - WITHDRAWAL_NETWORK: ${WITHDRAWAL_NETWORK}`)
await checkProxy(hre, 'SequencerFeeVault', signer.provider)
await assertProxy(hre, 'SequencerFeeVault', signer.provider)
},
// OptimismMintableERC20Factory
// - check version
OptimismMintableERC20Factory: async (
hre: HardhatRuntimeEnvironment,
signer: Signer
) => {
const OptimismMintableERC20Factory = await hre.ethers.getContractAt(
'OptimismMintableERC20Factory',
predeploys.OptimismMintableERC20Factory,
signer
)
await assertSemver(
OptimismMintableERC20Factory,
'OptimismMintableERC20Factory',
'1.1.1'
)
const BRIDGE = await OptimismMintableERC20Factory.BRIDGE()
assert(BRIDGE !== hre.ethers.constants.AddressZero)
await checkProxy(hre, 'OptimismMintableERC20Factory', signer.provider)
await assertProxy(hre, 'OptimismMintableERC20Factory', signer.provider)
},
// L1BlockNumber
// - check version
L1BlockNumber: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
const L1BlockNumber = await hre.ethers.getContractAt(
'L1BlockNumber',
predeploys.L1BlockNumber,
signer
)
await assertSemver(L1BlockNumber, 'L1BlockNumber', '1.0.1')
await checkProxy(hre, 'L1BlockNumber', signer.provider)
await assertProxy(hre, 'L1BlockNumber', signer.provider)
},
// L1Block
// - check version
L1Block: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
const L1Block = await hre.ethers.getContractAt(
'L1Block',
predeploys.L1Block,
signer
)
await assertSemver(L1Block, 'L1Block', '1.0.1')
await checkProxy(hre, 'L1Block', signer.provider)
await assertProxy(hre, 'L1Block', signer.provider)
},
// WETH9
// - check name
// - check symbol
// - check decimals
WETH9: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
const WETH9 = await hre.ethers.getContractAt(
'WETH9',
predeploys.WETH9,
signer
)
const name = await WETH9.name()
assert(name === 'Wrapped Ether')
console.log(` - name: ${name}`)
const symbol = await WETH9.symbol()
assert(symbol === 'WETH')
console.log(` - symbol: ${symbol}`)
const decimals = await WETH9.decimals()
assert(decimals === 18)
console.log(` - decimals: ${decimals}`)
},
// GovernanceToken
// - not behind a proxy
// - check name
// - check symbol
// - check owner
GovernanceToken: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
const GovernanceToken = await hre.ethers.getContractAt(
'GovernanceToken',
predeploys.GovernanceToken,
signer
)
const name = await GovernanceToken.name()
assert(name === 'Optimism')
console.log(` - name: ${name}`)
const symbol = await GovernanceToken.symbol()
assert(symbol === 'OP')
console.log(` - symbol: ${symbol}`)
const owner = await GovernanceToken.owner()
yell(` - owner: ${owner}`)
const totalSupply = await GovernanceToken.totalSupply()
console.log(` - totalSupply: ${totalSupply}`)
await checkProxy(hre, 'GovernanceToken', signer.provider)
// No proxy at this address, don't call assertProxy
},
// L2ERC721Bridge
// - check version
L2ERC721Bridge: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
const L2ERC721Bridge = await hre.ethers.getContractAt(
'L2ERC721Bridge',
predeploys.L2ERC721Bridge,
signer
)
await assertSemver(L2ERC721Bridge, 'L2ERC721Bridge', '1.1.1')
const MESSENGER = await L2ERC721Bridge.MESSENGER()
assert(MESSENGER !== hre.ethers.constants.AddressZero)
console.log(` - MESSENGER: ${MESSENGER}`)
const OTHER_BRIDGE = await L2ERC721Bridge.OTHER_BRIDGE()
assert(OTHER_BRIDGE !== hre.ethers.constants.AddressZero)
yell(` - OTHER_BRIDGE: ${OTHER_BRIDGE}`)
await checkProxy(hre, 'L2ERC721Bridge', signer.provider)
await assertProxy(hre, 'L2ERC721Bridge', signer.provider)
},
// OptimismMintableERC721Factory
// - check version
OptimismMintableERC721Factory: async (
hre: HardhatRuntimeEnvironment,
signer: Signer
) => {
const OptimismMintableERC721Factory = await hre.ethers.getContractAt(
'OptimismMintableERC721Factory',
predeploys.OptimismMintableERC721Factory,
signer
)
await assertSemver(
OptimismMintableERC721Factory,
'OptimismMintableERC721Factory',
'1.2.1'
)
const BRIDGE = await OptimismMintableERC721Factory.BRIDGE()
assert(BRIDGE !== hre.ethers.constants.AddressZero)
console.log(` - BRIDGE: ${BRIDGE}`)
const REMOTE_CHAIN_ID =
await OptimismMintableERC721Factory.REMOTE_CHAIN_ID()
assert(REMOTE_CHAIN_ID !== 0)
console.log(` - REMOTE_CHAIN_ID: ${REMOTE_CHAIN_ID}`)
await checkProxy(hre, 'OptimismMintableERC721Factory', signer.provider)
await assertProxy(hre, 'OptimismMintableERC721Factory', signer.provider)
},
// ProxyAdmin
// - check owner
ProxyAdmin: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
const ProxyAdmin = await hre.ethers.getContractAt(
'ProxyAdmin',
predeploys.ProxyAdmin,
signer
)
const owner = await ProxyAdmin.owner()
assert(owner !== hre.ethers.constants.AddressZero)
yell(` - owner: ${owner}`)
const addressManager = await ProxyAdmin.addressManager()
console.log(` - addressManager: ${addressManager}`)
await checkProxy(hre, 'ProxyAdmin', signer.provider)
await assertProxy(hre, 'ProxyAdmin', signer.provider)
},
// BaseFeeVault
// - check version
// - check MIN_WITHDRAWAL_AMOUNT
// - check RECIPIENT
BaseFeeVault: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
const BaseFeeVault = await hre.ethers.getContractAt(
'BaseFeeVault',
predeploys.BaseFeeVault,
signer
)
await assertSemver(BaseFeeVault, 'BaseFeeVault', '1.2.1')
const MIN_WITHDRAWAL_AMOUNT = await BaseFeeVault.MIN_WITHDRAWAL_AMOUNT()
console.log(` - MIN_WITHDRAWAL_AMOUNT: ${MIN_WITHDRAWAL_AMOUNT}`)
const RECIPIENT = await BaseFeeVault.RECIPIENT()
assert(RECIPIENT !== hre.ethers.constants.AddressZero)
yell(` - RECIPIENT: ${RECIPIENT}`)
const WITHDRAWAL_NETWORK = await BaseFeeVault.WITHDRAWAL_NETWORK()
assert(WITHDRAWAL_NETWORK < 2)
console.log(` - WITHDRAWAL_NETWORK: ${WITHDRAWAL_NETWORK}`)
await checkProxy(hre, 'BaseFeeVault', signer.provider)
await assertProxy(hre, 'BaseFeeVault', signer.provider)
},
// L1FeeVault
// - check version
// - check MIN_WITHDRAWAL_AMOUNT
// - check RECIPIENT
L1FeeVault: async (hre: HardhatRuntimeEnvironment, signer: Signer) => {
const L1FeeVault = await hre.ethers.getContractAt(
'L1FeeVault',
predeploys.L1FeeVault,
signer
)
await assertSemver(L1FeeVault, 'L1FeeVault', '1.2.1')
const MIN_WITHDRAWAL_AMOUNT = await L1FeeVault.MIN_WITHDRAWAL_AMOUNT()
console.log(` - MIN_WITHDRAWAL_AMOUNT: ${MIN_WITHDRAWAL_AMOUNT}`)
const RECIPIENT = await L1FeeVault.RECIPIENT()
assert(RECIPIENT !== hre.ethers.constants.AddressZero)
yell(` - RECIPIENT: ${RECIPIENT}`)
const WITHDRAWAL_NETWORK = await L1FeeVault.WITHDRAWAL_NETWORK()
assert(WITHDRAWAL_NETWORK < 2)
console.log(` - WITHDRAWAL_NETWORK: ${WITHDRAWAL_NETWORK}`)
await checkProxy(hre, 'L1FeeVault', signer.provider)
await assertProxy(hre, 'L1FeeVault', signer.provider)
},
// L2ToL1MessagePasser
// - check version
L2ToL1MessagePasser: async (
hre: HardhatRuntimeEnvironment,
signer: Signer
) => {
const L2ToL1MessagePasser = await hre.ethers.getContractAt(
'L2ToL1MessagePasser',
predeploys.L2ToL1MessagePasser,
signer
)
await assertSemver(L2ToL1MessagePasser, 'L2ToL1MessagePasser', '1.0.1')
const MESSAGE_VERSION = await L2ToL1MessagePasser.MESSAGE_VERSION()
console.log(` - MESSAGE_VERSION: ${MESSAGE_VERSION}`)
const messageNonce = await L2ToL1MessagePasser.messageNonce()
console.log(` - messageNonce: ${messageNonce}`)
await checkProxy(hre, 'L2ToL1MessagePasser', signer.provider)
await assertProxy(hre, 'L2ToL1MessagePasser', signer.provider)
},
}
task('check-l2', 'Checks a freshly migrated L2 system for correct migration')
.addOptionalParam('l1RpcUrl', 'L1 RPC URL of node', '', types.string)
.addOptionalParam('l2RpcUrl', 'L2 RPC URL of node', '', types.string)
.addOptionalParam('chainId', 'Expected chain id', 0, types.int)
.addOptionalParam(
'l2OutputOracleAddress',
'Address of the L2OutputOracle oracle',
'',
types.string
)
.addOptionalParam(
'skipPredeployCheck',
'Skip long check',
false,
types.boolean
)
.setAction(async (args, hre: HardhatRuntimeEnvironment) => {
yell('Manually check values wrapped in !!!!')
console.log()
let signer: Signer = hre.ethers.provider.getSigner()
if (args.l2RpcUrl !== '') {
console.log('Using CLI URL for provider instead of hardhat network')
const provider = new hre.ethers.providers.JsonRpcBatchProvider(
args.l2RpcUrl
)
signer = Wallet.createRandom().connect(provider)
}
if (args.chainId !== 0) {
const chainId = await signer.getChainId()
if (chainId !== args.chainId) {
throw new Error(
`Unexpected Chain ID. Got ${chainId}, expected ${args.chainId}`
)
}
console.log(`Verified Chain ID: ${chainId}`)
} else {
console.log(`Skipping Chain ID validation...`)
}
// Ensure that all the predeploys exist, including the not
// currently configured ones
if (!args.skipPredeployCheck) {
await checkPredeploys(hre, signer.provider)
}
await checkGenesisMagic(hre, signer.provider, args)
console.log()
// Check the currently configured predeploys
for (const [name, fn] of Object.entries(check)) {
const address = predeploys[name]
console.log(`${name}: ${address}`)
await fn(hre, signer)
}
})
import './solidity'
import './check-l2'
import './generate-deploy-config'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment