Skip to content

Commit 718a5da

Browse files
mbaxterajsutton
andauthored
cannon: Add feature toggling to MIPS VM contracts (#15487)
* cannon: Add state version to MIPS contract. * Formatting. * cannon: Update EVM tests to init contract correctly. * Fix contracts checks. * op-deployer: Fix test * Formatting * Fix interfaces. * Update MIPS2 version. * cleanup: Cut println * Remove MIPS contracts from code freeze * Drop legacy MipsVersion 2 * Run semver-lock * Drop -beta suffix from version * Run semver-lock * cleanup: Reorganize MIPS64 imports --------- Co-authored-by: Adrian Sutton <[email protected]>
1 parent b2451a6 commit 718a5da

File tree

24 files changed

+189
-76
lines changed

24 files changed

+189
-76
lines changed

cannon/mipsevm/tests/evm_multithreaded_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,6 @@ func TestEVM_MT_StoreOpsClearMemReservation32(t *testing.T) {
234234
}
235235

236236
func TestEVM_SysClone_FlagHandling(t *testing.T) {
237-
contracts := testutil.TestContractsSetup(t, testutil.MipsMultithreaded)
238237

239238
cases := []struct {
240239
name string
@@ -283,7 +282,7 @@ func TestEVM_SysClone_FlagHandling(t *testing.T) {
283282
require.Equal(t, 2, state.ThreadCount())
284283
}
285284

286-
testutil.ValidateEVM(t, stepWitness, curStep, goVm, multithreaded.GetStateHashFn(), contracts)
285+
testutil.ValidateEVM(t, stepWitness, curStep, goVm, multithreaded.GetStateHashFn(), version.Contracts)
287286
})
288287
}
289288
}

cannon/mipsevm/tests/helpers.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ type VersionedVMTestCase struct {
9999
func GetSingleThreadedTestCase(t require.TestingT) VersionedVMTestCase {
100100
return VersionedVMTestCase{
101101
Name: "single-threaded",
102-
Contracts: testutil.TestContractsSetup(t, testutil.MipsSingleThreaded),
102+
Contracts: testutil.TestContractsSetup(t, testutil.MipsSingleThreaded, 0),
103103
StateHashFn: singlethreaded.GetStateHashFn(),
104104
VMFactory: singleThreadedVmFactory,
105105
ElfVMFactory: singleThreadElfVmFactory,
@@ -112,7 +112,7 @@ func GetMultiThreadedTestCase(t require.TestingT, version versions.StateVersion)
112112
features := versions.FeaturesForVersion(version)
113113
return VersionedVMTestCase{
114114
Name: version.String(),
115-
Contracts: testutil.TestContractsSetup(t, testutil.MipsMultithreaded),
115+
Contracts: testutil.TestContractsSetup(t, testutil.MipsMultithreaded, uint8(version)),
116116
StateHashFn: multithreaded.GetStateHashFn(),
117117
VMFactory: func(po mipsevm.PreimageOracle, stdOut, stdErr io.Writer, log log.Logger, opts ...testutil.StateOption) mipsevm.FPVM {
118118
return multiThreadedVmFactory(po, stdOut, stdErr, log, features, opts...)

cannon/mipsevm/testutil/evm.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/ethereum/go-ethereum/core/tracing"
1313
"github.com/ethereum/go-ethereum/eth/tracers/logger"
1414
"github.com/ethereum/go-ethereum/triedb"
15+
"github.com/holiman/uint256"
1516
"github.com/stretchr/testify/require"
1617

1718
"github.com/ethereum-optimism/optimism/op-chain-ops/foundry"
@@ -42,9 +43,10 @@ type Addresses struct {
4243
type ContractMetadata struct {
4344
Artifacts *Artifacts
4445
Addresses *Addresses
46+
Version uint8 // versions.StateVersion can't be used as it causes dependency cycles
4547
}
4648

47-
func TestContractsSetup(t require.TestingT, version MipsVersion) *ContractMetadata {
49+
func TestContractsSetup(t require.TestingT, version MipsVersion, stateVersion uint8) *ContractMetadata {
4850
artifacts, err := loadArtifacts(version)
4951
require.NoError(t, err)
5052

@@ -55,7 +57,7 @@ func TestContractsSetup(t require.TestingT, version MipsVersion) *ContractMetada
5557
FeeRecipient: common.Address{0xaa},
5658
}
5759

58-
return &ContractMetadata{Artifacts: artifacts, Addresses: addrs}
60+
return &ContractMetadata{Artifacts: artifacts, Addresses: addrs, Version: stateVersion}
5961
}
6062

6163
// loadArtifacts loads the Cannon contracts, from the contracts package.
@@ -116,9 +118,19 @@ func NewEVMEnv(contracts *ContractMetadata) (*vm.EVM, *state.StateDB) {
116118
// pre-deploy the contracts
117119
env.StateDB.SetCode(contracts.Addresses.Oracle, contracts.Artifacts.Oracle.DeployedBytecode.Object)
118120

119-
var mipsCtorArgs [32]byte
120-
copy(mipsCtorArgs[12:], contracts.Addresses.Oracle[:])
121-
mipsDeploy := append(bytes.Clone(contracts.Artifacts.MIPS.Bytecode.Object), mipsCtorArgs[:]...)
121+
var ctorArgs []byte
122+
if contracts.Version == 0 { // Old MIPS.sol doesn't specify the state version in the constructor
123+
var mipsCtorArgs [32]byte
124+
copy(mipsCtorArgs[12:], contracts.Addresses.Oracle[:])
125+
ctorArgs = mipsCtorArgs[:]
126+
} else {
127+
var mipsCtorArgs [64]byte
128+
copy(mipsCtorArgs[12:], contracts.Addresses.Oracle[:])
129+
vers := uint256.NewInt(uint64(contracts.Version)).Bytes32()
130+
copy(mipsCtorArgs[32:], vers[:])
131+
ctorArgs = mipsCtorArgs[:]
132+
}
133+
mipsDeploy := append(bytes.Clone(contracts.Artifacts.MIPS.Bytecode.Object), ctorArgs...)
122134
startingGas := uint64(30_000_000)
123135
_, deployedMipsAddr, leftOverGas, err := env.Create(contracts.Addresses.Sender, mipsDeploy, startingGas, common.U2560)
124136
if err != nil {

op-chain-ops/interopgen/recipe.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func (recipe *InteropDevRecipe) Build(addrs devkeys.Addresses) (*WorldConfig, er
7676
ChallengePeriodSeconds: big.NewInt(120),
7777
ProofMaturityDelaySeconds: big.NewInt(12),
7878
DisputeGameFinalityDelaySeconds: big.NewInt(6),
79-
MipsVersion: big.NewInt(2),
79+
MipsVersion: big.NewInt(6),
8080
},
8181
UseInterop: true,
8282
},

op-deployer/pkg/deployer/bootstrap/implementations.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ func (c *ImplementationsConfig) Check() error {
7575
} else {
7676
c.L1ContractsRelease = "dev"
7777
}
78-
if c.MIPSVersion != 1 && c.MIPSVersion != 2 {
79-
return errors.New("MIPS version must be specified as either 1 or 2")
78+
if c.MIPSVersion != 1 && c.MIPSVersion != 6 {
79+
return errors.New("MIPS version must be specified as either 1 or 6")
8080
}
8181
if c.WithdrawalDelaySeconds == 0 {
8282
return errors.New("withdrawal delay in seconds must be specified")

op-deployer/pkg/deployer/integration_test/apply_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ func TestProofParamOverrides(t *testing.T) {
352352
"preimageOracleChallengePeriod": standard.ChallengePeriodSeconds + 1,
353353
"proofMaturityDelaySeconds": standard.ProofMaturityDelaySeconds + 1,
354354
"disputeGameFinalityDelaySeconds": standard.DisputeGameFinalityDelaySeconds + 1,
355-
"mipsVersion": standard.MIPSVersion + 1,
355+
"mipsVersion": 6, // Contract enforces a valid value be used
356356
"respectedGameType": standard.DisputeGameType, // This must be set to the permissioned game
357357
"faultGameAbsolutePrestate": common.Hash{'A', 'B', 'S', 'O', 'L', 'U', 'T', 'E'},
358358
"faultGameMaxDepth": standard.DisputeMaxGameDepth + 1,

op-deployer/pkg/deployer/pipeline/dispute_games.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func deployDisputeGame(
8787
case state.VMTypeCannon1, state.VMTypeCannon2:
8888
mipsVersion := 1
8989
if game.VMType == state.VMTypeCannon2 {
90-
mipsVersion = 2
90+
mipsVersion = 6
9191
}
9292

9393
out, err := opcm.DeployMIPS(env.L1ScriptHost, opcm.DeployMIPSInput{

op-deployer/pkg/deployer/standard/standard.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const (
2525
ChallengePeriodSeconds uint64 = 86400
2626
ProofMaturityDelaySeconds uint64 = 604800
2727
DisputeGameFinalityDelaySeconds uint64 = 302400
28-
MIPSVersion uint64 = 2
28+
MIPSVersion uint64 = 6
2929
DisputeGameType uint32 = 1 // PERMISSIONED game type
3030
DisputeMaxGameDepth uint64 = 73
3131
DisputeSplitDepth uint64 = 30

packages/contracts-bedrock/interfaces/cannon/IMIPS2.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,5 @@ interface IMIPS2 is ISemver {
5050
external
5151
returns (bytes32 postState_);
5252

53-
function __constructor__(IPreimageOracle _oracle) external;
53+
function __constructor__(IPreimageOracle _oracle, uint256 /*_stateVersion*/) external;
5454
}

packages/contracts-bedrock/scripts/checks/check-frozen-files.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ ALLOWED_FILES=(
8080
"src/L2/SuperchainTokenBridge.sol:SuperchainTokenBridge"
8181
"src/L2/SuperchainETHBridge.sol:SuperchainETHBridge"
8282
"src/L2/WETH.sol:WETH"
83-
# "src/cannon/MIPS.sol:MIPS"
84-
# "src/cannon/MIPS2.sol:MIPS2"
85-
# "src/cannon/MIPS64.sol:MIPS64"
83+
"src/cannon/MIPS.sol:MIPS"
84+
"src/cannon/MIPS2.sol:MIPS2"
85+
"src/cannon/MIPS64.sol:MIPS64"
8686
"src/cannon/PreimageOracle.sol:PreimageOracle"
8787
# "src/dispute/AnchorStateRegistry.sol:AnchorStateRegistry"
8888
"src/dispute/DelayedWETH.sol:DelayedWETH"

packages/contracts-bedrock/scripts/deploy/Deploy.s.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ contract Deploy is Deployer {
262262
dii.set(dii.challengePeriodSeconds.selector, cfg.preimageOracleChallengePeriod());
263263
dii.set(dii.proofMaturityDelaySeconds.selector, cfg.proofMaturityDelaySeconds());
264264
dii.set(dii.disputeGameFinalityDelaySeconds.selector, cfg.disputeGameFinalityDelaySeconds());
265-
dii.set(dii.mipsVersion.selector, Config.useMultithreadedCannon() ? 2 : 1);
265+
dii.set(dii.mipsVersion.selector, Config.useMultithreadedCannon() ? 6 : 1);
266266
string memory release = "dev";
267267
dii.set(dii.l1ContractsRelease.selector, release);
268268
dii.set(dii.protocolVersionsProxy.selector, artifacts.mustGetAddress("ProtocolVersionsProxy"));

packages/contracts-bedrock/scripts/deploy/DeployImplementations.s.sol

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";
1515
import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol";
1616
import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol";
1717
import { IMIPS } from "interfaces/cannon/IMIPS.sol";
18+
import { IMIPS2 } from "interfaces/cannon/IMIPS2.sol";
1819
import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol";
1920
import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol";
2021
import {
@@ -838,23 +839,36 @@ contract DeployImplementations is Script {
838839
}
839840

840841
function deployMipsSingleton(DeployImplementationsInput _dii, DeployImplementationsOutput _dio) public virtual {
842+
IMIPS singleton;
841843
uint256 mipsVersion = _dii.mipsVersion();
842844
IPreimageOracle preimageOracle = IPreimageOracle(address(_dio.preimageOracleSingleton()));
843845

844846
// We want to ensure that the OPCM for upgrade 13 is deployed with Mips32 on production networks.
845-
if (mipsVersion != 2) {
847+
if (mipsVersion < 2) {
846848
if (block.chainid == Chains.Mainnet || block.chainid == Chains.Sepolia) {
847849
revert("DeployImplementations: Only Mips64 should be deployed on Mainnet or Sepolia");
848850
}
849851
}
850852

851-
IMIPS singleton = IMIPS(
852-
DeployUtils.createDeterministic({
853-
_name: mipsVersion == 1 ? "MIPS" : "MIPS64",
854-
_args: DeployUtils.encodeConstructor(abi.encodeCall(IMIPS.__constructor__, (preimageOracle))),
855-
_salt: _salt
856-
})
857-
);
853+
if (mipsVersion == 1) {
854+
singleton = IMIPS(
855+
DeployUtils.createDeterministic({
856+
_name: "MIPS",
857+
_args: DeployUtils.encodeConstructor(abi.encodeCall(IMIPS.__constructor__, (preimageOracle))),
858+
_salt: DeployUtils.DEFAULT_SALT
859+
})
860+
);
861+
} else {
862+
singleton = IMIPS(
863+
DeployUtils.createDeterministic({
864+
_name: "MIPS64",
865+
_args: DeployUtils.encodeConstructor(
866+
abi.encodeCall(IMIPS2.__constructor__, (preimageOracle, mipsVersion))
867+
),
868+
_salt: DeployUtils.DEFAULT_SALT
869+
})
870+
);
871+
}
858872
vm.label(address(singleton), "MIPSSingleton");
859873
_dio.set(_dio.mipsSingleton.selector, address(singleton));
860874
}

packages/contracts-bedrock/scripts/deploy/DeployImplementations2.s.sol

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { IProtocolVersions } from "interfaces/L1/IProtocolVersions.sol";
1414
import { IDelayedWETH } from "interfaces/dispute/IDelayedWETH.sol";
1515
import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol";
1616
import { IMIPS } from "interfaces/cannon/IMIPS.sol";
17+
import { IMIPS2 } from "interfaces/cannon/IMIPS2.sol";
1718
import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol";
1819
import { IAnchorStateRegistry } from "interfaces/dispute/IAnchorStateRegistry.sol";
1920
import {
@@ -400,23 +401,36 @@ contract DeployImplementations2 is Script {
400401
}
401402

402403
function deployMipsSingleton(Input memory _input, Output memory _output) private {
404+
IMIPS singleton;
403405
uint256 mipsVersion = _input.mipsVersion;
404406
IPreimageOracle preimageOracle = IPreimageOracle(address(_output.preimageOracleSingleton));
405407

406408
// We want to ensure that the OPCM for upgrade 13 is deployed with Mips32 on production networks.
407-
if (mipsVersion != 2) {
409+
if (mipsVersion < 2) {
408410
if (block.chainid == Chains.Mainnet || block.chainid == Chains.Sepolia) {
409411
revert("DeployImplementations: Only Mips64 should be deployed on Mainnet or Sepolia");
410412
}
411413
}
412414

413-
IMIPS singleton = IMIPS(
414-
DeployUtils.createDeterministic({
415-
_name: mipsVersion == 1 ? "MIPS" : "MIPS64",
416-
_args: DeployUtils.encodeConstructor(abi.encodeCall(IMIPS.__constructor__, (preimageOracle))),
417-
_salt: _salt
418-
})
419-
);
415+
if (mipsVersion == 1) {
416+
singleton = IMIPS(
417+
DeployUtils.createDeterministic({
418+
_name: "MIPS",
419+
_args: DeployUtils.encodeConstructor(abi.encodeCall(IMIPS.__constructor__, (preimageOracle))),
420+
_salt: DeployUtils.DEFAULT_SALT
421+
})
422+
);
423+
} else {
424+
singleton = IMIPS(
425+
DeployUtils.createDeterministic({
426+
_name: "MIPS64",
427+
_args: DeployUtils.encodeConstructor(
428+
abi.encodeCall(IMIPS2.__constructor__, (preimageOracle, mipsVersion))
429+
),
430+
_salt: DeployUtils.DEFAULT_SALT
431+
})
432+
);
433+
}
420434
vm.label(address(singleton), "MIPSSingleton");
421435
_output.mipsSingleton = singleton;
422436
}

packages/contracts-bedrock/scripts/deploy/DeployMIPS.s.sol

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { DeployUtils } from "scripts/libraries/DeployUtils.sol";
1111
// Interfaces
1212
import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol";
1313
import { IMIPS } from "interfaces/cannon/IMIPS.sol";
14+
import { IMIPS2 } from "interfaces/cannon/IMIPS2.sol";
1415

1516
/// @title DeployMIPSInput
1617
contract DeployMIPSInput is BaseDeployIO {
@@ -22,7 +23,7 @@ contract DeployMIPSInput is BaseDeployIO {
2223

2324
function set(bytes4 _sel, uint256 _value) public {
2425
if (_sel == this.mipsVersion.selector) {
25-
require(_value == 1 || _value == 2, "DeployMIPS: unknown mips version");
26+
require(_value == 1 || _value == 6, "DeployMIPS: unknown mips version");
2627
_mipsVersion = _value;
2728
} else {
2829
revert("DeployMIPS: unknown selector");
@@ -40,7 +41,7 @@ contract DeployMIPSInput is BaseDeployIO {
4041

4142
function mipsVersion() public view returns (uint256) {
4243
require(_mipsVersion != 0, "DeployMIPS: mipsVersion not set");
43-
require(_mipsVersion == 1 || _mipsVersion == 2, "DeployMIPS: unknown mips version");
44+
require(_mipsVersion == 1 || _mipsVersion == 6, "DeployMIPS: unknown mips version");
4445
return _mipsVersion;
4546
}
4647

@@ -80,13 +81,25 @@ contract DeployMIPS is Script {
8081
IMIPS singleton;
8182
uint256 mipsVersion = _mi.mipsVersion();
8283
IPreimageOracle preimageOracle = IPreimageOracle(_mi.preimageOracle());
83-
singleton = IMIPS(
84-
DeployUtils.createDeterministic({
85-
_name: mipsVersion == 1 ? "MIPS" : "MIPS64",
86-
_args: DeployUtils.encodeConstructor(abi.encodeCall(IMIPS.__constructor__, (preimageOracle))),
87-
_salt: DeployUtils.DEFAULT_SALT
88-
})
89-
);
84+
if (mipsVersion == 1) {
85+
singleton = IMIPS(
86+
DeployUtils.createDeterministic({
87+
_name: "MIPS",
88+
_args: DeployUtils.encodeConstructor(abi.encodeCall(IMIPS.__constructor__, (preimageOracle))),
89+
_salt: DeployUtils.DEFAULT_SALT
90+
})
91+
);
92+
} else {
93+
singleton = IMIPS(
94+
DeployUtils.createDeterministic({
95+
_name: "MIPS64",
96+
_args: DeployUtils.encodeConstructor(
97+
abi.encodeCall(IMIPS2.__constructor__, (preimageOracle, mipsVersion))
98+
),
99+
_salt: DeployUtils.DEFAULT_SALT
100+
})
101+
);
102+
}
90103

91104
vm.label(address(singleton), "MIPSSingleton");
92105
_mo.set(_mo.mipsSingleton.selector, address(singleton));

packages/contracts-bedrock/scripts/deploy/DeployMIPS2.s.sol

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { DeployUtils } from "scripts/libraries/DeployUtils.sol";
1010
// Interfaces
1111
import { IPreimageOracle } from "interfaces/cannon/IPreimageOracle.sol";
1212
import { IMIPS } from "interfaces/cannon/IMIPS.sol";
13+
import { IMIPS2 } from "interfaces/cannon/IMIPS2.sol";
1314

1415
/// @title DeployMIPS
1516
contract DeployMIPS2 is Script {
@@ -33,16 +34,28 @@ contract DeployMIPS2 is Script {
3334
}
3435

3536
function deployMipsSingleton(Input memory _input, Output memory _output) internal {
37+
IMIPS singleton;
3638
uint256 mipsVersion = _input.mipsVersion;
37-
string memory contractName = mipsVersion == 1 ? "MIPS" : "MIPS64";
3839

39-
IMIPS singleton = IMIPS(
40-
DeployUtils.createDeterministic({
41-
_name: contractName,
42-
_args: DeployUtils.encodeConstructor(abi.encodeCall(IMIPS.__constructor__, (_input.preimageOracle))),
43-
_salt: DeployUtils.DEFAULT_SALT
44-
})
45-
);
40+
if (mipsVersion == 1) {
41+
singleton = IMIPS(
42+
DeployUtils.createDeterministic({
43+
_name: "MIPS",
44+
_args: DeployUtils.encodeConstructor(abi.encodeCall(IMIPS.__constructor__, (_input.preimageOracle))),
45+
_salt: DeployUtils.DEFAULT_SALT
46+
})
47+
);
48+
} else {
49+
singleton = IMIPS(
50+
DeployUtils.createDeterministic({
51+
_name: "MIPS64",
52+
_args: DeployUtils.encodeConstructor(
53+
abi.encodeCall(IMIPS2.__constructor__, (_input.preimageOracle, mipsVersion))
54+
),
55+
_salt: DeployUtils.DEFAULT_SALT
56+
})
57+
);
58+
}
4659

4760
vm.label(address(singleton), "MIPSSingleton");
4861
_output.mipsSingleton = singleton;
@@ -51,7 +64,7 @@ contract DeployMIPS2 is Script {
5164
function assertValidInput(Input memory _input) public pure {
5265
require(address(_input.preimageOracle) != address(0), "DeployMIPS: preimageOracle not set");
5366
require(_input.mipsVersion != 0, "DeployMIPS: mipsVersion not set");
54-
require(_input.mipsVersion == 1 || _input.mipsVersion == 2, "DeployMIPS: unknown mips version");
67+
require(_input.mipsVersion == 1 || _input.mipsVersion == 6, "DeployMIPS: unknown mips version");
5568
}
5669

5770
function assertValidOutput(Input memory _input, Output memory _output) public view {

packages/contracts-bedrock/snapshots/abi/MIPS2.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
"internalType": "contract IPreimageOracle",
66
"name": "_oracle",
77
"type": "address"
8+
},
9+
{
10+
"internalType": "uint256",
11+
"name": "",
12+
"type": "uint256"
813
}
914
],
1015
"stateMutability": "nonpayable",

0 commit comments

Comments
 (0)