Commit caf63ce1 authored by Sam Stokes's avatar Sam Stokes Committed by GitHub

op-deployer: add 'inspect superchain-registry' subcommand (#12736)

* op-deployer: add 'inspect superchain-registry' subcommand

* op-deployer: generate artifacts at runtime of superchain-registry cmd

* op-deployer: add missing err handler

* op-deployer: add Printf to prompt user to populate .env vals

* op-deployer: reformat addresses to superchain.AddressList
parent 72c11daa
......@@ -3,10 +3,12 @@ package inspect
import (
"fmt"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/pipeline"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state"
"github.com/ethereum-optimism/optimism/op-service/ioutil"
"github.com/ethereum-optimism/optimism/op-service/jsonutil"
"github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v2"
)
......@@ -18,29 +20,40 @@ func DeployConfigCLI(cliCtx *cli.Context) error {
globalState, err := pipeline.ReadState(cliCfg.Workdir)
if err != nil {
return fmt.Errorf("failed to read intent: %w", err)
return fmt.Errorf("failed to read globalState: %w", err)
}
chainState, err := globalState.Chain(cliCfg.ChainID)
config, err := DeployConfig(globalState, cliCfg.ChainID)
if err != nil {
return fmt.Errorf("failed to find chain state: %w", err)
return fmt.Errorf("failed to generate deploy config: %w", err)
}
if err := jsonutil.WriteJSON(config, ioutil.ToStdOutOrFileOrNoop(cliCfg.Outfile, 0o666)); err != nil {
return fmt.Errorf("failed to write deploy config: %w", err)
}
return nil
}
func DeployConfig(globalState *state.State, chainID common.Hash) (*genesis.DeployConfig, error) {
chainState, err := globalState.Chain(chainID)
if err != nil {
return nil, fmt.Errorf("failed to find chain state: %w", err)
}
intent := globalState.AppliedIntent
if intent == nil {
return fmt.Errorf("can only run this command following a full apply")
return nil, fmt.Errorf("can only run this command following a full apply")
}
chainIntent, err := intent.Chain(cliCfg.ChainID)
chainIntent, err := intent.Chain(chainID)
if err != nil {
return fmt.Errorf("failed to find chain intent: %w", err)
return nil, fmt.Errorf("failed to find chain intent: %w", err)
}
config, err := state.CombineDeployConfig(intent, chainIntent, globalState, chainState)
if err != nil {
return fmt.Errorf("failed to generate deploy config: %w", err)
}
if err := jsonutil.WriteJSON(config, ioutil.ToStdOutOrFileOrNoop(cliCfg.Outfile, 0o666)); err != nil {
return fmt.Errorf("failed to write deploy config: %w", err)
return nil, fmt.Errorf("failed to generate deploy config: %w", err)
}
return nil
return &config, nil
}
......@@ -69,6 +69,14 @@ var Commands = []*cli.Command{
Action: L2SemversCLI,
Flags: Flags,
},
{
Name: "superchain-registry",
Usage: "outputs the .env file expected by superchain-registry add-chain tool",
Args: true,
ArgsUsage: "<l2-chain-id>",
Action: SuperchainRegistryCLI,
Flags: Flags,
},
}
type cliConfig struct {
......
......@@ -4,6 +4,7 @@ import (
"fmt"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/pipeline"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state"
"github.com/ethereum-optimism/optimism/op-service/ioutil"
"github.com/ethereum-optimism/optimism/op-service/jsonutil"
......@@ -37,9 +38,9 @@ type OpChainDeployment struct {
DisputeGameFactoryProxyAddress common.Address `json:"disputeGameFactoryProxyAddress"`
AnchorStateRegistryProxyAddress common.Address `json:"anchorStateRegistryProxyAddress"`
AnchorStateRegistryImplAddress common.Address `json:"anchorStateRegistryImplAddress"`
// FaultDisputeGameAddress common.Address `json:"faultDisputeGameAddress"`
PermissionedDisputeGameAddress common.Address `json:"permissionedDisputeGameAddress"`
DelayedWETHPermissionedGameProxyAddress common.Address `json:"delayedWETHPermissionedGameProxyAddress"`
FaultDisputeGameAddress common.Address `json:"faultDisputeGameAddress"`
PermissionedDisputeGameAddress common.Address `json:"permissionedDisputeGameAddress"`
DelayedWETHPermissionedGameProxyAddress common.Address `json:"delayedWETHPermissionedGameProxyAddress"`
// DelayedWETHPermissionlessGameProxyAddress common.Address `json:"delayedWETHPermissionlessGameProxyAddress"`
}
......@@ -68,9 +69,22 @@ func L1CLI(cliCtx *cli.Context) error {
return fmt.Errorf("failed to read intent: %w", err)
}
chainState, err := globalState.Chain(cfg.ChainID)
l1Contracts, err := L1(globalState, cfg.ChainID)
if err != nil {
return fmt.Errorf("failed to get chain state for ID %s: %w", cfg.ChainID.String(), err)
return fmt.Errorf("failed to generate l1Contracts: %w", err)
}
if err := jsonutil.WriteJSON(l1Contracts, ioutil.ToStdOutOrFileOrNoop(cfg.Outfile, 0o666)); err != nil {
return fmt.Errorf("failed to write L1 contract addresses: %w", err)
}
return nil
}
func L1(globalState *state.State, chainID common.Hash) (*L1Contracts, error) {
chainState, err := globalState.Chain(chainID)
if err != nil {
return nil, fmt.Errorf("failed to get chain state for ID %s: %w", chainID.String(), err)
}
l1Contracts := L1Contracts{
......@@ -93,9 +107,9 @@ func L1CLI(cliCtx *cli.Context) error {
DisputeGameFactoryProxyAddress: chainState.DisputeGameFactoryProxyAddress,
AnchorStateRegistryProxyAddress: chainState.AnchorStateRegistryProxyAddress,
AnchorStateRegistryImplAddress: chainState.AnchorStateRegistryImplAddress,
// FaultDisputeGameAddress: chainState.FaultDisputeGameAddress,
PermissionedDisputeGameAddress: chainState.PermissionedDisputeGameAddress,
DelayedWETHPermissionedGameProxyAddress: chainState.DelayedWETHPermissionedGameProxyAddress,
FaultDisputeGameAddress: chainState.FaultDisputeGameAddress,
PermissionedDisputeGameAddress: chainState.PermissionedDisputeGameAddress,
DelayedWETHPermissionedGameProxyAddress: chainState.DelayedWETHPermissionedGameProxyAddress,
// DelayedWETHPermissionlessGameProxyAddress: chainState.DelayedWETHPermissionlessGameProxyAddress,
},
ImplementationsDeployment: ImplementationsDeployment{
......@@ -113,9 +127,5 @@ func L1CLI(cliCtx *cli.Context) error {
},
}
if err := jsonutil.WriteJSON(l1Contracts, ioutil.ToStdOutOrFileOrNoop(cfg.Outfile, 0o666)); err != nil {
return fmt.Errorf("failed to write L1 contract addresses: %w", err)
}
return nil
return &l1Contracts, nil
}
package inspect
import (
"fmt"
"os"
"path/filepath"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/pipeline"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/standard"
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/state"
"github.com/ethereum-optimism/optimism/op-service/ioutil"
"github.com/ethereum-optimism/optimism/op-service/jsonutil"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/superchain-registry/superchain"
"github.com/urfave/cli/v2"
)
func SuperchainRegistryCLI(cliCtx *cli.Context) error {
cfg, err := readConfig(cliCtx)
if err != nil {
return err
}
globalIntent, err := pipeline.ReadIntent(cfg.Workdir)
if err != nil {
return fmt.Errorf("failed to read intent: %w", err)
}
envVars := map[string]string{}
envVars["SCR_CHAIN_NAME"] = ""
envVars["SCR_CHAIN_SHORT_NAME"] = ""
envVars["SCR_PUBLIC_RPC"] = ""
envVars["SCR_SEQUENCER_RPC"] = ""
envVars["SCR_EXPLORER"] = ""
envVars["SCR_STANDARD_CHAIN_CANDIDATE"] = "false"
creationCommit, err := standard.CommitForDeployTag(globalIntent.L2ContractsLocator.Tag)
if err != nil {
return fmt.Errorf("failed to get commit for deploy tag: %w", err)
}
envVars["SCR_GENESIS_CREATION_COMMIT"] = creationCommit
l1ChainName, err := standard.ChainNameFor(globalIntent.L1ChainID)
if err != nil {
return fmt.Errorf("failed to get l1 chain name: %w", err)
}
envVars["SCR_SUPERCHAIN_TARGET"] = l1ChainName
globalState, err := pipeline.ReadState(cfg.Workdir)
if err != nil {
return fmt.Errorf("failed to read state: %w", err)
}
genesis, rollup, err := GenesisAndRollup(globalState, cfg.ChainID)
if err != nil {
return fmt.Errorf("failed to generate genesis and rollup: %w", err)
}
genesisFilepath := filepath.Join(cfg.Workdir, "genesis.json")
if err := jsonutil.WriteJSON(genesis, ioutil.ToStdOutOrFileOrNoop(genesisFilepath, 0o666)); err != nil {
return fmt.Errorf("failed to write genesis: %w", err)
}
rollupFilepath := filepath.Join(cfg.Workdir, "rollup.json")
if err := jsonutil.WriteJSON(rollup, ioutil.ToStdOutOrFileOrNoop(rollupFilepath, 0o666)); err != nil {
return fmt.Errorf("failed to write rollup: %w", err)
}
deployConfig, err := DeployConfig(globalState, cfg.ChainID)
if err != nil {
return fmt.Errorf("failed to generate deploy config: %w", err)
}
deployConfigFilepath := filepath.Join(cfg.Workdir, "deploy-config.json")
if err := jsonutil.WriteJSON(deployConfig, ioutil.ToStdOutOrFileOrNoop(deployConfigFilepath, 0o666)); err != nil {
return fmt.Errorf("failed to write rollup: %w", err)
}
l1Contracts, err := L1(globalState, cfg.ChainID)
if err != nil {
return fmt.Errorf("failed to generate l1 contracts: %w", err)
}
addressList, err := createAddressList(l1Contracts, globalState.AppliedIntent, cfg.ChainID)
if err != nil {
return fmt.Errorf("failed to create address list: %w", err)
}
addressListFilepath := filepath.Join(cfg.Workdir, "addresses.json")
if err := jsonutil.WriteJSON(addressList, ioutil.ToStdOutOrFileOrNoop(addressListFilepath, 0o666)); err != nil {
return fmt.Errorf("failed to write address list: %w", err)
}
envVars["SCR_GENESIS"] = genesisFilepath
envVars["SCR_ROLLUP_CONFIG"] = rollupFilepath
envVars["SCR_DEPLOY_CONFIG"] = deployConfigFilepath
envVars["SCR_DEPLOYMENTS_DIR"] = addressListFilepath
envFilepath := filepath.Join(cfg.Workdir, "superchain-registry.env")
err = writeEnvFile(envFilepath, envVars)
if err != nil {
return fmt.Errorf("failed to write .env file: %w", err)
}
fmt.Printf("---------------------------------------------------\n"+
"Please populate any empty values in your .env file\n"+
"before creating your pull-request to add this chain\n"+
"to the superchain-registry repo.\n\n"+
" * %s\n"+
"---------------------------------------------------\n", envFilepath,
)
return nil
}
func writeEnvFile(filepath string, envVars map[string]string) error {
file, err := os.Create(filepath)
if err != nil {
return err
}
defer file.Close()
for key, value := range envVars {
_, err := file.WriteString(fmt.Sprintf("%s=\"%s\"\n", key, value))
if err != nil {
return err
}
}
return nil
}
func createAddressList(l1Contracts *L1Contracts, appliedIntent *state.Intent, chainId common.Hash) (*superchain.AddressList, error) {
chainIntent, err := appliedIntent.Chain(chainId)
if err != nil {
return nil, fmt.Errorf("failed to get applied chain intent: %w", err)
}
addressList := superchain.AddressList{
// Roles
Roles: superchain.Roles{
Guardian: superchain.Address(appliedIntent.SuperchainRoles.Guardian),
SystemConfigOwner: superchain.Address(chainIntent.Roles.SystemConfigOwner),
ProxyAdminOwner: superchain.Address(chainIntent.Roles.L1ProxyAdminOwner),
Challenger: superchain.Address(chainIntent.Roles.Challenger),
Proposer: superchain.Address(chainIntent.Roles.Proposer),
UnsafeBlockSigner: superchain.Address(chainIntent.Roles.UnsafeBlockSigner),
BatchSubmitter: superchain.Address(chainIntent.Roles.Batcher),
},
// Contracts
AddressManager: superchain.Address(l1Contracts.OpChainDeployment.AddressManagerAddress),
L1CrossDomainMessengerProxy: superchain.Address(l1Contracts.OpChainDeployment.L1CrossDomainMessengerProxyAddress),
L1ERC721BridgeProxy: superchain.Address(l1Contracts.OpChainDeployment.L1ERC721BridgeProxyAddress),
L1StandardBridgeProxy: superchain.Address(l1Contracts.OpChainDeployment.L1StandardBridgeProxyAddress),
OptimismMintableERC20FactoryProxy: superchain.Address(l1Contracts.OpChainDeployment.OptimismMintableERC20FactoryProxyAddress),
OptimismPortalProxy: superchain.Address(l1Contracts.OpChainDeployment.OptimismPortalProxyAddress),
SystemConfigProxy: superchain.Address(l1Contracts.OpChainDeployment.SystemConfigProxyAddress),
ProxyAdmin: superchain.Address(l1Contracts.OpChainDeployment.ProxyAdminAddress),
SuperchainConfig: superchain.Address(l1Contracts.SuperchainDeployment.SuperchainConfigProxyAddress),
// Fault proof contracts
AnchorStateRegistryProxy: superchain.Address(l1Contracts.OpChainDeployment.AnchorStateRegistryProxyAddress),
DelayedWETHProxy: superchain.Address(l1Contracts.OpChainDeployment.L1CrossDomainMessengerProxyAddress),
DisputeGameFactoryProxy: superchain.Address(l1Contracts.OpChainDeployment.DisputeGameFactoryProxyAddress),
FaultDisputeGame: superchain.Address(l1Contracts.OpChainDeployment.FaultDisputeGameAddress),
MIPS: superchain.Address(l1Contracts.ImplementationsDeployment.MipsSingletonAddress),
PermissionedDisputeGame: superchain.Address(l1Contracts.OpChainDeployment.PermissionedDisputeGameAddress),
PreimageOracle: superchain.Address(l1Contracts.ImplementationsDeployment.PreimageOracleSingletonAddress),
}
return &addressList, nil
}
......@@ -105,6 +105,28 @@ func SuperchainFor(chainID uint64) (*superchain.Superchain, error) {
}
}
func ChainNameFor(chainID uint64) (string, error) {
switch chainID {
case 1:
return "mainnet", nil
case 11155111:
return "sepolia", nil
default:
return "", fmt.Errorf("unrecognized chain ID: %d", chainID)
}
}
func CommitForDeployTag(tag string) (string, error) {
switch tag {
case "op-contracts/v1.6.0":
return "33f06d2d5e4034125df02264a5ffe84571bd0359", nil
case "op-contracts/v1.7.0-beta.1+l2-contracts":
return "5e14a61547a45eef2ebeba677aee4a049f106ed8", nil
default:
return "", fmt.Errorf("unsupported tag: %s", tag)
}
}
func ManagerImplementationAddrFor(chainID uint64) (common.Address, error) {
switch chainID {
case 1:
......
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