diff --git a/op-chain-ops/script/script.go b/op-chain-ops/script/script.go index 9a3d9ae80201..7185c9e08b2d 100644 --- a/op-chain-ops/script/script.go +++ b/op-chain-ops/script/script.go @@ -440,6 +440,10 @@ func (h *Host) ImportAccount(addr common.Address, account types.Account) { } } +func (h *Host) SetStorage(addr common.Address, key common.Hash, value common.Hash) { + h.state.SetState(addr, key, value) +} + // getPrecompile overrides any accounts during runtime, to insert special precompiles, if activated. func (h *Host) getPrecompile(rules params.Rules, original vm.PrecompiledContract, addr common.Address) vm.PrecompiledContract { if p, ok := h.precompiles[addr]; ok { diff --git a/op-deployer/pkg/deployer/opcm/alphabet.go b/op-deployer/pkg/deployer/opcm/alphabet.go new file mode 100644 index 000000000000..a3d2016f3ef8 --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/alphabet.go @@ -0,0 +1,27 @@ +package opcm + +import ( + "github.com/ethereum-optimism/optimism/op-chain-ops/script" + "github.com/ethereum/go-ethereum/common" +) + +type DeployAlphabetVMInput struct { + AbsolutePrestate common.Hash + PreimageOracle common.Address +} + +type DeployAlphabetVMOutput struct { + AlphabetVM common.Address +} + +func DeployAlphabetVM( + host *script.Host, + input DeployAlphabetVMInput, +) (DeployAlphabetVMOutput, error) { + return RunScriptSingle[DeployAlphabetVMInput, DeployAlphabetVMOutput]( + host, + input, + "DeployAlphabetVM.s.sol", + "DeployAlphabetVM", + ) +} diff --git a/op-deployer/pkg/deployer/opcm/alphabet_test.go b/op-deployer/pkg/deployer/opcm/alphabet_test.go new file mode 100644 index 000000000000..a1595156ac1b --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/alphabet_test.go @@ -0,0 +1,37 @@ +package opcm + +import ( + "testing" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/testutil" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" +) + +func TestDeployAlphabetVM(t *testing.T) { + t.Parallel() + + _, artifacts := testutil.LocalArtifacts(t) + + host, err := env.DefaultScriptHost( + broadcaster.NoopBroadcaster(), + testlog.Logger(t, log.LevelInfo), + common.Address{'D'}, + artifacts, + ) + require.NoError(t, err) + + input := DeployAlphabetVMInput{ + AbsolutePrestate: common.Hash{'A'}, + PreimageOracle: common.Address{'O'}, + } + + output, err := DeployAlphabetVM(host, input) + require.NoError(t, err) + + require.NotEmpty(t, output.AlphabetVM) +} diff --git a/op-deployer/pkg/deployer/opcm/alt_da_test.go b/op-deployer/pkg/deployer/opcm/alt_da_test.go index 97e2b485b900..eab5d8b706ad 100644 --- a/op-deployer/pkg/deployer/opcm/alt_da_test.go +++ b/op-deployer/pkg/deployer/opcm/alt_da_test.go @@ -14,6 +14,8 @@ import ( ) func TestDeployAltDA(t *testing.T) { + t.Parallel() + _, artifacts := testutil.LocalArtifacts(t) host, err := env.DefaultScriptHost( diff --git a/op-deployer/pkg/deployer/opcm/asterisc.go b/op-deployer/pkg/deployer/opcm/asterisc.go index 053da43b4258..c034e6bf3ba5 100644 --- a/op-deployer/pkg/deployer/opcm/asterisc.go +++ b/op-deployer/pkg/deployer/opcm/asterisc.go @@ -26,5 +26,5 @@ func DeployAsterisc( host *script.Host, input DeployAsteriscInput, ) (DeployAsteriscOutput, error) { - return RunBasicScript[DeployAsteriscInput, DeployAsteriscOutput](host, input, "DeployAsterisc.s.sol", "DeployAsterisc") + return RunScriptSingle[DeployAsteriscInput, DeployAsteriscOutput](host, input, "DeployAsterisc.s.sol", "DeployAsterisc") } diff --git a/op-deployer/pkg/deployer/opcm/asterisc_test.go b/op-deployer/pkg/deployer/opcm/asterisc_test.go index 0ed68f7aeaff..91d463825d24 100644 --- a/op-deployer/pkg/deployer/opcm/asterisc_test.go +++ b/op-deployer/pkg/deployer/opcm/asterisc_test.go @@ -13,6 +13,8 @@ import ( ) func TestDeployAsterisc(t *testing.T) { + t.Parallel() + _, artifacts := testutil.LocalArtifacts(t) host, err := env.DefaultScriptHost( diff --git a/op-deployer/pkg/deployer/opcm/delayed_weth.go b/op-deployer/pkg/deployer/opcm/delayed_weth.go index 06f533956f89..ecee2a4df29f 100644 --- a/op-deployer/pkg/deployer/opcm/delayed_weth.go +++ b/op-deployer/pkg/deployer/opcm/delayed_weth.go @@ -34,5 +34,5 @@ func DeployDelayedWETH( host *script.Host, input DeployDelayedWETHInput, ) (DeployDelayedWETHOutput, error) { - return RunBasicScript[DeployDelayedWETHInput, DeployDelayedWETHOutput](host, input, "DeployDelayedWETH.s.sol", "DeployDelayedWETH") + return RunScriptSingle[DeployDelayedWETHInput, DeployDelayedWETHOutput](host, input, "DeployDelayedWETH.s.sol", "DeployDelayedWETH") } diff --git a/op-deployer/pkg/deployer/opcm/delayed_weth_test.go b/op-deployer/pkg/deployer/opcm/delayed_weth_test.go index 3a8be1b3e0d6..caa555ac0fcf 100644 --- a/op-deployer/pkg/deployer/opcm/delayed_weth_test.go +++ b/op-deployer/pkg/deployer/opcm/delayed_weth_test.go @@ -14,6 +14,8 @@ import ( ) func TestDeployDelayedWETH(t *testing.T) { + t.Parallel() + _, artifacts := testutil.LocalArtifacts(t) testCases := []struct { diff --git a/op-deployer/pkg/deployer/opcm/dispute_game.go b/op-deployer/pkg/deployer/opcm/dispute_game.go index 7128a08e8b02..b6e60dd0281d 100644 --- a/op-deployer/pkg/deployer/opcm/dispute_game.go +++ b/op-deployer/pkg/deployer/opcm/dispute_game.go @@ -44,5 +44,5 @@ func DeployDisputeGame( host *script.Host, input DeployDisputeGameInput, ) (DeployDisputeGameOutput, error) { - return RunBasicScript[DeployDisputeGameInput, DeployDisputeGameOutput](host, input, "DeployDisputeGame.s.sol", "DeployDisputeGame") + return RunScriptSingle[DeployDisputeGameInput, DeployDisputeGameOutput](host, input, "DeployDisputeGame.s.sol", "DeployDisputeGame") } diff --git a/op-deployer/pkg/deployer/opcm/dispute_game_factory.go b/op-deployer/pkg/deployer/opcm/dispute_game_factory.go new file mode 100644 index 000000000000..eb34e9f2206b --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/dispute_game_factory.go @@ -0,0 +1,24 @@ +package opcm + +import ( + "github.com/ethereum-optimism/optimism/op-chain-ops/script" + "github.com/ethereum/go-ethereum/common" +) + +type SetDisputeGameImplInput struct { + Factory common.Address + Impl common.Address + GameType uint32 +} + +func SetDisputeGameImpl( + h *script.Host, + input SetDisputeGameImplInput, +) error { + return RunScriptVoid[SetDisputeGameImplInput]( + h, + input, + "SetDisputeGameImpl.s.sol", + "SetDisputeGameImpl", + ) +} diff --git a/op-deployer/pkg/deployer/opcm/dispute_game_factory_test.go b/op-deployer/pkg/deployer/opcm/dispute_game_factory_test.go new file mode 100644 index 000000000000..c2003cb365ca --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/dispute_game_factory_test.go @@ -0,0 +1,55 @@ +package opcm + +import ( + "context" + "os" + "testing" + "time" + + "github.com/ethereum/go-ethereum/rpc" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/testutil" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" +) + +func TestSetDisputeGameImpl(t *testing.T) { + t.Parallel() + + _, artifacts := testutil.LocalArtifacts(t) + + l1RPCUrl := os.Getenv("SEPOLIA_RPC_URL") + require.NotEmpty(t, l1RPCUrl, "SEPOLIA_RPC_URL must be set") + + l1RPC, err := rpc.Dial(l1RPCUrl) + require.NoError(t, err) + + // OP Sepolia DGF owner + deployer := common.HexToAddress("0x1Eb2fFc903729a0F03966B917003800b145F56E2") + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + host, err := env.DefaultForkedScriptHost( + ctx, + broadcaster.NoopBroadcaster(), + testlog.Logger(t, log.LevelInfo), + deployer, + artifacts, + l1RPC, + ) + require.NoError(t, err) + + // Use OP Sepolia's dispute game factory + factoryAddr := common.HexToAddress("0x05F9613aDB30026FFd634f38e5C4dFd30a197Fa1") + + input := SetDisputeGameImplInput{ + Factory: factoryAddr, + Impl: common.Address{'I'}, + GameType: 999, + } + require.NoError(t, SetDisputeGameImpl(host, input)) +} diff --git a/op-deployer/pkg/deployer/opcm/dispute_game_test.go b/op-deployer/pkg/deployer/opcm/dispute_game_test.go index 2b2d33f9efe0..9fcae49ef555 100644 --- a/op-deployer/pkg/deployer/opcm/dispute_game_test.go +++ b/op-deployer/pkg/deployer/opcm/dispute_game_test.go @@ -15,6 +15,8 @@ import ( ) func TestDeployDisputeGame(t *testing.T) { + t.Parallel() + _, artifacts := testutil.LocalArtifacts(t) host, err := env.DefaultScriptHost( diff --git a/op-deployer/pkg/deployer/opcm/mips.go b/op-deployer/pkg/deployer/opcm/mips.go index 6150b3088351..77919ffbd796 100644 --- a/op-deployer/pkg/deployer/opcm/mips.go +++ b/op-deployer/pkg/deployer/opcm/mips.go @@ -31,5 +31,5 @@ func DeployMIPS( host *script.Host, input DeployMIPSInput, ) (DeployMIPSOutput, error) { - return RunBasicScript[DeployMIPSInput, DeployMIPSOutput](host, input, "DeployMIPS.s.sol", "DeployMIPS") + return RunScriptSingle[DeployMIPSInput, DeployMIPSOutput](host, input, "DeployMIPS.s.sol", "DeployMIPS") } diff --git a/op-deployer/pkg/deployer/opcm/mips_test.go b/op-deployer/pkg/deployer/opcm/mips_test.go index 848b46356525..1357c55cac90 100644 --- a/op-deployer/pkg/deployer/opcm/mips_test.go +++ b/op-deployer/pkg/deployer/opcm/mips_test.go @@ -13,6 +13,8 @@ import ( ) func TestDeployMIPS(t *testing.T) { + t.Parallel() + _, artifacts := testutil.LocalArtifacts(t) host, err := env.DefaultScriptHost( diff --git a/op-deployer/pkg/deployer/opcm/opchain.go b/op-deployer/pkg/deployer/opcm/opchain.go index 2a8664501337..69891358dfbe 100644 --- a/op-deployer/pkg/deployer/opcm/opchain.go +++ b/op-deployer/pkg/deployer/opcm/opchain.go @@ -88,7 +88,7 @@ func DeployOPChainIsthmus(host *script.Host, input DeployOPChainInputIsthmus) (D } func deployOPChain[T any](host *script.Host, input T) (DeployOPChainOutput, error) { - return RunBasicScript[T, DeployOPChainOutput](host, input, "DeployOPChain.s.sol", "DeployOPChain") + return RunScriptSingle[T, DeployOPChainOutput](host, input, "DeployOPChain.s.sol", "DeployOPChain") } type ReadImplementationAddressesInput struct { diff --git a/op-deployer/pkg/deployer/opcm/opcm.go b/op-deployer/pkg/deployer/opcm/opcm.go index 26179271b692..dbcc9281ee06 100644 --- a/op-deployer/pkg/deployer/opcm/opcm.go +++ b/op-deployer/pkg/deployer/opcm/opcm.go @@ -40,7 +40,7 @@ func DeployOPCM( host *script.Host, input DeployOPCMInput, ) (DeployOPCMOutput, error) { - out, err := RunBasicScript[DeployOPCMInput, DeployOPCMOutput](host, input, "DeployOPCM.s.sol", "DeployOPCM") + out, err := RunScriptSingle[DeployOPCMInput, DeployOPCMOutput](host, input, "DeployOPCM.s.sol", "DeployOPCM") if err != nil { return DeployOPCMOutput{}, fmt.Errorf("failed to deploy OPCM: %w", err) } diff --git a/op-deployer/pkg/deployer/opcm/preimage_oracle.go b/op-deployer/pkg/deployer/opcm/preimage_oracle.go new file mode 100644 index 000000000000..fb8a5c8e4c1a --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/preimage_oracle.go @@ -0,0 +1,29 @@ +package opcm + +import ( + "math/big" + + "github.com/ethereum-optimism/optimism/op-chain-ops/script" + "github.com/ethereum/go-ethereum/common" +) + +type DeployPreimageOracleInput struct { + MinProposalSize *big.Int + ChallengePeriod *big.Int +} + +type DeployPreimageOracleOutput struct { + PreimageOracle common.Address +} + +func DeployPreimageOracle( + host *script.Host, + input DeployPreimageOracleInput, +) (DeployPreimageOracleOutput, error) { + return RunScriptSingle[DeployPreimageOracleInput, DeployPreimageOracleOutput]( + host, + input, + "DeployPreimageOracle.s.sol", + "DeployPreimageOracle", + ) +} diff --git a/op-deployer/pkg/deployer/opcm/preimage_oracle_test.go b/op-deployer/pkg/deployer/opcm/preimage_oracle_test.go new file mode 100644 index 000000000000..04aeeca41785 --- /dev/null +++ b/op-deployer/pkg/deployer/opcm/preimage_oracle_test.go @@ -0,0 +1,38 @@ +package opcm + +import ( + "math/big" + "testing" + + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/broadcaster" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/testutil" + "github.com/ethereum-optimism/optimism/op-deployer/pkg/env" + "github.com/ethereum-optimism/optimism/op-service/testlog" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + "github.com/stretchr/testify/require" +) + +func TestDeployPreimageOracle(t *testing.T) { + t.Parallel() + + _, artifacts := testutil.LocalArtifacts(t) + + host, err := env.DefaultScriptHost( + broadcaster.NoopBroadcaster(), + testlog.Logger(t, log.LevelInfo), + common.Address{'D'}, + artifacts, + ) + require.NoError(t, err) + + input := DeployPreimageOracleInput{ + MinProposalSize: big.NewInt(123), + ChallengePeriod: big.NewInt(456), + } + + output, err := DeployPreimageOracle(host, input) + require.NoError(t, err) + + require.NotEmpty(t, output.PreimageOracle) +} diff --git a/op-deployer/pkg/deployer/opcm/proxy.go b/op-deployer/pkg/deployer/opcm/proxy.go index 850c337f83f4..ce463b1c2d1f 100644 --- a/op-deployer/pkg/deployer/opcm/proxy.go +++ b/op-deployer/pkg/deployer/opcm/proxy.go @@ -26,5 +26,5 @@ func DeployProxy( host *script.Host, input DeployProxyInput, ) (DeployProxyOutput, error) { - return RunBasicScript[DeployProxyInput, DeployProxyOutput](host, input, "DeployProxy.s.sol", "DeployProxy") + return RunScriptSingle[DeployProxyInput, DeployProxyOutput](host, input, "DeployProxy.s.sol", "DeployProxy") } diff --git a/op-deployer/pkg/deployer/opcm/proxy_test.go b/op-deployer/pkg/deployer/opcm/proxy_test.go index bb9cb350a369..30f0b1482f3d 100644 --- a/op-deployer/pkg/deployer/opcm/proxy_test.go +++ b/op-deployer/pkg/deployer/opcm/proxy_test.go @@ -13,6 +13,8 @@ import ( ) func TestDeployProxy(t *testing.T) { + t.Parallel() + _, artifacts := testutil.LocalArtifacts(t) host, err := env.DefaultScriptHost( diff --git a/op-deployer/pkg/deployer/opcm/script.go b/op-deployer/pkg/deployer/opcm/script.go index 6a138f67cb8f..bbb978b1c02a 100644 --- a/op-deployer/pkg/deployer/opcm/script.go +++ b/op-deployer/pkg/deployer/opcm/script.go @@ -7,11 +7,11 @@ import ( "github.com/ethereum/go-ethereum/common" ) -type BasicScriptIO struct { +type SingleScript struct { Run func(input, output common.Address) error } -func RunBasicScript[I any, O any]( +func RunScriptSingle[I any, O any]( host *script.Host, input I, scriptFile string, @@ -34,7 +34,7 @@ func RunBasicScript[I any, O any]( } defer cleanupOutput() - deployScript, cleanupDeploy, err := script.WithScript[BasicScriptIO](host, scriptFile, contractName) + deployScript, cleanupDeploy, err := script.WithScript[SingleScript](host, scriptFile, contractName) if err != nil { return output, fmt.Errorf("failed to load %s script: %w", scriptFile, err) } @@ -46,3 +46,34 @@ func RunBasicScript[I any, O any]( return output, nil } + +type VoidScript struct { + Run func(common.Address) error +} + +func RunScriptVoid[I any]( + host *script.Host, + input I, + scriptFile string, + contractName string, +) error { + inputAddr := host.NewScriptAddress() + + cleanupInput, err := script.WithPrecompileAtAddress[*I](host, inputAddr, &input) + if err != nil { + return fmt.Errorf("failed to insert input precompile: %w", err) + } + defer cleanupInput() + + deployScript, cleanupDeploy, err := script.WithScript[VoidScript](host, scriptFile, contractName) + if err != nil { + return fmt.Errorf("failed to load %s script: %w", scriptFile, err) + } + defer cleanupDeploy() + + if err := deployScript.Run(inputAddr); err != nil { + return fmt.Errorf("failed to run %s script: %w", scriptFile, err) + } + + return nil +} diff --git a/op-deployer/pkg/deployer/opcm/superchain.go b/op-deployer/pkg/deployer/opcm/superchain.go index fcbccc3cea4a..4bd918757ff9 100644 --- a/op-deployer/pkg/deployer/opcm/superchain.go +++ b/op-deployer/pkg/deployer/opcm/superchain.go @@ -52,5 +52,5 @@ type DeploySuperchainOpts struct { } func DeploySuperchain(h *script.Host, input DeploySuperchainInput) (DeploySuperchainOutput, error) { - return RunBasicScript[DeploySuperchainInput, DeploySuperchainOutput](h, input, "DeploySuperchain.s.sol", "DeploySuperchain") + return RunScriptSingle[DeploySuperchainInput, DeploySuperchainOutput](h, input, "DeploySuperchain.s.sol", "DeploySuperchain") } diff --git a/packages/contracts-bedrock/scripts/deploy/DeployAlphabetVM.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployAlphabetVM.s.sol new file mode 100644 index 000000000000..11f1c35ce1bb --- /dev/null +++ b/packages/contracts-bedrock/scripts/deploy/DeployAlphabetVM.s.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { Script } from "forge-std/Script.sol"; + +import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol"; +import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; +import { AlphabetVM } from "test/mocks/AlphabetVM.sol"; +import { Claim } from "src/dispute/lib/Types.sol"; + +contract DeployAlphabetVMInput is BaseDeployIO { + bytes32 internal _absolutePrestate; + IPreimageOracle internal _preimageOracle; + + function set(bytes4 _sel, address _addr) public { + require(_addr != address(0), "DeployAlphabetVMInput: cannot set zero address"); + + if (_sel == this.preimageOracle.selector) _preimageOracle = IPreimageOracle(_addr); + else revert("DeployAlphabetVMInput: unknown selector"); + } + + function set(bytes4 _sel, bytes32 _value) public { + if (_sel == this.absolutePrestate.selector) _absolutePrestate = _value; + else revert("DeployAlphabetVMInput: unknown selector"); + } + + function absolutePrestate() public view returns (bytes32) { + require(_absolutePrestate != bytes32(0), "DeployAlphabetVMInput: not set"); + return _absolutePrestate; + } + + function preimageOracle() public view returns (IPreimageOracle) { + require(address(_preimageOracle) != address(0), "DeployAlphabetVMInput: not set"); + return _preimageOracle; + } +} + +contract DeployAlphabetVMOutput is BaseDeployIO { + AlphabetVM internal _alphabetVM; + + function set(bytes4 _sel, address _addr) public { + require(_addr != address(0), "DeployAlphabetVMOutput: cannot set zero address"); + if (_sel == this.alphabetVM.selector) _alphabetVM = AlphabetVM(_addr); + else revert("DeployAlphabetVMOutput: unknown selector"); + } + + function alphabetVM() public view returns (AlphabetVM) { + require(address(_alphabetVM) != address(0), "DeployAlphabetVMOutput: not set"); + return _alphabetVM; + } +} + +contract DeployAlphabetVM is Script { + function run(DeployAlphabetVMInput _input, DeployAlphabetVMOutput _output) public { + Claim absolutePrestate = Claim.wrap(_input.absolutePrestate()); + IPreimageOracle preimageOracle = _input.preimageOracle(); + + vm.broadcast(msg.sender); + AlphabetVM alphabetVM = new AlphabetVM(absolutePrestate, preimageOracle); + + _output.set(_output.alphabetVM.selector, address(alphabetVM)); + } +} diff --git a/packages/contracts-bedrock/scripts/deploy/DeployPreimageOracle.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployPreimageOracle.s.sol new file mode 100644 index 000000000000..eff286d19134 --- /dev/null +++ b/packages/contracts-bedrock/scripts/deploy/DeployPreimageOracle.s.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { Script } from "forge-std/Script.sol"; + +import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol"; +import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; +import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; + +contract DeployPreimageOracleInput is BaseDeployIO { + uint256 internal _minProposalSize; + uint256 internal _challengePeriod; + + function set(bytes4 _sel, uint256 _value) public { + if (_sel == this.minProposalSize.selector) _minProposalSize = _value; + else if (_sel == this.challengePeriod.selector) _challengePeriod = _value; + else revert("DeployPreimageOracleInput: unknown selector"); + } + + function minProposalSize() public view returns (uint256) { + require(_minProposalSize > 0, "DeployPreimageOracleInput: not set"); + return _minProposalSize; + } + + function challengePeriod() public view returns (uint256) { + require(_challengePeriod > 0, "DeployPreimageOracleInput: not set"); + return _challengePeriod; + } +} + +contract DeployPreimageOracleOutput is BaseDeployIO { + IPreimageOracle internal _preimageOracle; + + function set(bytes4 _sel, address _addr) public { + require(_addr != address(0), "DeployPreimageOracleOutput: cannot set zero address"); + + if (_sel == this.preimageOracle.selector) _preimageOracle = IPreimageOracle(_addr); + else revert("DeployPreimageOracleOutput: unknown selector"); + } + + function preimageOracle() public view returns (IPreimageOracle) { + require(address(_preimageOracle) != address(0), "DeployPreimageOracleOutput: not set"); + return _preimageOracle; + } +} + +contract DeployPreimageOracle is Script { + function run(DeployPreimageOracleInput _input, DeployPreimageOracleOutput _output) public { + uint256 minProposalSize = _input.minProposalSize(); + uint256 challengePeriod = _input.challengePeriod(); + + vm.broadcast(msg.sender); + IPreimageOracle preimageOracle = IPreimageOracle( + DeployUtils.create1({ + _name: "PreimageOracle", + _args: DeployUtils.encodeConstructor( + abi.encodeCall(IPreimageOracle.__constructor__, (minProposalSize, challengePeriod)) + ) + }) + ); + + _output.set(_output.preimageOracle.selector, address(preimageOracle)); + assertValid(_input, _output); + } + + function assertValid(DeployPreimageOracleInput _input, DeployPreimageOracleOutput _output) public view { + IPreimageOracle oracle = _output.preimageOracle(); + require(address(oracle) != address(0), "DPO-10"); + require(oracle.minProposalSize() == _input.minProposalSize(), "DPO-20"); + require(oracle.challengePeriod() == _input.challengePeriod(), "DPO-30"); + } +} diff --git a/packages/contracts-bedrock/scripts/deploy/SetDisputeGameImpl.s.sol b/packages/contracts-bedrock/scripts/deploy/SetDisputeGameImpl.s.sol new file mode 100644 index 000000000000..0a0896c69ef7 --- /dev/null +++ b/packages/contracts-bedrock/scripts/deploy/SetDisputeGameImpl.s.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { Script } from "forge-std/Script.sol"; + +import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; +import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; +import { BaseDeployIO } from "scripts/deploy/BaseDeployIO.sol"; +import { GameType } from "src/dispute/lib/Types.sol"; + +contract SetDisputeGameImplInput is BaseDeployIO { + IDisputeGameFactory internal _factory; + IDisputeGame internal _impl; + uint32 internal _gameType; + + // Setter for address type + function set(bytes4 _sel, address _addr) public { + require(_addr != address(0), "SetDisputeGameImplInput: cannot set zero address"); + + if (_sel == this.factory.selector) _factory = IDisputeGameFactory(_addr); + else if (_sel == this.impl.selector) _impl = IDisputeGame(_addr); + else revert("SetDisputeGameImplInput: unknown selector"); + } + + // Setter for GameType + function set(bytes4 _sel, uint32 _type) public { + if (_sel == this.gameType.selector) _gameType = _type; + else revert("SetDisputeGameImplInput: unknown selector"); + } + + // Getters + function factory() public view returns (IDisputeGameFactory) { + require(address(_factory) != address(0), "SetDisputeGameImplInput: not set"); + return _factory; + } + + function impl() public view returns (IDisputeGame) { + require(address(_impl) != address(0), "SetDisputeGameImplInput: not set"); + return _impl; + } + + function gameType() public view returns (uint32) { + return _gameType; + } +} + +contract SetDisputeGameImpl is Script { + function run(SetDisputeGameImplInput _input) public { + IDisputeGameFactory factory = _input.factory(); + GameType gameType = GameType.wrap(_input.gameType()); + require(address(factory.gameImpls(gameType)) == address(0), "SDGI-10"); + + IDisputeGame impl = _input.impl(); + vm.broadcast(msg.sender); + factory.setImplementation(gameType, impl); + assertValid(_input); + } + + function assertValid(SetDisputeGameImplInput _input) public view { + GameType gameType = GameType.wrap(_input.gameType()); + require(address(_input.factory().gameImpls(gameType)) == address(_input.impl()), "SDGI-20"); + } +} diff --git a/packages/contracts-bedrock/test/opcm/DeployAlphabetVM.t.sol b/packages/contracts-bedrock/test/opcm/DeployAlphabetVM.t.sol new file mode 100644 index 000000000000..ac5938061f9f --- /dev/null +++ b/packages/contracts-bedrock/test/opcm/DeployAlphabetVM.t.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { Test } from "forge-std/Test.sol"; +import { AlphabetVM } from "test/mocks/AlphabetVM.sol"; +import { DeployAlphabetVM, DeployAlphabetVMInput, DeployAlphabetVMOutput } from "scripts/deploy/DeployAlphabetVM.s.sol"; + +contract DeployAlphabetVMInput_Test is Test { + DeployAlphabetVMInput input; + + function setUp() public { + input = new DeployAlphabetVMInput(); + } + + function test_getters_whenNotSet_reverts() public { + vm.expectRevert("DeployAlphabetVMInput: not set"); + input.preimageOracle(); + + vm.expectRevert("DeployAlphabetVMInput: not set"); + input.absolutePrestate(); + } + + function test_set_succeeds() public { + address oracle = makeAddr("oracle"); + bytes32 prestate = bytes32(uint256(1)); + + vm.etch(oracle, hex"01"); + + input.set(input.preimageOracle.selector, oracle); + input.set(input.absolutePrestate.selector, prestate); + + assertEq(address(input.preimageOracle()), oracle); + assertEq(input.absolutePrestate(), prestate); + } + + function test_set_withZeroAddress_reverts() public { + vm.expectRevert("DeployAlphabetVMInput: cannot set zero address"); + input.set(input.preimageOracle.selector, address(0)); + } + + function test_set_withInvalidSelector_reverts() public { + vm.expectRevert("DeployAlphabetVMInput: unknown selector"); + input.set(bytes4(0xdeadbeef), makeAddr("test")); + + vm.expectRevert("DeployAlphabetVMInput: unknown selector"); + input.set(bytes4(0xdeadbeef), bytes32(0)); + } +} + +contract DeployAlphabetVMOutput_Test is Test { + DeployAlphabetVMOutput output; + address mockVM; + + function setUp() public { + output = new DeployAlphabetVMOutput(); + mockVM = makeAddr("vm"); + vm.etch(mockVM, hex"01"); + } + + function test_getters_whenNotSet_reverts() public { + vm.expectRevert("DeployAlphabetVMOutput: not set"); + output.alphabetVM(); + } + + function test_set_succeeds() public { + output.set(output.alphabetVM.selector, mockVM); + assertEq(address(output.alphabetVM()), mockVM); + } + + function test_set_withZeroAddress_reverts() public { + vm.expectRevert("DeployAlphabetVMOutput: cannot set zero address"); + output.set(output.alphabetVM.selector, address(0)); + } + + function test_set_withInvalidSelector_reverts() public { + vm.expectRevert("DeployAlphabetVMOutput: unknown selector"); + output.set(bytes4(0xdeadbeef), mockVM); + } +} + +contract DeployAlphabetVM_Test is Test { + DeployAlphabetVM script; + DeployAlphabetVMInput input; + DeployAlphabetVMOutput output; + address mockOracle; + bytes32 mockPrestate; + + function setUp() public { + script = new DeployAlphabetVM(); + input = new DeployAlphabetVMInput(); + output = new DeployAlphabetVMOutput(); + mockOracle = makeAddr("oracle"); + mockPrestate = bytes32(uint256(1)); + } + + function test_run_succeeds() public { + input.set(input.preimageOracle.selector, mockOracle); + input.set(input.absolutePrestate.selector, mockPrestate); + script.run(input, output); + require(address(output.alphabetVM()) != address(0), "DeployAlphabetVM_Test: alphabetVM not set"); + } +} diff --git a/packages/contracts-bedrock/test/opcm/DeployPreimageOracle.t.sol b/packages/contracts-bedrock/test/opcm/DeployPreimageOracle.t.sol new file mode 100644 index 000000000000..ab9dc7b6278c --- /dev/null +++ b/packages/contracts-bedrock/test/opcm/DeployPreimageOracle.t.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { Test } from "forge-std/Test.sol"; + +import { + DeployPreimageOracle, + DeployPreimageOracleInput, + DeployPreimageOracleOutput +} from "scripts/deploy/DeployPreimageOracle.s.sol"; + +contract DeployPreimageOracleInput_Test is Test { + DeployPreimageOracleInput input; + + function setUp() public { + input = new DeployPreimageOracleInput(); + } + + function test_getters_whenNotSet_reverts() public { + vm.expectRevert("DeployPreimageOracleInput: not set"); + input.minProposalSize(); + + vm.expectRevert("DeployPreimageOracleInput: not set"); + input.challengePeriod(); + } + + function test_set_succeeds() public { + uint256 minProposalSize = 1000; + uint256 challengePeriod = 7 days; + + input.set(input.minProposalSize.selector, minProposalSize); + input.set(input.challengePeriod.selector, challengePeriod); + + assertEq(input.minProposalSize(), minProposalSize); + assertEq(input.challengePeriod(), challengePeriod); + } + + function test_set_withInvalidSelector_reverts() public { + vm.expectRevert("DeployPreimageOracleInput: unknown selector"); + input.set(bytes4(0xdeadbeef), 100); + } +} + +contract DeployPreimageOracleOutput_Test is Test { + DeployPreimageOracleOutput output; + address mockOracle; + + function setUp() public { + output = new DeployPreimageOracleOutput(); + mockOracle = makeAddr("oracle"); + vm.etch(mockOracle, hex"01"); + } + + function test_getters_whenNotSet_reverts() public { + vm.expectRevert("DeployPreimageOracleOutput: not set"); + output.preimageOracle(); + } + + function test_set_succeeds() public { + output.set(output.preimageOracle.selector, mockOracle); + assertEq(address(output.preimageOracle()), mockOracle); + } + + function test_set_withZeroAddress_reverts() public { + vm.expectRevert("DeployPreimageOracleOutput: cannot set zero address"); + output.set(output.preimageOracle.selector, address(0)); + } + + function test_set_withInvalidSelector_reverts() public { + vm.expectRevert("DeployPreimageOracleOutput: unknown selector"); + output.set(bytes4(0xdeadbeef), mockOracle); + } +} + +contract DeployPreimageOracle_Test is Test { + DeployPreimageOracle script; + DeployPreimageOracleInput input; + DeployPreimageOracleOutput output; + + uint256 minProposalSize; + uint256 challengePeriod; + + function setUp() public { + script = new DeployPreimageOracle(); + input = new DeployPreimageOracleInput(); + output = new DeployPreimageOracleOutput(); + + minProposalSize = 1000; + challengePeriod = 7 days; + } + + function test_run_succeeds() public { + input.set(input.minProposalSize.selector, minProposalSize); + input.set(input.challengePeriod.selector, challengePeriod); + + script.run(input, output); + + assertTrue(address(output.preimageOracle()) != address(0)); + } + + function test_assertValid_whenInvalid_reverts() public { + vm.expectRevert("DeployPreimageOracleOutput: not set"); + script.assertValid(input, output); + } +} diff --git a/packages/contracts-bedrock/test/opcm/SetDisputeGameImpl.t.sol b/packages/contracts-bedrock/test/opcm/SetDisputeGameImpl.t.sol new file mode 100644 index 000000000000..7477350a4f62 --- /dev/null +++ b/packages/contracts-bedrock/test/opcm/SetDisputeGameImpl.t.sol @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import { Test } from "forge-std/Test.sol"; +import { IDisputeGame } from "interfaces/dispute/IDisputeGame.sol"; +import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol"; +import { GameType } from "src/dispute/lib/Types.sol"; +import { SetDisputeGameImpl, SetDisputeGameImplInput } from "scripts/deploy/SetDisputeGameImpl.s.sol"; +import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol"; +import { Proxy } from "src/universal/Proxy.sol"; + +contract SetDisputeGameImplInput_Test is Test { + SetDisputeGameImplInput input; + + function setUp() public { + input = new SetDisputeGameImplInput(); + } + + function test_getters_whenNotSet_reverts() public { + vm.expectRevert("SetDisputeGameImplInput: not set"); + input.factory(); + + vm.expectRevert("SetDisputeGameImplInput: not set"); + input.impl(); + + // gameType doesn't revert when not set, returns 0 + assertEq(input.gameType(), 0); + } + + function test_set_succeeds() public { + address factory = makeAddr("factory"); + address impl = makeAddr("impl"); + uint32 gameType = 1; + + vm.etch(factory, hex"01"); + vm.etch(impl, hex"01"); + + input.set(input.factory.selector, factory); + input.set(input.impl.selector, impl); + input.set(input.gameType.selector, gameType); + + assertEq(address(input.factory()), factory); + assertEq(address(input.impl()), impl); + assertEq(input.gameType(), gameType); + } + + function test_set_withZeroAddress_reverts() public { + vm.expectRevert("SetDisputeGameImplInput: cannot set zero address"); + input.set(input.factory.selector, address(0)); + + vm.expectRevert("SetDisputeGameImplInput: cannot set zero address"); + input.set(input.impl.selector, address(0)); + } + + function test_set_withInvalidSelector_reverts() public { + vm.expectRevert("SetDisputeGameImplInput: unknown selector"); + input.set(bytes4(0xdeadbeef), makeAddr("test")); + + vm.expectRevert("SetDisputeGameImplInput: unknown selector"); + input.set(bytes4(0xdeadbeef), uint32(1)); + } +} + +contract SetDisputeGameImpl_Test is Test { + SetDisputeGameImpl script; + SetDisputeGameImplInput input; + IDisputeGameFactory factory; + address mockImpl; + uint32 gameType; + + function setUp() public { + script = new SetDisputeGameImpl(); + input = new SetDisputeGameImplInput(); + DisputeGameFactory impl = new DisputeGameFactory(); + + // Needs to be a proxy to properly initialize + Proxy proxy = new Proxy(address(1)); + vm.prank(address(1)); + proxy.upgradeToAndCall(address(impl), abi.encodeCall(impl.initialize, address(this))); + factory = IDisputeGameFactory(address(proxy)); + + mockImpl = makeAddr("impl"); + gameType = 999; + } + + function test_run_succeeds() public { + input.set(input.factory.selector, address(factory)); + input.set(input.impl.selector, mockImpl); + input.set(input.gameType.selector, gameType); + + script.run(input); + } + + function test_run_whenImplAlreadySet_reverts() public { + input.set(input.factory.selector, address(factory)); + input.set(input.impl.selector, mockImpl); + input.set(input.gameType.selector, gameType); + + // First run should succeed + script.run(input); + + // Subsequent runs should revert + vm.expectRevert("SDGI-10"); + script.run(input); + } + + function test_assertValid_whenNotValid_reverts() public { + input.set(input.factory.selector, address(factory)); + input.set(input.impl.selector, mockImpl); + input.set(input.gameType.selector, gameType); + + // First run should succeed + script.run(input); + + vm.broadcast(address(this)); + factory.setImplementation(GameType.wrap(gameType), IDisputeGame(address(0))); + + vm.expectRevert("SDGI-20"); + script.assertValid(input); + } +}