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: ...@@ -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=FuzzAliasing ./crossdomain
go test $(FUZZLDFLAGS) -run NOTAREALTEST -v -fuzztime 10s -fuzz=FuzzVersionedNonce ./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) { ...@@ -115,6 +115,7 @@ func TestEndToEndApply(t *testing.T) {
UseFaultProofs: true, UseFaultProofs: true,
FundDevAccounts: true, FundDevAccounts: true,
ContractArtifactsURL: (*state.ArtifactsURL)(artifactsURL), ContractArtifactsURL: (*state.ArtifactsURL)(artifactsURL),
ContractsRelease: "dev",
Chains: []*state.ChainIntent{ Chains: []*state.ChainIntent{
{ {
ID: id.Bytes32(), ID: id.Bytes32(),
......
...@@ -23,6 +23,7 @@ type DeployImplementationsInput struct { ...@@ -23,6 +23,7 @@ type DeployImplementationsInput struct {
UseInterop bool // if true, deploy Interop implementations UseInterop bool // if true, deploy Interop implementations
SuperchainProxyAdmin common.Address SuperchainProxyAdmin common.Address
StandardVersionsToml string // contents of 'standard-versions.toml' file
} }
func (input *DeployImplementationsInput) InputSet() bool { func (input *DeployImplementationsInput) InputSet() bool {
...@@ -31,6 +32,7 @@ func (input *DeployImplementationsInput) InputSet() bool { ...@@ -31,6 +32,7 @@ func (input *DeployImplementationsInput) InputSet() bool {
type DeployImplementationsOutput struct { type DeployImplementationsOutput struct {
OpsmProxy common.Address OpsmProxy common.Address
OpsmImpl common.Address
DelayedWETHImpl common.Address DelayedWETHImpl common.Address
OptimismPortalImpl common.Address OptimismPortalImpl common.Address
PreimageOracleSingleton 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 ...@@ -46,10 +46,11 @@ func DeployImplementations(ctx context.Context, env *Env, artifactsFS foundry.St
ChallengePeriodSeconds: big.NewInt(86400), ChallengePeriodSeconds: big.NewInt(86400),
ProofMaturityDelaySeconds: big.NewInt(604800), ProofMaturityDelaySeconds: big.NewInt(604800),
DisputeGameFinalityDelaySeconds: big.NewInt(302400), DisputeGameFinalityDelaySeconds: big.NewInt(302400),
Release: "op-contracts/v1.6.0", Release: intent.ContractsRelease,
SuperchainConfigProxy: st.SuperchainDeployment.SuperchainConfigProxyAddress, SuperchainConfigProxy: st.SuperchainDeployment.SuperchainConfigProxyAddress,
ProtocolVersionsProxy: st.SuperchainDeployment.ProtocolVersionsProxyAddress, ProtocolVersionsProxy: st.SuperchainDeployment.ProtocolVersionsProxyAddress,
SuperchainProxyAdmin: st.SuperchainDeployment.ProxyAdminAddress, SuperchainProxyAdmin: st.SuperchainDeployment.ProxyAdminAddress,
StandardVersionsToml: opsm.StandardVersionsData,
UseInterop: false, UseInterop: false,
}, },
) )
......
...@@ -24,6 +24,8 @@ type Intent struct { ...@@ -24,6 +24,8 @@ type Intent struct {
ContractArtifactsURL *ArtifactsURL `json:"contractArtifactsURL" toml:"contractArtifactsURL"` ContractArtifactsURL *ArtifactsURL `json:"contractArtifactsURL" toml:"contractArtifactsURL"`
ContractsRelease string `json:"contractsVersion" toml:"contractsVersion"`
Chains []*ChainIntent `json:"chains" toml:"chains"` Chains []*ChainIntent `json:"chains" toml:"chains"`
GlobalDeployOverrides map[string]any `json:"globalDeployOverrides" toml:"globalDeployOverrides"` GlobalDeployOverrides map[string]any `json:"globalDeployOverrides" toml:"globalDeployOverrides"`
......
...@@ -39,6 +39,8 @@ type OPSMImplementationsConfig struct { ...@@ -39,6 +39,8 @@ type OPSMImplementationsConfig struct {
FaultProof SuperFaultProofConfig FaultProof SuperFaultProofConfig
UseInterop bool // to deploy Interop implementation contracts, instead of the regular ones. 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 { type SuperchainConfig struct {
......
...@@ -172,6 +172,7 @@ func deploySuperchainToL1(l1Host *script.Host, superCfg *SuperchainConfig) (*Sup ...@@ -172,6 +172,7 @@ func deploySuperchainToL1(l1Host *script.Host, superCfg *SuperchainConfig) (*Sup
ProtocolVersionsProxy: superDeployment.ProtocolVersionsProxy, ProtocolVersionsProxy: superDeployment.ProtocolVersionsProxy,
SuperchainProxyAdmin: superDeployment.SuperchainProxyAdmin, SuperchainProxyAdmin: superDeployment.SuperchainProxyAdmin,
UseInterop: superCfg.Implementations.UseInterop, UseInterop: superCfg.Implementations.UseInterop,
StandardVersionsToml: opsm.StandardVersionsData,
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to deploy Implementations contracts: %w", err) return nil, fmt.Errorf("failed to deploy Implementations contracts: %w", err)
......
...@@ -10,6 +10,7 @@ type L1Deployment struct { ...@@ -10,6 +10,7 @@ type L1Deployment struct {
type Implementations struct { type Implementations struct {
OpsmProxy common.Address `json:"OPSMProxy"` OpsmProxy common.Address `json:"OPSMProxy"`
OpsmImpl common.Address `json:"OPSMImpl"`
DelayedWETHImpl common.Address `json:"DelayedWETHImpl"` DelayedWETHImpl common.Address `json:"DelayedWETHImpl"`
OptimismPortalImpl common.Address `json:"OptimismPortalImpl"` OptimismPortalImpl common.Address `json:"OptimismPortalImpl"`
PreimageOracleSingleton common.Address `json:"PreimageOracleSingleton"` PreimageOracleSingleton common.Address `json:"PreimageOracleSingleton"`
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/params" "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/devkeys"
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis" "github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
) )
...@@ -61,12 +62,13 @@ func (r *InteropDevRecipe) Build(addrs devkeys.Addresses) (*WorldConfig, error) ...@@ -61,12 +62,13 @@ func (r *InteropDevRecipe) Build(addrs devkeys.Addresses) (*WorldConfig, error)
l1Cfg.Prefund[superchainDeployer] = Ether(10_000_000) l1Cfg.Prefund[superchainDeployer] = Ether(10_000_000)
l1Cfg.Prefund[superchainProxyAdmin] = Ether(10_000_000) l1Cfg.Prefund[superchainProxyAdmin] = Ether(10_000_000)
l1Cfg.Prefund[superchainConfigGuardian] = Ether(10_000_000) l1Cfg.Prefund[superchainConfigGuardian] = Ether(10_000_000)
superchainCfg := &SuperchainConfig{ superchainCfg := &SuperchainConfig{
ProxyAdminOwner: superchainProxyAdmin, ProxyAdminOwner: superchainProxyAdmin,
ProtocolVersionsOwner: superchainProtocolVersionsOwner, ProtocolVersionsOwner: superchainProtocolVersionsOwner,
Deployer: superchainDeployer, Deployer: superchainDeployer,
Implementations: OPSMImplementationsConfig{ Implementations: OPSMImplementationsConfig{
Release: "op-contracts/0.0.1", Release: "dev",
FaultProof: SuperFaultProofConfig{ FaultProof: SuperFaultProofConfig{
WithdrawalDelaySeconds: big.NewInt(604800), WithdrawalDelaySeconds: big.NewInt(604800),
MinProposalSizeBytes: big.NewInt(10000), MinProposalSizeBytes: big.NewInt(10000),
...@@ -74,7 +76,8 @@ func (r *InteropDevRecipe) Build(addrs devkeys.Addresses) (*WorldConfig, error) ...@@ -74,7 +76,8 @@ func (r *InteropDevRecipe) Build(addrs devkeys.Addresses) (*WorldConfig, error)
ProofMaturityDelaySeconds: big.NewInt(12), ProofMaturityDelaySeconds: big.NewInt(12),
DisputeGameFinalityDelaySeconds: big.NewInt(6), DisputeGameFinalityDelaySeconds: big.NewInt(6),
}, },
UseInterop: true, UseInterop: true,
StandardVersionsToml: opsm.StandardVersionsData,
}, },
SuperchainL1DeployConfig: genesis.SuperchainL1DeployConfig{ SuperchainL1DeployConfig: genesis.SuperchainL1DeployConfig{
RequiredProtocolVersion: params.OPStackSupport, RequiredProtocolVersion: params.OPStackSupport,
......
...@@ -3,9 +3,12 @@ package script ...@@ -3,9 +3,12 @@ package script
import ( import (
"fmt" "fmt"
"math/big" "math/big"
"regexp"
"strconv" "strconv"
"strings" "strings"
"github.com/BurntSushi/toml"
hdwallet "github.com/ethereum-optimism/go-ethereum-hdwallet" hdwallet "github.com/ethereum-optimism/go-ethereum-hdwallet"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
...@@ -188,5 +191,77 @@ func (c *CheatCodesPrecompile) Breakpoint_f7d39a8d(name string, v bool) { ...@@ -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 // unsupported
//func (c *CheatCodesPrecompile) CreateWallet() {} //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)
}
...@@ -62,6 +62,8 @@ contract DeployImplementationsInput is BaseDeployIO { ...@@ -62,6 +62,8 @@ contract DeployImplementationsInput is BaseDeployIO {
SuperchainConfig internal _superchainConfigProxy; SuperchainConfig internal _superchainConfigProxy;
ProtocolVersions internal _protocolVersionsProxy; ProtocolVersions internal _protocolVersionsProxy;
string internal _standardVersionsToml;
function set(bytes4 sel, uint256 _value) public { function set(bytes4 sel, uint256 _value) public {
require(_value != 0, "DeployImplementationsInput: cannot set zero value"); require(_value != 0, "DeployImplementationsInput: cannot set zero value");
...@@ -84,6 +86,7 @@ contract DeployImplementationsInput is BaseDeployIO { ...@@ -84,6 +86,7 @@ contract DeployImplementationsInput is BaseDeployIO {
function set(bytes4 sel, string memory _value) public { function set(bytes4 sel, string memory _value) public {
require(!LibString.eq(_value, ""), "DeployImplementationsInput: cannot set empty string"); require(!LibString.eq(_value, ""), "DeployImplementationsInput: cannot set empty string");
if (sel == this.release.selector) _release = _value; if (sel == this.release.selector) _release = _value;
else if (sel == this.standardVersionsToml.selector) _standardVersionsToml = _value;
else revert("DeployImplementationsInput: unknown selector"); else revert("DeployImplementationsInput: unknown selector");
} }
...@@ -137,6 +140,11 @@ contract DeployImplementationsInput is BaseDeployIO { ...@@ -137,6 +140,11 @@ contract DeployImplementationsInput is BaseDeployIO {
return _release; return _release;
} }
function standardVersionsToml() public view returns (string memory) {
require(!LibString.eq(_standardVersionsToml, ""), "DeployImplementationsInput: not set");
return _standardVersionsToml;
}
function superchainConfigProxy() public view returns (SuperchainConfig) { function superchainConfigProxy() public view returns (SuperchainConfig) {
require(address(_superchainConfigProxy) != address(0), "DeployImplementationsInput: not set"); require(address(_superchainConfigProxy) != address(0), "DeployImplementationsInput: not set");
return _superchainConfigProxy; return _superchainConfigProxy;
...@@ -159,6 +167,7 @@ contract DeployImplementationsInput is BaseDeployIO { ...@@ -159,6 +167,7 @@ contract DeployImplementationsInput is BaseDeployIO {
contract DeployImplementationsOutput is BaseDeployIO { contract DeployImplementationsOutput is BaseDeployIO {
OPStackManager internal _opsmProxy; OPStackManager internal _opsmProxy;
OPStackManager internal _opsmImpl;
DelayedWETH internal _delayedWETHImpl; DelayedWETH internal _delayedWETHImpl;
OptimismPortal2 internal _optimismPortalImpl; OptimismPortal2 internal _optimismPortalImpl;
PreimageOracle internal _preimageOracleSingleton; PreimageOracle internal _preimageOracleSingleton;
...@@ -175,6 +184,7 @@ contract DeployImplementationsOutput is BaseDeployIO { ...@@ -175,6 +184,7 @@ contract DeployImplementationsOutput is BaseDeployIO {
// forgefmt: disable-start // forgefmt: disable-start
if (sel == this.opsmProxy.selector) _opsmProxy = OPStackManager(payable(_addr)); if (sel == this.opsmProxy.selector) _opsmProxy = OPStackManager(payable(_addr));
else if (sel == this.opsmImpl.selector) _opsmImpl = OPStackManager(payable(_addr));
else if (sel == this.optimismPortalImpl.selector) _optimismPortalImpl = OptimismPortal2(payable(_addr)); else if (sel == this.optimismPortalImpl.selector) _optimismPortalImpl = OptimismPortal2(payable(_addr));
else if (sel == this.delayedWETHImpl.selector) _delayedWETHImpl = DelayedWETH(payable(_addr)); else if (sel == this.delayedWETHImpl.selector) _delayedWETHImpl = DelayedWETH(payable(_addr));
else if (sel == this.preimageOracleSingleton.selector) _preimageOracleSingleton = PreimageOracle(_addr); else if (sel == this.preimageOracleSingleton.selector) _preimageOracleSingleton = PreimageOracle(_addr);
...@@ -190,12 +200,18 @@ contract DeployImplementationsOutput is BaseDeployIO { ...@@ -190,12 +200,18 @@ contract DeployImplementationsOutput is BaseDeployIO {
} }
function checkOutput(DeployImplementationsInput _dii) public { function checkOutput(DeployImplementationsInput _dii) public {
address[] memory addrs = Solarray.addresses( // With 12 addresses, we'd get a stack too deep error if we tried to do this inline as a
// single call to `Solarray.addresses`. So we split it into two calls.
address[] memory addrs1 = Solarray.addresses(
address(this.opsmProxy()), address(this.opsmProxy()),
address(this.opsmImpl()),
address(this.optimismPortalImpl()), address(this.optimismPortalImpl()),
address(this.delayedWETHImpl()), address(this.delayedWETHImpl()),
address(this.preimageOracleSingleton()), address(this.preimageOracleSingleton()),
address(this.mipsSingleton()), address(this.mipsSingleton())
);
address[] memory addrs2 = Solarray.addresses(
address(this.systemConfigImpl()), address(this.systemConfigImpl()),
address(this.l1CrossDomainMessengerImpl()), address(this.l1CrossDomainMessengerImpl()),
address(this.l1ERC721BridgeImpl()), address(this.l1ERC721BridgeImpl()),
...@@ -203,7 +219,8 @@ contract DeployImplementationsOutput is BaseDeployIO { ...@@ -203,7 +219,8 @@ contract DeployImplementationsOutput is BaseDeployIO {
address(this.optimismMintableERC20FactoryImpl()), address(this.optimismMintableERC20FactoryImpl()),
address(this.disputeGameFactoryImpl()) address(this.disputeGameFactoryImpl())
); );
DeployUtils.assertValidContractAddresses(addrs);
DeployUtils.assertValidContractAddresses(Solarray.extend(addrs1, addrs2));
assertValidDeploy(_dii); assertValidDeploy(_dii);
} }
...@@ -214,6 +231,11 @@ contract DeployImplementationsOutput is BaseDeployIO { ...@@ -214,6 +231,11 @@ contract DeployImplementationsOutput is BaseDeployIO {
return _opsmProxy; return _opsmProxy;
} }
function opsmImpl() public view returns (OPStackManager) {
DeployUtils.assertValidContractAddress(address(_opsmImpl));
return _opsmImpl;
}
function optimismPortalImpl() public view returns (OptimismPortal2) { function optimismPortalImpl() public view returns (OptimismPortal2) {
DeployUtils.assertValidContractAddress(address(_optimismPortalImpl)); DeployUtils.assertValidContractAddress(address(_optimismPortalImpl));
return _optimismPortalImpl; return _optimismPortalImpl;
...@@ -474,26 +496,30 @@ contract DeployImplementations is Script { ...@@ -474,26 +496,30 @@ contract DeployImplementations is Script {
// Deploy and initialize a proxied OPStackManager. // Deploy and initialize a proxied OPStackManager.
function createOPSMContract( function createOPSMContract(
DeployImplementationsInput _dii, DeployImplementationsInput _dii,
DeployImplementationsOutput, DeployImplementationsOutput _dio,
OPStackManager.Blueprints memory blueprints, OPStackManager.Blueprints memory _blueprints,
string memory release, string memory _release,
OPStackManager.ImplementationSetter[] memory setters OPStackManager.ImplementationSetter[] memory _setters
) )
internal internal
virtual virtual
returns (OPStackManager opsmProxy_) returns (OPStackManager opsmProxy_)
{ {
SuperchainConfig superchainConfigProxy = _dii.superchainConfigProxy();
ProtocolVersions protocolVersionsProxy = _dii.protocolVersionsProxy();
ProxyAdmin proxyAdmin = _dii.superchainProxyAdmin(); ProxyAdmin proxyAdmin = _dii.superchainProxyAdmin();
vm.startBroadcast(msg.sender); vm.broadcast(msg.sender);
Proxy proxy = new Proxy(address(msg.sender)); Proxy proxy = new Proxy(address(msg.sender));
OPStackManager opsm = new OPStackManager(superchainConfigProxy, protocolVersionsProxy);
deployOPContractsManagerImpl(_dii, _dio);
OPStackManager opsmImpl = _dio.opsmImpl();
OPStackManager.InitializerInputs memory initializerInputs = OPStackManager.InitializerInputs memory initializerInputs =
OPStackManager.InitializerInputs(blueprints, setters, release, true); OPStackManager.InitializerInputs(_blueprints, _setters, _release, true);
proxy.upgradeToAndCall(address(opsm), abi.encodeWithSelector(opsm.initialize.selector, initializerInputs));
vm.startBroadcast(msg.sender);
proxy.upgradeToAndCall(
address(opsmImpl), abi.encodeWithSelector(opsmImpl.initialize.selector, initializerInputs)
);
proxy.changeAdmin(address(proxyAdmin)); // transfer ownership of Proxy contract to the ProxyAdmin contract proxy.changeAdmin(address(proxyAdmin)); // transfer ownership of Proxy contract to the ProxyAdmin contract
vm.stopBroadcast(); vm.stopBroadcast();
...@@ -572,56 +598,148 @@ contract DeployImplementations is Script { ...@@ -572,56 +598,148 @@ contract DeployImplementations is Script {
// --- Core Contracts --- // --- Core Contracts ---
function deploySystemConfigImpl(DeployImplementationsInput, DeployImplementationsOutput _dio) public virtual { function deploySystemConfigImpl(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual {
vm.broadcast(msg.sender); string memory release = _dii.release();
SystemConfig systemConfigImpl = new SystemConfig(); string memory stdVerToml = _dii.standardVersionsToml();
// Using snake case for contract name to match the TOML file in superchain-registry.
string memory contractName = "system_config";
SystemConfig impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = SystemConfig(existingImplementation);
} else if (isDevelopRelease(release)) {
// Deploy a new implementation for development builds.
vm.broadcast(msg.sender);
impl = new SystemConfig();
} else {
revert(string.concat("DeployImplementations: failed to deploy release ", release));
}
vm.label(address(systemConfigImpl), "SystemConfigImpl"); vm.label(address(impl), "SystemConfigImpl");
_dio.set(_dio.systemConfigImpl.selector, address(systemConfigImpl)); _dio.set(_dio.systemConfigImpl.selector, address(impl));
} }
function deployL1CrossDomainMessengerImpl( function deployL1CrossDomainMessengerImpl(
DeployImplementationsInput, DeployImplementationsInput _dii,
DeployImplementationsOutput _dio DeployImplementationsOutput _dio
) )
public public
virtual virtual
{ {
vm.broadcast(msg.sender); string memory release = _dii.release();
L1CrossDomainMessenger l1CrossDomainMessengerImpl = new L1CrossDomainMessenger(); string memory stdVerToml = _dii.standardVersionsToml();
string memory contractName = "l1_cross_domain_messenger";
L1CrossDomainMessenger impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = L1CrossDomainMessenger(existingImplementation);
} else if (isDevelopRelease(release)) {
vm.broadcast(msg.sender);
impl = new L1CrossDomainMessenger();
} else {
revert(string.concat("DeployImplementations: failed to deploy release ", release));
}
vm.label(address(l1CrossDomainMessengerImpl), "L1CrossDomainMessengerImpl"); vm.label(address(impl), "L1CrossDomainMessengerImpl");
_dio.set(_dio.l1CrossDomainMessengerImpl.selector, address(l1CrossDomainMessengerImpl)); _dio.set(_dio.l1CrossDomainMessengerImpl.selector, address(impl));
} }
function deployL1ERC721BridgeImpl(DeployImplementationsInput, DeployImplementationsOutput _dio) public virtual { function deployL1ERC721BridgeImpl(
vm.broadcast(msg.sender); DeployImplementationsInput _dii,
L1ERC721Bridge l1ERC721BridgeImpl = new L1ERC721Bridge(); DeployImplementationsOutput _dio
)
public
virtual
{
string memory release = _dii.release();
string memory stdVerToml = _dii.standardVersionsToml();
string memory contractName = "l1_erc721_bridge";
L1ERC721Bridge impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = L1ERC721Bridge(existingImplementation);
} else if (isDevelopRelease(release)) {
vm.broadcast(msg.sender);
impl = new L1ERC721Bridge();
} else {
revert(string.concat("DeployImplementations: failed to deploy release ", release));
}
vm.label(address(l1ERC721BridgeImpl), "L1ERC721BridgeImpl"); vm.label(address(impl), "L1ERC721BridgeImpl");
_dio.set(_dio.l1ERC721BridgeImpl.selector, address(l1ERC721BridgeImpl)); _dio.set(_dio.l1ERC721BridgeImpl.selector, address(impl));
} }
function deployL1StandardBridgeImpl(DeployImplementationsInput, DeployImplementationsOutput _dio) public virtual { function deployL1StandardBridgeImpl(
vm.broadcast(msg.sender); DeployImplementationsInput _dii,
L1StandardBridge l1StandardBridgeImpl = new L1StandardBridge(); DeployImplementationsOutput _dio
)
public
virtual
{
string memory release = _dii.release();
string memory stdVerToml = _dii.standardVersionsToml();
string memory contractName = "l1_standard_bridge";
L1StandardBridge impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = L1StandardBridge(payable(existingImplementation));
} else if (isDevelopRelease(release)) {
vm.broadcast(msg.sender);
impl = new L1StandardBridge();
} else {
revert(string.concat("DeployImplementations: failed to deploy release ", release));
}
vm.label(address(l1StandardBridgeImpl), "L1StandardBridgeImpl"); vm.label(address(impl), "L1StandardBridgeImpl");
_dio.set(_dio.l1StandardBridgeImpl.selector, address(l1StandardBridgeImpl)); _dio.set(_dio.l1StandardBridgeImpl.selector, address(impl));
} }
function deployOptimismMintableERC20FactoryImpl( function deployOptimismMintableERC20FactoryImpl(
DeployImplementationsInput, DeployImplementationsInput _dii,
DeployImplementationsOutput _dio DeployImplementationsOutput _dio
) )
public public
virtual virtual
{ {
string memory release = _dii.release();
string memory stdVerToml = _dii.standardVersionsToml();
string memory contractName = "optimism_mintable_erc20_factory";
OptimismMintableERC20Factory impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = OptimismMintableERC20Factory(existingImplementation);
} else if (isDevelopRelease(release)) {
vm.broadcast(msg.sender);
impl = new OptimismMintableERC20Factory();
} else {
revert(string.concat("DeployImplementations: failed to deploy release ", release));
}
vm.label(address(impl), "OptimismMintableERC20FactoryImpl");
_dio.set(_dio.optimismMintableERC20FactoryImpl.selector, address(impl));
}
function deployOPContractsManagerImpl(
DeployImplementationsInput _dii,
DeployImplementationsOutput _dio
)
public
virtual
{
SuperchainConfig superchainConfigProxy = _dii.superchainConfigProxy();
ProtocolVersions protocolVersionsProxy = _dii.protocolVersionsProxy();
vm.broadcast(msg.sender); vm.broadcast(msg.sender);
OptimismMintableERC20Factory optimismMintableERC20FactoryImpl = new OptimismMintableERC20Factory(); // TODO: Eventually we will want to select the correct implementation based on the release.
OPStackManager impl = new OPStackManager(superchainConfigProxy, protocolVersionsProxy);
vm.label(address(optimismMintableERC20FactoryImpl), "OptimismMintableERC20FactoryImpl"); vm.label(address(impl), "OPStackManagerImpl");
_dio.set(_dio.optimismMintableERC20FactoryImpl.selector, address(optimismMintableERC20FactoryImpl)); _dio.set(_dio.opsmImpl.selector, address(impl));
} }
// --- Fault Proofs Contracts --- // --- Fault Proofs Contracts ---
...@@ -659,27 +777,46 @@ contract DeployImplementations is Script { ...@@ -659,27 +777,46 @@ contract DeployImplementations is Script {
public public
virtual virtual
{ {
uint256 proofMaturityDelaySeconds = _dii.proofMaturityDelaySeconds(); string memory release = _dii.release();
uint256 disputeGameFinalityDelaySeconds = _dii.disputeGameFinalityDelaySeconds(); string memory stdVerToml = _dii.standardVersionsToml();
string memory contractName = "optimism_portal";
vm.broadcast(msg.sender); OptimismPortal2 impl;
OptimismPortal2 optimismPortalImpl = new OptimismPortal2({
_proofMaturityDelaySeconds: proofMaturityDelaySeconds, address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
_disputeGameFinalityDelaySeconds: disputeGameFinalityDelaySeconds if (existingImplementation != address(0)) {
}); impl = OptimismPortal2(payable(existingImplementation));
} else if (isDevelopRelease(release)) {
uint256 proofMaturityDelaySeconds = _dii.proofMaturityDelaySeconds();
uint256 disputeGameFinalityDelaySeconds = _dii.disputeGameFinalityDelaySeconds();
vm.broadcast(msg.sender);
impl = new OptimismPortal2(proofMaturityDelaySeconds, disputeGameFinalityDelaySeconds);
} else {
revert(string.concat("DeployImplementations: failed to deploy release ", release));
}
vm.label(address(optimismPortalImpl), "OptimismPortalImpl"); vm.label(address(impl), "OptimismPortalImpl");
_dio.set(_dio.optimismPortalImpl.selector, address(optimismPortalImpl)); _dio.set(_dio.optimismPortalImpl.selector, address(impl));
} }
function deployDelayedWETHImpl(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual { function deployDelayedWETHImpl(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual {
uint256 withdrawalDelaySeconds = _dii.withdrawalDelaySeconds(); string memory release = _dii.release();
string memory stdVerToml = _dii.standardVersionsToml();
vm.broadcast(msg.sender); string memory contractName = "delayed_weth";
DelayedWETH delayedWETHImpl = new DelayedWETH({ _delay: withdrawalDelaySeconds }); DelayedWETH impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = DelayedWETH(payable(existingImplementation));
} else if (isDevelopRelease(release)) {
uint256 withdrawalDelaySeconds = _dii.withdrawalDelaySeconds();
vm.broadcast(msg.sender);
impl = new DelayedWETH(withdrawalDelaySeconds);
} else {
revert(string.concat("DeployImplementations: failed to deploy release ", release));
}
vm.label(address(delayedWETHImpl), "DelayedWETHImpl"); vm.label(address(impl), "DelayedWETHImpl");
_dio.set(_dio.delayedWETHImpl.selector, address(delayedWETHImpl)); _dio.set(_dio.delayedWETHImpl.selector, address(impl));
} }
function deployPreimageOracleSingleton( function deployPreimageOracleSingleton(
...@@ -689,39 +826,72 @@ contract DeployImplementations is Script { ...@@ -689,39 +826,72 @@ contract DeployImplementations is Script {
public public
virtual virtual
{ {
uint256 minProposalSizeBytes = _dii.minProposalSizeBytes(); string memory release = _dii.release();
uint256 challengePeriodSeconds = _dii.challengePeriodSeconds(); string memory stdVerToml = _dii.standardVersionsToml();
string memory contractName = "preimage_oracle";
vm.broadcast(msg.sender); PreimageOracle singleton;
PreimageOracle preimageOracleSingleton =
new PreimageOracle({ _minProposalSize: minProposalSizeBytes, _challengePeriod: challengePeriodSeconds }); address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
singleton = PreimageOracle(payable(existingImplementation));
} else if (isDevelopRelease(release)) {
uint256 minProposalSizeBytes = _dii.minProposalSizeBytes();
uint256 challengePeriodSeconds = _dii.challengePeriodSeconds();
vm.broadcast(msg.sender);
singleton = new PreimageOracle(minProposalSizeBytes, challengePeriodSeconds);
} else {
revert(string.concat("DeployImplementations: failed to deploy release ", release));
}
vm.label(address(preimageOracleSingleton), "PreimageOracleSingleton"); vm.label(address(singleton), "PreimageOracleSingleton");
_dio.set(_dio.preimageOracleSingleton.selector, address(preimageOracleSingleton)); _dio.set(_dio.preimageOracleSingleton.selector, address(singleton));
} }
function deployMipsSingleton(DeployImplementationsInput, DeployImplementationsOutput _dio) public virtual { function deployMipsSingleton(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual {
IPreimageOracle preimageOracle = IPreimageOracle(_dio.preimageOracleSingleton()); string memory release = _dii.release();
string memory stdVerToml = _dii.standardVersionsToml();
vm.broadcast(msg.sender); string memory contractName = "mips";
MIPS mipsSingleton = new MIPS(preimageOracle); MIPS singleton;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
singleton = MIPS(payable(existingImplementation));
} else if (isDevelopRelease(release)) {
IPreimageOracle preimageOracle = IPreimageOracle(_dio.preimageOracleSingleton());
vm.broadcast(msg.sender);
singleton = new MIPS(preimageOracle);
} else {
revert(string.concat("DeployImplementations: failed to deploy release ", release));
}
vm.label(address(mipsSingleton), "MIPSSingleton"); vm.label(address(singleton), "MIPSSingleton");
_dio.set(_dio.mipsSingleton.selector, address(mipsSingleton)); _dio.set(_dio.mipsSingleton.selector, address(singleton));
} }
function deployDisputeGameFactoryImpl( function deployDisputeGameFactoryImpl(
DeployImplementationsInput, DeployImplementationsInput _dii,
DeployImplementationsOutput _dio DeployImplementationsOutput _dio
) )
public public
virtual virtual
{ {
vm.broadcast(msg.sender); string memory release = _dii.release();
DisputeGameFactory disputeGameFactoryImpl = new DisputeGameFactory(); string memory stdVerToml = _dii.standardVersionsToml();
string memory contractName = "dispute_game_factory";
DisputeGameFactory impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = DisputeGameFactory(payable(existingImplementation));
} else if (isDevelopRelease(release)) {
vm.broadcast(msg.sender);
impl = new DisputeGameFactory();
} else {
revert(string.concat("DeployImplementations: failed to deploy release ", release));
}
vm.label(address(disputeGameFactoryImpl), "DisputeGameFactoryImpl"); vm.label(address(impl), "DisputeGameFactoryImpl");
_dio.set(_dio.disputeGameFactoryImpl.selector, address(disputeGameFactoryImpl)); _dio.set(_dio.disputeGameFactoryImpl.selector, address(impl));
} }
// -------- Utilities -------- // -------- Utilities --------
...@@ -763,6 +933,35 @@ contract DeployImplementations is Script { ...@@ -763,6 +933,35 @@ contract DeployImplementations is Script {
newContract1_ = deployBytecode(part1, _salt); newContract1_ = deployBytecode(part1, _salt);
newContract2_ = deployBytecode(part2, _salt); newContract2_ = deployBytecode(part2, _salt);
} }
// Zero address is returned if the address is not found in '_standardVersionsToml'.
function getReleaseAddress(
string memory _version,
string memory _contractName,
string memory _standardVersionsToml
)
internal
pure
returns (address addr_)
{
string memory baseKey = string.concat('.releases["', _version, '"].', _contractName);
string memory implAddressKey = string.concat(baseKey, ".implementation_address");
string memory addressKey = string.concat(baseKey, ".address");
try vm.parseTomlAddress(_standardVersionsToml, implAddressKey) returns (address parsedAddr_) {
addr_ = parsedAddr_;
} catch {
try vm.parseTomlAddress(_standardVersionsToml, addressKey) returns (address parsedAddr_) {
addr_ = parsedAddr_;
} catch {
addr_ = address(0);
}
}
}
// A release is considered a 'develop' release if it does not start with 'op-contracts'.
function isDevelopRelease(string memory _release) internal pure returns (bool) {
return !LibString.startsWith(_release, "op-contracts");
}
} }
// Similar to how DeploySuperchain.s.sol contains a lot of comments to thoroughly document the script // Similar to how DeploySuperchain.s.sol contains a lot of comments to thoroughly document the script
...@@ -800,26 +999,30 @@ contract DeployImplementations is Script { ...@@ -800,26 +999,30 @@ contract DeployImplementations is Script {
contract DeployImplementationsInterop is DeployImplementations { contract DeployImplementationsInterop is DeployImplementations {
function createOPSMContract( function createOPSMContract(
DeployImplementationsInput _dii, DeployImplementationsInput _dii,
DeployImplementationsOutput, DeployImplementationsOutput _dio,
OPStackManager.Blueprints memory blueprints, OPStackManager.Blueprints memory _blueprints,
string memory release, string memory _release,
OPStackManager.ImplementationSetter[] memory setters OPStackManager.ImplementationSetter[] memory _setters
) )
internal internal
override override
returns (OPStackManager opsmProxy_) returns (OPStackManager opsmProxy_)
{ {
SuperchainConfig superchainConfigProxy = _dii.superchainConfigProxy();
ProtocolVersions protocolVersionsProxy = _dii.protocolVersionsProxy();
ProxyAdmin proxyAdmin = _dii.superchainProxyAdmin(); ProxyAdmin proxyAdmin = _dii.superchainProxyAdmin();
vm.startBroadcast(msg.sender); vm.broadcast(msg.sender);
Proxy proxy = new Proxy(address(msg.sender)); Proxy proxy = new Proxy(address(msg.sender));
OPStackManager opsm = new OPStackManagerInterop(superchainConfigProxy, protocolVersionsProxy);
deployOPContractsManagerImpl(_dii, _dio); // overriding function
OPStackManager opsmImpl = _dio.opsmImpl();
OPStackManager.InitializerInputs memory initializerInputs = OPStackManager.InitializerInputs memory initializerInputs =
OPStackManager.InitializerInputs(blueprints, setters, release, true); OPStackManager.InitializerInputs(_blueprints, _setters, _release, true);
proxy.upgradeToAndCall(address(opsm), abi.encodeWithSelector(opsm.initialize.selector, initializerInputs));
vm.startBroadcast(msg.sender);
proxy.upgradeToAndCall(
address(opsmImpl), abi.encodeWithSelector(opsmImpl.initialize.selector, initializerInputs)
);
proxy.changeAdmin(address(proxyAdmin)); // transfer ownership of Proxy contract to the ProxyAdmin contract proxy.changeAdmin(address(proxyAdmin)); // transfer ownership of Proxy contract to the ProxyAdmin contract
vm.stopBroadcast(); vm.stopBroadcast();
...@@ -834,25 +1037,70 @@ contract DeployImplementationsInterop is DeployImplementations { ...@@ -834,25 +1037,70 @@ contract DeployImplementationsInterop is DeployImplementations {
public public
override override
{ {
uint256 proofMaturityDelaySeconds = _dii.proofMaturityDelaySeconds(); string memory release = _dii.release();
uint256 disputeGameFinalityDelaySeconds = _dii.disputeGameFinalityDelaySeconds(); string memory stdVerToml = _dii.standardVersionsToml();
string memory contractName = "optimism_portal";
OptimismPortal2 impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = OptimismPortalInterop(payable(existingImplementation));
} else if (isDevelopRelease(release)) {
uint256 proofMaturityDelaySeconds = _dii.proofMaturityDelaySeconds();
uint256 disputeGameFinalityDelaySeconds = _dii.disputeGameFinalityDelaySeconds();
vm.broadcast(msg.sender);
impl = new OptimismPortalInterop(proofMaturityDelaySeconds, disputeGameFinalityDelaySeconds);
} else {
revert(string.concat("DeployImplementations: failed to deploy release ", release));
}
vm.broadcast(msg.sender); vm.label(address(impl), "OptimismPortalImpl");
OptimismPortalInterop optimismPortalImpl = new OptimismPortalInterop({ _dio.set(_dio.optimismPortalImpl.selector, address(impl));
_proofMaturityDelaySeconds: proofMaturityDelaySeconds, }
_disputeGameFinalityDelaySeconds: disputeGameFinalityDelaySeconds
});
vm.label(address(optimismPortalImpl), "OptimismPortalImpl"); function deploySystemConfigImpl(
_dio.set(_dio.optimismPortalImpl.selector, address(optimismPortalImpl)); DeployImplementationsInput _dii,
DeployImplementationsOutput _dio
)
public
override
{
string memory release = _dii.release();
string memory stdVerToml = _dii.standardVersionsToml();
string memory contractName = "system_config";
SystemConfig impl;
address existingImplementation = getReleaseAddress(release, contractName, stdVerToml);
if (existingImplementation != address(0)) {
impl = SystemConfigInterop(existingImplementation);
} else if (isDevelopRelease(release)) {
vm.broadcast(msg.sender);
impl = new SystemConfigInterop();
} else {
revert(string.concat("DeployImplementations: failed to deploy release ", release));
}
vm.label(address(impl), "SystemConfigImpl");
_dio.set(_dio.systemConfigImpl.selector, address(impl));
} }
function deploySystemConfigImpl(DeployImplementationsInput, DeployImplementationsOutput _dio) public override { function deployOPContractsManagerImpl(
DeployImplementationsInput _dii,
DeployImplementationsOutput _dio
)
public
override
{
SuperchainConfig superchainConfigProxy = _dii.superchainConfigProxy();
ProtocolVersions protocolVersionsProxy = _dii.protocolVersionsProxy();
vm.broadcast(msg.sender); vm.broadcast(msg.sender);
SystemConfigInterop systemConfigImpl = new SystemConfigInterop(); // TODO: Eventually we will want to select the correct implementation based on the release.
OPStackManager impl = new OPStackManagerInterop(superchainConfigProxy, protocolVersionsProxy);
vm.label(address(systemConfigImpl), "SystemConfigImpl"); vm.label(address(impl), "OPStackManagerImpl");
_dio.set(_dio.systemConfigImpl.selector, address(systemConfigImpl)); _dio.set(_dio.opsmImpl.selector, address(impl));
} }
function opsmSystemConfigSetter( function opsmSystemConfigSetter(
......
...@@ -35,7 +35,7 @@ contract DeployImplementationsInput_Test is Test { ...@@ -35,7 +35,7 @@ contract DeployImplementationsInput_Test is Test {
uint256 challengePeriodSeconds = 300; uint256 challengePeriodSeconds = 300;
uint256 proofMaturityDelaySeconds = 400; uint256 proofMaturityDelaySeconds = 400;
uint256 disputeGameFinalityDelaySeconds = 500; uint256 disputeGameFinalityDelaySeconds = 500;
string release = "op-contracts/latest"; string release = "dev-release"; // this means implementation contracts will be deployed
SuperchainConfig superchainConfigProxy = SuperchainConfig(makeAddr("superchainConfigProxy")); SuperchainConfig superchainConfigProxy = SuperchainConfig(makeAddr("superchainConfigProxy"));
ProtocolVersions protocolVersionsProxy = ProtocolVersions(makeAddr("protocolVersionsProxy")); ProtocolVersions protocolVersionsProxy = ProtocolVersions(makeAddr("protocolVersionsProxy"));
...@@ -70,6 +70,9 @@ contract DeployImplementationsInput_Test is Test { ...@@ -70,6 +70,9 @@ contract DeployImplementationsInput_Test is Test {
vm.expectRevert("DeployImplementationsInput: not set"); vm.expectRevert("DeployImplementationsInput: not set");
dii.superchainProxyAdmin(); dii.superchainProxyAdmin();
vm.expectRevert("DeployImplementationsInput: not set");
dii.standardVersionsToml();
} }
function test_superchainProxyAdmin_whenNotSet_reverts() public { function test_superchainProxyAdmin_whenNotSet_reverts() public {
...@@ -247,13 +250,18 @@ contract DeployImplementations_Test is Test { ...@@ -247,13 +250,18 @@ contract DeployImplementations_Test is Test {
uint256 challengePeriodSeconds = 300; uint256 challengePeriodSeconds = 300;
uint256 proofMaturityDelaySeconds = 400; uint256 proofMaturityDelaySeconds = 400;
uint256 disputeGameFinalityDelaySeconds = 500; uint256 disputeGameFinalityDelaySeconds = 500;
string release = "op-contracts/latest";
SuperchainConfig superchainConfigProxy = SuperchainConfig(makeAddr("superchainConfigProxy")); SuperchainConfig superchainConfigProxy = SuperchainConfig(makeAddr("superchainConfigProxy"));
ProtocolVersions protocolVersionsProxy = ProtocolVersions(makeAddr("protocolVersionsProxy")); ProtocolVersions protocolVersionsProxy = ProtocolVersions(makeAddr("protocolVersionsProxy"));
function setUp() public virtual { function setUp() public virtual {
deployImplementations = new DeployImplementations(); deployImplementations = new DeployImplementations();
(dii, dio) = deployImplementations.etchIOContracts(); (dii, dio) = deployImplementations.etchIOContracts();
// 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);
} }
// By deploying the `DeployImplementations` contract with this virtual function, we provide a // By deploying the `DeployImplementations` contract with this virtual function, we provide a
...@@ -267,13 +275,142 @@ contract DeployImplementations_Test is Test { ...@@ -267,13 +275,142 @@ contract DeployImplementations_Test is Test {
return keccak256(abi.encode(_seed, _i)); return keccak256(abi.encode(_seed, _i));
} }
function test_deployImplementation_succeeds() public {
string memory deployContractsRelease = "dev-release";
dii.set(dii.release.selector, deployContractsRelease);
deployImplementations.deploySystemConfigImpl(dii, dio);
assertTrue(address(0) != address(dio.systemConfigImpl()));
}
function test_reuseImplementation_succeeds() public {
// All hardcoded addresses below are taken from the superchain-registry config:
// https://github.com/ethereum-optimism/superchain-registry/blob/be65d22f8128cf0c4e5b4e1f677daf86843426bf/validation/standard/standard-versions.toml#L11
string memory testRelease = "op-contracts/v1.6.0";
dii.set(dii.release.selector, testRelease);
deployImplementations.deploySystemConfigImpl(dii, dio);
address srSystemConfigImpl = address(0xF56D96B2535B932656d3c04Ebf51baBff241D886);
vm.etch(address(srSystemConfigImpl), hex"01");
assertEq(srSystemConfigImpl, address(dio.systemConfigImpl()));
address srL1CrossDomainMessengerImpl = address(0xD3494713A5cfaD3F5359379DfA074E2Ac8C6Fd65);
vm.etch(address(srL1CrossDomainMessengerImpl), hex"01");
deployImplementations.deployL1CrossDomainMessengerImpl(dii, dio);
assertEq(srL1CrossDomainMessengerImpl, address(dio.l1CrossDomainMessengerImpl()));
address srL1ERC721BridgeImpl = address(0xAE2AF01232a6c4a4d3012C5eC5b1b35059caF10d);
vm.etch(address(srL1ERC721BridgeImpl), hex"01");
deployImplementations.deployL1ERC721BridgeImpl(dii, dio);
assertEq(srL1ERC721BridgeImpl, address(dio.l1ERC721BridgeImpl()));
address srL1StandardBridgeImpl = address(0x64B5a5Ed26DCb17370Ff4d33a8D503f0fbD06CfF);
vm.etch(address(srL1StandardBridgeImpl), hex"01");
deployImplementations.deployL1StandardBridgeImpl(dii, dio);
assertEq(srL1StandardBridgeImpl, address(dio.l1StandardBridgeImpl()));
address srOptimismMintableERC20FactoryImpl = address(0xE01efbeb1089D1d1dB9c6c8b135C934C0734c846);
vm.etch(address(srOptimismMintableERC20FactoryImpl), hex"01");
deployImplementations.deployOptimismMintableERC20FactoryImpl(dii, dio);
assertEq(srOptimismMintableERC20FactoryImpl, address(dio.optimismMintableERC20FactoryImpl()));
address srOptimismPortalImpl = address(0xe2F826324b2faf99E513D16D266c3F80aE87832B);
vm.etch(address(srOptimismPortalImpl), hex"01");
deployImplementations.deployOptimismPortalImpl(dii, dio);
assertEq(srOptimismPortalImpl, address(dio.optimismPortalImpl()));
address srDelayedWETHImpl = address(0x71e966Ae981d1ce531a7b6d23DC0f27B38409087);
vm.etch(address(srDelayedWETHImpl), hex"01");
deployImplementations.deployDelayedWETHImpl(dii, dio);
assertEq(srDelayedWETHImpl, address(dio.delayedWETHImpl()));
address srPreimageOracleSingleton = address(0x9c065e11870B891D214Bc2Da7EF1f9DDFA1BE277);
vm.etch(address(srPreimageOracleSingleton), hex"01");
deployImplementations.deployPreimageOracleSingleton(dii, dio);
assertEq(srPreimageOracleSingleton, address(dio.preimageOracleSingleton()));
address srMipsSingleton = address(0x16e83cE5Ce29BF90AD9Da06D2fE6a15d5f344ce4);
vm.etch(address(srMipsSingleton), hex"01");
deployImplementations.deployMipsSingleton(dii, dio);
assertEq(srMipsSingleton, address(dio.mipsSingleton()));
address srDisputeGameFactoryImpl = address(0xc641A33cab81C559F2bd4b21EA34C290E2440C2B);
vm.etch(address(srDisputeGameFactoryImpl), hex"01");
deployImplementations.deployDisputeGameFactoryImpl(dii, dio);
assertEq(srDisputeGameFactoryImpl, address(dio.disputeGameFactoryImpl()));
}
function test_deployAtNonExistentRelease_reverts() public {
string memory unknownRelease = "op-contracts/v0.0.0";
dii.set(dii.release.selector, unknownRelease);
bytes memory expectedErr =
bytes(string.concat("DeployImplementations: failed to deploy release ", unknownRelease));
vm.expectRevert(expectedErr);
deployImplementations.deploySystemConfigImpl(dii, dio);
vm.expectRevert(expectedErr);
deployImplementations.deployL1CrossDomainMessengerImpl(dii, dio);
vm.expectRevert(expectedErr);
deployImplementations.deployL1ERC721BridgeImpl(dii, dio);
vm.expectRevert(expectedErr);
deployImplementations.deployL1StandardBridgeImpl(dii, dio);
vm.expectRevert(expectedErr);
deployImplementations.deployOptimismMintableERC20FactoryImpl(dii, dio);
// TODO: Uncomment the code below when OPContractsManager is deployed based on release. Superchain-registry
// doesn't contain OPContractsManager yet.
// dii.set(dii.superchainConfigProxy.selector, address(superchainConfigProxy));
// dii.set(dii.protocolVersionsProxy.selector, address(protocolVersionsProxy));
// vm.etch(address(superchainConfigProxy), hex"01");
// vm.etch(address(protocolVersionsProxy), hex"01");
// vm.expectRevert(expectedErr);
// deployImplementations.deployOPContractsManagerImpl(dii, dio);
dii.set(dii.proofMaturityDelaySeconds.selector, 1);
dii.set(dii.disputeGameFinalityDelaySeconds.selector, 2);
vm.expectRevert(expectedErr);
deployImplementations.deployOptimismPortalImpl(dii, dio);
dii.set(dii.withdrawalDelaySeconds.selector, 1);
vm.expectRevert(expectedErr);
deployImplementations.deployDelayedWETHImpl(dii, dio);
dii.set(dii.minProposalSizeBytes.selector, 1);
dii.set(dii.challengePeriodSeconds.selector, 2);
vm.expectRevert(expectedErr);
deployImplementations.deployPreimageOracleSingleton(dii, dio);
address preImageOracleSingleton = makeAddr("preImageOracleSingleton");
vm.etch(address(preImageOracleSingleton), hex"01");
dio.set(dio.preimageOracleSingleton.selector, preImageOracleSingleton);
vm.expectRevert(expectedErr);
deployImplementations.deployMipsSingleton(dii, dio);
vm.expectRevert(expectedErr); // fault proof contracts don't exist at this release
deployImplementations.deployDisputeGameFactoryImpl(dii, dio);
}
function test_noContractExistsAtRelease_reverts() public {
string memory unknownRelease = "op-contracts/v1.3.0";
dii.set(dii.release.selector, unknownRelease);
bytes memory expectedErr =
bytes(string.concat("DeployImplementations: failed to deploy release ", unknownRelease));
vm.expectRevert(expectedErr); // fault proof contracts don't exist at this release
deployImplementations.deployDisputeGameFactoryImpl(dii, dio);
}
function testFuzz_run_memory_succeeds(bytes32 _seed) public { function testFuzz_run_memory_succeeds(bytes32 _seed) public {
withdrawalDelaySeconds = uint256(hash(_seed, 0)); withdrawalDelaySeconds = uint256(hash(_seed, 0));
minProposalSizeBytes = uint256(hash(_seed, 1)); minProposalSizeBytes = uint256(hash(_seed, 1));
challengePeriodSeconds = bound(uint256(hash(_seed, 2)), 0, type(uint64).max); challengePeriodSeconds = bound(uint256(hash(_seed, 2)), 0, type(uint64).max);
proofMaturityDelaySeconds = uint256(hash(_seed, 3)); proofMaturityDelaySeconds = uint256(hash(_seed, 3));
disputeGameFinalityDelaySeconds = uint256(hash(_seed, 4)); disputeGameFinalityDelaySeconds = uint256(hash(_seed, 4));
release = string(bytes.concat(hash(_seed, 5))); string memory release = string(bytes.concat(hash(_seed, 5)));
protocolVersionsProxy = ProtocolVersions(address(uint160(uint256(hash(_seed, 7))))); protocolVersionsProxy = ProtocolVersions(address(uint160(uint256(hash(_seed, 7)))));
// Must configure the ProxyAdmin contract which is used to upgrade the OPSM's proxy contract. // Must configure the ProxyAdmin contract which is used to upgrade the OPSM's proxy contract.
...@@ -325,6 +462,7 @@ contract DeployImplementations_Test is Test { ...@@ -325,6 +462,7 @@ contract DeployImplementations_Test is Test {
dii.set(dii.challengePeriodSeconds.selector, challengePeriodSeconds); dii.set(dii.challengePeriodSeconds.selector, challengePeriodSeconds);
dii.set(dii.proofMaturityDelaySeconds.selector, proofMaturityDelaySeconds); dii.set(dii.proofMaturityDelaySeconds.selector, proofMaturityDelaySeconds);
dii.set(dii.disputeGameFinalityDelaySeconds.selector, disputeGameFinalityDelaySeconds); dii.set(dii.disputeGameFinalityDelaySeconds.selector, disputeGameFinalityDelaySeconds);
string memory release = "dev-release";
dii.set(dii.release.selector, release); dii.set(dii.release.selector, release);
dii.set(dii.superchainConfigProxy.selector, address(superchainConfigProxy)); dii.set(dii.superchainConfigProxy.selector, address(superchainConfigProxy));
dii.set(dii.protocolVersionsProxy.selector, address(protocolVersionsProxy)); dii.set(dii.protocolVersionsProxy.selector, address(protocolVersionsProxy));
......
...@@ -323,7 +323,7 @@ contract DeployOPChain_TestBase is Test { ...@@ -323,7 +323,7 @@ contract DeployOPChain_TestBase is Test {
uint256 challengePeriodSeconds = 300; uint256 challengePeriodSeconds = 300;
uint256 proofMaturityDelaySeconds = 400; uint256 proofMaturityDelaySeconds = 400;
uint256 disputeGameFinalityDelaySeconds = 500; uint256 disputeGameFinalityDelaySeconds = 500;
string release = "op-contracts/latest"; string release = "dev-release"; // this means implementation contracts will be deployed
SuperchainConfig superchainConfigProxy; SuperchainConfig superchainConfigProxy;
ProtocolVersions protocolVersionsProxy; ProtocolVersions protocolVersionsProxy;
...@@ -393,6 +393,11 @@ contract DeployOPChain_TestBase is Test { ...@@ -393,6 +393,11 @@ contract DeployOPChain_TestBase is Test {
dii.set(dii.release.selector, release); dii.set(dii.release.selector, release);
dii.set(dii.superchainConfigProxy.selector, address(superchainConfigProxy)); dii.set(dii.superchainConfigProxy.selector, address(superchainConfigProxy));
dii.set(dii.protocolVersionsProxy.selector, address(protocolVersionsProxy)); 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); deployImplementations.run(dii, dio);
// Set the OPStackManager input for DeployOPChain. // 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