diff --git a/.eslintrc b/.eslintrc index e287b9a7fdc6..149807292224 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,9 +3,10 @@ "rules": { "no-multiple-empty-lines": ["error", { "max": 1 }], "@typescript-eslint/no-namespace": "off", + "@typescript-eslint/ban-ts-comment": "off", "import/no-named-as-default-member": "off", "import/namespace": "off", "import/no-unresolved": "off", "import/order": "off" } -} \ No newline at end of file +} diff --git a/SystemConfig.json b/SystemConfig.json index c88a23040149..827e11b5bd09 100644 --- a/SystemConfig.json +++ b/SystemConfig.json @@ -9,7 +9,7 @@ "L1_TX_INTRINSIC_L2_GAS": 167157, "L1_TX_INTRINSIC_PUBDATA": 88, "MAX_GAS_PER_TRANSACTION": 80000000, - "BOOTLOADER_MEMORY_FOR_TXS": 273132, + "BOOTLOADER_MEMORY_FOR_TXS": 8740224, "REFUND_GAS": 7343, "KECCAK_ROUND_COST_GAS": 40, "SHA256_ROUND_COST_GAS": 7, diff --git a/SystemContractsHashes.json b/SystemContractsHashes.json index efce4f4cce74..e123d0e6cbe1 100644 --- a/SystemContractsHashes.json +++ b/SystemContractsHashes.json @@ -3,99 +3,99 @@ "contractName": "AccountCodeStorage", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/AccountCodeStorage.sol/AccountCodeStorage.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/AccountCodeStorage.sol", - "bytecodeHash": "0x0100009b3cd9a137912ffbd406a1d73eaffbcf40a760f3956fea7e051f0c6101", - "sourceCodeHash": "0xf56f18d6ccec4a1e083ece9d5dea511b610905b3be42bf81e81e53f8a7028162" + "bytecodeHash": "0x0100009bc0511159b5ec703d0c56f87615964017739def4ab1ee606b8ec6458c", + "sourceCodeHash": "0xb7a285eceef853b5259266de51584c7120fdc0335657b457c63a331301c96d8f" }, { "contractName": "BootloaderUtilities", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/BootloaderUtilities.sol/BootloaderUtilities.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/BootloaderUtilities.sol", - "bytecodeHash": "0x01000975e811c2ba4a3b28f70426598129f0029feb086714980f9513f59531c7", - "sourceCodeHash": "0xcb8d18786a9dca90524de992e3216f57d89192600c2aa758f071a6a6ae3162c4" + "bytecodeHash": "0x010009759cab4fa9e6ca0784746e1df600ff523f0f90c1e94191755cab4b2ed0", + "sourceCodeHash": "0xf40ae3c82f6eb7b88e4d926c706c3edc3c2ce07bb60f60cd21accd228f38c212" }, { "contractName": "ComplexUpgrader", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/ComplexUpgrader.sol/ComplexUpgrader.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/ComplexUpgrader.sol", - "bytecodeHash": "0x0100005b2eef785c804dc40ec24b3c2339b11a314fec6eb91db551a2523d6a2b", - "sourceCodeHash": "0x02b3234b8aa3dde88cf2cf6c1447512dd953ed355be9ba21c22d48ca6d3eee67" + "bytecodeHash": "0x0100005bfc0443349233459892b51e9f67e27ac828d44d9c7cba8c8285fd66bc", + "sourceCodeHash": "0xbf583b121fde4d406912afa7af7943adb440e355fcbf476f5b454c58fd07eda0" }, { "contractName": "Compressor", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/Compressor.sol/Compressor.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/Compressor.sol", - "bytecodeHash": "0x010001b7a7bb988e52b8fca05d82bccf63ea34c6617ebea1765c91e911386756", - "sourceCodeHash": "0x214a2b123ecdf3b135709d0b6207b3d41d9e8c68a0aa74b88c64fc983382d7b0" + "bytecodeHash": "0x010001b72874590239af612f65d50a35975299f88de022493fe7f0a190e79496", + "sourceCodeHash": "0xba41d1e46cd62c08f61ac78b693e5adbb5428f33640e0e55ff58cbd04093cd07" }, { "contractName": "ContractDeployer", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/ContractDeployer.sol/ContractDeployer.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/ContractDeployer.sol", - "bytecodeHash": "0x010005bb3e1bb343565920b37c6c0d716dcfca45bbdada20a305e80ab60a6916", - "sourceCodeHash": "0xed9088758b3cbc9c450da0ac18e0e11359efe7341219ac1c331a4f5712c2dacb" + "bytecodeHash": "0x010006091341955c8f76409de00549fb00b275166b5a0d0d7b82cbd629bb4212", + "sourceCodeHash": "0x660e9a188006f9e6086214f8aefa7bc9dc434ce6ff220bfec98327c42953dda4" }, { "contractName": "DefaultAccount", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/DefaultAccount.sol/DefaultAccount.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/DefaultAccount.sol", - "bytecodeHash": "0x0100065d0ea6130f484f6cd4936f2d5114abc9961328d6acd8b311dd00b94546", - "sourceCodeHash": "0x34aaf3d8fbe90cf35efcfa5d8361de8a97be0a7cb60b9b117cda0dfd78fab6a6" + "bytecodeHash": "0x01000651c5ae96f2aab07d720439e42491bb44c6384015e3a08e32620a4d582d", + "sourceCodeHash": "0x7356cb68b6326a6ee4871525bfb26aedf9a30c1da18461c68d10d90e1653b05c" }, { "contractName": "EmptyContract", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/EmptyContract.sol/EmptyContract.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/EmptyContract.sol", - "bytecodeHash": "0x01000007c08e60bc60d70f759bc49f2488b70054b0cec1a64f0cf27953448f4c", - "sourceCodeHash": "0x34cf9324829a0a1653486242a5dbee58aa93a8b9888415791bafe2c7a966400d" + "bytecodeHash": "0x01000007271e9710c356751295d83a25ffec94be2b4ada01ec1fa04c7cd6f2c7", + "sourceCodeHash": "0x8bb626635c3cab6c5fc3b83e2ce09f98a8193ecdf019653bbe55d6cae3138b5d" }, { "contractName": "ImmutableSimulator", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/ImmutableSimulator.sol/ImmutableSimulator.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/ImmutableSimulator.sol", - "bytecodeHash": "0x01000047b7e40b0e0f7bd7051e20853a49b972c6c0ac16872425067cb3288f08", - "sourceCodeHash": "0x315e71df564977165decbbbda504fee9d3dd98b6ca1e5dc68572d74bc308b03f" + "bytecodeHash": "0x01000047a3c40e3f4eb98f14967f141452ae602d8723a10975dc33960911d8c5", + "sourceCodeHash": "0x8d1f252875fe4a8a1cd51bf7bd678b9bff7542bb468f75929cea69df4a16850d" }, { "contractName": "KnownCodesStorage", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/KnownCodesStorage.sol/KnownCodesStorage.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/KnownCodesStorage.sol", - "bytecodeHash": "0x0100008b806f904a40cadb94318db1d8a8ae9a579f46ee0b50432e4c221572ee", - "sourceCodeHash": "0x33c7e9af04650d7e802ecfcf099fefde1ddb1a4268f521c0d69dea014ce5853d" + "bytecodeHash": "0x0100008b0ca6c6f277035366e99407fbb4b01e743e80b7d24dea5a3d647b423e", + "sourceCodeHash": "0x15cb53060dad4c62e72c62777ff6a25029c6ec0ab37adacb684d0e275cec6749" }, { "contractName": "L1Messenger", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/L1Messenger.sol/L1Messenger.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/L1Messenger.sol", - "bytecodeHash": "0x010002fb863dc09dbfdae276418c307eb39af03f335a0b23a2edc8bcd1835fce", - "sourceCodeHash": "0x1c355d04ecf4e4c39ab6481f2bb17e5e30d3aa4563342aaa4c9aa122ac3a14d3" + "bytecodeHash": "0x01000301c943edb65f5a0b8cdd806218b8ecf25c022720fe3afe6951f202f3fa", + "sourceCodeHash": "0x11a4280dcacc9de950ee8724bc6e4f99a4268c38a0cb26ebd5f28e6ea1094463" }, { "contractName": "L2EthToken", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/L2EthToken.sol/L2EthToken.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/L2EthToken.sol", - "bytecodeHash": "0x01000139b0930df0818b0f10f7c78feed9ca93020efcb72e749a7ea842d08576", - "sourceCodeHash": "0xb8e404a5e82c50b9f0cfb6412049d1174df3fbe8af40750a756ad0c1cfefb593" + "bytecodeHash": "0x01000139b506af2b02225838c5a33e30ace701b44b210a422eedab7dd31c28a3", + "sourceCodeHash": "0xadc69be5b5799d0f1a6fa71d56a6706b146447c8e3c6516a5191a0b23bd134e8" }, { "contractName": "MsgValueSimulator", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/MsgValueSimulator.sol/MsgValueSimulator.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/MsgValueSimulator.sol", - "bytecodeHash": "0x0100006f5dab2685a586d5ebbd360a2c1c2d593df1ab8267d8e172d92a202bfa", - "sourceCodeHash": "0x038cc8e7fe97ad4befa2d5ab4ae77fdefdecc20338142565b8086cd9342868ef" + "bytecodeHash": "0x0100006fa1591d93fcc4a25e9340ad11d0e825904cd1842b8f7255701e1aacbb", + "sourceCodeHash": "0xe7a85dc51512cab431d12bf062847c4dcf2f1c867e7d547ff95638f6a4e8fd4e" }, { "contractName": "NonceHolder", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/NonceHolder.sol/NonceHolder.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/NonceHolder.sol", - "bytecodeHash": "0x0100012f7252eee16af884775bd3279b577bbed64f124349ac6179aeb6ae3cb8", - "sourceCodeHash": "0xdfdd234e9d7f6cc7dfb0b9c8b6a2dea3dc40204539bfb836c9ae2bb1dc9cbb1f" + "bytecodeHash": "0x0100012fa73fa922dd9fabb40d3275ce80396eff6ccf1b452c928c17d98bd470", + "sourceCodeHash": "0x1680f801086c654032f2331a574752e9c3b21df8a60110f4ea5fe26bb51e8095" }, { "contractName": "SystemContext", "bytecodePath": "artifacts-zk/cache-zk/solpp-generated-contracts/SystemContext.sol/SystemContext.json", "sourceCodePath": "cache-zk/solpp-generated-contracts/SystemContext.sol", - "bytecodeHash": "0x0100023f1761d12df53e8581fabcb359cb069bbd2a7a7a3ef0b49f2f5d46169a", - "sourceCodeHash": "0x60d9007efb7f1bf9417f0856f3799937357a64c2e5f858d13d3ee584e8b9832e" + "bytecodeHash": "0x0100023ba65021e4689dd1755f82108214a1f25150d439fe58c55cdb1f376436", + "sourceCodeHash": "0x43d1d893695361edf014acd62f66dfe030868f342fe5d0aa1b6ddb520f3a5ad4" }, { "contractName": "EventWriter", @@ -108,15 +108,15 @@ "contractName": "EcAdd", "bytecodePath": "contracts/precompiles/artifacts/EcAdd.yul/EcAdd.yul.zbin", "sourceCodePath": "contracts/precompiles/EcAdd.yul", - "bytecodeHash": "0x010000c56c054a0de4a36b133d3c114ec514c3ce0334ad7759c202392386a913", - "sourceCodeHash": "0xe73c8960a8b4060113adca9f03207d379580d172df9f0b499dd5353934a557a6" + "bytecodeHash": "0x010000c5a85a372f441ac693210a18e683b530bed875fdcab2f7e101b057d433", + "sourceCodeHash": "0x32645126b8765e4f7ced63c9508c70edc4ab734843d5f0f0f01d153c27206cee" }, { "contractName": "EcMul", "bytecodePath": "contracts/precompiles/artifacts/EcMul.yul/EcMul.yul.zbin", "sourceCodePath": "contracts/precompiles/EcMul.yul", - "bytecodeHash": "0x010001378d31273c8e58caa12bcf1a5694e66a0aefdba2504adb8e3eb02b21c7", - "sourceCodeHash": "0x6c4b11542bcf85e6e02ca193fc0548353b1f21c27e972b9e73781e8f7eaf50b0" + "bytecodeHash": "0x0100013759b40792c2c3d033990e992e5508263c15252eb2d9bfbba571350675", + "sourceCodeHash": "0xdad8be6e926155a362ea05b132ba8b6c634e978a41f79bb6390b870e18049e45" }, { "contractName": "Ecrecover", @@ -143,35 +143,35 @@ "contractName": "bootloader_test", "bytecodePath": "bootloader/build/artifacts/bootloader_test.yul/bootloader_test.yul.zbin", "sourceCodePath": "bootloader/build/bootloader_test.yul", - "bytecodeHash": "0x0100037b0462ed355364eaabccbea2a018afad4c8841b9856514c027400f1b10", - "sourceCodeHash": "0x467a36057882d6740a016cda812798d1be9a0ea60cb7ef90996e2c5be55e75a4" + "bytecodeHash": "0x01000385425e3ddcaa5a6780f2463c8aa71b844d914b61471f468173d7eaff0d", + "sourceCodeHash": "0xda28bc1ac0cd1e0a34ea99bb70cde15fd0edbacffe7491186620f46fc821c201" }, { "contractName": "fee_estimate", "bytecodePath": "bootloader/build/artifacts/fee_estimate.yul/fee_estimate.yul.zbin", "sourceCodePath": "bootloader/build/fee_estimate.yul", - "bytecodeHash": "0x010009434283c0bc9f32e51a9aa84523ee7a381e3e0c5ae63f639998d915f54b", - "sourceCodeHash": "0x3fb415ac6f59c35ea17b85aabb551df1b44a6fc7e051c2e33f5fc76c17432167" + "bytecodeHash": "0x0100096bebcd3abfed25138ff97587a5783c0294c25627aa4166bd1c91913a2d", + "sourceCodeHash": "0x6732aa11175c77394065e586f123d10a844335bc57a58ef47291de32583de225" }, { "contractName": "gas_test", "bytecodePath": "bootloader/build/artifacts/gas_test.yul/gas_test.yul.zbin", "sourceCodePath": "bootloader/build/gas_test.yul", - "bytecodeHash": "0x01000927ea81a1afe5a586853a9c43fb928bcf1f1fba51a19c48ce1b940867c7", - "sourceCodeHash": "0x84648c958714d952248b8553456b5a5e3860e00871f01644297531e991a67d64" + "bytecodeHash": "0x0100094b78d8a52b54f82e4f1007a1c0c9ae7e2d54e73321549d7a70bb320bbf", + "sourceCodeHash": "0x68f07a46c3179705047c41b63b03e157fa48b0f06427801bedc8d45e335ea7c3" }, { "contractName": "playground_batch", "bytecodePath": "bootloader/build/artifacts/playground_batch.yul/playground_batch.yul.zbin", "sourceCodePath": "bootloader/build/playground_batch.yul", - "bytecodeHash": "0x0100094d801bf4180d020692a95cf26a3c9adcaedfd5be47ec08b1637b0282da", - "sourceCodeHash": "0xe02bed16015da2f03dcf5a7ed1bf2132009e69f4bfb5335e13cc406327e84d5e" + "bytecodeHash": "0x0100097500c0f3cc64c09339b8215f35ebdf155f2c7188b4b9426cd8d58b80cc", + "sourceCodeHash": "0x5a121577cd4335105a6b9864196ecb5796890299fac95e7003d9f23bd210e907" }, { "contractName": "proved_batch", "bytecodePath": "bootloader/build/artifacts/proved_batch.yul/proved_batch.yul.zbin", "sourceCodePath": "bootloader/build/proved_batch.yul", - "bytecodeHash": "0x010009411d9c2342671c57d5ce038ce3e142c750df85ac5d23f67b4e4215fede", - "sourceCodeHash": "0xd48e5abbfbb493eacfcbe6dc788eada867d58ab8596d55736b496b1c2e22c636" + "bytecodeHash": "0x010009657432df24acfe7950b2d1a0707520ca6b7acb699e58c0f378c0ed7a11", + "sourceCodeHash": "0x2469138639d133005f6d3b7fad3d7404db5b4088b2649e9f5167d2a22df3b1de" } ] diff --git a/bootloader/bootloader.yul b/bootloader/bootloader.yul index 98efc7a63a3f..89a2c0500d4d 100644 --- a/bootloader/bootloader.yul +++ b/bootloader/bootloader.yul @@ -917,11 +917,9 @@ object "Bootloader" { // In case the operator provided smaller refund than the one calculated // by the bootloader, we return the refund calculated by the bootloader. - refundGas := max(getOperatorRefundForTx(transactionIndex), potentialRefund) + refundGas := max(getOperatorRefundForTx(transactionIndex), safeAdd(potentialRefund, reservedGas, "iop")) } - refundGas := add(refundGas, reservedGas) - if gt(refundGas, gasLimit) { assertionError("L1: refundGas > gasLimit") } @@ -939,10 +937,14 @@ object "Bootloader" { let toRefundRecipient switch success case 0 { + if iszero(isPriorityOp) { + // Upgrade transactions must always succeed + assertionError("Upgrade tx failed") + } + // If the transaction reverts, then minting the msg.value to the user has been reverted // as well, so we can simply mint everything that the user has deposited to // the refund recipient - toRefundRecipient := safeSub(getReserved0(innerTxDataOffset), payToOperator, "vji") } default { @@ -1178,7 +1180,7 @@ object "Bootloader" { /// @param txDataOffset The offset to the ABI-encoded Transaction struct. /// @param gasLimitForTx The L2 gas limit for the transaction validation & execution. /// @param gasPrice The L2 gas price that should be used by the transaction. - /// @return ergsLeft The ergs left after the validation step. + /// @return gasLeft The gas left after the validation step. function l2TxValidation( txDataOffset, gasLimitForTx, @@ -1230,9 +1232,9 @@ object "Bootloader" { /// @dev The function responsible for the execution step of the L2 transaction. /// @param txDataOffset The offset to the ABI-encoded Transaction struct. - /// @param ergsLeft The ergs left after the validation step. + /// @param gasLeft The gas left after the validation step. /// @return success Whether or not the execution step was successful. - /// @return ergsSpentOnExecute The ergs spent on the transaction execution. + /// @return gasSpentOnExecute The gas spent on the transaction execution. function l2TxExecution( txDataOffset, gasLeft, @@ -1262,7 +1264,7 @@ object "Bootloader" { default { // Note, that since gt(gasLeft, gasSpentOnFactoryDeps) = true // sub(gasLeft, gasSpentOnFactoryDeps) > 0, which is important - // because a nearCall with 0 ergs passes on all the ergs of the parent frame. + // because a nearCall with 0 gas passes on all the gas of the parent frame. gasLeft := sub(gasLeft, gasSpentOnFactoryDeps) let executeABI := getNearCallABI(gasLeft) @@ -1425,6 +1427,7 @@ object "Bootloader" { refundRecipient := paymaster if gt(gasLeft, 0) { + checkEnoughGas(gasLeft) let nearCallAbi := getNearCallABI(gasLeft) let gasBeforePostOp := gas() pop(ZKSYNC_NEAR_CALL_callPostOp( @@ -1435,7 +1438,7 @@ object "Bootloader" { success, // Since the paymaster will be refunded with reservedGas, // it should know about it - safeAdd(gasLeft, reservedGas, "jkl"), + safeAdd(gasLeft, reservedGas, "jkl") )) let gasSpentByPostOp := sub(gasBeforePostOp, gas()) @@ -1595,7 +1598,7 @@ object "Bootloader" { /// @dev Get checked for overcharged operator's overhead for the transaction. /// @param transactionIndex The index of the transaction in the batch /// @param txTotalGasLimit The total gass limit of the transaction (including the overhead). - /// @param gasPerPubdataByte The price for pubdata byte in ergs. + /// @param gasPerPubdataByte The price for pubdata byte in gas. /// @param txEncodeLen The length of the ABI-encoding of the transaction function getVerifiedOperatorOverheadForTx( transactionIndex, @@ -1755,6 +1758,37 @@ object "Bootloader" { } + /// @dev Given the callee and the data to be called with, + /// this function returns whether the mimicCall should use the `isSystem` flag. + /// This flag should only be used for contract deployments and nothing else. + /// @param to The callee of the call. + /// @param dataPtr The pointer to the calldata of the transaction. + function shouldMsgValueMimicCallBeSystem(to, dataPtr) -> ret { + let dataLen := mload(dataPtr) + // Note, that this point it is not fully known whether it is indeed the selector + // of the calldata (it might not be the case if the `dataLen` < 4), but it will be checked later on + let selector := shr(224, mload(add(dataPtr, 32))) + + let isSelectorCreate := or( + eq(selector, {{CREATE_SELECTOR}}), + eq(selector, {{CREATE_ACCOUNT_SELECTOR}}) + ) + let isSelectorCreate2 := or( + eq(selector, {{CREATE2_SELECTOR}}), + eq(selector, {{CREATE2_ACCOUNT_SELECTOR}}) + ) + + // Firstly, ensure that the selector is a valid deployment function + ret := or( + isSelectorCreate, + isSelectorCreate2 + ) + // Secondly, ensure that the callee is ContractDeployer + ret := and(ret, eq(to, CONTRACT_DEPLOYER_ADDR())) + // Thirdly, ensure that the calldata is long enough to contain the selector + ret := and(ret, gt(dataLen, 3)) + } + /// @dev Given the pointer to the calldata, the value and to /// performs the call through the msg.value simulator. /// @param to Which contract to call @@ -1764,7 +1798,7 @@ object "Bootloader" { /// the length of the calldata and the calldata itself right afterwards. function msgValueSimulatorMimicCall(to, from, value, dataPtr) -> success { // Only calls to the deployer system contract are allowed to be system - let isSystem := eq(to, CONTRACT_DEPLOYER_ADDR()) + let isSystem := shouldMsgValueMimicCallBeSystem(to, dataPtr) success := mimicCallOnlyResult( MSG_VALUE_SIMULATOR_ADDR(), @@ -2515,7 +2549,7 @@ object "Bootloader" { ) if iszero(success) { - debugLog("Failed publish timestamp data to L1", 0) + debugLog("Failed publish timestamp to L1", 0) revertWithReason(FAILED_TO_PUBLISH_TIMESTAMP_DATA_TO_L1(), 1) } } @@ -2902,7 +2936,7 @@ object "Bootloader" { - + assertEq(gt(getFrom(innerTxDataOffset), MAX_SYSTEM_CONTRACT_ADDR()), 1, "from in kernel space") @@ -3255,7 +3289,7 @@ object "Bootloader" { } } - /// @dev Returns the addition of two unsigned integers, reverting on overflow. + /// @dev Returns the subtraction of two unsigned integers, reverting on underflow. function safeSub(x, y, errMsg) -> ret { if gt(y, x) { assertionError(errMsg) @@ -3431,19 +3465,19 @@ object "Bootloader" { ret := 25 } - function L1_MESSENGER_PUBLISHING_FAILED_ERR_CODE() -> ret { + function FAILED_TO_PUBLISH_TIMESTAMP_DATA_TO_L1() -> ret { ret := 26 } - function L1_MESSENGER_LOG_SENDING_FAILED_ERR_CODE() -> ret { + function L1_MESSENGER_PUBLISHING_FAILED_ERR_CODE() -> ret { ret := 27 } - function FAILED_TO_CALL_SYSTEM_CONTEXT_ERR_CODE() -> ret { + function L1_MESSENGER_LOG_SENDING_FAILED_ERR_CODE() -> ret { ret := 28 } - function FAILED_TO_PUBLISH_TIMESTAMP_DATA_TO_L1() -> ret { + function FAILED_TO_CALL_SYSTEM_CONTEXT_ERR_CODE() -> ret { ret := 29 } diff --git a/bootloader/tests/bootloader/bootloader_test.yul b/bootloader/tests/bootloader/bootloader_test.yul index 79024eb70c23..cd41c45d004b 100644 --- a/bootloader/tests/bootloader/bootloader_test.yul +++ b/bootloader/tests/bootloader/bootloader_test.yul @@ -49,4 +49,4 @@ function TEST_simple_transaction() { let txDataOffset := testing_txDataOffset(0) let innerTxDataOffset := add(txDataOffset, 0x20) testing_assertEq(getGasPerPubdataByteLimit(innerTxDataOffset), 0xc350, "Invalid pubdata limit") -} \ No newline at end of file +} diff --git a/bootloader/tests/utils/test_utils.yul b/bootloader/tests/utils/test_utils.yul index c8cf49cbf19f..561a4679f23a 100644 --- a/bootloader/tests/utils/test_utils.yul +++ b/bootloader/tests/utils/test_utils.yul @@ -38,6 +38,7 @@ function testing_assertEq(a, b, message) { setTestHook(nonOptimized(101)) } } + function testing_testWillFailWith(message) { storeTestHookParam(0, unoptimized(message)) setTestHook(nonOptimized(102)) @@ -51,4 +52,4 @@ function testing_totalTests(tests) { function testing_txDataOffset(index) -> txDataOffset { let txPtr := add(TX_DESCRIPTION_BEGIN_BYTE(), mul(index, TX_DESCRIPTION_SIZE())) txDataOffset := mload(add(txPtr, 0x20)) -} \ No newline at end of file +} diff --git a/contracts/AccountCodeStorage.sol b/contracts/AccountCodeStorage.sol index 21a2311bb0ec..d5027f2f5944 100644 --- a/contracts/AccountCodeStorage.sol +++ b/contracts/AccountCodeStorage.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import "./interfaces/IAccountCodeStorage.sol"; import "./libraries/Utils.sol"; diff --git a/contracts/BootloaderUtilities.sol b/contracts/BootloaderUtilities.sol index 5a73eb2fa59d..49467bdc23e9 100644 --- a/contracts/BootloaderUtilities.sol +++ b/contracts/BootloaderUtilities.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import "./interfaces/IBootloaderUtilities.sol"; import "./libraries/TransactionHelper.sol"; diff --git a/contracts/ComplexUpgrader.sol b/contracts/ComplexUpgrader.sol index d45ecd57af84..2f4d886cdc0d 100644 --- a/contracts/ComplexUpgrader.sol +++ b/contracts/ComplexUpgrader.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import {IComplexUpgrader} from "./interfaces/IComplexUpgrader.sol"; import {FORCE_DEPLOYER} from "./Constants.sol"; diff --git a/contracts/Compressor.sol b/contracts/Compressor.sol index 235146d04d72..24aac725a6c2 100644 --- a/contracts/Compressor.sol +++ b/contracts/Compressor.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import {ICompressor, OPERATION_BITMASK, LENGTH_BITS_OFFSET, MAX_ENUMERATION_INDEX_SIZE} from "./interfaces/ICompressor.sol"; import {ISystemContract} from "./interfaces/ISystemContract.sol"; diff --git a/contracts/Constants.sol b/contracts/Constants.sol index b6a788a7603c..f089671031d8 100644 --- a/contracts/Constants.sol +++ b/contracts/Constants.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import {IAccountCodeStorage} from "./interfaces/IAccountCodeStorage.sol"; import {INonceHolder} from "./interfaces/INonceHolder.sol"; @@ -27,12 +27,10 @@ address constant SHA256_SYSTEM_CONTRACT = address(0x02); address constant ECADD_SYSTEM_CONTRACT = address(0x06); address constant ECMUL_SYSTEM_CONTRACT = address(0x07); -/// @dev The current maximum deployed precompile address. -/// Note: currently only two precompiles are deployed: -/// 0x01 - ecrecover -/// 0x02 - sha256 -/// Important! So the constant should be updated if more precompiles are deployed. -uint256 constant CURRENT_MAX_PRECOMPILE_ADDRESS = uint256(uint160(SHA256_SYSTEM_CONTRACT)); +/// @dev The maximal possible address of an L1-like precompie. These precompiles maintain the following properties: +/// - Their extcodehash is EMPTY_STRING_KECCAK +/// - Their extcodesize is 0 despite having a bytecode formally deployed there. +uint256 constant CURRENT_MAX_PRECOMPILE_ADDRESS = 0xff; address payable constant BOOTLOADER_FORMAL_ADDRESS = payable(address(SYSTEM_CONTRACTS_OFFSET + 0x01)); IAccountCodeStorage constant ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT = IAccountCodeStorage( diff --git a/contracts/ContractDeployer.sol b/contracts/ContractDeployer.sol index ed6d3fc2a98d..50af974213a8 100644 --- a/contracts/ContractDeployer.sol +++ b/contracts/ContractDeployer.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import {ImmutableData} from "./interfaces/IImmutableSimulator.sol"; import {IContractDeployer} from "./interfaces/IContractDeployer.sol"; -import {CREATE2_PREFIX, CREATE_PREFIX, NONCE_HOLDER_SYSTEM_CONTRACT, ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT, FORCE_DEPLOYER, MAX_SYSTEM_CONTRACT_ADDRESS, KNOWN_CODE_STORAGE_CONTRACT, ETH_TOKEN_SYSTEM_CONTRACT, IMMUTABLE_SIMULATOR_SYSTEM_CONTRACT, COMPLEX_UPGRADER_CONTRACT} from "./Constants.sol"; +import {CREATE2_PREFIX, CREATE_PREFIX, NONCE_HOLDER_SYSTEM_CONTRACT, ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT, FORCE_DEPLOYER, MAX_SYSTEM_CONTRACT_ADDRESS, KNOWN_CODE_STORAGE_CONTRACT, ETH_TOKEN_SYSTEM_CONTRACT, IMMUTABLE_SIMULATOR_SYSTEM_CONTRACT, COMPLEX_UPGRADER_CONTRACT, KECCAK256_SYSTEM_CONTRACT} from "./Constants.sol"; import {Utils} from "./libraries/Utils.sol"; import {EfficientCall} from "./libraries/EfficientCall.sol"; @@ -44,7 +44,10 @@ contract ContractDeployer is IContractDeployer, ISystemContract { } // It is an EOA, it is still an account. - if (ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT.getRawCodeHash(_address) == 0) { + if ( + _address > address(MAX_SYSTEM_CONTRACT_ADDRESS) && + ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT.getRawCodeHash(_address) == 0 + ) { return AccountAbstractionVersion.Version1; } @@ -214,6 +217,9 @@ contract ContractDeployer is IContractDeployer, ISystemContract { function forceDeployOnAddress(ForceDeployment calldata _deployment, address _sender) external payable onlySelf { _ensureBytecodeIsKnown(_deployment.bytecodeHash); + // Since the `forceDeployOnAddress` function is called only during upgrades, the Governance is trusted to correctly select + // the addresses to deploy the new bytecodes to and to assess whether overriding the AccountInfo for the "force-deployed" + // contract is acceptable. AccountInfo memory newAccountInfo; newAccountInfo.supportedAAVersion = AccountAbstractionVersion.None; // Accounts have sequential nonces by default. @@ -228,8 +234,23 @@ contract ContractDeployer is IContractDeployer, ISystemContract { false, _deployment.callConstructor ); + } - emit ContractDeployed(_sender, _deployment.bytecodeHash, _deployment.newAddress); + /// @notice The method that is temporarily needed to upgrade the Keccak256 precompile. It is to be removed in the + /// future. Unlike a normal forced deployment, it does not update account information as it requires updating a + /// mapping, and so requires Keccak256 precompile to work already. + /// @dev This method expects the sender (FORCE_DEPLOYER) to provide the correct bytecode hash for the Keccak256 + /// precompile. + function forceDeployKeccak256(bytes32 _keccak256BytecodeHash) external payable onlyCallFrom(FORCE_DEPLOYER) { + _ensureBytecodeIsKnown(_keccak256BytecodeHash); + _constructContract( + msg.sender, + address(KECCAK256_SYSTEM_CONTRACT), + _keccak256BytecodeHash, + msg.data[0:0], + false, + false + ); } /// @notice This method is to be used only during an upgrade to set bytecodes on specific addresses. @@ -295,7 +316,6 @@ contract ContractDeployer is IContractDeployer, ISystemContract { _storeAccountInfo(_newAddress, newAccountInfo); _constructContract(msg.sender, _newAddress, _bytecodeHash, _input, false, true); - emit ContractDeployed(msg.sender, _bytecodeHash, _newAddress); } /// @notice Check that bytecode hash is marked as known on the `KnownCodeStorage` system contracts @@ -352,5 +372,7 @@ contract ContractDeployer is IContractDeployer, ISystemContract { // If we do not call the constructor, we need to set the constructed code hash. ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT.storeAccountConstructedCodeHash(_newAddress, _bytecodeHash); } + + emit ContractDeployed(_sender, _bytecodeHash, _newAddress); } } diff --git a/contracts/DefaultAccount.sol b/contracts/DefaultAccount.sol index 0021839ede70..2257269d634a 100644 --- a/contracts/DefaultAccount.sol +++ b/contracts/DefaultAccount.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import "./interfaces/IAccount.sol"; import "./libraries/TransactionHelper.sol"; @@ -101,8 +101,6 @@ contract DefaultAccount is IAccount { if (_isValidSignature(txHash, _transaction.signature)) { magic = ACCOUNT_VALIDATION_SUCCESS_MAGIC; - } else { - magic = bytes4(0); } } @@ -219,7 +217,7 @@ contract DefaultAccount is IAccount { _transaction.processPaymasterInput(); } - fallback() external payable { + fallback() external payable ignoreInDelegateCall { // fallback of default account shouldn't be called by bootloader under no circumstances assert(msg.sender != BOOTLOADER_FORMAL_ADDRESS); diff --git a/contracts/EmptyContract.sol b/contracts/EmptyContract.sol index 711f8ba16d90..f0304beb49ae 100644 --- a/contracts/EmptyContract.sol +++ b/contracts/EmptyContract.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; /** * @author Matter Labs diff --git a/contracts/ImmutableSimulator.sol b/contracts/ImmutableSimulator.sol index 54fb4c9dd655..a018c92a1f9b 100644 --- a/contracts/ImmutableSimulator.sol +++ b/contracts/ImmutableSimulator.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import "./interfaces/IImmutableSimulator.sol"; import {DEPLOYER_SYSTEM_CONTRACT} from "./Constants.sol"; diff --git a/contracts/KnownCodesStorage.sol b/contracts/KnownCodesStorage.sol index 290063899177..2dda7854cccb 100644 --- a/contracts/KnownCodesStorage.sol +++ b/contracts/KnownCodesStorage.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import {IKnownCodesStorage} from "./interfaces/IKnownCodesStorage.sol"; import {ISystemContract} from "./interfaces/ISystemContract.sol"; diff --git a/contracts/L1Messenger.sol b/contracts/L1Messenger.sol index 5d5b34e6da07..47ee32657881 100644 --- a/contracts/L1Messenger.sol +++ b/contracts/L1Messenger.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import {IL1Messenger, L2ToL1Log, L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH, L2_TO_L1_LOG_SERIALIZE_SIZE, STATE_DIFF_COMPRESSION_VERSION_NUMBER} from "./interfaces/IL1Messenger.sol"; import {ISystemContract} from "./interfaces/ISystemContract.sol"; @@ -81,8 +81,9 @@ contract L1Messenger is IL1Messenger, ISystemContract { // We need to charge cost of hashing, as it will be used in `publishPubdataAndClearState`: // - keccakGasCost(L2_TO_L1_LOG_SERIALIZE_SIZE) and keccakGasCost(64) when reconstructing L2ToL1Log - // - at most 2 times keccakGasCost(64) (as merkle tree can contain ~2*N leaves) - uint256 gasToPay = keccakGasCost(L2_TO_L1_LOG_SERIALIZE_SIZE) + 3 * keccakGasCost(64); + // - at most 1 time keccakGasCost(64) when building the Merkle tree (as merkle tree can contain + // ~2*N nodes, where the first N nodes are leaves the hash of which is calculated on the previous step). + uint256 gasToPay = keccakGasCost(L2_TO_L1_LOG_SERIALIZE_SIZE) + 2 * keccakGasCost(64); SystemContractHelper.burnGas(Utils.safeCastToU32(gasToPay)); } @@ -141,11 +142,12 @@ contract L1Messenger is IL1Messenger, ISystemContract { // We need to charge cost of hashing, as it will be used in `publishPubdataAndClearState`: // - keccakGasCost(L2_TO_L1_LOG_SERIALIZE_SIZE) and keccakGasCost(64) when reconstructing L2ToL1Log // - keccakGasCost(64) and gasSpentOnMessageHashing when reconstructing Messages - // - at most 2 times keccakGasCost(64) (as merkle tree can contain ~2*N leaves) + // - at most 1 time keccakGasCost(64) when building the Merkle tree (as merkle tree can contain + // ~2*N nodes, where the first N nodes are leaves the hash of which is calculated on the previous step). uint256 gasToPay = pubdataLen * gasPerPubdataBytes + keccakGasCost(L2_TO_L1_LOG_SERIALIZE_SIZE) + - 4 * + 3 * keccakGasCost(64) + gasSpentOnMessageHashing; SystemContractHelper.burnGas(Utils.safeCastToU32(gasToPay)); @@ -195,7 +197,7 @@ contract L1Messenger is IL1Messenger, ISystemContract { /// Check logs uint32 numberOfL2ToL1Logs = uint32(bytes4(_totalL2ToL1PubdataAndStateDiffs[calldataPtr:calldataPtr + 4])); - require(numberOfL2ToL1Logs <= numberOfL2ToL1Logs, "Too many L2->L1 logs"); + require(numberOfL2ToL1Logs <= L2_TO_L1_LOGS_MERKLE_TREE_LEAVES, "Too many L2->L1 logs"); calldataPtr += 4; bytes32[] memory l2ToL1LogsTreeArray = new bytes32[](L2_TO_L1_LOGS_MERKLE_TREE_LEAVES); @@ -270,7 +272,7 @@ contract L1Messenger is IL1Messenger, ISystemContract { /// Check State Diffs /// encoding is as follows: - /// header (1 byte version, 2 bytes total len of compressed, 1 byte enumeration index size, 2 bytes number of initial writes) + /// header (1 byte version, 3 bytes total len of compressed, 1 byte enumeration index size, 2 bytes number of initial writes) /// body (N bytes of initial writes [32 byte derived key || compressed value], M bytes repeated writes [enumeration index || compressed value]) /// encoded state diffs: [20bytes address][32bytes key][32bytes derived key][8bytes enum index][32bytes initial value][32bytes final value] require( diff --git a/contracts/L2EthToken.sol b/contracts/L2EthToken.sol index 6a2ca48e5c08..fbd63ae213b3 100644 --- a/contracts/L2EthToken.sol +++ b/contracts/L2EthToken.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import {IEthToken} from "./interfaces/IEthToken.sol"; import {ISystemContract} from "./interfaces/ISystemContract.sol"; diff --git a/contracts/MsgValueSimulator.sol b/contracts/MsgValueSimulator.sol index 6a6a9d9f6dc8..07ed23d4ba23 100644 --- a/contracts/MsgValueSimulator.sol +++ b/contracts/MsgValueSimulator.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import "./libraries/Utils.sol"; import "./libraries/EfficientCall.sol"; diff --git a/contracts/NonceHolder.sol b/contracts/NonceHolder.sol index f5a08a6b5b30..b2775f1cb22c 100644 --- a/contracts/NonceHolder.sol +++ b/contracts/NonceHolder.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import "./interfaces/INonceHolder.sol"; import "./interfaces/IContractDeployer.sol"; @@ -132,8 +132,11 @@ contract NonceHolder is INonceHolder, ISystemContract { /// @notice Increments the deployment nonce for the account and returns the previous one. /// @param _address The address of the account which to return the deploy nonce for. /// @return prevDeploymentNonce The deployment nonce at the time this function is called. - function incrementDeploymentNonce(address _address) external onlySystemCall returns (uint256 prevDeploymentNonce) { - require(msg.sender == address(DEPLOYER_SYSTEM_CONTRACT), ""); + function incrementDeploymentNonce(address _address) external returns (uint256 prevDeploymentNonce) { + require( + msg.sender == address(DEPLOYER_SYSTEM_CONTRACT), + "Only the contract deployer can increment the deployment nonce" + ); uint256 addressAsKey = uint256(uint160(_address)); uint256 oldRawNonce = rawNonces[addressAsKey]; diff --git a/contracts/SystemContext.sol b/contracts/SystemContext.sol index ad20d4bbadcf..67f9248e9b13 100644 --- a/contracts/SystemContext.sol +++ b/contracts/SystemContext.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import {ISystemContext} from "./interfaces/ISystemContext.sol"; import {ISystemContract} from "./interfaces/ISystemContract.sol"; @@ -216,14 +216,14 @@ contract SystemContext is ISystemContext, ISystemContextDeprecated, ISystemContr require(_l2BlockNumber > 0, "L2 block number is never expected to be zero"); unchecked { - bytes32 correctPrevBlockHash = _calculateLegacyL2BlockHash(uint128(_l2BlockNumber - 1)); + bytes32 correctPrevBlockHash = _calculateLegacyL2BlockHash(_l2BlockNumber - 1); require(correctPrevBlockHash == _expectedPrevL2BlockHash, "The previous L2 block hash is incorrect"); // Whenever we'll be queried about the hashes of the blocks before the upgrade, // we'll use batches' hashes, so we don't need to store 256 previous hashes. // However, we do need to store the last previous hash in order to be able to correctly calculate the // hash of the new L2 block. - _setL2BlockHash(uint128(_l2BlockNumber - 1), correctPrevBlockHash); + _setL2BlockHash(_l2BlockNumber - 1, correctPrevBlockHash); } } @@ -382,7 +382,6 @@ contract SystemContext is ISystemContext, ISystemContextDeprecated, ISystemContr // The structure of the "setNewBatch" implies that currentBatchNumber > 0, but we still double check it require(currentBatchNumber > 0, "The current batch number must be greater than 0"); - bytes32 prevBatchHash = batchHash[currentBatchNumber - 1]; // In order to spend less pubdata, the packed version is published uint256 packedTimestamps = (uint256(currentBatchTimestamp) << 128) | currentL2BlockTimestamp; diff --git a/contracts/interfaces/IAccount.sol b/contracts/interfaces/IAccount.sol index cb54f313e82b..3ee3f616c7ec 100644 --- a/contracts/interfaces/IAccount.sol +++ b/contracts/interfaces/IAccount.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import "../libraries/TransactionHelper.sol"; diff --git a/contracts/interfaces/IAccountCodeStorage.sol b/contracts/interfaces/IAccountCodeStorage.sol index 977e7e168590..c266774ea3bf 100644 --- a/contracts/interfaces/IAccountCodeStorage.sol +++ b/contracts/interfaces/IAccountCodeStorage.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; interface IAccountCodeStorage { function storeAccountConstructingCodeHash(address _address, bytes32 _hash) external; diff --git a/contracts/interfaces/IBootloaderUtilities.sol b/contracts/interfaces/IBootloaderUtilities.sol index 16cfc7cf650c..e995295e16d9 100644 --- a/contracts/interfaces/IBootloaderUtilities.sol +++ b/contracts/interfaces/IBootloaderUtilities.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import "../libraries/TransactionHelper.sol"; diff --git a/contracts/interfaces/IComplexUpgrader.sol b/contracts/interfaces/IComplexUpgrader.sol index 91095cfc838c..ebc26dd2035e 100644 --- a/contracts/interfaces/IComplexUpgrader.sol +++ b/contracts/interfaces/IComplexUpgrader.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; interface IComplexUpgrader { function upgrade(address _delegateTo, bytes calldata _calldata) external payable; diff --git a/contracts/interfaces/ICompressor.sol b/contracts/interfaces/ICompressor.sol index 602cb70b3737..16e02d97f9ba 100644 --- a/contracts/interfaces/ICompressor.sol +++ b/contracts/interfaces/ICompressor.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; // The bitmask by applying which to the compressed state diff metadata we retrieve its operation. uint8 constant OPERATION_BITMASK = 7; diff --git a/contracts/interfaces/IContractDeployer.sol b/contracts/interfaces/IContractDeployer.sol index d21b917df81b..3f84672d76ec 100644 --- a/contracts/interfaces/IContractDeployer.sol +++ b/contracts/interfaces/IContractDeployer.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; interface IContractDeployer { /// @notice Defines the version of the account abstraction protocol diff --git a/contracts/interfaces/IEthToken.sol b/contracts/interfaces/IEthToken.sol index 5543d93111af..ec9b399f54f4 100644 --- a/contracts/interfaces/IEthToken.sol +++ b/contracts/interfaces/IEthToken.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; interface IEthToken { function balanceOf(uint256) external view returns (uint256); diff --git a/contracts/interfaces/IImmutableSimulator.sol b/contracts/interfaces/IImmutableSimulator.sol index 650f47d87c7e..d30ac9b96607 100644 --- a/contracts/interfaces/IImmutableSimulator.sol +++ b/contracts/interfaces/IImmutableSimulator.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; struct ImmutableData { uint256 index; diff --git a/contracts/interfaces/IKnownCodesStorage.sol b/contracts/interfaces/IKnownCodesStorage.sol index 075ad95f1036..b5a783baa7a9 100644 --- a/contracts/interfaces/IKnownCodesStorage.sol +++ b/contracts/interfaces/IKnownCodesStorage.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; interface IKnownCodesStorage { event MarkedAsKnown(bytes32 indexed bytecodeHash, bool indexed sendBytecodeToL1); diff --git a/contracts/interfaces/IL1Messenger.sol b/contracts/interfaces/IL1Messenger.sol index 05919edbee0e..ab6a670f98d5 100644 --- a/contracts/interfaces/IL1Messenger.sol +++ b/contracts/interfaces/IL1Messenger.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; /// @dev The log passed from L2 /// @param l2ShardId The shard identifier, 0 - rollup, 1 - porter. All other values are not used but are reserved for the future diff --git a/contracts/interfaces/IL2StandardToken.sol b/contracts/interfaces/IL2StandardToken.sol index 5edb43c2bbd0..3d75c8ede4ae 100644 --- a/contracts/interfaces/IL2StandardToken.sol +++ b/contracts/interfaces/IL2StandardToken.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; interface IL2StandardToken { event BridgeMint(address indexed _account, uint256 _amount); diff --git a/contracts/interfaces/IMailbox.sol b/contracts/interfaces/IMailbox.sol index b82305fcd302..ba673058c76b 100644 --- a/contracts/interfaces/IMailbox.sol +++ b/contracts/interfaces/IMailbox.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; interface IMailbox { function finalizeEthWithdrawal( diff --git a/contracts/interfaces/INonceHolder.sol b/contracts/interfaces/INonceHolder.sol index ebddfb0499a9..1213fbea477e 100644 --- a/contracts/interfaces/INonceHolder.sol +++ b/contracts/interfaces/INonceHolder.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; /** * @author Matter Labs diff --git a/contracts/interfaces/IPaymaster.sol b/contracts/interfaces/IPaymaster.sol index cc151935c53d..928f19eda9f9 100644 --- a/contracts/interfaces/IPaymaster.sol +++ b/contracts/interfaces/IPaymaster.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import "../libraries/TransactionHelper.sol"; diff --git a/contracts/interfaces/IPaymasterFlow.sol b/contracts/interfaces/IPaymasterFlow.sol index dc1b849f4012..59352f23b794 100644 --- a/contracts/interfaces/IPaymasterFlow.sol +++ b/contracts/interfaces/IPaymasterFlow.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; /** * @author Matter Labs diff --git a/contracts/interfaces/ISystemContext.sol b/contracts/interfaces/ISystemContext.sol index 096243f63dc4..d8a98292a3d7 100644 --- a/contracts/interfaces/ISystemContext.sol +++ b/contracts/interfaces/ISystemContext.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; /** * @author Matter Labs diff --git a/contracts/interfaces/ISystemContextDeprecated.sol b/contracts/interfaces/ISystemContextDeprecated.sol index 6a647c7e6d11..b51faeedacb9 100644 --- a/contracts/interfaces/ISystemContextDeprecated.sol +++ b/contracts/interfaces/ISystemContextDeprecated.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; /** * @author Matter Labs diff --git a/contracts/interfaces/ISystemContract.sol b/contracts/interfaces/ISystemContract.sol index 7a66587a502d..c486abc96f5b 100644 --- a/contracts/interfaces/ISystemContract.sol +++ b/contracts/interfaces/ISystemContract.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import {SystemContractHelper} from "../libraries/SystemContractHelper.sol"; import {BOOTLOADER_FORMAL_ADDRESS} from "../Constants.sol"; diff --git a/contracts/libraries/EfficientCall.sol b/contracts/libraries/EfficientCall.sol index 16a6b535cf5d..22801d6f7517 100644 --- a/contracts/libraries/EfficientCall.sol +++ b/contracts/libraries/EfficientCall.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import "./SystemContractHelper.sol"; import "./Utils.sol"; diff --git a/contracts/libraries/RLPEncoder.sol b/contracts/libraries/RLPEncoder.sol index aeacab68b18b..8e32ea9bacf9 100644 --- a/contracts/libraries/RLPEncoder.sol +++ b/contracts/libraries/RLPEncoder.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; /** * @author Matter Labs diff --git a/contracts/libraries/SystemContractHelper.sol b/contracts/libraries/SystemContractHelper.sol index 8a7734ce3593..a66b9670670d 100644 --- a/contracts/libraries/SystemContractHelper.sol +++ b/contracts/libraries/SystemContractHelper.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import {MAX_SYSTEM_CONTRACT_ADDRESS} from "../Constants.sol"; @@ -270,6 +270,8 @@ library SystemContractHelper { function getZkSyncMeta() internal view returns (ZkSyncMeta memory meta) { uint256 metaPacked = getZkSyncMetaBytes(); meta.gasPerPubdataByte = getGasPerPubdataByteFromMeta(metaPacked); + meta.heapSize = getHeapSizeFromMeta(metaPacked); + meta.auxHeapSize = getAuxHeapSizeFromMeta(metaPacked); meta.shardId = getShardIdFromMeta(metaPacked); meta.callerShardId = getCallerShardIdFromMeta(metaPacked); meta.codeShardId = getCodeShardIdFromMeta(metaPacked); diff --git a/contracts/libraries/SystemContractsCaller.sol b/contracts/libraries/SystemContractsCaller.sol index fe35341b3460..7be17992951c 100644 --- a/contracts/libraries/SystemContractsCaller.sol +++ b/contracts/libraries/SystemContractsCaller.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8; +pragma solidity 0.8.20; import {MSG_VALUE_SYSTEM_CONTRACT, MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT} from "../Constants.sol"; import "./Utils.sol"; diff --git a/contracts/libraries/TransactionHelper.sol b/contracts/libraries/TransactionHelper.sol index 10065f561380..e05781974261 100644 --- a/contracts/libraries/TransactionHelper.sol +++ b/contracts/libraries/TransactionHelper.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import "../openzeppelin/token/ERC20/IERC20.sol"; import "../openzeppelin/token/ERC20/utils/SafeERC20.sol"; diff --git a/contracts/libraries/UnsafeBytesCalldata.sol b/contracts/libraries/UnsafeBytesCalldata.sol index 7beca859bd98..4ce65f5fb271 100644 --- a/contracts/libraries/UnsafeBytesCalldata.sol +++ b/contracts/libraries/UnsafeBytesCalldata.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; /** * @author Matter Labs diff --git a/contracts/libraries/Utils.sol b/contracts/libraries/Utils.sol index 8e66e35fdfb1..a279152074d0 100644 --- a/contracts/libraries/Utils.sol +++ b/contracts/libraries/Utils.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity >=0.8.0; +pragma solidity 0.8.20; import "./EfficientCall.sol"; @@ -83,15 +83,15 @@ library Utils { // Note that the length of the bytecode must be provided in 32-byte words. require(_bytecode.length % 32 == 0, "po"); - uint256 bytecodeLenInWords = _bytecode.length / 32; - require(bytecodeLenInWords < 2 ** 16, "pp"); // bytecode length must be less than 2^16 words - require(bytecodeLenInWords % 2 == 1, "pr"); // bytecode length in words must be odd + uint256 lengthInWords = _bytecode.length / 32; + require(lengthInWords < 2 ** 16, "pp"); // bytecode length must be less than 2^16 words + require(lengthInWords % 2 == 1, "pr"); // bytecode length in words must be odd hashedBytecode = EfficientCall.sha(_bytecode) & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // Setting the version of the hash hashedBytecode = (hashedBytecode | bytes32(uint256(1 << 248))); // Setting the length - hashedBytecode = hashedBytecode | bytes32(bytecodeLenInWords << 224); + hashedBytecode = hashedBytecode | bytes32(lengthInWords << 224); } } diff --git a/contracts/precompiles/EcAdd.yul b/contracts/precompiles/EcAdd.yul index c5581457a165..bfbac645d079 100644 --- a/contracts/precompiles/EcAdd.yul +++ b/contracts/precompiles/EcAdd.yul @@ -247,7 +247,7 @@ object "EcAdd" { /// @dev See https://en.wikipedia.org/wiki/Montgomery_modular_multiplication#The_REDC_algorithm for further details on the Montgomery multiplication. /// @param minuend The minuend in Montgomery form. /// @param subtrahend The subtrahend in Montgomery form. - /// @return ret The result of the Montgomery addition. + /// @return ret The result of the Montgomery subtraction. function montgomerySub(minuend, subtrahend) -> ret { ret := montgomeryAdd(minuend, sub(P(), subtrahend)) } diff --git a/contracts/precompiles/EcMul.yul b/contracts/precompiles/EcMul.yul index 5de5dee0fe36..83c45ff095c1 100644 --- a/contracts/precompiles/EcMul.yul +++ b/contracts/precompiles/EcMul.yul @@ -225,7 +225,7 @@ object "EcMul" { /// @dev See https://en.wikipedia.org/wiki/Montgomery_modular_multiplication#The_The_REDC_algorithm for further details on the Montgomery multiplication. /// @param minuend The minuend in Montgomery form. /// @param subtrahend The subtrahend in Montgomery form. - /// @return ret The result of the Montgomery addition. + /// @return ret The result of the Montgomery subtraction. function montgomerySub(minuend, subtrahend) -> ret { ret := montgomeryAdd(minuend, sub(P(), subtrahend)) } diff --git a/contracts/test-contracts/Callable.sol b/contracts/test-contracts/Callable.sol index d2d56dc45680..e7477e0c3121 100644 --- a/contracts/test-contracts/Callable.sol +++ b/contracts/test-contracts/Callable.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; contract Callable { event Called(uint256 value, bytes data); diff --git a/contracts/test-contracts/DelegateCaller.sol b/contracts/test-contracts/DelegateCaller.sol new file mode 100644 index 000000000000..caa5aae6b5fe --- /dev/null +++ b/contracts/test-contracts/DelegateCaller.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract DelegateCaller { + function delegateCall(address _to) external payable { + assembly { + calldatacopy(0, 0, calldatasize()) + let result := delegatecall(gas(), _to, 0, calldatasize(), 0, 0) + returndatacopy(0, 0, returndatasize()) + switch result + case 0 { + revert(0, returndatasize()) + } + default { + return(0, returndatasize()) + } + } + } +} diff --git a/contracts/test-contracts/Deployable.sol b/contracts/test-contracts/Deployable.sol index 88b3c79725a4..be35861a4c5d 100644 --- a/contracts/test-contracts/Deployable.sol +++ b/contracts/test-contracts/Deployable.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; contract Deployable { event Deployed(uint256 value, bytes data); diff --git a/contracts/test-contracts/DummyUpgrade.sol b/contracts/test-contracts/DummyUpgrade.sol index 680df42aa1e7..b369f9a9bfa0 100644 --- a/contracts/test-contracts/DummyUpgrade.sol +++ b/contracts/test-contracts/DummyUpgrade.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; contract DummyUpgrade { event Upgraded(); diff --git a/contracts/test-contracts/EventWriterTest.sol b/contracts/test-contracts/EventWriterTest.sol index 3ad494f4559c..faf09cd78acf 100644 --- a/contracts/test-contracts/EventWriterTest.sol +++ b/contracts/test-contracts/EventWriterTest.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; contract EventWriterTest { event ZeroTopics(bytes data) anonymous; diff --git a/contracts/test-contracts/MockERC20Approve.sol b/contracts/test-contracts/MockERC20Approve.sol index 826ed41b2590..c993138944e2 100644 --- a/contracts/test-contracts/MockERC20Approve.sol +++ b/contracts/test-contracts/MockERC20Approve.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; contract MockERC20Approve { event Approved(address to, uint256 value); diff --git a/contracts/test-contracts/MockKnownCodesStorage.sol b/contracts/test-contracts/MockKnownCodesStorage.sol index c8ae0b9d6f5f..7cec142ebb5d 100644 --- a/contracts/test-contracts/MockKnownCodesStorage.sol +++ b/contracts/test-contracts/MockKnownCodesStorage.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; contract MockKnownCodesStorage { event MockBytecodePublished(bytes32 indexed bytecodeHash); diff --git a/contracts/test-contracts/MockL1Messenger.sol b/contracts/test-contracts/MockL1Messenger.sol index 9b74f9295f07..b24da5119f03 100644 --- a/contracts/test-contracts/MockL1Messenger.sol +++ b/contracts/test-contracts/MockL1Messenger.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; contract MockL1Messenger { event MockBytecodeL1Published(bytes32 indexed bytecodeHash); diff --git a/contracts/test-contracts/NotSystemCaller.sol b/contracts/test-contracts/NotSystemCaller.sol index c570a469ecf0..0c85deb63908 100644 --- a/contracts/test-contracts/NotSystemCaller.sol +++ b/contracts/test-contracts/NotSystemCaller.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8; +pragma solidity 0.8.20; contract NotSystemCaller { address immutable to; diff --git a/contracts/test-contracts/SystemCaller.sol b/contracts/test-contracts/SystemCaller.sol index 096f2a63a652..58adfce21f49 100644 --- a/contracts/test-contracts/SystemCaller.sol +++ b/contracts/test-contracts/SystemCaller.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8; +pragma solidity 0.8.20; import {SystemContractsCaller} from "../libraries/SystemContractsCaller.sol"; diff --git a/contracts/test-contracts/TestSystemContract.sol b/contracts/test-contracts/TestSystemContract.sol index 135e2cd769b5..8eba841dd602 100644 --- a/contracts/test-contracts/TestSystemContract.sol +++ b/contracts/test-contracts/TestSystemContract.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity 0.8.20; import "../Constants.sol"; diff --git a/contracts/test-contracts/TestSystemContractHelper.sol b/contracts/test-contracts/TestSystemContractHelper.sol index 6a114e4b9d64..2f9f7073be8d 100644 --- a/contracts/test-contracts/TestSystemContractHelper.sol +++ b/contracts/test-contracts/TestSystemContractHelper.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8; +pragma solidity 0.8.20; import {MAX_SYSTEM_CONTRACT_ADDRESS, MSG_VALUE_SYSTEM_CONTRACT} from "../Constants.sol"; diff --git a/hardhat.config.ts b/hardhat.config.ts index 6374c4e30e9d..73c7c0e883c5 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -20,13 +20,17 @@ export default { ethNetwork: "http://localhost:8545", }, solidity: { - version: "0.8.17", + version: "0.8.20", settings: { optimizer: { enabled: true, - runs: 200, + runs: 9999999, + }, + outputSelection: { + "*": { + "*": ["storageLayout"], + }, }, - viaIR: true, }, }, solpp: { diff --git a/scripts/compile-yul.ts b/scripts/compile-yul.ts index 51b91977ae8f..31ea720baf25 100644 --- a/scripts/compile-yul.ts +++ b/scripts/compile-yul.ts @@ -15,6 +15,7 @@ async function compilerLocation(): Promise { let salt = ""; if (IS_COMPILER_PRE_RELEASE) { + // @ts-ignore const url = getZksolcUrl("https://github.com/matter-labs/zksolc-prerelease", hre.config.zksolc.version); salt = saltFromUrl(url); } diff --git a/test/AccountCodeStorage.spec.ts b/test/AccountCodeStorage.spec.ts index e7d6e8d3262e..2be7c650bd18 100644 --- a/test/AccountCodeStorage.spec.ts +++ b/test/AccountCodeStorage.spec.ts @@ -105,16 +105,32 @@ describe("AccountCodeStorage tests", function () { await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); }); - it("successfully marked", async () => { - await accountCodeStorage - .connect(deployerAccount) - .storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH); + describe("getCodeHash", function () { + it("precompile", async () => { + // Check that the smallest precompile has EMPTY_STRING_KECCAK hash + expect(await accountCodeStorage.getCodeHash("0x0000000000000000000000000000000000000001")).to.be.eq( + EMPTY_STRING_KECCAK + ); + + // Check that the upper end of the precompile range has EMPTY_STRING_KECCAK hash + expect(await accountCodeStorage.getCodeHash("0x00000000000000000000000000000000000000ff")).to.be.eq( + EMPTY_STRING_KECCAK + ); + }); + + it("successfully marked", async () => { + await accountCodeStorage + .connect(deployerAccount) + .storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH); - await accountCodeStorage.connect(deployerAccount).markAccountCodeHashAsConstructed(RANDOM_ADDRESS); + await accountCodeStorage.connect(deployerAccount).markAccountCodeHashAsConstructed(RANDOM_ADDRESS); - expect(await accountCodeStorage.getRawCodeHash(RANDOM_ADDRESS)).to.be.eq(CONSTRUCTED_BYTECODE_HASH.toLowerCase()); + expect(await accountCodeStorage.getRawCodeHash(RANDOM_ADDRESS)).to.be.eq( + CONSTRUCTED_BYTECODE_HASH.toLowerCase() + ); - await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); + await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); + }); }); }); diff --git a/test/ContractDeployer.spec.ts b/test/ContractDeployer.spec.ts index f87d2ab3a38d..7f944e687370 100644 --- a/test/ContractDeployer.spec.ts +++ b/test/ContractDeployer.spec.ts @@ -26,6 +26,7 @@ describe("ContractDeployer tests", function () { const RANDOM_ADDRESS = ethers.utils.getAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbee1"); const RANDOM_ADDRESS_2 = ethers.utils.getAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbee2"); const RANDOM_ADDRESS_3 = ethers.utils.getAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbee3"); + const EMPTY_KERNEL_ADDRESS = ethers.utils.getAddress("0x0000000000000000000000000000000000000101"); const AA_VERSION_NONE = 0; const AA_VERSION_1 = 1; const NONCE_ORDERING_SEQUENTIAL = 0; @@ -158,6 +159,14 @@ describe("ContractDeployer tests", function () { expect(await contractDeployer.extendedAccountVersion(EOA)).to.be.eq(AA_VERSION_1); }); + it("Empty address", async () => { + // Double checking that the address is indeed empty + expect(await wallet.provider.getCode(EMPTY_KERNEL_ADDRESS)).to.be.eq("0x"); + + // Now testing that the system contracts with empty bytecode are still treated as AA_VERSION_NONE + expect(await contractDeployer.extendedAccountVersion(EMPTY_KERNEL_ADDRESS)).to.be.eq(AA_VERSION_NONE); + }); + it("not AA", async () => { expect(await contractDeployer.extendedAccountVersion(contractDeployerSystemCall.address)).to.be.eq( AA_VERSION_NONE diff --git a/test/DefaultAccount.spec.ts b/test/DefaultAccount.spec.ts index 25f5b86ca560..7cba80cae089 100644 --- a/test/DefaultAccount.spec.ts +++ b/test/DefaultAccount.spec.ts @@ -3,7 +3,19 @@ import { ethers, network } from "hardhat"; import * as zksync from "zksync-web3"; import type { Wallet } from "zksync-web3"; import { serialize } from "zksync-web3/build/src/utils"; -import type { Callable, DefaultAccount, L2EthToken, MockERC20Approve, NonceHolder } from "../typechain-types"; +import type { + Callable, + DefaultAccount, + L2EthToken, + MockERC20Approve, + NonceHolder, + Callable, + DefaultAccount, + DelegateCaller, + L2EthToken, + MockERC20Approve, + NonceHolder, +} from "../typechain-types"; import { DefaultAccount__factory, L2EthToken__factory, NonceHolder__factory } from "../typechain-types"; import { BOOTLOADER_FORMAL_ADDRESS, @@ -23,6 +35,7 @@ describe("DefaultAccount tests", function () { let callable: Callable; let mockERC20Approve: MockERC20Approve; let paymasterFlowInterface: ethers.utils.Interface; + let delegateCaller: DelegateCaller; const RANDOM_ADDRESS = ethers.utils.getAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); @@ -35,6 +48,7 @@ describe("DefaultAccount tests", function () { nonceHolder = NonceHolder__factory.connect(NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS, wallet); l2EthToken = L2EthToken__factory.connect(ETH_TOKEN_SYSTEM_CONTRACT_ADDRESS, wallet); callable = (await deployContract("Callable")) as Callable; + delegateCaller = (await deployContract("DelegateCaller")) as DelegateCaller; mockERC20Approve = (await deployContract("MockERC20Approve")) as MockERC20Approve; const paymasterFlowInterfaceArtifact = await loadArtifact("IPaymasterFlow"); @@ -350,14 +364,124 @@ describe("DefaultAccount tests", function () { expect(await wallet.provider.call(call)).to.be.eq("0x"); }); - it("non-zero value", async () => { - const call = { - from: wallet.address, - to: defaultAccount.address, - value: 3223, - data: "0x87238489489983493904904390431212224343434344433443433434344234234234", - }; - expect(await wallet.provider.call(call)).to.be.eq("0x"); + describe("prepareForPaymaster", function () { + it("non-deployer ignored", async () => { + const eip712Tx = await account.populateTransaction({ + type: 113, + to: callable.address, + from: account.address, + data: "0x", + value: 0, + maxFeePerGas: 12000, + maxPriorityFeePerGas: 100, + gasLimit: 50000, + customData: { + gasPerPubdata: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, + paymasterParams: { + paymaster: RANDOM_ADDRESS, + paymasterInput: paymasterFlowInterface.encodeFunctionData("approvalBased", [ + mockERC20Approve.address, + 2023, + "0x", + ]), + }, + }, + }); + const signedEip712Tx = await account.signTransaction(eip712Tx); + const parsedEIP712tx = zksync.utils.parseTransaction(signedEip712Tx); + + const eip712TxData = signedTxToTransactionData(parsedEIP712tx)!; + const eip712TxHash = parsedEIP712tx.hash; + const eip712SignedHash = zksync.EIP712Signer.getSignedDigest(eip712Tx); + + await expect( + await defaultAccount.prepareForPaymaster(eip712TxHash, eip712SignedHash, eip712TxData) + ).to.not.emit(mockERC20Approve, "Approved"); + }); + + it("successfully prepared", async () => { + const eip712Tx = await account.populateTransaction({ + type: 113, + to: callable.address, + from: account.address, + data: "0x", + value: 0, + maxFeePerGas: 12000, + maxPriorityFeePerGas: 100, + gasLimit: 50000, + customData: { + gasPerPubdata: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, + paymasterParams: { + paymaster: RANDOM_ADDRESS, + paymasterInput: paymasterFlowInterface.encodeFunctionData("approvalBased", [ + mockERC20Approve.address, + 2023, + "0x", + ]), + }, + }, + }); + const signedEip712Tx = await account.signTransaction(eip712Tx); + const parsedEIP712tx = zksync.utils.parseTransaction(signedEip712Tx); + + const eip712TxData = signedTxToTransactionData(parsedEIP712tx)!; + const eip712TxHash = parsedEIP712tx.hash; + const eip712SignedHash = zksync.EIP712Signer.getSignedDigest(eip712Tx); + + await expect( + await defaultAccount.connect(bootloader).prepareForPaymaster(eip712TxHash, eip712SignedHash, eip712TxData) + ) + .to.emit(mockERC20Approve, "Approved") + .withArgs(RANDOM_ADDRESS, 2023); + }); + }); + + describe("fallback/receive", function () { + it("zero value by EOA wallet", async () => { + const call = { + from: wallet.address, + to: defaultAccount.address, + value: 0, + data: "0x872384894899834939049043904390390493434343434344433443433434344234234234", + }; + expect(await wallet.provider.call(call)).to.be.eq("0x"); + }); + + it("non-zero value by EOA wallet", async () => { + const call = { + from: wallet.address, + to: defaultAccount.address, + value: 3223, + data: "0x87238489489983493904904390431212224343434344433443433434344234234234", + }; + expect(await wallet.provider.call(call)).to.be.eq("0x"); + }); + + it("zero value by bootloader", async () => { + // Here we need to ensure that during delegatecalls even if `msg.sender` is the bootloader, + // the fallback is behaving correctly + const calldata = delegateCaller.interface.encodeFunctionData("delegateCall", [defaultAccount.address]); + const call = { + from: BOOTLOADER_FORMAL_ADDRESS, + to: delegateCaller.address, + value: 0, + data: calldata, + }; + expect(await bootloader.call(call)).to.be.eq("0x"); + }); + + it("non-zero value by bootloader", async () => { + // Here we need to ensure that during delegatecalls even if `msg.sender` is the bootloader, + // the fallback is behaving correctly + const calldata = delegateCaller.interface.encodeFunctionData("delegateCall", [defaultAccount.address]); + const call = { + from: BOOTLOADER_FORMAL_ADDRESS, + to: delegateCaller.address, + value: 3223, + data: calldata, + }; + expect(await bootloader.call(call)).to.be.eq("0x"); + }); }); }); });