Commit 8b769313 authored by Blaine Malone's avatar Blaine Malone Committed by GitHub

feat: Implement release-based contract deployment (#12035)

* forge install: superchain-registry

v0.1.2

* fix: better clarity around when we're in a broadcast context.
parent 43224ed7
......@@ -44,4 +44,8 @@ fuzz:
go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzAliasing ./crossdomain
go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzVersionedNonce ./crossdomain
.PHONY: test fuzz op-deployer
\ No newline at end of file
sync-standard-version:
curl -Lo ./deployer/opsm/standard-versions.toml https://raw.githubusercontent.com/ethereum-optimism/superchain-registry/refs/heads/main/validation/standard/standard-versions.toml
.PHONY: test fuzz op-deployer sync-standard-version
\ No newline at end of file
......@@ -115,6 +115,7 @@ func TestEndToEndApply(t *testing.T) {
UseFaultProofs: true,
FundDevAccounts: true,
ContractArtifactsURL: (*state.ArtifactsURL)(artifactsURL),
ContractsRelease: "dev",
Chains: []*state.ChainIntent{
{
ID: id.Bytes32(),
......
......@@ -23,6 +23,7 @@ type DeployImplementationsInput struct {
UseInterop bool // if true, deploy Interop implementations
SuperchainProxyAdmin common.Address
StandardVersionsToml string // contents of 'standard-versions.toml' file
}
func (input *DeployImplementationsInput) InputSet() bool {
......@@ -31,6 +32,7 @@ func (input *DeployImplementationsInput) InputSet() bool {
type DeployImplementationsOutput struct {
OpsmProxy common.Address
OpsmImpl common.Address
DelayedWETHImpl common.Address
OptimismPortalImpl common.Address
PreimageOracleSingleton common.Address
......
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" }
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 -- This contract not used in fault proofs
optimism_mintable_erc20_factory = { version = "1.9.0", implementation_address = "0xE01efbeb1089D1d1dB9c6c8b135C934C0734c846" }
# 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" }
package opsm
import "embed"
//go:embed standard-versions.toml
var StandardVersionsData string
var _ embed.FS
......@@ -46,10 +46,11 @@ func DeployImplementations(ctx context.Context, env *Env, artifactsFS foundry.St
ChallengePeriodSeconds: big.NewInt(86400),
ProofMaturityDelaySeconds: big.NewInt(604800),
DisputeGameFinalityDelaySeconds: big.NewInt(302400),
Release: "op-contracts/v1.6.0",
Release: intent.ContractsRelease,
SuperchainConfigProxy: st.SuperchainDeployment.SuperchainConfigProxyAddress,
ProtocolVersionsProxy: st.SuperchainDeployment.ProtocolVersionsProxyAddress,
SuperchainProxyAdmin: st.SuperchainDeployment.ProxyAdminAddress,
StandardVersionsToml: opsm.StandardVersionsData,
UseInterop: false,
},
)
......
......@@ -24,6 +24,8 @@ type Intent struct {
ContractArtifactsURL *ArtifactsURL `json:"contractArtifactsURL" toml:"contractArtifactsURL"`
ContractsRelease string `json:"contractsVersion" toml:"contractsVersion"`
Chains []*ChainIntent `json:"chains" toml:"chains"`
GlobalDeployOverrides map[string]any `json:"globalDeployOverrides" toml:"globalDeployOverrides"`
......
......@@ -39,6 +39,8 @@ type OPSMImplementationsConfig struct {
FaultProof SuperFaultProofConfig
UseInterop bool // to deploy Interop implementation contracts, instead of the regular ones.
StandardVersionsToml string // serialized string of superchain-registry 'standard-versions.toml' file
}
type SuperchainConfig struct {
......
......@@ -172,6 +172,7 @@ func deploySuperchainToL1(l1Host *script.Host, superCfg *SuperchainConfig) (*Sup
ProtocolVersionsProxy: superDeployment.ProtocolVersionsProxy,
SuperchainProxyAdmin: superDeployment.SuperchainProxyAdmin,
UseInterop: superCfg.Implementations.UseInterop,
StandardVersionsToml: opsm.StandardVersionsData,
})
if err != nil {
return nil, fmt.Errorf("failed to deploy Implementations contracts: %w", err)
......
......@@ -10,6 +10,7 @@ type L1Deployment struct {
type Implementations struct {
OpsmProxy common.Address `json:"OPSMProxy"`
OpsmImpl common.Address `json:"OPSMImpl"`
DelayedWETHImpl common.Address `json:"DelayedWETHImpl"`
OptimismPortalImpl common.Address `json:"OptimismPortalImpl"`
PreimageOracleSingleton common.Address `json:"PreimageOracleSingleton"`
......
......@@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer/opsm"
"github.com/ethereum-optimism/optimism/op-chain-ops/devkeys"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
)
......@@ -61,12 +62,13 @@ func (r *InteropDevRecipe) Build(addrs devkeys.Addresses) (*WorldConfig, error)
l1Cfg.Prefund[superchainDeployer] = Ether(10_000_000)
l1Cfg.Prefund[superchainProxyAdmin] = Ether(10_000_000)
l1Cfg.Prefund[superchainConfigGuardian] = Ether(10_000_000)
superchainCfg := &SuperchainConfig{
ProxyAdminOwner: superchainProxyAdmin,
ProtocolVersionsOwner: superchainProtocolVersionsOwner,
Deployer: superchainDeployer,
Implementations: OPSMImplementationsConfig{
Release: "op-contracts/0.0.1",
Release: "dev",
FaultProof: SuperFaultProofConfig{
WithdrawalDelaySeconds: big.NewInt(604800),
MinProposalSizeBytes: big.NewInt(10000),
......@@ -74,7 +76,8 @@ func (r *InteropDevRecipe) Build(addrs devkeys.Addresses) (*WorldConfig, error)
ProofMaturityDelaySeconds: big.NewInt(12),
DisputeGameFinalityDelaySeconds: big.NewInt(6),
},
UseInterop: true,
UseInterop: true,
StandardVersionsToml: opsm.StandardVersionsData,
},
SuperchainL1DeployConfig: genesis.SuperchainL1DeployConfig{
RequiredProtocolVersion: params.OPStackSupport,
......
......@@ -3,9 +3,12 @@ package script
import (
"fmt"
"math/big"
"regexp"
"strconv"
"strings"
"github.com/BurntSushi/toml"
hdwallet "github.com/ethereum-optimism/go-ethereum-hdwallet"
"github.com/ethereum/go-ethereum/accounts"
......@@ -188,5 +191,77 @@ func (c *CheatCodesPrecompile) Breakpoint_f7d39a8d(name string, v bool) {
}
}
// ParseTomlAddress_65e7c844 implements https://book.getfoundry.sh/cheatcodes/parse-toml. This
// method is not well optimized or implemented. It's optimized for quickly delivering OPCM. We
// can come back and clean it up more later.
func (c *CheatCodesPrecompile) ParseTomlAddress_65e7c844(tomlStr string, key string) (common.Address, error) {
var data map[string]any
if err := toml.Unmarshal([]byte(tomlStr), &data); err != nil {
return common.Address{}, fmt.Errorf("failed to parse TOML: %w", err)
}
keys, err := SplitJSONPathKeys(key)
if err != nil {
return common.Address{}, fmt.Errorf("failed to split keys: %w", err)
}
loc := data
for i, k := range keys {
value, ok := loc[k]
if !ok {
return common.Address{}, fmt.Errorf("key %q not found in TOML", k)
}
if i == len(keys)-1 {
addrStr, ok := value.(string)
if !ok {
return common.Address{}, fmt.Errorf("key %q is not a string", key)
}
if !common.IsHexAddress(addrStr) {
return common.Address{}, fmt.Errorf("key %q is not a valid address", key)
}
return common.HexToAddress(addrStr), nil
}
next, ok := value.(map[string]any)
if !ok {
return common.Address{}, fmt.Errorf("key %q is not a nested map", key)
}
loc = next
}
panic("should never get here")
}
// unsupported
//func (c *CheatCodesPrecompile) CreateWallet() {}
// SplitJSONPathKeys splits a JSON path into keys. It supports bracket notation. There is a much
// better way to implement this, but I'm keeping this simple for now.
func SplitJSONPathKeys(path string) ([]string, error) {
var out []string
bracketSplit := regexp.MustCompile(`[\[\]]`).Split(path, -1)
for _, split := range bracketSplit {
if len(split) == 0 {
continue
}
split = strings.ReplaceAll(split, "\"", "")
split = strings.ReplaceAll(split, " ", "")
if !strings.HasPrefix(split, ".") {
out = append(out, split)
continue
}
keys := strings.Split(split, ".")
for _, key := range keys {
if len(key) == 0 {
continue
}
out = append(out, key)
}
}
return out, nil
}
package script
import (
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
const tomlTest = `
foo = "0x0d4CE7B6a91A35c31D7D62b327D19617c8da6F23"
[foomap]
[foomap."bar.bump"]
baz = "0xff4ce7b6a91a35c31d7d62b327d19617c8da6f23"
`
func TestSplitJSONPathKeys(t *testing.T) {
tests := []struct {
name string
path string
expected []string
}{
{
"simple",
".foo.bar",
[]string{"foo", "bar"},
},
{
"bracket keys",
".foo[\"hey\"].bar",
[]string{"foo", "hey", "bar"},
},
{
"bracket keys with dots",
".foo[\"hey.there\"].bar",
[]string{"foo", "hey.there", "bar"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := SplitJSONPathKeys(tt.path)
require.NoError(t, err)
require.Equal(t, tt.expected, got)
})
}
}
func TestParseTomlAddress(t *testing.T) {
c := &CheatCodesPrecompile{}
addr, err := c.ParseTomlAddress_65e7c844(tomlTest, "foo")
require.NoError(t, err)
require.Equal(t, common.HexToAddress("0x0d4ce7b6a91a35c31d7d62b327d19617c8da6f23"), addr)
addr, err = c.ParseTomlAddress_65e7c844(tomlTest, "foomap[\"bar.bump\"].baz")
require.NoError(t, err)
require.Equal(t, common.HexToAddress("0xff4ce7b6a91a35c31d7d62b327d19617c8da6f23"), addr)
}
......@@ -323,7 +323,7 @@ contract DeployOPChain_TestBase is Test {
uint256 challengePeriodSeconds = 300;
uint256 proofMaturityDelaySeconds = 400;
uint256 disputeGameFinalityDelaySeconds = 500;
string release = "op-contracts/latest";
string release = "dev-release"; // this means implementation contracts will be deployed
SuperchainConfig superchainConfigProxy;
ProtocolVersions protocolVersionsProxy;
......@@ -393,6 +393,11 @@ contract DeployOPChain_TestBase is Test {
dii.set(dii.release.selector, release);
dii.set(dii.superchainConfigProxy.selector, address(superchainConfigProxy));
dii.set(dii.protocolVersionsProxy.selector, address(protocolVersionsProxy));
// End users of the DeployImplementations contract will need to set the `standardVersionsToml`.
string memory standardVersionsTomlPath =
string.concat(vm.projectRoot(), "/test/fixtures/standard-versions.toml");
string memory standardVersionsToml = vm.readFile(standardVersionsTomlPath);
dii.set(dii.standardVersionsToml.selector, standardVersionsToml);
deployImplementations.run(dii, dio);
// Set the OPStackManager input for DeployOPChain.
......
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" }
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 -- This contract not used in fault proofs
optimism_mintable_erc20_factory = { version = "1.9.0", implementation_address = "0xE01efbeb1089D1d1dB9c6c8b135C934C0734c846" }
# 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" }
[safe]
threshold = 5
owners = [
"0x1111111111111111111111111111111111111111",
"0x2222222222222222222222222222222222222222",
"0x3333333333333333333333333333333333333333",
"0x4444444444444444444444444444444444444444",
"0x5555555555555555555555555555555555555555",
"0x6666666666666666666666666666666666666666",
"0x7777777777777777777777777777777777777777"
]
paused = false
requiredProtocolVersion = 1
recommendedProtocolVersion = 2
[roles]
proxyAdminOwner = "0x51f0348a9fA2aAbaB45E82825Fbd13d406e04497"
protocolVersionsOwner = "0xeEB4cc05dC0dE43c465f97cfc703D165418CA93A"
guardian = "0xE5DbA98c65F4B9EB0aeEBb3674fE64f88509a1eC"
protocolVersionsImpl = "0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9"
protocolVersionsProxy = "0x1d1499e622D69689cdf9004d05Ec547d650Ff211"
superchainConfigImpl = "0xF62849F9A0B5Bf2913b396098F7c7019b51A820a"
superchainConfigProxy = "0xc7183455a4C133Ae270771860664b6B7ec320bB1"
superchainProxyAdmin = "0x2e234DAe75C793f67A35089C9d99245E1C58470b"
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