diff --git a/packages/protocol/contract_layout.md b/packages/protocol/contract_layout.md index f48f3e8b103..bec4136538e 100644 --- a/packages/protocol/contract_layout.md +++ b/packages/protocol/contract_layout.md @@ -35,10 +35,10 @@ | __gap | uint256[49] | 202 | 0 | 1568 | contracts/L2/TaikoL2.sol:TaikoL2 | | l2Hashes | mapping(uint256 => bytes32) | 251 | 0 | 32 | contracts/L2/TaikoL2.sol:TaikoL2 | | publicInputHash | bytes32 | 252 | 0 | 32 | contracts/L2/TaikoL2.sol:TaikoL2 | -| gasExcess | uint64 | 253 | 0 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | +| parentGasExcess | uint64 | 253 | 0 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | | lastSyncedBlock | uint64 | 253 | 8 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | -| __deprecated1 | uint64 | 253 | 16 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | -| __deprecated2 | uint64 | 253 | 24 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | +| parentTimestamp | uint64 | 253 | 16 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | +| parentGasTarget | uint64 | 253 | 24 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | | l1ChainId | uint64 | 254 | 0 | 8 | contracts/L2/TaikoL2.sol:TaikoL2 | | __gap | uint256[46] | 255 | 0 | 1472 | contracts/L2/TaikoL2.sol:TaikoL2 | diff --git a/packages/protocol/contracts/L1/TaikoData.sol b/packages/protocol/contracts/L1/TaikoData.sol index 86c5093e43d..8b08b699a14 100644 --- a/packages/protocol/contracts/L1/TaikoData.sol +++ b/packages/protocol/contracts/L1/TaikoData.sol @@ -41,7 +41,7 @@ library TaikoData { // --------------------------------------------------------------------- uint8 basefeeAdjustmentQuotient; uint8 basefeeSharingPctg; - uint32 blockGasIssuance; + uint32 gasIssuancePerSecond; // --------------------------------------------------------------------- // Group 6: Others // --------------------------------------------------------------------- @@ -126,7 +126,7 @@ library TaikoData { uint8 blobIndex; uint8 basefeeAdjustmentQuotient; uint8 basefeeSharingPctg; - uint32 blockGasIssuance; + uint32 gasIssuancePerSecond; } /// @dev Struct representing transition to be proven. diff --git a/packages/protocol/contracts/L1/TaikoL1.sol b/packages/protocol/contracts/L1/TaikoL1.sol index df4e47140a1..272cd6c61d9 100644 --- a/packages/protocol/contracts/L1/TaikoL1.sol +++ b/packages/protocol/contracts/L1/TaikoL1.sol @@ -290,18 +290,9 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents { /// @inheritdoc ITaikoL1 function getConfig() public pure virtual override returns (TaikoData.Config memory) { - // All hard-coded configurations: - // - treasury: the actual TaikoL2 address. - // - anchorGasLimit: 250_000 (based on internal devnet, its ~220_000 - // after 256 L2 blocks) return TaikoData.Config({ chainId: LibNetwork.TAIKO_MAINNET, - // If we have 1 block per 12 seconds, then each day there will be 86400/12=7200 blocks. - // We therefore use 7200 as the base unit to configure blockMaxProposals and - // blockRingBufferSize. blockMaxProposals: 324_000, // = 7200 * 45 - // We give 7200 * 5 = 36000 slots for verifeid blocks in case third party apps will use - // their data. blockRingBufferSize: 360_000, // = 7200 * 50 maxBlocksToVerify: 16, blockMaxGasLimit: 240_000_000, @@ -310,7 +301,7 @@ contract TaikoL1 is EssentialContract, ITaikoL1, TaikoEvents { maxAnchorHeightOffset: 64, basefeeAdjustmentQuotient: 8, basefeeSharingPctg: 75, - blockGasIssuance: 20_000_000, + gasIssuancePerSecond: 5_000_000, ontakeForkHeight: 374_400 // = 7200 * 52 }); } diff --git a/packages/protocol/contracts/L1/libs/LibData.sol b/packages/protocol/contracts/L1/libs/LibData.sol index 8804cd2000d..f497b7fa0ac 100644 --- a/packages/protocol/contracts/L1/libs/LibData.sol +++ b/packages/protocol/contracts/L1/libs/LibData.sol @@ -78,7 +78,7 @@ library LibData { blobIndex: 0, basefeeAdjustmentQuotient: 0, basefeeSharingPctg: 0, - blockGasIssuance: 0 + gasIssuancePerSecond: 0 }); } } diff --git a/packages/protocol/contracts/L1/libs/LibProposing.sol b/packages/protocol/contracts/L1/libs/LibProposing.sol index df332d55967..14afcf4f5cd 100644 --- a/packages/protocol/contracts/L1/libs/LibProposing.sol +++ b/packages/protocol/contracts/L1/libs/LibProposing.sol @@ -176,7 +176,7 @@ library LibProposing { blobIndex: local.params.blobIndex, basefeeAdjustmentQuotient: _config.basefeeAdjustmentQuotient, basefeeSharingPctg: _config.basefeeSharingPctg, - blockGasIssuance: _config.blockGasIssuance + gasIssuancePerSecond: _config.gasIssuancePerSecond }); } diff --git a/packages/protocol/contracts/L2/Lib1559Math.sol b/packages/protocol/contracts/L2/Lib1559Math.sol index 4065bed7ca9..8c68091cae4 100644 --- a/packages/protocol/contracts/L2/Lib1559Math.sol +++ b/packages/protocol/contracts/L2/Lib1559Math.sol @@ -17,8 +17,7 @@ library Lib1559Math { error EIP1559_INVALID_PARAMS(); function calc1559BaseFee( - uint32 _gasTarget, - uint8 _adjustmentQuotient, + uint256 _gasTarget, uint64 _gasExcess, uint64 _gasIssuance, uint32 _parentGasUsed @@ -37,42 +36,52 @@ library Lib1559Math { // bonding curve, regardless the actual amount of gas used by this // block, however, this block's gas used will affect the next // block's base fee. - basefee_ = basefee(gasExcess_, uint256(_adjustmentQuotient) * _gasTarget); - - // Always make sure basefee is nonzero, this is required by the node. - if (basefee_ == 0) basefee_ = 1; + basefee_ = basefee(gasExcess_, _gasTarget); } - /// @dev eth_qty(excess_gas_issued) / (TARGET * ADJUSTMENT_QUOTIENT) - /// @param _gasExcess The gas excess value - /// @param _adjustmentFactor The product of gasTarget and adjustmentQuotient - function basefee( - uint256 _gasExcess, - uint256 _adjustmentFactor + /// @dev Returns the new gas excess that will keep the basefee the same. + /// `_newGasTarget * ln(_newGasTarget / _target) + _gasExcess * _newGasTarget / _target` + function adjustExcess( + uint64 _gasExcess, + uint64 _gasTarget, + uint64 _newGasTarget ) internal pure - returns (uint256) + returns (uint64) { - if (_adjustmentFactor == 0) { - revert EIP1559_INVALID_PARAMS(); + if (_gasTarget == 0) { + return _newGasTarget; } - return _ethQty(_gasExcess, _adjustmentFactor) / FixedPointMathLib.WAD; + + uint256 f = FixedPointMathLib.WAD; + uint256 ratio = f * _newGasTarget / _gasTarget; + if (ratio > uint256(type(int256).max)) revert EIP1559_INVALID_PARAMS(); + + int256 lnRatio = FixedPointMathLib.lnWad(int256(ratio)); // may be negative + + uint256 newGasExcess; + assembly { + newGasExcess := sdiv(add(mul(lnRatio, _newGasTarget), mul(ratio, _gasExcess)), f) + } + + return uint64(newGasExcess.min(type(uint64).max)); } - /// @dev exp(gas_qty / TARGET / ADJUSTMENT_QUOTIENT) - function _ethQty( - uint256 _gasExcess, - uint256 _adjustmentFactor - ) - private - pure - returns (uint256) - { - uint256 input = _gasExcess * FixedPointMathLib.WAD / _adjustmentFactor; + /// @dev exp(_gasExcess / _gasTarget) / _gasTarget + function basefee(uint256 _gasExcess, uint256 _gasTarget) internal pure returns (uint256) { + uint256 fee = ethQty(_gasExcess, _gasTarget) / _gasTarget; + return fee == 0 ? 1 : fee; + } + + /// @dev exp(_gasExcess / _gasTarget) + function ethQty(uint256 _gasExcess, uint256 _gasTarget) internal pure returns (uint256) { + if (_gasTarget == 0) revert EIP1559_INVALID_PARAMS(); + + uint256 input = FixedPointMathLib.WAD * _gasExcess / _gasTarget; if (input > MAX_EXP_INPUT) { input = MAX_EXP_INPUT; } - return uint256(FixedPointMathLib.expWad(int256(input))); + return uint256(FixedPointMathLib.expWad(int256(input))) / FixedPointMathLib.WAD; } } diff --git a/packages/protocol/contracts/L2/TaikoL2.sol b/packages/protocol/contracts/L2/TaikoL2.sol index 417a62149fc..68b73e48733 100644 --- a/packages/protocol/contracts/L2/TaikoL2.sol +++ b/packages/protocol/contracts/L2/TaikoL2.sol @@ -25,8 +25,6 @@ contract TaikoL2 is EssentialContract { /// @notice Golden touch address is the only address that can do the anchor transaction. address public constant GOLDEN_TOUCH_ADDRESS = 0x0000777735367b36bC9B61C50022d9D0700dB4Ec; - uint256 public constant ONTAKE_FORK_HEIGHT = 374_400; // = 7200 * 52 - /// @notice Mapping from L2 block numbers to their block hashes. All L2 block hashes will /// be saved in this mapping. mapping(uint256 blockId => bytes32 blockHash) public l2Hashes; @@ -37,13 +35,12 @@ contract TaikoL2 is EssentialContract { /// @notice The gas excess value used to calculate the base fee. /// @dev Slot 3. - uint64 public gasExcess; + uint64 public parentGasExcess; /// @notice The last synced L1 block height. uint64 public lastSyncedBlock; - - uint64 private __deprecated1; // was parentTimestamp - uint64 private __deprecated2; // was __currentBlockTimestamp + uint64 private parentTimestamp; + uint64 private parentGasTarget; /// @notice The L1's chain ID. uint64 public l1ChainId; @@ -52,8 +49,8 @@ contract TaikoL2 is EssentialContract { /// @notice Emitted when the latest L1 block details are anchored to L2. /// @param parentHash The hash of the parent block. - /// @param gasExcess The gas excess value used to calculate the base fee. - event Anchored(bytes32 parentHash, uint64 gasExcess); + /// @param parentGasExcess The gas excess value used to calculate the base fee. + event Anchored(bytes32 parentHash, uint64 parentGasExcess); error L2_BASEFEE_MISMATCH(); error L2_FORK_ERROR(); @@ -68,12 +65,12 @@ contract TaikoL2 is EssentialContract { /// @param _owner The owner of this contract. msg.sender will be used if this value is zero. /// @param _rollupAddressManager The address of the {AddressManager} contract. /// @param _l1ChainId The ID of the base layer. - /// @param _gasExcess The initial gasExcess. + /// @param _initialGasExcess The initial parentGasExcess. function init( address _owner, address _rollupAddressManager, uint64 _l1ChainId, - uint64 _gasExcess + uint64 _initialGasExcess ) external initializer @@ -98,10 +95,21 @@ contract TaikoL2 is EssentialContract { } l1ChainId = _l1ChainId; - gasExcess = _gasExcess; + parentGasExcess = _initialGasExcess; (publicInputHash,) = _calcPublicInputHash(block.number); } + /// @dev Reinitialize some state variables. + /// We may want to init the basefee to a default value using one of the following values. + /// - _initialGasExcess = 274*5_000_000 => basefee =0.01 gwei + /// - _initialGasExcess = 282*5_000_000 => basefee =0.05 gwei + /// - _initialGasExcess = 288*5_000_000 => basefee =0.1 gwei + function init2(uint64 _initialGasExcess) external onlyOwner reinitializer(2) { + parentGasExcess = _initialGasExcess; + parentTimestamp = uint64(block.timestamp); + parentGasTarget = 0; + } + /// @notice Anchors the latest L1 block details to L2 for cross-layer /// message verification. /// @dev This function can be called freely as the golden touch private key is publicly known, @@ -120,13 +128,15 @@ contract TaikoL2 is EssentialContract { external nonReentrant { - if (block.number >= ONTAKE_FORK_HEIGHT) revert L2_FORK_ERROR(); + if (block.number >= ontakeForkHeight()) revert L2_FORK_ERROR(); + + LibL2Config.Config memory config = getConfig(); _anchor( _l1BlockId, _l1StateRoot, _parentGasUsed, - 0, // not used - 0 // not used + config.gasTargetPerL1Block, + config.basefeeAdjustmentQuotient ); } @@ -134,18 +144,18 @@ contract TaikoL2 is EssentialContract { uint64 _anchorBlockId, bytes32 _anchorStateRoot, uint32 _parentGasUsed, - uint32 _blockGasIssuance, + uint32 _gasIssuancePerSecond, uint8 _basefeeAdjustmentQuotient ) external nonReentrant { - if (block.number < ONTAKE_FORK_HEIGHT) revert L2_FORK_ERROR(); + if (block.number < ontakeForkHeight()) revert L2_FORK_ERROR(); _anchor( _anchorBlockId, _anchorStateRoot, _parentGasUsed, - _blockGasIssuance, + _gasIssuancePerSecond, _basefeeAdjustmentQuotient ); } @@ -177,23 +187,21 @@ contract TaikoL2 is EssentialContract { /// @param _anchorBlockId The synced L1 height in the next Taiko block /// @param _parentGasUsed Gas used in the parent block. /// @return basefee_ The calculated EIP-1559 base fee per gas. - /// @return gasExcess_ The new gasExcess value. + /// @return parentGasExcess_ The new parentGasExcess value. function getBasefee( uint64 _anchorBlockId, uint32 _parentGasUsed ) public view - returns (uint256 basefee_, uint64 gasExcess_) + returns (uint256 basefee_, uint64 parentGasExcess_) { LibL2Config.Config memory config = getConfig(); - uint64 gasIssuance = uint64(_anchorBlockId - lastSyncedBlock) * config.gasTargetPerL1Block; - (basefee_, gasExcess_) = Lib1559Math.calc1559BaseFee( - config.gasTargetPerL1Block, - config.basefeeAdjustmentQuotient, - gasExcess, - gasIssuance, + (basefee_, parentGasExcess_) = Lib1559Math.calc1559BaseFee( + uint256(config.gasTargetPerL1Block) * config.basefeeAdjustmentQuotient, + parentGasExcess, + uint64(_anchorBlockId - lastSyncedBlock) * config.gasTargetPerL1Block, _parentGasUsed ); } @@ -220,26 +228,35 @@ contract TaikoL2 is EssentialContract { return false; } + function ontakeForkHeight() public pure virtual returns (uint64) { + return 0; + } + /// @notice Calculates the basefee and the new gas excess value based on parent gas used and gas /// excess. - /// @param _blockGasIssuance The L2 block's gas issuance. + /// @param _gasIssuancePerSecond The gas target for L2 per second. + /// @param _blocktime The time between this block and the parent block. /// @param _adjustmentQuotient The gas adjustment quotient. - /// @param _gasExcess The current gas excess value. + /// @param _parentGasExcess The current gas excess value. /// @param _parentGasUsed Total gas used by the parent block. /// @return basefee_ Next block's base fee. - /// @return gasExcess_ The new gas excess value. + /// @return parentGasExcess_ The new gas excess value. function calculateBaseFee( - uint32 _blockGasIssuance, + uint32 _gasIssuancePerSecond, + uint64 _blocktime, uint8 _adjustmentQuotient, - uint64 _gasExcess, + uint64 _parentGasExcess, uint32 _parentGasUsed ) public pure - returns (uint256 basefee_, uint64 gasExcess_) + returns (uint256 basefee_, uint64 parentGasExcess_) { return Lib1559Math.calc1559BaseFee( - _blockGasIssuance, _adjustmentQuotient, _gasExcess, _blockGasIssuance, _parentGasUsed + uint256(_gasIssuancePerSecond) * _adjustmentQuotient, + _parentGasExcess, + _blocktime * _gasIssuancePerSecond, + _parentGasUsed ); } @@ -247,8 +264,8 @@ contract TaikoL2 is EssentialContract { uint64 _anchorBlockId, bytes32 _anchorStateRoot, uint32 _parentGasUsed, - uint32 _blockGasIssuance, // only used by ontake - uint8 _basefeeAdjustmentQuotient // only used by ontake + uint32 _gasIssuancePerSecond, + uint8 _basefeeAdjustmentQuotient ) private { @@ -261,25 +278,34 @@ contract TaikoL2 is EssentialContract { if (msg.sender != GOLDEN_TOUCH_ADDRESS) revert L2_INVALID_SENDER(); - uint256 parentId; - unchecked { - parentId = block.number - 1; - } - // Verify ancestor hashes - (bytes32 publicInputHashOld, bytes32 publicInputHashNew) = _calcPublicInputHash(parentId); - if (publicInputHash != publicInputHashOld) { - revert L2_PUBLIC_INPUT_HASH_MISMATCH(); + uint256 parentId = block.number - 1; + (bytes32 currentPublicInputHash, bytes32 newPublicInputHash) = + _calcPublicInputHash(parentId); + if (publicInputHash != currentPublicInputHash) revert L2_PUBLIC_INPUT_HASH_MISMATCH(); + + // Check if the gas settings has changed + bool postFork = block.number >= ontakeForkHeight(); + uint64 newGasTarget = uint64(_gasIssuancePerSecond) * _basefeeAdjustmentQuotient; + if (postFork && newGasTarget != parentGasTarget) { + // adjust parentGasExcess to keep the basefee unchanged. Note that due to math + // calculation precision, the basefee may change slightly. + parentGasExcess = + Lib1559Math.adjustExcess(parentGasExcess, parentGasTarget, newGasTarget); } // Verify the base fee per gas is correct - (uint256 _basefee, uint64 _gasExcess) = block.number < ONTAKE_FORK_HEIGHT - ? getBasefee(_anchorBlockId, _parentGasUsed) - : calculateBaseFee(_blockGasIssuance, _basefeeAdjustmentQuotient, gasExcess, _parentGasUsed); - - if (!skipFeeCheck() && block.basefee != _basefee) { - revert L2_BASEFEE_MISMATCH(); - } + (uint256 basefee, uint64 newGasExcess) = postFork + ? calculateBaseFee( + _gasIssuancePerSecond, + uint64(block.timestamp - parentTimestamp), + _basefeeAdjustmentQuotient, + parentGasExcess, + _parentGasUsed + ) + : getBasefee(_anchorBlockId, _parentGasUsed); + + if (!skipFeeCheck() && block.basefee != basefee) revert L2_BASEFEE_MISMATCH(); if (_anchorBlockId > lastSyncedBlock) { // Store the L1's state root as a signal to the local signal service to @@ -292,12 +318,15 @@ contract TaikoL2 is EssentialContract { } // Update state variables - bytes32 _parentHash = blockhash(parentId); - l2Hashes[parentId] = _parentHash; - publicInputHash = publicInputHashNew; - gasExcess = _gasExcess; + bytes32 parentHash = blockhash(parentId); + l2Hashes[parentId] = parentHash; + + publicInputHash = newPublicInputHash; + parentGasExcess = newGasExcess; + parentTimestamp = uint64(block.timestamp); + parentGasTarget = newGasTarget; - emit Anchored(_parentHash, _gasExcess); + emit Anchored(parentHash, newGasExcess); } function _calcPublicInputHash(uint256 _blockId) diff --git a/packages/protocol/contracts/hekla/HeklaTaikoL1.sol b/packages/protocol/contracts/hekla/HeklaTaikoL1.sol index 79d7c750108..32299e5d74d 100644 --- a/packages/protocol/contracts/hekla/HeklaTaikoL1.sol +++ b/packages/protocol/contracts/hekla/HeklaTaikoL1.sol @@ -22,7 +22,7 @@ contract HeklaTaikoL1 is TaikoL1 { maxAnchorHeightOffset: 64, basefeeAdjustmentQuotient: 8, basefeeSharingPctg: 75, - blockGasIssuance: 20_000_000, + gasIssuancePerSecond: 5_000_000, ontakeForkHeight: 720_000 // = 7200 * 100 }); } diff --git a/packages/protocol/contracts/hekla/HeklaTaikoL2.sol b/packages/protocol/contracts/hekla/HeklaTaikoL2.sol new file mode 100644 index 00000000000..68b518da5da --- /dev/null +++ b/packages/protocol/contracts/hekla/HeklaTaikoL2.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import "../L2/TaikoL2.sol"; + +/// @title HeklaTaikoL2 +/// @custom:security-contact security@taiko.xyz +contract HeklaTaikoL2 is TaikoL2 { + function ontakeForkHeight() public pure override returns (uint64) { + return 720_000; // = 7200 * 100 + } +} diff --git a/packages/protocol/contracts/mainnet/MainnetTaikoL1.sol b/packages/protocol/contracts/mainnet/MainnetTaikoL1.sol index 3b752f1c54d..c2ff8c232c8 100644 --- a/packages/protocol/contracts/mainnet/MainnetTaikoL1.sol +++ b/packages/protocol/contracts/mainnet/MainnetTaikoL1.sol @@ -10,6 +10,33 @@ import "./LibRollupAddressCache.sol"; /// @notice See the documentation in {TaikoL1}. /// @custom:security-contact security@taiko.xyz contract MainnetTaikoL1 is TaikoL1 { + /// @inheritdoc ITaikoL1 + function getConfig() public pure override returns (TaikoData.Config memory) { + // All hard-coded configurations: + // - treasury: the actual TaikoL2 address. + // - anchorGasLimit: 250_000 (based on internal devnet, its ~220_000 + // after 256 L2 blocks) + return TaikoData.Config({ + chainId: LibNetwork.TAIKO_MAINNET, + // If we have 1 block per 12 seconds, then each day there will be 86400/12=7200 blocks. + // We therefore use 7200 as the base unit to configure blockMaxProposals and + // blockRingBufferSize. + blockMaxProposals: 324_000, // = 7200 * 45 + // We give 7200 * 5 = 36000 slots for verifeid blocks in case third party apps will use + // their data. + blockRingBufferSize: 360_000, // = 7200 * 50 + maxBlocksToVerify: 16, + blockMaxGasLimit: 240_000_000, + livenessBond: 125e18, // 125 Taiko token + stateRootSyncInternal: 16, + maxAnchorHeightOffset: 64, + basefeeAdjustmentQuotient: 8, + basefeeSharingPctg: 75, + gasIssuancePerSecond: 5_000_000, + ontakeForkHeight: 374_400 // = 7200 * 52 + }); + } + function _getAddress(uint64 _chainId, bytes32 _name) internal view override returns (address) { (bool found, address addr) = LibRollupAddressCache.getAddress(_chainId, _name); return found ? addr : super._getAddress(_chainId, _name); diff --git a/packages/protocol/contracts/mainnet/MainnetTaikoL2.sol b/packages/protocol/contracts/mainnet/MainnetTaikoL2.sol new file mode 100644 index 00000000000..6600050a1df --- /dev/null +++ b/packages/protocol/contracts/mainnet/MainnetTaikoL2.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import "../L2/TaikoL2.sol"; + +/// @title MainnetTaikoL2 +/// @custom:security-contact security@taiko.xyz +contract MainnetTaikoL2 is TaikoL2 { + function ontakeForkHeight() public pure override returns (uint64) { + return 374_400; // = 7200 * 52 + } +} diff --git a/packages/protocol/test/L2/Lib1559Math.t.sol b/packages/protocol/test/L2/Lib1559Math.t.sol index a4d275d26be..e05e9ddf104 100644 --- a/packages/protocol/test/L2/Lib1559Math.t.sol +++ b/packages/protocol/test/L2/Lib1559Math.t.sol @@ -6,33 +6,60 @@ import "../TaikoTest.sol"; contract TestLib1559Math is TaikoTest { using LibMath for uint256; - function test_eip1559_math() external pure { - LibL2Config.Config memory config = LibL2Config.get(); - uint256 adjustmentFactor = config.gasTargetPerL1Block * config.basefeeAdjustmentQuotient; - - uint256 baseFee; - uint256 i; - uint256 target = 0.01 gwei; + function test_ethQty() external { + assertEq(Lib1559Math.ethQty(0, 60_000_000 * 8), 1); + assertEq(Lib1559Math.ethQty(60_000_000, 60_000_000 * 8), 1); + assertEq(Lib1559Math.ethQty(60_000_000 * 100, 60_000_000 * 8), 268_337); + assertEq(Lib1559Math.ethQty(60_000_000 * 200, 60_000_000 * 8), 72_004_899_337); + } - for (uint256 k; k < 5; ++k) { - for (; baseFee < target; ++i) { - baseFee = Lib1559Math.basefee(config.gasTargetPerL1Block * i, adjustmentFactor); + function test_basefee() external pure { + uint256 basefee; + for (uint256 i; basefee <= 5000;) { + // uint 0.01 gwei + basefee = Lib1559Math.basefee(i * 5_000_000, 5_000_000 * 8) / 10_000_000; + if (basefee != 0) { + console2.log("basefee (uint 0.01gwei) after", i, "seconds:", basefee); } - console2.log("base fee:", baseFee); - console2.log(" gasExcess:", config.gasTargetPerL1Block * i); - console2.log(" i:", i); - target *= 10; + i += 1; } } - function test_eip1559_math_max() external pure { - LibL2Config.Config memory config = LibL2Config.get(); - uint256 adjustmentFactor = config.gasTargetPerL1Block * config.basefeeAdjustmentQuotient; + function test_change_of_quotient_and_gips() public { + uint64 excess = 150 * 2_000_000; + uint64 target = 4 * 2_000_000; + uint256 unit = 10_000_000; // 0.01 gwei + + // uint 0.01 gwei + uint256 baselineBasefee = Lib1559Math.basefee(excess, target) / unit; + console2.log("baseline basefee: ", baselineBasefee); + + uint256 basefee = Lib1559Math.basefee(excess, target * 2) / unit; + console2.log("basefee will decrease if target increases:", basefee); - uint256 gasExcess = type(uint64).max; - uint256 baseFee = Lib1559Math.basefee(gasExcess, adjustmentFactor); + basefee = Lib1559Math.basefee(excess, target / 2) / unit; + console2.log("basefee will increase if target decreases:", basefee); - console2.log("base fee (gwei):", baseFee / 1 gwei); - console2.log(" gasExcess:", gasExcess); + console2.log("maintain basefee when target increases"); + { + uint64 newTarget = 5 * 2_000_000; + uint64 newExcess = Lib1559Math.adjustExcess(excess, target, newTarget); + basefee = Lib1559Math.basefee(newExcess, newTarget) / unit; + console2.log("old gas excess: ", excess); + console2.log("new gas excess: ", newExcess); + console2.log("basefee: ", basefee); + assertEq(baselineBasefee, basefee); + } + + console2.log("maintain basefee when target decreases"); + { + uint64 newTarget = 3 * 2_000_000; + uint64 newExcess = Lib1559Math.adjustExcess(excess, target, newTarget); + basefee = Lib1559Math.basefee(newExcess, newTarget) / unit; + console2.log("old gas excess: ", excess); + console2.log("new gas excess: ", newExcess); + console2.log("basefee: ", basefee); + assertEq(baselineBasefee, basefee); + } } } diff --git a/packages/protocol/test/L2/TaikoL2EIP1559Configurable.sol b/packages/protocol/test/L2/TaikoL2EIP1559Configurable.sol index 69661686afd..75b2cc0529d 100644 --- a/packages/protocol/test/L2/TaikoL2EIP1559Configurable.sol +++ b/packages/protocol/test/L2/TaikoL2EIP1559Configurable.sol @@ -34,7 +34,7 @@ contract TaikoL2EIP1559Configurable is TaikoL2 { if (_newConfig.basefeeAdjustmentQuotient == 0) revert L2_INVALID_CONFIG(); customConfig = _newConfig; - gasExcess = _newGasExcess; + parentGasExcess = _newGasExcess; emit ConfigAndExcessChanged(_newConfig, _newGasExcess); } @@ -43,4 +43,8 @@ contract TaikoL2EIP1559Configurable is TaikoL2 { function getConfig() public view override returns (LibL2Config.Config memory) { return customConfig; } + + function ontakeForkHeight() public pure override returns (uint64) { + return 10_000; + } } diff --git a/packages/protocol/utils/generate_genesis/taikoL2.ts b/packages/protocol/utils/generate_genesis/taikoL2.ts index 9e631d35f6c..30d33fedd4f 100644 --- a/packages/protocol/utils/generate_genesis/taikoL2.ts +++ b/packages/protocol/utils/generate_genesis/taikoL2.ts @@ -515,7 +515,7 @@ async function generateContractConfigs( // TaikoL2 => CrossChainOwned l1ChainId, // TaikoL2 - gasExcess: param1559.gasExcess, + parentGasExcess: param1559.gasExcess, publicInputHash: `${ethers.utils.solidityKeccak256( ["bytes32[256]"], [