diff --git a/packages/contracts-bedrock/interfaces/L2/IL1Block.sol b/packages/contracts-bedrock/interfaces/L2/IL1Block.sol index c8c2c9119ce..30c42275adf 100644 --- a/packages/contracts-bedrock/interfaces/L2/IL1Block.sol +++ b/packages/contracts-bedrock/interfaces/L2/IL1Block.sol @@ -3,23 +3,22 @@ pragma solidity ^0.8.0; interface IL1Block { function DEPOSITOR_ACCOUNT() external pure returns (address addr_); - function number() external view returns (uint64); - function timestamp() external view returns (uint64); - function basefee() external view returns (uint256); - function hash() external view returns (bytes32); - function sequenceNumber() external view returns (uint64); - function blobBaseFeeScalar() external view returns (uint32); function baseFeeScalar() external view returns (uint32); + function basefee() external view returns (uint256); function batcherHash() external view returns (bytes32); + function blobBaseFee() external view returns (uint256); + function blobBaseFeeScalar() external view returns (uint32); + function gasPayingToken() external pure returns (address addr_, uint8 decimals_); + function gasPayingTokenName() external pure returns (string memory name_); + function gasPayingTokenSymbol() external pure returns (string memory symbol_); + function hash() external view returns (bytes32); + function isCustomGasToken() external pure returns (bool is_); function l1FeeOverhead() external view returns (uint256); function l1FeeScalar() external view returns (uint256); - function blobBaseFee() external view returns (uint256); - function operatorFeeConstant() external view returns (uint64); + function number() external view returns (uint64); function operatorFeeScalar() external view returns (uint32); - function version() external pure returns (string memory); - function isCustomGasToken() external view returns (bool isCustom_); - function gasPayingTokenName() external view returns (string memory name_); - function gasPayingTokenSymbol() external view returns (string memory symbol_); + function operatorFeeConstant() external view returns (uint64); + function sequenceNumber() external view returns (uint64); function setL1BlockValues( uint64 _number, uint64 _timestamp, @@ -33,7 +32,8 @@ interface IL1Block { external; function setL1BlockValuesEcotone() external; function setL1BlockValuesIsthmus() external; - function setCustomGasToken() external; + function timestamp() external view returns (uint64); + function version() external pure returns (string memory); function __constructor__() external; } diff --git a/packages/contracts-bedrock/interfaces/L2/IL1BlockCGT.sol b/packages/contracts-bedrock/interfaces/L2/IL1BlockCGT.sol new file mode 100644 index 00000000000..4e1e3d92bf4 --- /dev/null +++ b/packages/contracts-bedrock/interfaces/L2/IL1BlockCGT.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IL1BlockCGT { + function DEPOSITOR_ACCOUNT() external pure returns (address addr_); + function number() external view returns (uint64); + function timestamp() external view returns (uint64); + function basefee() external view returns (uint256); + function hash() external view returns (bytes32); + function sequenceNumber() external view returns (uint64); + function blobBaseFeeScalar() external view returns (uint32); + function baseFeeScalar() external view returns (uint32); + function batcherHash() external view returns (bytes32); + function l1FeeOverhead() external view returns (uint256); + function l1FeeScalar() external view returns (uint256); + function blobBaseFee() external view returns (uint256); + function operatorFeeConstant() external view returns (uint64); + function operatorFeeScalar() external view returns (uint32); + function version() external pure returns (string memory); + function isCustomGasToken() external view returns (bool isCustom_); + function gasPayingTokenName() external view returns (string memory name_); + function gasPayingTokenSymbol() external view returns (string memory symbol_); + function setL1BlockValues( + uint64 _number, + uint64 _timestamp, + uint256 _basefee, + bytes32 _hash, + uint64 _sequenceNumber, + bytes32 _batcherHash, + uint256 _l1FeeOverhead, + uint256 _l1FeeScalar + ) + external; + function setL1BlockValuesEcotone() external; + function setL1BlockValuesIsthmus() external; + function setCustomGasToken() external; + + function __constructor__() external; +} diff --git a/packages/contracts-bedrock/interfaces/L2/IL2ToL1MessagePasser.sol b/packages/contracts-bedrock/interfaces/L2/IL2ToL1MessagePasser.sol index 488798c65ac..4629dbaba8d 100644 --- a/packages/contracts-bedrock/interfaces/L2/IL2ToL1MessagePasser.sol +++ b/packages/contracts-bedrock/interfaces/L2/IL2ToL1MessagePasser.sol @@ -2,8 +2,6 @@ pragma solidity ^0.8.0; interface IL2ToL1MessagePasser { - error L2ToL1MessagePasser_NotAllowedOnCGTMode(); - event MessagePassed( uint256 indexed nonce, address indexed sender, diff --git a/packages/contracts-bedrock/interfaces/L2/IL2ToL1MessagePasserCGT.sol b/packages/contracts-bedrock/interfaces/L2/IL2ToL1MessagePasserCGT.sol new file mode 100644 index 00000000000..cdb94f21d47 --- /dev/null +++ b/packages/contracts-bedrock/interfaces/L2/IL2ToL1MessagePasserCGT.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IL2ToL1MessagePasserCGT { + error L2ToL1MessagePasserCGT_NotAllowedOnCGTMode(); + + event MessagePassed( + uint256 indexed nonce, + address indexed sender, + address indexed target, + uint256 value, + uint256 gasLimit, + bytes data, + bytes32 withdrawalHash + ); + event WithdrawerBalanceBurnt(uint256 indexed amount); + + receive() external payable; + + function MESSAGE_VERSION() external view returns (uint16); + function burn() external; + function initiateWithdrawal(address _target, uint256 _gasLimit, bytes memory _data) external payable; + function messageNonce() external view returns (uint256); + function sentMessages(bytes32) external view returns (bool); + function version() external view returns (string memory); + + function __constructor__() external; +} diff --git a/packages/contracts-bedrock/scripts/L2Genesis.s.sol b/packages/contracts-bedrock/scripts/L2Genesis.s.sol index 4516d8061a7..755af0d42e1 100644 --- a/packages/contracts-bedrock/scripts/L2Genesis.s.sol +++ b/packages/contracts-bedrock/scripts/L2Genesis.s.sol @@ -31,6 +31,7 @@ import { IL2CrossDomainMessenger } from "interfaces/L2/IL2CrossDomainMessenger.s import { IGasPriceOracle } from "interfaces/L2/IGasPriceOracle.sol"; import { IL1Block } from "interfaces/L2/IL1Block.sol"; import { ILiquidityController } from "interfaces/L2/ILiquidityController.sol"; +import { IL1BlockCGT } from "interfaces/L2/IL1BlockCGT.sol"; /// @title L2Genesis /// @notice Generates the genesis state for the L2 network. @@ -225,7 +226,7 @@ contract L2Genesis is Script { setL1BlockNumber(); // 13 setL2ERC721Bridge(_input.l1ERC721BridgeProxy); // 14 setL1Block(_input.isCustomGasToken); // 15 - setL2ToL1MessagePasser(); // 16 + setL2ToL1MessagePasser(_input.isCustomGasToken); // 16 setOptimismMintableERC721Factory(_input); // 17 setProxyAdmin(_input); // 18 setBaseFeeVault(_input); // 19 @@ -261,8 +262,14 @@ contract L2Genesis is Script { vm.store(impl, _ownerSlot, bytes32(uint256(uint160(_input.opChainProxyAdminOwner)))); } - function setL2ToL1MessagePasser() internal { - _setImplementationCode(Predeploys.L2_TO_L1_MESSAGE_PASSER); + function setL2ToL1MessagePasser(bool _isCustomGasToken) internal { + if (_isCustomGasToken) { + string memory cname = "L2ToL1MessagePasserCGT"; + address impl = Predeploys.predeployToCodeNamespace(Predeploys.L2_TO_L1_MESSAGE_PASSER); + vm.etch(impl, vm.getDeployedCode(string.concat(cname, ".sol:", cname))); + } else { + _setImplementationCode(Predeploys.L2_TO_L1_MESSAGE_PASSER); + } } /// @notice This predeploy is following the safety invariant #1. @@ -362,11 +369,18 @@ contract L2Genesis is Script { /// @notice This predeploy is following the safety invariant #1. function setL1Block(bool _isCustomGasToken) internal { - _setImplementationCode(Predeploys.L1_BLOCK_ATTRIBUTES); if (_isCustomGasToken) { - vm.startPrank(IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).DEPOSITOR_ACCOUNT()); - IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).setCustomGasToken(); + // Set the implementation code for L1BlockCGT + string memory cname = "L1BlockCGT"; + address impl = Predeploys.predeployToCodeNamespace(Predeploys.L1_BLOCK_ATTRIBUTES); + vm.etch(impl, vm.getDeployedCode(string.concat(cname, ".sol:", cname))); + + // Set the custom gas token flag + vm.startPrank(IL1BlockCGT(Predeploys.L1_BLOCK_ATTRIBUTES).DEPOSITOR_ACCOUNT()); + IL1BlockCGT(Predeploys.L1_BLOCK_ATTRIBUTES).setCustomGasToken(); vm.stopPrank(); + } else { + _setImplementationCode(Predeploys.L1_BLOCK_ATTRIBUTES); } } diff --git a/packages/contracts-bedrock/scripts/checks/test-validation/main.go b/packages/contracts-bedrock/scripts/checks/test-validation/main.go index 7c4dba25ce9..863f180c1d2 100644 --- a/packages/contracts-bedrock/scripts/checks/test-validation/main.go +++ b/packages/contracts-bedrock/scripts/checks/test-validation/main.go @@ -323,21 +323,19 @@ var excludedPaths = []string{ // Resolving these naming inconsistencies is outside the script's scope, but they are // documented here to avoid false validation failures while maintaining the validation rules // for standard contract tests. - "test/invariants/", // Invariant testing framework - no direct src counterpart - "test/opcm/", // OP Chain Manager tests - may have different structure - "test/scripts/", // Script tests - test deployment/utility scripts, not contracts - "test/integration/", // Integration tests - test multiple contracts together - "test/cannon/MIPS64Memory.t.sol", // Tests external MIPS implementation - "test/dispute/lib/LibClock.t.sol", // Tests library utilities - "test/dispute/lib/LibGameId.t.sol", // Tests library utilities - "test/setup/DeployVariations.t.sol", // Tests deployment variations - "test/universal/BenchmarkTest.t.sol", // Performance benchmarking tests - "test/universal/ExtendedPause.t.sol", // Tests extended functionality - "test/vendor/Initializable.t.sol", // Tests external vendor code - "test/vendor/InitializableOZv5.t.sol", // Tests external vendor code - "test/L2/L1BlockCGT.t.sol", // Tests L1Block with custom gas token - "test/L2/L2ToL1MessagePasserCGT.t.sol", // Tests L2ToL1MessagePasser with custom gas token - "test/L1/OptimismPortal2CGT.t.sol", // Tests OptimismPortal2 with custom gas token + "test/invariants/", // Invariant testing framework - no direct src counterpart + "test/opcm/", // OP Chain Manager tests - may have different structure + "test/scripts/", // Script tests - test deployment/utility scripts, not contracts + "test/integration/", // Integration tests - test multiple contracts together + "test/cannon/MIPS64Memory.t.sol", // Tests external MIPS implementation + "test/dispute/lib/LibClock.t.sol", // Tests library utilities + "test/dispute/lib/LibGameId.t.sol", // Tests library utilities + "test/setup/DeployVariations.t.sol", // Tests deployment variations + "test/universal/BenchmarkTest.t.sol", // Performance benchmarking tests + "test/universal/ExtendedPause.t.sol", // Tests extended functionality + "test/vendor/Initializable.t.sol", // Tests external vendor code + "test/vendor/InitializableOZv5.t.sol", // Tests external vendor code + "test/L1/OptimismPortal2CGT.t.sol", // Tests OptimismPortal2 with custom gas token // PATHS EXCLUDED FROM CONTRACT NAME FILE PATH VALIDATION: // These paths are excluded because they don't follow the standard naming convention where the diff --git a/packages/contracts-bedrock/snapshots/abi/L1Block.json b/packages/contracts-bedrock/snapshots/abi/L1Block.json index 55b23f0699b..153d2676cf5 100644 --- a/packages/contracts-bedrock/snapshots/abi/L1Block.json +++ b/packages/contracts-bedrock/snapshots/abi/L1Block.json @@ -77,6 +77,24 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [], + "name": "gasPayingToken", + "outputs": [ + { + "internalType": "address", + "name": "addr_", + "type": "address" + }, + { + "internalType": "uint8", + "name": "decimals_", + "type": "uint8" + } + ], + "stateMutability": "pure", + "type": "function" + }, { "inputs": [], "name": "gasPayingTokenName", @@ -87,7 +105,7 @@ "type": "string" } ], - "stateMutability": "view", + "stateMutability": "pure", "type": "function" }, { @@ -100,7 +118,7 @@ "type": "string" } ], - "stateMutability": "view", + "stateMutability": "pure", "type": "function" }, { @@ -122,11 +140,11 @@ "outputs": [ { "internalType": "bool", - "name": "isCustom_", + "name": "is_", "type": "bool" } ], - "stateMutability": "view", + "stateMutability": "pure", "type": "function" }, { @@ -207,13 +225,6 @@ "stateMutability": "view", "type": "function" }, - { - "inputs": [], - "name": "setCustomGasToken", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { diff --git a/packages/contracts-bedrock/snapshots/abi/L1BlockCGT.json b/packages/contracts-bedrock/snapshots/abi/L1BlockCGT.json new file mode 100644 index 00000000000..55b23f0699b --- /dev/null +++ b/packages/contracts-bedrock/snapshots/abi/L1BlockCGT.json @@ -0,0 +1,305 @@ +[ + { + "inputs": [], + "name": "DEPOSITOR_ACCOUNT", + "outputs": [ + { + "internalType": "address", + "name": "addr_", + "type": "address" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [], + "name": "baseFeeScalar", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "basefee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "batcherHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "blobBaseFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "blobBaseFeeScalar", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gasPayingTokenName", + "outputs": [ + { + "internalType": "string", + "name": "name_", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gasPayingTokenSymbol", + "outputs": [ + { + "internalType": "string", + "name": "symbol_", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "hash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "isCustomGasToken", + "outputs": [ + { + "internalType": "bool", + "name": "isCustom_", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1FeeOverhead", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1FeeScalar", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "number", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "operatorFeeConstant", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "operatorFeeScalar", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "sequenceNumber", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "setCustomGasToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "_number", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "_timestamp", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "_basefee", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "_hash", + "type": "bytes32" + }, + { + "internalType": "uint64", + "name": "_sequenceNumber", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "_batcherHash", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "_l1FeeOverhead", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_l1FeeScalar", + "type": "uint256" + } + ], + "name": "setL1BlockValues", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "setL1BlockValuesEcotone", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "setL1BlockValuesIsthmus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "timestamp", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "pure", + "type": "function" + } +] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/L2ToL1MessagePasser.json b/packages/contracts-bedrock/snapshots/abi/L2ToL1MessagePasser.json index 232440307d8..77e1cf7596b 100644 --- a/packages/contracts-bedrock/snapshots/abi/L2ToL1MessagePasser.json +++ b/packages/contracts-bedrock/snapshots/abi/L2ToL1MessagePasser.json @@ -152,10 +152,5 @@ ], "name": "WithdrawerBalanceBurnt", "type": "event" - }, - { - "inputs": [], - "name": "L2ToL1MessagePasser_NotAllowedOnCGTMode", - "type": "error" } ] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/abi/L2ToL1MessagePasserCGT.json b/packages/contracts-bedrock/snapshots/abi/L2ToL1MessagePasserCGT.json new file mode 100644 index 00000000000..409f61e6ed4 --- /dev/null +++ b/packages/contracts-bedrock/snapshots/abi/L2ToL1MessagePasserCGT.json @@ -0,0 +1,161 @@ +[ + { + "stateMutability": "payable", + "type": "receive" + }, + { + "inputs": [], + "name": "MESSAGE_VERSION", + "outputs": [ + { + "internalType": "uint16", + "name": "", + "type": "uint16" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_target", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_gasLimit", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "name": "initiateWithdrawal", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [], + "name": "messageNonce", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "name": "sentMessages", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "nonce", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "target", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "gasLimit", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "data", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "withdrawalHash", + "type": "bytes32" + } + ], + "name": "MessagePassed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "WithdrawerBalanceBurnt", + "type": "event" + }, + { + "inputs": [], + "name": "L2ToL1MessagePasserCGT_NotAllowedOnCGTMode", + "type": "error" + } +] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/semver-lock.json b/packages/contracts-bedrock/snapshots/semver-lock.json index 2a01a6a46ef..03ea828a725 100644 --- a/packages/contracts-bedrock/snapshots/semver-lock.json +++ b/packages/contracts-bedrock/snapshots/semver-lock.json @@ -60,8 +60,12 @@ "sourceCodeHash": "0x4351fe2ac1106c8c220b8cfe7839bc107c24d8084deb21259ac954f5a362725d" }, "src/L2/L1Block.sol:L1Block": { + "initCodeHash": "0xc35734387887a95f611888f3944546c6bcf82fd4c05dcdaa1e019779b628ad68", + "sourceCodeHash": "0x6e5349fd781d5f0127ff29ccea4d86a80240550cfa322364183a0f629abcb43e" + }, + "src/L2/L1BlockCGT.sol:L1BlockCGT": { "initCodeHash": "0x90ca955a1927e9637289a98f27a40a4a2332e3633cc26ed2fce0008847669c56", - "sourceCodeHash": "0xae35ae9826a846a895839304c34de5fad668b20e716ccc50c771685368e1a76f" + "sourceCodeHash": "0x9e79c368ae5f046fd97df46a47aff60f9c37982580f0c1f8f931847d3122ef9b" }, "src/L2/L1FeeVault.sol:L1FeeVault": { "initCodeHash": "0x9b664e3d84ad510091337b4aacaa494b142512e2f6f7fbcdb6210ed62ca9b885", @@ -84,8 +88,12 @@ "sourceCodeHash": "0xde724da82ecf3c96b330c2876a7285b6e2b933ac599241eaa3174c443ebbe33a" }, "src/L2/L2ToL1MessagePasser.sol:L2ToL1MessagePasser": { - "initCodeHash": "0x98fbe3f1325e245b29edc3710877736165692026becb93c59a7dbcfc34af0809", - "sourceCodeHash": "0xf700775f5401872798bb13db5fe37ebd361acbee05b1e2c46c17178737b2ec6d" + "initCodeHash": "0x88f7b25f956eceeab9ad84c17e66cded6a1acbb933054ac2c8b336641f70f875", + "sourceCodeHash": "0x83396cbd12a0c5c02e09a4d99c4b62ab4e9d9eb762745e63283e2e818a78a39c" + }, + "src/L2/L2ToL1MessagePasserCGT.sol:L2ToL1MessagePasserCGT": { + "initCodeHash": "0x9a99e97e5e4aeef421226a7f30e5132cee3d1ea1afb16fe41c5aac97478b8a80", + "sourceCodeHash": "0x7233348d779a1679a9862d65c9208d7076bc353b25d063bc3eba8acbdedc5f21" }, "src/L2/L2ToL2CrossDomainMessenger.sol:L2ToL2CrossDomainMessenger": { "initCodeHash": "0x975fd33a3a386310d54dbb01b56f3a6a8350f55a3b6bd7781e5ccc2166ddf2e6", diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L1BlockCGT.json b/packages/contracts-bedrock/snapshots/storageLayout/L1BlockCGT.json new file mode 100644 index 00000000000..2c23f063678 --- /dev/null +++ b/packages/contracts-bedrock/snapshots/storageLayout/L1BlockCGT.json @@ -0,0 +1,93 @@ +[ + { + "bytes": "8", + "label": "number", + "offset": 0, + "slot": "0", + "type": "uint64" + }, + { + "bytes": "8", + "label": "timestamp", + "offset": 8, + "slot": "0", + "type": "uint64" + }, + { + "bytes": "32", + "label": "basefee", + "offset": 0, + "slot": "1", + "type": "uint256" + }, + { + "bytes": "32", + "label": "hash", + "offset": 0, + "slot": "2", + "type": "bytes32" + }, + { + "bytes": "8", + "label": "sequenceNumber", + "offset": 0, + "slot": "3", + "type": "uint64" + }, + { + "bytes": "4", + "label": "blobBaseFeeScalar", + "offset": 8, + "slot": "3", + "type": "uint32" + }, + { + "bytes": "4", + "label": "baseFeeScalar", + "offset": 12, + "slot": "3", + "type": "uint32" + }, + { + "bytes": "32", + "label": "batcherHash", + "offset": 0, + "slot": "4", + "type": "bytes32" + }, + { + "bytes": "32", + "label": "l1FeeOverhead", + "offset": 0, + "slot": "5", + "type": "uint256" + }, + { + "bytes": "32", + "label": "l1FeeScalar", + "offset": 0, + "slot": "6", + "type": "uint256" + }, + { + "bytes": "32", + "label": "blobBaseFee", + "offset": 0, + "slot": "7", + "type": "uint256" + }, + { + "bytes": "8", + "label": "operatorFeeConstant", + "offset": 0, + "slot": "8", + "type": "uint64" + }, + { + "bytes": "4", + "label": "operatorFeeScalar", + "offset": 8, + "slot": "8", + "type": "uint32" + } +] \ No newline at end of file diff --git a/packages/contracts-bedrock/snapshots/storageLayout/L2ToL1MessagePasserCGT.json b/packages/contracts-bedrock/snapshots/storageLayout/L2ToL1MessagePasserCGT.json new file mode 100644 index 00000000000..09cc3b54401 --- /dev/null +++ b/packages/contracts-bedrock/snapshots/storageLayout/L2ToL1MessagePasserCGT.json @@ -0,0 +1,16 @@ +[ + { + "bytes": "32", + "label": "sentMessages", + "offset": 0, + "slot": "0", + "type": "mapping(bytes32 => bool)" + }, + { + "bytes": "30", + "label": "msgNonce", + "offset": 0, + "slot": "1", + "type": "uint240" + } +] \ No newline at end of file diff --git a/packages/contracts-bedrock/src/L2/L1Block.sol b/packages/contracts-bedrock/src/L2/L1Block.sol index e9d089b568f..31935dfab7e 100644 --- a/packages/contracts-bedrock/src/L2/L1Block.sol +++ b/packages/contracts-bedrock/src/L2/L1Block.sol @@ -3,11 +3,9 @@ pragma solidity 0.8.15; // Libraries import { Constants } from "src/libraries/Constants.sol"; -import { Predeploys } from "src/libraries/Predeploys.sol"; // Interfaces import { ISemver } from "interfaces/universal/ISemver.sol"; -import { ILiquidityController } from "interfaces/L2/ILiquidityController.sol"; /// @custom:proxied true /// @custom:predeploy 0x4200000000000000000000000000000000000015 @@ -17,11 +15,6 @@ import { ILiquidityController } from "interfaces/L2/ILiquidityController.sol"; /// set by the "depositor" account, a special system address. Depositor account transactions /// are created by the protocol whenever we move to a new epoch. contract L1Block is ISemver { - /// @notice Storage slot for the isCustomGasToken flag - /// @dev bytes32(uint256(keccak256("l1block.isCustomGasToken")) - 1) - bytes32 private constant IS_CUSTOM_GAS_TOKEN_SLOT = - 0xd2ff82c9b477ff6a09f530b1c627ffb4b0b81e2ae2ba427f824162e8dad020aa; - /// @notice Address of the special depositor account. function DEPOSITOR_ACCOUNT() public pure returns (address addr_) { addr_ = Constants.DEPOSITOR_ACCOUNT; @@ -68,33 +61,35 @@ contract L1Block is ISemver { /// @notice The scalar value applied to the operator fee. uint32 public operatorFeeScalar; - /// @custom:semver 1.7.0 + /// @custom:semver 1.6.1 function version() public pure virtual returns (string memory) { - return "1.7.0"; + return "1.6.1"; } - /// @notice Returns whether the gas paying token is custom. - function isCustomGasToken() public view returns (bool isCustom_) { - bytes32 slot = IS_CUSTOM_GAS_TOKEN_SLOT; - assembly { - isCustom_ := sload(slot) - } + /// @notice Returns the gas paying token, its decimals, name and symbol. + function gasPayingToken() public pure returns (address addr_, uint8 decimals_) { + addr_ = Constants.ETHER; + decimals_ = 18; } /// @notice Returns the gas paying token name. /// If nothing is set in state, then it means ether is used. /// This function cannot be removed because WETH depends on it. - function gasPayingTokenName() public view returns (string memory name_) { - name_ = - isCustomGasToken() ? ILiquidityController(Predeploys.LIQUIDITY_CONTROLLER).gasPayingTokenName() : "Ether"; + function gasPayingTokenName() public pure returns (string memory name_) { + name_ = "Ether"; } /// @notice Returns the gas paying token symbol. /// If nothing is set in state, then it means ether is used. /// This function cannot be removed because WETH depends on it. - function gasPayingTokenSymbol() public view returns (string memory symbol_) { - symbol_ = - isCustomGasToken() ? ILiquidityController(Predeploys.LIQUIDITY_CONTROLLER).gasPayingTokenSymbol() : "ETH"; + function gasPayingTokenSymbol() public pure returns (string memory symbol_) { + symbol_ = "ETH"; + } + + /// @notice Getter for custom gas token paying networks. Returns true if the + /// network uses a custom gas token. + function isCustomGasToken() public pure returns (bool is_) { + is_ = false; } /// @custom:legacy @@ -217,18 +212,4 @@ contract L1Block is ISemver { sstore(operatorFeeConstant.slot, shr(160, calldataload(164))) } } - - /// @notice Set chain to use custom gas token (callable by depositor account) - function setCustomGasToken() external { - require( - msg.sender == Constants.DEPOSITOR_ACCOUNT, - "L1Block: only the depositor account can set isCustomGasToken flag" - ); - require(isCustomGasToken() == false, "L1Block: CustomGasToken already active"); - - bytes32 slot = IS_CUSTOM_GAS_TOKEN_SLOT; - assembly { - sstore(slot, 1) - } - } } diff --git a/packages/contracts-bedrock/src/L2/L1BlockCGT.sol b/packages/contracts-bedrock/src/L2/L1BlockCGT.sol new file mode 100644 index 00000000000..64d8741716a --- /dev/null +++ b/packages/contracts-bedrock/src/L2/L1BlockCGT.sol @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +// Libraries +import { Constants } from "src/libraries/Constants.sol"; +import { Predeploys } from "src/libraries/Predeploys.sol"; + +// Interfaces +import { ISemver } from "interfaces/universal/ISemver.sol"; +import { ILiquidityController } from "interfaces/L2/ILiquidityController.sol"; + +/// @custom:proxied true +/// @custom:predeploy 0x4200000000000000000000000000000000000015 +/// @title L1BlockCGT +/// @notice The L1BlockCGT predeploy gives users access to information about the last known L1 block. +/// Values within this contract are updated once per epoch (every L1 block) and can only be +/// set by the "depositor" account, a special system address. Depositor account transactions +/// are created by the protocol whenever we move to a new epoch. +contract L1BlockCGT is ISemver { + /// @notice Storage slot for the isCustomGasToken flag + /// @dev bytes32(uint256(keccak256("l1block.isCustomGasToken")) - 1) + bytes32 private constant IS_CUSTOM_GAS_TOKEN_SLOT = + 0xd2ff82c9b477ff6a09f530b1c627ffb4b0b81e2ae2ba427f824162e8dad020aa; + + /// @notice Address of the special depositor account. + function DEPOSITOR_ACCOUNT() public pure returns (address addr_) { + addr_ = Constants.DEPOSITOR_ACCOUNT; + } + + /// @notice The latest L1 block number known by the L2 system. + uint64 public number; + + /// @notice The latest L1 timestamp known by the L2 system. + uint64 public timestamp; + + /// @notice The latest L1 base fee. + uint256 public basefee; + + /// @notice The latest L1 blockhash. + bytes32 public hash; + + /// @notice The number of L2 blocks in the same epoch. + uint64 public sequenceNumber; + + /// @notice The scalar value applied to the L1 blob base fee portion of the blob-capable L1 cost func. + uint32 public blobBaseFeeScalar; + + /// @notice The scalar value applied to the L1 base fee portion of the blob-capable L1 cost func. + uint32 public baseFeeScalar; + + /// @notice The versioned hash to authenticate the batcher by. + bytes32 public batcherHash; + + /// @notice The overhead value applied to the L1 portion of the transaction fee. + /// @custom:legacy + uint256 public l1FeeOverhead; + + /// @notice The scalar value applied to the L1 portion of the transaction fee. + /// @custom:legacy + uint256 public l1FeeScalar; + + /// @notice The latest L1 blob base fee. + uint256 public blobBaseFee; + + /// @notice The constant value applied to the operator fee. + uint64 public operatorFeeConstant; + + /// @notice The scalar value applied to the operator fee. + uint32 public operatorFeeScalar; + + /// @custom:semver 1.7.0 + function version() public pure virtual returns (string memory) { + return "1.7.0"; + } + + /// @notice Returns whether the gas paying token is custom. + function isCustomGasToken() public view returns (bool isCustom_) { + bytes32 slot = IS_CUSTOM_GAS_TOKEN_SLOT; + assembly { + isCustom_ := sload(slot) + } + } + + /// @notice Returns the gas paying token name. + /// If nothing is set in state, then it means ether is used. + /// This function cannot be removed because WETH depends on it. + function gasPayingTokenName() public view returns (string memory name_) { + name_ = + isCustomGasToken() ? ILiquidityController(Predeploys.LIQUIDITY_CONTROLLER).gasPayingTokenName() : "Ether"; + } + + /// @notice Returns the gas paying token symbol. + /// If nothing is set in state, then it means ether is used. + /// This function cannot be removed because WETH depends on it. + function gasPayingTokenSymbol() public view returns (string memory symbol_) { + symbol_ = + isCustomGasToken() ? ILiquidityController(Predeploys.LIQUIDITY_CONTROLLER).gasPayingTokenSymbol() : "ETH"; + } + + /// @custom:legacy + /// @notice Updates the L1 block values. + /// @param _number L1 blocknumber. + /// @param _timestamp L1 timestamp. + /// @param _basefee L1 basefee. + /// @param _hash L1 blockhash. + /// @param _sequenceNumber Number of L2 blocks since epoch start. + /// @param _batcherHash Versioned hash to authenticate batcher by. + /// @param _l1FeeOverhead L1 fee overhead. + /// @param _l1FeeScalar L1 fee scalar. + function setL1BlockValues( + uint64 _number, + uint64 _timestamp, + uint256 _basefee, + bytes32 _hash, + uint64 _sequenceNumber, + bytes32 _batcherHash, + uint256 _l1FeeOverhead, + uint256 _l1FeeScalar + ) + external + { + require(msg.sender == DEPOSITOR_ACCOUNT(), "L1Block: only the depositor account can set L1 block values"); + + number = _number; + timestamp = _timestamp; + basefee = _basefee; + hash = _hash; + sequenceNumber = _sequenceNumber; + batcherHash = _batcherHash; + l1FeeOverhead = _l1FeeOverhead; + l1FeeScalar = _l1FeeScalar; + } + + /// @notice Updates the L1 block values for an Ecotone upgraded chain. + /// Params are packed and passed in as raw msg.data instead of ABI to reduce calldata size. + /// Params are expected to be in the following order: + /// 1. _baseFeeScalar L1 base fee scalar + /// 2. _blobBaseFeeScalar L1 blob base fee scalar + /// 3. _sequenceNumber Number of L2 blocks since epoch start. + /// 4. _timestamp L1 timestamp. + /// 5. _number L1 blocknumber. + /// 6. _basefee L1 base fee. + /// 7. _blobBaseFee L1 blob base fee. + /// 8. _hash L1 blockhash. + /// 9. _batcherHash Versioned hash to authenticate batcher by. + function setL1BlockValuesEcotone() public { + _setL1BlockValuesEcotone(); + } + + /// @notice Updates the L1 block values for an Ecotone upgraded chain. + /// Params are packed and passed in as raw msg.data instead of ABI to reduce calldata size. + /// Params are expected to be in the following order: + /// 1. _baseFeeScalar L1 base fee scalar + /// 2. _blobBaseFeeScalar L1 blob base fee scalar + /// 3. _sequenceNumber Number of L2 blocks since epoch start. + /// 4. _timestamp L1 timestamp. + /// 5. _number L1 blocknumber. + /// 6. _basefee L1 base fee. + /// 7. _blobBaseFee L1 blob base fee. + /// 8. _hash L1 blockhash. + /// 9. _batcherHash Versioned hash to authenticate batcher by. + function _setL1BlockValuesEcotone() internal { + address depositor = DEPOSITOR_ACCOUNT(); + assembly { + // Revert if the caller is not the depositor account. + if xor(caller(), depositor) { + mstore(0x00, 0x3cc50b45) // 0x3cc50b45 is the 4-byte selector of "NotDepositor()" + revert(0x1C, 0x04) // returns the stored 4-byte selector from above + } + // sequencenum (uint64), blobBaseFeeScalar (uint32), baseFeeScalar (uint32) + sstore(sequenceNumber.slot, shr(128, calldataload(4))) + // number (uint64) and timestamp (uint64) + sstore(number.slot, shr(128, calldataload(20))) + sstore(basefee.slot, calldataload(36)) // uint256 + sstore(blobBaseFee.slot, calldataload(68)) // uint256 + sstore(hash.slot, calldataload(100)) // bytes32 + sstore(batcherHash.slot, calldataload(132)) // bytes32 + } + } + + /// @notice Updates the L1 block values for an Isthmus upgraded chain. + /// Params are packed and passed in as raw msg.data instead of ABI to reduce calldata size. + /// Params are expected to be in the following order: + /// 1. _baseFeeScalar L1 base fee scalar + /// 2. _blobBaseFeeScalar L1 blob base fee scalar + /// 3. _sequenceNumber Number of L2 blocks since epoch start. + /// 4. _timestamp L1 timestamp. + /// 5. _number L1 blocknumber. + /// 6. _basefee L1 base fee. + /// 7. _blobBaseFee L1 blob base fee. + /// 8. _hash L1 blockhash. + /// 9. _batcherHash Versioned hash to authenticate batcher by. + /// 10. _operatorFeeScalar Operator fee scalar. + /// 11. _operatorFeeConstant Operator fee constant. + function setL1BlockValuesIsthmus() public { + _setL1BlockValuesIsthmus(); + } + + /// @notice Updates the L1 block values for an Isthmus upgraded chain. + /// Params are packed and passed in as raw msg.data instead of ABI to reduce calldata size. + /// Params are expected to be in the following order: + /// 1. _baseFeeScalar L1 base fee scalar + /// 2. _blobBaseFeeScalar L1 blob base fee scalar + /// 3. _sequenceNumber Number of L2 blocks since epoch start. + /// 4. _timestamp L1 timestamp. + /// 5. _number L1 blocknumber. + /// 6. _basefee L1 base fee. + /// 7. _blobBaseFee L1 blob base fee. + /// 8. _hash L1 blockhash. + /// 9. _batcherHash Versioned hash to authenticate batcher by. + /// 10. _operatorFeeScalar Operator fee scalar. + /// 11. _operatorFeeConstant Operator fee constant. + function _setL1BlockValuesIsthmus() internal { + _setL1BlockValuesEcotone(); + assembly { + // operatorFeeScalar (uint32), operatorFeeConstant (uint64) + sstore(operatorFeeConstant.slot, shr(160, calldataload(164))) + } + } + + /// @notice Set chain to use custom gas token (callable by depositor account) + function setCustomGasToken() external { + require( + msg.sender == Constants.DEPOSITOR_ACCOUNT, + "L1Block: only the depositor account can set isCustomGasToken flag" + ); + require(isCustomGasToken() == false, "L1Block: CustomGasToken already active"); + + bytes32 slot = IS_CUSTOM_GAS_TOKEN_SLOT; + assembly { + sstore(slot, 1) + } + } +} diff --git a/packages/contracts-bedrock/src/L2/L2ToL1MessagePasser.sol b/packages/contracts-bedrock/src/L2/L2ToL1MessagePasser.sol index 5e70d4ef39e..b25a2a1248b 100644 --- a/packages/contracts-bedrock/src/L2/L2ToL1MessagePasser.sol +++ b/packages/contracts-bedrock/src/L2/L2ToL1MessagePasser.sol @@ -6,11 +6,9 @@ import { Types } from "src/libraries/Types.sol"; import { Hashing } from "src/libraries/Hashing.sol"; import { Encoding } from "src/libraries/Encoding.sol"; import { Burn } from "src/libraries/Burn.sol"; -import { Predeploys } from "src/libraries/Predeploys.sol"; // Interfaces import { ISemver } from "interfaces/universal/ISemver.sol"; -import { IL1Block } from "interfaces/L2/IL1Block.sol"; /// @custom:proxied true /// @custom:predeploy 0x4200000000000000000000000000000000000016 @@ -31,9 +29,6 @@ contract L2ToL1MessagePasser is ISemver { /// @notice A unique value hashed with each withdrawal. uint240 internal msgNonce; - /// @notice The error thrown when a withdrawal is initiated with value and custom gas token is used. - error L2ToL1MessagePasser_NotAllowedOnCGTMode(); - /// @notice Emitted any time a withdrawal is initiated. /// @param nonce Unique value corresponding to each withdrawal. /// @param sender The L2 account address which initiated the withdrawal. @@ -56,8 +51,8 @@ contract L2ToL1MessagePasser is ISemver { /// @param amount Amount of ETh that was burned. event WithdrawerBalanceBurnt(uint256 indexed amount); - /// @custom:semver 1.2.0 - string public constant version = "1.2.0"; + /// @custom:semver 1.1.2 + string public constant version = "1.1.2"; /// @notice Allows users to withdraw ETH by sending directly to this contract. receive() external payable { @@ -79,10 +74,6 @@ contract L2ToL1MessagePasser is ISemver { /// @param _gasLimit Minimum gas limit for executing the message on L1. /// @param _data Data to forward to L1 target. function initiateWithdrawal(address _target, uint256 _gasLimit, bytes memory _data) public payable { - if (IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).isCustomGasToken() && msg.value > 0) { - revert L2ToL1MessagePasser_NotAllowedOnCGTMode(); - } - bytes32 withdrawalHash = Hashing.hashWithdrawal( Types.WithdrawalTransaction({ nonce: messageNonce(), diff --git a/packages/contracts-bedrock/src/L2/L2ToL1MessagePasserCGT.sol b/packages/contracts-bedrock/src/L2/L2ToL1MessagePasserCGT.sol new file mode 100644 index 00000000000..df35555bdb5 --- /dev/null +++ b/packages/contracts-bedrock/src/L2/L2ToL1MessagePasserCGT.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +// Libraries +import { Types } from "src/libraries/Types.sol"; +import { Hashing } from "src/libraries/Hashing.sol"; +import { Encoding } from "src/libraries/Encoding.sol"; +import { Burn } from "src/libraries/Burn.sol"; +import { Predeploys } from "src/libraries/Predeploys.sol"; + +// Interfaces +import { ISemver } from "interfaces/universal/ISemver.sol"; +import { IL1Block } from "interfaces/L2/IL1Block.sol"; + +/// @custom:proxied true +/// @custom:predeploy 0x4200000000000000000000000000000000000016 +/// @title L2ToL1MessagePasserCGT +/// @notice The L2ToL1MessagePasserCGT is a dedicated contract where messages that are being sent from +/// L2 to L1 can be stored. The storage root of this contract is pulled up to the top level +/// of the L2 output to reduce the cost of proving the existence of sent messages. +contract L2ToL1MessagePasserCGT is ISemver { + /// @notice The L1 gas limit set when eth is withdrawn using the receive() function. + uint256 internal constant RECEIVE_DEFAULT_GAS_LIMIT = 100_000; + + /// @notice The current message version identifier. + uint16 public constant MESSAGE_VERSION = 1; + + /// @notice Includes the message hashes for all withdrawals + mapping(bytes32 => bool) public sentMessages; + + /// @notice A unique value hashed with each withdrawal. + uint240 internal msgNonce; + + /// @notice The error thrown when a withdrawal is initiated with value and custom gas token is used. + error L2ToL1MessagePasserCGT_NotAllowedOnCGTMode(); + + /// @notice Emitted any time a withdrawal is initiated. + /// @param nonce Unique value corresponding to each withdrawal. + /// @param sender The L2 account address which initiated the withdrawal. + /// @param target The L1 account address the call will be send to. + /// @param value The ETH value submitted for withdrawal, to be forwarded to the target. + /// @param gasLimit The minimum amount of gas that must be provided when withdrawing. + /// @param data The data to be forwarded to the target on L1. + /// @param withdrawalHash The hash of the withdrawal. + event MessagePassed( + uint256 indexed nonce, + address indexed sender, + address indexed target, + uint256 value, + uint256 gasLimit, + bytes data, + bytes32 withdrawalHash + ); + + /// @notice Emitted when the balance of this contract is burned. + /// @param amount Amount of ETh that was burned. + event WithdrawerBalanceBurnt(uint256 indexed amount); + + /// @custom:semver 1.2.0 + string public constant version = "1.2.0"; + + /// @notice Allows users to withdraw ETH by sending directly to this contract. + receive() external payable { + initiateWithdrawal(msg.sender, RECEIVE_DEFAULT_GAS_LIMIT, bytes("")); + } + + /// @notice Removes all ETH held by this contract from the state. Used to prevent the amount of + /// ETH on L2 inflating when ETH is withdrawn. Currently only way to do this is to + /// create a contract and self-destruct it to itself. Anyone can call this function. Not + /// incentivized since this function is very cheap. + function burn() external { + uint256 balance = address(this).balance; + Burn.eth(balance); + emit WithdrawerBalanceBurnt(balance); + } + + /// @notice Sends a message from L2 to L1. + /// @param _target Address to call on L1 execution. + /// @param _gasLimit Minimum gas limit for executing the message on L1. + /// @param _data Data to forward to L1 target. + function initiateWithdrawal(address _target, uint256 _gasLimit, bytes memory _data) public payable { + if (IL1Block(Predeploys.L1_BLOCK_ATTRIBUTES).isCustomGasToken() && msg.value > 0) { + revert L2ToL1MessagePasserCGT_NotAllowedOnCGTMode(); + } + + bytes32 withdrawalHash = Hashing.hashWithdrawal( + Types.WithdrawalTransaction({ + nonce: messageNonce(), + sender: msg.sender, + target: _target, + value: msg.value, + gasLimit: _gasLimit, + data: _data + }) + ); + + sentMessages[withdrawalHash] = true; + + emit MessagePassed(messageNonce(), msg.sender, _target, msg.value, _gasLimit, _data, withdrawalHash); + + unchecked { + ++msgNonce; + } + } + + /// @notice Retrieves the next message nonce. Message version will be added to the upper two + /// bytes of the message nonce. Message version allows us to treat messages as having + /// different structures. + /// @return Nonce of the next message to be sent, with added message version. + function messageNonce() public view returns (uint256) { + return Encoding.encodeVersionedNonce(msgNonce, MESSAGE_VERSION); + } +} diff --git a/packages/contracts-bedrock/test/L2/L1BlockCGT.t.sol b/packages/contracts-bedrock/test/L2/L1BlockCGT.t.sol index ce22ca23d40..7cb11a04c54 100644 --- a/packages/contracts-bedrock/test/L2/L1BlockCGT.t.sol +++ b/packages/contracts-bedrock/test/L2/L1BlockCGT.t.sol @@ -8,58 +8,64 @@ import { L1Block_SetL1BlockValuesEcotone_Test, L1Block_SetL1BlockValuesIsthmus_Test } from "test/L2/L1Block.t.sol"; +import { stdStorage, StdStorage } from "forge-std/Test.sol"; // Libraries import "src/libraries/L1BlockErrors.sol"; +// Interfaces +import { IL1BlockCGT } from "interfaces/L2/IL1BlockCGT.sol"; + /// @title L1BlockCGT_TestInit /// @notice Reusable test initialization for `L1Block` tests with custom gas token enabled. contract L1BlockCGT_TestInit is CommonTest { address depositor; + IL1BlockCGT l1BlockCGT; /// @notice Sets up the test suite. function setUp() public virtual override { super.enableCustomGasToken(); super.setUp(); - depositor = l1Block.DEPOSITOR_ACCOUNT(); + l1BlockCGT = IL1BlockCGT(address(l1Block)); + depositor = l1BlockCGT.DEPOSITOR_ACCOUNT(); } } -/// @title L1Block_CGT_GasPayingTokenName_Test +/// @title L1BlockCGT_GasPayingTokenName_Test /// @notice Tests the `gasPayingTokenName` function of the `L1Block` contract with custom gas /// token enabled. -contract L1Block_CGT_GasPayingTokenName_Test is L1BlockCGT_TestInit { +contract L1BlockCGT_GasPayingTokenName_Test is L1BlockCGT_TestInit { /// @notice Tests that the `gasPayingTokenName` function returns the correct token name. function test_gasPayingTokenName_succeeds() external view { - assertEq(liquidityController.gasPayingTokenName(), l1Block.gasPayingTokenName()); + assertEq(liquidityController.gasPayingTokenName(), l1BlockCGT.gasPayingTokenName()); } } -/// @title L1Block_CGT_GasPayingTokenSymbol_Test +/// @title L1BlockCGT_GasPayingTokenSymbol_Test /// @notice Tests the `gasPayingTokenSymbol` function of the `L1Block` contract with custom gas /// token enabled. -contract L1Block_CGT_GasPayingTokenSymbol_Test is L1BlockCGT_TestInit { +contract L1BlockCGT_GasPayingTokenSymbol_Test is L1BlockCGT_TestInit { /// @notice Tests that the `gasPayingTokenSymbol` function returns the correct token symbol. function test_gasPayingTokenSymbol_succeeds() external view { - assertEq(liquidityController.gasPayingTokenSymbol(), l1Block.gasPayingTokenSymbol()); + assertEq(liquidityController.gasPayingTokenSymbol(), l1BlockCGT.gasPayingTokenSymbol()); } } -/// @title L1Block_CGT_IsCustomGasToken_Test +/// @title L1BlockCGT_IsCustomGasToken_Test /// @notice Tests the `isCustomGasToken` function of the `L1Block` contract with custom gas token /// enabled. -contract L1Block_CGT_IsCustomGasToken_Test is L1BlockCGT_TestInit { +contract L1BlockCGT_IsCustomGasToken_Test is L1BlockCGT_TestInit { /// @notice Tests that the `isCustomGasToken` function returns false when no custom gas token /// is used. function test_isCustomGasToken_succeeds() external view { - assertTrue(l1Block.isCustomGasToken()); + assertTrue(l1BlockCGT.isCustomGasToken()); } } -/// @title L1Block_CGT_SetL1BlockValues_Test +/// @title L1BlockCGT_SetL1BlockValues_Test /// @notice Tests the `setL1BlockValues` function of the `L1Block` contract with custom gas token /// enabled. -contract L1Block_CGT_SetL1BlockValues_Test is L1Block_SetL1BlockValues_Test { +contract L1BlockCGT_SetL1BlockValues_Test is L1Block_SetL1BlockValues_Test { // Override setUp to enable custom gas token // Re-use the test from L1Block.t.sol function setUp() public override { @@ -68,10 +74,10 @@ contract L1Block_CGT_SetL1BlockValues_Test is L1Block_SetL1BlockValues_Test { } } -/// @title L1Block_CGT_SetL1BlockValuesEcotone_Test +/// @title L1BlockCGT_SetL1BlockValuesEcotone_Test /// @notice Tests the `setL1BlockValuesEcotone` function of the `L1Block` contract with custom gas /// token enabled. -contract L1Block_CGT_SetL1BlockValuesEcotone_Test is L1Block_SetL1BlockValuesEcotone_Test { +contract L1BlockCGT_SetL1BlockValuesEcotone_Test is L1Block_SetL1BlockValuesEcotone_Test { // Override setUp to enable custom gas token // Re-use the test from L1Block.t.sol function setUp() public override { @@ -80,59 +86,51 @@ contract L1Block_CGT_SetL1BlockValuesEcotone_Test is L1Block_SetL1BlockValuesEco } } -/// @title L1Block_CGTSetL1BlockValuesIsthmus_Test +/// @title L1BlockCGTSetL1BlockValuesIsthmus_Test /// @notice Tests the `setL1BlockValuesIsthmus` function of the `L1Block` contract with custom gas /// token enabled. -contract L1Block_CGT_SetL1BlockValuesIsthmus_Test is L1Block_SetL1BlockValuesIsthmus_Test { +contract L1BlockCGT_SetL1BlockValuesIsthmus_Test is L1Block_SetL1BlockValuesIsthmus_Test { // Override setUp to enable custom gas token - // Re-use the test from L1Block.t.sols + // Re-use the test from L1Block.t.sol function setUp() public override { super.enableCustomGasToken(); super.setUp(); } } -/// @title L1Block_CGT_SetCustomGasToken_Test +/// @title L1BlockCGT_SetCustomGasToken_Test /// @notice Tests the `setCustomGasToken` function of the `L1Block` contract. -contract L1Block_CGT_SetCustomGasToken_Test is L1BlockCGT_TestInit { +contract L1BlockCGT_SetCustomGasToken_Test is L1BlockCGT_TestInit { + using stdStorage for StdStorage; + /// @notice Tests that `setCustomGasToken` reverts if called twice. function test_setCustomGasToken_alreadyActive_reverts() external { // This test uses the setUp that already activates custom gas token - assertTrue(l1Block.isCustomGasToken()); + assertTrue(l1BlockCGT.isCustomGasToken()); vm.expectRevert("L1Block: CustomGasToken already active"); vm.prank(depositor); - l1Block.setCustomGasToken(); - } -} - -/// @title L1Block_SetCustomGasToken_Test -/// @notice Tests the `setCustomGasToken` function of the `L1Block` contract without CGT enabled. -contract L1Block_SetCustomGasToken_Test is CommonTest { - address depositor; - - /// @notice Sets up the test suite. - function setUp() public virtual override { - // Don't enable custom gas token - test the activation process - super.setUp(); - depositor = l1Block.DEPOSITOR_ACCOUNT(); + IL1BlockCGT(address(l1BlockCGT)).setCustomGasToken(); } /// @notice Tests that `setCustomGasToken` updates the flag correctly when called by depositor. function test_setCustomGasToken_succeeds() external { - assertFalse(l1Block.isCustomGasToken()); + stdstore.target(address(l1BlockCGT)).sig("isCustomGasToken()").checked_write(false); + // This test uses the setUp that already activates custom gas token + assertFalse(l1BlockCGT.isCustomGasToken()); vm.prank(depositor); - l1Block.setCustomGasToken(); + l1BlockCGT.setCustomGasToken(); - assertTrue(l1Block.isCustomGasToken()); + assertTrue(l1BlockCGT.isCustomGasToken()); } /// @notice Tests that `setCustomGasToken` reverts if sender address is not the depositor. function test_setCustomGasToken_notDepositor_reverts(address nonDepositor) external { + stdstore.target(address(l1BlockCGT)).sig("isCustomGasToken()").checked_write(false); vm.assume(nonDepositor != depositor); vm.expectRevert("L1Block: only the depositor account can set isCustomGasToken flag"); vm.prank(nonDepositor); - l1Block.setCustomGasToken(); + l1BlockCGT.setCustomGasToken(); } } diff --git a/packages/contracts-bedrock/test/L2/L2ToL1MessagePasserCGT.t.sol b/packages/contracts-bedrock/test/L2/L2ToL1MessagePasserCGT.t.sol index 52ed7d81807..17ff93b7779 100644 --- a/packages/contracts-bedrock/test/L2/L2ToL1MessagePasserCGT.t.sol +++ b/packages/contracts-bedrock/test/L2/L2ToL1MessagePasserCGT.t.sol @@ -9,7 +9,7 @@ import { Types } from "src/libraries/Types.sol"; import { Hashing } from "src/libraries/Hashing.sol"; // Interfaces -import { IL2ToL1MessagePasser } from "interfaces/L2/IL2ToL1MessagePasser.sol"; +import { IL2ToL1MessagePasserCGT } from "interfaces/L2/IL2ToL1MessagePasserCGT.sol"; /// @title L2ToL1MessagePasserCGT_TestInit /// @notice Tests the `L2ToL1MessagePasser` contract with a custom gas token enabled. @@ -70,7 +70,7 @@ contract L2ToL1MessagePasserCGT_InitiateWithdrawal_Test is L2ToL1MessagePasserCG // Expect revert with NotAllowedOnCGTMode vm.prank(_randomAddress); - vm.expectRevert(IL2ToL1MessagePasser.L2ToL1MessagePasser_NotAllowedOnCGTMode.selector); + vm.expectRevert(IL2ToL1MessagePasserCGT.L2ToL1MessagePasserCGT_NotAllowedOnCGTMode.selector); l2ToL1MessagePasser.initiateWithdrawal{ value: _value }({ _target: address(0), _gasLimit: 1, _data: "" }); } }