Skip to content

Commit

Permalink
Config: Add contract impl addresses & versions to config toml (ethere…
Browse files Browse the repository at this point in the history
…um-optimism#525)

* Config: Add standard contract impl addresses & versions to superchain config toml

* store and expose the contract implementation addresses & versions for each contracts release.
this is intended to be used by internal/external components such as validation code
within superchain-registry, op-stack-manager, monorepo upgrade tool etc.
The intent is to persist a single source of truth for the implementation addresses.
* the addresses are stored in `superchain.toml` as a map of the contracts release
 tag as a string to the implementation contract addresses
* Initial addresses/versions are recorded for v1.3.0/MCP L1 contracts release

* add contract addresses & versions for sepolia (testnet)

* Move contract implementation addresses under validation dir

* contract implemetnation addresses now live with contract versions in validation
* Instead of two separate files/sections, they are now specified as a `VersionedContract`
  which is a pre-existing construct in SCR.

* Run just codegen

* Address review comments

moved `op_contracts_release` from superchain.toml
to `validation/standard/standard-config.toml`

* Fix naming and update addresses

* Print a more useful diff for contract version check (ethereum-optimism#582)

* update standard release

* make a more useful diff

* update go mod

---------

Co-authored-by: Vinod Damle <[email protected]>

* Use optional fields to track either `implementation_address` or `address` in standard contract versions (ethereum-optimism#587)

* VersionedContract has optional implementation_address and address fields

* use pointers

---------

Co-authored-by: Vinod Damle <[email protected]>
Co-authored-by: George Knee <[email protected]>
  • Loading branch information
3 people authored Sep 16, 2024
1 parent af8d409 commit a90e302
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 98 deletions.
89 changes: 61 additions & 28 deletions superchain/superchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,16 +374,10 @@ func (a AddressList) AddressFor(name string) (Address, error) {
// contract. They are keyed by the semantic version.
type AddressSet map[string]Address

// VersionedContract represents a contract that has a semantic version.
type VersionedContract struct {
Version string `json:"version" toml:"version"`
Address Address `json:"address" toml:"address"`
}

// ContractVersions represents the desired semantic version of the contracts
// in the superchain. This currently only supports L1 contracts but could
// represent L2 predeploys in the future.
type ContractVersions struct {
type ContractBytecodeHashes struct {
L1CrossDomainMessenger string `toml:"l1_cross_domain_messenger"`
L1ERC721Bridge string `toml:"l1_erc721_bridge"`
L1StandardBridge string `toml:"l1_standard_bridge"`
Expand All @@ -404,43 +398,82 @@ type ContractVersions struct {
PreimageOracle string `toml:"preimage_oracle,omitempty"`
}

// VersionedContract represents a contract that has a semantic version.
type VersionedContract struct {
Version string `toml:"version"`
// If the contract is a superchain singleton, it will have a static address
Address *Address `toml:"implementation_address,omitempty"`
// If the contract is proxied, the implementation will have a static address
ImplementationAddress *Address `toml:"address,omitempty"`
}

// ContractVersions represents the desired semantic version of the contracts
// in the superchain. This currently only supports L1 contracts but could
// represent L2 predeploys in the future.
type ContractVersions struct {
L1CrossDomainMessenger VersionedContract `toml:"l1_cross_domain_messenger,omitempty"`
L1ERC721Bridge VersionedContract `toml:"l1_erc721_bridge,omitempty"`
L1StandardBridge VersionedContract `toml:"l1_standard_bridge,omitempty"`
L2OutputOracle VersionedContract `toml:"l2_output_oracle,omitempty"`
OptimismMintableERC20Factory VersionedContract `toml:"optimism_mintable_erc20_factory,omitempty"`
OptimismPortal VersionedContract `toml:"optimism_portal,omitempty"`
OptimismPortal2 VersionedContract `toml:"optimism_portal2,omitempty"`
SystemConfig VersionedContract `toml:"system_config,omitempty"`
// Superchain-wide contracts:
ProtocolVersions VersionedContract `toml:"protocol_versions,omitempty"`
SuperchainConfig VersionedContract `toml:"superchain_config,omitempty"`
// Fault Proof contracts:
AnchorStateRegistry VersionedContract `toml:"anchor_state_registry,omitempty"`
DelayedWETH VersionedContract `toml:"delayed_weth,omitempty"`
DisputeGameFactory VersionedContract `toml:"dispute_game_factory,omitempty"`
FaultDisputeGame VersionedContract `toml:"fault_dispute_game,omitempty"`
MIPS VersionedContract `toml:"mips,omitempty"`
PermissionedDisputeGame VersionedContract `toml:"permissioned_dispute_game,omitempty"`
PreimageOracle VersionedContract `toml:"preimage_oracle,omitempty"`
CannonFaultDisputeGame VersionedContract `toml:"cannon_fault_dispute_game,omitempty"`
}

// VersionFor returns the version for the supplied contract name, if it exits
// (and an error otherwise). Useful for slicing into the struct using a string.
func (c ContractVersions) VersionFor(contractName string) (string, error) {
var version string
switch contractName {
case "L1CrossDomainMessenger":
version = c.L1CrossDomainMessenger
version = c.L1CrossDomainMessenger.Version
case "L1ERC721Bridge":
version = c.L1ERC721Bridge
version = c.L1ERC721Bridge.Version
case "L1StandardBridge":
version = c.L1StandardBridge
version = c.L1StandardBridge.Version
case "L2OutputOracle":
version = c.L2OutputOracle
version = c.L2OutputOracle.Version
case "OptimismMintableERC20Factory":
version = c.OptimismMintableERC20Factory
version = c.OptimismMintableERC20Factory.Version
case "OptimismPortal":
version = c.OptimismPortal
version = c.OptimismPortal.Version
case "OptimismPortal2":
version = c.OptimismPortal2.Version
case "SystemConfig":
version = c.SystemConfig
version = c.SystemConfig.Version
case "AnchorStateRegistry":
version = c.AnchorStateRegistry
version = c.AnchorStateRegistry.Version
case "DelayedWETH":
version = c.DelayedWETH
version = c.DelayedWETH.Version
case "DisputeGameFactory":
version = c.DisputeGameFactory
version = c.DisputeGameFactory.Version
case "FaultDisputeGame":
version = c.FaultDisputeGame
version = c.FaultDisputeGame.Version
case "MIPS":
version = c.MIPS
version = c.MIPS.Version
case "PermissionedDisputeGame":
version = c.PermissionedDisputeGame
version = c.PermissionedDisputeGame.Version
case "PreimageOracle":
version = c.PreimageOracle
version = c.PreimageOracle.Version
case "ProtocolVersions":
version = c.ProtocolVersions
version = c.ProtocolVersions.Version
case "SuperchainConfig":
version = c.SuperchainConfig
version = c.SuperchainConfig.Version
case "CannonFaultDisputeGame":
version = c.CannonFaultDisputeGame.Version
default:
return "", errors.New("no such contract name")
}
Expand All @@ -456,19 +489,19 @@ func (c ContractVersions) Check(allowEmptyVersions bool) error {
val := reflect.ValueOf(c)
for i := 0; i < val.NumField(); i++ {
field := val.Field(i)
str, ok := field.Interface().(string)
vC, ok := field.Interface().(VersionedContract)
if !ok {
return fmt.Errorf("invalid type for field %s", val.Type().Field(i).Name)
}
if str == "" {
if vC.Version == "" {
if allowEmptyVersions {
continue // we allow empty strings and rely on tests to assert (or except) a nonempty version
}
return fmt.Errorf("empty version for field %s", val.Type().Field(i).Name)
}
str = CanonicalizeSemver(str)
if !semver.IsValid(str) {
return fmt.Errorf("invalid semver %s for field %s", str, val.Type().Field(i).Name)
vC.Version = CanonicalizeSemver(vC.Version)
if !semver.IsValid(vC.Version) {
return fmt.Errorf("invalid semver %s for field %s", vC.Version, val.Type().Field(i).Name)
}
}
return nil
Expand Down
12 changes: 7 additions & 5 deletions superchain/superchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ func TestAddressFor(t *testing.T) {

func TestVersionFor(t *testing.T) {
cl := ContractVersions{
L1CrossDomainMessenger: "1.9.9",
OptimismPortal: "",
L1CrossDomainMessenger: VersionedContract{Version: "1.9.9"},
OptimismPortal: VersionedContract{Version: ""},
}
want := "1.9.9"
got, err := cl.VersionFor("L1CrossDomainMessenger")
Expand Down Expand Up @@ -208,12 +208,14 @@ ecotone_time = 3
err := unMarshalSuperchainConfig([]byte(rawTOML), &s)
require.NoError(t, err)

require.Equal(t, "Mickey Mouse", s.Name)
require.Equal(t, SuperchainL1Info{
expectL1Info := SuperchainL1Info{
ChainID: 314,
PublicRPC: "https://disney.com",
Explorer: "https://disneyscan.io",
}, s.L1)
}

require.Equal(t, "Mickey Mouse", s.Name)
require.Equal(t, expectL1Info, s.L1)

require.Equal(t, "0x252CbE9517F731C618961D890D534183822dcC8d", s.ProtocolVersionsAddr.String())
require.Equal(t, "0x02d91Cf852423640d93920BE0CAdceC0E7A00FA7", s.SuperchainConfigAddr.String())
Expand Down
1 change: 1 addition & 0 deletions validation/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/ethereum-optimism/optimism v1.9.1-0.20240814195148-0bb2ff57c813
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240828144951-4e6edcb7d36c
github.com/ethereum/go-ethereum v1.14.7
github.com/google/go-cmp v0.6.0
github.com/stretchr/testify v1.9.0
golang.org/x/mod v0.20.0
)
Expand Down
4 changes: 2 additions & 2 deletions validation/standard/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var standardConfigFile embed.FS
var ContractASTsWithImmutableReferences = map[string]string{}

// L1ContractBytecodeHashes represents the hash of the contract bytecode (as a hex string) for each L1 contract
type L1ContractBytecodeHashes superchain.ContractVersions
type L1ContractBytecodeHashes superchain.ContractBytecodeHashes

// ContractBytecodeImmutables stores the immutable references as a raw stringified JSON string in a TOML config.
// it is stored this way because it can be plucked out of the contract compilation output as is and pasted into the TOML config file.
Expand Down Expand Up @@ -71,7 +71,7 @@ func decodeTOMLFileIntoConfig[T Params | Roles | MultisigRoles | VersionTags | B
// LoadImmutableReferences parses standard-immutables.toml and stores it in a map. Needs to be invoked one-time only.
func LoadImmutableReferences() {
var bytecodeImmutables *ContractBytecodeImmutables
for tag := range Versions {
for tag := range Versions.Releases {
for contractVersion, immutables := range BytecodeImmutables {
if tag == contractVersion {
bytecodeImmutables = &immutables
Expand Down
56 changes: 42 additions & 14 deletions validation/standard/standard-versions.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,42 @@
["op-contracts/v1.4.0"] # Fault Proofs https://github.com/ethereum-optimism/optimism/releases/tag/op-contracts%2Fv1.4.0
address_manager = ""
l1_cross_domain_messenger = "2.3.0"
l1_erc721_bridge = "2.1.0"
l1_standard_bridge = "2.1.0"
optimism_mintable_erc20_factory = "1.9.0"
optimism_portal = "3.10.0"
system_config = "2.2.0"
protocol_versions = "1.0.0"
anchor_state_registry = "1.0.0"
delayed_weth = "1.0.0"
dispute_game_factory = "1.0.0"
fault_dispute_game = "1.2.0"
permissioned_dispute_game = "1.2.0"
standard_release = "op-contracts/v1.6.0"

[releases]

# Contracts which are
# * unproxied singletons: specify a standard "address"
# * proxied : specify a standard "implementation_address"
# * neither : specify neither a standard "address" nor "implementation_address"

# Fault Proofs https://github.com/ethereum-optimism/optimism/releases/tag/op-contracts%2Fv1.6.0
[releases."op-contracts/v1.6.0"]
optimism_portal = { version = "3.10.0", implementation_address = "0xe2F826324b2faf99E513D16D266c3F80aE87832B" }
system_config = { version = "2.2.0", implementation_address = "0xF56D96B2535B932656d3c04Ebf51baBff241D886" }
anchor_state_registry = { version = "2.0.0" }
delayed_weth = { version = "1.1.0", implementation_address = "0x71e966Ae981d1ce531a7b6d23DC0f27B38409087" }
dispute_game_factory = { version = "1.0.0", implementation_address = "0xc641A33cab81C559F2bd4b21EA34C290E2440C2B" }
fault_dispute_game = { version = "1.3.0" }
permissioned_dispute_game = { version = "1.3.0" }
mips = { version = "1.1.0", address = "0x16e83cE5Ce29BF90AD9Da06D2fE6a15d5f344ce4" }
preimage_oracle = { version = "1.1.2", address = "0x9c065e11870B891D214Bc2Da7EF1f9DDFA1BE277" }

# Fault Proofs https://github.com/ethereum-optimism/optimism/releases/tag/op-contracts%2Fv1.4.0
[releases."op-contracts/v1.4.0"]
optimism_portal = { version = "3.10.0", implementation_address = "0xe2F826324b2faf99E513D16D266c3F80aE87832B" }
system_config = { version = "2.2.0", implementation_address = "0xF56D96B2535B932656d3c04Ebf51baBff241D886" }
anchor_state_registry = { version = "1.0.0" }
delayed_weth = { version = "1.0.0", implementation_address = "0x97988d5624F1ba266E1da305117BCf20713bee08" }
dispute_game_factory = { version = "1.0.0", implementation_address = "0xc641A33cab81C559F2bd4b21EA34C290E2440C2B" }
fault_dispute_game = { version = "1.2.0" }
permissioned_dispute_game = { version = "1.2.0" }
mips = { version = "1.0.1", address = "0x0f8EdFbDdD3c0256A80AD8C0F2560B1807873C9c" }
preimage_oracle = { version = "1.0.0", address = "0xD326E10B8186e90F4E2adc5c13a2d0C137ee8b34" }

# MCP https://github.com/ethereum-optimism/optimism/releases/tag/op-contracts%2Fv1.3.0
[releases."op-contracts/v1.3.0"]
l1_cross_domain_messenger = { version = "2.3.0", implementation_address = "0xD3494713A5cfaD3F5359379DfA074E2Ac8C6Fd65" }
l1_erc721_bridge = { version = "2.1.0", implementation_address = "0xAE2AF01232a6c4a4d3012C5eC5b1b35059caF10d" }
l1_standard_bridge = { version = "2.1.0", implementation_address = "0x64B5a5Ed26DCb17370Ff4d33a8D503f0fbD06CfF" }
l2_output_oracle = { version = "1.8.0", implementation_address = "0xF243BEd163251380e78068d317ae10f26042B292" }
optimism_mintable_erc20_factory = { version = "1.9.0", implementation_address = "0xE01efbeb1089D1d1dB9c6c8b135C934C0734c846" }
optimism_portal = { version = "2.5.0", implementation_address = "0x2D778797049FE9259d947D1ED8e5442226dFB589" }
system_config = { version = "1.12.0", implementation_address = "0xba2492e52F45651B60B8B38d4Ea5E2390C64Ffb1" }
10 changes: 8 additions & 2 deletions validation/standard/versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@ import (
type Tag string

type (
VersionTags = map[Tag]superchain.ContractVersions
BytecodeHashTags = map[Tag]L1ContractBytecodeHashes
BytecodeImmutablesTags = map[Tag]ContractBytecodeImmutables
)

type VersionTags struct {
Releases map[Tag]superchain.ContractVersions `toml:"releases"`
StandardRelease Tag `toml:"standard_release,omitempty"`
}

var (
Versions VersionTags = make(VersionTags, 0)
Versions VersionTags = VersionTags{
Releases: make(map[Tag]superchain.ContractVersions, 0),
}
BytecodeHashes BytecodeHashTags = make(BytecodeHashTags, 0)
BytecodeImmutables BytecodeImmutablesTags = make(BytecodeImmutablesTags, 0)
)
Loading

0 comments on commit a90e302

Please sign in to comment.