diff --git a/op-chain-ops/interopgen/deploy.go b/op-chain-ops/interopgen/deploy.go index 73584fce412..aaaeb32456f 100644 --- a/op-chain-ops/interopgen/deploy.go +++ b/op-chain-ops/interopgen/deploy.go @@ -254,6 +254,7 @@ func DeployL2ToL1(l1Host *script.Host, superCfg *SuperchainConfig, superDeployme AllowCustomDisputeParameters: true, OperatorFeeScalar: cfg.GasPriceOracleOperatorFeeScalar, OperatorFeeConstant: cfg.GasPriceOracleOperatorFeeConstant, + UseCustomGasToken: cfg.UseCustomGasToken, }) if err != nil { return nil, fmt.Errorf("failed to deploy L2 OP chain: %w", err) diff --git a/op-deployer/pkg/deployer/opcm/opchain.go b/op-deployer/pkg/deployer/opcm/opchain.go index 4b09de4a2cb..115bb14f9af 100644 --- a/op-deployer/pkg/deployer/opcm/opchain.go +++ b/op-deployer/pkg/deployer/opcm/opchain.go @@ -43,6 +43,8 @@ type DeployOPChainInput struct { OperatorFeeScalar uint32 OperatorFeeConstant uint64 + + UseCustomGasToken bool } type DeployOPChainOutput struct { diff --git a/op-deployer/pkg/deployer/pipeline/opchain.go b/op-deployer/pkg/deployer/pipeline/opchain.go index b148d2eb090..2ef41d73d60 100644 --- a/op-deployer/pkg/deployer/pipeline/opchain.go +++ b/op-deployer/pkg/deployer/pipeline/opchain.go @@ -126,6 +126,7 @@ func makeDCI(intent *state.Intent, thisIntent *state.ChainIntent, chainID common AllowCustomDisputeParameters: proofParams.DangerouslyAllowCustomDisputeParameters, OperatorFeeScalar: thisIntent.OperatorFeeScalar, OperatorFeeConstant: thisIntent.OperatorFeeConstant, + UseCustomGasToken: thisIntent.IsCustomGasTokenEnabled(), }, nil } diff --git a/packages/contracts-bedrock/interfaces/L1/IOPContractsManager.sol b/packages/contracts-bedrock/interfaces/L1/IOPContractsManager.sol index 46d6db683dc..f042cffa579 100644 --- a/packages/contracts-bedrock/interfaces/L1/IOPContractsManager.sol +++ b/packages/contracts-bedrock/interfaces/L1/IOPContractsManager.sol @@ -157,6 +157,8 @@ interface IOPContractsManager { uint256 disputeSplitDepth; Duration disputeClockExtension; Duration disputeMaxClockDuration; + // Whether to use the custom gas token. + bool useCustomGasToken; } /// @notice The full set of outputs from deploying a new OP Stack chain. @@ -337,17 +339,17 @@ interface IOPContractsManager { bool _allowFailure, IOPContractsManagerStandardValidator.ValidationOverrides calldata _overrides ) - external - view - returns (string memory); + external + view + returns (string memory); function validate( IOPContractsManagerStandardValidator.ValidationInputDev calldata _input, bool _allowFailure ) - external - view - returns (string memory); + external + view + returns (string memory); function deploy(DeployInput calldata _input) external returns (DeployOutput memory); diff --git a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol index 93edb1d7ac0..460d6b90b5c 100644 --- a/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol @@ -441,7 +441,8 @@ contract Deploy is Deployer { disputeMaxGameDepth: cfg.faultGameMaxDepth(), disputeSplitDepth: cfg.faultGameSplitDepth(), disputeClockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())), - disputeMaxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())) + disputeMaxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())), + useCustomGasToken: cfg.useCustomGasToken() }); } } diff --git a/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol b/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol index 7bf5c07456d..07683d3fca5 100644 --- a/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol +++ b/packages/contracts-bedrock/scripts/deploy/DeployOPChain.s.sol @@ -78,7 +78,8 @@ contract DeployOPChain is Script { disputeMaxGameDepth: _input.disputeMaxGameDepth, disputeSplitDepth: _input.disputeSplitDepth, disputeClockExtension: _input.disputeClockExtension, - disputeMaxClockDuration: _input.disputeMaxClockDuration + disputeMaxClockDuration: _input.disputeMaxClockDuration, + useCustomGasToken: _input.useCustomGasToken }); vm.broadcast(msg.sender); diff --git a/packages/contracts-bedrock/scripts/libraries/Types.sol b/packages/contracts-bedrock/scripts/libraries/Types.sol index 52f8557d977..7b90b7204e9 100644 --- a/packages/contracts-bedrock/scripts/libraries/Types.sol +++ b/packages/contracts-bedrock/scripts/libraries/Types.sol @@ -49,5 +49,7 @@ library Types { // Fee params uint32 operatorFeeScalar; uint64 operatorFeeConstant; + // Whether to use the custom gas token. + bool useCustomGasToken; } } diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json index ed428d40a1d..33f8880d27e 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManager.json @@ -312,6 +312,11 @@ "internalType": "Duration", "name": "disputeMaxClockDuration", "type": "uint64" + }, + { + "internalType": "bool", + "name": "useCustomGasToken", + "type": "bool" } ], "internalType": "struct OPContractsManager.DeployInput", diff --git a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerDeployer.json b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerDeployer.json index 62e169196ff..a8798bdcb95 100644 --- a/packages/contracts-bedrock/snapshots/abi/OPContractsManagerDeployer.json +++ b/packages/contracts-bedrock/snapshots/abi/OPContractsManagerDeployer.json @@ -215,6 +215,11 @@ "internalType": "Duration", "name": "disputeMaxClockDuration", "type": "uint64" + }, + { + "internalType": "bool", + "name": "useCustomGasToken", + "type": "bool" } ], "internalType": "struct OPContractsManager.DeployInput", diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index 775b4af8514..0912dfc008a 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -24,8 +24,8 @@ "sourceCodeHash": "0xfca613b5d055ffc4c3cbccb0773ddb9030abedc1aa6508c9e2e7727cc0cd617b" }, "src/L1/OPContractsManager.sol:OPContractsManager": { - "initCodeHash": "0xcf86b4c819efbd2a1ade90a4390269ff0137c8ea79887d55c9c457c2cef186c0", - "sourceCodeHash": "0x5498fda0ce02788807f2589656355bdbb6df06fe4cdc2b6e31b6387f812422a5" + "initCodeHash": "0x6fd82aaec43858b34bd093e29bbacb659a95817d506de948aebd3c84e6d2a00a", + "sourceCodeHash": "0x5f63555e12cb8e27ce5c1511e986550bf2f1b9769e314223a7324b8dcfa29523" }, "src/L1/OPContractsManagerStandardValidator.sol:OPContractsManagerStandardValidator": { "initCodeHash": "0x0c8b15453d0f0bc5d9af07f104505e0bbb2b358f0df418289822fb73a8652b30", diff --git a/packages/contracts-bedrock/src/L1/OPContractsManager.sol b/packages/contracts-bedrock/src/L1/OPContractsManager.sol index d43c8fa55dd..31bfb0989e8 100644 --- a/packages/contracts-bedrock/src/L1/OPContractsManager.sol +++ b/packages/contracts-bedrock/src/L1/OPContractsManager.sol @@ -1463,7 +1463,7 @@ contract OPContractsManagerDeployer is OPContractsManagerBase { // If the custom gas token feature was requested, enable the custom gas token feature in the SystemConfig // contract. - if (isDevFeatureEnabled(DevFeatures.CUSTOM_GAS_TOKEN)) { + if (_input.useCustomGasToken) { output.systemConfigProxy.setFeature(Features.CUSTOM_GAS_TOKEN, true); } @@ -2137,6 +2137,8 @@ contract OPContractsManager is ISemver { uint256 disputeSplitDepth; Duration disputeClockExtension; Duration disputeMaxClockDuration; + // Whether to use the custom gas token. + bool useCustomGasToken; } /// @notice The full set of outputs from deploying a new OP Stack chain. diff --git a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol index 418151729e9..877ab5e9781 100644 --- a/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol +++ b/packages/contracts-bedrock/test/L1/OPContractsManager.t.sol @@ -514,7 +514,8 @@ abstract contract OPContractsManager_TestInit is CommonTest, DisputeGames { disputeMaxGameDepth: 73, disputeSplitDepth: 30, disputeClockExtension: Duration.wrap(10800), - disputeMaxClockDuration: Duration.wrap(302400) + disputeMaxClockDuration: Duration.wrap(302400), + useCustomGasToken: false }) ); } @@ -2359,7 +2360,8 @@ contract OPContractsManager_Deploy_Test is DeployOPChain_TestBase, DisputeGames disputeMaxGameDepth: _doi.disputeMaxGameDepth, disputeSplitDepth: _doi.disputeSplitDepth, disputeClockExtension: _doi.disputeClockExtension, - disputeMaxClockDuration: _doi.disputeMaxClockDuration + disputeMaxClockDuration: _doi.disputeMaxClockDuration, + useCustomGasToken: _doi.useCustomGasToken }); } diff --git a/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol b/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol index d8e48aadeaa..3246d9de9b4 100644 --- a/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol +++ b/packages/contracts-bedrock/test/opcm/DeployOPChain.t.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.15; import { Test } from "forge-std/Test.sol"; import { FeatureFlags } from "test/setup/FeatureFlags.sol"; import { DevFeatures } from "src/libraries/DevFeatures.sol"; +import { Features } from "src/libraries/Features.sol"; import { DeploySuperchain } from "scripts/deploy/DeploySuperchain.s.sol"; import { DeployImplementations } from "scripts/deploy/DeployImplementations.s.sol"; @@ -58,6 +59,7 @@ contract DeployOPChain_TestBase is Test, FeatureFlags { Duration disputeClockExtension = Duration.wrap(3 hours); Duration disputeMaxClockDuration = Duration.wrap(3.5 days); IOPContractsManager opcm; + bool useCustomGasToken = false; event Deployed(uint256 indexed l2ChainId, address indexed deployer, bytes deployOutput); @@ -125,7 +127,8 @@ contract DeployOPChain_TestBase is Test, FeatureFlags { disputeMaxClockDuration: disputeMaxClockDuration, allowCustomDisputeParameters: false, operatorFeeScalar: 0, - operatorFeeConstant: 0 + operatorFeeConstant: 0, + useCustomGasToken: useCustomGasToken }); } } @@ -160,6 +163,14 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { Claim.unwrap(pdg.absolutePrestate()), Claim.unwrap(disputeAbsolutePrestate), "PDG absolutePrestate" ); } + + // Custom gas token feature should reflect input + assertEq(doo.systemConfigProxy.isCustomGasToken(), useCustomGasToken, "SystemConfig isCustomGasToken"); + assertEq( + doo.systemConfigProxy.isFeatureEnabled(Features.CUSTOM_GAS_TOKEN), + useCustomGasToken, + "SystemConfig CUSTOM_GAS_TOKEN feature" + ); } function testFuzz_run_memory_succeeds(bytes32 _seed) public { @@ -172,6 +183,7 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { deployOPChainInput.basefeeScalar = uint32(uint256(hash(_seed, 6))); deployOPChainInput.blobBaseFeeScalar = uint32(uint256(hash(_seed, 7))); deployOPChainInput.l2ChainId = uint256(hash(_seed, 8)); + deployOPChainInput.useCustomGasToken = uint256(hash(_seed, 9)) % 2 == 1; DeployOPChain.Output memory doo = deployOPChain.run(deployOPChainInput); @@ -199,6 +211,30 @@ contract DeployOPChain_Test is DeployOPChain_TestBase { assertEq(Duration.unwrap(pdg.maxClockDuration()), 302400, "3300"); assertEq(pdg.splitDepth(), 30, "3400"); assertEq(pdg.maxGameDepth(), 73, "3500"); + + // Verify custom gas token feature is set as seeded + assertEq( + doo.systemConfigProxy.isCustomGasToken(), + deployOPChainInput.useCustomGasToken, + "SystemConfig isCustomGasToken (fuzz)" + ); + assertEq( + doo.systemConfigProxy.isFeatureEnabled(Features.CUSTOM_GAS_TOKEN), + deployOPChainInput.useCustomGasToken, + "SystemConfig CUSTOM_GAS_TOKEN feature (fuzz)" + ); + } + + function test_customGasToken_enabled_succeeds() public { + deployOPChainInput.useCustomGasToken = true; + DeployOPChain.Output memory doo = deployOPChain.run(deployOPChainInput); + + assertEq(doo.systemConfigProxy.isCustomGasToken(), true, "SystemConfig isCustomGasToken should be true"); + assertEq( + doo.systemConfigProxy.isFeatureEnabled(Features.CUSTOM_GAS_TOKEN), + true, + "SystemConfig CUSTOM_GAS_TOKEN feature should be true" + ); } function test_customDisputeGame_customEnabled_succeeds() public {