Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
70abccf
Convert add-chain.sh into a go package
bitwiseguy Apr 23, 2024
0b4d631
Create go module
bitwiseguy Apr 24, 2024
4de3faa
Fixes to produce correct output files from addchain module
bitwiseguy Apr 24, 2024
22b4748
Rename go module addchain to add-chain
bitwiseguy Apr 24, 2024
1b1acea
Remove duplicate invocation of registry-data go program
bitwiseguy Apr 24, 2024
9afdef3
Add conditional when searching for contract addrs from file
bitwiseguy Apr 24, 2024
4969abd
Add e2e test for add-chain go module
bitwiseguy Apr 24, 2024
9c04805
Finish removing add-chain go test dep on monorepo
bitwiseguy Apr 25, 2024
175f5ae
Rename add-chain test files to expected.[json|yam]l
bitwiseguy Apr 25, 2024
af89ef1
Merge branch 'main' into ss/addchain-go
bitwiseguy Apr 25, 2024
7205dbe
Retrieve L1 url from superchain package instead of hardcoding
bitwiseguy Apr 26, 2024
1b2967a
Use consistent go 1.21 version in all go.mod files
bitwiseguy Apr 26, 2024
61ea05f
Read contract addresses from .deploy file within add-chain
bitwiseguy Apr 26, 2024
cb6864a
Move add-chain/.env.test into testdata dir
bitwiseguy Apr 26, 2024
9b4f82e
Merge branch 'main' into ss/addchain-go
bitwiseguy Apr 26, 2024
2fd6532
Refactor 'cast call' commands to reduce duplicate code
bitwiseguy Apr 26, 2024
ccd2fdd
Fix call to OptimismPortalProxy.guardian() - instead of calling GUARD…
bitwiseguy Apr 26, 2024
c331023
Removed unused genesis.json file from add-chain/testdata dir
bitwiseguy Apr 26, 2024
7013cd3
Use custom yaml encoder to add whitespace
bitwiseguy Apr 26, 2024
bcdfb7c
Compare config raw bytes instead of structs in e2e test
bitwiseguy Apr 26, 2024
c5c6afe
Add human readable timestamp as comments in yaml file
bitwiseguy Apr 27, 2024
dda8220
Remove hardfork timestamp overrides if they match superchain defaults
bitwiseguy Apr 28, 2024
9446436
Move enhanceYAML to a method of RollupConfig
bitwiseguy Apr 28, 2024
354b976
Add godoc comments to a few functions
bitwiseguy Apr 29, 2024
80fad15
improve cast call error handling (#215)
geoknee Apr 29, 2024
7f55ffa
Merge branch 'main' into ss/addchain-go
bitwiseguy Apr 29, 2024
50b1c85
Address PR comments
bitwiseguy May 2, 2024
bb991a1
Run gofumpt and golangci-lint
bitwiseguy May 2, 2024
ef4fb1d
Install foundry in Circle CI for cast call in tests
bitwiseguy May 2, 2024
1a26e4c
Fix timestamp to use consistent UTC+0 timezone
bitwiseguy May 2, 2024
6b8483f
Set Circle CI shell type to bash
bitwiseguy May 2, 2024
019fe31
Move shell type to job level in Circle CI
bitwiseguy May 2, 2024
5f09d55
Merge branch 'main' into ss/addchain-go
bitwiseguy May 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
tag: '1.21'
steps:
- checkout
- run: golangci-lint run superchain/... validation/...
- run: golangci-lint run superchain/... validation/... add-chain/...
golang-modules-tidy:
executor:
name: go/default # is based on cimg/go
Expand All @@ -39,15 +39,36 @@ jobs:
name: tidy validation module
command: go mod tidy
working_directory: validation
- run:
name: tidy add-chain module
command: go mod tidy
working_directory: add-chain
- run:
name: check git tree is clean
command: git diff --exit-code
golang-test:
shell: /bin/bash -eo pipefail
executor:
name: go/default # is based on cimg/go
tag: '1.21'
steps:
- checkout
- run:
# need foundry to execute 'cast call' within add-chain script
name: Install foundry
command: |
echo "SHELL=$SHELL"
# Set up directory structure
mkdir -p $HOME/.foundry/bin
echo 'export PATH="$HOME/.foundry/bin:$PATH"' >> $BASH_ENV
source $BASH_ENV

# Download foundryup and make it executable
curl -sSL "https://raw.githubusercontent.com/foundry-rs/foundry/master/foundryup/foundryup" -o $HOME/.foundry/bin/foundryup
chmod +x $HOME/.foundry/bin/foundryup

$HOME/.foundry/bin/foundryup
forge --version
- run:
name: run superchain module tests
command: go test ./... -v
Expand All @@ -56,6 +77,10 @@ jobs:
name: run validation module tests
command: go test ./... -v
working_directory: validation
- run:
name: run add-chain module tests
command: go test ./... -v
working_directory: add-chain
- notify-failures-on-main
publish-bot:
environment:
Expand Down Expand Up @@ -101,7 +126,7 @@ jobs:
- run:
name: check security configs
command: sh ./scripts/check-security-configs.sh
- notify-failures-on-main
- notify-failures-on-main

workflows:
hourly:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ docs/
.env
.env*
!.env.example
!.env.test
*.log


Expand Down
2 changes: 2 additions & 0 deletions add-chain/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# test output artifacts
testdata/**/awesomechain*
Comment thread
bitwiseguy marked this conversation as resolved.
121 changes: 121 additions & 0 deletions add-chain/chain_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package main

import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"time"

"github.com/ethereum-optimism/superchain-registry/superchain"
"gopkg.in/yaml.v3"
)

// constructRollupConfig creates and populates a ChainConfig struct by reading from an input file and
// explicitly setting some additional fields to input argument values
func constructRollupConfig(inputFilePath, chainName, publicRPC, sequencerRPC, explorer string, superchainLevel superchain.SuperchainLevel) (superchain.ChainConfig, error) {
fmt.Printf("Attempting to read from %s\n", inputFilePath)
file, err := os.ReadFile(inputFilePath)
if err != nil {
return superchain.ChainConfig{}, fmt.Errorf("error reading file: %w", err)
}
var config superchain.ChainConfig
if err = json.Unmarshal(file, &config); err != nil {
return superchain.ChainConfig{}, fmt.Errorf("error unmarshaling json: %w", err)
}

config.Name = chainName
config.PublicRPC = publicRPC
config.SequencerRPC = sequencerRPC
config.SuperchainLevel = superchainLevel
config.Explorer = explorer

fmt.Printf("Rollup config successfully constructed\n")
return config, nil
}

// writeChainConfig accepts a rollupConfig, formats it, and writes some output files based on the given
// target directories
func writeChainConfig(
rollupConfig superchain.ChainConfig,
targetDirectory string,
superchainRepoPath string,
superchainTarget string,
) error {
// Create genesis-system-config data
// (this is deprecated, users should load this from L1, when available via SystemConfig)
dirPath := filepath.Join(superchainRepoPath, "superchain", "extra", "genesis-system-configs", superchainTarget)

if err := os.MkdirAll(dirPath, 0o755); err != nil {
return fmt.Errorf("failed to create directory: %w", err)
}

systemConfigJSON, err := json.MarshalIndent(rollupConfig.Genesis.SystemConfig, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal genesis system config json: %w", err)
}

// Write the genesis system config JSON to a new file
filePath := filepath.Join(dirPath, rollupConfig.Name+".json")
if err := os.WriteFile(filePath, systemConfigJSON, 0o644); err != nil {
return fmt.Errorf("failed to write genesis system config json: %w", err)
}
fmt.Printf("Genesis system config written to: %s\n", filePath)

rollupConfig.Genesis.SystemConfig = superchain.SystemConfig{} // remove SystemConfig so its omitted from yaml

// Remove hardfork timestamp override fields if they match superchain defaults
defaults := superchain.Superchains[superchainTarget]
rollupConfig.SetDefaultHardforkTimestampsToNil(&defaults.Config)

yamlData, err := yaml.Marshal(rollupConfig)
if err != nil {
return fmt.Errorf("failed to marshal yaml: %w", err)
}

// Unmarshal bytes into a yaml.Node for custom manipulation
var rootNode yaml.Node
if err = yaml.Unmarshal(yamlData, &rootNode); err != nil {
return err
}

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err = rollupConfig.EnhanceYAML(ctx, &rootNode); err != nil {
return err
}

// Write the rollup config to a yaml file
filename := filepath.Join(targetDirectory)
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()

encoder := yaml.NewEncoder(file)
defer encoder.Close()

encoder.SetIndent(2)
if err := encoder.Encode(&rootNode); err != nil {
return fmt.Errorf("failed to write yaml file: %w", err)
}

fmt.Printf("Rollup config written to: %s\n", filename)
return nil
}

func getL1RpcUrl(superchainTarget string) (string, error) {
superChain, ok := superchain.Superchains[superchainTarget]
if !ok {
return "", fmt.Errorf("unknown superchain target provided: %s", superchainTarget)
}

if superChain.Config.L1.PublicRPC == "" {
return "", fmt.Errorf("missing L1 public rpc endpoint in superchain config")
}

fmt.Printf("Setting L1 public rpc endpoint to %s\n", superChain.Config.L1.PublicRPC)
return superChain.Config.L1.PublicRPC, nil
}
160 changes: 160 additions & 0 deletions add-chain/contract_addresses.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package main

import (
"encoding/json"
"fmt"
"os"
"path/filepath"

"github.com/ethereum-optimism/superchain-registry/superchain"
)

type AddressData struct {
Address string `json:"address"`
}

var (
// Addresses to retrieve from JSON
Comment thread
bitwiseguy marked this conversation as resolved.
AddressManager = "AddressManager"
L1CrossDomainMessengerProxy = "L1CrossDomainMessengerProxy"
L1ERC721BridgeProxy = "L1ERC721BridgeProxy"
L1StandardBridgeProxy = "L1StandardBridgeProxy"
L2OutputOracleProxy = "L2OutputOracleProxy"
OptimismMintableERC20FactoryProxy = "OptimismMintableERC20FactoryProxy"
SystemConfigProxy = "SystemConfigProxy"
OptimismPortalProxy = "OptimismPortalProxy"
ProxyAdmin = "ProxyAdmin"

// Addresses to retrieve from chain
SuperchainConfig = "SuperchainConfig"
Guardian = "Guardian"
Challenger = "Challenger"
ProxyAdminOwner = "ProxyAdminOwner"
SystemConfigOwner = "SystemConfigOwner"
)

func readAddressesFromChain(contractAddresses map[string]string, l1RpcUrl string) error {
// SuperchainConfig
address, err := castCall(contractAddresses[OptimismPortalProxy], "superchainConfig()(address)", l1RpcUrl)
if err != nil {
contractAddresses[SuperchainConfig] = ""
} else {
contractAddresses[SuperchainConfig] = address
}

// Guardian
address, err = castCall(contractAddresses[SuperchainConfig], "guardian()(address)", l1RpcUrl)
if err != nil {
address, err = castCall(contractAddresses[OptimismPortalProxy], "guardian()(address)", l1RpcUrl)
Comment thread
bitwiseguy marked this conversation as resolved.
if err != nil {
return fmt.Errorf("could not retrieve address for Guardian %w", err)
}
}
contractAddresses[Guardian] = address

// Challenger
address, err = castCall(contractAddresses[L2OutputOracleProxy], "challenger()(address)", l1RpcUrl)
if err != nil {
return fmt.Errorf("could not retrieve address for Guardian")
}
contractAddresses[Challenger] = address

// ProxyAdminOwner
address, err = castCall(contractAddresses[ProxyAdmin], "owner()(address)", l1RpcUrl)
if err != nil {
return fmt.Errorf("could not retrieve address for ProxyAdminOwner")
}
contractAddresses[ProxyAdminOwner] = address

// SystemConfigOwner
address, err = castCall(contractAddresses[SystemConfigProxy], "owner()(address)", l1RpcUrl)
if err != nil {
return fmt.Errorf("could not retrieve address for ProxyAdminOwner")
}
contractAddresses[SystemConfigOwner] = address

fmt.Printf("Contract addresses read from on-chain contracts\n")
return nil
}

func readAddressesFromJSON(contractAddresses map[string]string, deploymentsDir string) error {
contractsFromJSON := []string{
AddressManager,
L1CrossDomainMessengerProxy,
L1ERC721BridgeProxy,
L1StandardBridgeProxy,
L2OutputOracleProxy,
OptimismMintableERC20FactoryProxy,
SystemConfigProxy,
OptimismPortalProxy,
ProxyAdmin,
}

deployFilePath := filepath.Join(deploymentsDir, ".deploy")
_, err := os.Stat(deployFilePath)

if err != nil {
// Use legacy deployment artifact schema
for _, name := range contractsFromJSON {
path := filepath.Join(deploymentsDir, name+".json")
file, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("failed to read file: %w", err)
}
var data AddressData
if err = json.Unmarshal(file, &data); err != nil {
return fmt.Errorf("failed to unmarshal json: %w", err)
}
contractAddresses[name] = data.Address
}
} else {
var addressList superchain.AddressList
rawData, err := os.ReadFile(deployFilePath)
if err != nil {
return fmt.Errorf("failed to read file: %w", err)
}

if err = json.Unmarshal(rawData, &addressList); err != nil {
return fmt.Errorf("failed to unmarshal json: %w", err)
}

for _, name := range contractsFromJSON {
address, err := addressList.AddressFor(name)
if err != nil {
return fmt.Errorf("failed to retrieve %s address from list: %w", name, err)
}
contractAddresses[name] = address.String()
}
}

fmt.Printf("Contract addresses read from deployments directory: %s\n", deploymentsDir)
return nil
}

func writeAddressesToJSON(contractsAddresses map[string]string, superchainRepoPath, target, chainName string) error {
dirPath := filepath.Join(superchainRepoPath, "superchain", "extra", "addresses", target)
if err := os.MkdirAll(dirPath, 0o755); err != nil {
return fmt.Errorf("failed to create directory: %w", err)
}

filePath := filepath.Join(dirPath, chainName+".json")
file, err := os.Create(filePath)
if err != nil {
return fmt.Errorf("failed to create file: %w", err)
}
defer file.Close()

// Marshal the map to JSON
jsonData, err := json.MarshalIndent(contractsAddresses, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal json: %w", err)
}

// Write the JSON data to the file
if _, err := file.Write(jsonData); err != nil {
return fmt.Errorf("failed to write json to file: %w", err)
}
fmt.Printf("Contract addresses written to: %s\n", filePath)

return nil
}
Loading