diff --git a/.github/workflows/invariant-tests.yaml b/.github/workflows/invariant-tests.yaml index 0a0bedd27b..fd51dc51ac 100644 --- a/.github/workflows/invariant-tests.yaml +++ b/.github/workflows/invariant-tests.yaml @@ -38,7 +38,7 @@ jobs: - name: Install foundry-zksync uses: dutterbutter/foundry-zksync-toolchain@5b0459c3701903f1913b8b2558a22bf49138e495 # v1.0.0 with: - version: nightly-27360d4c8d12beddbb730dae07ad33a206b38f4b + version: nightly-34fe0bc655c6b15e869ffd465addde001f6b474d - name: Show forge version shell: bash diff --git a/.github/workflows/l1-contracts-ci.yaml b/.github/workflows/l1-contracts-ci.yaml index 31aca2a76f..f6776415b8 100644 --- a/.github/workflows/l1-contracts-ci.yaml +++ b/.github/workflows/l1-contracts-ci.yaml @@ -330,7 +330,7 @@ jobs: defaults: run: working-directory: l1-contracts - needs: [build, lint] + needs: [build] # TODO return lint into dependencies when it's fully fixed runs-on: ubuntu-latest steps: @@ -372,7 +372,7 @@ jobs: system-contracts/zkout - name: Run coverage - run: yarn test:foundry && yarn coverage:foundry --report summary --report lcov + run: yarn test:foundry --no-match-path 'test/foundry/l1/unit/concrete/Executor/*' && yarn coverage:foundry --report summary --report lcov # Installing the specific version of `lcov` because of # the `genhtml: ERROR: line ... of ... has branchcov but no linecov data` error. diff --git a/.gitignore b/.gitignore index a25e3328e6..508f5d1d41 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ l1-contracts/out/* l1-contracts/zkout/* l1-contracts/broadcast/* l1-contracts/script-config/* +l1-contracts/snapshots/* !l1-contracts/script-config/artifacts l1-contracts/script-out/* l1-contracts/test/foundry/l1/integration/deploy-scripts/script-out/*.toml diff --git a/.solhint.json b/.solhint.json index e729cdd2e7..b3b2ddd74b 100644 --- a/.solhint.json +++ b/.solhint.json @@ -18,6 +18,7 @@ "func-name-mixedcase": "off", "func-named-parameters": ["error", 4], "func-visibility": ["error", { "ignoreConstructors": true }], + "import-path-check": "off", "imports-on-top": "error", "max-states-count": "off", "modifier-name-mixedcase": "error", diff --git a/.solhintignore b/.solhintignore index d24e429ca8..3fb2381522 100644 --- a/.solhintignore +++ b/.solhintignore @@ -8,6 +8,7 @@ l1-contracts/lib l1-contracts/node_modules l1-contracts/contracts/dev-contracts l1-contracts/test +l1-contracts/snapshots/* l1-contracts/deploy-scripts !l1-contracts/deploy-scripts/DeployCTM.s.sol !l1-contracts/deploy-scripts/DeployUtils.s.sol diff --git a/AllContractsHashes.json b/AllContractsHashes.json index cce17b3214..8da0bebea5 100644 --- a/AllContractsHashes.json +++ b/AllContractsHashes.json @@ -1,7 +1,7 @@ [ { "contractName": "system-contracts/AccountCodeStorage", - "zkBytecodeHash": "0x01000075cf1ac0ce411ada7abb6013e21c696808fb2f218c362c762c55aee6ed", + "zkBytecodeHash": "0x01000075bc7886a04ee6ae0d09d1b147782b3385656fdc9ad7acca96b2b89687", "zkBytecodePath": "/system-contracts/zkout/AccountCodeStorage.sol/AccountCodeStorage.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -10,6 +10,7 @@ { "contractName": "system-contracts/Address", "zkBytecodeHash": "0x010000078af90eee2a4a816909b23eb5f17b25b9c569ec40f7419bbb1a501044", + "zkBytecodeHash": "0x010000078af90eee2a4a816909b23eb5f17b25b9c569ec40f7419bbb1a501044", "zkBytecodePath": "/system-contracts/zkout/Address.sol/Address.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -23,9 +24,17 @@ "evmBytecodePath": null, "evmDeployedBytecodeHash": null }, + { + "contractName": "system-contracts/Arrays", + "zkBytecodeHash": "0x01000007f510fa13077b64f92f07ba01c744046a7f613e34ac5cb3c4de26a99d", + "zkBytecodePath": "/system-contracts/zkout/Arrays.sol/Arrays.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, { "contractName": "system-contracts/BootloaderUtilities", - "zkBytecodeHash": "0x0100092578227d3a76095f2a28b5fb42c071f2f3368181c0352e9de5e3bf2810", + "zkBytecodeHash": "0x01000925b6f5176b7d05699e2ef0c57c7e20e979e2e739dfe9d0a06624baf702", "zkBytecodePath": "/system-contracts/zkout/BootloaderUtilities.sol/BootloaderUtilities.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -33,7 +42,7 @@ }, { "contractName": "system-contracts/Compressor", - "zkBytecodeHash": "0x0100013fabead47869c649facad722751dfd011714db9d593266d6576ac4b56c", + "zkBytecodeHash": "0x010001395fa23f37c9616e365c13a0aa7b9bd0540d9df9716957574cbb18d420", "zkBytecodePath": "/system-contracts/zkout/Compressor.sol/Compressor.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -41,7 +50,7 @@ }, { "contractName": "system-contracts/ContractDeployer", - "zkBytecodeHash": "0x010006ab7168fe9c5d90d37926c70013a3fa8dc55a231948b12e2239136949fb", + "zkBytecodeHash": "0x010006ab30029b4c31df39ee6a4d187702e2dbf8b3cf84a47323cdc485c95e65", "zkBytecodePath": "/system-contracts/zkout/ContractDeployer.sol/ContractDeployer.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -49,15 +58,23 @@ }, { "contractName": "system-contracts/Create2Factory", - "zkBytecodeHash": "0x0100003fe99547296e4d43779e6701b0ee8e52de6dc6ced07de8b4d863e9cbdd", + "zkBytecodeHash": "0x0100003f56627f317a9771426aff874164dd9f68f30d6933a418425bf09cb425", "zkBytecodePath": "/system-contracts/zkout/Create2Factory.sol/Create2Factory.json", "evmBytecodeHash": null, "evmBytecodePath": null, "evmDeployedBytecodeHash": null }, + { + "contractName": "system-contracts/DIMTLegacyTester", + "zkBytecodeHash": "0x01000431143226b2635b03b163f06a278af10a53483adcbef989f84136224f4d", + "zkBytecodePath": "/system-contracts/zkout/DIMTLegacyTester.sol/DIMTLegacyTester.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, { "contractName": "system-contracts/DefaultAccount", - "zkBytecodeHash": "0x010005f78e3cffae9023909875344864308cf7fbe90cdab4d2c7d8bacc557e44", + "zkBytecodeHash": "0x010005f7dc8563086b13f0b6ca88092859e29f50d4adf8c2924fec0f2227d892", "zkBytecodePath": "/system-contracts/zkout/DefaultAccount.sol/DefaultAccount.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -79,6 +96,14 @@ "evmBytecodePath": null, "evmDeployedBytecodeHash": null }, + { + "contractName": "system-contracts/DummyAssetTracker", + "zkBytecodeHash": "0x0100001d5320630819608f319e4ec66cb4aff49bc3240ef28e6159391be90fe0", + "zkBytecodePath": "/system-contracts/zkout/DummyAssetTracker.sol/DummyAssetTracker.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, { "contractName": "system-contracts/DummyBridgehub", "zkBytecodeHash": "0x0100001dcf7600d434df00c791c74525046826b4c8ecf1d84ea20c0148db640a", @@ -87,6 +112,70 @@ "evmBytecodePath": null, "evmDeployedBytecodeHash": null }, + { + "contractName": "system-contracts/DummyChainAssetHandler", + "zkBytecodeHash": "0x010000155973300832b2697d53a543ab1742e89f918eba767e272e79c5e6d3b2", + "zkBytecodePath": "/system-contracts/zkout/DummyChainAssetHandler.sol/DummyChainAssetHandler.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, + { + "contractName": "system-contracts/DummyInteropCenter", + "zkBytecodeHash": "0x01000013804880d2633856139aef7afccde54defb2533b74ebc59aa40d87798b", + "zkBytecodePath": "/system-contracts/zkout/DummyInteropCenter.sol/DummyInteropCenter.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, + { + "contractName": "system-contracts/DummyInteropHandler", + "zkBytecodeHash": "0x0100010db5fad8232af652de9889b0bf09b615f3eeb190a88af2f1025d950b44", + "zkBytecodePath": "/system-contracts/zkout/DummyInteropHandler.sol/DummyInteropHandler.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, + { + "contractName": "system-contracts/DummyL2AssetRouter", + "zkBytecodeHash": "0x0100003f095133ee4195d58f2a2714c0e9cea5cb2e873e13213007e77d9b97ab", + "zkBytecodePath": "/system-contracts/zkout/DummyL2AssetRouter.sol/DummyL2AssetRouter.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, + { + "contractName": "system-contracts/DummyL2MessageVerification", + "zkBytecodeHash": "0x010001592fe55c9051422797043f22a7c330f9471ac6b5591d9517e996093e1d", + "zkBytecodePath": "/system-contracts/zkout/DummyL2MessageVerification.sol/DummyL2MessageVerification.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, + { + "contractName": "system-contracts/DummyL2NativeTokenVault", + "zkBytecodeHash": "0x010000173d8ca2f2fcdb53c0f8cd3404aab085d61dbb0b3810144d225f1fd449", + "zkBytecodePath": "/system-contracts/zkout/DummyL2NativeTokenVault.sol/DummyL2NativeTokenVault.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, + { + "contractName": "system-contracts/DummyMessageRoot", + "zkBytecodeHash": "0x010000134e39355067d9da937bb94de9853965f6a2bc037081417bbc7d922023", + "zkBytecodePath": "/system-contracts/zkout/DummyMessageRoot.sol/DummyMessageRoot.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, + { + "contractName": "system-contracts/DynamicIncrementalMerkle", + "zkBytecodeHash": "0x01000007b8e0956a154ad5a8cfff706379dba4a17582be002ba1be92d25665f5", + "zkBytecodePath": "/system-contracts/zkout/DynamicIncrementalMerkle.sol/DynamicIncrementalMerkle.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, { "contractName": "system-contracts/ERC1967Proxy", "zkBytecodeHash": "0x01000099061056e891546ad811105c25405ec2dcfa53acd6a2fe34a008005233", @@ -97,7 +186,7 @@ }, { "contractName": "system-contracts/EfficientCall", - "zkBytecodeHash": "0x01000007fbc8cb150e8fcd507418e6ecdb4062f0c0994b3da4c592e3689373d2", + "zkBytecodeHash": "0x010000074185d7604f2e24561ab384d8da51be50da2322cd032401518e57fea5", "zkBytecodePath": "/system-contracts/zkout/EfficientCall.sol/EfficientCall.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -113,7 +202,7 @@ }, { "contractName": "system-contracts/EvmHashesStorage", - "zkBytecodeHash": "0x01000017eef4af4558800d57efaf2e5f870b4cdde4bb1868c573206c71543aea", + "zkBytecodeHash": "0x01000017400227a7208281d85abcbe2786d6ce9bdfda35aeb85991c46de3a3dd", "zkBytecodePath": "/system-contracts/zkout/EvmHashesStorage.sol/EvmHashesStorage.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -121,7 +210,7 @@ }, { "contractName": "system-contracts/EvmPredeploysManager", - "zkBytecodeHash": "0x010001112021c54006587c48d427193bf679274826ee5667d832feb0af576cbc", + "zkBytecodeHash": "0x01000111824ad1ef5f9872fba72c7ccfab0cfa98351be63a01d1a9a19e65e971", "zkBytecodePath": "/system-contracts/zkout/EvmPredeploysManager.sol/EvmPredeploysManager.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -129,7 +218,7 @@ }, { "contractName": "system-contracts/ImmutableSimulator", - "zkBytecodeHash": "0x010000332ed070da786e43007e2cd596236f18745508e1d7c529f6db9a677385", + "zkBytecodeHash": "0x01000033e688a7e9977ea858c9c2184b2f0accc2c023cdb50d712826b9f03df7", "zkBytecodePath": "/system-contracts/zkout/ImmutableSimulator.sol/ImmutableSimulator.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -137,7 +226,7 @@ }, { "contractName": "system-contracts/KnownCodesStorage", - "zkBytecodeHash": "0x010000c9c0cd033a01bd49753f1228c4c7ab528553275c79d4b36f7c4f95894a", + "zkBytecodeHash": "0x010000c97ad4b3c9b3bff80ab34db6b9c57542a226a52a6d4e7100bfadedb43a", "zkBytecodePath": "/system-contracts/zkout/KnownCodesStorage.sol/KnownCodesStorage.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -145,7 +234,7 @@ }, { "contractName": "system-contracts/L1Messenger", - "zkBytecodeHash": "0x010002e120e16f75b505c47cbec49d82712c1b68efec2e8830f8ee2ec8c0a446", + "zkBytecodeHash": "0x010002e18a5f59ba5e379fbca788e918cbd48e5a65121b70602c559a58803aee", "zkBytecodePath": "/system-contracts/zkout/L1Messenger.sol/L1Messenger.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -153,7 +242,7 @@ }, { "contractName": "system-contracts/L2BaseToken", - "zkBytecodeHash": "0x010000ed521a2441f6599525c78c79ab71815c9537cf47b7e55c837773bc89a0", + "zkBytecodeHash": "0x0100013524a319c62edf813092bc668099a1a68cfce88bfad6031707ba933cc2", "zkBytecodePath": "/system-contracts/zkout/L2BaseToken.sol/L2BaseToken.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -161,7 +250,7 @@ }, { "contractName": "system-contracts/L2DAValidator", - "zkBytecodeHash": "0x0100000724f422c607a4919a1ae6edb1971e30e6723471ed024e05eec8d54e67", + "zkBytecodeHash": "0x01000007fe5a0a6fa2be594c4ac97301a04f084cbf0b2128c2f24f8505abc1a3", "zkBytecodePath": "/system-contracts/zkout/L2DAValidator.sol/L2DAValidator.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -169,7 +258,7 @@ }, { "contractName": "system-contracts/L2DAValidatorTester", - "zkBytecodeHash": "0x0100016328a259e7859cb15214d4a85982c43225190b44e5a0ed923172b46698", + "zkBytecodeHash": "0x01000163c2d9161980b4a6e54e2ef88fe5c669a4e85371041c965a31f346052f", "zkBytecodePath": "/system-contracts/zkout/L2DAValidatorTester.sol/L2DAValidatorTester.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -177,7 +266,7 @@ }, { "contractName": "system-contracts/L2InteropRootStorage", - "zkBytecodeHash": "0x010000494d1e4532693d503dbb277f6afad4814c211f6541eb8a01e98f74e666", + "zkBytecodeHash": "0x010000494b2b490c56d0d116280c000053d0ef055a3d3a17a8312d0eb02e58f7", "zkBytecodePath": "/system-contracts/zkout/L2InteropRootStorage.sol/L2InteropRootStorage.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -185,7 +274,7 @@ }, { "contractName": "system-contracts/L2UpgradeUtils", - "zkBytecodeHash": "0x01000007b5557ae45dfa7b068c86a6cad43954ab6eeaf1a456e78b2e888dd717", + "zkBytecodeHash": "0x01000007a8dac081aa2f5315ad5629993bad7b86364eff15f7daefd1c8ba24cd", "zkBytecodePath": "/system-contracts/zkout/L2UpgradeUtils.sol/L2UpgradeUtils.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -193,12 +282,36 @@ }, { "contractName": "system-contracts/L2V29Upgrade", - "zkBytecodeHash": "0x0100037be17949ee3872488fa041fa8c888a0d3067b131270363d98f804662cd", + "zkBytecodeHash": "0x0100037bf94ef8dc593e28f036854bf352a32ea21dc6a5861e8cffff88fd0ac8", "zkBytecodePath": "/system-contracts/zkout/L2V29Upgrade.sol/L2V29Upgrade.json", "evmBytecodeHash": null, "evmBytecodePath": null, "evmDeployedBytecodeHash": null }, + { + "contractName": "system-contracts/Math", + "zkBytecodeHash": "0x01000007c20f7d266392a00bd2a2dab4c4d1e0e0b868565d2e70c799a5213863", + "zkBytecodePath": "/system-contracts/zkout/Math.sol/Math.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, + { + "contractName": "system-contracts/Merkle", + "zkBytecodeHash": "0x0100000726f0c4d55ed68cc70b6ffcef82d5c41f20cf7f3a7e10cf9ceab3b866", + "zkBytecodePath": "/system-contracts/zkout/Merkle.sol/Merkle.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, + { + "contractName": "system-contracts/MessageHashing", + "zkBytecodeHash": "0x01000007915c72b130f4b5d8f43217f9ca7b60afa4f239f8097a1d9b817eeb8b", + "zkBytecodePath": "/system-contracts/zkout/MessageHashing.sol/MessageHashing.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, { "contractName": "system-contracts/MockContract", "zkBytecodeHash": "0x010001457098d01041f0198f63894e4a3a3970f6b81c84e59fdb32896a3cb388", @@ -209,7 +322,7 @@ }, { "contractName": "system-contracts/MsgValueSimulator", - "zkBytecodeHash": "0x010000570a52a83fef0d92b3cbadde4a480c80dbd52b641da192de35a9b35a0b", + "zkBytecodeHash": "0x010000570468fbe1ab9cf3b7ddd5923541ab671ee375243b8717572cabcfd7a3", "zkBytecodePath": "/system-contracts/zkout/MsgValueSimulator.sol/MsgValueSimulator.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -217,7 +330,7 @@ }, { "contractName": "system-contracts/NonceHolder", - "zkBytecodeHash": "0x010000d92eb04bd0ec8b534876aec24e7361527c10fce703a79cd07b34860ea3", + "zkBytecodeHash": "0x010000d99622b0ebd66cc1ab452a9c6925a4249f89e3d9ad7fe17234f2bf92da", "zkBytecodePath": "/system-contracts/zkout/NonceHolder.sol/NonceHolder.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -233,7 +346,7 @@ }, { "contractName": "system-contracts/PubdataChunkPublisher", - "zkBytecodeHash": "0x010000738b1d2d75d830cf3009d9bf39cbe88765186f134781067786ff94cfa3", + "zkBytecodeHash": "0x01000073de4edf3f717b38c06dfd8a687ae0edda0e10097cc1fa09855ae596a9", "zkBytecodePath": "/system-contracts/zkout/PubdataChunkPublisher.sol/PubdataChunkPublisher.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -242,6 +355,7 @@ { "contractName": "system-contracts/RLPEncoder", "zkBytecodeHash": "0x010000079233243b612c43c8f70ace73338e1dfa1cdd1cc68b5395f86024d5cb", + "zkBytecodeHash": "0x010000079233243b612c43c8f70ace73338e1dfa1cdd1cc68b5395f86024d5cb", "zkBytecodePath": "/system-contracts/zkout/RLPEncoder.sol/RLPEncoder.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -250,6 +364,7 @@ { "contractName": "system-contracts/SafeERC20", "zkBytecodeHash": "0x010000077fd68bb9188bc511ccdc373ceba64c5fffdb2e7cf9cb2144e002eb63", + "zkBytecodeHash": "0x010000077fd68bb9188bc511ccdc373ceba64c5fffdb2e7cf9cb2144e002eb63", "zkBytecodePath": "/system-contracts/zkout/SafeERC20.sol/SafeERC20.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -258,12 +373,16 @@ { "contractName": "system-contracts/SloadContract", "zkBytecodeHash": "0x0100000f3db9bc40d7c57e7a4daa0e1d121e2a3d374cb8bb2bee1429f605b903", + "zkBytecodeHash": "0x0100000f3db9bc40d7c57e7a4daa0e1d121e2a3d374cb8bb2bee1429f605b903", "zkBytecodePath": "/system-contracts/zkout/SloadContract.sol/SloadContract.json", "evmBytecodeHash": null, "evmBytecodePath": null, "evmDeployedBytecodeHash": null }, { + "contractName": "system-contracts/StdConstants", + "zkBytecodeHash": "0x01000007ddfd0a0397e98fe318f7d53d89019690b419807f269ab5c3fbf986f5", + "zkBytecodePath": "/system-contracts/zkout/StdConstants.sol/StdConstants.json", "contractName": "system-contracts/StdConstants", "zkBytecodeHash": "0x01000007ddfd0a0397e98fe318f7d53d89019690b419807f269ab5c3fbf986f5", "zkBytecodePath": "/system-contracts/zkout/StdConstants.sol/StdConstants.json", @@ -272,6 +391,9 @@ "evmDeployedBytecodeHash": null }, { + "contractName": "system-contracts/stdError", + "zkBytecodeHash": "0x01000039f016b197404b3d00ebebb9570e703b70f039b165cb0f195d9b65f3de", + "zkBytecodePath": "/system-contracts/zkout/StdError.sol/stdError.json", "contractName": "system-contracts/stdError", "zkBytecodeHash": "0x01000039f016b197404b3d00ebebb9570e703b70f039b165cb0f195d9b65f3de", "zkBytecodePath": "/system-contracts/zkout/StdError.sol/stdError.json", @@ -280,6 +402,9 @@ "evmDeployedBytecodeHash": null }, { + "contractName": "system-contracts/stdJson", + "zkBytecodeHash": "0x0100000749143f4d6fed67f50b535fbc038660b6631e6b0ea07a399ab4d1eda0", + "zkBytecodePath": "/system-contracts/zkout/StdJson.sol/stdJson.json", "contractName": "system-contracts/stdJson", "zkBytecodeHash": "0x0100000749143f4d6fed67f50b535fbc038660b6631e6b0ea07a399ab4d1eda0", "zkBytecodePath": "/system-contracts/zkout/StdJson.sol/stdJson.json", @@ -288,6 +413,9 @@ "evmDeployedBytecodeHash": null }, { + "contractName": "system-contracts/stdMath", + "zkBytecodeHash": "0x010000070668235bf7d6adc01628803988cf8cdd298c7b7d6f07a3a7937633e6", + "zkBytecodePath": "/system-contracts/zkout/StdMath.sol/stdMath.json", "contractName": "system-contracts/stdMath", "zkBytecodeHash": "0x010000070668235bf7d6adc01628803988cf8cdd298c7b7d6f07a3a7937633e6", "zkBytecodePath": "/system-contracts/zkout/StdMath.sol/stdMath.json", @@ -296,6 +424,9 @@ "evmDeployedBytecodeHash": null }, { + "contractName": "system-contracts/stdStorage", + "zkBytecodeHash": "0x010000071b707323ada64f37c70ac2b00a7578f4b2f438c11013b6a152584bd9", + "zkBytecodePath": "/system-contracts/zkout/StdStorage.sol/stdStorage.json", "contractName": "system-contracts/stdStorage", "zkBytecodeHash": "0x010000071b707323ada64f37c70ac2b00a7578f4b2f438c11013b6a152584bd9", "zkBytecodePath": "/system-contracts/zkout/StdStorage.sol/stdStorage.json", @@ -304,6 +435,9 @@ "evmDeployedBytecodeHash": null }, { + "contractName": "system-contracts/stdStorageSafe", + "zkBytecodeHash": "0x01000007828ec24fcd1edbcf4ccbb50e3dce0335c6591cc7ebda89a6e8d6c213", + "zkBytecodePath": "/system-contracts/zkout/StdStorage.sol/stdStorageSafe.json", "contractName": "system-contracts/stdStorageSafe", "zkBytecodeHash": "0x01000007828ec24fcd1edbcf4ccbb50e3dce0335c6591cc7ebda89a6e8d6c213", "zkBytecodePath": "/system-contracts/zkout/StdStorage.sol/stdStorageSafe.json", @@ -312,6 +446,9 @@ "evmDeployedBytecodeHash": null }, { + "contractName": "system-contracts/StdStyle", + "zkBytecodeHash": "0x01000007e746868260368e5fab998a3c8ab7327c73389eb1bbda91575269e8c2", + "zkBytecodePath": "/system-contracts/zkout/StdStyle.sol/StdStyle.json", "contractName": "system-contracts/StdStyle", "zkBytecodeHash": "0x01000007e746868260368e5fab998a3c8ab7327c73389eb1bbda91575269e8c2", "zkBytecodePath": "/system-contracts/zkout/StdStyle.sol/StdStyle.json", @@ -320,6 +457,9 @@ "evmDeployedBytecodeHash": null }, { + "contractName": "system-contracts/stdToml", + "zkBytecodeHash": "0x01000007a218f4437e8e0ad79b0fc08c7e9fdcd8b079155620b318cd5ab4604a", + "zkBytecodePath": "/system-contracts/zkout/StdToml.sol/stdToml.json", "contractName": "system-contracts/stdToml", "zkBytecodeHash": "0x01000007a218f4437e8e0ad79b0fc08c7e9fdcd8b079155620b318cd5ab4604a", "zkBytecodePath": "/system-contracts/zkout/StdToml.sol/stdToml.json", @@ -328,6 +468,9 @@ "evmDeployedBytecodeHash": null }, { + "contractName": "system-contracts/StorageSlot", + "zkBytecodeHash": "0x01000007b4da23e7ecc67139bc7263577c22c9f4e3500ff7f33893a7a0387125", + "zkBytecodePath": "/system-contracts/zkout/StorageSlot.sol/StorageSlot.json", "contractName": "system-contracts/StorageSlot", "zkBytecodeHash": "0x01000007b4da23e7ecc67139bc7263577c22c9f4e3500ff7f33893a7a0387125", "zkBytecodePath": "/system-contracts/zkout/StorageSlot.sol/StorageSlot.json", @@ -337,7 +480,7 @@ }, { "contractName": "system-contracts/SystemCaller", - "zkBytecodeHash": "0x0100004df010bf9dd6caf8adf6ee04e2ec753c719cc11d21aa2530c382a0c57b", + "zkBytecodeHash": "0x0100004d9f11fdc8de2f57df0970c53e396c4fbc3e7aa97ff29c3ddae369058b", "zkBytecodePath": "/system-contracts/zkout/SystemCaller.sol/SystemCaller.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -345,7 +488,7 @@ }, { "contractName": "system-contracts/SystemContext", - "zkBytecodeHash": "0x010001735d394bdae9a8cfeed4527c6f8c70d31b6557365c715d04b5f345602a", + "zkBytecodeHash": "0x0100019fbdf115fa474ca9706ca7282a74d9993df2342ef9540bef6c3a744b30", "zkBytecodePath": "/system-contracts/zkout/SystemContext.sol/SystemContext.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -353,7 +496,7 @@ }, { "contractName": "system-contracts/SystemContractHelper", - "zkBytecodeHash": "0x010000074efda9a7bd1e9b4124864d40f7444ddd838e70ccb99b10ddbe85b43d", + "zkBytecodeHash": "0x0100000722f8e4416995de1c5eb102648c0a532e322b9fcb6acc20d323714114", "zkBytecodePath": "/system-contracts/zkout/SystemContractHelper.sol/SystemContractHelper.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -361,7 +504,7 @@ }, { "contractName": "system-contracts/SystemContractsCaller", - "zkBytecodeHash": "0x01000007c950811e35b306e38b798c361975c297591b1d62c745822ad40318fd", + "zkBytecodeHash": "0x0100000799b238729013a8922a012634fdb25aa1592c66d8d4fcb14233f561f0", "zkBytecodePath": "/system-contracts/zkout/SystemContractsCaller.sol/SystemContractsCaller.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -369,7 +512,7 @@ }, { "contractName": "system-contracts/TestStateDiffComposer", - "zkBytecodeHash": "0x0100025b510286ac7122ef076313defdb8ecd491570e6a4e5b2e36c899e2ec27", + "zkBytecodeHash": "0x0100025bb8f008a15aa51ca78e27897ac9c99a1a7e6d42f003002dd38b616c84", "zkBytecodePath": "/system-contracts/zkout/TestStateDiffComposer.sol/TestStateDiffComposer.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -377,7 +520,7 @@ }, { "contractName": "system-contracts/TransactionHelper", - "zkBytecodeHash": "0x0100000785fdc4cc63d956eef0d19aae3c31945e84fcfa5b9291b5b70407cddf", + "zkBytecodeHash": "0x010000074c1557ee9ee0654f4d1bb81d4c3ec798dfb4478e4b331455b6c52359", "zkBytecodePath": "/system-contracts/zkout/TransactionHelper.sol/TransactionHelper.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -387,6 +530,17 @@ "contractName": "system-contracts/TransparentUpgradeableProxy", "zkBytecodeHash": "0x010001490c1476510fa5cf427e77e16b960754d2a646825dde419ceb30478131", "zkBytecodePath": "/system-contracts/zkout/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json", + "contractName": "system-contracts/TransparentUpgradeableProxy", + "zkBytecodeHash": "0x010001490c1476510fa5cf427e77e16b960754d2a646825dde419ceb30478131", + "zkBytecodePath": "/system-contracts/zkout/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json", + "evmBytecodeHash": null, + "evmBytecodePath": null, + "evmDeployedBytecodeHash": null + }, + { + "contractName": "system-contracts/UncheckedMath", + "zkBytecodeHash": "0x01000007abbd5cd48d76a5f8f46845051c407bffaefa6d87b3461ef73d7a03c1", + "zkBytecodePath": "/system-contracts/zkout/UncheckedMath.sol/UncheckedMath.json", "evmBytecodeHash": null, "evmBytecodePath": null, "evmDeployedBytecodeHash": null @@ -409,7 +563,7 @@ }, { "contractName": "system-contracts/Utils", - "zkBytecodeHash": "0x010000076be6e11858fbc23a988254f8aa8cb4d07b588a89f54306710394e0c4", + "zkBytecodeHash": "0x01000007a06a586254114ded2bb2a1eba82ac70f6429d3d7e52d5fb324262bfd", "zkBytecodePath": "/system-contracts/zkout/Utils.sol/Utils.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -457,7 +611,7 @@ }, { "contractName": "l2-contracts/ForceDeployUpgrader", - "zkBytecodeHash": "0x0100005bb7578bc969f9264b5d1d46e904dd33b076123a85c8fd7761075d5324", + "zkBytecodeHash": "0x0100005b28fc9bf196c2d3c6ddf19bd319d2653427d561cf89e0dc8b65934b3a", "zkBytecodePath": "/l2-contracts/zkout/ForceDeployUpgrader.sol/ForceDeployUpgrader.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -465,7 +619,7 @@ }, { "contractName": "l2-contracts/L2ContractHelper", - "zkBytecodeHash": "0x01000007290ca51a97c7cd59c67df30cd201344727eabc5194cc560ba8e54360", + "zkBytecodeHash": "0x01000007825908c890562d6ad26dd7ab5e97403c91fa3be72ca6f7a5e4606161", "zkBytecodePath": "/l2-contracts/zkout/L2ContractHelper.sol/L2ContractHelper.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -481,7 +635,7 @@ }, { "contractName": "l2-contracts/SystemContractsCaller", - "zkBytecodeHash": "0x010000075cc6eff8545839d7213a13458c4eb1b42124affa91a710342241f5d0", + "zkBytecodeHash": "0x01000007812db9b8527aeb98da8ffe774aafd81858bdf0042f5072932a080ffb", "zkBytecodePath": "/l2-contracts/zkout/SystemContractsCaller.sol/SystemContractsCaller.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -489,7 +643,7 @@ }, { "contractName": "l2-contracts/Utils", - "zkBytecodeHash": "0x010000076dcb32ff66fc3e1c6c2e64862507458e190890e6168be4ad9e77ba08", + "zkBytecodeHash": "0x010000078ce44c601a0afc261d88f0e83fa4c03d93085d074c29ad22d96c96f7", "zkBytecodePath": "/l2-contracts/zkout/SystemContractsCaller.sol/Utils.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -497,7 +651,7 @@ }, { "contractName": "l2-contracts/TestnetPaymaster", - "zkBytecodeHash": "0x010000b79156c594628696ea8a631a0352435ba14de5425192d5bf5deb403f15", + "zkBytecodeHash": "0x010000b74db0bac06a0b47198c77e00c69cd05979d828116c327a1854f60154c", "zkBytecodePath": "/l2-contracts/zkout/TestnetPaymaster.sol/TestnetPaymaster.json", "evmBytecodeHash": null, "evmBytecodePath": null, @@ -513,961 +667,1057 @@ }, { "contractName": "l1-contracts/AccessControlRestriction", - "zkBytecodeHash": "0x01000295e5896d178124373321307583774d0f632906bd2bc89383ed072a08b8", + "zkBytecodeHash": "0x01000295594476efb444aa3ae4b136ca53ed9091235b8d876cd19a2eaebdbd5c", "zkBytecodePath": "/l1-contracts/zkout/AccessControlRestriction.sol/AccessControlRestriction.json", - "evmBytecodeHash": "0xcef7d681373c481dd4979d5f0bec01af08011bcf62a6a412064712583a2f9c7d", + "evmBytecodeHash": "0x9cdf43578ca1bee443ea6fc973aacb8bce76358c31271731c69032a40c9da000", "evmBytecodePath": "/l1-contracts/out/AccessControlRestriction.sol/AccessControlRestriction.json", - "evmDeployedBytecodeHash": "0xc511d6933ad7e392de9e84e88faa4d1c810126b88292f17afd4f4ba9678e886f" + "evmDeployedBytecodeHash": "0xc6eaccb26ac9a02e4418521949a6b0f4f2dcb51fa0836c3d12273c5392172cef" }, { "contractName": "l1-contracts/Address", - "zkBytecodeHash": "0x01000007920a76c05c5b8a6eb413a4f61d7406617edbda6fa1e6fda77c58717a", + "zkBytecodeHash": "0x01000007b003fea07e410c16ce3b445c70e84ed30a3f9a3bb13fa670bc6aaef0", "zkBytecodePath": "/l1-contracts/zkout/Address.sol/Address.json", - "evmBytecodeHash": "0x50642dd87abdb731d22b845d534a61bbe9c5145492fc6ac2ad5de86e1332cc71", + "evmBytecodeHash": "0x609bc5f9e123bba3ad3a585bf21fa5ee59af2f9951a185f87a9243ba4df38266", "evmBytecodePath": "/l1-contracts/out/Address.sol/Address.json", - "evmDeployedBytecodeHash": "0x816f1255a594513f2ebe09ca6f43588b0c34892a1e6e5c235b55e5fa28487816" + "evmDeployedBytecodeHash": "0x9658c8c02050ac4259b0fe6ad40491a2ea345b04729187c1badb31d6fafb8db5" }, { "contractName": "l1-contracts/AddressAliasHelper", - "zkBytecodeHash": "0x010000078fadbc6298ac00b9ee69ced598d5c9454899747ac6f08a29b86110f9", + "zkBytecodeHash": "0x01000007e444d3fa32d7b47de890197a08a3729c4e6ee581d438a35b434eb373", "zkBytecodePath": "/l1-contracts/zkout/AddressAliasHelper.sol/AddressAliasHelper.json", - "evmBytecodeHash": "0xc746891e19890ce2a4eec783c469f396838acd66d88642095d2ef3f0401cee99", + "evmBytecodeHash": "0x09b0566e6fd44b16682fbe35f9c6b4d8472ab8f268292a2d3e8e7ae663635588", "evmBytecodePath": "/l1-contracts/out/AddressAliasHelper.sol/AddressAliasHelper.json", - "evmDeployedBytecodeHash": "0x29bafdde6756da17a3b05174ea233f68abd1849ea534f99c4ab27a2966d29d07" + "evmDeployedBytecodeHash": "0x49aa7cba7920b9aa65d8bb0987a35a2e813f316a4f507ec25ffc8ed2d2ab5937" }, { "contractName": "l1-contracts/AddressUpgradeable", - "zkBytecodeHash": "0x01000007dd0acb212a28acc95b5ec6fe781397ecee8013ec1953673209b7cd2b", + "zkBytecodeHash": "0x01000007beeebd7748677372133ac29dcc6a17c4bf1606a9477fd9a663957338", "zkBytecodePath": "/l1-contracts/zkout/AddressUpgradeable.sol/AddressUpgradeable.json", - "evmBytecodeHash": "0x9bf8386f143fc1f2f2d174737097e0256fef2b126feebe6f04e06300e8d0a817", + "evmBytecodeHash": "0x63930cbe0207c081e2d6601576f304d7d7be0976756f33440d106db9101fb75e", "evmBytecodePath": "/l1-contracts/out/AddressUpgradeable.sol/AddressUpgradeable.json", - "evmDeployedBytecodeHash": "0x9fc2a478f1de0921735a2cf334e9665a96195bcddf21221b31c5ac87d9ba76a7" + "evmDeployedBytecodeHash": "0x766dc18a507ac9d3712e81b28f6e45a3c7f6d4633e24d570c3626679bd75000d" }, { "contractName": "l1-contracts/AdminFacet", - "zkBytecodeHash": "0x010007b912af636904380ab0c660380c7e1bd082ff469e28b83d87de49ec362c", + "zkBytecodeHash": "0x010008032a2d3b5f4c6f78525d1b06975385533890957d9790678206c96e44e1", "zkBytecodePath": "/l1-contracts/zkout/Admin.sol/AdminFacet.json", - "evmBytecodeHash": "0x1ed3a49cde7a7c60be692a702621dfe8ce9cff232835644260ded27b37a346af", + "evmBytecodeHash": "0x06e96646dc58647021eeebec41c56437f92593a66e80da5829131487c3d555b8", "evmBytecodePath": "/l1-contracts/out/Admin.sol/AdminFacet.json", - "evmDeployedBytecodeHash": "0xf0ade2d851bbcfb217cf1fdc647637b052b4753e6f5adcf61d3490387c4c0454" + "evmDeployedBytecodeHash": "0x80d56e2ffc1fc9b909554addbe6ebcda7fe317ba353ad90121359000504b3f3d" }, { "contractName": "l1-contracts/Arrays", - "zkBytecodeHash": "0x01000007ec54bcf91f8c27aa52160019edf07d15a0873f8757f565fbe77be64f", + "zkBytecodeHash": "0x01000007045d5f7963e15e6a75b275a71a2e08de94129b35094be3c02a8e196c", "zkBytecodePath": "/l1-contracts/zkout/Arrays.sol/Arrays.json", - "evmBytecodeHash": "0x8cdf407dac3e3d354b380a5cd910a01622b4ef0f812ab438bf1b6c583212698e", + "evmBytecodeHash": "0x57cefcb0170223e73f8eafbff2d00ec1d230751f1db9fef28f59e36ccda33ea5", "evmBytecodePath": "/l1-contracts/out/Arrays.sol/Arrays.json", - "evmDeployedBytecodeHash": "0x7080ea75be8c190a0727ac4695d2b3cdb77a6ddd9fe1eb16a094ce0f918f4167" + "evmDeployedBytecodeHash": "0x19f74fe0d4e858a7c0b84b30fb95ff87ac2af018eb7b56d52b32650867520960" + }, + { + "contractName": "l1-contracts/AttributesDecoder", + "zkBytecodeHash": "0x01000007b965615dbeb40d649d85d5c8a219ec00466fb10e74fa093c80488668", + "zkBytecodePath": "/l1-contracts/zkout/AttributesDecoder.sol/AttributesDecoder.json", + "evmBytecodeHash": "0x84f3dac4d3783cbbec994cda79a236b5c0123d660e6c8b9254f95a0d83f2d1ec", + "evmBytecodePath": "/l1-contracts/out/AttributesDecoder.sol/AttributesDecoder.json", + "evmDeployedBytecodeHash": "0xea40f89072c6eb6b324766a158ac5ce2a260d5ee272c71f02061718e3b18b917" }, { "contractName": "l1-contracts/BatchDecoder", - "zkBytecodeHash": "0x01000007dcc6bc72832bc654b101548c28a34d913d8497ad4ccf765c609e452a", + "zkBytecodeHash": "0x010000077d42bdbcbe6328f4e41d9384987557efd8349db8ee6cb070413a9dba", "zkBytecodePath": "/l1-contracts/zkout/BatchDecoder.sol/BatchDecoder.json", - "evmBytecodeHash": "0xad4d26b00825348732a0937c70d58fe61a759b7c63b3ca224b957e5da6de0f48", + "evmBytecodeHash": "0xcdd6bf557b199394be733fdc7e69dcc070a4877f3000cc79a54a8a420f4111f5", "evmBytecodePath": "/l1-contracts/out/BatchDecoder.sol/BatchDecoder.json", - "evmDeployedBytecodeHash": "0xbbfac109cb204e7ce7debdeafd59b65afa2bacdcd3327f4e07f8d26548079dd3" + "evmDeployedBytecodeHash": "0x27fa8eb86d0517b4a26a564f8eea90cf216dab38eac4098bc7060fb242df9d15" }, { "contractName": "l1-contracts/BeaconProxy", - "zkBytecodeHash": "0x010000f1477ebc7355591c664c501757b31e9cd0025d565546fc0054f28a6411", + "zkBytecodeHash": "0x010000f1e7cee5737fb3420e342a87f840e396306cf42f794506e858cfeb5a05", "zkBytecodePath": "/l1-contracts/zkout/BeaconProxy.sol/BeaconProxy.json", - "evmBytecodeHash": "0x70fe6fb533ade74d2bf2cd6ba8e7a10c9bf9831c65b6d01ac968ada913ca5e88", + "evmBytecodeHash": "0x29248707f05fa7edc797763b53aa089cc5f3b93e7777e7e5bd96a38b695af0da", "evmBytecodePath": "/l1-contracts/out/BeaconProxy.sol/BeaconProxy.json", - "evmDeployedBytecodeHash": "0xd98972a966e6a38b007ca6c285511cbeb70fbebd6a4dbab9b0ba94c29a60392a" + "evmDeployedBytecodeHash": "0x3549d6d44d9779e2f50e6e061679ed89f781bd205f17384fb439e47e1d686ed2" }, { "contractName": "l1-contracts/BridgeHelper", - "zkBytecodeHash": "0x0100000799dc076fa752a7d69898e9b4c77acb2cf99d8ad2ca0e683529f0e9c5", + "zkBytecodeHash": "0x01000007e4d030732120f635e06391a3bbdb34e366ec3bdd20f0973905f1c67e", "zkBytecodePath": "/l1-contracts/zkout/BridgeHelper.sol/BridgeHelper.json", - "evmBytecodeHash": "0x996301869d67ca06198e83d2396df6f19175b7242e89574b64d088cc7ec6612c", + "evmBytecodeHash": "0x4681e9c62f4bda0fd63abc4cb74d80932bd6b193d2b921aa9063efc45cedd8fe", "evmBytecodePath": "/l1-contracts/out/BridgeHelper.sol/BridgeHelper.json", - "evmDeployedBytecodeHash": "0xdb09cf0b2369bcbddc7cbf2b0b14dcc0bcc9658dddcbda095483bf8dc174f243" + "evmDeployedBytecodeHash": "0x4fa854ada37d4bd2b2da9a57ab66e56bae4174b5922eebb50338c47517035c00" }, { "contractName": "l1-contracts/BridgedStandardERC20", - "zkBytecodeHash": "0x010004ed8ad6db856062c4595633ca6a43c72074948e830a88ee097a33f43cfc", + "zkBytecodeHash": "0x010004eda1221272e6d1ad37cc95706001c95000e46d586763d7ed593c839680", "zkBytecodePath": "/l1-contracts/zkout/BridgedStandardERC20.sol/BridgedStandardERC20.json", - "evmBytecodeHash": "0x63c052ee24c7964473baf5093e95b81f8b06c49c634c58d1e0eee063e0d2b105", + "evmBytecodeHash": "0xa409df6c140124a435939e418c7048737cf2180db0610ef96a69ffe9f7ef9a03", "evmBytecodePath": "/l1-contracts/out/BridgedStandardERC20.sol/BridgedStandardERC20.json", - "evmDeployedBytecodeHash": "0xb5af54cea10ab7e521ebbd70c9e5b68dcb51c3a848fb30255654c446179c3f4c" + "evmDeployedBytecodeHash": "0x1bf80d76158daac11631e0a3738acb13acf01355b16c780b8d2ee69bcb05298d" }, { "contractName": "l1-contracts/BytecodesSupplier", - "zkBytecodeHash": "0x010000bf8ce0c7c0df69706e4e2d09ee16b9a7c1abec502f30e873835a6d90e7", + "zkBytecodeHash": "0x010000bf20cba4fb288ebd493c270f8d3e1c1e21238ce76bf814f5e0be2f8d29", "zkBytecodePath": "/l1-contracts/zkout/BytecodesSupplier.sol/BytecodesSupplier.json", - "evmBytecodeHash": "0xe39451eee53266783a76654e8b0c01bdc9571ed0210ef0b2d802f48b3304931a", + "evmBytecodeHash": "0x467baca1892fe6917029fa40df1c4b78abd0fff934161a17fb8ac6497720b525", "evmBytecodePath": "/l1-contracts/out/BytecodesSupplier.sol/BytecodesSupplier.json", - "evmDeployedBytecodeHash": "0xa0222abd90fa554833b485a9d44287cf8fada711f73a338b6d3683ce622f25e8" + "evmDeployedBytecodeHash": "0x76536d69e0624319ed92b7104633d163f254ea710f5d3b6f0fbb0bf0186b2e74" + }, + { + "contractName": "l1-contracts/Bytes", + "zkBytecodeHash": "0x010000075df32cfa7c7ec79f282a6f86bd7eb631fb67c12cc413a8bf0a2ba443", + "zkBytecodePath": "/l1-contracts/zkout/Bytes.sol/Bytes.json", + "evmBytecodeHash": "0x0f7d65d594388a34294a355cda3098ac8473305ff979dbdd840191d62404dec2", + "evmBytecodePath": "/l1-contracts/out/Bytes.sol/Bytes.json", + "evmDeployedBytecodeHash": "0xa316e4efaf4ef383b92831c2336c25fa48e27ebfb01eaa420eeba1b6c15aacd2" }, { "contractName": "l1-contracts/CTMDeploymentTracker", - "zkBytecodeHash": "0x010001bbde985068e52c27ef6287d3ffa4cd541e50459e71a58fee39c8294f39", + "zkBytecodeHash": "0x010001bb2fe6c1072454defc05acd9191e651e235e489cbbad4faf4a1eead68e", "zkBytecodePath": "/l1-contracts/zkout/CTMDeploymentTracker.sol/CTMDeploymentTracker.json", - "evmBytecodeHash": "0xc2dc97e41c498da7ee2ecb1cf45361d53fe83dce5210f926a935b910d0053d8e", + "evmBytecodeHash": "0x3529f6583d008f39d918de901e03e6ec79dfdd1b55d86cbcf2ea8b835dda56a3", "evmBytecodePath": "/l1-contracts/out/CTMDeploymentTracker.sol/CTMDeploymentTracker.json", - "evmDeployedBytecodeHash": "0xb2e8ae814d6e5b08d10207ac64fa859d486ae0c7d71734897b446c64cdc0dd1f" + "evmDeployedBytecodeHash": "0x5de0b338111de2ed2ae9b5e6b30efcbbe8f7ca4fea905344255484dec10add43" + }, + { + "contractName": "l1-contracts/Calldata", + "zkBytecodeHash": "0x0100000748bde040411cb2bdf6b0095a0e70d0b574bfbe68576f64781385eabd", + "zkBytecodePath": "/l1-contracts/zkout/Calldata.sol/Calldata.json", + "evmBytecodeHash": "0x7698b143dec518b5bb320a6888f4095777b2d479dca46a739309f36a03cf05e4", + "evmBytecodePath": "/l1-contracts/out/Calldata.sol/Calldata.json", + "evmDeployedBytecodeHash": "0xfc8df681ffe709d162f8169a0a1bbe7f147893bf7f08368607adbe64d02e956b" }, { "contractName": "l1-contracts/ChainAdmin", - "zkBytecodeHash": "0x0100019ba69bb3564e92dcd15e303b077526ffb8c39319a1be034818f438d4c5", + "zkBytecodeHash": "0x0100019ba9595f373678a0e50566eeda238dce1a63c281f53cf835f5590fc0e4", "zkBytecodePath": "/l1-contracts/zkout/ChainAdmin.sol/ChainAdmin.json", - "evmBytecodeHash": "0xf69e13cf3fdba3d6ecb310c2e4c072e433ce6372b1adc314ad1788d83159fbd8", + "evmBytecodeHash": "0x955cd00dd04846396d11ac09d9bc50fc53f5d5cec3eee26f79a5c3737b4aae78", "evmBytecodePath": "/l1-contracts/out/ChainAdmin.sol/ChainAdmin.json", - "evmDeployedBytecodeHash": "0xe2f9c21c5e1c60110c8a97f7d292a6fb8eb3999c0ac2fb6dd71d68c498b78a6d" + "evmDeployedBytecodeHash": "0x1434f7755e62e28b159f57cc99f62b1b27a23a81e916f80048b88abf4dc2ab42" }, { "contractName": "l1-contracts/ChainAdminOwnable", - "zkBytecodeHash": "0x010001217794cfb511deeb48121b53964acf20d4cb45d8589caa0b02fa15e2d0", + "zkBytecodeHash": "0x01000121e1a93385eb2a0e2fe05daea32f3bb503bf8dfa722ca8304ebfaac860", "zkBytecodePath": "/l1-contracts/zkout/ChainAdminOwnable.sol/ChainAdminOwnable.json", - "evmBytecodeHash": "0xe8f09febab29b1c10063e5a6d47d16c04d123fc22249e6c285e18ad2a8fe5505", + "evmBytecodeHash": "0xdad9bfb1235a59c6736713a75b78fdc268520b7fef20cdc790cfbb63eb504d99", "evmBytecodePath": "/l1-contracts/out/ChainAdminOwnable.sol/ChainAdminOwnable.json", - "evmDeployedBytecodeHash": "0x09890187305e4f2ca7a006c3ca497110f5e3abff63e667426b127f55a66ee5a2" + "evmDeployedBytecodeHash": "0xfd92be84c3fb1f3eda234b0c7ac7ee7f222744142e3652e421b639d0c5eb8ba5" }, { "contractName": "l1-contracts/ChainRegistrar", - "zkBytecodeHash": "0x010001fb74f6e00646b15b44f0cc3157d3278bee286e120770491ca6c9c47430", + "zkBytecodeHash": "0x010001fbd3ca6a92cd4892daafd4b0bcbb583b00eaaaa26cb9c5d8aa7a2c8985", "zkBytecodePath": "/l1-contracts/zkout/ChainRegistrar.sol/ChainRegistrar.json", - "evmBytecodeHash": "0xd753018c6ac43e46ef58696e08cf847ec934e4e886271fb5becdeb6d993b1b75", + "evmBytecodeHash": "0x42d0bac88338554f4bca93aef8e7a818b6b1282e3012ae7daa6e3c69a06ace42", "evmBytecodePath": "/l1-contracts/out/ChainRegistrar.sol/ChainRegistrar.json", - "evmDeployedBytecodeHash": "0x28a7276addcf18d6a6ffbb8b0431c168742ba4b60b9d957666697444fc8ee852" + "evmDeployedBytecodeHash": "0xbf712c79e39be16da585a6131d31bd99b298d49abd3684dd1614431ae485bb19" + }, + { + "contractName": "l1-contracts/ChainRegistrationSender", + "zkBytecodeHash": "0x0100015905511230afcc3164fdc00b81b910ee3329483ab4e48df31a5ec8e20e", + "zkBytecodePath": "/l1-contracts/zkout/ChainRegistrationSender.sol/ChainRegistrationSender.json", + "evmBytecodeHash": "0x35409161fb3fe43a327cb53f8de954379b470da15386771bca8efaf1934a6c2b", + "evmBytecodePath": "/l1-contracts/out/ChainRegistrationSender.sol/ChainRegistrationSender.json", + "evmDeployedBytecodeHash": "0x0b90f0b2c593b07bdea85544f9c4077645d4525404181384ffc0478eaf1e5803" + }, + { + "contractName": "l1-contracts/ChainTypeManager", + "zkBytecodeHash": "0x01000779b16f418f262b805a35d1a716ff1ca362067958a40e9907ed4ccb250b", + "zkBytecodePath": "/l1-contracts/zkout/ChainTypeManager.sol/ChainTypeManager.json", + "evmBytecodeHash": "0x3f4259adf8112fdc73adba2ba99228375a00381426dfe8ee7a0dcc2a75e1d735", + "evmBytecodePath": "/l1-contracts/out/ChainTypeManager.sol/ChainTypeManager.json", + "evmDeployedBytecodeHash": "0x43c9343e50cea937cbeae03de1898a1e3de2f3dcf844e081bc28722d1f5a0953" }, { "contractName": "l1-contracts/CountersUpgradeable", - "zkBytecodeHash": "0x010000076df32a9bc96f42e9f3855c4229b8786a032635908de44c9ceb7bbe91", + "zkBytecodeHash": "0x010000072ed133d29d6794de0367217b5796f5fd71a41450fca351d5a20e29f1", "zkBytecodePath": "/l1-contracts/zkout/CountersUpgradeable.sol/CountersUpgradeable.json", - "evmBytecodeHash": "0x2db8e6cd3078849ce3926a8eb9841fb5fd9d5ffe7d1d832cd84b8c7ae267c7e9", + "evmBytecodeHash": "0x4269099c34fd165384690346328f77f73219b9a4ba270335d548220b2a7c78a3", "evmBytecodePath": "/l1-contracts/out/CountersUpgradeable.sol/CountersUpgradeable.json", - "evmDeployedBytecodeHash": "0x5554cc69a5d787990518c0dfb3eb3aeb5fda0ac7d25d756bfa6faa3644fb7ecc" + "evmDeployedBytecodeHash": "0xe9ecd1dfec0441687237d02a73fb899ad59ef6f8c2d33d8f7960b46bc7a8b8ed" }, { "contractName": "l1-contracts/Create2", - "zkBytecodeHash": "0x01000007f2c54e57fe601024b571320f761a2811d849b0dfd82f4a43ac289a0d", + "zkBytecodeHash": "0x0100000701588d255ec031488d3f55cc283e881359935b65f983950e3462e355", "zkBytecodePath": "/l1-contracts/zkout/Create2.sol/Create2.json", - "evmBytecodeHash": "0xbf8297a1cb4ff4fc6dcd199d8a66b32f7b21b9e9a18d6d635d4e71e0d54fcc63", + "evmBytecodeHash": "0x12938872a6547ef351bf3e4b24e5547454d646bc7215ffb6434b699ca75850ef", "evmBytecodePath": "/l1-contracts/out/Create2.sol/Create2.json", - "evmDeployedBytecodeHash": "0xed794d8d33062a4df19b10cb44c2eb16b1c89bf1227becbef7622365b9d6d1e5" + "evmDeployedBytecodeHash": "0xed96964466586b6b0f495c4e84c675454f5f6afc45533870a358cc759e486798" }, { "contractName": "l1-contracts/DataEncoding", - "zkBytecodeHash": "0x0100000756c2591212d3aa85330871a99cc824a333a2085eca8e172e4998521c", + "zkBytecodeHash": "0x01000007861c5141a2bc15b752de34d80f2ec0b4676770dbe7414a43109b9cfb", "zkBytecodePath": "/l1-contracts/zkout/DataEncoding.sol/DataEncoding.json", - "evmBytecodeHash": "0xfd8a3cb4e7077683bca89328c50d1b90e34080d07006eb12ccd71a5cfb7105eb", + "evmBytecodeHash": "0xd5a6fc61e5bc80fda01783b99df43b0c19530fb280bb90f67e69bd7b127f2441", "evmBytecodePath": "/l1-contracts/out/DataEncoding.sol/DataEncoding.json", - "evmDeployedBytecodeHash": "0xe632758beeb6a5ebc095961e5b26a15287b18b463700490c5491116351f88b6e" + "evmDeployedBytecodeHash": "0x4afc0bebe0d6397a7c7784866aded2c4871236f8cc4a984ea7eda29970c3d2df" }, { "contractName": "l1-contracts/DefaultUpgrade", - "zkBytecodeHash": "0x010002dbf09341889971e3278676eac21e4989533bb0d95903e764a943cc9195", + "zkBytecodeHash": "0x01000279420dae7cf21e5f7e5219ad24b864cd52570f7736a697878edbc5f199", "zkBytecodePath": "/l1-contracts/zkout/DefaultUpgrade.sol/DefaultUpgrade.json", - "evmBytecodeHash": "0xfde61d529557a357b487a26da4e1b3364eaa3b8cb71b8b28a44106885b6892e8", + "evmBytecodeHash": "0x3f8c216cff33f0d2c29555eb4c7d778266bc41897e021dd2ec81178b1943cf2b", "evmBytecodePath": "/l1-contracts/out/DefaultUpgrade.sol/DefaultUpgrade.json", - "evmDeployedBytecodeHash": "0x7922343e27272a15c9329e7763f5e2393a5fb4eb6515357de85b74e7ab3fae80" + "evmDeployedBytecodeHash": "0x8b89831fe1ff71f8d9be25344c0a4182cf5a7dd749f6e6f6f27b987025ff233a" }, { "contractName": "l1-contracts/Diamond", - "zkBytecodeHash": "0x010000073a1e786b6cb014eeda38070dedf419f3ba92ab807074326048041aea", + "zkBytecodeHash": "0x01000007c6811572825ee1b699dfad279869b15a072c1466191fa5637b48993b", "zkBytecodePath": "/l1-contracts/zkout/Diamond.sol/Diamond.json", - "evmBytecodeHash": "0x91349a9fd09370618e765ee1a1f945cb586b699c3a54eefb279356473b094616", + "evmBytecodeHash": "0xb55fca329a4a09c61332a671e78533c59afee01dc96c96c441a6d728d1234157", "evmBytecodePath": "/l1-contracts/out/Diamond.sol/Diamond.json", - "evmDeployedBytecodeHash": "0xb59267b7375b324b6715e5ab5295b08984c0d1b327dfaac22db96c01c81d8615" + "evmDeployedBytecodeHash": "0x77b3ffd4af66371d11d017c51d6439b2d7599bb09f1e3536b0a3426dfdaecf93" }, { "contractName": "l1-contracts/DiamondInit", - "zkBytecodeHash": "0x010000897ea06913bed5e076e2f9cf5973468d527481ecb2efceb108f7efddcd", + "zkBytecodeHash": "0x010000d13d2d5f631ce56bc0c0b8bcfa789537cd5990ff34fac693cc41bd5244", "zkBytecodePath": "/l1-contracts/zkout/DiamondInit.sol/DiamondInit.json", - "evmBytecodeHash": "0x19673b60200f44a899b9918a25659c24f57b7cf30454cb94e29d719d9efa5b14", + "evmBytecodeHash": "0xefb66d997aee0067aa002e124b4149a55cc037485bed8bd6c141939e4989c181", "evmBytecodePath": "/l1-contracts/out/DiamondInit.sol/DiamondInit.json", - "evmDeployedBytecodeHash": "0x030c17614019b9386ee2122c0bc5ee6b0d485cb412e7bb3cbbb29bb1ce15ad8c" + "evmDeployedBytecodeHash": "0x19169919a0192f1bb99af74dfc8463d1fbe480c415c9f643f14e5618f4c624f4" }, { "contractName": "l1-contracts/DiamondProxy", - "zkBytecodeHash": "0x010002451e0fcd51cf44a06d89f2b4716075b2204328251e2e44003829647f90", + "zkBytecodeHash": "0x01000245b17f25764ce92fa00118b80cd2b4354a49859df1862b27f40df60baf", "zkBytecodePath": "/l1-contracts/zkout/DiamondProxy.sol/DiamondProxy.json", - "evmBytecodeHash": "0x3dfa9f83e7f4959bfb7c23dc9345b3609cdab560168a4bb18b140b00f26f70b3", + "evmBytecodeHash": "0x2029b092367fe63be63a4f22effa8cbb03633a4e673c43e8be4313a088f33d97", "evmBytecodePath": "/l1-contracts/out/DiamondProxy.sol/DiamondProxy.json", - "evmDeployedBytecodeHash": "0xf4a49a70227ca9ae0eb9b595b478f85eba9d179e7e95572094a317925920a1a5" + "evmDeployedBytecodeHash": "0xa3b313fc94244b789509ad2943d6c9130755965edccfc9e7de75f736a27de521" + }, + { + "contractName": "l1-contracts/DualVerifier", + "zkBytecodeHash": "0x010001fbdd365bf648e102635d3161bc6bb7e5b9a188052e68fcc8ea580d0950", + "zkBytecodePath": "/l1-contracts/zkout/DualVerifier.sol/DualVerifier.json", + "evmBytecodeHash": "0xebbb30552f6de07f465693fda1e73cca26b582d12252f7ccf1edf9f431285eaa", + "evmBytecodePath": "/l1-contracts/out/DualVerifier.sol/DualVerifier.json", + "evmDeployedBytecodeHash": "0x20cf2da8291045c0b5e00e6f585bfe3a5ed440f9a2d274a2447178a0a0e9fd62" }, { "contractName": "l1-contracts/DynamicIncrementalMerkle", - "zkBytecodeHash": "0x010000074dacb67fd24a3cac2033b67b5757b0879704c00bfcc4e3ddabdf30cb", + "zkBytecodeHash": "0x01000007abc13acf4911f3a89f4768bc18e71cf2bca2fff4b38f20212ef29954", "zkBytecodePath": "/l1-contracts/zkout/DynamicIncrementalMerkle.sol/DynamicIncrementalMerkle.json", - "evmBytecodeHash": "0x0a996e581b7c738ff205b43850b991711776cacb4f66b679d5598c97496b1deb", + "evmBytecodeHash": "0x306778660d40e4b32cf07dbfb232df3fe79f60bcfaac4203346358b1a62ae37e", "evmBytecodePath": "/l1-contracts/out/DynamicIncrementalMerkle.sol/DynamicIncrementalMerkle.json", - "evmDeployedBytecodeHash": "0x4f06a269231347d68b1a8bcef46029589832a30b4710d9a512af178f08662644" + "evmDeployedBytecodeHash": "0x532e8ab8a3cb4fdcd145758d6308ee1f2b21be413a1d52d0d300ee5fb5894c9b" + }, + { + "contractName": "l1-contracts/DynamicIncrementalMerkleMemory", + "zkBytecodeHash": "0x0100000784c27aca62543fb3c1aa53951f749dca11a3ebb2f7dd37ea7ea40e4c", + "zkBytecodePath": "/l1-contracts/zkout/DynamicIncrementalMerkleMemory.sol/DynamicIncrementalMerkleMemory.json", + "evmBytecodeHash": "0x6f60cee8184e3098cb51d348569d955cae968786de9673cb343a63e5a0d568f8", + "evmBytecodePath": "/l1-contracts/out/DynamicIncrementalMerkleMemory.sol/DynamicIncrementalMerkleMemory.json", + "evmDeployedBytecodeHash": "0x5c49ac66d04c76653b1ae3588c05de8127401690708e5f38643319572198ff83" }, { "contractName": "l1-contracts/ECDSAUpgradeable", - "zkBytecodeHash": "0x01000007060437b2f23712de7b3e19db54d9e77235802daf5be2e79f723f32af", + "zkBytecodeHash": "0x0100000748fbf994d4f812ca6a13ca57a59bcf401945a1da59e3293cdc1d4dd5", "zkBytecodePath": "/l1-contracts/zkout/ECDSAUpgradeable.sol/ECDSAUpgradeable.json", - "evmBytecodeHash": "0x4dc94826ab3488229991b6a087799cb74c70e08ea543a0b4a79b83cd3738774b", + "evmBytecodeHash": "0xc1d9af9655cb317f865fac6a1a687c339cd3b6485021888365b2a232e5eb81d6", "evmBytecodePath": "/l1-contracts/out/ECDSAUpgradeable.sol/ECDSAUpgradeable.json", - "evmDeployedBytecodeHash": "0x5f8548a188370531952b89772e90dd048fd6f5f17518bf03f7207d9f9f9e1841" + "evmDeployedBytecodeHash": "0x80e4b49efba562901cfba78eb190a520deed12a6bb999bdf66af1a986ff0b073" }, { "contractName": "l1-contracts/ERC1967Proxy", - "zkBytecodeHash": "0x010000995b4bcbf4b9d2eede849e79ef7f2019fdbfca92122e14bcd8f21172ee", + "zkBytecodeHash": "0x01000099409fe8149d8a2bb35004d881ac52a5f224e6c93fc321cd407a747f7f", "zkBytecodePath": "/l1-contracts/zkout/ERC1967Proxy.sol/ERC1967Proxy.json", - "evmBytecodeHash": "0x76536d2506147297710c71ebb9b13960c8f7aaddd512d48ccd4fe8ac00d6ddc7", + "evmBytecodeHash": "0x5155c35feb76d6ab8f6272285895074a3c8952ceda3664cc5799852fe6a5855d", "evmBytecodePath": "/l1-contracts/out/ERC1967Proxy.sol/ERC1967Proxy.json", - "evmDeployedBytecodeHash": "0x95eebd4d5e1c0c7747e3f02a11196ef6bf2096c1cbfb847291cc70481b9ae4c0" + "evmDeployedBytecodeHash": "0xdcf4aae7b923391b594238d29200f7343a86c607c4ddbb5ff994d5dc165f9da3" }, { "contractName": "l1-contracts/ERC20", - "zkBytecodeHash": "0x0100014f180f4dd3eb99a9434dbc88812b1d0d009b4923a2c8bb1734b406dc06", + "zkBytecodeHash": "0x0100014fe9e92b067a75ad7db5fa00f9717489ec3f94734e87ba45eab4c20847", "zkBytecodePath": "/l1-contracts/zkout/ERC20.sol/ERC20.json", - "evmBytecodeHash": "0xfdf9dcaa39e27121a9fb4c600f83e3071bea4322fc4c017116eca67995b1c1a4", + "evmBytecodeHash": "0x608b44022990143ae9656424dbf9e0eecebeb4d8140e8d48a511a6225d2d7c6e", "evmBytecodePath": "/l1-contracts/out/ERC20.sol/ERC20.json", - "evmDeployedBytecodeHash": "0xc06fb68d0c98fb02aa89485a16a0972d2858547af602234de6fbcab34663cd1c" + "evmDeployedBytecodeHash": "0x9f6eb6aba4b0fc3939ce09a7fd31bfea34cbef1093391d44afb4db487d5a4300" }, { "contractName": "l1-contracts/ERC20Upgradeable", - "zkBytecodeHash": "0x010000e522ee538248b60f5b06dc3a55ab2639adecc19bd76edf57a4379dba0e", + "zkBytecodeHash": "0x010000e53d870233def24e64b841d54eb88398049727acba233954a2b3591df1", "zkBytecodePath": "/l1-contracts/zkout/ERC20Upgradeable.sol/ERC20Upgradeable.json", - "evmBytecodeHash": "0xf043b0e2a047d3cc7fa1a836ec4044b72c649718c0ce9e2505058abb6690c3be", + "evmBytecodeHash": "0xcb37f14ca7dd2b4e43fe0b5204d623edccbd1cc8f4fb6f9d736256300c464149", "evmBytecodePath": "/l1-contracts/out/ERC20Upgradeable.sol/ERC20Upgradeable.json", - "evmDeployedBytecodeHash": "0x4b1e528e3ec0896a541d0abb856de38b7ff3c2ab94ab0964c8ad02019bd56b1a" + "evmDeployedBytecodeHash": "0x2a0eaeb72f73883c504aa2ed1fa687af76b573c82884b12eeec9f96b8537657f" }, { "contractName": "l1-contracts/EnumerableMap", - "zkBytecodeHash": "0x01000007a146063593c95a2bbfdd41cea358ddc106150b57d75a197d51845684", + "zkBytecodeHash": "0x010000073eb1ab92761a1c0eb9bff0cd4fe2ee774441926c4d516dccd02d4125", "zkBytecodePath": "/l1-contracts/zkout/EnumerableMap.sol/EnumerableMap.json", - "evmBytecodeHash": "0xaad7760e04e0f2fa7a36e860d0a388e6ceca1f0db2f8ac447404af60ca1d3053", + "evmBytecodeHash": "0x0783fd373005c66bd59901c135906074b1845a5adae50bb02b5942f97cc87373", "evmBytecodePath": "/l1-contracts/out/EnumerableMap.sol/EnumerableMap.json", - "evmDeployedBytecodeHash": "0x0aa3f2c62fd0c9b30357162bf66941e800c7ab424912d041c5ff6273d257f0cc" + "evmDeployedBytecodeHash": "0x24b6d9afe08f0e6fb8a337c59a8180d502399ec1a3b6a49a043257164a2a9381" }, { "contractName": "l1-contracts/EnumerableSet", - "zkBytecodeHash": "0x01000007b58459aa05910ae26cf0ae5c1df59de5bd23590c8553f007c47a3240", + "zkBytecodeHash": "0x010000075cb9cb410488a13395419f572a88095a5053e9d1690f9693cef64bda", "zkBytecodePath": "/l1-contracts/zkout/EnumerableSet.sol/EnumerableSet.json", - "evmBytecodeHash": "0xb08a80781a7a39e6223e61ff850923e15a445dcf501efb19821cf7e906126cfa", + "evmBytecodeHash": "0x75b3d1a3622d0f26402906487930dd021433289010d092d5da39b72acf21340b", "evmBytecodePath": "/l1-contracts/out/EnumerableSet.sol/EnumerableSet.json", - "evmDeployedBytecodeHash": "0x8152a86ec5da5cb0766a3ad871b04ee4e67e95969d6736dfd01b144436fb4f6c" + "evmDeployedBytecodeHash": "0xde1be93bf42afbff9b680fc7321d97079ca82bc2101a10d5ff7767d0e11d48cf" }, { "contractName": "l1-contracts/EnumerableSetUpgradeable", - "zkBytecodeHash": "0x0100000706bfef0b25446c02d345113acdde8bf899d45ebd46b1efa40fce2ac8", + "zkBytecodeHash": "0x0100000777cf795baf8b43009944603bf37fdb87d2bf6555006a0ff4edd0ef23", "zkBytecodePath": "/l1-contracts/zkout/EnumerableSetUpgradeable.sol/EnumerableSetUpgradeable.json", - "evmBytecodeHash": "0xdecae3f6fd4d8f4f3961e32291c54e6ae0a0ca2146d56f8a52dc97eefb39a4e7", + "evmBytecodeHash": "0x2a02cb19d4f0d651aef8f55db0629bea602785dd21f04e99a044843a5280d608", "evmBytecodePath": "/l1-contracts/out/EnumerableSetUpgradeable.sol/EnumerableSetUpgradeable.json", - "evmDeployedBytecodeHash": "0xac0ab9b347d51da6f463f09306e3b5d763e92f5cbe1f324f51a716eb5ecaac24" - }, - { - "contractName": "l1-contracts/EraChainTypeManager", - "zkBytecodeHash": "0x0100077f7ef8d3dfb6a3a54a392816f2c6b4daa946c84697538659f908585e6c", - "zkBytecodePath": "/l1-contracts/zkout/EraChainTypeManager.sol/EraChainTypeManager.json", - "evmBytecodeHash": "0x08a4e405a9043c678321e599f9fff7759f0f5c7441a3da41f7e4c65ae2080842", - "evmBytecodePath": "/l1-contracts/out/EraChainTypeManager.sol/EraChainTypeManager.json", - "evmDeployedBytecodeHash": "0x9929b927f2ff4d4ca75c91fbe954226fbb799f711ab06ab585c975ef70ef3dec" - }, - { - "contractName": "l1-contracts/EraDualVerifier", - "zkBytecodeHash": "0x010000d3ba3b48a8e77df87ad9c489456057ca97d847b6e06356628ca17953de", - "zkBytecodePath": "/l1-contracts/zkout/EraDualVerifier.sol/EraDualVerifier.json", - "evmBytecodeHash": "0xa67cd779fba58755974b9da43eb594a0778aa56566f1460914a7bc2f1a0a09ba", - "evmBytecodePath": "/l1-contracts/out/EraDualVerifier.sol/EraDualVerifier.json", - "evmDeployedBytecodeHash": "0x901e232d2dd0895e207e1d8f476b4f3105e58094d467333b04a63825026d0504" - }, - { - "contractName": "l1-contracts/EraVerifierFflonk", - "zkBytecodeHash": "0x010009bfac2efba649c7f4e404bd48a82af72a71e8c6a1c2d6b5cf2e4807eb8c", - "zkBytecodePath": "/l1-contracts/zkout/EraVerifierFflonk.sol/EraVerifierFflonk.json", - "evmBytecodeHash": "0xf76bbc855351c8325243cb5df5ca23fb13f7b5f6b23e25ec8b6bba480cbc42f9", - "evmBytecodePath": "/l1-contracts/out/EraVerifierFflonk.sol/EraVerifierFflonk.json", - "evmDeployedBytecodeHash": "0x82944bc7851caffcd6a29d3371b573605ea3bb2202b943b6cd6bdab09da0d0f8" - }, - { - "contractName": "l1-contracts/EraVerifierPlonk", - "zkBytecodeHash": "0x01000dbb869dc557d07c73d1faff013459ce428a7bd49e6830d0d6cafb2b8f80", - "zkBytecodePath": "/l1-contracts/zkout/EraVerifierPlonk.sol/EraVerifierPlonk.json", - "evmBytecodeHash": "0xf88da6341754253c76fb78928009e785162fa920c4a13dafeae90d184ed15271", - "evmBytecodePath": "/l1-contracts/out/EraVerifierPlonk.sol/EraVerifierPlonk.json", - "evmDeployedBytecodeHash": "0xc16a744e432a6ae7ea923e6ddb076b68b3829a706f6e4e0fcc95e3153756d9ce" + "evmDeployedBytecodeHash": "0x6364b37576a3e07b585f20dd21d51444d8212aaa9898a4fa5d838294428cc1ed" }, { "contractName": "l1-contracts/ExecutorFacet", - "zkBytecodeHash": "0x0100085be34184f14be92fff1e2338269df39d18e47e21fb219b4c976c64e55d", + "zkBytecodeHash": "0x010009013ef4e1accabda79ea2d1c2e1baa1c1d6699db0873b1ff1f8bc70cf9d", "zkBytecodePath": "/l1-contracts/zkout/Executor.sol/ExecutorFacet.json", - "evmBytecodeHash": "0x16d2bf85da0fdb81bb3e1c2458057c0e0e941681374d9632110f1042a4773ba4", + "evmBytecodeHash": "0x3cb675fe1c4e139d837fbd60729804e6beef85e57fdde0b564c81bfc349cfc09", "evmBytecodePath": "/l1-contracts/out/Executor.sol/ExecutorFacet.json", - "evmDeployedBytecodeHash": "0xd6b38889ffb1e60da69b2180e644fbe34b6c33cf506625cb867004369d64946f" + "evmDeployedBytecodeHash": "0x4051d1bbd3fd6331830d00d490b9afaefe95d338cdcd36b4861c47025f8450ba" }, { "contractName": "l1-contracts/FullMerkle", - "zkBytecodeHash": "0x01000007d5c09292d49ed9013c58fa7b49588532abd92529a30609b0456a63bc", + "zkBytecodeHash": "0x01000007d6a7453e2ada9ec3b6a9054f5f2763eb99a60832de9ac6ff486e4d9d", "zkBytecodePath": "/l1-contracts/zkout/FullMerkle.sol/FullMerkle.json", - "evmBytecodeHash": "0x18d77642b6663edd75071f608bc05c069219205b34596dbc36be34c3ebe9da9e", + "evmBytecodeHash": "0x8b6e7026527532f60c113873e7e155d85deb294d343ceda5dabeb68d768fc4ab", "evmBytecodePath": "/l1-contracts/out/FullMerkle.sol/FullMerkle.json", - "evmDeployedBytecodeHash": "0xd1e33c2e9b7b070d58a7e6b92514e3ae71ab29ebc5e9b060835043d1e5b79ad3" + "evmDeployedBytecodeHash": "0xfcd0a6cb1ea6aea0e2c6f900e7a1862c33545b5fa22917f09b69393bc5f2cf77" + }, + { + "contractName": "l1-contracts/FullMerkleMemory", + "zkBytecodeHash": "0x0100000767abf2384d8dda2166f7f92dce9ecb6d702144ffcbbd1d01b0dd36ac", + "zkBytecodePath": "/l1-contracts/zkout/FullMerkleMemory.sol/FullMerkleMemory.json", + "evmBytecodeHash": "0xc72336d2acec99255cb1984b09450569ffd421164113ca6bc7fa1d69d3c305bf", + "evmBytecodePath": "/l1-contracts/out/FullMerkleMemory.sol/FullMerkleMemory.json", + "evmDeployedBytecodeHash": "0x79fb390e75b855054417c772cb66a36df852ee20fef079876f777ea7f1dfe8c9" + }, + { + "contractName": "l1-contracts/GWAssetTracker", + "zkBytecodeHash": "0x010007814b5041055291911ceb055e99c855fa495d9e1b45d758682dc7585135", + "zkBytecodePath": "/l1-contracts/zkout/GWAssetTracker.sol/GWAssetTracker.json", + "evmBytecodeHash": "0xe594d9a93e74d78103c9f933d71cf93164b6dd327c7fd3ba515f96b938a68327", + "evmBytecodePath": "/l1-contracts/out/GWAssetTracker.sol/GWAssetTracker.json", + "evmDeployedBytecodeHash": "0x8b5790ef5d9761594811b5b8ac482b7a9b985846a7cc6476d5b6471cfbe201b3" }, { "contractName": "l1-contracts/GatewayCTMDeployer", - "zkBytecodeHash": "0x01000413a7cbf98de61ae3614e60a9365f21a18b33d0b6d2dbf0ddd60b3950bc", + "zkBytecodeHash": "0x010003ef2e6d6293758f2e3c8dab878225a22ad80f2d4c9240971c9262087452", "zkBytecodePath": "/l1-contracts/zkout/GatewayCTMDeployer.sol/GatewayCTMDeployer.json", - "evmBytecodeHash": "0x0e7c13fd36787e65eac0a938aab89a37261b9c7f82662773ae5933ca3a04fa58", + "evmBytecodeHash": "0x2e7b72c734eb462074f5ef743aebfaa2c40f3727a452de75d5a444d53a311bd5", "evmBytecodePath": "/l1-contracts/out/GatewayCTMDeployer.sol/GatewayCTMDeployer.json", - "evmDeployedBytecodeHash": "0xb28987d2c0f86aab292ac283dec0330161e15b9018867587f3288530fe72f307" + "evmDeployedBytecodeHash": "0x1fcdb6ff0be48a4f5bc252e96edf803f4e0f8648e00a1baf6c8a11fd78e255ea" }, { "contractName": "l1-contracts/GatewayTransactionFilterer", - "zkBytecodeHash": "0x0100013dc475da66570ea6fc7d94d2967b88b71c1ced7be7fef055fcf90bb6bd", + "zkBytecodeHash": "0x0100013d37ddc569d3541653b9af400d9783ac09f39ca012ad8f3a160af57985", "zkBytecodePath": "/l1-contracts/zkout/GatewayTransactionFilterer.sol/GatewayTransactionFilterer.json", - "evmBytecodeHash": "0xccff2d5630cd9ffd0e9d5d6ddbfe1bb6311dadbaa3e72d17ec3dff1e9c1c8066", + "evmBytecodeHash": "0x4fee1621d05816ecb4ed4855a15e583c70c63c604d0c32ff353ea3710b3a435c", "evmBytecodePath": "/l1-contracts/out/GatewayTransactionFilterer.sol/GatewayTransactionFilterer.json", - "evmDeployedBytecodeHash": "0x627b0b4148da95e88e7712859ccaddd2186b7433da5c7ebf873219770e9a93bd" - }, - { - "contractName": "l1-contracts/GatewayUpgrade", - "zkBytecodeHash": "0x01000597153873fdd0b2b6eaed7a683d00e77cf0323553c1b8f82637da324afa", - "zkBytecodePath": "/l1-contracts/zkout/GatewayUpgrade.sol/GatewayUpgrade.json", - "evmBytecodeHash": "0xce28e06792ed56aaa7310ebd96778b3b3433c826530c363d60eab979dabaa25f", - "evmBytecodePath": "/l1-contracts/out/GatewayUpgrade.sol/GatewayUpgrade.json", - "evmDeployedBytecodeHash": "0x7040350016c976555d2d22be792cc83297220a6bd1708e188a3c3fc0fc276f46" + "evmDeployedBytecodeHash": "0xa45878bf059880a5135e75f0aea87125abe98bf931fe724802cad490af6bad47" }, { "contractName": "l1-contracts/GettersFacet", - "zkBytecodeHash": "0x010001af929a538b132867d045234b5a89b117c1a359fc001065c77fd698d52f", + "zkBytecodeHash": "0x010001af188a706c75c809cd35c1077d88a9b49de6918dc8fa39e28e87477051", "zkBytecodePath": "/l1-contracts/zkout/Getters.sol/GettersFacet.json", - "evmBytecodeHash": "0xdfbd6a4d5a92c638b4fedee01a1f0ad13dc3951d8ef951caaf95150af547ff7a", + "evmBytecodeHash": "0x3e0124c1e691151ade5ceaa2561c680fbd29b5769859985f55f1501ff05ee8ec", "evmBytecodePath": "/l1-contracts/out/Getters.sol/GettersFacet.json", - "evmDeployedBytecodeHash": "0xecb36cc7582f7d7c911d4b0998766fc3f2f9e8e8edfbd445f6b4de14cc415469" + "evmDeployedBytecodeHash": "0xdf977495037c6d2e19d19111f946d8f8ab4c437577d63efb98c2a4f0b87b4edc" }, { "contractName": "l1-contracts/Governance", - "zkBytecodeHash": "0x0100030174a939b5c6b4d85a4dfcdaf49d6ebda0f495777bcde6a21badf7d996", + "zkBytecodeHash": "0x01000301fb4b22ba1c8de7476ca16b6f944dd9c42d93087a92111bcb0a035321", "zkBytecodePath": "/l1-contracts/zkout/Governance.sol/Governance.json", - "evmBytecodeHash": "0x7f0e4cc17165d80cf1c576de54986438053c21031b594d6fc1648513db4acfd9", + "evmBytecodeHash": "0x1fe7221ae97ad5547b57f7f85b9e4459b8f1d331eeaa8318513b619d3a3b7005", "evmBytecodePath": "/l1-contracts/out/Governance.sol/Governance.json", - "evmDeployedBytecodeHash": "0xb241611831c97585d8f125702efcad4b44da53a903379758831b1f9932e30379" + "evmDeployedBytecodeHash": "0xfccdb085b48d16f0bbdc5667f622d623a98221debb2b2a8da84615fbf085477b" }, { "contractName": "l1-contracts/GovernanceUpgradeTimer", - "zkBytecodeHash": "0x010000c18aff7a36820f141404d920b26e0cf624a55f5740fa6867a31763cbb3", + "zkBytecodeHash": "0x010000c173d590a4391e9a048e3b5761f792dbe63d92e294d7bf1e55c3bc0d41", "zkBytecodePath": "/l1-contracts/zkout/GovernanceUpgradeTimer.sol/GovernanceUpgradeTimer.json", - "evmBytecodeHash": "0x210727e42dcd07a0951ea591e69e1191009d8cecc094692ed6adad7d27448b01", + "evmBytecodeHash": "0xcbc124ea522add88825efd80e8a1c7bfbb6cccc989c53b47773dfb746fc33de2", "evmBytecodePath": "/l1-contracts/out/GovernanceUpgradeTimer.sol/GovernanceUpgradeTimer.json", - "evmDeployedBytecodeHash": "0x19c2083a71e68cf4bc6f1998de310545590a655ef6ea00520b47f99acfa7c593" + "evmDeployedBytecodeHash": "0x8fffdeef7093088d77f0a22ccc1ab0c4bf7d05e6fc7bf6de8a87633dd5aa305d" + }, + { + "contractName": "l1-contracts/InteropCenter", + "zkBytecodeHash": "0x0100075db68df4a39097f7f0ebe5f7d3537839fd6d2c1c8eca77ff14d2cffc9f", + "zkBytecodePath": "/l1-contracts/zkout/InteropCenter.sol/InteropCenter.json", + "evmBytecodeHash": "0x0b3ed39626deab5498689617a2efa2dba7720db197b6e076a70f4da9fe9fa1cb", + "evmBytecodePath": "/l1-contracts/out/InteropCenter.sol/InteropCenter.json", + "evmDeployedBytecodeHash": "0x5bfb4e8b2c67562c453cd313faf618553abf68cbdb2d0dedefa1f8b432bb498c" + }, + { + "contractName": "l1-contracts/InteropDataEncoding", + "zkBytecodeHash": "0x01000007d0488b9cf3047300e50054ad00c26bb0709402082072bf2ca68b9381", + "zkBytecodePath": "/l1-contracts/zkout/InteropDataEncoding.sol/InteropDataEncoding.json", + "evmBytecodeHash": "0x5ada9bf05245e11b3c8a201911285431e57fc544c6b855111375ad2058fb802d", + "evmBytecodePath": "/l1-contracts/out/InteropDataEncoding.sol/InteropDataEncoding.json", + "evmDeployedBytecodeHash": "0xa50059f465944090791c3682ab7191cd1c3068fecc98cabbf9ef84b70c421255" + }, + { + "contractName": "l1-contracts/InteropHandler", + "zkBytecodeHash": "0x01000581e6011dd406abfdcc2e45888ed9b52b3a3643aabe19b8ca558e562924", + "zkBytecodePath": "/l1-contracts/zkout/InteropHandler.sol/InteropHandler.json", + "evmBytecodeHash": "0xb92d880901cff40f9be8d52767ca803db053d2239397dc9d52ff153ffb120439", + "evmBytecodePath": "/l1-contracts/out/InteropHandler.sol/InteropHandler.json", + "evmDeployedBytecodeHash": "0x4c154b71f1ec62c55d991e686ed27121af3e8d27a4b4d075d613ee6b09fa891e" }, { "contractName": "l1-contracts/L1AssetRouter", - "zkBytecodeHash": "0x010008338791472518ab61101413c677d93370a974a3aa544baa419c36197116", + "zkBytecodeHash": "0x010008557afafeb68cc5e33afa77e8e84dff9598ef225a5a0c570cb4e5ec55c5", "zkBytecodePath": "/l1-contracts/zkout/L1AssetRouter.sol/L1AssetRouter.json", - "evmBytecodeHash": "0x22a45c20dff99e194fd92aa3bb486d050ac18388c6184f6c71959f0564cc3d95", + "evmBytecodeHash": "0x515f5e1cc22b09c3ecaebf2123d5f18099a4f9529c919f454089800b9672caf8", "evmBytecodePath": "/l1-contracts/out/L1AssetRouter.sol/L1AssetRouter.json", - "evmDeployedBytecodeHash": "0x6e86f59d3ec952e1cd31aca543c0c0450a4f675f48eb995ad54992f09e4a180c" + "evmDeployedBytecodeHash": "0xd05465dfffa96a424a522c471613ed0c985d355f27c8410d442bfb10fe925255" + }, + { + "contractName": "l1-contracts/L1AssetTracker", + "zkBytecodeHash": "0x010004e1f5697faa66c19ea86634886594a6e0eb75e0aedfe175458078c75f91", + "zkBytecodePath": "/l1-contracts/zkout/L1AssetTracker.sol/L1AssetTracker.json", + "evmBytecodeHash": "0xa44860edac9defc9dd9af93ae26bc5f6b6396b9f160f787113ec75fd386f9ced", + "evmBytecodePath": "/l1-contracts/out/L1AssetTracker.sol/L1AssetTracker.json", + "evmDeployedBytecodeHash": "0xe8f437d3acece182829808907cf3dce9d42a559ced08aeb2b5fd71ea724af779" }, { "contractName": "l1-contracts/L1Bridgehub", - "zkBytecodeHash": "0x0100075d85c22e65aff97521cf0227a5916aa4ac770276324c5a1b13b288b4fc", + "zkBytecodeHash": "0x01000741cfe642b201bb03db67af0cec79913f696073d8d3123197cd1b2c9024", "zkBytecodePath": "/l1-contracts/zkout/L1Bridgehub.sol/L1Bridgehub.json", - "evmBytecodeHash": "0x3a72de2bbc13860fcf9af3b1657ef7f7bd716bdcf332481fe93a484bb8800b2e", + "evmBytecodeHash": "0x4b6f61284094e92396c3098b622bd05f20f209a8e99914dcebc18985d4c4c11b", "evmBytecodePath": "/l1-contracts/out/L1Bridgehub.sol/L1Bridgehub.json", - "evmDeployedBytecodeHash": "0x3f0151b371f9028afc9f8c8343d3eefbfd303590fb93052386ce6d5431aaaa31" + "evmDeployedBytecodeHash": "0xc442785a7d3b89afd3e1e01a0e5d023188b927cd895df15c767f8d33708ef310" }, { "contractName": "l1-contracts/L1ChainAssetHandler", - "zkBytecodeHash": "0x010003e1ff9a0d453cd0328f708c0b423475b242f36ddc57a15b93a279e778fc", + "zkBytecodeHash": "0x010004f142ae6911496dc72330e48f5c9535320fd61fc0d854be75146d38d108", "zkBytecodePath": "/l1-contracts/zkout/L1ChainAssetHandler.sol/L1ChainAssetHandler.json", - "evmBytecodeHash": "0x507f8e19bbaa6096452c5eb61b56bf9dfac110674dc8d4c7efb7557ff27090f9", + "evmBytecodeHash": "0x09b10756863e85e2f3f9fd04655a9490f48e13b2e2691c48cc0a26c1a5abe0fe", "evmBytecodePath": "/l1-contracts/out/L1ChainAssetHandler.sol/L1ChainAssetHandler.json", - "evmDeployedBytecodeHash": "0xfc9ff739d66452d9afbedd70fb7ab20311a2628ea2938259b4cbec411f1a7d6b" + "evmDeployedBytecodeHash": "0xe7b3e004cca36aceed48393505f437d9439ed6a879065ec52028ad458c7cdbf4" }, { "contractName": "l1-contracts/L1ERC20Bridge", - "zkBytecodeHash": "0x010002e9082593edd11cc4bc60d47af13b38f9bf078dd15223ceabd424fb0189", + "zkBytecodeHash": "0x010002e9f60bf0993adaae2d0f50255bab4d9b487ceb79c3b51d23135daf214a", "zkBytecodePath": "/l1-contracts/zkout/L1ERC20Bridge.sol/L1ERC20Bridge.json", - "evmBytecodeHash": "0x23e0313fb72c121a024f10c2a8b109f96ecfafdf22e5b26b9684ddc2d5b01744", + "evmBytecodeHash": "0xabce43240b648bc35645d08f4368439f96cd4394b8402082a69f3d2debc851c6", "evmBytecodePath": "/l1-contracts/out/L1ERC20Bridge.sol/L1ERC20Bridge.json", - "evmDeployedBytecodeHash": "0x67cf95ec3d9068eb88a9abea97fff8370a20dc0e9e54dc0ee1d618e447e37742" + "evmDeployedBytecodeHash": "0x3f3cf6d6d19d5c5d439eb817d197857d255b9c3a7c3d16955ad852a2961da439" }, { "contractName": "l1-contracts/L1GenesisUpgrade", - "zkBytecodeHash": "0x01000695341938aa049b9659139de86413d3b324a8bc0c8020e9db446141e4ae", + "zkBytecodeHash": "0x0100067797fd977e6d4e735bb4cc93b35507ea41479285620f556a5559596b27", "zkBytecodePath": "/l1-contracts/zkout/L1GenesisUpgrade.sol/L1GenesisUpgrade.json", - "evmBytecodeHash": "0x0c3c4ec61810780ac71ec28f33a82845153bc0a1f144778f77804508db897714", + "evmBytecodeHash": "0x906f6d7fa34fdb2f865164c9d22d8db1fe5d9d38c540b4b52428f5cd87a1d337", "evmBytecodePath": "/l1-contracts/out/L1GenesisUpgrade.sol/L1GenesisUpgrade.json", - "evmDeployedBytecodeHash": "0x2ca6ca6c147350a33cbc9e0d8644ea7ceb6103ed2f1bf253edd2922885674ac7" + "evmDeployedBytecodeHash": "0x8c99f766d180ffd3b0130348fee0dd431de68309467cb5f6cfb02589e1e263b7" }, { "contractName": "l1-contracts/L1MessageRoot", - "zkBytecodeHash": "0x010002e54c919502e2df5f2d17b6a9f33d272e9763641ffe4cf1f30d6ab9a2d6", + "zkBytecodeHash": "0x010009532cdc73121262f301ea14a66d127ee61358d5a4a742b209c6c4dc94a3", "zkBytecodePath": "/l1-contracts/zkout/L1MessageRoot.sol/L1MessageRoot.json", - "evmBytecodeHash": "0x266c50a7afc17bb271d02686626473db141a125c56457d9e417d31379dbe9410", + "evmBytecodeHash": "0x6a2291d4c8041e72a440d816a2ffb65f5ecb073b96d8ff1f4dc4c8d683219597", "evmBytecodePath": "/l1-contracts/out/L1MessageRoot.sol/L1MessageRoot.json", - "evmDeployedBytecodeHash": "0x759d8789ff685aeaf77aa721337f6a90b0b9bc368a2ea37cb820303883eb8519" + "evmDeployedBytecodeHash": "0xc6a2119255daba07e296f1ba3aabe71ee9794e06082c2168fa7abfe0d1a77807" }, { "contractName": "l1-contracts/L1NativeTokenVault", - "zkBytecodeHash": "0x0100097d8342ac496839beee1882ff5579ac5218136b16f81192fe656bac1b1c", + "zkBytecodeHash": "0x01000a1d10663e4fca1f00792e1db3ee1056a482b9a5676fd4b835d088d09053", "zkBytecodePath": "/l1-contracts/zkout/L1NativeTokenVault.sol/L1NativeTokenVault.json", - "evmBytecodeHash": "0x91385b562ee39cc02d89048dd0da66679d9b5241878ca71cf23195b9b48d24f0", + "evmBytecodeHash": "0x61ef7bca7c14b50a2e810fb18b4195e01615ffa0aac63c9b44e8ccbf7e6f26d8", "evmBytecodePath": "/l1-contracts/out/L1NativeTokenVault.sol/L1NativeTokenVault.json", - "evmDeployedBytecodeHash": "0x8e1c973d52e3baeee44635500efe9644112be1e49165318f52680f60543e2140" + "evmDeployedBytecodeHash": "0x6552a3a506434869cb2638e7a878617ab899b8aeeaf27e233d8e146c12a084f7" }, { "contractName": "l1-contracts/L1Nullifier", - "zkBytecodeHash": "0x01000659fc7796fcac236611131d4900d44549976e37e1ea43efd22395dfa172", + "zkBytecodeHash": "0x0100076d5d1248f5c58d736f934b7413e2531b985236de5687e04447adb2890a", "zkBytecodePath": "/l1-contracts/zkout/L1Nullifier.sol/L1Nullifier.json", - "evmBytecodeHash": "0x4ed24d33db23104f0864f3dddbb98c17e2fbf72892c194597ebe97a1934bcb18", + "evmBytecodeHash": "0x9909a58a115524f6e5137a3572e7e185528c47edfef105cccbdb93ae8c4f1810", "evmBytecodePath": "/l1-contracts/out/L1Nullifier.sol/L1Nullifier.json", - "evmDeployedBytecodeHash": "0xd64ca627b60499d11123e3c5235960ace6db4989f88f68697857e561e0ddcf87" + "evmDeployedBytecodeHash": "0xa61f869ef65efeb519b08e8595d0fb2f9c74c3682b530a4aa1426005eeec2812" }, { "contractName": "l1-contracts/L1V29Upgrade", - "zkBytecodeHash": "0x0100032bfe9b2453eec5ec194872220439fae6cff4c5de4e4d3a9e04933387e0", + "zkBytecodeHash": "0x010002c5ccd3e7e5be731a55c1ef44acaa53548a563de7c1b3838ac0ab06fc22", "zkBytecodePath": "/l1-contracts/zkout/L1V29Upgrade.sol/L1V29Upgrade.json", - "evmBytecodeHash": "0xebf7f2dfd98dde39242f4853445583e29d55322cea2fb99126de2c19c4001e9a", + "evmBytecodeHash": "0x1d4caa8bc3708d53184cf3c9c7d29325d57cd03425317ef1aacb667625b01e49", "evmBytecodePath": "/l1-contracts/out/L1V29Upgrade.sol/L1V29Upgrade.json", - "evmDeployedBytecodeHash": "0x67201fc17aa5e0a05be66451217223aaa97218fa13b40a65d6514cad4b2cb86c" + "evmDeployedBytecodeHash": "0xfb56a5f4fdb8ade46202c1ef65348099d2936aaa741864451ed909f8c4fb942d" }, { "contractName": "l1-contracts/L2AdminFactory", - "zkBytecodeHash": "0x010000bb278d393eba8a8230880b7ff9b2aab1228e87a5af256bfa89b6f1c0b6", + "zkBytecodeHash": "0x010000bbdf9a2361ca1c68933d589710ec6a6d38a4d10d9e3f88670bd70b29e3", "zkBytecodePath": "/l1-contracts/zkout/L2AdminFactory.sol/L2AdminFactory.json", - "evmBytecodeHash": "0xa6742902b9f759e700f6141a86328fc6493a40a9b705bf3de7868236c04b7daa", + "evmBytecodeHash": "0x38c2946dcd394120fd14ea202885ce6717ccecea65856a451c88719c5efe8ac2", "evmBytecodePath": "/l1-contracts/out/L2AdminFactory.sol/L2AdminFactory.json", - "evmDeployedBytecodeHash": "0x367c9b3ac85f480d0ad0c0d13bf56b7f73a7f955568d58e149af87b957886236" + "evmDeployedBytecodeHash": "0x83e60761107b12d95266b7dc015878d11c2825167b21f64f6d2c7aea1523fd5b" }, { "contractName": "l1-contracts/L2AssetRouter", - "zkBytecodeHash": "0x010004c947944854a746124d126c7f0b3ea193e9805ffa4b8a06b5ebcb0414d7", + "zkBytecodeHash": "0x010007132c8432ecd70801d3e8515850d574b20f44a75a0c5977c00658780494", "zkBytecodePath": "/l1-contracts/zkout/L2AssetRouter.sol/L2AssetRouter.json", - "evmBytecodeHash": "0x312a92512764cdd0efa4309f934e29034df4288e1e5f8c8811b23a7f1e552508", + "evmBytecodeHash": "0x6fb68dc7cc56797e650ee89f4ddf8381a3b72f222adb46fc82f16ab0e77e1594", "evmBytecodePath": "/l1-contracts/out/L2AssetRouter.sol/L2AssetRouter.json", - "evmDeployedBytecodeHash": "0xb0d86364bd93bcc94e11bfdc2851326911760a8d7d53fef3061ca16daef90f9d" + "evmDeployedBytecodeHash": "0xd87d8e160ec25f92b2311b00b6bec3a04a933cc3ea191d065880c7dc14bde7cd" + }, + { + "contractName": "l1-contracts/L2AssetTracker", + "zkBytecodeHash": "0x010003555f9a911dfc86068d0758a25646adc41dda1dfc82b9aaa2c671808a15", + "zkBytecodePath": "/l1-contracts/zkout/L2AssetTracker.sol/L2AssetTracker.json", + "evmBytecodeHash": "0xbdacba83da04fbc84c9a60a1f7f968fcb71ae6da47792e2e62449b871c304196", + "evmBytecodePath": "/l1-contracts/out/L2AssetTracker.sol/L2AssetTracker.json", + "evmDeployedBytecodeHash": "0x65907cd21b842a6e4a28aa5a2a1c3286769a27a3dc86d8b2bf234ac6d44c0467" }, { "contractName": "l1-contracts/L2Bridgehub", - "zkBytecodeHash": "0x010003c5fb74fa7e1b6c36686dc6100e2740c5a11320bc66d91066c646d6d075", + "zkBytecodeHash": "0x010003b15e1a7d31ef2d0472f587df88ff0454954588d6f21337875fcb4eb233", "zkBytecodePath": "/l1-contracts/zkout/L2Bridgehub.sol/L2Bridgehub.json", - "evmBytecodeHash": "0x439529699ba6639596c38fecbbc95b74773183017c91c05a55f84923bc329e3b", + "evmBytecodeHash": "0x63a9773b5559f2141a5b1336f66968a35528471e5d953617722b84ad5a1b28b9", "evmBytecodePath": "/l1-contracts/out/L2Bridgehub.sol/L2Bridgehub.json", - "evmDeployedBytecodeHash": "0x3c065860af31d429939084d0200359ec994600ca7bd1eb4f924406c0b5a49af9" + "evmDeployedBytecodeHash": "0x44aaf0e89be461a82dfaeee343c8417f14eeb98f4c01f80be907209db6ce49c0" }, { "contractName": "l1-contracts/L2ChainAssetHandler", - "zkBytecodeHash": "0x0100031f0aa6b3e3af5d2c2310d7332b789889c695cbab9ffc46aa178aaed346", + "zkBytecodeHash": "0x01000491d0f70cba606a1e5e83cc28724d6c7e98a4f56dc04cc7de75fe40bd8f", "zkBytecodePath": "/l1-contracts/zkout/L2ChainAssetHandler.sol/L2ChainAssetHandler.json", - "evmBytecodeHash": "0x54ed0ac8712265e1896692c9796cac13bb7760a0411f6956991f17ac0bad6698", + "evmBytecodeHash": "0x29cc1910775324914924b0d849b1ee2eb73306dbc4843b50c440a9381e2cb0f8", "evmBytecodePath": "/l1-contracts/out/L2ChainAssetHandler.sol/L2ChainAssetHandler.json", - "evmDeployedBytecodeHash": "0xf20f218e1046e4970af4769276065dc102af5780023a1351e2aa14e56895df46" + "evmDeployedBytecodeHash": "0xdf7566fd80ff4f04a108980bc8c390449ad7d65e2199ca707ac16bdf145b2ce3" }, { "contractName": "l1-contracts/L2ComplexUpgrader", - "zkBytecodeHash": "0x01000133f841701cfba2e0bedbd1bcc409f0554f357a1563710f40c6497bfeba", + "zkBytecodeHash": "0x01000133f665fa51652f6fd19e901cec6a535cc70c519f444fb1e0ac4459fa26", "zkBytecodePath": "/l1-contracts/zkout/L2ComplexUpgrader.sol/L2ComplexUpgrader.json", - "evmBytecodeHash": "0x3ec55487405b4eb9b681c3b1334ff32c88676ed99a21f77ca69a595938d2bd2f", + "evmBytecodeHash": "0x88abfba99331bf0d7cbfa8c338cd0b302aaf53335cd9e5cb37eeebffe11dc46b", "evmBytecodePath": "/l1-contracts/out/L2ComplexUpgrader.sol/L2ComplexUpgrader.json", - "evmDeployedBytecodeHash": "0xc06df30e8a25132cfafddcfecc998a3cb50066756ed23182e08e7b83a689c858" + "evmDeployedBytecodeHash": "0xf740c8de9c7b4d0238978da2658faadb73255cb6cb45c76d7309a60247951f9b" }, { "contractName": "l1-contracts/L2ContractHelper", - "zkBytecodeHash": "0x0100000741fa45858f3bc8c8d422240568f3731df8e7ad18de0ef0f48aca4462", + "zkBytecodeHash": "0x0100000702a07083ebf4bf8da1e28f56e94bc2ec6a91d9d15d24f3f80312fbce", "zkBytecodePath": "/l1-contracts/zkout/L2ContractHelper.sol/L2ContractHelper.json", - "evmBytecodeHash": "0xe405d2f7b05d4b8c29754841711caa65263ce9f81e87eeb06d509d4956a37db1", + "evmBytecodeHash": "0x685295a3db1a6135cf0cd97e9e56db902f9488312237fddd1c49694fb6f58cf3", "evmBytecodePath": "/l1-contracts/out/L2ContractHelper.sol/L2ContractHelper.json", - "evmDeployedBytecodeHash": "0x35c50317093fc2feffd5772c5112424a479811891748776255d28b5ee43eb67f" + "evmDeployedBytecodeHash": "0x37b277d5c17dded1f8b4e597679a93e57a9ce6915c9f0b6a16a93824edea06b1" }, { "contractName": "l1-contracts/L2GenesisForceDeploymentsHelper", - "zkBytecodeHash": "0x01000007a3721430ee99380128b72580d8fa9305d221391590f13aa3eca729af", + "zkBytecodeHash": "0x010000074f69a6aeaaddf24c4aca107700840501667cd11fb43ce4a0cd785359", "zkBytecodePath": "/l1-contracts/zkout/L2GenesisForceDeploymentsHelper.sol/L2GenesisForceDeploymentsHelper.json", - "evmBytecodeHash": "0xc01e17f55c55ff5ff136a43b1454a67bf3f454deb2400d3044a391ae65255ad4", + "evmBytecodeHash": "0xd828edcdfde7b85bebe1ac8ea3a1878890bd50cf5a2f993a149683746dfc7928", "evmBytecodePath": "/l1-contracts/out/L2GenesisForceDeploymentsHelper.sol/L2GenesisForceDeploymentsHelper.json", - "evmDeployedBytecodeHash": "0x47eaaa8c6d51dfb9b1ae6609fb1203e358370dbe21c004ccde950820ddd85cd6" + "evmDeployedBytecodeHash": "0x8613ed0c29f2f59cdedb586854d1583f4e661689e8bd59393a8a0f93304ea72a" }, { "contractName": "l1-contracts/L2GenesisUpgrade", - "zkBytecodeHash": "0x0100029f60b721fe130a6030842b49a695cc1df406898b0344f4fa0faf3da77e", + "zkBytecodeHash": "0x0100032336fc968363afd3a736d13b05decfc1a03f326d4adf966e5e72bab5ff", "zkBytecodePath": "/l1-contracts/zkout/L2GenesisUpgrade.sol/L2GenesisUpgrade.json", - "evmBytecodeHash": "0x8d94bad92acf9fcd9a2396616fdd1938f7ce994f7747b1ee2405cded7dc66060", + "evmBytecodeHash": "0xaeceb6b0c611a70be2584a886546d30538e1f1bf3a9a88cf13b6ee5ae15add89", "evmBytecodePath": "/l1-contracts/out/L2GenesisUpgrade.sol/L2GenesisUpgrade.json", - "evmDeployedBytecodeHash": "0x5657aed7923ab5e62059b061e027402cdca5ea1e965a403bf152e48e9939fa6b" + "evmDeployedBytecodeHash": "0xf2dd9dd58ba99be0246abba4bb4e176bfd3fa7b26eadaf0b7d34b8464b638d79" }, { "contractName": "l1-contracts/L2MessageRoot", - "zkBytecodeHash": "0x010002dfb1683c67eb841ca01d69f12d8c0c9c3e5b49a7b0004347c1e3d22cca", + "zkBytecodeHash": "0x0100082fc52684420fbc085bdc282962ec26043864cf55e2b5e9539934589fc4", "zkBytecodePath": "/l1-contracts/zkout/L2MessageRoot.sol/L2MessageRoot.json", - "evmBytecodeHash": "0x34d47b2cfd967c7485f7b7dad0ebd5c129570bfd7d233c0b31d51d6366ed38be", + "evmBytecodeHash": "0x93b1efc31d80b17d2e9323c439649eaf01990efcaf7d05e47f3bd7eaf1a3e8de", "evmBytecodePath": "/l1-contracts/out/L2MessageRoot.sol/L2MessageRoot.json", - "evmDeployedBytecodeHash": "0x475a9918952b93733042c978d93976b65a5d2a71259699edbb6a0eb414d802f2" + "evmDeployedBytecodeHash": "0x4778c811ee88eec8127eed652b13066ebc4881d34fdb3824599f67c62baf1934" }, { "contractName": "l1-contracts/L2MessageVerification", - "zkBytecodeHash": "0x01000159900ad1847e5ce7b37485070e518ccb9830be0ecc01308eeb756bd059", + "zkBytecodeHash": "0x0100027f9917553fc8cdd39906000223a3301799d48d4a1c5c06ddfa1628a50c", "zkBytecodePath": "/l1-contracts/zkout/L2MessageVerification.sol/L2MessageVerification.json", - "evmBytecodeHash": "0x9d5ea3d4d4c81b8e5cdeda5c117ac34c68360fdfed2b5d28d23cf686b039212c", + "evmBytecodeHash": "0x9ec948aaa71d70d58f4effd0ec19729eeb6d6a6ee4c434a6f7e402d68d6dc0a8", "evmBytecodePath": "/l1-contracts/out/L2MessageVerification.sol/L2MessageVerification.json", - "evmDeployedBytecodeHash": "0x68e08726b3e8e5d6480e11b6716fadada34a84d4ca2db8aa7fc3cd1e2ba64ced" + "evmDeployedBytecodeHash": "0x670dee0d76018a27652ccc2d5cba2d3bdaf01ef4516eace4e11faea889841e07" }, { "contractName": "l1-contracts/L2NativeTokenVault", - "zkBytecodeHash": "0x0100078d07e1fb2e785c813bd3de9a31f2f738fdee610efe57a4dc50351e9509", + "zkBytecodeHash": "0x01000897939c3655556fa40698abbbca81183581806e70a83ee0fa2b8bc1d1e1", "zkBytecodePath": "/l1-contracts/zkout/L2NativeTokenVault.sol/L2NativeTokenVault.json", - "evmBytecodeHash": "0xbfe79c20b2791440adccc52aa3c84176fdc9ed4fa628318e3738f4b08974874c", + "evmBytecodeHash": "0x93692599ffc3a79e47557f294017221100c9cd9d62fea5a31184243b147e3985", "evmBytecodePath": "/l1-contracts/out/L2NativeTokenVault.sol/L2NativeTokenVault.json", - "evmDeployedBytecodeHash": "0xdc98fecdabe5f2bfc46055e4bc8849a4940812495467f61134c1e04d404d95ca" + "evmDeployedBytecodeHash": "0x64d7b1a51405b2439af650c6f094e54b7cf82360680c55cc8f2cd35bcf39354b" }, { "contractName": "l1-contracts/L2NativeTokenVaultZKOS", - "zkBytecodeHash": "0x010005c7e19a70fd9d95cdb532d96e36cabaa1b8cb53468bc5e3d5aef4cedf94", + "zkBytecodeHash": "0x01000733e80fcc1941eef15e3e94c9f45cfb572fa9cf6ffe1249a43cc378d3b3", "zkBytecodePath": "/l1-contracts/zkout/L2NativeTokenVaultZKOS.sol/L2NativeTokenVaultZKOS.json", - "evmBytecodeHash": "0x01ae3cbf1132bab1b7e8407b6c4ec5894c1bc5b765aad80cc090444bd2784170", + "evmBytecodeHash": "0x60abe2e78cf22dc070e3a13fa0e12243d7fd6d37cc1dc3ec6b0e71ce3746bb0e", "evmBytecodePath": "/l1-contracts/out/L2NativeTokenVaultZKOS.sol/L2NativeTokenVaultZKOS.json", - "evmDeployedBytecodeHash": "0xedcd7627effc11c9258a1202a50dfe7e66410022fb4f493fcc5e9a80b8324edd" + "evmDeployedBytecodeHash": "0xfc2a4db4318ee15e86e2aa4d67a23f77b3ba1d90b2d5c27b684aa024515bd7ec" }, { "contractName": "l1-contracts/L2ProxyAdminDeployer", - "zkBytecodeHash": "0x0100005fcb83d64a2c142996104330e7ce72ae4c2828fa8305d2524cd457e9a5", + "zkBytecodeHash": "0x0100005f3136b6c0d9d1725d4ee5e2b8f1da1f3fa1c640728780e8a580050b18", "zkBytecodePath": "/l1-contracts/zkout/L2ProxyAdminDeployer.sol/L2ProxyAdminDeployer.json", - "evmBytecodeHash": "0x3d7ac817bf44b7213b2f6672d1eec308f7534b9ee707839b297a34c637a818ee", + "evmBytecodeHash": "0xa1df7e4af97c51d969d063259239b7cf5e873d4761e09e9ec8df4d7ffa063821", "evmBytecodePath": "/l1-contracts/out/L2ProxyAdminDeployer.sol/L2ProxyAdminDeployer.json", - "evmDeployedBytecodeHash": "0x017e0a802b14c0f5070490f38b3a6dae7311de0350d9469b0251ae89a3cd9145" + "evmDeployedBytecodeHash": "0x07a3d51aa4a51c716fc437e8cc72cd5cb7029eb7cf3247c796aeed158d29c036" }, { "contractName": "l1-contracts/L2SharedBridgeLegacy", - "zkBytecodeHash": "0x01000195a5217e8b786cba93ee0220fc81a2dd484dd4258dcb9b67de18555094", + "zkBytecodeHash": "0x0100019522a7a58af79b9298a375a615e3fbe7fa554690d862518f9031260253", "zkBytecodePath": "/l1-contracts/zkout/L2SharedBridgeLegacy.sol/L2SharedBridgeLegacy.json", - "evmBytecodeHash": "0x512686f9f54ae579198da609cf875ac91950022c1f42fa711da05840e14e612d", + "evmBytecodeHash": "0x349cf77a56731a63485632165662e7d8477c0a3c30fe72131afb656257c209a0", "evmBytecodePath": "/l1-contracts/out/L2SharedBridgeLegacy.sol/L2SharedBridgeLegacy.json", - "evmDeployedBytecodeHash": "0xdf3377b1d38d0e3321c850fb200714026e69e4787be946c69ed19fe9ec587df0" + "evmDeployedBytecodeHash": "0x5b59173a82c1bfdcdbe4bb7fbeb35d50e0dd8e9512d7fca06ec0af234805bbe0" + }, + { + "contractName": "l1-contracts/L2V30Upgrade", + "zkBytecodeHash": "0x0100000f2db850bb37c0db4559137e1c85d4bdc8bef45b803d337bb14b37a494", + "zkBytecodePath": "/l1-contracts/zkout/L2V30Upgrade.sol/L2V30Upgrade.json", + "evmBytecodeHash": "0x0b0462097203378442f9c68a674813176626a8d191a333a239f508fd9f724fab", + "evmBytecodePath": "/l1-contracts/out/L2V30Upgrade.sol/L2V30Upgrade.json", + "evmDeployedBytecodeHash": "0xd4ed81c3a1da41d92a51bf0b3bad853b754a0669685d49547980d4dabf59ad60" }, { "contractName": "l1-contracts/L2WrappedBaseToken", - "zkBytecodeHash": "0x01000341058683817eed8e52088c177933361a7823a191dbf134b4a56ec831ea", + "zkBytecodeHash": "0x010003411be9019dca76bd893e39bc238fec773c93066cbfa5f3a36a0db26dfe", "zkBytecodePath": "/l1-contracts/zkout/L2WrappedBaseToken.sol/L2WrappedBaseToken.json", - "evmBytecodeHash": "0x9ea69d5ed3b848e4425fe4d5e41bf9ace7e656ac440fe83c543ef55eeafe9c30", + "evmBytecodeHash": "0x25c561171eb847298b45106c84c280084e4683e751b558b12a19bbd16af04ea9", "evmBytecodePath": "/l1-contracts/out/L2WrappedBaseToken.sol/L2WrappedBaseToken.json", - "evmDeployedBytecodeHash": "0x4ef6234c95f9648686c265effb9332591ed9272e9938f9a926f8882964ac0a01" + "evmDeployedBytecodeHash": "0x98e47b48ae149d2933fbdb3f62adda4302d372da8e0ebe2b458e7f8b0fdc2793" }, { "contractName": "l1-contracts/L2WrappedBaseTokenStore", - "zkBytecodeHash": "0x010000a976c1b6e9080d26bc72548097b1b2e1c57c772154d311112bcc2612ae", + "zkBytecodeHash": "0x010000a9317dcd1357de94de71006717dd4bdc5e7ed1146513b2f9fd4375b22a", "zkBytecodePath": "/l1-contracts/zkout/L2WrappedBaseTokenStore.sol/L2WrappedBaseTokenStore.json", - "evmBytecodeHash": "0x305957521f682c50d8b9cdf52ae62842ac1faf80e6f37b6fab0f27d30c1be9a9", + "evmBytecodeHash": "0x9c002ec173912c8c6e32b3ed928d4c4550a961686a0c3c954cd96b54b8fe7773", "evmBytecodePath": "/l1-contracts/out/L2WrappedBaseTokenStore.sol/L2WrappedBaseTokenStore.json", - "evmDeployedBytecodeHash": "0x7c6d09ba61506f4096717a4f0760e58078bedd25dfb70c76cef62c39b9fdd2c8" + "evmDeployedBytecodeHash": "0x56c301ea8caee08bb6b911ae77287b706d22c037623167ea6f2fe25f07ffbf6d" + }, + { + "contractName": "l1-contracts/LegacySharedBridgeAddresses", + "zkBytecodeHash": "0x01000007e1f0e22bb590aa736d1deb65cdf470375a3b883fda541993a0a4d047", + "zkBytecodePath": "/l1-contracts/zkout/LegacySharedBridgeAddresses.sol/LegacySharedBridgeAddresses.json", + "evmBytecodeHash": "0x8fff88346b53ab7f2564a9611903f3499545884e861f844a21d4323292ff95c7", + "evmBytecodePath": "/l1-contracts/out/LegacySharedBridgeAddresses.sol/LegacySharedBridgeAddresses.json", + "evmDeployedBytecodeHash": "0xc51c89394ca5efbc8c4f7cfbe5cb05cb10ff3ed1da8eaa633387b4ed8f1635e4" }, { "contractName": "l1-contracts/LibMap", - "zkBytecodeHash": "0x01000007c9d4634530675b17346b57327af5c6f4ee376f121d51ab7b0a2a2111", + "zkBytecodeHash": "0x01000007d7b1625ffa33b79a47b533208f2cbb2ff42be7eba67ce762d4b5b8fc", "zkBytecodePath": "/l1-contracts/zkout/LibMap.sol/LibMap.json", - "evmBytecodeHash": "0xd675a82c93214994e704e9ca6cb42be1ef15e05f08b62105b94591c1451c16f9", + "evmBytecodeHash": "0xba10b56a4c322eb53212cbf8eb4fcd7215b1fb4e1bd46ad9060e83eb37feb518", "evmBytecodePath": "/l1-contracts/out/LibMap.sol/LibMap.json", - "evmDeployedBytecodeHash": "0x5e2fe29366bb5dddde2f3fc4252b29aefc397a93b54fa2e5f4d70da6819c3976" + "evmDeployedBytecodeHash": "0xffd2f5ea48a31f3e8ea9a36a72f56e131f554ac94fba5a61b14bf3f4310196c2" }, { "contractName": "l1-contracts/MailboxFacet", - "zkBytecodeHash": "0x010006c575edcfff7086d4ce08c83ce0e3e55df1b68b42682846de6c21ac9380", + "zkBytecodeHash": "0x01000909b08c56dd7f369bb7be1ca89f8bbedea3cfc944e7272806acbaf349dc", "zkBytecodePath": "/l1-contracts/zkout/Mailbox.sol/MailboxFacet.json", - "evmBytecodeHash": "0xc15cb350b40bbd6b28ec7bc388fe48cbed656e28d479d25d39c813c411e813c8", + "evmBytecodeHash": "0xeb000ca18e1650b8656c0e0d7d3b9e4ac9a7b83741c30357f88c5572867bdf35", "evmBytecodePath": "/l1-contracts/out/Mailbox.sol/MailboxFacet.json", - "evmDeployedBytecodeHash": "0x96f8296082c2b379d905de984328486006f84962ed2182fed12273776504269f" + "evmDeployedBytecodeHash": "0xf69d38e8cbd8ca59fd52664a6db1a70f3c64821f45ec7c45d8207441987d0b3c" }, { "contractName": "l1-contracts/Math", - "zkBytecodeHash": "0x0100000784fa40c1f5aa5ee8bd526141395649512aad43de97ea24e2129e4aa6", + "zkBytecodeHash": "0x01000007a85ed03b0a607ed99f27394ec352d404c66dd4c43fcb1febbc816830", "zkBytecodePath": "/l1-contracts/zkout/Math.sol/Math.json", - "evmBytecodeHash": "0x74db5ccbf8ab82b2f16550c7a2d56dde7247fb48e365b9f204dee84937845f6d", + "evmBytecodeHash": "0xdddf1ed27b9118815e91e25fa9500a9a7da2c48876712d85c74a400b15c5cbe2", "evmBytecodePath": "/l1-contracts/out/Math.sol/Math.json", - "evmDeployedBytecodeHash": "0xe48c4cb85f6238d73d834a908c6aa1313060cb7b5950d290a814fdfdcb6368e5" + "evmDeployedBytecodeHash": "0x6a38684cab81c07093ec189d28ed52ec1e01641d24ed0763c267cfbfb2d3ccba" }, { "contractName": "l1-contracts/MathUpgradeable", - "zkBytecodeHash": "0x01000007d5aec9b0ffc3be29e7464aa6833f48bbb44d6485e811e281d6949713", + "zkBytecodeHash": "0x0100000740ddf99118e43461f58c9e3ac09d7b140e297c1d99645643b7248440", "zkBytecodePath": "/l1-contracts/zkout/MathUpgradeable.sol/MathUpgradeable.json", - "evmBytecodeHash": "0xf3bf3a6d5324771cba823f95550c6a9eca4ac5d91f3ca7a8797ca4d6f86709cb", + "evmBytecodeHash": "0x1cb97267b3ad4cd287eb82440c3615385e7545533ecaa5888214da05e511618a", "evmBytecodePath": "/l1-contracts/out/MathUpgradeable.sol/MathUpgradeable.json", - "evmDeployedBytecodeHash": "0x20f7236bd2051084ff472a2dab7230610a1689a79aca2f9108632fe557b6cb35" + "evmDeployedBytecodeHash": "0x51661cee73521f114d353f95ec578ebd33bda1bf489870f7468f05a0243cb78a" }, { "contractName": "l1-contracts/Merkle", - "zkBytecodeHash": "0x01000007a14b370d7e8afd5efc517e14f6c77ec3723fcfb7c5aa51308f1e8a13", + "zkBytecodeHash": "0x01000007f068948afb0928f2776121b8a227ebc13595fbcc398050f6c8a31dc3", "zkBytecodePath": "/l1-contracts/zkout/Merkle.sol/Merkle.json", - "evmBytecodeHash": "0xa055335d5ab48341cca200701dd2500cf6ef7174e4f3077a37503b48a24a7f38", + "evmBytecodeHash": "0x37a25e6aa70e8ab93b9c7bd6e5c2909847babf5a7fefe022438b884c86b2479d", "evmBytecodePath": "/l1-contracts/out/Merkle.sol/Merkle.json", - "evmDeployedBytecodeHash": "0x966815231cbc52c9d0877fefa8723f071408170c9c3cbc09b7a085f26dc0bb52" + "evmDeployedBytecodeHash": "0x585847da95d68afed72fc93bfe323bbb02d456bad18bb50e33a57515d697f5e5" }, { "contractName": "l1-contracts/MessageHashing", - "zkBytecodeHash": "0x01000007603a42e2646adf29eaaa7b94894d85d184aa0f45423ff7a2e5dd4c36", + "zkBytecodeHash": "0x01000007505db2673ee3d9538c42a3e686c90878efb81f140f7b43c433c62718", "zkBytecodePath": "/l1-contracts/zkout/MessageHashing.sol/MessageHashing.json", - "evmBytecodeHash": "0xc49eef7550bad1e2c7536cb533ef5fe05e091f7e1a33a59a53596a84537a9f61", + "evmBytecodeHash": "0x481704def49f1ab3c4c01007a7c92a1d24911ef2a2ff6b40c2b7585d5c61d32f", "evmBytecodePath": "/l1-contracts/out/MessageHashing.sol/MessageHashing.json", - "evmDeployedBytecodeHash": "0x6761f43ebfd777a31e47f633854011170561679b489bc52eab2ff1496bc15f8d" + "evmDeployedBytecodeHash": "0xa9def7ad4c01e383a65c1d65c49497b3f261f7b5496f7275be25c816f3e6176f" }, { "contractName": "l1-contracts/PermanentRestriction", - "zkBytecodeHash": "0x01000311c3e58790a4224345dadc36f82bf543424ece4e9e72fa4157b5701095", + "zkBytecodeHash": "0x010003113a5821ed63ee936bd66991ae47f6b2177604510fdf048da9af515c02", "zkBytecodePath": "/l1-contracts/zkout/PermanentRestriction.sol/PermanentRestriction.json", - "evmBytecodeHash": "0x7898cbbfcbb752b02cafbad06b0ff174b92fff918926a398bf5109339ed17b90", + "evmBytecodeHash": "0x6b624fac8e4028e657e4988999956ecb214aea4a23144924809191a36708e804", "evmBytecodePath": "/l1-contracts/out/PermanentRestriction.sol/PermanentRestriction.json", - "evmDeployedBytecodeHash": "0x3eaeb08ed31d7acb23eaa304ddb77869bd5739a123a3935ad12c1d0dbcfac477" + "evmDeployedBytecodeHash": "0x71ca59d11ff7b12928f8a6b544eac0b4b80f26a0f7598d09ea7e308d808f54af" }, { "contractName": "l1-contracts/PriorityQueue", - "zkBytecodeHash": "0x01000007a5dc90eda9034c05939219ad0409ec5b10f2857c54636c1d3a42fb87", + "zkBytecodeHash": "0x01000007b63d8e971333d69080ecc4ffbe09c21d7dbebdffe7346cf6298ef500", "zkBytecodePath": "/l1-contracts/zkout/PriorityQueue.sol/PriorityQueue.json", - "evmBytecodeHash": "0xb2527e988f8587f01ffd5195cd64b04eb55895aadf7b4272b978be5a1830b4ba", + "evmBytecodeHash": "0x4761e78621f877717010906664d994f1cf7e6591b8a51e32f6632fd234f2f583", "evmBytecodePath": "/l1-contracts/out/PriorityQueue.sol/PriorityQueue.json", - "evmDeployedBytecodeHash": "0x340bc290fd73e36b4d62ac60d670764838c910be24e52dc86225a7b2d8aca52e" + "evmDeployedBytecodeHash": "0x1b674c4afe51db2fed28ca5553984fe999b0db59f4c6a602c71f98a7e6b26972" }, { "contractName": "l1-contracts/PriorityTree", - "zkBytecodeHash": "0x0100000724ae1f21d12e01e1fd02abe86406e9720e6a35d0e60696adb0c11422", + "zkBytecodeHash": "0x010000076077a15332747c506ead794a91c2a5ee2292cc235c10b32912c95c5e", "zkBytecodePath": "/l1-contracts/zkout/PriorityTree.sol/PriorityTree.json", - "evmBytecodeHash": "0x2a4de71dd98397cd5e3aac7c4d555b24e7fccb621101996b74851193d428d783", + "evmBytecodeHash": "0x59b7d4d1801c2084bfbcc14150392f7cd381ae3138ce462784642ac68c26a60f", "evmBytecodePath": "/l1-contracts/out/PriorityTree.sol/PriorityTree.json", - "evmDeployedBytecodeHash": "0x7809acb70469228fa16ee6d3d47817b6f5f30db33fcbb2be94ab545a420f0fe1" + "evmDeployedBytecodeHash": "0x9800d80e5115abc7f19a32fdc8a247e6147f39026c2ac54c74f02f896a3195d7" }, { "contractName": "l1-contracts/ProxyAdmin", - "zkBytecodeHash": "0x010000e18d0788d925e16659993ff65cb636c3ed1fd5b90115ee07382b3ce24f", + "zkBytecodeHash": "0x010000e116c5932016ba45e8145461c0aad5c02ca3617bfdb7d0dd46c23e0390", "zkBytecodePath": "/l1-contracts/zkout/ProxyAdmin.sol/ProxyAdmin.json", - "evmBytecodeHash": "0xae804cba018bd20f1433163bdb40280e81dd2b07ea50524148886c3682abb0a2", + "evmBytecodeHash": "0x6de427f2ab6e4857e4a4b03ba7f9353c5c93e1d45c10ec03a22354ef86ddacd7", "evmBytecodePath": "/l1-contracts/out/ProxyAdmin.sol/ProxyAdmin.json", - "evmDeployedBytecodeHash": "0x14ab4271cecf41fd1de3364dcfb049553af19593cac645b24ca375c52a9c50ff" + "evmDeployedBytecodeHash": "0xfaee1dd339ae01834ff9fbf1b4f0f1d025b66c5297d54f411748d1c51860e451" }, { "contractName": "l1-contracts/RelayedSLDAValidator", - "zkBytecodeHash": "0x010000fdca014a214fc3525108159d5d412592d40b689e6103b203da6433c2d2", + "zkBytecodeHash": "0x010000fd4ea41c696a696b0df7c96febd8222f026f0968f11c8ff1d4de90e18d", "zkBytecodePath": "/l1-contracts/zkout/RelayedSLDAValidator.sol/RelayedSLDAValidator.json", - "evmBytecodeHash": "0x142aa22ca31d6af69657610b5c427dd286320b464488cb6763ac8d4fb3ce09ff", + "evmBytecodeHash": "0xa511318cc2bb5f333502d436b5172d7205c12349340d795b1044eb897cf9ce15", "evmBytecodePath": "/l1-contracts/out/RelayedSLDAValidator.sol/RelayedSLDAValidator.json", - "evmDeployedBytecodeHash": "0xcf9661af99eebf8cb965aa38663d7a48ea855a819e47241b616403c4f45a76b5" + "evmDeployedBytecodeHash": "0xddce5fcf2a97a2cf73033207b945fb5987fc5b6c8ad7d07d28597ab9dbb861fb" }, { "contractName": "l1-contracts/RestrictionValidator", - "zkBytecodeHash": "0x010000079cfb0ed1a18f139725ccf7cf8baba7b3a7434d301ce0b7a23fabd599", + "zkBytecodeHash": "0x01000007f25ac002ddf6da0b401cfdb0a906bffe6e96dd0d831f8dd1ac32651a", "zkBytecodePath": "/l1-contracts/zkout/RestrictionValidator.sol/RestrictionValidator.json", - "evmBytecodeHash": "0x73796484972ea0c6bcda8d8ae4f18acd842105b903c64bc2f4e1937b941f863f", + "evmBytecodeHash": "0x16eb8b6e90fa2e724798d70648201d769bb4afdbdc122cae9984b9e2c8641b6f", "evmBytecodePath": "/l1-contracts/out/RestrictionValidator.sol/RestrictionValidator.json", - "evmDeployedBytecodeHash": "0xf5534a9ff3563f788f2a26869789dcfebd820e1c5e408fab9185e2df08759909" + "evmDeployedBytecodeHash": "0x50de3810115591f7b3a04d3b78361e3f82e98da91ff68f9a75f21c9194726710" }, { "contractName": "l1-contracts/RevertReceiveAccount", - "zkBytecodeHash": "0x0100001b8591fba336df6685cf15a8f823a0111d0a6370e9f695abd1bd23cf3f", + "zkBytecodeHash": "0x0100001b89e002f44f028792e48ac8891843343cc1e3ff8b25b9c22e9e3b6789", "zkBytecodePath": "/l1-contracts/zkout/RevertReceiveAccount.sol/RevertReceiveAccount.json", - "evmBytecodeHash": "0x2267239699453c5998d497bbc39e1b64b2c22cf3ad69326b3b5929a27971e12f", + "evmBytecodeHash": "0x8ec5df935507a6d7a4410423af7d1bb1f865bf64e1cc4c54cb37a821c1001a61", "evmBytecodePath": "/l1-contracts/out/RevertReceiveAccount.sol/RevertReceiveAccount.json", - "evmDeployedBytecodeHash": "0xc900e4080679f84148d32383c2aefce71aaa6ce63504ace61595b5c1b9b0f215" + "evmDeployedBytecodeHash": "0x1281959efe0c68486aa6424724d9069ea3d4848bef0719cffbb20313c0161130" }, { "contractName": "l1-contracts/RevertTransferERC20", - "zkBytecodeHash": "0x0100017b9a39434f86ab39017bcc0fd821445875a6a1aa93ac7a3aef1b7347c7", + "zkBytecodeHash": "0x0100017b3aa67752ca7990021e69288aa4ba85e92880c8491807269ccd369650", "zkBytecodePath": "/l1-contracts/zkout/RevertTransferERC20.sol/RevertTransferERC20.json", - "evmBytecodeHash": "0x398006d07ea9f30a7a7e4fd11eedb254c33957985bedd401b098817d6b72c728", + "evmBytecodeHash": "0x58774e0b9974ecfb1ca05a201c08add98a940e0e2fd26bf8f8b4940641cf35ba", "evmBytecodePath": "/l1-contracts/out/RevertTransferERC20.sol/RevertTransferERC20.json", - "evmDeployedBytecodeHash": "0xb4afdd7a35adcf6994891369dddefcc5569651f61fa3c20b2da2fb61e59e1252" + "evmDeployedBytecodeHash": "0xe32c85a5d522c6c5244e3f6979edd1cdc01fd46c4b0acbd834125e5e83624dd8" }, { "contractName": "l1-contracts/RollupDAManager", - "zkBytecodeHash": "0x01000083dae328e05fe24fa94367c2f67e26c32e6ab4aa3fcd8eb5c7e77ef46d", + "zkBytecodeHash": "0x0100008365bb042ad61611ee272d1053d723c077b8c15a92942bde552178abc5", "zkBytecodePath": "/l1-contracts/zkout/RollupDAManager.sol/RollupDAManager.json", - "evmBytecodeHash": "0xd7590b962f1d4e14bbd000daea89de12bf3bac10a8fc9169f8b0385ec5b54056", + "evmBytecodeHash": "0x9f5562d866769aa8c82bb2ee225b17203f489a6272823340cb2bed8032d89fb6", "evmBytecodePath": "/l1-contracts/out/RollupDAManager.sol/RollupDAManager.json", - "evmDeployedBytecodeHash": "0x18623db63af424bbac7bd361129e70fef1823f5bd0a17a7a92715b7d034110a5" + "evmDeployedBytecodeHash": "0x33d5a2cd60491cb4d15a81145e05536d50e9da2cdece8b15c1cb8c2639a0a9c6" }, { "contractName": "l1-contracts/SafeCast", - "zkBytecodeHash": "0x0100000730acac4ef083a37d6ab89aa36cd9963db4e489879b78fd75f23430a5", + "zkBytecodeHash": "0x01000007c6dca26533491a569cb979f9f353f9dc5e12dabdb40f58fe4ea94be1", "zkBytecodePath": "/l1-contracts/zkout/SafeCast.sol/SafeCast.json", - "evmBytecodeHash": "0x4a0a496059c19390c76f1599fb94254c9edad03ea59b33da8575344807e20c0e", + "evmBytecodeHash": "0xb29a0e4c65e5fd67db4d22ceb4bc2111a5dd5c2ef99ef6bafebf598b2d4985a7", "evmBytecodePath": "/l1-contracts/out/SafeCast.sol/SafeCast.json", - "evmDeployedBytecodeHash": "0x86f83221f827ae0104c67cbd0c783f95072cfb0062f8e489815a546c349aa9ae" + "evmDeployedBytecodeHash": "0x27c2bd2cd2a8d3c889f7139cd81baf7fedf30b5d89822106f98a35e684e055a8" }, { "contractName": "l1-contracts/SafeERC20", - "zkBytecodeHash": "0x010000073b40f6657214c1c08498da4c6044e841db780ec53dcc6e1319ce4ccb", + "zkBytecodeHash": "0x010000070d8552130aa17c5a92fb8b8b1bfdef9e64bb3eee76cd92923307ae14", "zkBytecodePath": "/l1-contracts/zkout/SafeERC20.sol/SafeERC20.json", - "evmBytecodeHash": "0x8bcaaae3edcd704336fb87ff526323636ab7c153592a0804f8b65156f3cbdd73", + "evmBytecodeHash": "0xd60fdc60989067af924a94ac37169cc80703eb751e84c77646c7acf98fcc3a08", "evmBytecodePath": "/l1-contracts/out/SafeERC20.sol/SafeERC20.json", - "evmDeployedBytecodeHash": "0x37bb79938d832f604f20542497f60f8cc41f46a0525d837460755f975bd26202" + "evmDeployedBytecodeHash": "0x404a1ad118337d3f9527423c2350463dd54d14c4744f7125e8537e084f67df6d" }, { "contractName": "l1-contracts/SemVer", - "zkBytecodeHash": "0x0100000733c2d2368df4bff2f15475d1cfc5db39cbe975f364b403b0932b99a0", + "zkBytecodeHash": "0x01000007358aeed1944d950d874285a7780ef14cf9322a4bf00d5b8570e35225", "zkBytecodePath": "/l1-contracts/zkout/SemVer.sol/SemVer.json", - "evmBytecodeHash": "0x69b82664ac0eff045d6ca1e34974387a3a856a46578b1fa6dafd2ac3020e613c", + "evmBytecodeHash": "0xd67afabbbf9fc02f5b8324ef84bc1d678895df2415bd967d595ae477b87cd2f5", "evmBytecodePath": "/l1-contracts/out/SemVer.sol/SemVer.json", - "evmDeployedBytecodeHash": "0xe1f70baa7b9a10beea537323699161a613a10cfd2f5abdccf7eb34e7e2b5eb51" + "evmDeployedBytecodeHash": "0x2b36afb3e3054598df99853c2581ce1cc6d8fcc1022c2fcd1b9aaf08ba126a0e" }, { "contractName": "l1-contracts/ServerNotifier", - "zkBytecodeHash": "0x010000f17b2c98f45f8016a9032070de13bca8637ee80756e190e44fac1b851e", + "zkBytecodeHash": "0x010000f1970365c6edd0c63c9e291e6b44865ee7a31585e992c0b1ca292544d4", "zkBytecodePath": "/l1-contracts/zkout/ServerNotifier.sol/ServerNotifier.json", - "evmBytecodeHash": "0x8e096dfe2fe6f3fda78b048e6a738f03e95bef1d13b68a12a8067d0d6464b9dd", + "evmBytecodeHash": "0x5b7ff40df1f31d14306ac63b9f1b7d7a6ab8b8b64957a5dbcaf9b807031fc607", "evmBytecodePath": "/l1-contracts/out/ServerNotifier.sol/ServerNotifier.json", - "evmDeployedBytecodeHash": "0x1a77073e729598b658c686641d7f7d552875d7bfbda33b1d785322a3ef8b1629" + "evmDeployedBytecodeHash": "0x1b66c8a36246ccab7744eebc2d3a254b12615b4ae2b2ec77ebe7a830d99d06ef" + }, + { + "contractName": "l1-contracts/SettlementLayerV30Upgrade", + "zkBytecodeHash": "0x010003ebb39e1d085359bec9c0bce44331fb75dd01f436be45d2867184e0f18f", + "zkBytecodePath": "/l1-contracts/zkout/SettlementLayerV30Upgrade.sol/SettlementLayerV30Upgrade.json", + "evmBytecodeHash": "0x52fdb8549da8e33433c99b22d7926b90713b79b55f1f11ece1f29a2fd5ae87b9", + "evmBytecodePath": "/l1-contracts/out/SettlementLayerV30Upgrade.sol/SettlementLayerV30Upgrade.json", + "evmDeployedBytecodeHash": "0x9fe211180cd50ad686eae53188cba99ed0ce06039624d04947d1257e32528483" }, { "contractName": "l1-contracts/SignedMath", - "zkBytecodeHash": "0x010000073b4ff9ba2f6ae737833f673602e0c344bb2ef794f5303b4edb03c959", + "zkBytecodeHash": "0x01000007734e1a64940f236c9ea1098ca6592adb18ffe643e86ad7d53997834c", "zkBytecodePath": "/l1-contracts/zkout/SignedMath.sol/SignedMath.json", - "evmBytecodeHash": "0xd1539f05abc9be582f7fd40681d23cf512e79a64c3d1a631f9edfe38780747a7", + "evmBytecodeHash": "0x9c3121a4e15c93949b1f66b32482dbc827a1052b0c8d46f5b1028eef928ab1c5", "evmBytecodePath": "/l1-contracts/out/SignedMath.sol/SignedMath.json", - "evmDeployedBytecodeHash": "0x59c1227d9c5cf1f3564cafc87031f44398aa3879bc42585902586cc9c4b0cbb1" + "evmDeployedBytecodeHash": "0x226f711348f18363dc667fa3787411fb8f22fc0c2360b6ef46f67f628bbcf08c" }, { "contractName": "l1-contracts/SignedMathUpgradeable", - "zkBytecodeHash": "0x01000007e11221e38bbf4cc6f25d26978bb65379e7c9bb0773f04bf4291bc30f", + "zkBytecodeHash": "0x010000076807447d5f6004179147c04a3b73ca7756856c760d1ae2a3047ac55b", "zkBytecodePath": "/l1-contracts/zkout/SignedMathUpgradeable.sol/SignedMathUpgradeable.json", - "evmBytecodeHash": "0x4a6177ee9326e3f8062a17735efeecafd301cc501c24196d1cb43221eb4bc67a", + "evmBytecodeHash": "0x313e0f68010f3e0a40c88c8edc950dca4e6288d966135ceca762f2d58f8a6506", "evmBytecodePath": "/l1-contracts/out/SignedMathUpgradeable.sol/SignedMathUpgradeable.json", - "evmDeployedBytecodeHash": "0x103a3cc591ce8bd1bbd30680ef2096bd064eba508a86f3018087d8f4f2ee177a" + "evmDeployedBytecodeHash": "0x227a864702903ab71b59c5e2a001e9999a48d23248826c9fc462dd9a94d4d029" }, { "contractName": "l1-contracts/StorageSlot", - "zkBytecodeHash": "0x01000007abfdd8447cec54942b782815aaa2999cbd1fcf9e4805abdd0acbd8bd", + "zkBytecodeHash": "0x010000071d07fb2b17601b567022259c41a65929aa74b295071db52dc6b82683", "zkBytecodePath": "/l1-contracts/zkout/StorageSlot.sol/StorageSlot.json", - "evmBytecodeHash": "0x4f21ecace17e117d55148f15fe26ab474d70f2b20057eb87321350a3e7ddec91", + "evmBytecodeHash": "0x17ae1f844d138a435dbf16582564ebf194d3b6f3c14bb272c71a12a98828b884", "evmBytecodePath": "/l1-contracts/out/StorageSlot.sol/StorageSlot.json", - "evmDeployedBytecodeHash": "0xebe440b3c783cfdfc4f45dbc5760ba83e9deeb84d67617976ef3f13963860202" + "evmDeployedBytecodeHash": "0xf8a574a877f6e32197cca2bb26a594d6fd0f74441e510fe2dbd54f46398b60b1" }, { "contractName": "l1-contracts/Strings", - "zkBytecodeHash": "0x010000075a354ac6a9ece550e8d3e7379e78946a4b0fcadea45df8f4e500a4b7", + "zkBytecodeHash": "0x010000077ebddfd88cfc9bcc19dd74e9c9dfcf05fe1f5fbbca7bb6862f720663", "zkBytecodePath": "/l1-contracts/zkout/Strings.sol/Strings.json", - "evmBytecodeHash": "0x58c632496fb4e72f86cbd208c70e9613accfcd28adf4d7744ee7165bde1fb9fc", + "evmBytecodeHash": "0x7137d4183e5c0ee6f1c28fc17d6fb53d8936913e0c619cbfbfd5b9b0f0872421", "evmBytecodePath": "/l1-contracts/out/Strings.sol/Strings.json", - "evmDeployedBytecodeHash": "0x83ef366ca7c636a1360ca8ac33cf80e4bedc8bfaa62f4397064751b005d22b33" + "evmDeployedBytecodeHash": "0x23d0f043b6a838b0940a4ab06f074182d21c93b989596b80d406eaa641fc6f64" }, { "contractName": "l1-contracts/StringsUpgradeable", - "zkBytecodeHash": "0x01000007584a040e5c5918b86d8f91401f32a9412673bc604492a5181e38cc25", + "zkBytecodeHash": "0x0100000716fcd61ef92ddb45942af1aaf83732725b7ed751c9e234e3959e6722", "zkBytecodePath": "/l1-contracts/zkout/StringsUpgradeable.sol/StringsUpgradeable.json", - "evmBytecodeHash": "0x34cb6de5b5aa20f3f4f6ccd48308fdb86e53e2684513d7a51b6f4224e7d1fc7f", + "evmBytecodeHash": "0xb33159df2219361dc08396cfd2648bc685e970600b0cc596cbaa31fda232e340", "evmBytecodePath": "/l1-contracts/out/StringsUpgradeable.sol/StringsUpgradeable.json", - "evmDeployedBytecodeHash": "0xef6f42791be03f203def1f5cae725ac78bc2ee8cc919539b2a241dc593440355" + "evmDeployedBytecodeHash": "0x52f84adc0d9ee6f12496e318866d0bf984180c3b73f8dfa31f0c53e1302e667a" }, { "contractName": "l1-contracts/SystemContractsCaller", - "zkBytecodeHash": "0x010000077b0c3e28fba074520862ed5ddcdb029741dae6d8aa5ddb438a980c63", + "zkBytecodeHash": "0x01000007c51677e013ec202eb8195bd7bf31da1d63dddb80573981f61c2265bd", "zkBytecodePath": "/l1-contracts/zkout/SystemContractsCaller.sol/SystemContractsCaller.json", - "evmBytecodeHash": "0xa4a11152326709e199cbd580347377c3d4ed13f3a5a1a70ce71b508bfd82713e", + "evmBytecodeHash": "0xdfa2aedfb1eebf78324678ece6f3543e68187f0de14f6477eb3563213c58ba02", "evmBytecodePath": "/l1-contracts/out/SystemContractsCaller.sol/SystemContractsCaller.json", - "evmDeployedBytecodeHash": "0xe3bd09a26c19a31205170e23806402bf35b4253f40c7763d8aa8f41f9cb93cc4" + "evmDeployedBytecodeHash": "0x98720c687a9b7f5e098043c2cf2c05c87f2b5ee21e51cf717c804f320602fb57" }, { "contractName": "l1-contracts/Utils", - "zkBytecodeHash": "0x01000007560163cd816f0ed1434e2460f03fff9feca80bf0cf1edb1e00d5d44b", + "zkBytecodeHash": "0x01000007842b535279bd716875453dbc8f7e763b8465d956b22c362bf9cf272d", "zkBytecodePath": "/l1-contracts/zkout/SystemContractsCaller.sol/Utils.json", - "evmBytecodeHash": "0x0277be2155e0a13624aac068cd2ef0d82559e5b2cdbe9b85fc8803178b1d0b95", + "evmBytecodeHash": "0xb427da64c552a0d2c5f8ae3640fb9e06cc202431102c8e5182741da68ed9dc50", "evmBytecodePath": "/l1-contracts/out/SystemContractsCaller.sol/Utils.json", - "evmDeployedBytecodeHash": "0x346652385ffbf9145c3951418f99ea3857a08a48ba8fd396806677e8c60214dc" + "evmDeployedBytecodeHash": "0x741a57583bde971799d39880ea9713bba5c234344d852623c2b26d46b6f2328b" }, { "contractName": "l1-contracts/TestnetVerifier", - "zkBytecodeHash": "0x010000adeb045b4632e677416b7202907820866ac61526cd415f19cd74ab4131", + "zkBytecodeHash": "0x010001ff8f9420eaab5f171c7539aa10fa8b9bd79b9da087353b597f71b5bfa3", "zkBytecodePath": "/l1-contracts/zkout/TestnetVerifier.sol/TestnetVerifier.json", - "evmBytecodeHash": "0x1d769e1544a3c49f4b349ce3ca478eb32f197bf7426d20a1edd2619f110fb53e", + "evmBytecodeHash": "0xc5b71a976a246f5ae3f35aeb83d63c754982c2e6db6f850c9fbabcfb1cdb0f42", "evmBytecodePath": "/l1-contracts/out/TestnetVerifier.sol/TestnetVerifier.json", - "evmDeployedBytecodeHash": "0x446f1024262ede502eb86983000b16a91c2f8254c0de3e82e4bf24f4852f32b3" + "evmDeployedBytecodeHash": "0x198e9068d36372a0850554e88eae110c4f27d80b4da54e77985829658441bb6a" }, { "contractName": "l1-contracts/TransactionValidator", - "zkBytecodeHash": "0x01000007c91270c36866d86be1a1b90904fc2d617cdde21b71990d0ecf785aec", + "zkBytecodeHash": "0x01000007429edfd1a46621a98054292765cdd72c3dc48ce62e81b79a393d00fc", "zkBytecodePath": "/l1-contracts/zkout/TransactionValidator.sol/TransactionValidator.json", - "evmBytecodeHash": "0x460784736e65811b69f552447624f740f9b0f318083ce9f7fc8aeb0b6bc80a4b", + "evmBytecodeHash": "0x63b1e666cae253cc35f38ea0d1beabc64a98b7f78d96f62591ab1602e202bd1a", "evmBytecodePath": "/l1-contracts/out/TransactionValidator.sol/TransactionValidator.json", - "evmDeployedBytecodeHash": "0xc9408b8b387201ef176a2388316c98d7187aaf4061c7487ea8c9b69d6e198aa1" + "evmDeployedBytecodeHash": "0xaa2b727c96f6fa10c89fa086818c62fc1cbb9dde3e2da76a8ac3a5ad04926383" + }, + { + "contractName": "l1-contracts/TransientPrimitivesLib", + "zkBytecodeHash": "0x010000071998eb38fc5360673eba5d31b5cb824415acfd9e89a2a68ab3e82b76", + "zkBytecodePath": "/l1-contracts/zkout/TransientPrimitives.sol/TransientPrimitivesLib.json", + "evmBytecodeHash": "0xa5f90a43ccbe8102a522bdda48319fb36bebe01d8f40c99f72ae9dd03efd775f", + "evmBytecodePath": "/l1-contracts/out/TransientPrimitives.sol/TransientPrimitivesLib.json", + "evmDeployedBytecodeHash": "0x4305b83567ce661edd2e807c9f8df1fdc682183bc5f1471293e145320bbb6744" }, { "contractName": "l1-contracts/TransitionaryOwner", - "zkBytecodeHash": "0x0100005bd2f3ba147ba7ae7b091665249e47524c2c777a5eef48df88474f0837", + "zkBytecodeHash": "0x0100005b8584d3d509fbf5ef7fb6f3695b3ef8c15f7d725a73b9e96eb93ae27a", "zkBytecodePath": "/l1-contracts/zkout/TransitionaryOwner.sol/TransitionaryOwner.json", - "evmBytecodeHash": "0x0b0e968e8b3a3499d6a64465c65caf0e2ee58f0d9822c6a61555d0b4c87e3867", + "evmBytecodeHash": "0x0d3ebedff3ea2f1157698fc5d604cc1ac0569f59426e6fabbc19db9a98a8cf13", "evmBytecodePath": "/l1-contracts/out/TransitionaryOwner.sol/TransitionaryOwner.json", - "evmDeployedBytecodeHash": "0xe8e47e802c9f28bc2c2a33e861e00a3d3a77690ec78ec0387f77e90f04e8d949" + "evmDeployedBytecodeHash": "0x8d3a8864e1c9ebdc2868d6b5c1364958311de2b9aa8e4b0ce5d50836bfb428dd" }, { "contractName": "l1-contracts/TransparentUpgradeableProxy", - "zkBytecodeHash": "0x01000149593c20ec28bef707d918a4f963887591dbe8278c730e860abf0fdb64", + "zkBytecodeHash": "0x010001491f717ebf9a6f551e4dfab4b7254b554ad678abee06d265a44167082e", "zkBytecodePath": "/l1-contracts/zkout/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json", - "evmBytecodeHash": "0xeff8a1d98c67d773530551ca091731243869cec1e637b9e35a773dc9ee1ec3d3", + "evmBytecodeHash": "0x6c9b25997720ab45ba6f19e7f535f9254afb98c704a64c3670dfe2873d9120e7", "evmBytecodePath": "/l1-contracts/out/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json", - "evmDeployedBytecodeHash": "0x233c67ec54c6d38b0fc1b57546483b2849e61308832443513d521c4188ff63d7" + "evmDeployedBytecodeHash": "0x889bf122aa5d0beafa26838d8d2ea19109387add08435635775c33390a770591" }, { "contractName": "l1-contracts/UncheckedMath", - "zkBytecodeHash": "0x010000077758666a5353fc097b50d4715d4d63bdcfd0fc93ca7a9dae308c8f15", + "zkBytecodeHash": "0x0100000720d96111cd1ad3fccedd2280449c263f89bfb2b0da31b0ad8808853f", "zkBytecodePath": "/l1-contracts/zkout/UncheckedMath.sol/UncheckedMath.json", - "evmBytecodeHash": "0xd11762496af656d6431ef7542844802f76d84004de4648867dd3ba1575ab182e", + "evmBytecodeHash": "0x6ef3da82f822e8635193a1dceba1ac848ad81acddac82f0fa69da90fa842ff59", "evmBytecodePath": "/l1-contracts/out/UncheckedMath.sol/UncheckedMath.json", - "evmDeployedBytecodeHash": "0x36e00ecf44abe9616f66bccc0dc0dca5c961a21e1df9c45590357cded6401b75" + "evmDeployedBytecodeHash": "0x1bd3df057466be5e60b52bb0595bafd7630083aac9e67760715692e25c2a1e9e" }, { "contractName": "l1-contracts/UnsafeBytes", - "zkBytecodeHash": "0x0100000705aab131e66b26d5976a28c7f8616e43bbaa8d162c637f6f412c8259", + "zkBytecodeHash": "0x01000007b45f2cb1d3dae47864fb51f0e42576f909ce25602e2e122fd960464a", "zkBytecodePath": "/l1-contracts/zkout/UnsafeBytes.sol/UnsafeBytes.json", - "evmBytecodeHash": "0x0e43251a01dea60598d935f22a05c7b5afc2e769f049d035d8cfe36ab6f88e6a", + "evmBytecodeHash": "0xc61ad304f9c8a98410c9e18be606ee04388d8f5baf956c4e615d24e14295709c", "evmBytecodePath": "/l1-contracts/out/UnsafeBytes.sol/UnsafeBytes.json", - "evmDeployedBytecodeHash": "0x97b15b9cf3a912e69c3f08a5c2dbe0ec352ba2283f230b17e39c2eaa0a8244ca" + "evmDeployedBytecodeHash": "0x18bcea2a56bbebc8320f465377d8a900b623b752d4ed73c58fced5c2fd4efcc5" }, { "contractName": "l1-contracts/UpgradeStageValidator", - "zkBytecodeHash": "0x010000c309cf7e349d36477a7935660a5ee2ef6c3f381bf76ce815c3ce26a6f6", + "zkBytecodeHash": "0x010000a35e9084c2004713b19628154fabaf3f0526efc9e39b63c28bace48877", "zkBytecodePath": "/l1-contracts/zkout/UpgradeStageValidator.sol/UpgradeStageValidator.json", - "evmBytecodeHash": "0xc141f50f605a515726f31c2d955aa98f55c92ecddc50fe2da9c0eff06649b0a6", + "evmBytecodeHash": "0x8fb0add13cb8dee122a243638ae2110f6038b962b0f99c46201a9ef972b6d314", "evmBytecodePath": "/l1-contracts/out/UpgradeStageValidator.sol/UpgradeStageValidator.json", - "evmDeployedBytecodeHash": "0x4ceb5f34c1bd4d814c63543b24dfe3ff72f4dac578ab3f12edab7c73d1122f75" + "evmDeployedBytecodeHash": "0x740d72dadea0c1e19e355a07da6cb2e5a7fe63ed6ca6057cac2dbba8829af94f" }, { "contractName": "l1-contracts/UpgradeableBeacon", - "zkBytecodeHash": "0x010000674dd9c2b44a5c02408bda04df734b258d1c6ee9e07f5a6904a13d27fc", + "zkBytecodeHash": "0x01000067a0fdd045ad21a20e7031e06609ca1e9eaed3946aefd51ebf97af5156", "zkBytecodePath": "/l1-contracts/zkout/UpgradeableBeacon.sol/UpgradeableBeacon.json", - "evmBytecodeHash": "0x16e9b6d2d2ff2d4f09e041993b5bb29902e10dc154491fac8e1dcd8cd0faf50e", + "evmBytecodeHash": "0x72dda3bd9650d3a9f5684b135fc2335931f3aa74f8104e4651d984e0a5606398", "evmBytecodePath": "/l1-contracts/out/UpgradeableBeacon.sol/UpgradeableBeacon.json", - "evmDeployedBytecodeHash": "0xba4bfb9d8fdb5e5690b9c2e10d68acdd886790840a3da73771993f5ddd9cf23f" + "evmDeployedBytecodeHash": "0xea314c4227dea58a88686a4a40f971b645b63e23d87bc6dae17c55e2c31d6bb0" }, { "contractName": "l1-contracts/UpgradeableBeaconDeployer", - "zkBytecodeHash": "0x01000053e7fb4b9215c7a95e2b3ab481d0b5a44d6902c5c168e5795216cc3e53", + "zkBytecodeHash": "0x01000053f9447bd2b67a125d577d931a36c5ba2ffdf98f428d8f32db86e54924", "zkBytecodePath": "/l1-contracts/zkout/UpgradeableBeaconDeployer.sol/UpgradeableBeaconDeployer.json", - "evmBytecodeHash": "0x272dce8a071930c07d10a35cef3a2d7d6d21687eb0986baf94ef1e35dbb8a488", + "evmBytecodeHash": "0xd892a48ee772bee32c42dc6b326ded9034aeb37e4efd4171aa5fd033cc708071", "evmBytecodePath": "/l1-contracts/out/UpgradeableBeaconDeployer.sol/UpgradeableBeaconDeployer.json", - "evmDeployedBytecodeHash": "0x3b82bfd98320c45362887f0459a8c7a6bece2880aaf839ff8f4baf348710b395" + "evmDeployedBytecodeHash": "0x485fbb5b70df3fca61a7d80f89902c53c07a376502f1828d5a2204272e6ab130" }, { "contractName": "l1-contracts/ValidatorTimelock", - "zkBytecodeHash": "0x010009b3d25b9b0e6649162f938b796c05ec36758934b6c721323183367d6859", + "zkBytecodeHash": "0x010009b32958d1058b7a6bb3c48e4c8ab39e831ab94d3aee9ce17aaff5f20c74", "zkBytecodePath": "/l1-contracts/zkout/ValidatorTimelock.sol/ValidatorTimelock.json", - "evmBytecodeHash": "0xd1023d4de70158a5e3d00f8b1dd92e84fa8878d4661acaa096844bd285ae5fd1", + "evmBytecodeHash": "0x8fa535172ebb4224a9ecb350361543d981d77e9de838f7969a64b9f8af2765bb", "evmBytecodePath": "/l1-contracts/out/ValidatorTimelock.sol/ValidatorTimelock.json", - "evmDeployedBytecodeHash": "0x74653e183a85cd68fc6e12575fd5d2a0494835f6a55d2f2e2454c79a9ff208ba" + "evmDeployedBytecodeHash": "0xb3016d878388bb3ca51125e9b585e6f678973624cf9e1cab2c770856ed3eaf63" }, { "contractName": "l1-contracts/ValidiumL1DAValidator", - "zkBytecodeHash": "0x010000333500616c60127b34dba0cdc1447a26213ce2f7c3c40a632ce8f0dec1", + "zkBytecodeHash": "0x010000330d612bc352fa0a1ed5b1116d1d6eca63551f54a2b96d97170f8a678a", "zkBytecodePath": "/l1-contracts/zkout/ValidiumL1DAValidator.sol/ValidiumL1DAValidator.json", - "evmBytecodeHash": "0x4ffe3077d3c4f1588a43b8b906e27155e412ef646c91ddaeb87ed975abac7207", + "evmBytecodeHash": "0xeaf883a77e73c202905409ee6d358d50dd797b445412c03e12c0b35939c62e82", "evmBytecodePath": "/l1-contracts/out/ValidiumL1DAValidator.sol/ValidiumL1DAValidator.json", - "evmDeployedBytecodeHash": "0xdac15910d458f082b4c687aa52e961150e82b47d19c86f6de1198516977d4fc7" - }, - { - "contractName": "l1-contracts/ZKChainBase", - "zkBytecodeHash": "0x0100000757a0629931417f5aa084deb53eaa120cd7eb9067111ecab9aae4235d", - "zkBytecodePath": "/l1-contracts/zkout/ZKChainBase.sol/ZKChainBase.json", - "evmBytecodeHash": "0x537b4eb4824b730285be1b0d3022ff16af9cf96654c910ea926e93dd06c11835", - "evmBytecodePath": "/l1-contracts/out/ZKChainBase.sol/ZKChainBase.json", - "evmDeployedBytecodeHash": "0x48bd6da7b124bf3021ecdb166eeff5f9235b6d1b38daf528541f0f7d45362839" + "evmDeployedBytecodeHash": "0x277cdd9c5ebfafc4d317394838a1ddfce80f77cc30ad5fcb38fd72c9921cbb76" }, { - "contractName": "l1-contracts/ZKsyncOSChainTypeManager", - "zkBytecodeHash": "0x01000751f4e001455335f56f51bf2327213da3087d822fe87d18470f9d40a524", - "zkBytecodePath": "/l1-contracts/zkout/ZKsyncOSChainTypeManager.sol/ZKsyncOSChainTypeManager.json", - "evmBytecodeHash": "0x3e5be9cea8bc62b5eac3f89e3064707e93979da928142f6880995a8d4ff57c42", - "evmBytecodePath": "/l1-contracts/out/ZKsyncOSChainTypeManager.sol/ZKsyncOSChainTypeManager.json", - "evmDeployedBytecodeHash": "0xede174e2d192cc988554c20c215e1e16387170d26bfffdbcaf4d65604dcd12ff" + "contractName": "l1-contracts/VerifierFflonk", + "zkBytecodeHash": "0x010009bfb2b3ec7572a37694280dad38d51cc56a30142612ae1c507a13947247", + "zkBytecodePath": "/l1-contracts/zkout/VerifierFflonk.sol/VerifierFflonk.json", + "evmBytecodeHash": "0x737ea16294bc698c9c388604c09f0510953499501a21d18dc57404f0f69e5b20", + "evmBytecodePath": "/l1-contracts/out/VerifierFflonk.sol/VerifierFflonk.json", + "evmDeployedBytecodeHash": "0x1172be6495ece8b7eaf5e9870f6489e665187aca9e3b14fc1295a2fa29ff6c79" }, { - "contractName": "l1-contracts/ZKsyncOSDualVerifier", - "zkBytecodeHash": "0x010001ad28077de4cb5362ef928ca8f2ed472e8dbaf076aa4d0ea4511afedfaa", - "zkBytecodePath": "/l1-contracts/zkout/ZKsyncOSDualVerifier.sol/ZKsyncOSDualVerifier.json", - "evmBytecodeHash": "0xd5c916e298f62972ea6c418fe5e7b15d29579c62a986a7b7714f59ebb665a938", - "evmBytecodePath": "/l1-contracts/out/ZKsyncOSDualVerifier.sol/ZKsyncOSDualVerifier.json", - "evmDeployedBytecodeHash": "0x38c1bf1f381e9e31cef74c6da0917448ef869f1f7adb68533b272a0a6b9a7414" + "contractName": "l1-contracts/VerifierPlonk", + "zkBytecodeHash": "0x01000dbbf483334b7d20395aaff3af0c3529914d072ced54d4e4f3a4e3f9d3df", + "zkBytecodePath": "/l1-contracts/zkout/VerifierPlonk.sol/VerifierPlonk.json", + "evmBytecodeHash": "0x3db49eec608e61a63f3173731051abad4d02dfd392a9e5379b8f45c69a807602", + "evmBytecodePath": "/l1-contracts/out/VerifierPlonk.sol/VerifierPlonk.json", + "evmDeployedBytecodeHash": "0x25a083a08136a491ad68832c90fb246d7960542c019b7d42fc4545c623fe8799" }, { - "contractName": "l1-contracts/ZKsyncOSVerifierFflonk", - "zkBytecodeHash": "0x010009bf79f4d5dbe0d181ea9f730925447a6feb3e6fc513ba64c5d6cb1c39eb", - "zkBytecodePath": "/l1-contracts/zkout/ZKsyncOSVerifierFflonk.sol/ZKsyncOSVerifierFflonk.json", - "evmBytecodeHash": "0x3ca976c1ce6d179937d39881b7cce11443220246d1c29c5bde81d159920d12a2", - "evmBytecodePath": "/l1-contracts/out/ZKsyncOSVerifierFflonk.sol/ZKsyncOSVerifierFflonk.json", - "evmDeployedBytecodeHash": "0xfc06817188bd38a8a33e8f8d602ae6093036424e84b06cb254ab49eece32c865" + "contractName": "l1-contracts/ZKChainBase", + "zkBytecodeHash": "0x0100000738192f76938f6a6828fbccfe8682dc28e7f38cd73b4eae7ad36b99ff", + "zkBytecodePath": "/l1-contracts/zkout/ZKChainBase.sol/ZKChainBase.json", + "evmBytecodeHash": "0xdc0264d46431b61436373d9bc36b2f4030ca347f13baea930c4711a6a18e7798", + "evmBytecodePath": "/l1-contracts/out/ZKChainBase.sol/ZKChainBase.json", + "evmDeployedBytecodeHash": "0x52abad1c9442805a828e134270b915696988df569ca1a0832849605ce3f13b4b" }, { - "contractName": "l1-contracts/ZKsyncOSVerifierPlonk", - "zkBytecodeHash": "0x01000dbbdd23d732ca844cd3a48bec80df92d17748cd0a30c256084fd830991a", - "zkBytecodePath": "/l1-contracts/zkout/ZKsyncOSVerifierPlonk.sol/ZKsyncOSVerifierPlonk.json", - "evmBytecodeHash": "0xe75ee6b02eea872b66c73fff34cb436eb2ec06d8a7d5fdf22a8cb582cc7d08ae", - "evmBytecodePath": "/l1-contracts/out/ZKsyncOSVerifierPlonk.sol/ZKsyncOSVerifierPlonk.json", - "evmDeployedBytecodeHash": "0x053ef86d5bbccdb3fd0b04347753d9acc7392cee80df9aed6a98d5cca5af4311" + "contractName": "l1-contracts/InteroperableAddress", + "zkBytecodeHash": "0x0100000798222d562bcb39ad432663b0d716242067411f156fb040e740fac054", + "zkBytecodePath": "/l1-contracts/zkout/draft-InteroperableAddress.sol/InteroperableAddress.json", + "evmBytecodeHash": "0x9123544ec115dd93e47b99552a73c8013750cfa8d07962be2ecd94c9d54e071c", + "evmBytecodePath": "/l1-contracts/out/draft-InteroperableAddress.sol/InteroperableAddress.json", + "evmDeployedBytecodeHash": "0x6ececb50839e7a1d881e76fc9726ad33914c6ca1908a71caaacaca2b3dd9998b" }, { "contractName": "l1-contracts/Create2AndTransfer", - "evmBytecodeHash": "0xfebf807006627544db6eaf474508d47b688adb3d5195b5071b3bf34ead2f81b6", + "evmBytecodeHash": "0xcc26cde344d675a47392307dfc2df17e4ed087d4c89111085a500ebd4007cbc5", "evmBytecodePath": "/l1-contracts/out/Create2AndTransfer.sol/Create2AndTransfer.json", - "evmDeployedBytecodeHash": "0x7e0b5656d9ac680e5d3ad8606eb48aca581a8f125a115c6c01e7cbb7ac068bd7", + "evmDeployedBytecodeHash": "0x0264471ce3f4592825453ee305c018aa4591a5d8871e137ebe1af19c422eb49b", "zkBytecodeHash": null, "zkBytecodePath": null }, { "contractName": "l1-contracts/StdConstants", - "evmBytecodeHash": "0xa204555ddb5b7aae6f985aab731d8bbef3cc8dbd4eb3cd00f003badc5a71bcfc", + "evmBytecodeHash": "0xa067a2f8a9c91ea248802c29fc3cb4eb77fb36fa7544c8dff1e25edfa4f728ea", "evmBytecodePath": "/l1-contracts/out/StdConstants.sol/StdConstants.json", - "evmDeployedBytecodeHash": "0xcdfd7fa41f81f94facaa07c41ba2ef87058b72fd3c81dd3f3b6145e061faa0dd", + "evmDeployedBytecodeHash": "0x4f853ea0954fcc1fe83ffa1e4adab34d80cb7c3e3f819fea5e46d41955117a6a", "zkBytecodeHash": null, "zkBytecodePath": null }, { "contractName": "l1-contracts/stdError", - "evmBytecodeHash": "0xc665c6f2163557700dc7cd809615cf2fcf70af3400a150cb9f68fbb8daa643e2", + "evmBytecodeHash": "0x59266a89bc6c104781926c209fba7fbcb52ed30d8155fbf305143d0c6df0e18e", "evmBytecodePath": "/l1-contracts/out/StdError.sol/stdError.json", - "evmDeployedBytecodeHash": "0xae396a9f2444f6ca903c33b92aeabe1a6e8f5d74a30ccf57fb9730890b8c353a", + "evmDeployedBytecodeHash": "0x5e7e77ebfb463152fc739350ed561d75dde7ea1e2c6ff306452d8932676fb871", "zkBytecodeHash": null, "zkBytecodePath": null }, { "contractName": "l1-contracts/stdJson", - "evmBytecodeHash": "0x4e218a599b6fa65d3e466fba80556fd94229593a741f7490b5f5360a310c938d", + "evmBytecodeHash": "0xe65a5abb4297e923ac48c7bb6707991bc5797f036789b42f58ca9b3879727850", "evmBytecodePath": "/l1-contracts/out/StdJson.sol/stdJson.json", - "evmDeployedBytecodeHash": "0xba647b6d04cc8c8e7ac2622358adcefb72176dedb898cf97006a4f2a6f5e1295", + "evmDeployedBytecodeHash": "0x0aea7c80746b1719a8153caa30fd1af89c27d1ef8de911752cc877f77bd19345", "zkBytecodeHash": null, "zkBytecodePath": null }, { "contractName": "l1-contracts/stdMath", - "evmBytecodeHash": "0xda78553c78a5f4d3bcd8bf198b63e9e5fba3b22efc22ba73f31e5e19476d0aa6", + "evmBytecodeHash": "0x159025812468232befde1107a3504da03756554970220b0b54c49302265cdaa9", "evmBytecodePath": "/l1-contracts/out/StdMath.sol/stdMath.json", - "evmDeployedBytecodeHash": "0x4ceda3e6f661699d507e56828120123765e74d00dada868fd2f3be962286970d", + "evmDeployedBytecodeHash": "0xc8dc68f1b4686b457b851d2739369bbe76434c3eaef8b73f402e0fc19b058d51", "zkBytecodeHash": null, "zkBytecodePath": null }, { "contractName": "l1-contracts/stdStorage", - "evmBytecodeHash": "0xe73c9bc14f4be28ffe7db3da3f3c9ee2f75bef6bdf5048b47b5817a8e67301c5", + "evmBytecodeHash": "0x3e48a6f9ebf0dc67a700d8c70693c088d5e1e4dad9c9d4261e86c7d95df8bd3a", "evmBytecodePath": "/l1-contracts/out/StdStorage.sol/stdStorage.json", - "evmDeployedBytecodeHash": "0x8e8eafa5e1ed36eb25521a05c73f6eb2e1651a56a0d8fd923dbd6ef096bc2539", + "evmDeployedBytecodeHash": "0x32e68842fac57bc6325a44b2fc1976bd92cf2f1c56689ed6c275f69e0a3c3e25", "zkBytecodeHash": null, "zkBytecodePath": null }, { "contractName": "l1-contracts/stdStorageSafe", - "evmBytecodeHash": "0xf2fb194607aa51280838aecb0a368ecdd4027c22f83a2189f0ee90e2f50e6cf3", + "evmBytecodeHash": "0x0b17debfd6aff7853f6639d6eca526cc573ad7da40fd53403de5c29a7076e5a4", "evmBytecodePath": "/l1-contracts/out/StdStorage.sol/stdStorageSafe.json", - "evmDeployedBytecodeHash": "0xffab4afc5be82e2526f782907511e29053f316e21720c186b378d9d023740fa5", + "evmDeployedBytecodeHash": "0xf235a2d850c59b349f9fd07fbd3ee430ac32e586ddd98c372c8418f2661ece76", "zkBytecodeHash": null, "zkBytecodePath": null }, { "contractName": "l1-contracts/StdStyle", - "evmBytecodeHash": "0xf139d3e0715a6f0ad32e7ed62f4b8d16fd9c0a98688655cf99a877107e0320be", + "evmBytecodeHash": "0xd06e9f4b5f8ac536443b9e1e04ac5e1c04f49a6cc5b89c83c253b4f9a9c217e3", "evmBytecodePath": "/l1-contracts/out/StdStyle.sol/StdStyle.json", - "evmDeployedBytecodeHash": "0xd721ed6a39216cce8f9c762756fe81c00b1e98abc25b5b9b44901dfb472c83d4", + "evmDeployedBytecodeHash": "0xb1496a00bb5b23c578fda68a9b452d4176e1979775d736dc45ed77d37a74ada9", "zkBytecodeHash": null, "zkBytecodePath": null }, { "contractName": "l1-contracts/stdToml", - "evmBytecodeHash": "0x78fd33c1b97e99fe8a23f8bdf7a364426db74b403f575fe7ddb4f6b41d5c76ea", + "evmBytecodeHash": "0x0a4345b6ecaf5bfba6a436b6cf5f9ab439e6fdd2149de4e46dcc19056407fe12", "evmBytecodePath": "/l1-contracts/out/StdToml.sol/stdToml.json", - "evmDeployedBytecodeHash": "0xf019d02fc84f1ec73a3bed891fa20cc550f68e2975d05021ecf2fb569f884714", + "evmDeployedBytecodeHash": "0x72916c4c05eec2294b46a0d7e65fd2b4ca4f705827ab71a78213e6e1f3d2aff0", "zkBytecodeHash": null, "zkBytecodePath": null }, { "contractName": "l1-contracts/console", - "evmBytecodeHash": "0x16e8e6e585a7711fe2b2c1502fe7527ed2cd93c3cf540a3e33965c52f920f870", + "evmBytecodeHash": "0x351e1b74569234e64aa4d89846884dc80458632fbd8b513f1c62d7544c8736ae", "evmBytecodePath": "/l1-contracts/out/console.sol/console.json", - "evmDeployedBytecodeHash": "0x05a5cc84d188bc5c8f296d9c854d7039dd246ef6cd5174379cf7dcf924de2e54", + "evmDeployedBytecodeHash": "0x515abe083fa5a8fc3d632f694566b1d26b3e3f8195ac07db5bba63d36f80e2d3", "zkBytecodeHash": null, "zkBytecodePath": null }, { "contractName": "l1-contracts/safeconsole", - "evmBytecodeHash": "0x8d4a6c561bee25898bd6a5ba365c5eedf9e0a56fc74dea5486c64a59496431f3", + "evmBytecodeHash": "0x5fdd1883cfcaa747780a43d339de8bde29975242895a8f4cdd8ea090d9c486df", "evmBytecodePath": "/l1-contracts/out/safeconsole.sol/safeconsole.json", - "evmDeployedBytecodeHash": "0xe8fbe25dd4a1388b6b3556d52ad8ac9ef7b61f03d1c64371803c3338e725c71e", + "evmDeployedBytecodeHash": "0xa72dd47a684d4d14917f29423b09944910be8950fd904c9266e8b3616cddba5f", "zkBytecodeHash": null, "zkBytecodePath": null }, @@ -1505,89 +1755,9 @@ }, { "contractName": "da-contracts/RollupL1DAValidator", - "evmBytecodeHash": "0x7e1145b2319cf1ed34eef05ffc83c512028b041d2a9fb1f3c8b7277c343f19e8", + "evmBytecodeHash": "0x425b950982bad9b379f923063671748b1cd2870af96eeea3bc2226275ff8e475", "evmBytecodePath": "/da-contracts/out/RollupL1DAValidator.sol/RollupL1DAValidator.json", - "evmDeployedBytecodeHash": "0xfa4af82e0886606f4fad3a4c42ee77fd502defdced7f0a10c98c69f4012b76cc", - "zkBytecodeHash": null, - "zkBytecodePath": null - }, - { - "contractName": "da-contracts/StdConstants", - "evmBytecodeHash": "0xb405ae47fd1be5b2ca33c4b0bd6b3f684f9594ab7c12740804cbdb4adef2b9a5", - "evmBytecodePath": "/da-contracts/out/StdConstants.sol/StdConstants.json", - "evmDeployedBytecodeHash": "0xc603cd0a031bda80abcf61274ee4da920264c22039251bb5c7e45026bd337016", - "zkBytecodeHash": null, - "zkBytecodePath": null - }, - { - "contractName": "da-contracts/stdError", - "evmBytecodeHash": "0x0eea93c4e9c682efeffa05c1625dc9f6001c5a82490d44fd5914d98732cd48be", - "evmBytecodePath": "/da-contracts/out/StdError.sol/stdError.json", - "evmDeployedBytecodeHash": "0xb5d5e7b21dd40f7eff84629ba5145c7baba0414fb7e20740f29f56f8ae676673", - "zkBytecodeHash": null, - "zkBytecodePath": null - }, - { - "contractName": "da-contracts/stdJson", - "evmBytecodeHash": "0xecf866e997649180ad5f4439be3fa821b17a2e2f7d07f1c230cf39d9f4cfcbc0", - "evmBytecodePath": "/da-contracts/out/StdJson.sol/stdJson.json", - "evmDeployedBytecodeHash": "0xd9fbc640e9affb7e03f2e3398d42f243cf88565484789a19859e7d98c66009b7", - "zkBytecodeHash": null, - "zkBytecodePath": null - }, - { - "contractName": "da-contracts/stdMath", - "evmBytecodeHash": "0xbcccf2a80b178d46e29e78907d4a51aa8815c979cd90b1642ac6442ee07247bb", - "evmBytecodePath": "/da-contracts/out/StdMath.sol/stdMath.json", - "evmDeployedBytecodeHash": "0x4ee7a23849443f4b3c8904fef2d2f01c21cb14c12e68631dff3ac14b86b926a1", - "zkBytecodeHash": null, - "zkBytecodePath": null - }, - { - "contractName": "da-contracts/stdStorage", - "evmBytecodeHash": "0xb2b2765e6294045e47fc522db568fabc00debba96b3fdfd3e9d565c282656e86", - "evmBytecodePath": "/da-contracts/out/StdStorage.sol/stdStorage.json", - "evmDeployedBytecodeHash": "0x26b241200223a9b31cf32a9d3ae9a23d6a6902e7e0469378f25b943bfbfe8b0d", - "zkBytecodeHash": null, - "zkBytecodePath": null - }, - { - "contractName": "da-contracts/stdStorageSafe", - "evmBytecodeHash": "0x6876dbb1907681b9bf04c3988eebff3fd1c129e7cd64c8174342220d12da7194", - "evmBytecodePath": "/da-contracts/out/StdStorage.sol/stdStorageSafe.json", - "evmDeployedBytecodeHash": "0x51570eca9872278e04c30834deb88a5b5b7ffb6024c06b7cb745423905accfc3", - "zkBytecodeHash": null, - "zkBytecodePath": null - }, - { - "contractName": "da-contracts/StdStyle", - "evmBytecodeHash": "0xb0abceba2c5835fd86e10e55a0bedab96c8d79ec154c3b5cd0dbcf9b2ce73284", - "evmBytecodePath": "/da-contracts/out/StdStyle.sol/StdStyle.json", - "evmDeployedBytecodeHash": "0xfca84901e84de88820c179c1a55dd75f4ff08a2115af9f200eb5d1ce138207f5", - "zkBytecodeHash": null, - "zkBytecodePath": null - }, - { - "contractName": "da-contracts/stdToml", - "evmBytecodeHash": "0xb8d1d82b7f3f2874d3cd0a4b792aa72b95dbd7713197fdbadc965faccbdef411", - "evmBytecodePath": "/da-contracts/out/StdToml.sol/stdToml.json", - "evmDeployedBytecodeHash": "0xf6533e9d8ca53d05f8f4427062602798e87ca817d0b67bc60a84ae206107bdfc", - "zkBytecodeHash": null, - "zkBytecodePath": null - }, - { - "contractName": "da-contracts/console", - "evmBytecodeHash": "0x595049812a464074f1e1bb1b42b41891d5351667faac9aa53954e8d7788fec11", - "evmBytecodePath": "/da-contracts/out/console.sol/console.json", - "evmDeployedBytecodeHash": "0xd180079e3dbed340a3d341aee16e29cc94ff9c74e2e627f0ea21819105731206", - "zkBytecodeHash": null, - "zkBytecodePath": null - }, - { - "contractName": "da-contracts/safeconsole", - "evmBytecodeHash": "0x52ffde03a93c645a082c5faee36e6c505585e8ced21152265e61eb49590b24e2", - "evmBytecodePath": "/da-contracts/out/safeconsole.sol/safeconsole.json", - "evmDeployedBytecodeHash": "0x396253445cf56426c7f04b051e8b7044eae5240d3cccd659383e5edb803ffa85", + "evmDeployedBytecodeHash": "0xcbc176c09b0c12199dd0359aa75ebed3ff553add6a8f182a7f2a6021434e8d4c", "zkBytecodeHash": null, "zkBytecodePath": null }, @@ -1706,7 +1876,7 @@ { "contractName": "Bootloader", "zkBytecodePath": "/system-contracts/zkout/bootloader_test.yul/Bootloader.json", - "zkBytecodeHash": "0x0100044d2ae0bc6c0d42743bfcc99bfa0b429de9b37eacee30ff2145bff74ef8", + "zkBytecodeHash": "0x01000455a00b5d4609e96c99ab1cbf2427ed4f12a7ba8804fe8fb7d8dc6a66f5", "evmBytecodePath": null, "evmBytecodeHash": null, "evmDeployedBytecodeHash": null @@ -1722,7 +1892,7 @@ { "contractName": "Bootloader", "zkBytecodePath": "/system-contracts/zkout/fee_estimate.yul/Bootloader.json", - "zkBytecodeHash": "0x01000997391d5ddfee336617822423cada0df4df5b1a3a86468bd8aeb95d476f", + "zkBytecodeHash": "0x010009e50882809d10b7df76e573f327244bdd1238e57578235eafcdf76b1799", "evmBytecodePath": null, "evmBytecodeHash": null, "evmDeployedBytecodeHash": null @@ -1730,7 +1900,7 @@ { "contractName": "Bootloader", "zkBytecodePath": "/system-contracts/zkout/gas_test.yul/Bootloader.json", - "zkBytecodeHash": "0x010009032023cdad5a869231ef13278467192d4b0fdd578484381718fe2aa680", + "zkBytecodeHash": "0x0100095183a6a02b9cce6b906fb232eb79251be254b5925fd5a08597178c5e7e", "evmBytecodePath": null, "evmBytecodeHash": null, "evmDeployedBytecodeHash": null @@ -1738,7 +1908,7 @@ { "contractName": "Bootloader", "zkBytecodePath": "/system-contracts/zkout/playground_batch.yul/Bootloader.json", - "zkBytecodeHash": "0x0100099de729834148ebac3d21c83a4b528f6abe757fb8c568a39802cc1e4d80", + "zkBytecodeHash": "0x010009eb0ea5048a028b59adc4c871cbd351ec6c5c31f04ef9f0b4729f7cb778", "evmBytecodePath": null, "evmBytecodeHash": null, "evmDeployedBytecodeHash": null @@ -1746,7 +1916,7 @@ { "contractName": "Bootloader", "zkBytecodePath": "/system-contracts/zkout/proved_batch.yul/Bootloader.json", - "zkBytecodeHash": "0x0100091118d2d6c46d8e646b67026ef848826845d0aff1cb72cddb6b98e4e90c", + "zkBytecodeHash": "0x010009618912f1830c8560fdb5d418583619bbb26d20dc7a620bed5596c1968f", "evmBytecodePath": null, "evmBytecodeHash": null, "evmDeployedBytecodeHash": null diff --git a/docs/chain_management/upgrade_process.md b/docs/chain_management/upgrade_process.md index 634212ac11..54e9c1fdc5 100644 --- a/docs/chain_management/upgrade_process.md +++ b/docs/chain_management/upgrade_process.md @@ -22,7 +22,7 @@ Upgrade information is composed in the form of a [DiamondCutData](../../l1-contr 1. [BaseZkSyncUpgrade](../../l1-contracts/contracts/upgrades/BaseZkSyncUpgrade.sol) - Generic template with function that can be useful for upgrades 2. [DefaultUpgrade](../../l1-contracts/contracts/upgrades/DefaultUpgrade.sol) - Default implementation of the `BaseZkSyncUpgrade`, contract that is most often planned to be used as diamond initialization when doing upgrades. -> Note, that the Gateway upgrade will be more complex than the usual ones and so a similar, but separate [process](<../upgrade_history/gateway_preparation_upgrade/upgrade_process_(no_gateway_chain).md>) will be used for it. It will also use its own custom implementation of the `BaseZkSyncUpgrade`: [GatewayUpgrade](../../l1-contracts/contracts/upgrades/GatewayUpgrade.sol). +> Note, that the Gateway upgrade was more complex than the usual ones and so a similar, but separate [process](<../upgrade_history/gateway_preparation_upgrade/upgrade_process_(no_gateway_chain).md>) was used for it. It was done using its own custom implementation of the `BaseZkSyncUpgrade`: [GatewayUpgrade](https://github.com/matter-labs/era-contracts/blob/14961f1efecac1030139c4cf0655b14135197772/l1-contracts/contracts/upgrades/GatewayUpgrade.sol). ### Protocol version diff --git a/l1-contracts/.env b/l1-contracts/.env index 946080b2c6..69d22c900d 100644 --- a/l1-contracts/.env +++ b/l1-contracts/.env @@ -38,7 +38,9 @@ ETH_SENDER_SENDER_OPERATOR_BLOBS_ETH_ADDR=0x000000000000000000000000000000000000 CONTRACTS_SHARED_BRIDGE_UPGRADE_STORAGE_SWITCH=0 CONTRACTS_MAX_NUMBER_OF_ZK_CHAINS=100 L1_CONFIG=/script-config/config-deploy-l1.toml +CTM_CONFIG=/script-config/config-deploy-ctm.toml L2_CONFIG=/script-config/config-deploy-l2-contracts.toml +CTM_OUTPUT=/script-out/output-deploy-ctm.toml L1_OUTPUT=/script-out/output-deploy-l1.toml L2_CONFIG=/script-config/config-deploy-l2-contracts.toml TOKENS_CONFIG=/script-config/config-deploy-erc20.toml @@ -61,3 +63,4 @@ GATEWAY_VOTE_PREPARATION_INPUT=/script-config/gateway-vote-preparation.toml GATEWAY_VOTE_PREPARATION_OUTPUT=/script-out/gateway-vote-preparation.toml ZK_OS_V28_1_UPGRADE_ECOSYSTEM_INPUT=/script-config/zk-os-v28-1-upgrade-ecosystem.toml ZK_OS_V28_1_UPGRADE_ECOSYSTEM_OUTPUT=/script-out/zk-os-v28-1-upgrade-ecosystem.toml +CONTRACTS_PATH=.. diff --git a/l1-contracts/contracts/bridge/BridgeHelper.sol b/l1-contracts/contracts/bridge/BridgeHelper.sol index bc22e81b23..2fc7fee092 100644 --- a/l1-contracts/contracts/bridge/BridgeHelper.sol +++ b/l1-contracts/contracts/bridge/BridgeHelper.sol @@ -12,7 +12,11 @@ import {DataEncoding} from "../common/libraries/DataEncoding.sol"; * @notice Helper library for working with native tokens on both L1 and L2. */ library BridgeHelper { - /// @dev Receives and parses (name, symbol, decimals) from the token contract + /// @notice Retrieves and encodes token metadata (name, symbol, decimals) for bridging purposes. + /// @dev For ETH_TOKEN_ADDRESS, returns hardcoded ETH metadata. + /// @param _token The token address to query metadata from. + /// @param _originChainId The chain ID where the token originates. + /// @return Encoded token data containing name, symbol, decimals, and origin chain ID. function getERC20Getters(address _token, uint256 _originChainId) internal view returns (bytes memory) { bytes memory name; bytes memory symbol; diff --git a/l1-contracts/contracts/bridge/BridgedStandardERC20.sol b/l1-contracts/contracts/bridge/BridgedStandardERC20.sol index 93817c37f6..2c474841e1 100644 --- a/l1-contracts/contracts/bridge/BridgedStandardERC20.sol +++ b/l1-contracts/contracts/bridge/BridgedStandardERC20.sol @@ -34,8 +34,8 @@ contract BridgedStandardERC20 is ERC20PermitUpgradeable, IBridgedStandardToken, /// @notice OpenZeppelin token represents `name` and `symbol` as storage variables and `decimals` as constant. uint8 private decimals_; - /// @notice The l2Bridge now is deprecated, use the L2AssetRouter and L2NativeTokenVault instead. - /// @dev Address of the L2 bridge that is used as trustee who can mint/burn tokens + /// @notice The l2Bridge is deprecated, use the L2AssetRouter and L2NativeTokenVault instead. + /// @dev Address of the deprecated L2 bridge that was used as trustee to mint/burn tokens address public override l2Bridge; /// @dev Address of the token on its origin chain that can be deposited to mint this bridged token @@ -59,18 +59,14 @@ contract BridgedStandardERC20 is ERC20PermitUpgradeable, IBridgedStandardToken, originToken ); } - if (msg.sender != ntv) { - revert Unauthorized(msg.sender); - } + require(msg.sender == ntv, Unauthorized(msg.sender)); _; } modifier onlyNextVersion(uint8 _version) { // The version should be incremented by 1. Otherwise, the governor risks disabling // future reinitialization of the token by providing too large a version. - if (_version != _getInitializedVersion() + 1) { - revert NonSequentialVersion(); - } + require(_version == _getInitializedVersion() + 1, NonSequentialVersion()); _; } @@ -87,9 +83,7 @@ contract BridgedStandardERC20 is ERC20PermitUpgradeable, IBridgedStandardToken, /// @param _data The additional data that the L1 bridge provide for initialization. /// In this case, it is packed `name`/`symbol`/`decimals` of the L1 token. function bridgeInitialize(bytes32 _assetId, address _originToken, bytes calldata _data) external initializer { - if (_originToken == address(0)) { - revert ZeroAddress(); - } + require(_originToken != address(0), ZeroAddress()); originToken = _originToken; assetId = _assetId; @@ -160,9 +154,7 @@ contract BridgedStandardERC20 is ERC20PermitUpgradeable, IBridgedStandardToken, // It is expected that this token is deployed as a beacon proxy, so we'll // allow the governor of the beacon to reinitialize the token. address beaconAddress = _getBeacon(); - if (msg.sender != UpgradeableBeacon(beaconAddress).owner()) { - revert Unauthorized(msg.sender); - } + require(msg.sender == UpgradeableBeacon(beaconAddress).owner(), Unauthorized(msg.sender)); __ERC20_init_unchained(_newName, _newSymbol); __ERC20Permit_init(_newName); @@ -189,16 +181,22 @@ contract BridgedStandardERC20 is ERC20PermitUpgradeable, IBridgedStandardToken, emit BridgeBurn(_from, _amount); } - /// @dev External function to decode a string from bytes. + /// @notice Decodes a string from ABI-encoded bytes. + /// @param _input The ABI-encoded bytes containing a string. + /// @return result The decoded string. function decodeString(bytes calldata _input) external pure returns (string memory result) { (result) = abi.decode(_input, (string)); } - /// @dev External function to decode a uint8 from bytes. + /// @notice Decodes a uint8 from ABI-encoded bytes. + /// @param _input The ABI-encoded bytes containing a uint8. + /// @return result The decoded uint8 value. function decodeUint8(bytes calldata _input) external pure returns (uint8 result) { (result) = abi.decode(_input, (uint8)); } + /// @notice Returns the token name, reverts if name getter is disabled. + /// @return The token name string. function name() public view override returns (string memory) { // If method is not available, behave like a token that does not implement this method - revert on call. // solhint-disable-next-line reason-string, gas-custom-errors @@ -206,6 +204,8 @@ contract BridgedStandardERC20 is ERC20PermitUpgradeable, IBridgedStandardToken, return super.name(); } + /// @notice Returns the token symbol, reverts if symbol getter is disabled. + /// @return The token symbol string. function symbol() public view override returns (string memory) { // If method is not available, behave like a token that does not implement this method - revert on call. // solhint-disable-next-line reason-string, gas-custom-errors @@ -213,6 +213,8 @@ contract BridgedStandardERC20 is ERC20PermitUpgradeable, IBridgedStandardToken, return super.symbol(); } + /// @notice Returns the token decimals, reverts if decimals getter is disabled. + /// @return The number of decimals for the token. function decimals() public view override returns (uint8) { // If method is not available, behave like a token that does not implement this method - revert on call. // solhint-disable-next-line reason-string, gas-custom-errors diff --git a/l1-contracts/contracts/bridge/L1BridgeContractErrors.sol b/l1-contracts/contracts/bridge/L1BridgeContractErrors.sol index 99c6d87a19..fd55f67e46 100644 --- a/l1-contracts/contracts/bridge/L1BridgeContractErrors.sol +++ b/l1-contracts/contracts/bridge/L1BridgeContractErrors.sol @@ -6,17 +6,17 @@ pragma solidity ^0.8.21; error ClaimFailedDepositFailed(); // 0x066f53b1 error EmptyToken(); -// 0x6d963f88 -error EthTransferFailed(); +// 0x82b0de47 +error EthAlreadyMigratedToL1NTV(); // 0x1c55230b error NativeTokenVaultAlreadySet(); -// 0xfeda3bf8 -error WrongAmountTransferred(uint256 balance, uint256 nullifierChainBalance); +// 0x7ec6d3a1 +error OnlyFailureStatusAllowed(); +// 0x84204265 +error TokenAlreadyInBridgedTokensList(); // 0xb4aeddbc error WrongCounterpart(); // 0x636c90db error WrongL2Sender(address providedL2Sender); // 0x61cdb17e error WrongMsgLength(uint256 expected, uint256 length); -// 0xe4742c42 -error ZeroAmountToTransfer(); diff --git a/l1-contracts/contracts/bridge/L1ERC20Bridge.sol b/l1-contracts/contracts/bridge/L1ERC20Bridge.sol index cdd0e2a133..8b426bc3e7 100644 --- a/l1-contracts/contracts/bridge/L1ERC20Bridge.sol +++ b/l1-contracts/contracts/bridge/L1ERC20Bridge.sol @@ -82,7 +82,7 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { ERA_CHAIN_ID = _eraChainId; } - /// @dev Initializes the reentrancy guard. Expected to be used in the proxy. + /// @notice Initializes the reentrancy guard for the proxy implementation. function initialize() external reentrancyGuardInitializer {} /*////////////////////////////////////////////////////////////// @@ -131,9 +131,7 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { bytes calldata _message, bytes32[] calldata _merkleProof ) external nonReentrant { - if (isWithdrawalFinalized[_l2BatchNumber][_l2MessageIndex]) { - revert WithdrawalAlreadyFinalized(); - } + require(!isWithdrawalFinalized[_l2BatchNumber][_l2MessageIndex], WithdrawalAlreadyFinalized()); // We don't need to set finalizeWithdrawal here, as we set it in the L1 Nullifier FinalizeL1DepositParams memory finalizeWithdrawalParams = FinalizeL1DepositParams({ @@ -149,7 +147,6 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { } /// @notice Initiates a deposit by locking funds on the contract and sending the request - /// @dev Initiates a deposit by locking funds on the contract and sending the request /// of processing an L2 transaction where tokens would be minted /// @dev If the token is bridged for the first time, the L2 token contract will be deployed. Note however, that the /// newly-deployed token does not support any custom logic, i.e. rebase tokens' functionality is not supported. @@ -181,18 +178,12 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { uint256 _l2TxGasPerPubdataByte, address _refundRecipient ) public payable nonReentrant returns (bytes32 l2TxHash) { - if (_amount == 0) { - // empty deposit amount - revert EmptyDeposit(); - } - if (_l1Token == ETH_TOKEN_ADDRESS) { - revert ETHDepositNotSupported(); - } + // empty deposit amount + require(_amount != 0, EmptyDeposit()); + require(_l1Token != ETH_TOKEN_ADDRESS, ETHDepositNotSupported()); uint256 amount = _approveFundsToAssetRouter(msg.sender, IERC20(_l1Token), _amount); - if (amount != _amount) { - // The token has non-standard transfer logic - revert TokensWithFeesNotSupported(); - } + // The token has non-standard transfer logic + require(amount == _amount, TokensWithFeesNotSupported()); l2TxHash = L1_ASSET_ROUTER.depositLegacyErc20Bridge{value: msg.value}({ _originalCaller: msg.sender, @@ -204,9 +195,8 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { _refundRecipient: _refundRecipient }); // Ensuring that all the funds that were locked into this bridge were spent by the asset router / native token vault. - if (IERC20(_l1Token).allowance(address(this), address(L1_ASSET_ROUTER)) != 0) { - revert AssetRouterAllowanceNotZero(); - } + uint256 allowance = IERC20(_l1Token).allowance(address(this), address(L1_ASSET_ROUTER)); + require(allowance == 0, AssetRouterAllowanceNotZero()); depositAmount[msg.sender][_l1Token][l2TxHash] = _amount; emit DepositInitiated({ l2DepositTxHash: l2TxHash, @@ -223,6 +213,9 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { /// @dev Transfers tokens from the depositor address to this contract and force approves those /// to the asset router address. + /// @param _from The address to transfer tokens from. + /// @param _token The ERC20 token to transfer. + /// @param _amount The amount of tokens to transfer. /// @return The difference between the contract balance before and after the transferring of funds. function _approveFundsToAssetRouter(address _from, IERC20 _token, uint256 _amount) internal returns (uint256) { uint256 balanceBefore = _token.balanceOf(address(this)); @@ -252,9 +245,7 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { ) external nonReentrant { uint256 amount = depositAmount[_depositSender][_l1Token][_l2TxHash]; // empty deposit - if (amount == 0) { - revert EmptyDeposit(); - } + require(amount != 0, EmptyDeposit()); delete depositAmount[_depositSender][_l1Token][_l2TxHash]; L1_NULLIFIER.claimFailedDepositLegacyErc20Bridge({ @@ -274,6 +265,8 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { ERA LEGACY GETTERS //////////////////////////////////////////////////////////////*/ + /// @notice Calculates the L2 token address for a given L1 token using CREATE2. + /// @param _l1Token The L1 token address to calculate the L2 counterpart for. /// @return The L2 token address that would be minted for deposit of the given L1 token on ZKsync Era. function l2TokenAddress(address _l1Token) external view returns (address) { bytes32 constructorInputHash = keccak256(abi.encode(l2TokenBeacon, "")); diff --git a/l1-contracts/contracts/bridge/L1Nullifier.sol b/l1-contracts/contracts/bridge/L1Nullifier.sol index 0be9483df0..a9c5562be2 100644 --- a/l1-contracts/contracts/bridge/L1Nullifier.sol +++ b/l1-contracts/contracts/bridge/L1Nullifier.sol @@ -14,21 +14,22 @@ import {IL1NativeTokenVault} from "./ntv/IL1NativeTokenVault.sol"; import {IL1ERC20Bridge} from "./interfaces/IL1ERC20Bridge.sol"; import {IL1AssetRouter} from "./asset-router/IL1AssetRouter.sol"; - -import {FinalizeL1DepositParams, IL1Nullifier} from "./interfaces/IL1Nullifier.sol"; +import {FinalizeL1DepositParams, IL1Nullifier, TRANSIENT_SETTLEMENT_LAYER_SLOT} from "./interfaces/IL1Nullifier.sol"; import {IGetters} from "../state-transition/chain-interfaces/IGetters.sol"; import {IMailboxImpl} from "../state-transition/chain-interfaces/IMailboxImpl.sol"; -import {L2Message, TxStatus} from "../common/Messaging.sol"; -import {UnsafeBytes} from "../common/libraries/UnsafeBytes.sol"; +import {L2Log, L2Message, TxStatus, ConfirmTransferResultData} from "../common/Messaging.sol"; import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; import {ETH_TOKEN_ADDRESS} from "../common/Config.sol"; import {DataEncoding} from "../common/libraries/DataEncoding.sol"; import {IL1Bridgehub} from "../bridgehub/IL1Bridgehub.sol"; import {L2_ASSET_ROUTER_ADDR, L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; -import {AddressAlreadySet, DepositDoesNotExist, DepositExists, InvalidProof, InvalidSelector, L2WithdrawalMessageWrongLength, LegacyBridgeNotSet, LegacyMethodForNonL1Token, SharedBridgeKey, SharedBridgeValueNotSet, TokenNotLegacy, Unauthorized, WithdrawalAlreadyFinalized, ZeroAddress} from "../common/L1ContractErrors.sol"; -import {EthTransferFailed, NativeTokenVaultAlreadySet, WrongL2Sender, WrongMsgLength} from "./L1BridgeContractErrors.sol"; +import {AddressAlreadySet, DepositDoesNotExist, DepositExists, InvalidProof, InvalidSelector, LegacyBridgeNotSet, LegacyMethodForNonL1Token, SharedBridgeKey, SharedBridgeValueNotSet, TokenNotLegacy, Unauthorized, WithdrawalAlreadyFinalized, ZeroAddress} from "../common/L1ContractErrors.sol"; +import {EthAlreadyMigratedToL1NTV, NativeTokenVaultAlreadySet, WrongL2Sender} from "./L1BridgeContractErrors.sol"; +import {MessageHashing, ProofData} from "../common/libraries/MessageHashing.sol"; +import {TransientPrimitivesLib} from "../common/libraries/TransientPrimitives/TransientPrimitives.sol"; +import {IMessageRoot} from "../bridgehub/IMessageRoot.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -46,6 +47,9 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, /// @dev The address of ZKsync Era diamond proxy contract. address internal immutable ERA_DIAMOND_PROXY; + /// @dev MessageRoot smart contract that is used to prove message inclusion. + IMessageRoot public immutable MESSAGE_ROOT; + /// @dev Stores the first batch number on the ZKsync Era Diamond Proxy that was settled after Diamond proxy upgrade. /// This variable is used to differentiate between pre-upgrade and post-upgrade Eth withdrawals. Withdrawals from batches older /// than this value are considered to have been finalized prior to the upgrade and handled separately. @@ -111,33 +115,33 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, /// @notice Checks that the message sender is the asset router.. modifier onlyAssetRouter() { - if (msg.sender != address(l1AssetRouter)) { - revert Unauthorized(msg.sender); - } + require(msg.sender == address(l1AssetRouter), Unauthorized(msg.sender)); _; } /// @notice Checks that the message sender is the native token vault. modifier onlyL1NTV() { - if (msg.sender != address(l1NativeTokenVault)) { - revert Unauthorized(msg.sender); - } + require(msg.sender == address(l1NativeTokenVault), Unauthorized(msg.sender)); _; } /// @notice Checks that the message sender is the legacy bridge. modifier onlyLegacyBridge() { - if (msg.sender != address(legacyBridge)) { - revert Unauthorized(msg.sender); - } + require(msg.sender == address(legacyBridge), Unauthorized(msg.sender)); _; } /// @dev Contract is expected to be used as proxy implementation. /// @dev Initialize the implementation to prevent Parity hack. - constructor(IL1Bridgehub _bridgehub, uint256 _eraChainId, address _eraDiamondProxy) reentrancyGuardInitializer { + constructor( + IL1Bridgehub _bridgehub, + IMessageRoot _messageRoot, + uint256 _eraChainId, + address _eraDiamondProxy + ) reentrancyGuardInitializer { _disableInitializers(); BRIDGE_HUB = _bridgehub; + MESSAGE_ROOT = _messageRoot; ERA_CHAIN_ID = _eraChainId; ERA_DIAMOND_PROXY = _eraDiamondProxy; } @@ -157,9 +161,7 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, uint256 _eraLegacyBridgeLastDepositBatch, uint256 _eraLegacyBridgeLastDepositTxNumber ) external reentrancyGuardInitializer initializer { - if (_owner == address(0)) { - revert ZeroAddress(); - } + require(_owner != address(0), ZeroAddress()); _transferOwnership(_owner); if (eraPostDiamondUpgradeFirstBatch == 0) { eraPostDiamondUpgradeFirstBatch = _eraPostDiamondUpgradeFirstBatch; @@ -175,15 +177,7 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, function transferTokenToNTV(address _token) external onlyL1NTV { address ntvAddress = address(l1NativeTokenVault); if (ETH_TOKEN_ADDRESS == _token) { - uint256 amount = address(this).balance; - bool callSuccess; - // Low-level assembly call, to avoid any memory copying (save gas) - assembly { - callSuccess := call(gas(), ntvAddress, amount, 0, 0, 0, 0) - } - if (!callSuccess) { - revert EthTransferFailed(); - } + revert EthAlreadyMigratedToL1NTV(); } else { IERC20(_token).safeTransfer(ntvAddress, IERC20(_token).balanceOf(address(this))); } @@ -206,8 +200,10 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, } /// @notice Legacy function used for migration, do not use! + /// @dev Returns the deprecated chain balance for backwards compatibility. /// @param _chainId The chain id we want to get the balance for. /// @param _token The address of the token. + /// @return The balance of the token on the specified chain (deprecated). // slither-disable-next-line uninitialized-state-variables function chainBalance(uint256 _chainId, address _token) external view returns (uint256) { // slither-disable-next-line uninitialized-state-variables @@ -218,12 +214,8 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, /// @dev Should be called only once by the owner. /// @param _legacyBridge The address of the legacy bridge. function setL1Erc20Bridge(IL1ERC20Bridge _legacyBridge) external onlyOwner { - if (address(legacyBridge) != address(0)) { - revert AddressAlreadySet(address(legacyBridge)); - } - if (address(_legacyBridge) == address(0)) { - revert ZeroAddress(); - } + require(address(legacyBridge) == address(0), AddressAlreadySet(address(legacyBridge))); + require(address(_legacyBridge) != address(0), ZeroAddress()); legacyBridge = _legacyBridge; } @@ -231,12 +223,8 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, /// @dev Should be called only once by the owner. /// @param _l1NativeTokenVault The address of the native token vault. function setL1NativeTokenVault(IL1NativeTokenVault _l1NativeTokenVault) external onlyOwner { - if (address(l1NativeTokenVault) != address(0)) { - revert NativeTokenVaultAlreadySet(); - } - if (address(_l1NativeTokenVault) == address(0)) { - revert ZeroAddress(); - } + require(address(l1NativeTokenVault) == address(0), NativeTokenVaultAlreadySet()); + require(address(_l1NativeTokenVault) != address(0), ZeroAddress()); l1NativeTokenVault = _l1NativeTokenVault; } @@ -244,12 +232,8 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, /// @dev Should be called only once by the owner. /// @param _l1AssetRouter The address of the asset router. function setL1AssetRouter(address _l1AssetRouter) external onlyOwner { - if (address(l1AssetRouter) != address(0)) { - revert AddressAlreadySet(address(l1AssetRouter)); - } - if (_l1AssetRouter == address(0)) { - revert ZeroAddress(); - } + require(address(l1AssetRouter) == address(0), AddressAlreadySet(address(l1AssetRouter))); + require(_l1AssetRouter != address(0), ZeroAddress()); l1AssetRouter = IL1AssetRouter(_l1AssetRouter); } @@ -263,14 +247,12 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, bytes32 _txDataHash, bytes32 _txHash ) external override onlyAssetRouter whenNotPaused { - if (depositHappened[_chainId][_txHash] != 0x00) { - revert DepositExists(); - } + require(depositHappened[_chainId][_txHash] == 0x00, DepositExists()); depositHappened[_chainId][_txHash] = _txDataHash; emit BridgehubDepositFinalized(_chainId, _txDataHash, _txHash); } - /// @dev Calls the library `encodeTxDataHash`. Used as a wrapped for try / catch case. + /// @dev Calls the library `encodeTxDataHash`. Used as a wrapper for try / catch case. /// @dev Encodes the transaction data hash using either the latest encoding standard or the legacy standard. /// @param _encodingVersion EncodingVersion. /// @param _originalCaller The address of the entity that initiated the deposit. @@ -292,6 +274,19 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, }); } + function bridgeConfirmTransferResult( + ConfirmTransferResultData memory _confirmTransferResultData + ) public nonReentrant { + _verifyAndClearTransfer(false, _confirmTransferResultData); + l1AssetRouter.bridgeConfirmTransferResult({ + _chainId: _confirmTransferResultData._chainId, + _txStatus: _confirmTransferResultData._txStatus, + _depositSender: _confirmTransferResultData._depositSender, + _assetId: _confirmTransferResultData._assetId, + _assetData: _confirmTransferResultData._assetData + }); + } + /// @inheritdoc IL1Nullifier function bridgeRecoverFailedTransfer( uint256 _chainId, @@ -304,64 +299,77 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, uint16 _l2TxNumberInBatch, bytes32[] calldata _merkleProof ) public nonReentrant { - _verifyAndClearFailedTransfer({ - _checkedInLegacyBridge: false, + _verifyAndClearTransfer( + false, + ConfirmTransferResultData({ + _chainId: _chainId, + _depositSender: _depositSender, + _assetId: _assetId, + _assetData: _assetData, + _l2TxHash: _l2TxHash, + _l2BatchNumber: _l2BatchNumber, + _l2MessageIndex: _l2MessageIndex, + _l2TxNumberInBatch: _l2TxNumberInBatch, + _merkleProof: _merkleProof, + _txStatus: TxStatus.Failure + }) + ); + + l1AssetRouter.bridgeConfirmTransferResult({ _chainId: _chainId, + _txStatus: TxStatus.Failure, _depositSender: _depositSender, _assetId: _assetId, - _assetData: _assetData, - _l2TxHash: _l2TxHash, - _l2BatchNumber: _l2BatchNumber, - _l2MessageIndex: _l2MessageIndex, - _l2TxNumberInBatch: _l2TxNumberInBatch, - _merkleProof: _merkleProof + _assetData: _assetData }); - - l1AssetRouter.bridgeRecoverFailedTransfer(_chainId, _depositSender, _assetId, _assetData); } /// @dev Withdraw funds from the initiated deposit, that failed when finalizing on L2. - /// @param _chainId The ZK chain id to which deposit was initiated. - /// @param _depositSender The address of the entity that initiated the deposit. - /// @param _assetId The unique identifier of the deposited L1 token. - /// @param _assetData The encoded data, which is used by the asset handler to determine L2 recipient and amount. Might include extra information. - /// @param _l2TxHash The L2 transaction hash of the failed deposit finalization. - /// @param _l2BatchNumber The L2 batch number where the deposit finalization was processed. - /// @param _l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message. - /// @param _l2TxNumberInBatch The L2 transaction number in a batch, in which the log was sent. - /// @param _merkleProof The Merkle proof of the processing L1 -> L2 transaction with deposit finalization. + /// @param _checkedInLegacyBridge Whether the deposit was already checked in the legacy bridge system. + /// @param _confirmTransferResultData The data for confirming the transfer result. /// @dev Processes claims of failed deposit, whether they originated from the legacy bridge or the current system. - function _verifyAndClearFailedTransfer( + function _verifyAndClearTransfer( bool _checkedInLegacyBridge, - uint256 _chainId, - address _depositSender, - bytes32 _assetId, - bytes memory _assetData, - bytes32 _l2TxHash, - uint256 _l2BatchNumber, - uint256 _l2MessageIndex, - uint16 _l2TxNumberInBatch, - bytes32[] calldata _merkleProof + ConfirmTransferResultData memory _confirmTransferResultData ) internal whenNotPaused { { - bool proofValid = BRIDGE_HUB.proveL1ToL2TransactionStatus({ - _chainId: _chainId, - _l2TxHash: _l2TxHash, - _l2BatchNumber: _l2BatchNumber, - _l2MessageIndex: _l2MessageIndex, - _l2TxNumberInBatch: _l2TxNumberInBatch, - _merkleProof: _merkleProof, - _status: TxStatus.Failure + bool proofValid = MESSAGE_ROOT.proveL1ToL2TransactionStatusShared({ + _chainId: _confirmTransferResultData._chainId, + _l2TxHash: _confirmTransferResultData._l2TxHash, + _l2BatchNumber: _confirmTransferResultData._l2BatchNumber, + _l2MessageIndex: _confirmTransferResultData._l2MessageIndex, + _l2TxNumberInBatch: _confirmTransferResultData._l2TxNumberInBatch, + _merkleProof: _confirmTransferResultData._merkleProof, + _status: _confirmTransferResultData._txStatus }); - if (!proofValid) { - revert InvalidProof(); - } + require(proofValid, InvalidProof()); + L2Log memory l2Log = MessageHashing.getL2LogFromL1ToL2Transaction( + _confirmTransferResultData._l2TxNumberInBatch, + _confirmTransferResultData._l2TxHash, + _confirmTransferResultData._txStatus + ); + + bytes32 leaf = MessageHashing.getLeafHashFromLog(l2Log); + ProofData memory proofData = MESSAGE_ROOT.getProofData({ + _chainId: _confirmTransferResultData._chainId, + _batchNumber: _confirmTransferResultData._l2BatchNumber, + _leafProofMask: _confirmTransferResultData._l2MessageIndex, + _leaf: leaf, + _proof: _confirmTransferResultData._merkleProof + }); + TransientPrimitivesLib.set(TRANSIENT_SETTLEMENT_LAYER_SLOT, proofData.settlementLayerChainId); + TransientPrimitivesLib.set(TRANSIENT_SETTLEMENT_LAYER_SLOT + 1, _confirmTransferResultData._l2BatchNumber); + emit TransientSettlementLayerSet(proofData.settlementLayerChainId); } bool notCheckedInLegacyBridgeOrWeCanCheckDeposit; { // Deposits that happened before the upgrade cannot be checked here, they have to be claimed and checked in the legacyBridge - bool weCanCheckDepositHere = !_isPreSharedBridgeDepositOnEra(_chainId, _l2BatchNumber, _l2TxNumberInBatch); + bool weCanCheckDepositHere = !_isPreSharedBridgeDepositOnEra( + _confirmTransferResultData._chainId, + _confirmTransferResultData._l2BatchNumber, + _confirmTransferResultData._l2TxNumberInBatch + ); // Double claims are not possible, as depositHappened is checked here for all except legacy deposits (which have to happen through the legacy bridge) // Funds claimed before the update will still be recorded in the legacy bridge // Note we double check NEW deposits if they are called from the legacy bridge @@ -369,25 +377,32 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, } if (notCheckedInLegacyBridgeOrWeCanCheckDeposit) { - bytes32 dataHash = depositHappened[_chainId][_l2TxHash]; + bytes32 dataHash = depositHappened[_confirmTransferResultData._chainId][ + _confirmTransferResultData._l2TxHash + ]; // Determine if the given dataHash matches the calculated legacy transaction hash. - bool isLegacyTxDataHash = _isLegacyTxDataHash(_depositSender, _assetId, _assetData, dataHash); + bool isLegacyTxDataHash = _isLegacyTxDataHash( + _confirmTransferResultData._depositSender, + _confirmTransferResultData._assetId, + _confirmTransferResultData._assetData, + dataHash + ); // If the dataHash matches the legacy transaction hash, skip the next step. // Otherwise, perform the check using the new transaction data hash encoding. if (!isLegacyTxDataHash) { bytes32 txDataHash = DataEncoding.encodeTxDataHash({ _encodingVersion: NEW_ENCODING_VERSION, - _originalCaller: _depositSender, - _assetId: _assetId, + _originalCaller: _confirmTransferResultData._depositSender, + _assetId: _confirmTransferResultData._assetId, _nativeTokenVault: address(l1NativeTokenVault), - _transferData: _assetData + _transferData: _confirmTransferResultData._assetData }); if (dataHash != txDataHash) { - revert DepositDoesNotExist(); + revert DepositDoesNotExist(dataHash, txDataHash); } } } - delete depositHappened[_chainId][_l2TxHash]; + delete depositHappened[_confirmTransferResultData._chainId][_confirmTransferResultData._l2TxHash]; } /// @notice Finalize the withdrawal and release funds. @@ -406,9 +421,7 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, uint256 chainId = _finalizeWithdrawalParams.chainId; uint256 l2BatchNumber = _finalizeWithdrawalParams.l2BatchNumber; uint256 l2MessageIndex = _finalizeWithdrawalParams.l2MessageIndex; - if (isWithdrawalFinalized[chainId][l2BatchNumber][l2MessageIndex]) { - revert WithdrawalAlreadyFinalized(); - } + require(!isWithdrawalFinalized[chainId][l2BatchNumber][l2MessageIndex], WithdrawalAlreadyFinalized()); isWithdrawalFinalized[chainId][l2BatchNumber][l2MessageIndex] = true; (bytes32 assetId, bytes memory transferData) = _verifyWithdrawal(_finalizeWithdrawalParams); @@ -417,14 +430,10 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, if (_isPreSharedBridgeEraEthWithdrawal(chainId, l2BatchNumber)) { // Checks that the withdrawal wasn't finalized already. bool alreadyFinalized = IGetters(ERA_DIAMOND_PROXY).isEthWithdrawalFinalized(l2BatchNumber, l2MessageIndex); - if (alreadyFinalized) { - revert WithdrawalAlreadyFinalized(); - } + require(!alreadyFinalized, WithdrawalAlreadyFinalized()); } if (_isPreSharedBridgeEraTokenWithdrawal(chainId, l2BatchNumber)) { - if (legacyBridge.isWithdrawalFinalized(l2BatchNumber, l2MessageIndex)) { - revert WithdrawalAlreadyFinalized(); - } + require(!legacyBridge.isWithdrawalFinalized(l2BatchNumber, l2MessageIndex), WithdrawalAlreadyFinalized()); } AssetRouterBase(address(l1AssetRouter)).finalizeDeposit(chainId, assetId, transferData); @@ -499,7 +508,7 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, /// @notice Verifies the validity of a withdrawal message from L2 and returns withdrawal details. /// @param _finalizeWithdrawalParams The structure that holds all necessary data to finalize withdrawal /// @return assetId The ID of the bridged asset. - /// @return transferData The transfer data used to finalize withdawal. + /// @return transferData The transfer data used to finalize withdrawal. function _verifyWithdrawal( FinalizeL1DepositParams memory _finalizeWithdrawalParams ) internal returns (bytes32 assetId, bytes memory transferData) { @@ -515,9 +524,7 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, bool isL2SenderCorrect = l2Sender == L2_ASSET_ROUTER_ADDR || l2Sender == L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR || l2Sender == __DEPRECATED_l2BridgeAddress[_finalizeWithdrawalParams.chainId]; - if (!isL2SenderCorrect) { - revert WrongL2Sender(l2Sender); - } + require(isL2SenderCorrect, WrongL2Sender(l2Sender)); l2ToL1Message = L2Message({ txNumberInBatch: _finalizeWithdrawalParams.l2TxNumberInBatch, @@ -526,17 +533,35 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, }); } - bool success = BRIDGE_HUB.proveL2MessageInclusion({ + bool success = MESSAGE_ROOT.proveL2MessageInclusionShared({ _chainId: _finalizeWithdrawalParams.chainId, - _batchNumber: _finalizeWithdrawalParams.l2BatchNumber, + _blockOrBatchNumber: _finalizeWithdrawalParams.l2BatchNumber, _index: _finalizeWithdrawalParams.l2MessageIndex, _message: l2ToL1Message, _proof: _finalizeWithdrawalParams.merkleProof }); // withdrawal wrong proof - if (!success) { - revert InvalidProof(); - } + require(success, InvalidProof()); + + bytes32 leaf = MessageHashing.getLeafHashFromMessage(l2ToL1Message); + ProofData memory proofData = MESSAGE_ROOT.getProofData({ + _chainId: _finalizeWithdrawalParams.chainId, + _batchNumber: _finalizeWithdrawalParams.l2BatchNumber, + _leafProofMask: _finalizeWithdrawalParams.l2MessageIndex, + _leaf: leaf, + _proof: _finalizeWithdrawalParams.merkleProof + }); + TransientPrimitivesLib.set(TRANSIENT_SETTLEMENT_LAYER_SLOT, proofData.settlementLayerChainId); + TransientPrimitivesLib.set(TRANSIENT_SETTLEMENT_LAYER_SLOT + 1, _finalizeWithdrawalParams.l2BatchNumber); + emit TransientSettlementLayerSet(proofData.settlementLayerChainId); + } + + /// @inheritdoc IL1Nullifier + function getTransientSettlementLayer() external view returns (uint256, uint256) { + return ( + TransientPrimitivesLib.getUint256(TRANSIENT_SETTLEMENT_LAYER_SLOT), + TransientPrimitivesLib.getUint256(TRANSIENT_SETTLEMENT_LAYER_SLOT + 1) + ); } /// @notice Parses the withdrawal message and returns withdrawal details. @@ -545,7 +570,7 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, /// @param _chainId The ZK chain ID. /// @param _l2ToL1message The encoded L2 -> L1 message. /// @return assetId The ID of the bridged asset. - /// @return transferData The transfer data used to finalize withdawal. + /// @return transferData The transfer data used to finalize withdrawal. function _parseL2WithdrawalMessage( uint256 _chainId, bytes memory _l2ToL1message @@ -558,16 +583,10 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, uint256 amount; address l1Receiver; - (uint32 functionSignature, uint256 offset) = UnsafeBytes.readUint32(_l2ToL1message, 0); - if (bytes4(functionSignature) == IMailboxImpl.finalizeEthWithdrawal.selector) { - // The data is expected to be at least 56 bytes long. - if (_l2ToL1message.length < 56) { - revert L2WithdrawalMessageWrongLength(_l2ToL1message.length); - } - // this message is a base token withdrawal - (l1Receiver, offset) = UnsafeBytes.readAddress(_l2ToL1message, offset); + bytes4 functionSignature = DataEncoding.getSelector(_l2ToL1message); + if (functionSignature == IMailboxImpl.finalizeEthWithdrawal.selector) { // slither-disable-next-line unused-return - (amount, ) = UnsafeBytes.readUint256(_l2ToL1message, offset); + (, l1Receiver, amount) = DataEncoding.decodeBaseTokenFinalizeWithdrawalData(_l2ToL1message); assetId = BRIDGE_HUB.baseTokenAssetId(_chainId); transferData = DataEncoding.encodeBridgeMintData({ _originalCaller: address(0), @@ -580,44 +599,19 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, _amount: amount, _erc20Metadata: new bytes(0) }); - } else if (bytes4(functionSignature) == IL1ERC20Bridge.finalizeWithdrawal.selector) { + } else if (functionSignature == IL1ERC20Bridge.finalizeWithdrawal.selector) { // this message is a token withdrawal - - // Check that the message length is correct. - // It should be equal to the length of the function signature + address + address + uint256 = 4 + 20 + 20 + 32 = - // 76 (bytes). - if (_l2ToL1message.length != 76) { - revert L2WithdrawalMessageWrongLength(_l2ToL1message.length); - } - (l1Receiver, offset) = UnsafeBytes.readAddress(_l2ToL1message, offset); - // We use the IL1ERC20Bridge for backward compatibility with old withdrawals. address l1Token; - (l1Token, offset) = UnsafeBytes.readAddress(_l2ToL1message, offset); // slither-disable-next-line unused-return - (amount, ) = UnsafeBytes.readUint256(_l2ToL1message, offset); + (, l1Token, transferData) = DataEncoding.decodeLegacyFinalizeWithdrawalData(_l2ToL1message); assetId = l1NativeTokenVault.ensureTokenIsRegistered(l1Token); bytes32 expectedAssetId = DataEncoding.encodeNTVAssetId(block.chainid, l1Token); // This method is only expected to use L1-based tokens. - if (assetId != expectedAssetId) { - revert TokenNotLegacy(); - } - transferData = DataEncoding.encodeBridgeMintData({ - _originalCaller: address(0), - _remoteReceiver: l1Receiver, - _originToken: l1Token, - _amount: amount, - _erc20Metadata: new bytes(0) - }); - } else if (bytes4(functionSignature) == AssetRouterBase.finalizeDeposit.selector) { - // The data is expected to be at least 68 bytes long to contain assetId. - if (_l2ToL1message.length < 68) { - revert WrongMsgLength(68, _l2ToL1message.length); - } + require(assetId == expectedAssetId, TokenNotLegacy()); + } else if (functionSignature == AssetRouterBase.finalizeDeposit.selector) { // slither-disable-next-line unused-return - (, offset) = UnsafeBytes.readUint256(_l2ToL1message, offset); // originChainId, not used for L2->L1 txs - (assetId, offset) = UnsafeBytes.readBytes32(_l2ToL1message, offset); - transferData = UnsafeBytes.readRemainingBytes(_l2ToL1message, offset); + (, , assetId, transferData) = DataEncoding.decodeAssetRouterFinalizeDepositData(_l2ToL1message); } else { revert InvalidSelector(bytes4(functionSignature)); } @@ -659,21 +653,26 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, // The token address does not have to be provided for this functionality either. bytes memory assetData = DataEncoding.encodeBridgeBurnData(_amount, address(0), address(0)); - _verifyAndClearFailedTransfer({ - _checkedInLegacyBridge: false, - _depositSender: _depositSender, - _chainId: _chainId, - _assetId: assetId, - _assetData: assetData, - _l2TxHash: _l2TxHash, - _l2BatchNumber: _l2BatchNumber, - _l2MessageIndex: _l2MessageIndex, - _l2TxNumberInBatch: _l2TxNumberInBatch, - _merkleProof: _merkleProof - }); + { + ConfirmTransferResultData memory confirmTransferResultData = ConfirmTransferResultData({ + _depositSender: _depositSender, + _chainId: _chainId, + _assetId: assetId, + _assetData: assetData, + _l2TxHash: _l2TxHash, + _l2BatchNumber: _l2BatchNumber, + _l2MessageIndex: _l2MessageIndex, + _l2TxNumberInBatch: _l2TxNumberInBatch, + _merkleProof: _merkleProof, + _txStatus: TxStatus.Failure + }); - l1AssetRouter.bridgeRecoverFailedTransfer({ + _verifyAndClearTransfer(false, confirmTransferResultData); + } + + l1AssetRouter.bridgeConfirmTransferResult({ _chainId: _chainId, + _txStatus: TxStatus.Failure, _depositSender: _depositSender, _assetId: assetId, _assetData: assetData @@ -713,21 +712,25 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, /// the legacy bridge can only be used with L1 native tokens. bytes32 assetId = DataEncoding.encodeNTVAssetId(block.chainid, _l1Token); - _verifyAndClearFailedTransfer({ - _checkedInLegacyBridge: true, - _depositSender: _depositSender, - _chainId: ERA_CHAIN_ID, - _assetId: assetId, - _assetData: assetData, - _l2TxHash: _l2TxHash, - _l2BatchNumber: _l2BatchNumber, - _l2MessageIndex: _l2MessageIndex, - _l2TxNumberInBatch: _l2TxNumberInBatch, - _merkleProof: _merkleProof - }); + _verifyAndClearTransfer( + true, + ConfirmTransferResultData({ + _depositSender: _depositSender, + _chainId: ERA_CHAIN_ID, + _assetId: assetId, + _assetData: assetData, + _l2TxHash: _l2TxHash, + _l2BatchNumber: _l2BatchNumber, + _l2MessageIndex: _l2MessageIndex, + _l2TxNumberInBatch: _l2TxNumberInBatch, + _merkleProof: _merkleProof, + _txStatus: TxStatus.Failure + }) + ); - l1AssetRouter.bridgeRecoverFailedTransfer({ + l1AssetRouter.bridgeConfirmTransferResult({ _chainId: ERA_CHAIN_ID, + _txStatus: TxStatus.Failure, _depositSender: _depositSender, _assetId: assetId, _assetData: assetData @@ -764,9 +767,7 @@ contract L1Nullifier is IL1Nullifier, ReentrancyGuard, Ownable2StepUpgradeable, /// @dev We use a deprecated field to support L2->L1 legacy withdrawals, which were started /// by the legacy bridge. address legacyL2Bridge = __DEPRECATED_l2BridgeAddress[_chainId]; - if (legacyL2Bridge == address(0)) { - revert LegacyBridgeNotSet(); - } + require(legacyL2Bridge != address(0), LegacyBridgeNotSet()); FinalizeL1DepositParams memory finalizeWithdrawalParams = FinalizeL1DepositParams({ chainId: _chainId, diff --git a/l1-contracts/contracts/bridge/L2SharedBridgeLegacy.sol b/l1-contracts/contracts/bridge/L2SharedBridgeLegacy.sol index fea683a57b..c986c01650 100644 --- a/l1-contracts/contracts/bridge/L2SharedBridgeLegacy.sol +++ b/l1-contracts/contracts/bridge/L2SharedBridgeLegacy.sol @@ -16,7 +16,7 @@ import {IL2AssetRouter} from "./asset-router/IL2AssetRouter.sol"; import {IL2NativeTokenVault} from "./ntv/IL2NativeTokenVault.sol"; import {IL2SharedBridgeLegacy} from "./interfaces/IL2SharedBridgeLegacy.sol"; -import {AmountMustBeGreaterThanZero, DeployFailed, EmptyBytes32, InvalidCaller, Unauthorized, ZeroAddress} from "../common/L1ContractErrors.sol"; +import {AmountMustBeGreaterThanZero, DeployFailed, EmptyBytes32, Unauthorized, ZeroAddress} from "../common/L1ContractErrors.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -44,16 +44,12 @@ contract L2SharedBridgeLegacy is IL2SharedBridgeLegacy, Initializable { address public override l1Bridge; modifier onlyNTV() { - if (msg.sender != L2_NATIVE_TOKEN_VAULT_ADDR) { - revert Unauthorized(msg.sender); - } + require(msg.sender == L2_NATIVE_TOKEN_VAULT_ADDR, Unauthorized(msg.sender)); _; } modifier onlyAssetRouter() { - if (msg.sender != L2_ASSET_ROUTER_ADDR) { - revert Unauthorized(msg.sender); - } + require(msg.sender == L2_ASSET_ROUTER_ADDR, Unauthorized(msg.sender)); _; } @@ -70,17 +66,11 @@ contract L2SharedBridgeLegacy is IL2SharedBridgeLegacy, Initializable { bytes32 _l2TokenProxyBytecodeHash, address _aliasedOwner ) external reinitializer(2) { - if (_l1SharedBridge == address(0)) { - revert ZeroAddress(); - } + require(_l1SharedBridge != address(0), ZeroAddress()); - if (_l2TokenProxyBytecodeHash == bytes32(0)) { - revert EmptyBytes32(); - } + require(_l2TokenProxyBytecodeHash != bytes32(0), EmptyBytes32()); - if (_aliasedOwner == address(0)) { - revert ZeroAddress(); - } + require(_aliasedOwner != address(0), ZeroAddress()); l1SharedBridge = _l1SharedBridge; @@ -95,21 +85,19 @@ contract L2SharedBridgeLegacy is IL2SharedBridgeLegacy, Initializable { } } - /// @notice Initiates a withdrawal by burning funds on the contract and sending the message to L1 + /// @notice Initiates a withdrawal by burning funds and sending the message to L1 /// where tokens would be unlocked /// @param _l1Receiver The account address that should receive funds on L1 /// @param _l2Token The L2 token address which is withdrawn /// @param _amount The total amount of tokens to be withdrawn function withdraw(address _l1Receiver, address _l2Token, uint256 _amount) external override { - if (_amount == 0) { - revert AmountMustBeGreaterThanZero(); - } + require(_amount != 0, AmountMustBeGreaterThanZero()); IL2AssetRouter(L2_ASSET_ROUTER_ADDR).withdrawLegacyBridge(_l1Receiver, _l2Token, _amount, msg.sender); } /// @notice Finalize the deposit and mint funds /// @param _l1Sender The account address that initiated the deposit on L1 - /// @param _l2Receiver The account address that would receive minted ether + /// @param _l2Receiver The account address that would receive minted tokens /// @param _l1Token The address of the token that was locked on the L1 /// @param _amount Total amount of tokens deposited from L1 /// @param _data The additional data that user can pass with the deposit @@ -125,7 +113,7 @@ contract L2SharedBridgeLegacy is IL2SharedBridgeLegacy, Initializable { AddressAliasHelper.undoL1ToL2Alias(msg.sender) != l1Bridge && AddressAliasHelper.undoL1ToL2Alias(msg.sender) != l1SharedBridge ) { - revert InvalidCaller(msg.sender); + revert Unauthorized(msg.sender); } IL2AssetRouter(L2_ASSET_ROUTER_ADDR).finalizeDepositLegacyBridge({ @@ -169,9 +157,11 @@ contract L2SharedBridgeLegacy is IL2SharedBridgeLegacy, Initializable { salt = bytes32(uint256(uint160(_l1Token))); } - /// @dev Deploy the beacon proxy for the L2 token, while using ContractDeployer system contract. + /// @notice Deploys a beacon proxy for an L2 token using the ContractDeployer system contract. /// @dev This function uses raw call to ContractDeployer to make sure that exactly `l2TokenProxyBytecodeHash` is used /// for the code of the proxy. + /// @param salt The salt used for CREATE2 deployment to ensure deterministic addresses. + /// @return proxy The address of the deployed beacon proxy contract. function deployBeaconProxy(bytes32 salt) external onlyNTV returns (address proxy) { (bool success, bytes memory returndata) = SystemContractsCaller.systemCallWithReturndata( uint32(gasleft()), @@ -184,12 +174,13 @@ contract L2SharedBridgeLegacy is IL2SharedBridgeLegacy, Initializable { ); // The deployment should be successful and return the address of the proxy - if (!success) { - revert DeployFailed(); - } + require(success, DeployFailed()); proxy = abi.decode(returndata, (address)); } + /// @notice Sends a message from to L1. + /// @param _message The message data to send to L1. + /// @return The hash of the sent message. function sendMessageToL1(bytes calldata _message) external override onlyAssetRouter returns (bytes32) { // slither-disable-next-line unused-return return L2ContractHelper.sendMessageToL1(_message); diff --git a/l1-contracts/contracts/bridge/L2WrappedBaseToken.sol b/l1-contracts/contracts/bridge/L2WrappedBaseToken.sol index 38b056ed86..06116685b8 100644 --- a/l1-contracts/contracts/bridge/L2WrappedBaseToken.sol +++ b/l1-contracts/contracts/bridge/L2WrappedBaseToken.sol @@ -37,9 +37,7 @@ contract L2WrappedBaseToken is ERC20PermitUpgradeable, IL2WrappedBaseToken, IBri bytes32 public baseTokenAssetId; modifier onlyBridge() { - if (msg.sender != l2Bridge) { - revert Unauthorized(msg.sender); - } + require(msg.sender == l2Bridge, Unauthorized(msg.sender)); _; } @@ -69,16 +67,10 @@ contract L2WrappedBaseToken is ERC20PermitUpgradeable, IL2WrappedBaseToken, IBri address _l1Address, bytes32 _baseTokenAssetId ) external reinitializer(3) { - if (_l2Bridge == address(0)) { - revert ZeroAddress(); - } - - if (_l1Address == address(0)) { - revert ZeroAddress(); - } - if (_baseTokenAssetId == bytes32(0)) { - revert ZeroAddress(); - } + require(_l2Bridge != address(0), ZeroAddress()); + + require(_l1Address != address(0), ZeroAddress()); + require(_baseTokenAssetId != bytes32(0), ZeroAddress()); l2Bridge = _l2Bridge; l1Address = _l1Address; nativeTokenVault = L2_NATIVE_TOKEN_VAULT_ADDR; @@ -109,9 +101,7 @@ contract L2WrappedBaseToken is ERC20PermitUpgradeable, IL2WrappedBaseToken, IBri _burn(_from, _amount); // sends Ether to the bridge (bool success, ) = msg.sender.call{value: _amount}(""); - if (!success) { - revert WithdrawFailed(); - } + require(success, WithdrawFailed()); emit BridgeBurn(_from, _amount); } @@ -136,15 +126,17 @@ contract L2WrappedBaseToken is ERC20PermitUpgradeable, IL2WrappedBaseToken, IBri function withdrawTo(address _to, uint256 _amount) public override { _burn(msg.sender, _amount); (bool success, ) = _to.call{value: _amount}(""); - if (!success) { - revert WithdrawFailed(); - } + require(success, WithdrawFailed()); } + /// @notice Returns the L1 address of the original token that this wrapped token represents. + /// @return The L1 token address. function originToken() external view override returns (address) { return l1Address; } + /// @notice Returns the asset ID for this base token. + /// @return The base token asset ID. function assetId() external view override returns (bytes32) { return baseTokenAssetId; } diff --git a/l1-contracts/contracts/bridge/L2WrappedBaseTokenStore.sol b/l1-contracts/contracts/bridge/L2WrappedBaseTokenStore.sol index 5d8a179a47..971d6bd7ef 100644 --- a/l1-contracts/contracts/bridge/L2WrappedBaseTokenStore.sol +++ b/l1-contracts/contracts/bridge/L2WrappedBaseTokenStore.sol @@ -46,18 +46,14 @@ contract L2WrappedBaseTokenStore is Ownable2Step { /// @param _initialOwner The initial owner. /// @param _admin The address of the admin. constructor(address _initialOwner, address _admin) { - if (_admin == address(0) || _initialOwner == address(0)) { - revert ZeroAddress(); - } + require(_admin != address(0) && _initialOwner != address(0), ZeroAddress()); admin = _admin; _transferOwnership(_initialOwner); } /// @notice Throws if called by any account other than the owner or admin. modifier onlyOwnerOrAdmin() { - if (msg.sender != owner() && msg.sender != admin) { - revert Unauthorized(msg.sender); - } + require(msg.sender == owner() || msg.sender == admin, Unauthorized(msg.sender)); _; } @@ -66,24 +62,18 @@ contract L2WrappedBaseTokenStore is Ownable2Step { /// @param _chainId The ID of the blockchain network. /// @param _l2WBaseToken The address of the L2 WBaseToken token. function initializeChain(uint256 _chainId, address _l2WBaseToken) external onlyOwnerOrAdmin { - if (_l2WBaseToken == address(0)) { - revert ZeroAddress(); - } - if (l2WBaseTokenAddress[_chainId] != address(0)) { - revert WrappedBaseTokenAlreadyRegistered(); - } + require(_l2WBaseToken != address(0), ZeroAddress()); + require(l2WBaseTokenAddress[_chainId] == address(0), WrappedBaseTokenAlreadyRegistered()); _setWBaseTokenAddress(_chainId, _l2WBaseToken); } /// @notice Reinitializes the L2 WBaseToken address for a specific chain ID. - /// @dev Can only be called by the owner. It can not be called by the admin second time - /// to prevent retroactively damaging existing chains. + /// @dev Can only be called by the owner. Unlike initializeChain, this allows overwriting existing addresses. + /// @dev It can not be called by the admin to prevent retroactively damaging existing chains. /// @param _chainId The ID of the blockchain network. /// @param _l2WBaseToken The new address of the L2 WBaseToken token. function reinitializeChain(uint256 _chainId, address _l2WBaseToken) external onlyOwner { - if (_l2WBaseToken == address(0)) { - revert ZeroAddress(); - } + require(_l2WBaseToken != address(0), ZeroAddress()); _setWBaseTokenAddress(_chainId, _l2WBaseToken); } @@ -101,9 +91,7 @@ contract L2WrappedBaseTokenStore is Ownable2Step { /// @dev Please note, if the owner wants to enforce the admin change it must execute both `setPendingAdmin` and /// `acceptAdmin` atomically. Otherwise `admin` can set different pending admin and so fail to accept the admin rights. function setPendingAdmin(address _newPendingAdmin) external onlyOwnerOrAdmin { - if (_newPendingAdmin == address(0)) { - revert ZeroAddress(); - } + require(_newPendingAdmin != address(0), ZeroAddress()); // Save previous value into the stack to put it into the event later address oldPendingAdmin = pendingAdmin; // Change pending admin @@ -115,9 +103,7 @@ contract L2WrappedBaseTokenStore is Ownable2Step { function acceptAdmin() external { address currentPendingAdmin = pendingAdmin; // Only proposed by current admin address can claim the admin rights - if (msg.sender != currentPendingAdmin) { - revert Unauthorized(msg.sender); - } + require(msg.sender == currentPendingAdmin, Unauthorized(msg.sender)); address previousAdmin = admin; admin = currentPendingAdmin; diff --git a/l1-contracts/contracts/bridge/asset-router/AssetRouterBase.sol b/l1-contracts/contracts/bridge/asset-router/AssetRouterBase.sol index 28b221d702..89069168da 100644 --- a/l1-contracts/contracts/bridge/asset-router/AssetRouterBase.sol +++ b/l1-contracts/contracts/bridge/asset-router/AssetRouterBase.sol @@ -8,14 +8,17 @@ import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/securi import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20.sol"; -import {IAssetRouterBase} from "./IAssetRouterBase.sol"; +import {IAssetRouterBase, NEW_ENCODING_VERSION} from "./IAssetRouterBase.sol"; import {IAssetHandler} from "../interfaces/IAssetHandler.sol"; import {DataEncoding} from "../../common/libraries/DataEncoding.sol"; -import {L2_NATIVE_TOKEN_VAULT_ADDR} from "../../common/l2-helpers/L2ContractAddresses.sol"; +import {TWO_BRIDGES_MAGIC_VALUE} from "../../common/Config.sol"; +import {L2_ASSET_ROUTER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR} from "../../common/l2-helpers/L2ContractAddresses.sol"; -import {Unauthorized} from "../../common/L1ContractErrors.sol"; +import {L2TransactionRequestTwoBridgesInner} from "../../bridgehub/IBridgehubBase.sol"; +import {AssetHandlerDoesNotExist, AssetIdNotSupported, BadTransferDataLength, Unauthorized, UnsupportedEncodingVersion} from "../../common/L1ContractErrors.sol"; import {INativeTokenVaultBase} from "../ntv/INativeTokenVaultBase.sol"; +import {IBridgehubBase} from "../../bridgehub/IBridgehubBase.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -43,6 +46,8 @@ abstract contract AssetRouterBase is IAssetRouterBase, Ownable2StepUpgradeable, */ uint256[48] private __gap; + function _bridgehub() internal view virtual returns (IBridgehubBase); + /// @notice Sets the asset handler address for a specified asset ID on the chain of the asset deployment tracker. /// @dev The caller of this function is encoded within the `assetId`, therefore, it should be invoked by the asset deployment tracker contract. /// @dev No access control on the caller, as msg.sender is encoded in the assetId. @@ -63,14 +68,127 @@ abstract contract AssetRouterBase is IAssetRouterBase, Ownable2StepUpgradeable, bool senderIsNTV = msg.sender == _nativeTokenVault; address sender = senderIsNTV ? L2_NATIVE_TOKEN_VAULT_ADDR : msg.sender; bytes32 assetId = DataEncoding.encodeAssetId(block.chainid, _assetRegistrationData, sender); - if (!senderIsNTV && msg.sender != assetDeploymentTracker[assetId]) { - revert Unauthorized(msg.sender); - } + require(senderIsNTV || msg.sender == assetDeploymentTracker[assetId], Unauthorized(msg.sender)); _setAssetHandler(assetId, _assetHandlerAddress); assetDeploymentTracker[assetId] = msg.sender; emit AssetDeploymentTrackerRegistered(assetId, _assetRegistrationData, msg.sender); } + /*////////////////////////////////////////////////////////////// + INITIATE DEPOSIT Functions + //////////////////////////////////////////////////////////////*/ + + function bridgehubDepositBaseToken( + uint256 _chainId, + bytes32 _assetId, + address _originalCaller, + uint256 _amount + ) external payable virtual; + + function _bridgehubDepositBaseToken( + uint256 _chainId, + bytes32 _assetId, + address _originalCaller, + uint256 _amount + ) internal virtual { + address assetHandler = assetHandlerAddress[_assetId]; + require(assetHandler != address(0), AssetHandlerDoesNotExist(_assetId)); + + // slither-disable-next-line unused-return + IAssetHandler(assetHandler).bridgeBurn{value: msg.value}({ + _chainId: _chainId, + _msgValue: 0, + _assetId: _assetId, + _originalCaller: _originalCaller, + _data: DataEncoding.encodeBridgeBurnData(_amount, address(0), address(0)) + }); + + // Note that we don't save the deposited amount, as this is for the base token, which gets sent to the refundRecipient if the tx fails + emit BridgehubDepositBaseTokenInitiated(_chainId, _originalCaller, _assetId, _amount); + } + + function _bridgehubDeposit( + uint256 _chainId, + address _originalCaller, + uint256 _value, + bytes calldata _data, + address _nativeTokenVault + ) internal virtual whenNotPaused returns (L2TransactionRequestTwoBridgesInner memory request) { + bytes1 encodingVersion = _data[0]; + if (encodingVersion == NEW_ENCODING_VERSION) { + return + _bridgehubDepositNonBaseTokenAsset({ + _chainId: _chainId, + _originalCaller: _originalCaller, + _value: _value, + _data: _data, + _nativeTokenVault: _nativeTokenVault + }); + } else { + revert UnsupportedEncodingVersion(); + } + } + + function _bridgehubDepositNonBaseTokenAsset( + uint256 _chainId, + address _originalCaller, + uint256 _value, + bytes calldata _data, + address _nativeTokenVault + ) internal returns (L2TransactionRequestTwoBridgesInner memory request) { + bytes1 encodingVersion = _data[0]; + + (bytes32 assetId, bytes memory transferData) = _getTransferData(encodingVersion, _originalCaller, _data); + require(_bridgehub().baseTokenAssetId(_chainId) != assetId, AssetIdNotSupported(assetId)); + + bytes memory bridgeMintCalldata = _burn({ + _chainId: _chainId, + _nextMsgValue: _value, + _assetId: assetId, + _originalCaller: _originalCaller, + _transferData: transferData, + _passValue: true, + _nativeTokenVault: _nativeTokenVault + }); + + bytes32 txDataHash = DataEncoding.encodeTxDataHash({ + _nativeTokenVault: _nativeTokenVault, + _encodingVersion: encodingVersion, + _originalCaller: _originalCaller, + _assetId: assetId, + _transferData: transferData + }); + + request = _requestToBridge({ + _originalCaller: _originalCaller, + _assetId: assetId, + _bridgeMintCalldata: bridgeMintCalldata, + _txDataHash: txDataHash + }); + + emit BridgehubDepositInitiated({ + chainId: _chainId, + txDataHash: txDataHash, + from: _originalCaller, + assetId: assetId, + bridgeMintCalldata: bridgeMintCalldata + }); + } + + function _getTransferData( + bytes1 _encodingVersion, + address, + bytes calldata _data + ) internal virtual returns (bytes32 assetId, bytes memory transferData) { + if (_encodingVersion == NEW_ENCODING_VERSION) { + // For better error handling. + require(_data.length >= 33, BadTransferDataLength()); + (assetId, transferData) = abi.decode(_data[1:], (bytes32, bytes)); + } else { + revert UnsupportedEncodingVersion(); + } + } + /*////////////////////////////////////////////////////////////// Receive transaction Functions //////////////////////////////////////////////////////////////*/ @@ -156,6 +274,38 @@ abstract contract AssetRouterBase is IAssetRouterBase, Ownable2StepUpgradeable, }); } + /// @dev The request data that is passed to the bridgehub. + /// @param _originalCaller The `msg.sender` address from the external call that initiated current one. + /// @param _assetId The deposited asset ID. + /// @param _bridgeMintCalldata The calldata used by remote asset handler to mint tokens for recipient. + /// @param _txDataHash The keccak256 hash of 0x01 || abi.encode(bytes32, bytes) to identify deposits. + /// @return request The data used by the bridgehub to create L2 transaction request to specific ZK chain. + function _requestToBridge( + address _originalCaller, + bytes32 _assetId, + bytes memory _bridgeMintCalldata, + bytes32 _txDataHash + ) internal view virtual returns (L2TransactionRequestTwoBridgesInner memory request) { + bytes memory l2TxCalldata = getDepositCalldata(_originalCaller, _assetId, _bridgeMintCalldata); + + request = L2TransactionRequestTwoBridgesInner({ + magicValue: TWO_BRIDGES_MAGIC_VALUE, + l2Contract: L2_ASSET_ROUTER_ADDR, + l2Calldata: l2TxCalldata, + factoryDeps: new bytes[](0), + txDataHash: _txDataHash + }); + } + + /// @inheritdoc IAssetRouterBase + function getDepositCalldata( + address, + bytes32 _assetId, + bytes memory _assetData + ) public view virtual override returns (bytes memory) { + return abi.encodeCall(AssetRouterBase.finalizeDeposit, (block.chainid, _assetId, _assetData)); + } + /// @notice Ensures that token is registered with native token vault. /// @dev Only used when deposit is made with legacy data encoding format. /// @param _token The native token address which should be registered with native token vault. diff --git a/l1-contracts/contracts/bridge/asset-router/IAssetRouterBase.sol b/l1-contracts/contracts/bridge/asset-router/IAssetRouterBase.sol index 95d4bc270a..2ae7573779 100644 --- a/l1-contracts/contracts/bridge/asset-router/IAssetRouterBase.sol +++ b/l1-contracts/contracts/bridge/asset-router/IAssetRouterBase.sol @@ -48,4 +48,28 @@ interface IAssetRouterBase { event DepositFinalizedAssetRouter(uint256 indexed chainId, bytes32 indexed assetId, bytes assetData); function assetHandlerAddress(bytes32 _assetId) external view returns (address); + + /// @notice Generates a calldata for calling the deposit finalization on the L2 native token contract. + /// @param _sender The address of the deposit initiator. + /// @param _assetId The deposited asset ID. + /// @param _assetData The encoded data, which is used by the asset handler to determine L2 recipient and amount. Might include extra information. + /// @return Returns calldata used on ZK chain. + function getDepositCalldata( + address _sender, + bytes32 _assetId, + bytes memory _assetData + ) external view returns (bytes memory); + + /// @notice Allows bridgehub to acquire mintValue for L1->L2 and L2->L2 transactions. + /// @dev If the corresponding L2 transaction fails, refunds are issued to a refund recipient on L2. + /// @param _chainId The chain ID of the ZK chain to which deposit. + /// @param _assetId The deposited asset ID. + /// @param _originalCaller The `msg.sender` address from the external call that initiated current one. + /// @param _amount The total amount of tokens to be bridged. + function bridgehubDepositBaseToken( + uint256 _chainId, + bytes32 _assetId, + address _originalCaller, + uint256 _amount + ) external payable; } diff --git a/l1-contracts/contracts/bridge/asset-router/IL1AssetRouter.sol b/l1-contracts/contracts/bridge/asset-router/IL1AssetRouter.sol index 841afea1f1..098c13f89d 100644 --- a/l1-contracts/contracts/bridge/asset-router/IL1AssetRouter.sol +++ b/l1-contracts/contracts/bridge/asset-router/IL1AssetRouter.sol @@ -8,11 +8,13 @@ import {IAssetRouterBase} from "./IAssetRouterBase.sol"; import {L2TransactionRequestTwoBridgesInner} from "../../bridgehub/IBridgehubBase.sol"; import {IL1SharedBridgeLegacy} from "../interfaces/IL1SharedBridgeLegacy.sol"; import {IL1ERC20Bridge} from "../interfaces/IL1ERC20Bridge.sol"; +import {IL1CrossChainSender} from "../interfaces/IL1CrossChainSender.sol"; +import {TxStatus} from "../../common/Messaging.sol"; /// @title L1 Bridge contract interface /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev -interface IL1AssetRouter is IAssetRouterBase, IL1SharedBridgeLegacy { +interface IL1AssetRouter is IAssetRouterBase, IL1SharedBridgeLegacy, IL1CrossChainSender { event BridgehubMintData(bytes bridgeMintData); event BridgehubDepositFinalized( @@ -93,8 +95,9 @@ interface IL1AssetRouter is IAssetRouterBase, IL1SharedBridgeLegacy { /// @param _assetId The unique identifier of the deposited L1 token. /// @param _assetData The encoded transfer data, which includes both the deposit amount and the address of the L2 receiver. Might include extra information. /// @dev Processes claims of failed deposit, whether they originated from the legacy bridge or the current system. - function bridgeRecoverFailedTransfer( + function bridgeConfirmTransferResult( uint256 _chainId, + TxStatus _txStatus, address _depositSender, bytes32 _assetId, bytes calldata _assetData @@ -146,9 +149,9 @@ interface IL1AssetRouter is IAssetRouterBase, IL1SharedBridgeLegacy { ) external; /// @notice Initiates a transfer transaction within Bridgehub, used by `requestL2TransactionTwoBridges`. - /// @param _chainId The chain ID of the ZK chain to which deposit. + /// @param _chainId Destination chain ID. /// @param _originalCaller The `msg.sender` address from the external call that initiated current one. - /// @param _value The `msg.value` on the target chain tx. + /// @param _value The `msg.value` to be deposited on the target chain. /// @param _data The calldata for the second bridge deposit. /// @return request The data used by the bridgehub to create L2 transaction request to specific ZK chain. /// @dev Data has the following abi encoding for legacy deposits: @@ -165,35 +168,10 @@ interface IL1AssetRouter is IAssetRouterBase, IL1SharedBridgeLegacy { bytes calldata _data ) external payable returns (L2TransactionRequestTwoBridgesInner memory request); - /// @notice Generates a calldata for calling the deposit finalization on the L2 native token contract. - // / @param _chainId The chain ID of the ZK chain to which deposit. - /// @param _sender The address of the deposit initiator. - /// @param _assetId The deposited asset ID. - /// @param _assetData The encoded data, which is used by the asset handler to determine L2 recipient and amount. Might include extra information. - /// @return Returns calldata used on ZK chain. - function getDepositCalldata( - address _sender, - bytes32 _assetId, - bytes memory _assetData - ) external view returns (bytes memory); - - /// @notice Allows bridgehub to acquire mintValue for L1->L2 transactions. - /// @dev If the corresponding L2 transaction fails, refunds are issued to a refund recipient on L2. - /// @param _chainId The chain ID of the ZK chain to which deposit. - /// @param _assetId The deposited asset ID. - /// @param _originalCaller The `msg.sender` address from the external call that initiated current one. - /// @param _amount The total amount of tokens to be bridged. - function bridgehubDepositBaseToken( - uint256 _chainId, - bytes32 _assetId, - address _originalCaller, - uint256 _amount - ) external payable; - /// @notice Routes the confirmation to nullifier for backward compatibility. /// @notice Confirms the acceptance of a transaction by the Mailbox, as part of the L2 transaction process within Bridgehub. /// This function is utilized by `requestL2TransactionTwoBridges` to validate the execution of a transaction. - /// @param _chainId The chain ID of the ZK chain to which confirm the deposit. + /// @param _chainId Destination chain ID. /// @param _txDataHash The keccak256 hash of 0x01 || abi.encode(bytes32, bytes) to identify deposits. /// @param _txHash The hash of the L1->L2 transaction to confirm the deposit. function bridgehubConfirmL2Transaction(uint256 _chainId, bytes32 _txDataHash, bytes32 _txHash) external; diff --git a/l1-contracts/contracts/bridge/asset-router/IL2AssetRouter.sol b/l1-contracts/contracts/bridge/asset-router/IL2AssetRouter.sol index 181f32e2fe..752a6971e5 100644 --- a/l1-contracts/contracts/bridge/asset-router/IL2AssetRouter.sol +++ b/l1-contracts/contracts/bridge/asset-router/IL2AssetRouter.sol @@ -3,11 +3,12 @@ pragma solidity ^0.8.20; import {IAssetRouterBase} from "./IAssetRouterBase.sol"; +import {IL2CrossChainSender} from "../interfaces/IL2CrossChainSender.sol"; import {IL1AssetRouter} from "./IL1AssetRouter.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev -interface IL2AssetRouter is IAssetRouterBase { +interface IL2AssetRouter is IAssetRouterBase, IL2CrossChainSender { event WithdrawalInitiatedAssetRouter( uint256 chainId, address indexed l2Sender, @@ -19,6 +20,8 @@ interface IL2AssetRouter is IAssetRouterBase { function L1_ASSET_ROUTER() external view returns (IL1AssetRouter); + function BASE_TOKEN_ASSET_ID() external view returns (bytes32); + function withdrawLegacyBridge(address _l1Receiver, address _l2Token, uint256 _amount, address _sender) external; function finalizeDepositLegacyBridge( diff --git a/l1-contracts/contracts/bridge/asset-router/L1AssetRouter.sol b/l1-contracts/contracts/bridge/asset-router/L1AssetRouter.sol index 71ee463f1f..38b8c6580d 100644 --- a/l1-contracts/contracts/bridge/asset-router/L1AssetRouter.sol +++ b/l1-contracts/contracts/bridge/asset-router/L1AssetRouter.sol @@ -7,12 +7,12 @@ import {SafeERC20} from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20. import {IL1AssetRouter} from "./IL1AssetRouter.sol"; import {IL2AssetRouter} from "./IL2AssetRouter.sol"; -import {LEGACY_ENCODING_VERSION, NEW_ENCODING_VERSION, SET_ASSET_HANDLER_COUNTERPART_ENCODING_VERSION} from "./IAssetRouterBase.sol"; +import {IAssetRouterBase, LEGACY_ENCODING_VERSION, SET_ASSET_HANDLER_COUNTERPART_ENCODING_VERSION} from "./IAssetRouterBase.sol"; import {AssetRouterBase} from "./AssetRouterBase.sol"; +import {IL1CrossChainSender} from "../interfaces/IL1CrossChainSender.sol"; import {IL1AssetHandler} from "../interfaces/IL1AssetHandler.sol"; import {IL1ERC20Bridge} from "../interfaces/IL1ERC20Bridge.sol"; -import {IAssetHandler} from "../interfaces/IAssetHandler.sol"; import {IL1Nullifier} from "../interfaces/IL1Nullifier.sol"; import {INativeTokenVaultBase} from "../ntv/INativeTokenVaultBase.sol"; import {IL2SharedBridgeLegacyFunctions} from "../interfaces/IL2SharedBridgeLegacyFunctions.sol"; @@ -22,7 +22,7 @@ import {DataEncoding} from "../../common/libraries/DataEncoding.sol"; import {AddressAliasHelper} from "../../vendor/AddressAliasHelper.sol"; import {ETH_TOKEN_ADDRESS, TWO_BRIDGES_MAGIC_VALUE} from "../../common/Config.sol"; import {NativeTokenVaultAlreadySet} from "../L1BridgeContractErrors.sol"; -import {AddressAlreadySet, AssetHandlerDoesNotExist, AssetIdNotSupported, LegacyBridgeUsesNonNativeToken, LegacyEncodingUsedForNonL1Token, NonEmptyMsgValue, TokenNotSupported, TokensWithFeesNotSupported, Unauthorized, UnsupportedEncodingVersion, ZeroAddress} from "../../common/L1ContractErrors.sol"; +import {AddressAlreadySet, LegacyBridgeUsesNonNativeToken, LegacyEncodingUsedForNonL1Token, NonEmptyMsgValue, TokenNotSupported, TokensWithFeesNotSupported, Unauthorized, ZeroAddress} from "../../common/L1ContractErrors.sol"; import {L2_ASSET_ROUTER_ADDR} from "../../common/l2-helpers/L2ContractAddresses.sol"; import {IL1Bridgehub} from "../../bridgehub/IL1Bridgehub.sol"; @@ -30,6 +30,8 @@ import {IZKChain} from "../../state-transition/chain-interfaces/IZKChain.sol"; import {L2TransactionRequestDirect, L2TransactionRequestTwoBridgesInner} from "../../bridgehub/IBridgehubBase.sol"; import {IL1AssetDeploymentTracker} from "../interfaces/IL1AssetDeploymentTracker.sol"; +import {IBridgehubBase} from "../../bridgehub/IBridgehubBase.sol"; +import {TxStatus} from "../../common/Messaging.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -71,35 +73,28 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { /// @notice Checks that the message sender is the nullifier. modifier onlyNullifier() { - if (msg.sender != address(L1_NULLIFIER)) { - revert Unauthorized(msg.sender); - } + require(msg.sender == address(L1_NULLIFIER), Unauthorized(msg.sender)); _; } /// @notice Checks that the message sender is the bridgehub or ZKsync Era Diamond Proxy. modifier onlyBridgehubOrEra(uint256 _chainId) { - if ( - msg.sender != address(BRIDGE_HUB) && (_chainId != ERA_CHAIN_ID || msg.sender != address(ERA_DIAMOND_PROXY)) - ) { - revert Unauthorized(msg.sender); - } + require( + msg.sender == address(BRIDGE_HUB) || (_chainId == ERA_CHAIN_ID && msg.sender == address(ERA_DIAMOND_PROXY)), + Unauthorized(msg.sender) + ); _; } /// @notice Checks that the message sender is the legacy bridge. modifier onlyLegacyBridge() { - if (msg.sender != address(legacyBridge)) { - revert Unauthorized(msg.sender); - } + require(msg.sender == address(legacyBridge), Unauthorized(msg.sender)); _; } /// @notice Checks that the message sender is the native token vault. modifier onlyNativeTokenVault() { - if (msg.sender != address(nativeTokenVault)) { - revert Unauthorized(msg.sender); - } + require(msg.sender == address(nativeTokenVault), Unauthorized(msg.sender)); _; } @@ -111,6 +106,10 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { _; } + function _bridgehub() internal view virtual override returns (IBridgehubBase) { + return IBridgehubBase(BRIDGE_HUB); + } + /// @dev Contract is expected to be used as proxy implementation. /// @dev Initialize the implementation to prevent Parity hack. constructor( @@ -134,9 +133,7 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { /// @param _owner The address which can change L2 token implementation and upgrade the bridge implementation. /// The owner is the Governor and separate from the ProxyAdmin from now on, so that the Governor can call the bridge. function initialize(address _owner) external reentrancyGuardInitializer initializer { - if (_owner == address(0)) { - revert ZeroAddress(); - } + require(_owner != address(0), ZeroAddress()); _transferOwnership(_owner); } @@ -144,12 +141,8 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { /// @dev Should be called only once by the owner. /// @param _nativeTokenVault The address of the native token vault. function setNativeTokenVault(INativeTokenVaultBase _nativeTokenVault) external onlyOwner { - if (address(nativeTokenVault) != address(0)) { - revert NativeTokenVaultAlreadySet(); - } - if (address(_nativeTokenVault) == address(0)) { - revert ZeroAddress(); - } + require(address(nativeTokenVault) == address(0), NativeTokenVaultAlreadySet()); + require(address(_nativeTokenVault) != address(0), ZeroAddress()); nativeTokenVault = _nativeTokenVault; _setAssetHandler(ETH_TOKEN_ASSET_ID, address(_nativeTokenVault)); } @@ -158,16 +151,12 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { /// @dev Should be called only once by the owner. /// @param _legacyBridge The address of the legacy bridge. function setL1Erc20Bridge(IL1ERC20Bridge _legacyBridge) external override onlyOwner { - if (address(legacyBridge) != address(0)) { - revert AddressAlreadySet(address(legacyBridge)); - } - if (address(_legacyBridge) == address(0)) { - revert ZeroAddress(); - } + require(address(legacyBridge) == address(0), AddressAlreadySet(address(legacyBridge))); + require(address(_legacyBridge) != address(0), ZeroAddress()); legacyBridge = _legacyBridge; } - /// @notice Used to set the assed deployment tracker address for given asset data. + /// @notice Used to set the asset deployment tracker address for given asset data. /// @param _assetRegistrationData The asset data which may include the asset address and any additional required data or encodings. /// @param _assetDeploymentTracker The whitelisted address of asset deployment tracker for provided asset. function setAssetDeploymentTracker( @@ -220,35 +209,20 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { } /*////////////////////////////////////////////////////////////// - INITIATTE DEPOSIT Functions + INITIATE DEPOSIT Functions //////////////////////////////////////////////////////////////*/ - /// @inheritdoc IL1AssetRouter + /// @inheritdoc IAssetRouterBase function bridgehubDepositBaseToken( uint256 _chainId, bytes32 _assetId, address _originalCaller, uint256 _amount - ) public payable virtual override onlyBridgehubOrEra(_chainId) whenNotPaused { - address assetHandler = assetHandlerAddress[_assetId]; - if (assetHandler == address(0)) { - revert AssetHandlerDoesNotExist(_assetId); - } - - // slither-disable-next-line unused-return - IAssetHandler(assetHandler).bridgeBurn{value: msg.value}({ - _chainId: _chainId, - _msgValue: 0, - _assetId: _assetId, - _originalCaller: _originalCaller, - _data: DataEncoding.encodeBridgeBurnData(_amount, address(0), address(0)) - }); - - // Note that we don't save the deposited amount, as this is for the base token, which gets sent to the refundRecipient if the tx fails - emit BridgehubDepositBaseTokenInitiated(_chainId, _originalCaller, _assetId, _amount); + ) public payable virtual override(AssetRouterBase, IAssetRouterBase) onlyBridgehubOrEra(_chainId) whenNotPaused { + _bridgehubDepositBaseToken(_chainId, _assetId, _originalCaller, _amount); } - /// @inheritdoc IL1AssetRouter + /// @inheritdoc IL1CrossChainSender function bridgehubDeposit( uint256 _chainId, address _originalCaller, @@ -263,15 +237,9 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { whenNotPaused returns (L2TransactionRequestTwoBridgesInner memory request) { - bytes32 assetId; - bytes memory transferData; bytes1 encodingVersion = _data[0]; - // The new encoding ensures that the calldata is collision-resistant with respect to the legacy format. - // In the legacy calldata, the first input was the address, meaning the most significant byte was always `0x00`. if (encodingVersion == SET_ASSET_HANDLER_COUNTERPART_ENCODING_VERSION) { - if (msg.value != 0 || _value != 0) { - revert NonEmptyMsgValue(); - } + require(msg.value == 0 && _value == 0, NonEmptyMsgValue()); (bytes32 _assetId, address _assetHandlerAddressOnCounterpart) = abi.decode(_data[1:], (bytes32, address)); return @@ -281,52 +249,24 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { _assetId, _assetHandlerAddressOnCounterpart ); - } else if (encodingVersion == NEW_ENCODING_VERSION) { - (assetId, transferData) = abi.decode(_data[1:], (bytes32, bytes)); } else if (encodingVersion == LEGACY_ENCODING_VERSION) { - (assetId, transferData) = _handleLegacyData(_data, _originalCaller); - } else { - revert UnsupportedEncodingVersion(); - } - - if (BRIDGE_HUB.baseTokenAssetId(_chainId) == assetId) { - revert AssetIdNotSupported(assetId); + return + _bridgehubDepositNonBaseTokenAsset({ + _chainId: _chainId, + _originalCaller: _originalCaller, + _value: _value, + _data: _data, + _nativeTokenVault: address(nativeTokenVault) + }); } - - address ntvCached = address(nativeTokenVault); - - bytes memory bridgeMintCalldata = _burn({ - _chainId: _chainId, - _nextMsgValue: _value, - _assetId: assetId, - _originalCaller: _originalCaller, - _transferData: transferData, - _passValue: true, - _nativeTokenVault: ntvCached - }); - - bytes32 txDataHash = DataEncoding.encodeTxDataHash({ - _nativeTokenVault: ntvCached, - _encodingVersion: encodingVersion, - _originalCaller: _originalCaller, - _assetId: assetId, - _transferData: transferData - }); - - request = _requestToBridge({ - _originalCaller: _originalCaller, - _assetId: assetId, - _bridgeMintCalldata: bridgeMintCalldata, - _txDataHash: txDataHash - }); - - emit BridgehubDepositInitiated({ - chainId: _chainId, - txDataHash: txDataHash, - from: _originalCaller, - assetId: assetId, - bridgeMintCalldata: bridgeMintCalldata - }); + return + _bridgehubDeposit({ + _chainId: _chainId, + _originalCaller: _originalCaller, + _value: _value, + _data: _data, + _nativeTokenVault: address(nativeTokenVault) + }); } /// @inheritdoc IL1AssetRouter @@ -353,24 +293,28 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { } /*////////////////////////////////////////////////////////////// - CLAIM FAILED DEPOSIT Functions + CONFIRM DEPOSIT Functions //////////////////////////////////////////////////////////////*/ /// @inheritdoc IL1AssetRouter - function bridgeRecoverFailedTransfer( + function bridgeConfirmTransferResult( uint256 _chainId, + TxStatus _txStatus, address _depositSender, bytes32 _assetId, bytes calldata _assetData ) external override onlyNullifier nonReentrant whenNotPaused { - IL1AssetHandler(assetHandlerAddress[_assetId]).bridgeRecoverFailedTransfer( - _chainId, - _assetId, - _depositSender, - _assetData - ); + IL1AssetHandler(assetHandlerAddress[_assetId]).bridgeConfirmTransferResult({ + _chainId: _chainId, + _txStatus: _txStatus, + _assetId: _assetId, + _depositSender: _depositSender, + _data: _assetData + }); - emit ClaimedFailedDepositAssetRouter(_chainId, _assetId, _assetData); + if (_txStatus == TxStatus.Failure) { + emit ClaimedFailedDepositAssetRouter(_chainId, _assetId, _assetData); + } } function bridgeRecoverFailedTransfer( @@ -401,6 +345,20 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { Internal & Helpers //////////////////////////////////////////////////////////////*/ + function _getTransferData( + bytes1 _encodingVersion, + address _originalCaller, + bytes calldata _data + ) internal override returns (bytes32 assetId, bytes memory transferData) { + // The new encoding ensures that the calldata is collision-resistant with respect to the legacy format. + // In the legacy calldata, the first input was the address, meaning the most significant byte was always `0x00`. + if (_encodingVersion == LEGACY_ENCODING_VERSION) { + (assetId, transferData) = _handleLegacyData(_data, _originalCaller); + } else { + (assetId, transferData) = super._getTransferData(_encodingVersion, _originalCaller, _data); + } + } + /// @notice Decodes the transfer input for legacy data and transfers allowance to NTV. /// @dev Is not applicable for custom asset handlers. /// @param _data The encoded transfer data (address _l1Token, uint256 _depositAmount, address _l2Receiver). @@ -414,9 +372,7 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { // We ensure that the legacy data format can not be used for tokens that did not originate from L1. bytes32 expectedAssetId = DataEncoding.encodeNTVAssetId(block.chainid, _l1Token); - if (assetId != expectedAssetId) { - revert LegacyEncodingUsedForNonL1Token(); - } + require(assetId == expectedAssetId, LegacyEncodingUsedForNonL1Token()); if (assetId == ETH_TOKEN_ASSET_ID) { // In the old SDK/contracts the user had to always provide `0` as the deposit amount for ETH token, while @@ -468,43 +424,18 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { l1Token.safeTransferFrom(_originalCaller, address(nativeTokenVault), _amount); uint256 balanceAfter = l1Token.balanceOf(address(nativeTokenVault)); - if (balanceAfter - balanceBefore != _amount) { - revert TokensWithFeesNotSupported(); - } + require(balanceAfter - balanceBefore == _amount, TokensWithFeesNotSupported()); return true; } return false; } - /// @dev The request data that is passed to the bridgehub. - /// @param _originalCaller The `msg.sender` address from the external call that initiated current one. - /// @param _assetId The deposited asset ID. - /// @param _bridgeMintCalldata The calldata used by remote asset handler to mint tokens for recipient. - /// @param _txDataHash The keccak256 hash of 0x01 || abi.encode(bytes32, bytes) to identify deposits. - /// @return request The data used by the bridgehub to create L2 transaction request to specific ZK chain. - function _requestToBridge( - address _originalCaller, - bytes32 _assetId, - bytes memory _bridgeMintCalldata, - bytes32 _txDataHash - ) internal view virtual returns (L2TransactionRequestTwoBridgesInner memory request) { - bytes memory l2TxCalldata = getDepositCalldata(_originalCaller, _assetId, _bridgeMintCalldata); - - request = L2TransactionRequestTwoBridgesInner({ - magicValue: TWO_BRIDGES_MAGIC_VALUE, - l2Contract: L2_ASSET_ROUTER_ADDR, - l2Calldata: l2TxCalldata, - factoryDeps: new bytes[](0), - txDataHash: _txDataHash - }); - } - - /// @inheritdoc IL1AssetRouter + /// @inheritdoc IAssetRouterBase function getDepositCalldata( address _sender, bytes32 _assetId, bytes memory _assetData - ) public view override returns (bytes memory) { + ) public view override(AssetRouterBase, IAssetRouterBase) returns (bytes memory) { // First branch covers the case when asset is not registered with NTV (custom asset handler) // Second branch handles tokens registered with NTV and uses legacy calldata encoding // We need to use the legacy encoding to support the old SDK, which relies on a specific encoding of the data. @@ -512,7 +443,7 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { (nativeTokenVault.tokenAddress(_assetId) == address(0)) || (nativeTokenVault.originChainId(_assetId) != block.chainid) ) { - return abi.encodeCall(AssetRouterBase.finalizeDeposit, (block.chainid, _assetId, _assetData)); + return super.getDepositCalldata(_sender, _assetId, _assetData); } else { // slither-disable-next-line unused-return (, address _receiver, address _parsedNativeToken, uint256 _amount, bytes memory _gettersData) = DataEncoding @@ -556,9 +487,7 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { uint256 _l2TxGasPerPubdataByte, address _refundRecipient ) external payable override onlyLegacyBridge nonReentrant whenNotPaused returns (bytes32 txHash) { - if (_l1Token == L1_WETH_TOKEN) { - revert TokenNotSupported(L1_WETH_TOKEN); - } + require(_l1Token != L1_WETH_TOKEN, TokenNotSupported(L1_WETH_TOKEN)); bytes32 _assetId; { @@ -571,9 +500,8 @@ contract L1AssetRouter is AssetRouterBase, IL1AssetRouter, ReentrancyGuard { // Inner call to encode data to decrease local var numbers _assetId = _ensureTokenRegisteredWithNTV(_l1Token); // Legacy bridge is only expected to use native tokens for L1. - if (_assetId != DataEncoding.encodeNTVAssetId(block.chainid, _l1Token)) { - revert LegacyBridgeUsesNonNativeToken(); - } + bytes32 encodedAssetId = DataEncoding.encodeNTVAssetId(block.chainid, _l1Token); + require(_assetId == encodedAssetId, LegacyBridgeUsesNonNativeToken()); // Note, that starting from here `bridgeData` starts denoting bridgeMintData. bridgeData = _burn({ diff --git a/l1-contracts/contracts/bridge/asset-router/L2AssetRouter.sol b/l1-contracts/contracts/bridge/asset-router/L2AssetRouter.sol index 5f53ca4615..2806478607 100644 --- a/l1-contracts/contracts/bridge/asset-router/L2AssetRouter.sol +++ b/l1-contracts/contracts/bridge/asset-router/L2AssetRouter.sol @@ -3,6 +3,8 @@ pragma solidity 0.8.28; import {IL2AssetRouter} from "./IL2AssetRouter.sol"; +import {IL2CrossChainSender} from "../interfaces/IL2CrossChainSender.sol"; +import {IAssetRouterBase} from "./IAssetRouterBase.sol"; import {AssetRouterBase} from "./AssetRouterBase.sol"; import {IL1AssetRouter} from "./IL1AssetRouter.sol"; @@ -13,20 +15,25 @@ import {IBridgedStandardToken} from "../interfaces/IBridgedStandardToken.sol"; import {IL1ERC20Bridge} from "../interfaces/IL1ERC20Bridge.sol"; import {IL2Bridgehub} from "../../bridgehub/IL2Bridgehub.sol"; +import {IBridgehubBase, L2TransactionRequestTwoBridgesInner} from "../../bridgehub/IBridgehubBase.sol"; import {AddressAliasHelper} from "../../vendor/AddressAliasHelper.sol"; import {ReentrancyGuard} from "../../common/ReentrancyGuard.sol"; -import {L2_COMPLEX_UPGRADER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR, L2_BRIDGEHUB_ADDR} from "../../common/l2-helpers/L2ContractAddresses.sol"; +import {InteropCallStarter} from "../../common/Messaging.sol"; +import {L2_BRIDGEHUB_ADDR, L2_COMPLEX_UPGRADER_ADDR, L2_INTEROP_CENTER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR} from "../../common/l2-helpers/L2ContractAddresses.sol"; import {L2ContractHelper} from "../../common/l2-helpers/L2ContractHelper.sol"; import {DataEncoding} from "../../common/libraries/DataEncoding.sol"; -import {AmountMustBeGreaterThanZero, AssetIdNotSupported, EmptyAddress, InvalidCaller, TokenNotLegacy} from "../../common/L1ContractErrors.sol"; +import {AmountMustBeGreaterThanZero, AssetIdNotSupported, EmptyAddress, ExecuteMessageFailed, InvalidSelector, PayloadTooShort, TokenNotLegacy, Unauthorized} from "../../common/L1ContractErrors.sol"; +import {IERC7786Recipient} from "../../interop/IERC7786Recipient.sol"; +import {IERC7786Attributes} from "../../interop/IERC7786Attributes.sol"; +import {InteroperableAddress} from "../../vendor/draft-InteroperableAddress.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev /// @notice The "default" bridge implementation for the ERC20 tokens. Note, that it does not /// support any custom token logic, i.e. rebase tokens' functionality is not supported. /// @dev Important: L2 contracts are not allowed to have any immutable variables or constructors. This is needed for compatibility with ZKsyncOS. -contract L2AssetRouter is AssetRouterBase, IL2AssetRouter, ReentrancyGuard { +contract L2AssetRouter is AssetRouterBase, IL2AssetRouter, ReentrancyGuard, IERC7786Recipient { /// @dev Bridgehub smart contract that is used to operate with L2 via asynchronous L2 <-> L1 communication. /// @dev Note, that while it is a simple storage variable, the name is in capslock for the backward compatibility with /// the old version where it was an immutable. @@ -57,15 +64,21 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter, ReentrancyGuard { /// the old version where it was an immutable. bytes32 public BASE_TOKEN_ASSET_ID; + /// @notice Returns the bridgehub contract. + function _bridgehub() internal view virtual override returns (IBridgehubBase) { + return IBridgehubBase(L2_BRIDGEHUB_ADDR); + } + /// @notice Checks that the message sender is the L1 Asset Router. modifier onlyAssetRouterCounterpart(uint256 _originChainId) { if (_originChainId == L1_CHAIN_ID) { // Only the L1 Asset Router counterpart can initiate and finalize the deposit. - if (AddressAliasHelper.undoL1ToL2Alias(msg.sender) != address(L1_ASSET_ROUTER)) { - revert InvalidCaller(msg.sender); - } + require( + AddressAliasHelper.undoL1ToL2Alias(msg.sender) == address(L1_ASSET_ROUTER), + Unauthorized(msg.sender) + ); } else { - revert InvalidCaller(msg.sender); // xL2 messaging not supported for now + revert Unauthorized(msg.sender); } _; } @@ -76,35 +89,39 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter, ReentrancyGuard { // Only the L1 Asset Router counterpart can initiate and finalize the deposit. if ( (AddressAliasHelper.undoL1ToL2Alias(msg.sender) != address(L1_ASSET_ROUTER)) && - (msg.sender != address(this)) + msg.sender != address(this) ) { - revert InvalidCaller(msg.sender); + revert Unauthorized(msg.sender); } } else { - revert InvalidCaller(msg.sender); // xL2 messaging not supported for now + if (msg.sender != address(this)) { + revert Unauthorized(msg.sender); + } } _; } /// @notice Checks that the message sender is the legacy L2 bridge. modifier onlyLegacyBridge() { - if (msg.sender != address(L2_LEGACY_SHARED_BRIDGE)) { - revert InvalidCaller(msg.sender); - } + require(msg.sender == address(L2_LEGACY_SHARED_BRIDGE), Unauthorized(msg.sender)); _; } modifier onlyNTV() { - if (msg.sender != L2_NATIVE_TOKEN_VAULT_ADDR) { - revert InvalidCaller(msg.sender); - } + require(msg.sender == L2_NATIVE_TOKEN_VAULT_ADDR, Unauthorized(msg.sender)); + _; + } + + /// @notice Checks that the message sender is the bridgehub. + modifier onlyL2InteropCenter() { + require(msg.sender == L2_INTEROP_CENTER_ADDR, Unauthorized(msg.sender)); _; } /// @dev Only allows calls from the complex upgrader contract on L2. modifier onlyUpgrader() { if (msg.sender != L2_COMPLEX_UPGRADER_ADDR) { - revert InvalidCaller(msg.sender); + revert Unauthorized(msg.sender); } _; } @@ -149,9 +166,7 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter, ReentrancyGuard { bytes32 _baseTokenAssetId ) public onlyUpgrader { L2_LEGACY_SHARED_BRIDGE = _legacySharedBridge; - if (address(_l1AssetRouter) == address(0)) { - revert EmptyAddress(); - } + require(address(_l1AssetRouter) != address(0), EmptyAddress()); L1_CHAIN_ID = _l1ChainId; L1_ASSET_ROUTER = _l1AssetRouter; BASE_TOKEN_ASSET_ID = _baseTokenAssetId; @@ -181,6 +196,61 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter, ReentrancyGuard { _setAssetHandler(_assetId, L2_NATIVE_TOKEN_VAULT_ADDR); } + /// @notice Executes cross-chain interop messages following ERC-7786 standard + /// @param sender ERC-7930 Address of the message sender + /// @param payload Encoded function call data (must be finalizeDeposit) + /// @return Function selector confirming successful execution per ERC-7786 + function receiveMessage( + bytes32 /* receiveId */, // Unique identifier + bytes calldata sender, // ERC-7930 address + bytes calldata payload + ) external payable returns (bytes4) { + // This function serves as the L2AssetRouter's entry point for processing cross-chain bridge operations + // initiated through the InteropCenter system. It implements critical security validations: + // - L1->L2 calls: Currently Interop can only be initiated on L2, so this case shouldn't be covered. + // - L2->L2 calls: Only this contract (L2AssetRouter) can send messages from other L2 chains + // + // This dual validation prevents attackers from spoofing cross-chain messages by requiring + // both correct source chain ID and authorized sender address. + // + // INDIRECT CALL PATTERN (L2->L2 interop flow): + // 1. User calls InteropCenter on source L2 + // 2. InteropCenter calls initiateIndirectCall() on source chain's L2AssetRouter + // 3. Source L2AssetRouter becomes the "sender" for the destination L2 call + // 4. Destination L2 validates senderAddress == address(this) for non-L1 sources + // (L2AssetRouter address is equal for all ZKsync chains) + + (uint256 senderChainId, address senderAddress) = InteroperableAddress.parseEvmV1Calldata(sender); + + require((senderChainId != L1_CHAIN_ID && senderAddress == address(this)), Unauthorized(senderAddress)); + + // The payload must contain a valid finalizeDeposit selector to ensure only legitimate + // bridge operations are executed. This prevents arbitrary function calls through the interop system. + require(payload.length > 4, PayloadTooShort()); + require( + bytes4(payload[0:4]) == AssetRouterBase.finalizeDeposit.selector, + InvalidSelector(bytes4(payload[0:4])) + ); + + (bool success, ) = address(this).call(payload); + require(success, ExecuteMessageFailed()); + return IERC7786Recipient.receiveMessage.selector; + } + + /*////////////////////////////////////////////////////////////// + INITIATE DEPOSIT Functions + //////////////////////////////////////////////////////////////*/ + + /// @inheritdoc IAssetRouterBase + function bridgehubDepositBaseToken( + uint256 _chainId, + bytes32 _assetId, + address _originalCaller, + uint256 _amount + ) public payable virtual override(AssetRouterBase, IAssetRouterBase) onlyL2InteropCenter { + _bridgehubDepositBaseToken(_chainId, _assetId, _originalCaller, _amount); + } + /*////////////////////////////////////////////////////////////// Receive transaction Functions //////////////////////////////////////////////////////////////*/ @@ -190,16 +260,53 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter, ReentrancyGuard { /// @param _transferData The encoded data required for deposit (address _l1Sender, uint256 _amount, address _l2Receiver, bytes memory erc20Data, address originToken) function finalizeDeposit( // solhint-disable-next-line no-unused-vars - uint256, + uint256 _originChainId, bytes32 _assetId, bytes calldata _transferData - ) public payable override onlyAssetRouterCounterpartOrSelf(L1_CHAIN_ID) nonReentrant { - if (_assetId == BASE_TOKEN_ASSET_ID) { - revert AssetIdNotSupported(BASE_TOKEN_ASSET_ID); - } - _finalizeDeposit(L1_CHAIN_ID, _assetId, _transferData, L2_NATIVE_TOKEN_VAULT_ADDR); + ) public payable override onlyAssetRouterCounterpartOrSelf(_originChainId) nonReentrant { + require(_assetId != BASE_TOKEN_ASSET_ID, AssetIdNotSupported(BASE_TOKEN_ASSET_ID)); + _finalizeDeposit(_originChainId, _assetId, _transferData, L2_NATIVE_TOKEN_VAULT_ADDR); - emit DepositFinalizedAssetRouter(L1_CHAIN_ID, _assetId, _transferData); + emit DepositFinalizedAssetRouter(_originChainId, _assetId, _transferData); + } + + /// @inheritdoc IL2CrossChainSender + function initiateIndirectCall( + uint256 _chainId, + address _originalCaller, + uint256 _value, + bytes calldata _data + ) external payable onlyL2InteropCenter returns (InteropCallStarter memory interopCallStarter) { + // This function is called by the InteropCenter when processing indirect interop calls. + // It prepares the bridge operation for cross-chain execution through these steps: + // 1. Processing the deposit through the standard bridgehub flow + // 2. Encoding the call for interop execution with proper attributes + // 3. Returning an InteropCallStarter struct for the InteropCenter to process + // COMPLETE L2->L2 BRIDGE FLOW: + // - User wants to bridge from L2A to L2B + // - L2A InteropCenter calls this function on L2A AssetRouter + // - This creates an InteropCallStarter targeting L2B AssetRouter + // - InteropCenter sends the call to L2B via the interop messaging system + // - L2B AssetRouter receives via executeMessage() with sender=address(this) + // (L2AssetRouter address is equal on all ZKsync chains) + + L2TransactionRequestTwoBridgesInner memory request = _bridgehubDeposit({ + _chainId: _chainId, + _originalCaller: _originalCaller, + _value: _value, + _data: _data, + _nativeTokenVault: L2_NATIVE_TOKEN_VAULT_ADDR + }); + + // The _value parameter represents the amount being bridged and is encoded + // as an ERC-7786 attribute to ensure proper value transfer in the interop call. + bytes[] memory attributes = new bytes[](1); + attributes[0] = abi.encodeCall(IERC7786Attributes.interopCallValue, _value); + interopCallStarter = InteropCallStarter({ + to: InteroperableAddress.formatEvmV1(request.l2Contract), + data: request.l2Calldata, + callAttributes: attributes + }); } /// @notice Initiates a withdrawal by burning funds on the contract and sending the message to L1 @@ -224,7 +331,8 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter, ReentrancyGuard { /// @param _assetId The asset id of the withdrawn asset /// @param _assetData The data that is passed to the asset handler contract /// @param _sender The address of the sender of the message - /// @param _alwaysNewMessageFormat Whether to use the new message format compatible with Custom Asset Handlers + /// @param _alwaysNewMessageFormat Whether to use the new message format compatible with Custom Asset Handlers. + /// We use the new message format if we don't have the legacy shared bridge, and only for l1 native tokens. function _withdrawSender( bytes32 _assetId, bytes memory _assetData, @@ -250,9 +358,7 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter, ReentrancyGuard { address l1Token = IBridgedStandardToken( IL2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR).tokenAddress(_assetId) ).originToken(); - if (l1Token == address(0)) { - revert AssetIdNotSupported(_assetId); - } + require(l1Token != address(0), AssetIdNotSupported(_assetId)); // slither-disable-next-line unused-return (uint256 amount, address l1Receiver, ) = DataEncoding.decodeBridgeBurnData(_assetData); message = _getSharedBridgeWithdrawMessage(l1Receiver, l1Token, amount); @@ -346,9 +452,7 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter, ReentrancyGuard { /// @param _l2Token The L2 token address which is withdrawn /// @param _amount The total amount of tokens to be withdrawn function withdraw(address _l1Receiver, address _l2Token, uint256 _amount) external nonReentrant { - if (_amount == 0) { - revert AmountMustBeGreaterThanZero(); - } + require(_amount != 0, AmountMustBeGreaterThanZero()); _withdrawLegacy(_l1Receiver, _l2Token, _amount, msg.sender); } @@ -369,9 +473,7 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter, ReentrancyGuard { function _withdrawLegacy(address _l1Receiver, address _l2Token, uint256 _amount, address _sender) internal { address l1Address = l1TokenAddress(_l2Token); - if (l1Address == address(0)) { - revert TokenNotLegacy(); - } + require(l1Address != address(0), TokenNotLegacy()); bytes32 assetId = DataEncoding.encodeNTVAssetId(L1_CHAIN_ID, l1Address); bytes memory data = DataEncoding.encodeBridgeBurnData(_amount, _l1Receiver, _l2Token); _withdrawSender(assetId, data, _sender, false); @@ -407,7 +509,7 @@ contract L2AssetRouter is AssetRouterBase, IL2AssetRouter, ReentrancyGuard { return currentlyDeployedAddress; } - // For backwards compatibility, the bridge smust return the address of the token even if it + // For backwards compatibility, the bridge must return the address of the token even if it // has not been deployed yet. return NativeTokenVaultBase(address(l2NativeTokenVault)).calculateCreate2TokenAddress(L1_CHAIN_ID, _l1Token); } diff --git a/l1-contracts/contracts/bridge/asset-tracker/AssetTrackerBase.sol b/l1-contracts/contracts/bridge/asset-tracker/AssetTrackerBase.sol new file mode 100644 index 0000000000..66613cb32c --- /dev/null +++ b/l1-contracts/contracts/bridge/asset-tracker/AssetTrackerBase.sol @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; +import {ReentrancyGuard} from "../../common/ReentrancyGuard.sol"; + +import {IAssetTrackerBase, MAX_TOKEN_BALANCE} from "./IAssetTrackerBase.sol"; +import {TokenBalanceMigrationData} from "../../common/Messaging.sol"; + +import {L2_INTEROP_CENTER_ADDR, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT} from "../../common/l2-helpers/L2ContractAddresses.sol"; +import {INativeTokenVaultBase} from "../ntv/INativeTokenVaultBase.sol"; +import {Unauthorized} from "../../common/L1ContractErrors.sol"; +import {IMessageRoot} from "../../bridgehub/IMessageRoot.sol"; +import {DynamicIncrementalMerkleMemory} from "../../common/libraries/DynamicIncrementalMerkleMemory.sol"; +import {SERVICE_TRANSACTION_SENDER} from "../../common/Config.sol"; +import {AssetHandlerModifiers} from "../interfaces/AssetHandlerModifiers.sol"; +import {IBridgehubBase} from "../../bridgehub/IBridgehubBase.sol"; +import {InsufficientChainBalance} from "./AssetTrackerErrors.sol"; +import {IAssetTrackerDataEncoding} from "./IAssetTrackerDataEncoding.sol"; + +abstract contract AssetTrackerBase is + IAssetTrackerBase, + Ownable2StepUpgradeable, + AssetHandlerModifiers, + ReentrancyGuard +{ + using DynamicIncrementalMerkleMemory for DynamicIncrementalMerkleMemory.Bytes32PushTree; + + /// @notice Maps token balances for each chain to prevent unauthorized spending across ZK chains. + /// NOTE: this function may be removed in the future, don't rely on it! + /// @dev On L1AssetTracker: + /// - For token origin chains (or their settlement layer if they are connected to a settlement layer), the balance starts at type(uint256).max. + /// - Note that this balance is tracked even for tokens from L1, it is just that their `chainId` is `block.chainid`. + /// - A chain can spend its balance when finalizing withdrawals/claiming failed deposits or when migrating the balance to the settlement layer. + /// - A chain can increase its balance when deposits are made to the chain or when migrating the balance from the settlement layer. + /// @dev On GWAssetTracker: + /// - For each assetId, the sum of chainBalance[chainId][assetId] across all chains is less than or equal to + /// chainBalance[settlementLayerId][assetId] on L1AssetTracker, i.e., all tokens are backed by the settlement layer's balance on L1. + /// - Chains spend their balances when submitting withdrawals, processing failed deposits or sending tokens via interop. + /// - The balances are increased when deposits are made to the chains and when they receive interop from other chains. + /// - Also, the balances are increased or decreased when migrating the balance to/from the settlement layer. + /// @dev On L2AssetTracker: + /// - The `chainBalance` is only used to track the balance of native tokens on the L2. + /// - For all the other tokens it is expected to be 0. + mapping(uint256 chainId => mapping(bytes32 assetId => uint256 balance)) public chainBalance; + + /// @notice Tracks the migration number of each asset on each chain. If the migration number is the same + /// as the current migration number of the chain, then the token balance has been migrated to the settlement layer. + /// If it is not, bridging it may be restricted. + /// @dev On L1AssetTracker it is mainly used as a nullifier to ensure that the token migrations are not replayed. + /// @dev On GWAssetTracker it is mainly used as a nullifier to ensure that the token migrations are not replayed. + /// @dev On L2AssetTracker it is used to block withdrawals: + /// - If a chain settles on GW, it blocks withdrawals or interop until the token balance has been migrated to GW. + /// - If a chain settles on L1, it is mostly unused since withdrawals are always allowed. + mapping(uint256 chainId => mapping(bytes32 assetId => uint256 migrationNumber)) public assetMigrationNumber; + + /// NOTE: this mapping may be removed in the future, don't rely on it! + mapping(bytes32 assetId => bool maxChainBalanceAssigned) internal maxChainBalanceAssigned; + + function _l1ChainId() internal view virtual returns (uint256); + + function _bridgehub() internal view virtual returns (IBridgehubBase); + + function _nativeTokenVault() internal view virtual returns (INativeTokenVaultBase); + + function _messageRoot() internal view virtual returns (IMessageRoot); + + modifier onlyL1() { + require(block.chainid == _l1ChainId(), Unauthorized(msg.sender)); + _; + } + + modifier onlyServiceTransactionSender() { + require(msg.sender == SERVICE_TRANSACTION_SENDER, Unauthorized(msg.sender)); + _; + } + + modifier onlyNativeTokenVaultOrInteropCenter() { + require( + msg.sender == address(_nativeTokenVault()) || msg.sender == L2_INTEROP_CENTER_ADDR, + Unauthorized(msg.sender) + ); + _; + } + + modifier onlyNativeTokenVault() { + require(msg.sender == address(_nativeTokenVault()), Unauthorized(msg.sender)); + _; + } + + /// @notice Checks if a token has been migrated on the current chain. + /// @dev This is a convenience function that checks migration status for the current chain. + /// @param _assetId The asset ID of the token to check. + /// @return bool True if the token has been migrated, false otherwise. + function tokenMigratedThisChain(bytes32 _assetId) external view returns (bool) { + return tokenMigrated(block.chainid, _assetId); + } + + /// @notice Checks if a token has been migrated on a specific chain. + /// @dev Compares the asset's migration number with the chain's current migration number. + /// @param _chainId The chain ID to check migration status for. + /// @param _assetId The asset ID of the token to check. + /// @return bool True if the token has been migrated, false otherwise. + function tokenMigrated(uint256 _chainId, bytes32 _assetId) public view returns (bool) { + return assetMigrationNumber[_chainId][_assetId] == _getChainMigrationNumber(_chainId); + } + + /// @notice Determines if a token can skip migration on the settlement layer. + /// @dev If we are bridging the token for the first time, then we are allowed to bridge it, and set the assetMigrationNumber. + /// @dev Note it might be the case that the token was deposited and all the supply was withdrawn, and the token balance was never migrated. + /// @dev It is still ok to bridge in this case, since the chainBalance does not need to be migrated, and we set the assetMigrationNumber on the GW and the L2 manually. + /// @param _chainId The chain ID to check. + /// @param _assetId The asset ID to check. + /// @return bool True if migration can be skipped, false otherwise. + function _tokenCanSkipMigrationOnSettlementLayer(uint256 _chainId, bytes32 _assetId) internal view returns (bool) { + uint256 savedAssetMigrationNumber = assetMigrationNumber[_chainId][_assetId]; + return savedAssetMigrationNumber == 0 && chainBalance[_chainId][_assetId] == 0; + } + + /// @notice Forces the asset migration number to be set to the current chain migration number. + /// @dev This is used when we want to mark a token as migrated without going through the normal migration process. + /// @dev Force-set the asset's migration number to the chain's current migration number. + /// @param _chainId The chain ID for which to set the migration number. + /// @param _assetId The asset ID for which to set the migration number. + function _forceSetAssetMigrationNumber(uint256 _chainId, bytes32 _assetId) internal { + assetMigrationNumber[_chainId][_assetId] = _getChainMigrationNumber(_chainId); + } + + /*////////////////////////////////////////////////////////////// + Register token + //////////////////////////////////////////////////////////////*/ + + function registerNewToken(bytes32 _assetId, uint256 _originChainId) public virtual; + + function _assignMaxChainBalance(uint256 _originChainId, bytes32 _assetId) internal virtual { + chainBalance[_originChainId][_assetId] = MAX_TOKEN_BALANCE; + maxChainBalanceAssigned[_assetId] = true; + } + + /// @dev This function is used to decrease the chain balance of a token on a chain. + /// @dev It makes debugging issues easier. Overflows don't usually happen, so there is no similar function to increase the chain balance. + function _decreaseChainBalance(uint256 _chainId, bytes32 _assetId, uint256 _amount) internal { + if (chainBalance[_chainId][_assetId] < _amount) { + revert InsufficientChainBalance(_chainId, _assetId, _amount); + } + chainBalance[_chainId][_assetId] -= _amount; + } + + /// @notice Sends token balance migration data to L1 through the L2->L1 messenger. + /// @dev This function is used by L2 and Gateway to initiate migration operations on L1. + /// @param data The migration data containing token information and amounts to migrate. + function _sendMigrationDataToL1(TokenBalanceMigrationData memory data) internal { + // slither-disable-next-line unused-return + L2_TO_L1_MESSENGER_SYSTEM_CONTRACT.sendToL1( + abi.encodeCall(IAssetTrackerDataEncoding.receiveMigrationOnL1, data) + ); + } + + /*////////////////////////////////////////////////////////////// + Token deposits and withdrawals + //////////////////////////////////////////////////////////////*/ + function _getChainMigrationNumber(uint256 _chainId) internal view virtual returns (uint256); +} diff --git a/l1-contracts/contracts/bridge/asset-tracker/AssetTrackerErrors.sol b/l1-contracts/contracts/bridge/asset-tracker/AssetTrackerErrors.sol new file mode 100644 index 0000000000..3c8417c548 --- /dev/null +++ b/l1-contracts/contracts/bridge/asset-tracker/AssetTrackerErrors.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +// 0xda72d995 +error AssetIdNotRegistered(bytes32 _assetId); +// 0x07859b3b +error InsufficientChainBalance(uint256 _chainId, bytes32 _assetId, uint256 _amount); +// 0x2e19b556 +error InvalidAssetId(bytes32); +// 0x95bddd6c +error InvalidAssetMigrationNumber(); +// 0xd24c490f +error InvalidBuiltInContractMessage(uint256 logCount, uint256 msgCount, bytes32 key); +// 0x7ad8c2c9 +error InvalidCanonicalTxHash(bytes32); +// 0x05208b6d +error InvalidChainMigrationNumber(uint256, uint256); +// 0x24ef4f8a +error InvalidEmptyMessageRoot(bytes32 expectedMessageRoot, bytes32 providedMessageRoot); +// 0x532a43fc +error InvalidFunctionSignature(bytes4 functionSignature); +// 0xfbf8ed35 +error InvalidInteropBalanceChange(bytes32 bundleHash); +// 0x203d8be5 +error InvalidInteropChainId(uint256 fromChainId, uint256 toChainId); +// 0xeaa867a8 +error InvalidL1AssetRouter(address l1AssetRouter); +// 0xe1fe041e +error InvalidL2ShardId(); +// 0x9530c5e1 +error InvalidMigrationNumber(uint256, uint256); +// 0xddb5de5e +error InvalidSender(); +// 0xaca75b50 +error InvalidServiceLog(); +// 0xd0f0bff7 +error InvalidSettlementLayer(); +// 0xa9146eeb +error InvalidVersion(); +// 0xf76b228a +error InvalidWithdrawalChainId(); +// 0xa16d8a80 +error L1TotalSupplyAlreadyMigrated(); +// 0xda4352c4 +error MaxChainBalanceAlreadyAssigned(bytes32 assetId); +// 0x7e472272 +error MissingBaseTokenAssetId(); +// 0x8dfed13a +error NotMigratedChain(); +// 0x4a22c4b8 +error OnlyGatewaySettlementLayer(); +// 0x0fd3385e +error OnlyWhitelistedSettlementLayer(address, address); +// 0x174996d5 +error RegisterNewTokenNotAllowed(); +// 0x90ed63bb +error TokenBalanceNotMigratedToGateway(bytes32, uint256, uint256); +// 0x03a5ba47 +error TransientBalanceChangeAlreadySet(uint256 storedAssetId, uint256 storedAmount); diff --git a/l1-contracts/contracts/bridge/asset-tracker/GWAssetTracker.sol b/l1-contracts/contracts/bridge/asset-tracker/GWAssetTracker.sol new file mode 100644 index 0000000000..4934ba76fd --- /dev/null +++ b/l1-contracts/contracts/bridge/asset-tracker/GWAssetTracker.sol @@ -0,0 +1,684 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {BALANCE_CHANGE_VERSION, SavedTotalSupply, TOKEN_BALANCE_MIGRATION_DATA_VERSION, INTEROP_BALANCE_CHANGE_VERSION} from "./IAssetTrackerBase.sol"; +import {BUNDLE_IDENTIFIER, BalanceChange, InteropBalanceChange, ConfirmBalanceMigrationData, InteropBundle, InteropCall, L2Log, TokenBalanceMigrationData, TxStatus, AssetBalanceChange} from "../../common/Messaging.sol"; +import {L2_ASSET_ROUTER_ADDR, L2_ASSET_TRACKER_ADDR, L2_BASE_TOKEN_SYSTEM_CONTRACT, L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR, L2_BOOTLOADER_ADDRESS, L2_BRIDGEHUB, L2_CHAIN_ASSET_HANDLER, L2_COMPLEX_UPGRADER_ADDR, L2_INTEROP_HANDLER_ADDR, L2_COMPRESSOR_ADDR, L2_INTEROP_CENTER_ADDR, L2_KNOWN_CODE_STORAGE_SYSTEM_CONTRACT_ADDR, L2_MESSAGE_ROOT, L2_NATIVE_TOKEN_VAULT, L2_NATIVE_TOKEN_VAULT_ADDR, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, MAX_BUILT_IN_CONTRACT_ADDR, L2_ASSET_ROUTER} from "../../common/l2-helpers/L2ContractAddresses.sol"; +import {DataEncoding} from "../../common/libraries/DataEncoding.sol"; +import {AssetRouterBase} from "../asset-router/AssetRouterBase.sol"; +import {INativeTokenVaultBase} from "../ntv/INativeTokenVaultBase.sol"; +import {ChainIdNotRegistered, InvalidInteropCalldata, InvalidMessage, ReconstructionMismatch, Unauthorized} from "../../common/L1ContractErrors.sol"; +import {CHAIN_TREE_EMPTY_ENTRY_HASH, IMessageRoot, SHARED_ROOT_TREE_EMPTY_HASH} from "../../bridgehub/IMessageRoot.sol"; +import {ProcessLogsInput} from "../../state-transition/chain-interfaces/IExecutor.sol"; +import {DynamicIncrementalMerkleMemory} from "../../common/libraries/DynamicIncrementalMerkleMemory.sol"; +import {L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH, L2_TO_L1_LOGS_MERKLE_TREE_DEPTH} from "../../common/Config.sol"; +import {IBridgehubBase} from "../../bridgehub/IBridgehubBase.sol"; +import {FullMerkleMemory} from "../../common/libraries/FullMerkleMemory.sol"; + +import {InvalidAssetId, InvalidBuiltInContractMessage, InvalidCanonicalTxHash, InvalidFunctionSignature, InvalidInteropChainId, InvalidL2ShardId, InvalidServiceLog, InvalidEmptyMessageRoot, RegisterNewTokenNotAllowed, InvalidInteropBalanceChange} from "./AssetTrackerErrors.sol"; +import {AssetTrackerBase} from "./AssetTrackerBase.sol"; +import {IGWAssetTracker} from "./IGWAssetTracker.sol"; +import {MessageHashing} from "../../common/libraries/MessageHashing.sol"; +import {IL1ERC20Bridge} from "../interfaces/IL1ERC20Bridge.sol"; +import {IMailboxImpl} from "../../state-transition/chain-interfaces/IMailboxImpl.sol"; +import {IAssetTrackerDataEncoding} from "./IAssetTrackerDataEncoding.sol"; +import {LegacySharedBridgeAddresses, SharedBridgeOnChainId} from "./LegacySharedBridgeAddresses.sol"; +import {InteropDataEncoding} from "../../interop/InteropDataEncoding.sol"; +import {IInteropHandler} from "../../interop/IInteropHandler.sol"; + +contract GWAssetTracker is AssetTrackerBase, IGWAssetTracker { + using FullMerkleMemory for FullMerkleMemory.FullTree; + using DynamicIncrementalMerkleMemory for DynamicIncrementalMerkleMemory.Bytes32PushTree; + + uint256 public L1_CHAIN_ID; + + /// @notice Used to track how the balance has changed for each chain during a deposit. + /// We assume that during a single deposit at most two token balances for a chain are amended: + /// - base token of the chain. + /// - bridged token (in case it is a deposit of some sort). + /// @dev Whenever a failed deposit is processed, the chain balance must be decremented accordingly. + /// From this, it follows that all failed deposit logs that are ever sent to Gateway must have been routed through this contract, + /// i.e., a chain cannot migrate on top of ZK Gateway until all deposits that were submitted through L1 have been processed + /// and vice versa. + mapping(uint256 chainId => mapping(bytes32 canonicalTxHash => BalanceChange balanceChange)) internal balanceChange; + + /// Used only on Gateway. + mapping(bytes32 assetId => address originToken) internal originToken; + + /// Used only on Gateway. + mapping(bytes32 assetId => uint256 originChainId) internal tokenOriginChainId; + + /// Used only on Gateway. + mapping(uint256 chainId => address legacySharedBridgeAddress) internal legacySharedBridgeAddress; + + /// empty messageRoot calculated for specific chain. + mapping(uint256 chainId => bytes32 emptyMessageRoot) internal emptyMessageRoot; + + /// @notice We save the chainBalance which equals the chains totalSupply before the first GW->L1 migration so that it can be replayed. + /// @dev Note, that the balance is only saved for even migration numbers, i.e. when the chain did not settle on top of Gateway. + /// This is needed so that in the future after e.g. a chain migrated with number N (odd number), we would remember how much funds did it + /// have right before the migration (when N - 1 was the migration number). + mapping(uint256 chainId => mapping(uint256 migrationNumber => mapping(bytes32 assetId => SavedTotalSupply savedChainBalance))) + internal savedChainBalance; + + /// @notice We save the interop call balance change + mapping(uint256 receivingChainId => mapping(bytes32 bundleHash => InteropBalanceChange interopBalanceChange)) + internal interopBalanceChange; + + modifier onlyUpgrader() { + if (msg.sender != L2_COMPLEX_UPGRADER_ADDR) { + revert Unauthorized(msg.sender); + } + _; + } + + modifier onlyL2NativeTokenVault() { + if (msg.sender != L2_NATIVE_TOKEN_VAULT_ADDR) { + revert Unauthorized(msg.sender); + } + _; + } + + modifier onlyBaseTokenSystemContract() { + if (msg.sender != address(L2_BASE_TOKEN_SYSTEM_CONTRACT)) { + revert Unauthorized(msg.sender); + } + _; + } + + modifier onlyChain(uint256 _chainId) { + if (msg.sender != L2_BRIDGEHUB.getZKChain(_chainId)) { + revert Unauthorized(msg.sender); + } + _; + } + + modifier onlyL2InteropCenter() { + if (msg.sender != L2_INTEROP_CENTER_ADDR) { + revert Unauthorized(msg.sender); + } + _; + } + + function setAddresses(uint256 _l1ChainId) external onlyUpgrader { + L1_CHAIN_ID = _l1ChainId; + } + + /// @notice Sets legacy shared bridge addresses for chains that used the old bridging system. + /// @dev This function is called during upgrades to maintain backwards compatibility with pre-V30 chains. + /// @dev Legacy bridges are needed to process withdrawal messages from chains that haven't upgraded yet. + function setLegacySharedBridgeAddress() external onlyUpgrader { + address l1AssetRouter = address(L2_ASSET_ROUTER.L1_ASSET_ROUTER()); + SharedBridgeOnChainId[] memory sharedBridgeOnChainIds = LegacySharedBridgeAddresses + .getLegacySharedBridgeAddressOnGateway(l1AssetRouter); + uint256 length = sharedBridgeOnChainIds.length; + for (uint256 i = 0; i < length; ++i) { + legacySharedBridgeAddress[sharedBridgeOnChainIds[i].chainId] = sharedBridgeOnChainIds[i] + .legacySharedBridgeAddress; + } + } + + /// @dev for local testing + function setLegacySharedBridgeAddressForLocalTesting( + uint256 _chainId, + address _legacySharedBridgeAddress + ) external onlyUpgrader { + legacySharedBridgeAddress[_chainId] = _legacySharedBridgeAddress; + } + + function _l1ChainId() internal view override returns (uint256) { + return L1_CHAIN_ID; + } + + function _bridgehub() internal view override returns (IBridgehubBase) { + return L2_BRIDGEHUB; + } + + function _nativeTokenVault() internal view override returns (INativeTokenVaultBase) { + return L2_NATIVE_TOKEN_VAULT; + } + + function _messageRoot() internal view override returns (IMessageRoot) { + return L2_MESSAGE_ROOT; + } + + /*////////////////////////////////////////////////////////////// + Token deposits and withdrawals + //////////////////////////////////////////////////////////////*/ + + function registerNewToken(bytes32, uint256) public override onlyNativeTokenVault { + revert RegisterNewTokenNotAllowed(); + } + + /// @notice The function that is expected to be called by the InteropCenter whenever an L1->L2 + /// transaction gets relayed through ZK Gateway for chain `_chainId`. + /// @dev Note on trust assumptions: `_chainId` and `_balanceChange` are trusted to be correct, since + /// they are provided directly by the InteropCenter, which in turn, gets those from the L1 implementation of + /// the GW Mailbox. + /// @dev `_canonicalTxHash` is not trusted as it is provided at will by a malicious chain. + function handleChainBalanceIncreaseOnGateway( + uint256 _chainId, + bytes32 _canonicalTxHash, + BalanceChange calldata _balanceChange + ) external onlyL2InteropCenter { + uint256 chainMigrationNumber = _getChainMigrationNumber(_chainId); + + /// Note we don't decrease L1ChainBalance here, since we don't track L1 chainBalance on Gateway. + _increaseAndSaveChainBalance(_chainId, _balanceChange.assetId, _balanceChange.amount, chainMigrationNumber); + _increaseAndSaveChainBalance( + _chainId, + _balanceChange.baseTokenAssetId, + _balanceChange.baseTokenAmount, + chainMigrationNumber + ); + + if (_tokenCanSkipMigrationOnSettlementLayer(_chainId, _balanceChange.assetId)) { + _forceSetAssetMigrationNumber(_chainId, _balanceChange.assetId); + } + _registerToken(_balanceChange.assetId, _balanceChange.originToken, _balanceChange.tokenOriginChainId); + + /// A malicious chain can cause a collision for the canonical tx hash. + require(balanceChange[_chainId][_canonicalTxHash].version == 0, InvalidCanonicalTxHash(_canonicalTxHash)); + // we save the balance change to be able to handle failed deposits. + + balanceChange[_chainId][_canonicalTxHash] = _balanceChange; + } + + /// @notice Sets a legacy shared bridge address for a specific chain. + /// @param _chainId The chain ID for which to set the legacy bridge address. + /// @param _legacySharedBridgeAddress The address of the legacy shared bridge contract. + function setLegacySharedBridgeAddress( + uint256 _chainId, + address _legacySharedBridgeAddress + ) external onlyServiceTransactionSender { + legacySharedBridgeAddress[_chainId] = _legacySharedBridgeAddress; + } + + /*////////////////////////////////////////////////////////////// + Chain settlement logs processing on Gateway + //////////////////////////////////////////////////////////////*/ + + /// @notice Processes L2->Gateway logs and messages to update chain balances and handle cross-chain operations. + /// @dev This is the main function that processes a batch of L2 logs from a settling chain. + /// @dev It reconstructs the logs Merkle tree, validates messages, and routes them to appropriate handlers. + /// @dev The function handles multiple types of messages: interop, base token, asset router, and system messages. + /// @param _processLogsInputs The input containing logs, messages, and chain information to process. + function processLogsAndMessages( + ProcessLogsInput calldata _processLogsInputs + ) external onlyChain(_processLogsInputs.chainId) { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory reconstructedLogsTree; + reconstructedLogsTree.createTree(L2_TO_L1_LOGS_MERKLE_TREE_DEPTH); + + // slither-disable-next-line unused-return + reconstructedLogsTree.setup(L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH); + + uint256 msgCount = 0; + uint256 logsLength = _processLogsInputs.logs.length; + bytes32 baseTokenAssetId = _bridgehub().baseTokenAssetId(_processLogsInputs.chainId); + for (uint256 logCount = 0; logCount < logsLength; ++logCount) { + L2Log memory log = _processLogsInputs.logs[logCount]; + { + bytes32 hashedLog = MessageHashing.getLeafHashFromLog(log); + // slither-disable-next-line unused-return + reconstructedLogsTree.push(hashedLog); + } + if (log.sender == L2_BOOTLOADER_ADDRESS) { + _handlePotentialFailedDeposit(_processLogsInputs.chainId, log.key, log.value); + } else if (log.sender == L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR) { + ++msgCount; + bytes calldata message = _processLogsInputs.messages[msgCount - 1]; + + if (log.value != keccak256(message)) { + revert InvalidMessage(); + } + require(log.l2ShardId == 0, InvalidL2ShardId()); + require(log.isService, InvalidServiceLog()); + + if (log.key == bytes32(uint256(uint160(L2_INTEROP_CENTER_ADDR)))) { + _handleInteropCenterMessage(_processLogsInputs.chainId, message, baseTokenAssetId); + } else if (log.key == bytes32(uint256(uint160(L2_INTEROP_HANDLER_ADDR)))) { + _handleInteropHandlerReceiveMessage(_processLogsInputs.chainId, message, baseTokenAssetId); + } else if (log.key == bytes32(uint256(uint160(L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR)))) { + _handleBaseTokenSystemContractMessage(_processLogsInputs.chainId, baseTokenAssetId, message); + } else if (log.key == bytes32(uint256(uint160(L2_ASSET_ROUTER_ADDR)))) { + _handleAssetRouterMessage(_processLogsInputs.chainId, message); + } else if (log.key == bytes32(uint256(uint160(L2_ASSET_TRACKER_ADDR)))) { + _checkAssetTrackerMessageSelector(message); + } else if (log.key == bytes32(uint256(uint160(L2_COMPRESSOR_ADDR)))) { + // No further action is required in this case. + } else if (log.key == bytes32(uint256(uint160(L2_KNOWN_CODE_STORAGE_SYSTEM_CONTRACT_ADDR)))) { + // No further action is required in this case. + } else if (uint256(log.key) <= MAX_BUILT_IN_CONTRACT_ADDR) { + // This Log is not supported + revert InvalidBuiltInContractMessage(logCount, msgCount - 1, log.key); + } else { + address legacySharedBridge = legacySharedBridgeAddress[_processLogsInputs.chainId]; + if (log.key == bytes32(uint256(uint160(legacySharedBridge))) && legacySharedBridge != address(0)) { + _handleLegacySharedBridgeMessage(_processLogsInputs.chainId, message); + } + } + } + } + reconstructedLogsTree.extendUntilEnd(); + bytes32 localLogsRootHash = reconstructedLogsTree.root(); + + bytes32 emptyMessageRootForChain = _getEmptyMessageRoot(_processLogsInputs.chainId); + require( + _processLogsInputs.messageRoot == emptyMessageRootForChain, + InvalidEmptyMessageRoot(emptyMessageRootForChain, _processLogsInputs.messageRoot) + ); + bytes32 chainBatchRootHash = keccak256(bytes.concat(localLogsRootHash, _processLogsInputs.messageRoot)); + + if (chainBatchRootHash != _processLogsInputs.chainBatchRoot) { + revert ReconstructionMismatch(chainBatchRootHash, _processLogsInputs.chainBatchRoot); + } + + /// Appends the batch message root to the global message. + /// The logic of this function depends on the settlement layer as we support + /// message root aggregation only on non-L1 settlement layers for ease for migration. + _messageRoot().addChainBatchRoot( + _processLogsInputs.chainId, + _processLogsInputs.batchNumber, + chainBatchRootHash + ); + } + + function _getEmptyMessageRoot(uint256 _chainId) internal returns (bytes32) { + bytes32 savedEmptyMessageRoot = emptyMessageRoot[_chainId]; + if (savedEmptyMessageRoot != bytes32(0)) { + return savedEmptyMessageRoot; + } + FullMerkleMemory.FullTree memory sharedTree; + sharedTree.createTree(1); + // slither-disable-next-line unused-return + sharedTree.setup(SHARED_ROOT_TREE_EMPTY_HASH); + + DynamicIncrementalMerkleMemory.Bytes32PushTree memory chainTree; + chainTree.createTree(1); + bytes32 initialChainTreeHash = chainTree.setup(CHAIN_TREE_EMPTY_ENTRY_HASH); + bytes32 leafHash = MessageHashing.chainIdLeafHash(initialChainTreeHash, _chainId); + bytes32 emptyMessageRootCalculated = sharedTree.pushNewLeaf(leafHash); + + emptyMessageRoot[_chainId] = emptyMessageRootCalculated; + return emptyMessageRootCalculated; + } + + /// @notice Handles potential failed deposits. Not all L1->L2 txs are deposits. + function _handlePotentialFailedDeposit(uint256 _chainId, bytes32 _canonicalTxHash, bytes32 _value) internal { + BalanceChange memory savedBalanceChange = balanceChange[_chainId][_canonicalTxHash]; + require(savedBalanceChange.version == BALANCE_CHANGE_VERSION, InvalidCanonicalTxHash(_canonicalTxHash)); + if (_value == bytes32(uint256(TxStatus.Success))) { + return; + } + /// Note we handle failedDeposits here for deposits that do not go through GW during chainMigration, + /// because they were initiated when the chain settles on L1, however the failedDeposit L2->L1 message goes through GW. + /// Here we do not need to decrement the chainBalance, since the chainBalance was added to the chain's chainBalance on L1, + /// and never migrated to the GW's chainBalance, since it never increments the totalSupply since the L2 txs fails. + if (savedBalanceChange.amount > 0) { + _decreaseChainBalance(_chainId, savedBalanceChange.assetId, savedBalanceChange.amount); + } + /// Note the base token is never native to the chain as of V30. + if (savedBalanceChange.baseTokenAmount > 0) { + _decreaseChainBalance(_chainId, savedBalanceChange.baseTokenAssetId, savedBalanceChange.baseTokenAmount); + } + } + + function _handleInteropCenterMessage( + uint256 _chainId, + bytes calldata _message, + bytes32 _baseTokenAssetId + ) internal { + if (_message[0] != BUNDLE_IDENTIFIER) { + // This should not be possible in V30. In V31 this will be a trigger. + return; + } + + InteropBundle memory interopBundle = abi.decode(_message[1:], (InteropBundle)); + + bytes32 bundleHash = InteropDataEncoding.encodeInteropBundleHash(_chainId, _message[1:]); + interopBalanceChange[interopBundle.destinationChainId][bundleHash].version = INTEROP_BALANCE_CHANGE_VERSION; + + uint256 totalBaseTokenAmount = 0; + + uint256 interopBundleCallsLength = interopBundle.calls.length; + + for (uint256 callCount = 0; callCount < interopBundleCallsLength; ++callCount) { + InteropCall memory interopCall = interopBundle.calls[callCount]; + + if (interopCall.value > 0) { + totalBaseTokenAmount += interopCall.value; + } + + // e.g. for direct calls we just skip + if (interopCall.from != L2_ASSET_ROUTER_ADDR) { + continue; + } + + if (bytes4(interopCall.data) != AssetRouterBase.finalizeDeposit.selector) { + revert InvalidInteropCalldata(bytes4(interopCall.data)); + } + // solhint-disable-next-line + _processInteropCall(_chainId, bundleHash, interopCall, interopBundle.destinationChainId); + } + _decreaseChainBalance(_chainId, _baseTokenAssetId, totalBaseTokenAmount); + interopBalanceChange[interopBundle.destinationChainId][bundleHash].baseTokenAmount = totalBaseTokenAmount; + } + + function _processInteropCall( + uint256 _chainId, + bytes32 _bundleHash, + InteropCall memory _interopCall, + uint256 _destinationChainId + ) internal { + (uint256 fromChainId, bytes32 assetId, bytes memory transferData) = this.parseInteropCall(_interopCall.data); + + require(_chainId == fromChainId, InvalidInteropChainId(fromChainId, _destinationChainId)); + + uint256 amount = _handleAssetRouterMessageInner(_chainId, _destinationChainId, assetId, transferData); + + AssetBalanceChange memory change = AssetBalanceChange({assetId: assetId, amount: amount}); + interopBalanceChange[_destinationChainId][_bundleHash].assetBalanceChanges.push(change); + } + + function _handleInteropHandlerReceiveMessage( + uint256 _chainId, + bytes calldata _message, + bytes32 _baseTokenAssetId + ) internal { + bytes4 functionSelector = bytes4(_message[0:4]); + require(functionSelector == IInteropHandler.verifyBundle.selector, InvalidFunctionSignature(functionSelector)); + bytes32 bundleHash = bytes32(_message[4:36]); + + InteropBalanceChange memory receivedInteropBalanceChange = interopBalanceChange[_chainId][bundleHash]; + require( + receivedInteropBalanceChange.version == INTEROP_BALANCE_CHANGE_VERSION, + InvalidInteropBalanceChange(bundleHash) + ); + interopBalanceChange[_chainId][bundleHash].version = 0; + + uint256 length = receivedInteropBalanceChange.assetBalanceChanges.length; + uint256 chainMigrationNumber = _getChainMigrationNumber(_chainId); + for (uint256 i = 0; i < length; ++i) { + uint256 amount = receivedInteropBalanceChange.assetBalanceChanges[i].amount; + interopBalanceChange[_chainId][bundleHash].assetBalanceChanges[i].assetId = bytes32(0); + interopBalanceChange[_chainId][bundleHash].assetBalanceChanges[i].amount = 0; + _increaseAndSaveChainBalance( + _chainId, + receivedInteropBalanceChange.assetBalanceChanges[i].assetId, + amount, + chainMigrationNumber + ); + } + interopBalanceChange[_chainId][bundleHash].baseTokenAmount = 0; + _increaseAndSaveChainBalance( + _chainId, + _baseTokenAssetId, + receivedInteropBalanceChange.baseTokenAmount, + chainMigrationNumber + ); + } + + /// @notice L2->L1 withdrawals go through the L2AssetRouter directly. + function _handleAssetRouterMessage(uint256 _chainId, bytes memory _message) internal { + // slither-disable-next-line unused-return + (bytes4 functionSignature, , bytes32 assetId, bytes memory transferData) = DataEncoding + .decodeAssetRouterFinalizeDepositData(_message); + require( + functionSignature == AssetRouterBase.finalizeDeposit.selector, + InvalidFunctionSignature(functionSignature) + ); + _handleAssetRouterMessageInner(_chainId, L1_CHAIN_ID, assetId, transferData); + } + + /// @notice Handles the logic of the AssetRouter message. + /// @param _sourceChainId The chain id of the source chain. Can not be L1. + /// @param _destinationChainId The chain id of the destination chain. Can be L1. + /// @param _assetId The asset id of the asset. + /// @param _transferData The transfer data of the asset. + /// @dev This function is used to handle the logic of the AssetRouter message. + + function _handleAssetRouterMessageInner( + uint256 _sourceChainId, + uint256 _destinationChainId, + bytes32 _assetId, + bytes memory _transferData + ) internal returns (uint256 amount) { + address originalToken; + bytes memory erc20Metadata; + // slither-disable-next-line unused-return + (, , originalToken, amount, erc20Metadata) = DataEncoding.decodeBridgeMintData(_transferData); + // slither-disable-next-line unused-return + (uint256 tokenOriginalChainId, , , ) = this.parseTokenData(erc20Metadata); + DataEncoding.assetIdCheck(tokenOriginalChainId, _assetId, originalToken); + _registerToken(_assetId, originalToken, tokenOriginalChainId); + + _handleChainBalanceChangeOnGateway({ + _sourceChainId: _sourceChainId, + _destinationChainId: _destinationChainId, + _assetId: _assetId, + _amount: amount + }); + } + + function _handleChainBalanceChangeOnGateway( + uint256 _sourceChainId, + uint256 _destinationChainId, + bytes32 _assetId, + uint256 _amount + ) internal { + if (_amount > 0) { + /// Note, we don't track L1 chainBalance on Gateway. + if (_sourceChainId != L1_CHAIN_ID) { + _decreaseChainBalance(_sourceChainId, _assetId, _amount); + } + if (_destinationChainId != L1_CHAIN_ID) { + uint256 chainMigrationNumber = _getChainMigrationNumber(_destinationChainId); + _increaseAndSaveChainBalance(_destinationChainId, _assetId, _amount, chainMigrationNumber); + } + } + } + + /// @notice Handles withdrawal messages from legacy shared bridge contracts on pre-V30 chains. + /// @dev This function provides backwards compatibility for chains that used the old bridge system. + /// @param _chainId The chain ID that sent the legacy withdrawal message. + /// @param _message The raw legacy bridge message containing withdrawal data. + function _handleLegacySharedBridgeMessage(uint256 _chainId, bytes memory _message) internal { + (bytes4 functionSignature, address l1Token, bytes memory transferData) = DataEncoding + .decodeLegacyFinalizeWithdrawalData(_message); + require( + functionSignature == IL1ERC20Bridge.finalizeWithdrawal.selector, + InvalidFunctionSignature(functionSignature) + ); + /// The legacy shared bridge message is only for L1 tokens on legacy chains where the legacy L2 shared bridge is deployed. + // Convert legacy L1 token to modern asset ID format + bytes32 expectedAssetId = DataEncoding.encodeNTVAssetId(L1_CHAIN_ID, l1Token); + + // Process the withdrawal using the modern asset router logic + // slither-disable-next-line unused-return + _handleAssetRouterMessageInner(_chainId, L1_CHAIN_ID, expectedAssetId, transferData); + } + + /// @notice L2->L1 base token withdrawals go through the L2BaseTokenSystemContract directly. + function _handleBaseTokenSystemContractMessage( + uint256 _chainId, + bytes32 _baseTokenAssetId, + bytes memory _message + ) internal { + // slither-disable-next-line unused-return + (bytes4 functionSignature, , uint256 amount) = DataEncoding.decodeBaseTokenFinalizeWithdrawalData(_message); + require( + functionSignature == IMailboxImpl.finalizeEthWithdrawal.selector, + InvalidFunctionSignature(functionSignature) + ); + _decreaseChainBalance(_chainId, _baseTokenAssetId, amount); + } + + /// @notice this function is a bit unintuitive since the Gateway AssetTracker checks the messages sent by the L2 AssetTracker, + /// since we check the messages from all built-in contracts. + /// However this is not where the receiveMigrationOnL1 function is processed, but on L1. + function _checkAssetTrackerMessageSelector(bytes memory _message) internal pure { + bytes4 functionSignature = DataEncoding.getSelector(_message); + require( + functionSignature == IAssetTrackerDataEncoding.receiveMigrationOnL1.selector, + InvalidFunctionSignature(functionSignature) + ); + } + + /*////////////////////////////////////////////////////////////// + Gateway related token balance migration + //////////////////////////////////////////////////////////////*/ + + /// @notice used to pause deposits on Gateway from L1 for migration back to L1. + function requestPauseDepositsForChain(uint256 _chainId, uint256 _timestamp) external onlyServiceTransactionSender { + address zkChain = _bridgehub().getZKChain(_chainId); + require(zkChain != address(0), ChainIdNotRegistered(_chainId)); + IMailboxImpl(zkChain).pauseDepositsOnGateway(_timestamp); + } + + /// @notice Migrates the token balance from Gateway to L1. + /// @dev This function can be called multiple times on the Gateway as it saves the chainBalance on the first call. + /// @dev This function is permissionless. + function initiateGatewayToL1MigrationOnGateway(uint256 _chainId, bytes32 _assetId) external { + address zkChain = L2_BRIDGEHUB.getZKChain(_chainId); + require(zkChain != address(0), ChainIdNotRegistered(_chainId)); + + // If the chain already migrated back to GW, then we need the previous migration number. + uint256 chainMigrationNumber = _calculatePreviousChainMigrationNumber(_chainId); + require(assetMigrationNumber[_chainId][_assetId] < chainMigrationNumber, InvalidAssetId(_assetId)); + // We don't save chainBalance here since it might not be the final chainBalance for this value of the chainMigrationNumber. + uint256 amount = _getOrSaveChainBalance(_chainId, _assetId, chainMigrationNumber); + + TokenBalanceMigrationData memory tokenBalanceMigrationData = TokenBalanceMigrationData({ + version: TOKEN_BALANCE_MIGRATION_DATA_VERSION, + chainId: _chainId, + assetId: _assetId, + tokenOriginChainId: tokenOriginChainId[_assetId], + amount: amount, + chainMigrationNumber: chainMigrationNumber, + assetMigrationNumber: assetMigrationNumber[_chainId][_assetId], + originToken: originToken[_assetId], + isL1ToGateway: false + }); + + _sendMigrationDataToL1(tokenBalanceMigrationData); + } + + function _calculatePreviousChainMigrationNumber(uint256 _chainId) internal view returns (uint256) { + uint256 settlementLayer = L2_BRIDGEHUB.settlementLayer(_chainId); + uint256 chainMigrationNumber = _getChainMigrationNumber(_chainId); + // If the chain already migrated back to GW, then we need the previous migration number. + if (settlementLayer == block.chainid) { + --chainMigrationNumber; + } + return chainMigrationNumber; + } + + /// @notice Gets the chain balance for migration, saving it if this is the first time it's accessed. + /// @dev This function implements a "snapshot and clear" pattern for chain balances during migration. + /// @dev On first access, it saves the current chainBalance and sets it to 0 to prevent double-spending. + /// @dev Subsequent accesses return the saved value without modifying the current chainBalance. + /// @param _chainId The chain ID whose balance is being queried. + /// @param _assetId The asset ID of the token. + /// @param _migrationNumber The migration number for this operation. + /// @return The saved chain balance for this migration. + function _getOrSaveChainBalance( + uint256 _chainId, + bytes32 _assetId, + uint256 _migrationNumber + ) internal returns (uint256) { + // Check if we've already saved the balance for this migration + SavedTotalSupply memory tokenSavedTotalSupply = savedChainBalance[_chainId][_migrationNumber][_assetId]; + if (!tokenSavedTotalSupply.isSaved) { + // First time accessing this balance for this migration number + // Save the current balance and reset the chainBalance to 0 + tokenSavedTotalSupply.amount = chainBalance[_chainId][_assetId]; + // Persist the saved balance for this specific migration + savedChainBalance[_chainId][_migrationNumber][_assetId] = SavedTotalSupply({ + isSaved: true, + amount: tokenSavedTotalSupply.amount + }); + } + + // Return the balance that was available at the time of this migration + return tokenSavedTotalSupply.amount; + } + + /// @notice Confirms a migration operation has been completed and updates the asset migration number. + /// @param _data The migration confirmation data containing chain ID, asset ID, and migration number. + function confirmMigrationOnGateway( + ConfirmBalanceMigrationData calldata _data + ) external onlyServiceTransactionSender { + assetMigrationNumber[_data.chainId][_data.assetId] = _data.migrationNumber; + if (_data.isL1ToGateway) { + /// In this case the balance might never have been migrated back to L1. + chainBalance[_data.chainId][_data.assetId] += _data.amount; + } else { + _decreaseChainBalance(_data.chainId, _data.assetId, _data.amount); + + uint256 chainMigrationNumber = _calculatePreviousChainMigrationNumber(_data.chainId); + SavedTotalSupply memory savedBalance = savedChainBalance[_data.chainId][chainMigrationNumber][ + _data.assetId + ]; + if (savedBalance.isSaved) { + savedChainBalance[_data.chainId][chainMigrationNumber][_data.assetId].amount = + savedBalance.amount - + _data.amount; + } + } + } + + /*////////////////////////////////////////////////////////////// + Helper Functions + //////////////////////////////////////////////////////////////*/ + + function _increaseAndSaveChainBalance( + uint256 _chainId, + bytes32 _assetId, + uint256 _amount, + uint256 _chainMigrationNumber + ) internal { + // We save the chainBalance for the previous migration number so that the chain balance can be migrated back to GW in case it was not migrated. + // Note, that for this logic to be correct, we need to ensure that `_chainMigrationNumber` is odd, i.e. the chain actually + // actively settles on top of Gateway. + _getOrSaveChainBalance(_chainId, _assetId, _chainMigrationNumber - 1); + // we increase the chain balance of the token. + if (_amount > 0) { + chainBalance[_chainId][_assetId] += _amount; + } + } + + function _registerToken(bytes32 _assetId, address _originalToken, uint256 _tokenOriginChainId) internal { + if (originToken[_assetId] == address(0)) { + originToken[_assetId] = _originalToken; + tokenOriginChainId[_assetId] = _tokenOriginChainId; + } + } + + /// @notice Parses interop call data to extract transfer information. + /// @param _callData The encoded call data containing transfer information. + /// @return fromChainId The chain ID from which the transfer originates. + /// @return assetId The asset ID of the token being transferred. + /// @return transferData The encoded transfer data. + function parseInteropCall( + bytes calldata _callData + ) external pure returns (uint256 fromChainId, bytes32 assetId, bytes memory transferData) { + (fromChainId, assetId, transferData) = abi.decode(_callData[4:], (uint256, bytes32, bytes)); + } + + /// @notice Parses token metadata from encoded token data. + /// @param _tokenData The encoded token metadata. + /// @return originChainId The chain ID where the token was originally created. + /// @return name The token name as encoded bytes. + /// @return symbol The token symbol as encoded bytes. + /// @return decimals The token decimals as encoded bytes. + function parseTokenData( + bytes calldata _tokenData + ) external pure returns (uint256 originChainId, bytes memory name, bytes memory symbol, bytes memory decimals) { + (originChainId, name, symbol, decimals) = DataEncoding.decodeTokenData(_tokenData); + } + + function _getChainMigrationNumber(uint256 _chainId) internal view override returns (uint256) { + return L2_CHAIN_ASSET_HANDLER.migrationNumber(_chainId); + } +} diff --git a/l1-contracts/contracts/bridge/asset-tracker/IAssetTrackerBase.sol b/l1-contracts/contracts/bridge/asset-tracker/IAssetTrackerBase.sol new file mode 100644 index 0000000000..793329c84b --- /dev/null +++ b/l1-contracts/contracts/bridge/asset-tracker/IAssetTrackerBase.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.21; + +bytes1 constant BALANCE_CHANGE_VERSION = bytes1(uint8(1)); +bytes1 constant TOKEN_BALANCE_MIGRATION_DATA_VERSION = bytes1(uint8(1)); +bytes1 constant INTEROP_BALANCE_CHANGE_VERSION = bytes1(uint8(1)); +uint256 constant MAX_TOKEN_BALANCE = type(uint256).max; + +struct SavedTotalSupply { + bool isSaved; + uint256 amount; +} + +interface IAssetTrackerBase { + function tokenMigratedThisChain(bytes32 _assetId) external view returns (bool); + + function tokenMigrated(uint256 _chainId, bytes32 _assetId) external view returns (bool); + + function registerNewToken(bytes32 _assetId, uint256 _originChainId) external; + + function chainBalance(uint256 _chainId, bytes32 _assetId) external view returns (uint256); +} diff --git a/l1-contracts/contracts/bridge/asset-tracker/IAssetTrackerDataEncoding.sol b/l1-contracts/contracts/bridge/asset-tracker/IAssetTrackerDataEncoding.sol new file mode 100644 index 0000000000..0ac4cfb8f7 --- /dev/null +++ b/l1-contracts/contracts/bridge/asset-tracker/IAssetTrackerDataEncoding.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.21; + +import {TokenBalanceMigrationData} from "../../common/Messaging.sol"; + +interface IAssetTrackerDataEncoding { + function receiveMigrationOnL1(TokenBalanceMigrationData calldata _data) external; +} diff --git a/l1-contracts/contracts/bridge/asset-tracker/IGWAssetTracker.sol b/l1-contracts/contracts/bridge/asset-tracker/IGWAssetTracker.sol new file mode 100644 index 0000000000..55bb242b62 --- /dev/null +++ b/l1-contracts/contracts/bridge/asset-tracker/IGWAssetTracker.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.21; + +import {ProcessLogsInput} from "../../state-transition/chain-interfaces/IExecutor.sol"; +import {BalanceChange, ConfirmBalanceMigrationData} from "../../common/Messaging.sol"; + +interface IGWAssetTracker { + function setAddresses(uint256 _l1ChainId) external; + + function handleChainBalanceIncreaseOnGateway( + uint256 _chainId, + bytes32 _canonicalTxHash, + BalanceChange calldata _balanceChange + ) external; + + function processLogsAndMessages(ProcessLogsInput calldata) external; + + function initiateGatewayToL1MigrationOnGateway(uint256 _chainId, bytes32 _assetId) external; + + function confirmMigrationOnGateway(ConfirmBalanceMigrationData calldata _tokenBalanceMigrationData) external; + + function setLegacySharedBridgeAddress(uint256 _chainId, address _legacySharedBridgeAddress) external; + + function requestPauseDepositsForChain(uint256 _chainId, uint256 _timestamp) external; +} diff --git a/l1-contracts/contracts/bridge/asset-tracker/IL1AssetTracker.sol b/l1-contracts/contracts/bridge/asset-tracker/IL1AssetTracker.sol new file mode 100644 index 0000000000..08445ee08a --- /dev/null +++ b/l1-contracts/contracts/bridge/asset-tracker/IL1AssetTracker.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.21; + +import {FinalizeL1DepositParams} from "../../common/Messaging.sol"; +import {IBridgehubBase} from "../../bridgehub/IBridgehubBase.sol"; + +interface IL1AssetTracker { + function BRIDGE_HUB() external view returns (IBridgehubBase); + + function handleChainBalanceIncreaseOnL1( + uint256 _chainId, + bytes32 _assetId, + uint256 _amount, + uint256 _tokenOriginChainId + ) external; + + function handleChainBalanceDecreaseOnL1( + uint256 _chainId, + bytes32 _assetId, + uint256 _amount, + uint256 _tokenOriginChainId + ) external; + + function receiveMigrationOnL1(FinalizeL1DepositParams calldata _finalizeWithdrawalParams) external; + + function migrateTokenBalanceFromNTVV30(uint256 _chainId, bytes32 _assetId) external; + + function consumeBalanceChange( + uint256 _callerChainId, + uint256 _chainId + ) external returns (bytes32 assetId, uint256 amount); + + function setAddresses() external; + + function requestPauseDepositsForChainOnGateway(uint256 _chainId, uint256 _timestamp) external; +} diff --git a/l1-contracts/contracts/bridge/asset-tracker/IL2AssetTracker.sol b/l1-contracts/contracts/bridge/asset-tracker/IL2AssetTracker.sol new file mode 100644 index 0000000000..991a89fc64 --- /dev/null +++ b/l1-contracts/contracts/bridge/asset-tracker/IL2AssetTracker.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.21; + +import {ConfirmBalanceMigrationData} from "../../common/Messaging.sol"; + +interface IL2AssetTracker { + function setAddresses(uint256 _l1ChainId, bytes32 _baseTokenAssetId) external; + + function handleInitiateBridgingOnL2(bytes32 _assetId, uint256 _amount, uint256 _tokenOriginChainId) external; + + function handleInitiateBaseTokenBridgingOnL2(uint256 _amount) external; + + function handleFinalizeBaseTokenBridgingOnL2(uint256 _amount) external; + + function handleFinalizeBridgingOnL2( + bytes32 _assetId, + uint256 _amount, + uint256 _tokenOriginChainId, + address _tokenAddress + ) external; + + function initiateL1ToGatewayMigrationOnL2(bytes32 _assetId) external; + + function confirmMigrationOnL2(ConfirmBalanceMigrationData calldata _tokenBalanceMigrationData) external; + + function registerLegacyTokenOnChain(bytes32 _assetId) external; +} diff --git a/l1-contracts/contracts/bridge/asset-tracker/L1AssetTracker.sol b/l1-contracts/contracts/bridge/asset-tracker/L1AssetTracker.sol new file mode 100644 index 0000000000..baeb25b65d --- /dev/null +++ b/l1-contracts/contracts/bridge/asset-tracker/L1AssetTracker.sol @@ -0,0 +1,431 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; + +import {ConfirmBalanceMigrationData, TokenBalanceMigrationData} from "../../common/Messaging.sol"; +import {GW_ASSET_TRACKER_ADDR, L2_ASSET_TRACKER_ADDR} from "../../common/l2-helpers/L2ContractAddresses.sol"; +import {INativeTokenVaultBase} from "../ntv/INativeTokenVaultBase.sol"; +import {InvalidProof, ZeroAddress, InvalidChainId, Unauthorized} from "../../common/L1ContractErrors.sol"; +import {IMessageRoot, V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_GATEWAY} from "../../bridgehub/IMessageRoot.sol"; +import {IBridgehubBase} from "../../bridgehub/IBridgehubBase.sol"; +import {FinalizeL1DepositParams, IL1Nullifier} from "../../bridge/interfaces/IL1Nullifier.sol"; +import {IMailbox} from "../../state-transition/chain-interfaces/IMailbox.sol"; +import {IL1NativeTokenVault} from "../../bridge/ntv/IL1NativeTokenVault.sol"; + +import {TransientPrimitivesLib} from "../../common/libraries/TransientPrimitives/TransientPrimitives.sol"; +import {InvalidChainMigrationNumber, InvalidFunctionSignature, InvalidMigrationNumber, InvalidSender, InvalidWithdrawalChainId, NotMigratedChain, OnlyWhitelistedSettlementLayer, TransientBalanceChangeAlreadySet, InvalidVersion, L1TotalSupplyAlreadyMigrated, InvalidAssetMigrationNumber, InvalidSettlementLayer} from "./AssetTrackerErrors.sol"; +import {V30UpgradeChainBatchNumberNotSet} from "../../bridgehub/L1BridgehubErrors.sol"; +import {AssetTrackerBase} from "./AssetTrackerBase.sol"; +import {TOKEN_BALANCE_MIGRATION_DATA_VERSION} from "./IAssetTrackerBase.sol"; +import {IL2AssetTracker} from "./IL2AssetTracker.sol"; +import {IGWAssetTracker} from "./IGWAssetTracker.sol"; +import {IL1AssetTracker} from "./IL1AssetTracker.sol"; +import {DataEncoding} from "../../common/libraries/DataEncoding.sol"; +import {IChainAssetHandler} from "../../bridgehub/IChainAssetHandler.sol"; +import {IAssetTrackerDataEncoding} from "./IAssetTrackerDataEncoding.sol"; + +contract L1AssetTracker is AssetTrackerBase, IL1AssetTracker { + uint256 public immutable L1_CHAIN_ID; + + IBridgehubBase public immutable BRIDGE_HUB; + + INativeTokenVaultBase public immutable NATIVE_TOKEN_VAULT; + + IMessageRoot public immutable MESSAGE_ROOT; + + IL1Nullifier public immutable L1_NULLIFIER; + + IChainAssetHandler public chainAssetHandler; + + /// Todo Deprecate after V30 is finished. + mapping(bytes32 assetId => bool l1TotalSupplyMigrated) internal l1TotalSupplyMigrated; + + function _l1ChainId() internal view override returns (uint256) { + return L1_CHAIN_ID; + } + + function _bridgehub() internal view override returns (IBridgehubBase) { + return BRIDGE_HUB; + } + + function _nativeTokenVault() internal view override returns (INativeTokenVaultBase) { + return NATIVE_TOKEN_VAULT; + } + + function _messageRoot() internal view override returns (IMessageRoot) { + return MESSAGE_ROOT; + } + + modifier onlyWhitelistedSettlementLayer(uint256 _callerChainId) { + require( + _bridgehub().whitelistedSettlementLayers(_callerChainId) && + _bridgehub().getZKChain(_callerChainId) == msg.sender, + OnlyWhitelistedSettlementLayer(_bridgehub().getZKChain(_callerChainId), msg.sender) + ); + _; + } + + /// @notice Modifier to ensure the caller is the specified chain. + /// @param _chainId The ID of the chain that has to be the caller. + modifier onlyChain(uint256 _chainId) { + if (msg.sender != BRIDGE_HUB.getZKChain(_chainId)) { + revert Unauthorized(msg.sender); + } + _; + } + + /*////////////////////////////////////////////////////////////// + Initialization + //////////////////////////////////////////////////////////////*/ + + constructor( + uint256 _l1ChainId, + address _bridgehub, + address, + address _nativeTokenVault, + address _messageRoot + ) reentrancyGuardInitializer { + _disableInitializers(); + + L1_CHAIN_ID = _l1ChainId; + BRIDGE_HUB = IBridgehubBase(_bridgehub); + NATIVE_TOKEN_VAULT = INativeTokenVaultBase(_nativeTokenVault); + MESSAGE_ROOT = IMessageRoot(_messageRoot); + L1_NULLIFIER = IL1Nullifier(IL1NativeTokenVault(_nativeTokenVault).L1_NULLIFIER()); + } + + function initialize(address _owner) external reentrancyGuardInitializer initializer { + require(_owner != address(0), ZeroAddress()); + _transferOwnership(_owner); + } + + function setAddresses() external onlyOwner { + chainAssetHandler = IChainAssetHandler(BRIDGE_HUB.chainAssetHandler()); + } + + /// @notice This function is used to migrate the token balance from the NTV to the AssetTracker for V30 upgrade. + /// @param _chainId The chain id of the chain to migrate the token balance for. + /// @param _assetId The asset id of the token to migrate the token balance for. + function migrateTokenBalanceFromNTVV30(uint256 _chainId, bytes32 _assetId) external { + IL1NativeTokenVault l1NTV = IL1NativeTokenVault(address(NATIVE_TOKEN_VAULT)); + uint256 originChainId = NATIVE_TOKEN_VAULT.originChainId(_assetId); + // We do not migrate the chainBalance for the originChain directly, but indirectly by subtracting from MAX_TOKEN_BALANCE. + // Its important to call this for all chains in the ecosystem so that the sum is accurate. + require(_chainId != originChainId, InvalidChainId()); + uint256 migratedBalance; + if (_chainId != block.chainid) { + migratedBalance = l1NTV.migrateTokenBalanceToAssetTracker(_chainId, _assetId); + } else { + address tokenAddress = NATIVE_TOKEN_VAULT.tokenAddress(_assetId); + migratedBalance = IERC20(tokenAddress).totalSupply(); + // Unlike the case where we migrate the balance for L2 chains, the balance inside `L1NativeTokenVault` is not reset to zero, + // and so we need to ensure via the mapping below that the total supply is migrated only once. + require(!l1TotalSupplyMigrated[_assetId], L1TotalSupplyAlreadyMigrated()); + l1TotalSupplyMigrated[_assetId] = true; + } + + // Note it might be the case that the token's balance has not been registered on L1 yet, + // in this case the chainBalance[originChainId][_assetId] is set to MAX_TOKEN_BALANCE if it was not already. + // Note before the token is migrated the MAX_TOKEN_BALANCE is not assigned, since the registerNewToken is only called for new tokens. + _assignMaxChainBalanceIfNeeded(originChainId, _assetId); + chainBalance[originChainId][_assetId] -= migratedBalance; + chainBalance[_chainId][_assetId] += migratedBalance; + } + + function registerNewToken(bytes32 _assetId, uint256 _originChainId) public override onlyNativeTokenVault { + _assignMaxChainBalanceIfNeeded(_originChainId, _assetId); + } + + function _assignMaxChainBalanceIfNeeded(uint256 _originChainId, bytes32 _assetId) internal { + if (!maxChainBalanceAssigned[_assetId]) { + _assignMaxChainBalance(_originChainId, _assetId); + } + } + + /*////////////////////////////////////////////////////////////// + Token deposits and withdrawals + //////////////////////////////////////////////////////////////*/ + + /// @notice Called on the L1 when a deposit to the chain happens. + /// @dev As the chain does not update its balance when settling on L1. + /// @param _chainId The destination chain id of the transfer. + function handleChainBalanceIncreaseOnL1( + uint256 _chainId, + bytes32 _assetId, + uint256 _amount, + uint256 // _tokenOriginChainId + ) external onlyNativeTokenVault { + uint256 currentSettlementLayer = _bridgehub().settlementLayer(_chainId); + if (_tokenCanSkipMigrationOnSettlementLayer(_chainId, _assetId)) { + _forceSetAssetMigrationNumber(_chainId, _assetId); + } + + uint256 chainToUpdate = currentSettlementLayer == block.chainid ? _chainId : currentSettlementLayer; + if (currentSettlementLayer != block.chainid) { + bytes32 baseTokenAssetId = BRIDGE_HUB.baseTokenAssetId(_chainId); + if (baseTokenAssetId != _assetId) { + _setTransientBalanceChange(_chainId, _assetId, _amount); + } + } + + chainBalance[chainToUpdate][_assetId] += _amount; + _decreaseChainBalance(block.chainid, _assetId, _amount); + } + + /// @notice We set the transient balance change so the Mailbox can consume it so the Gateway can keep track of the balance change. + function _setTransientBalanceChange(uint256 _chainId, bytes32 _assetId, uint256 _amount) internal { + uint256 key = uint256(keccak256(abi.encode(_chainId))); + uint256 storedAssetId = TransientPrimitivesLib.getUint256(key); + uint256 storedAmount = TransientPrimitivesLib.getUint256(key + 1); + require(storedAssetId == 0, TransientBalanceChangeAlreadySet(storedAssetId, storedAmount)); + require(storedAmount == 0, TransientBalanceChangeAlreadySet(storedAssetId, storedAmount)); + TransientPrimitivesLib.set(key, uint256(_assetId)); + TransientPrimitivesLib.set(key + 1, _amount); + } + + /// @notice Called on the L1 by the gateway's mailbox when a deposit happens + /// @notice Used for deposits via Gateway. + /// @dev Note that this function assumes that all whitelisted settlement layers are trusted. + function consumeBalanceChange( + uint256 _callerChainId, + uint256 _chainId + ) external onlyWhitelistedSettlementLayer(_callerChainId) returns (bytes32 assetId, uint256 amount) { + uint256 key = uint256(keccak256(abi.encode(_chainId))); + assetId = bytes32(TransientPrimitivesLib.getUint256(key)); + amount = TransientPrimitivesLib.getUint256(key + 1); + TransientPrimitivesLib.set(key, 0); + TransientPrimitivesLib.set(key + 1, 0); + } + + /// @notice Called on the L1 when a withdrawal from the chain happens, or when a failed deposit is undone. + /// @dev As the chain does not update its balance when settling on L1. + function handleChainBalanceDecreaseOnL1( + uint256 _chainId, + bytes32 _assetId, + uint256 _amount, + uint256 // _tokenOriginChainId + ) external onlyNativeTokenVault { + uint256 chainToUpdate = _getWithdrawalChain(_chainId); + + _decreaseChainBalance(chainToUpdate, _assetId, _amount); + chainBalance[block.chainid][_assetId] += _amount; + } + + /// @notice Determines which chain's balance should be updated for a withdrawal operation. + /// @dev This function handles the complex logic around V30 upgrade transitions and settlement layer changes. + /// @dev The key insight is that before V30, withdrawals affected the chain's own balance, but after V30, + /// @dev withdrawals from Gateway-settled chains affect the Gateway's balance instead. + /// @param _chainId The ID of the chain from which the withdrawal is being processed. + /// @return chainToUpdate The chain ID whose balance should be decremented for this withdrawal. + function _getWithdrawalChain(uint256 _chainId) internal view returns (uint256 chainToUpdate) { + (uint256 settlementLayer, uint256 l2BatchNumber) = L1_NULLIFIER.getTransientSettlementLayer(); + // This is the batch starting from which it is the responsibility of all the settlement layers to ensure that + // all withdrawals coming from the chain are backed by the balance of this settlement layer. + // Note, that since this method is used for claiming failed deposits, it implies that any failed deposit that has been processed + // while the chain settled on top of Gateway, has been accredited to Gateway's balance. + // For all the batches smaller or equal to that, the responsibility lies with the chain itself. + uint256 v30UpgradeChainBatchNumber = MESSAGE_ROOT.v30UpgradeChainBatchNumber(_chainId); + + // We need to wait for the proper v30UpgradeChainBatchNumber to be set on the MessageRoot, otherwise we might decrement the chain's chainBalance instead of the gateway's. + require( + v30UpgradeChainBatchNumber != V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_GATEWAY, + V30UpgradeChainBatchNumberNotSet() + ); + if (v30UpgradeChainBatchNumber != 0) { + /// For chains that were settling on GW before V30, we need to update the chain's chainBalance until the chain updates to V30. + /// Logic: If no settlement layer OR the batch number is before V30 upgrade, update the chain itself. + /// Otherwise, update the settlement layer (Gateway) balance. + chainToUpdate = settlementLayer == 0 || l2BatchNumber < v30UpgradeChainBatchNumber + ? _chainId + : settlementLayer; + } else { + /// For chains deployed at V30 or later, the logic is simpler: + /// Update the chain balance if settling on L1, otherwise update the settlement layer balance. + chainToUpdate = settlementLayer == 0 ? _chainId : settlementLayer; + } + } + + /*////////////////////////////////////////////////////////////// + Gateway related token balance migration + //////////////////////////////////////////////////////////////*/ + + /// @notice This function receives the migration from the L2 or the Gateway. + /// @dev It sends the corresponding L1->L2 messages to the L2 and the Gateway. + /// @dev Note, that a chain can potentially be malicious and lie about the `amount` field in the + /// `TokenBalanceMigrationData`. The assetId is validated against the provided token data to prevent + /// manipulation. This method is intended to ensure that a chain can tell + /// how much of the token balance it has on L1 pending from previous withdrawals and how much is active, + /// i.e. the `amount` field in the `TokenBalanceMigrationData` and may be used by interop. + /// If the chain downplays `amount`, it will restrict its users from additional interop, + /// while if it overstates `amount`, it should be able to affect past withdrawals of the chain only. + function receiveMigrationOnL1(FinalizeL1DepositParams calldata _finalizeWithdrawalParams) external { + _proveMessageInclusion(_finalizeWithdrawalParams); + + (bytes4 functionSignature, TokenBalanceMigrationData memory data) = DataEncoding + .decodeTokenBalanceMigrationData(_finalizeWithdrawalParams.message); + require( + functionSignature == IAssetTrackerDataEncoding.receiveMigrationOnL1.selector, + InvalidFunctionSignature(functionSignature) + ); + require(data.version == TOKEN_BALANCE_MIGRATION_DATA_VERSION, InvalidVersion()); + require( + assetMigrationNumber[data.chainId][data.assetId] < data.chainMigrationNumber, + InvalidAssetMigrationNumber() + ); + + uint256 currentSettlementLayer = _bridgehub().settlementLayer(data.chainId); + uint256 fromChainId; + uint256 toChainId; + + // We check the assetId to make sure the chain is not lying about it. + DataEncoding.assetIdCheck(data.tokenOriginChainId, data.assetId, data.originToken); + + if (data.isL1ToGateway) { + uint256 chainMigrationNumber = _getChainMigrationNumber(data.chainId); + // We check the chainMigrationNumber to make sure the message is not from a previous token migration. + // What can happen in theory is the following: + // - Chain starts migration to Gateway (has chainMigrationNumber = n) + // - Migration fails, then chain restores itself on L1 (has chainMigrationNumber = n - 1) + // - Chain starts migration to Gateway again (has chainMigrationNumber = n) + // In this case there are two valid migrations with the same chainMigrationNumber. + // This affects only malicious chains, since a normal chain is not expected to send such a message + // when on L1. In the worst case only this chain is affected. + require( + chainMigrationNumber == data.chainMigrationNumber, + InvalidChainMigrationNumber(chainMigrationNumber, data.chainMigrationNumber) + ); + + // The TokenBalanceMigrationData data might be malicious. + // We check the chainId to match the finalizeWithdrawalParams.chainId. + // The amount might be malicious, but that poses a restriction on users of the chain, not other chains. + // The AssetTracker cannot protect individual users only other chains. Individual users rely on the proof system. + // The last field is migrationNumber, which cannot be abused due to the check above. + require(currentSettlementLayer != block.chainid, NotMigratedChain()); + require(data.chainId == _finalizeWithdrawalParams.chainId, InvalidWithdrawalChainId()); + + // We check parity here to make sure that we migrated the token balance back to L1 from Gateway. + // This is needed to ensure that the chainBalance on the Gateway AssetTracker is currently 0. + // In the future we might initialize chains on GW. So we subtract from chainMigrationNumber. + // Note, that this logic only works well when only a single ZK Gateway can be used as a settlement layer + // for an individual chain as well as the fact that chains can only migrate once on top of Gateway. + // Since `currentSettlementLayer != block.chainid` is checked above, it implies that the current + // `data.chainMigrationNumber` is odd and so after this migration is processed once, it will not be able to be reprocessed, + // due to `assetMigrationNumber` being assigned later.H + require( + (assetMigrationNumber[data.chainId][data.assetId]) % 2 == 0, + InvalidMigrationNumber(chainMigrationNumber, assetMigrationNumber[data.chainId][data.assetId]) + ); + + fromChainId = data.chainId; + toChainId = currentSettlementLayer; + } else { + // In this case we trust the TokenBalanceMigrationData data and the settlement layer = Gateway to be honest. + require( + _bridgehub().whitelistedSettlementLayers(_finalizeWithdrawalParams.chainId), + InvalidWithdrawalChainId() + ); + // The assetMigrationNumber on GW is set via forceSetAssetMigrationNumber to the chainMigrationNumber + // which asset migration number + 1 or it is set by confirmMigrationOnL2 to the actual asset migration number. + // This line also serves for replay protection as later the assetMigrationNumber is set to the chainMigrationNumber. + // We assume that data.chainMigrationNumber is > data.assetMigrationNumber. + uint256 readAssetMigrationNumber = assetMigrationNumber[data.chainId][data.assetId]; + require( + readAssetMigrationNumber == data.assetMigrationNumber || + readAssetMigrationNumber + 1 == data.assetMigrationNumber, + InvalidAssetMigrationNumber() + ); + + // Note, that here, unlike the case above, we do not enforce the `chainMigrationNumber`, since + // we always allow to finalize previous withdrawals. + + fromChainId = _finalizeWithdrawalParams.chainId; + toChainId = data.chainId; + } + + _assignMaxChainBalanceIfNeeded(data.tokenOriginChainId, data.assetId); + _migrateFunds({_fromChainId: fromChainId, _toChainId: toChainId, _assetId: data.assetId, _amount: data.amount}); + + assetMigrationNumber[data.chainId][data.assetId] = data.chainMigrationNumber; + + ConfirmBalanceMigrationData memory confirmBalanceMigrationData = ConfirmBalanceMigrationData({ + version: TOKEN_BALANCE_MIGRATION_DATA_VERSION, + isL1ToGateway: data.isL1ToGateway, + chainId: data.chainId, + assetId: data.assetId, + migrationNumber: data.chainMigrationNumber, + amount: data.amount + }); + + _sendConfirmationToChains( + data.isL1ToGateway ? currentSettlementLayer : _finalizeWithdrawalParams.chainId, + confirmBalanceMigrationData + ); + } + + /// @notice used to pause deposits on Gateway from L1 for migration back to L1. + function requestPauseDepositsForChainOnGateway(uint256 _chainId, uint256 _timestamp) external onlyChain(_chainId) { + uint256 settlementLayer = BRIDGE_HUB.settlementLayer(_chainId); + require(settlementLayer != 0, InvalidSettlementLayer()); + _sendToChain( + settlementLayer, + GW_ASSET_TRACKER_ADDR, + abi.encodeCall(IGWAssetTracker.requestPauseDepositsForChain, (_chainId, _timestamp)) + ); + } + + function _sendConfirmationToChains( + uint256 _settlementLayerChainId, + ConfirmBalanceMigrationData memory _confirmBalanceMigrationData + ) internal { + // We send the confirmMigrationOnGateway first, so that withdrawals are definitely paused until the migration is confirmed on GW. + // Note: the confirmMigrationOnL2 is a L1->GW->L2 txs if the chain is settling on Gateway. + _sendToChain( + _settlementLayerChainId, + GW_ASSET_TRACKER_ADDR, + abi.encodeCall(IGWAssetTracker.confirmMigrationOnGateway, (_confirmBalanceMigrationData)) + ); + _sendToChain( + _confirmBalanceMigrationData.chainId, + L2_ASSET_TRACKER_ADDR, + abi.encodeCall(IL2AssetTracker.confirmMigrationOnL2, (_confirmBalanceMigrationData)) + ); + } + + /// @notice Migrates token balance from one chain to another by updating chainBalance mappings. + /// @dev This is an internal accounting function that moves balance between chains without actual token transfers. + /// @param _fromChainId The chain ID from which to decrease the balance. + /// @param _toChainId The chain ID to which to increase the balance. + /// @param _assetId The asset ID of the token being migrated. + /// @param _amount The amount of tokens to migrate. + function _migrateFunds(uint256 _fromChainId, uint256 _toChainId, bytes32 _assetId, uint256 _amount) internal { + _decreaseChainBalance(_fromChainId, _assetId, _amount); + chainBalance[_toChainId][_assetId] += _amount; + } + + /// @notice Sends a transaction to a specific chain through its mailbox. + /// @dev This is a helper function that resolves the chain address and sends an L2 service transaction. + /// @param _chainId The target chain ID to send the transaction to. + /// @param _to The address of the contract to call on the target chain. + /// @param _data The encoded function call data to send. + function _sendToChain(uint256 _chainId, address _to, bytes memory _data) internal { + address zkChain = _bridgehub().getZKChain(_chainId); + // slither-disable-next-line unused-return + IMailbox(zkChain).requestL2ServiceTransaction(_to, _data); + } + + /// @notice Verifies that a message was properly included in the L2->L1 message system. + /// @param _finalizeWithdrawalParams The parameters containing the message and its inclusion proof. + function _proveMessageInclusion(FinalizeL1DepositParams calldata _finalizeWithdrawalParams) internal view { + require(_finalizeWithdrawalParams.l2Sender == L2_ASSET_TRACKER_ADDR, InvalidSender()); + bool success = MESSAGE_ROOT.proveL1DepositParamsInclusion(_finalizeWithdrawalParams); + if (!success) { + revert InvalidProof(); + } + } + + function _getChainMigrationNumber(uint256 _chainId) internal view override returns (uint256) { + return chainAssetHandler.migrationNumber(_chainId); + } +} diff --git a/l1-contracts/contracts/bridge/asset-tracker/L2AssetTracker.sol b/l1-contracts/contracts/bridge/asset-tracker/L2AssetTracker.sol new file mode 100644 index 0000000000..f3a4fc6a41 --- /dev/null +++ b/l1-contracts/contracts/bridge/asset-tracker/L2AssetTracker.sol @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; + +import {SavedTotalSupply, TOKEN_BALANCE_MIGRATION_DATA_VERSION, MAX_TOKEN_BALANCE} from "./IAssetTrackerBase.sol"; +import {ConfirmBalanceMigrationData, TokenBalanceMigrationData} from "../../common/Messaging.sol"; +import {L2_BASE_TOKEN_SYSTEM_CONTRACT, L2_BRIDGEHUB, L2_CHAIN_ASSET_HANDLER, L2_COMPLEX_UPGRADER_ADDR, L2_MESSAGE_ROOT, L2_NATIVE_TOKEN_VAULT, L2_NATIVE_TOKEN_VAULT_ADDR, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT} from "../../common/l2-helpers/L2ContractAddresses.sol"; +import {INativeTokenVaultBase} from "../ntv/INativeTokenVaultBase.sol"; +import {Unauthorized, InvalidChainId} from "../../common/L1ContractErrors.sol"; +import {IMessageRoot} from "../../bridgehub/IMessageRoot.sol"; +import {IBridgehubBase} from "../../bridgehub/IBridgehubBase.sol"; + +import {AssetIdNotRegistered, MissingBaseTokenAssetId, OnlyGatewaySettlementLayer, TokenBalanceNotMigratedToGateway, MaxChainBalanceAlreadyAssigned} from "./AssetTrackerErrors.sol"; +import {AssetTrackerBase} from "./AssetTrackerBase.sol"; +import {IL2AssetTracker} from "./IL2AssetTracker.sol"; + +contract L2AssetTracker is AssetTrackerBase, IL2AssetTracker { + uint256 public L1_CHAIN_ID; + + bytes32 public BASE_TOKEN_ASSET_ID; + + /// @notice We save the token balance in the first deposit after chain migration. For native tokens, this is the chainBalance; for foreign tokens, this is the total supply. See _handleFinalizeBridgingOnL2Inner for details. + /// We need this to be able to migrate token balance to Gateway AssetTracker from the L1AssetTracker. + mapping(uint256 migrationNumber => mapping(bytes32 assetId => SavedTotalSupply savedTotalSupply)) + internal savedTotalSupply; + + modifier onlyUpgrader() { + if (msg.sender != L2_COMPLEX_UPGRADER_ADDR) { + revert Unauthorized(msg.sender); + } + _; + } + + modifier onlyL2NativeTokenVault() { + if (msg.sender != L2_NATIVE_TOKEN_VAULT_ADDR) { + revert Unauthorized(msg.sender); + } + _; + } + + modifier onlyL2BaseTokenSystemContract() { + if (msg.sender != address(L2_BASE_TOKEN_SYSTEM_CONTRACT)) { + revert Unauthorized(msg.sender); + } + _; + } + + modifier onlyChain(uint256 _chainId) { + if (msg.sender != L2_BRIDGEHUB.getZKChain(_chainId)) { + revert Unauthorized(msg.sender); + } + _; + } + + /// @notice Sets the L1 chain ID and base token asset ID for this L2 chain. + /// @dev This function is called during contract initialization or upgrades. + /// @param _l1ChainId The chain ID of the L1 network. + /// @param _baseTokenAssetId The asset ID of the base token used for gas fees on this chain. + function setAddresses(uint256 _l1ChainId, bytes32 _baseTokenAssetId) external onlyUpgrader { + L1_CHAIN_ID = _l1ChainId; + BASE_TOKEN_ASSET_ID = _baseTokenAssetId; + } + + function _l1ChainId() internal view override returns (uint256) { + return L1_CHAIN_ID; + } + + function _bridgehub() internal view override returns (IBridgehubBase) { + return L2_BRIDGEHUB; + } + + function _nativeTokenVault() internal view override returns (INativeTokenVaultBase) { + return L2_NATIVE_TOKEN_VAULT; + } + + function _messageRoot() internal view override returns (IMessageRoot) { + return L2_MESSAGE_ROOT; + } + + function registerNewToken(bytes32 _assetId, uint256 _originChainId) public override onlyNativeTokenVault { + _registerTokenOnL2(_assetId); + if (_originChainId == block.chainid) { + _assignMaxChainBalance(_originChainId, _assetId); + } + } + + function _registerTokenOnL2(bytes32 _assetId) internal { + /// If the chain is settling on Gateway, then withdrawals are not automatically allowed for new tokens. + if (L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT.currentSettlementLayerChainId() == _l1ChainId()) { + assetMigrationNumber[block.chainid][_assetId] = L2_CHAIN_ASSET_HANDLER.migrationNumber(block.chainid); + } + } + + /// @notice Registers a legacy token on this L2 chain for backwards compatibility. + /// @dev This function is used during upgrades to ensure pre-V30 tokens continue to work. + /// @param _assetId The asset ID of the legacy token to register. + function registerLegacyTokenOnChain(bytes32 _assetId) external onlyNativeTokenVault { + _registerTokenOnL2(_assetId); + } + + /// @notice Migrates token balance tracking from NativeTokenVault to AssetTracker for V30 upgrade. + /// @dev This function calculates the correct chainBalance by accounting for tokens currently held in the NTV. + /// @dev The chainBalance represents how much of the token supply is "available" for bridging out. + /// @param _assetId The asset id of the token to migrate the token balance for. + function migrateTokenBalanceFromNTVV30(bytes32 _assetId) external { + INativeTokenVaultBase ntv = _nativeTokenVault(); + + // Validate that this is a token native to the current L2 + uint256 originChainId = ntv.originChainId(_assetId); + require(originChainId == block.chainid, InvalidChainId()); + + // Get token address + address tokenAddress = ntv.tokenAddress(_assetId); + require(tokenAddress != address(0), AssetIdNotRegistered(_assetId)); + + // Prevent re-initialization if already set + require(!maxChainBalanceAssigned[_assetId], MaxChainBalanceAlreadyAssigned(_assetId)); + + // Mark chainBalance as assigned + maxChainBalanceAssigned[_assetId] = true; + + // Initialize chainBalance + // For origin chains, chainBalance starts at MAX_TOKEN_BALANCE and decreases as tokens are bridged out + // We need to account for tokens currently locked in the NTV from previous bridge operations + uint256 ntvBalance = IERC20(tokenAddress).balanceOf(address(ntv)); + // First, flip the existing chainBalance calculation (was tracking bridged out, now tracks available) + chainBalance[originChainId][_assetId] = MAX_TOKEN_BALANCE - chainBalance[originChainId][_assetId]; + // Then subtract tokens currently locked in NTV (these were already "bridged out" in pre-V30) + chainBalance[originChainId][_assetId] -= ntvBalance; + } + + /*////////////////////////////////////////////////////////////// + Token deposits and withdrawals + //////////////////////////////////////////////////////////////*/ + + /// @notice This function is called for outgoing bridging from the L2, i.e. L2->L1 withdrawals and outgoing L2->L2 interop. + function handleInitiateBridgingOnL2( + bytes32 _assetId, + uint256 _amount, + uint256 _tokenOriginChainId + ) external onlyL2NativeTokenVault { + _handleInitiateBridgingOnL2Inner(_assetId, _amount, _tokenOriginChainId); + } + + function _handleInitiateBridgingOnL2Inner(bytes32 _assetId, uint256 _amount, uint256 _tokenOriginChainId) internal { + _checkAssetMigrationNumber(_assetId); + if (_tokenOriginChainId == block.chainid) { + /// On the L2 we only save chainBalance for native tokens. + _decreaseChainBalance(block.chainid, _assetId, _amount); + } + } + + /// @notice This function is used to check the asset migration number. + /// @dev This is used to pause outgoing withdrawals and interop transactions after the chain migrates to Gateway. + function _checkAssetMigrationNumber(bytes32 _assetId) internal view { + uint256 migrationNumber = _getChainMigrationNumber(block.chainid); + uint256 savedAssetMigrationNumber = assetMigrationNumber[block.chainid][_assetId]; + /// Note we always allow bridging when settling on L1. + /// On Gateway we require that the tokenBalance be migrated to Gateway from L1, + /// otherwise withdrawals might fail in the GWAssetTracker when the chain settles. + require( + savedAssetMigrationNumber == migrationNumber || + L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT.currentSettlementLayerChainId() == _l1ChainId(), + TokenBalanceNotMigratedToGateway(_assetId, savedAssetMigrationNumber, migrationNumber) + ); + } + + /// @notice Handles the initiation of base token bridging operations on L2. + /// @dev This function is specifically for the chain's native base token used for gas payments. + /// @param _amount The amount of base tokens being bridged out. + function handleInitiateBaseTokenBridgingOnL2(uint256 _amount) external onlyL2BaseTokenSystemContract { + bytes32 baseTokenAssetId = BASE_TOKEN_ASSET_ID; + uint256 baseTokenOriginChainId = L2_NATIVE_TOKEN_VAULT.originChainId(baseTokenAssetId); + _handleInitiateBridgingOnL2Inner(baseTokenAssetId, _amount, baseTokenOriginChainId); + } + + /// @notice Handles the finalization of incoming token bridging operations on L2. + /// @dev This function is called when tokens are bridged into this L2 from another chain. + /// @param _assetId The asset ID of the token being bridged in. + /// @param _amount The amount of tokens being bridged in. + /// @param _tokenOriginChainId The chain ID where this token was originally created. + /// @param _tokenAddress The contract address of the token on this chain. + function handleFinalizeBridgingOnL2( + bytes32 _assetId, + uint256 _amount, + uint256 _tokenOriginChainId, + address _tokenAddress + ) external onlyL2NativeTokenVault { + _handleFinalizeBridgingOnL2Inner(_assetId, _amount, _tokenOriginChainId, _tokenAddress); + } + + function _handleFinalizeBridgingOnL2Inner( + bytes32 _assetId, + uint256 _amount, + uint256 _tokenOriginChainId, + address _tokenAddress + ) internal { + if (_needToForceSetAssetMigrationOnL2(_assetId, _tokenOriginChainId, _tokenAddress)) { + _forceSetAssetMigrationNumber(block.chainid, _assetId); + } + + /// We save the total supply for the first deposit after a migration. + uint256 migrationNumber = _getChainMigrationNumber(block.chainid); + /// Here we don't care about the total supply, we only want to save it if it is not already saved. + // solhint-disable-next-line no-unused-vars + _getOrSaveTotalSupply(_assetId, migrationNumber, _tokenOriginChainId, _tokenAddress); + /// On the L2 we only save chainBalance for native tokens. + if (_tokenOriginChainId == block.chainid) { + chainBalance[block.chainid][_assetId] += _amount; + } + } + + /// @notice This saves the total supply if it is not saved yet. It returns the saved total supply. + function _getOrSaveTotalSupply( + bytes32 _assetId, + uint256 _migrationNumber, + uint256 _tokenOriginChainId, + address _tokenAddress + ) internal returns (uint256 _totalSupply) { + SavedTotalSupply memory tokenSavedTotalSupply = savedTotalSupply[_migrationNumber][_assetId]; + if (!tokenSavedTotalSupply.isSaved) { + _totalSupply = _readTotalSupply(_assetId, _tokenOriginChainId, _tokenAddress); + /// This function saves the token supply before the first deposit after the chain migration is processed (in the same transaction). + /// This totalSupply is the chain's total supply at the moment of chain migration. + savedTotalSupply[_migrationNumber][_assetId] = SavedTotalSupply({isSaved: true, amount: _totalSupply}); + } else { + _totalSupply = tokenSavedTotalSupply.amount; + } + } + + function _readTotalSupply( + bytes32 _assetId, + uint256 _tokenOriginChainId, + address _tokenAddress + ) internal view returns (uint256 _totalSupply) { + if (_tokenOriginChainId == block.chainid) { + _totalSupply = chainBalance[block.chainid][_assetId]; + } else { + _totalSupply = IERC20(_tokenAddress).totalSupply(); + } + } + + /// @notice Handles the finalization of incoming base token bridging operations on L2. + /// @dev This function is specifically for the chain's native base token used for gas payments. + /// @param _amount The amount of base tokens being bridged into this chain. + function handleFinalizeBaseTokenBridgingOnL2(uint256 _amount) external onlyL2BaseTokenSystemContract { + bytes32 baseTokenAssetId = BASE_TOKEN_ASSET_ID; + if (_amount == 0) { + return; + } + if (baseTokenAssetId == bytes32(0)) { + /// this means we are before the genesis upgrade, where we don't transfer value, so we can skip. + /// if we don't skip we use incorrect asset id. + revert MissingBaseTokenAssetId(); + } + + _handleFinalizeBridgingOnL2Inner( + baseTokenAssetId, + _amount, + L1_CHAIN_ID, + address(L2_BASE_TOKEN_SYSTEM_CONTRACT) + ); + } + + /*////////////////////////////////////////////////////////////// + Gateway related token balance migration + //////////////////////////////////////////////////////////////*/ + + /// @notice Migrates the token balance from L2 to L1. + /// @dev This function can be called multiple times on the chain it does not have a direct effect. + /// @dev This function is permissionless, it does not affect the state of the contract substantially, and can be called multiple times. + function initiateL1ToGatewayMigrationOnL2(bytes32 _assetId) external { + require( + L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT.currentSettlementLayerChainId() != L1_CHAIN_ID, + OnlyGatewaySettlementLayer() + ); + address tokenAddress = _tryGetTokenAddress(_assetId); + + uint256 originChainId = L2_NATIVE_TOKEN_VAULT.originChainId(_assetId); + address originalToken = L2_NATIVE_TOKEN_VAULT.originToken(_assetId); + + uint256 chainMigrationNumber = _getChainMigrationNumber(block.chainid); + if (chainMigrationNumber == assetMigrationNumber[block.chainid][_assetId]) { + /// In this case the token was either already migrated, or the migration number was set using _forceSetAssetMigrationNumber. + return; + } + uint256 amount = _getOrSaveTotalSupply(_assetId, chainMigrationNumber, originChainId, tokenAddress); + + TokenBalanceMigrationData memory tokenBalanceMigrationData = TokenBalanceMigrationData({ + version: TOKEN_BALANCE_MIGRATION_DATA_VERSION, + chainId: block.chainid, + assetId: _assetId, + tokenOriginChainId: originChainId, + amount: amount, + chainMigrationNumber: chainMigrationNumber, + assetMigrationNumber: assetMigrationNumber[block.chainid][_assetId], + originToken: originalToken, + isL1ToGateway: true + }); + _sendMigrationDataToL1(tokenBalanceMigrationData); + } + + /// @notice Confirms a migration operation has been completed and updates the asset migration number. + /// @dev This function is called by L1 after a migration has been processed to update local state. + /// @param data The migration confirmation data containing the asset ID and migration number. + function confirmMigrationOnL2(ConfirmBalanceMigrationData calldata data) external onlyServiceTransactionSender { + assetMigrationNumber[block.chainid][data.assetId] = data.migrationNumber; + } + + /*////////////////////////////////////////////////////////////// + Helper Functions + //////////////////////////////////////////////////////////////*/ + + /// @notice Determines if a token's migration number should be force-set during bridging operations. + /// @param _assetId The asset ID of the token to check. + /// @param _tokenOriginChainId The chain ID where this token originated. + /// @param _tokenAddress The contract address of the token on this chain. + /// @return bool True if the migration number should be force-set, false otherwise. + function _needToForceSetAssetMigrationOnL2( + bytes32 _assetId, + uint256 _tokenOriginChainId, + address _tokenAddress + ) internal view returns (bool) { + if (_tokenOriginChainId == block.chainid) { + return false; + } + uint256 savedAssetMigrationNumber = assetMigrationNumber[block.chainid][_assetId]; + uint256 amount = IERC20(_tokenAddress).totalSupply(); + + return savedAssetMigrationNumber == 0 && amount == 0; + } + + /// @notice Retrieves the token contract address for a given asset ID. + /// @param _assetId The asset ID to look up. + /// @return tokenAddress The contract address of the token. + function _tryGetTokenAddress(bytes32 _assetId) internal view returns (address tokenAddress) { + tokenAddress = L2_NATIVE_TOKEN_VAULT.tokenAddress(_assetId); + require(tokenAddress != address(0), AssetIdNotRegistered(_assetId)); + } + + function _getChainMigrationNumber(uint256 _chainId) internal view override returns (uint256) { + return L2_CHAIN_ASSET_HANDLER.migrationNumber(_chainId); + } +} diff --git a/l1-contracts/contracts/bridge/asset-tracker/LegacySharedBridgeAddresses.sol b/l1-contracts/contracts/bridge/asset-tracker/LegacySharedBridgeAddresses.sol new file mode 100644 index 0000000000..8389db4a5a --- /dev/null +++ b/l1-contracts/contracts/bridge/asset-tracker/LegacySharedBridgeAddresses.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {InvalidL1AssetRouter} from "./AssetTrackerErrors.sol"; + +struct SharedBridgeOnChainId { + uint256 chainId; + address legacySharedBridgeAddress; +} + +library LegacySharedBridgeAddresses { + uint256 internal constant STAGE_LEGACY_BRIDGES = 0; + uint256 internal constant TESTNET_LEGACY_BRIDGES = 0; + uint256 internal constant MAINNET_LEGACY_BRIDGES = 0; + + address internal constant STAGE_ECOSYSTEM_L1_ASSET_ROUTER_ADDRESS = 0x0000000000000000000000000000000000000000; + address internal constant TESTNET_ECOSYSTEM_L1_ASSET_ROUTER_ADDRESS = 0x0000000000000000000000000000000000000000; + address internal constant MAINNET_ECOSYSTEM_L1_ASSET_ROUTER_ADDRESS = 0x0000000000000000000000000000000000000000; + + /// @dev We have Stage, Testnet and Mainnet ecosystems. + /// We use the l1AssetRouter to distinguish between them, since stage and testnet are both on Sepolia. + function getLegacySharedBridgeAddressOnGateway( + address _l1AssetRouter + ) internal pure returns (SharedBridgeOnChainId[] memory) { + SharedBridgeOnChainId[] memory stageLegacySharedBridgeAddresses = new SharedBridgeOnChainId[]( + STAGE_LEGACY_BRIDGES + ); + SharedBridgeOnChainId[] memory testnetLegacySharedBridgeAddresses = new SharedBridgeOnChainId[]( + TESTNET_LEGACY_BRIDGES + ); + SharedBridgeOnChainId[] memory mainnetLegacySharedBridgeAddresses = new SharedBridgeOnChainId[]( + MAINNET_LEGACY_BRIDGES + ); + + if (_l1AssetRouter == STAGE_ECOSYSTEM_L1_ASSET_ROUTER_ADDRESS) { + return stageLegacySharedBridgeAddresses; + } else if (_l1AssetRouter == TESTNET_ECOSYSTEM_L1_ASSET_ROUTER_ADDRESS) { + return testnetLegacySharedBridgeAddresses; + } else if (_l1AssetRouter == MAINNET_ECOSYSTEM_L1_ASSET_ROUTER_ADDRESS) { + return mainnetLegacySharedBridgeAddresses; + } + revert InvalidL1AssetRouter(_l1AssetRouter); + } +} diff --git a/l1-contracts/contracts/bridge/interfaces/IL1AssetHandler.sol b/l1-contracts/contracts/bridge/interfaces/IL1AssetHandler.sol index 4612387c66..8cccc7f9d9 100644 --- a/l1-contracts/contracts/bridge/interfaces/IL1AssetHandler.sol +++ b/l1-contracts/contracts/bridge/interfaces/IL1AssetHandler.sol @@ -2,6 +2,8 @@ pragma solidity 0.8.28; +import {TxStatus} from "../../common/Messaging.sol"; + /// @title L1 Asset Handler contract interface /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -11,8 +13,9 @@ interface IL1AssetHandler { /// @param _assetId the assetId of the asset being bridged /// @param _depositSender the address of the entity that initiated the deposit. /// @param _data the actual data specified for the function - function bridgeRecoverFailedTransfer( + function bridgeConfirmTransferResult( uint256 _chainId, + TxStatus _txStatus, bytes32 _assetId, address _depositSender, bytes calldata _data diff --git a/l1-contracts/contracts/bridge/interfaces/IL1CrossChainSender.sol b/l1-contracts/contracts/bridge/interfaces/IL1CrossChainSender.sol new file mode 100644 index 0000000000..dc84de26f5 --- /dev/null +++ b/l1-contracts/contracts/bridge/interfaces/IL1CrossChainSender.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.21; + +import {L2TransactionRequestTwoBridgesInner} from "../../bridgehub/IBridgehubBase.sol"; + +/// @title L1 Bridge contract interface +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IL1CrossChainSender { + /// @notice Initiates a transfer transaction within Bridgehub, used by `requestL2TransactionTwoBridges`. + /// @param _chainId Destination chain ID. + /// @param _originalCaller The `msg.sender` address from the external call that initiated current one. + /// @param _value The `msg.value` to be deposited on the target chain. + /// @param _data The calldata for the second bridge deposit. + /// @return request The data used by the bridgehub to create L2 transaction request to specific ZK chain. + function bridgehubDeposit( + uint256 _chainId, + address _originalCaller, + uint256 _value, + bytes calldata _data + ) external payable returns (L2TransactionRequestTwoBridgesInner memory request); + + /// @notice Routes the confirmation to nullifier for backward compatibility. + /// @notice Confirms the acceptance of a transaction by the Mailbox, as part of the L2 transaction process within Bridgehub. + /// This function is utilized by `requestL2TransactionTwoBridges` to validate the execution of a transaction. + /// @param _chainId The chain ID of the ZK chain to which confirm the deposit. + /// @param _txDataHash The keccak256 hash of 0x01 || abi.encode(bytes32, bytes) to identify deposits. + /// @param _txHash The hash of the L1->L2 transaction to confirm the deposit. + function bridgehubConfirmL2Transaction(uint256 _chainId, bytes32 _txDataHash, bytes32 _txHash) external; +} diff --git a/l1-contracts/contracts/bridge/interfaces/IL1Nullifier.sol b/l1-contracts/contracts/bridge/interfaces/IL1Nullifier.sol index 4975a1c91a..ce855d42e6 100644 --- a/l1-contracts/contracts/bridge/interfaces/IL1Nullifier.sol +++ b/l1-contracts/contracts/bridge/interfaces/IL1Nullifier.sol @@ -2,26 +2,16 @@ pragma solidity 0.8.28; +import {IL1AssetRouter} from "../asset-router/IL1AssetRouter.sol"; import {IL1Bridgehub} from "../../bridgehub/IL1Bridgehub.sol"; import {IL1NativeTokenVault} from "../ntv/IL1NativeTokenVault.sol"; import {IL1ERC20Bridge} from "./IL1ERC20Bridge.sol"; +import {FinalizeL1DepositParams, ConfirmTransferResultData} from "../../common/Messaging.sol"; -/// @param chainId The chain ID of the transaction to check. -/// @param l2BatchNumber The L2 batch number where the withdrawal was processed. -/// @param l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message. -/// @param l2sender The address of the message sender on L2 (base token system contract address or asset handler) -/// @param l2TxNumberInBatch The L2 transaction number in the batch, in which the log was sent. -/// @param message The L2 withdraw data, stored in an L2 -> L1 message. -/// @param merkleProof The Merkle proof of the inclusion L2 -> L1 message about withdrawal initialization. -struct FinalizeL1DepositParams { - uint256 chainId; - uint256 l2BatchNumber; - uint256 l2MessageIndex; - address l2Sender; - uint16 l2TxNumberInBatch; - bytes message; - bytes32[] merkleProof; -} +/// @dev Transient storage slot for storing the settlement layer chain ID during proof verification. +/// @dev This slot is used to temporarily store which settlement layer is processing the current proof, +/// @dev and is cleared at the end of each transaction. +uint256 constant TRANSIENT_SETTLEMENT_LAYER_SLOT = uint256(keccak256("TRANSIENT_SETTLEMENT_LAYER_SLOT")) - 1; /// @title L1 Bridge contract interface /// @author Matter Labs @@ -33,6 +23,8 @@ interface IL1Nullifier { bytes32 indexed l2DepositTxHash ); + event TransientSettlementLayerSet(uint256 indexed settlementLayerChainId); + function isWithdrawalFinalized( uint256 _chainId, uint256 _l2BatchNumber, @@ -66,6 +58,8 @@ interface IL1Nullifier { function BRIDGE_HUB() external view returns (IL1Bridgehub); + function l1AssetRouter() external view returns (IL1AssetRouter); + function legacyBridge() external view returns (IL1ERC20Bridge); function depositHappened(uint256 _chainId, bytes32 _l2TxHash) external view returns (bytes32); @@ -86,6 +80,11 @@ interface IL1Nullifier { function nullifyChainBalanceByNTV(uint256 _chainId, address _token) external; + /// @notice Confirms the result of a deposit, whether it was successful or not. + /// @dev This function is used to confirm the migration of a chain to Gateway. + /// @param _confirmTransferResultData The data to confirm the deposit result. + function bridgeConfirmTransferResult(ConfirmTransferResultData calldata _confirmTransferResultData) external; + /// @dev Withdraw funds from the initiated deposit, that failed when finalizing on L2. /// @param _chainId The ZK chain id to which deposit was initiated. /// @param _depositSender The address of the entity that initiated the deposit. @@ -128,4 +127,13 @@ interface IL1Nullifier { bytes calldata _message, bytes32[] calldata _merkleProof ) external; + + /// @notice When verifying recursive proofs, we mark the transient settlement layer, + /// this function retrieves the currently stored transient settlement layer chain ID. + /// @dev The transient settlement layer is cleared at the end of each transaction. + /// @dev Note, that it is hard assumption that must be enforced by all the users of this function: + /// Any operations that reads this value, must be preceded by a successful invocation of L1Nullifier + /// that has set this value. Otherwise, it is possible that the same value is reused multiple times. + /// @return The chain ID of the settlement layer that processed the current proof, or 0 if none is set. + function getTransientSettlementLayer() external view returns (uint256, uint256); } diff --git a/l1-contracts/contracts/bridge/interfaces/IL2CrossChainSender.sol b/l1-contracts/contracts/bridge/interfaces/IL2CrossChainSender.sol new file mode 100644 index 0000000000..bda44cba3d --- /dev/null +++ b/l1-contracts/contracts/bridge/interfaces/IL2CrossChainSender.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.21; + +import {InteropCallStarter} from "../../common/Messaging.sol"; + +/// @title L2 Cross Chain Sender interface +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IL2CrossChainSender { + /// @notice Function that returns an InteropCallStarter corresponding to the interop call. Effectively this initiates a two step call, + /// where there is a middleman in the InteropCall. The expected usage is as follows: + /// We call initiateIndirectCall on contract A on source chain. It returns an interopCallStarter which will be used to pass the call + /// to the destination chain. In this second call the sender is contract A on source chain. This "indirect" call mechanism could be used for complex + /// Interop scenarios, such as bridging. + /// @param _chainId Destination chain ID. + /// @param _originalCaller The `msg.sender` address from the external call that initiated current one. + /// @param _value The `msg.value` to be deposited on the target chain. + /// @param _data The calldata for the second bridge deposit. + /// @return interopCallStarter InteropCallStarter corresponding to the second bridge call. + function initiateIndirectCall( + uint256 _chainId, + address _originalCaller, + uint256 _value, + bytes calldata _data + ) external payable returns (InteropCallStarter memory interopCallStarter); +} diff --git a/l1-contracts/contracts/bridge/ntv/IL1NativeTokenVault.sol b/l1-contracts/contracts/bridge/ntv/IL1NativeTokenVault.sol index f4278c9bbe..b3305b4b79 100644 --- a/l1-contracts/contracts/bridge/ntv/IL1NativeTokenVault.sol +++ b/l1-contracts/contracts/bridge/ntv/IL1NativeTokenVault.sol @@ -5,6 +5,7 @@ pragma solidity 0.8.28; import {IL1Nullifier} from "../interfaces/IL1Nullifier.sol"; import {INativeTokenVaultBase} from "./INativeTokenVaultBase.sol"; import {IL1AssetDeploymentTracker} from "../interfaces/IL1AssetDeploymentTracker.sol"; +import {IL1AssetTracker} from "../asset-tracker/IL1AssetTracker.sol"; /// @title L1 Native token vault contract interface /// @author Matter Labs @@ -21,5 +22,10 @@ interface IL1NativeTokenVault is INativeTokenVaultBase, IL1AssetDeploymentTracke /// @notice Registers ETH token function registerEthToken() external; + /// Used for V30 migrating token balances to AssetTracker + function migrateTokenBalanceToAssetTracker(uint256 _chainId, bytes32 _assetId) external returns (uint256); + + function l1AssetTracker() external view returns (IL1AssetTracker); + event TokenBeaconUpdated(address indexed l2TokenBeacon); } diff --git a/l1-contracts/contracts/bridge/ntv/INativeTokenVaultBase.sol b/l1-contracts/contracts/bridge/ntv/INativeTokenVaultBase.sol index 9d6fbdc4da..9da11eec51 100644 --- a/l1-contracts/contracts/bridge/ntv/INativeTokenVaultBase.sol +++ b/l1-contracts/contracts/bridge/ntv/INativeTokenVaultBase.sol @@ -12,6 +12,15 @@ interface INativeTokenVaultBase { /// @notice Returns the chain ID of the origin chain for a given asset ID function originChainId(bytes32 assetId) external view returns (uint256); + /// @notice Returns the origin token for a given asset ID + function originToken(bytes32 assetId) external view returns (address); + + /// @notice Returns the number of bridged tokens. + function bridgedTokensCount() external view returns (uint256); + + /// @notice Returns the bridged token at index `index`. + function bridgedTokens(uint256 index) external view returns (bytes32); + /// @notice Registers tokens within the NTV. /// @dev The goal is to allow bridging native tokens automatically, by registering them on the fly. /// @notice Allows the bridge to register a token address for the vault. diff --git a/l1-contracts/contracts/bridge/ntv/L1NativeTokenVault.sol b/l1-contracts/contracts/bridge/ntv/L1NativeTokenVault.sol index a2eac8a9cc..ecd2d97388 100644 --- a/l1-contracts/contracts/bridge/ntv/L1NativeTokenVault.sol +++ b/l1-contracts/contracts/bridge/ntv/L1NativeTokenVault.sol @@ -16,15 +16,18 @@ import {IL1AssetHandler} from "../interfaces/IL1AssetHandler.sol"; import {IL1Nullifier} from "../interfaces/IL1Nullifier.sol"; import {IBridgedStandardToken} from "../interfaces/IBridgedStandardToken.sol"; import {IL1AssetRouter} from "../asset-router/IL1AssetRouter.sol"; +import {IL1AssetTracker} from "../asset-tracker/IL1AssetTracker.sol"; +import {IAssetTrackerBase} from "../asset-tracker/IAssetTrackerBase.sol"; import {IAssetRouterBase} from "../asset-router/IAssetRouterBase.sol"; import {IWETH9} from "../interfaces/IWETH9.sol"; import {ETH_TOKEN_ADDRESS} from "../../common/Config.sol"; import {L2_NATIVE_TOKEN_VAULT_ADDR} from "../../common/l2-helpers/L2ContractAddresses.sol"; import {DataEncoding} from "../../common/libraries/DataEncoding.sol"; +import {TxStatus} from "../../common/Messaging.sol"; -import {InsufficientChainBalance, NoFundsTransferred, OriginChainIdNotFound, Unauthorized, WithdrawFailed, ZeroAddress} from "../../common/L1ContractErrors.sol"; -import {ClaimFailedDepositFailed, WrongAmountTransferred, WrongCounterpart, ZeroAmountToTransfer} from "../L1BridgeContractErrors.sol"; +import {NoFundsTransferred, OriginChainIdNotFound, Unauthorized, WithdrawFailed, ZeroAddress} from "../../common/L1ContractErrors.sol"; +import {ClaimFailedDepositFailed, WrongCounterpart, OnlyFailureStatusAllowed} from "../L1BridgeContractErrors.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -48,6 +51,11 @@ contract L1NativeTokenVault is IL1NativeTokenVault, IL1AssetHandler, NativeToken /// @dev L1 nullifier contract that handles legacy functions & finalize withdrawal, confirm l2 tx mappings IL1Nullifier public immutable L1_NULLIFIER; + /// @notice AssetTracker component address on L1. On L2 the address is L2_ASSET_TRACKER_ADDR. + /// It adds one more layer of security on top of cross chain communication. + /// Refer to its documentation for more details. + IL1AssetTracker public l1AssetTracker; + /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ @@ -72,9 +80,34 @@ contract L1NativeTokenVault is IL1NativeTokenVault, IL1AssetHandler, NativeToken return address(WETH_TOKEN); } /// @dev Maps token balances for each chain to prevent unauthorized spending across ZK chains. - /// This serves as a security measure until hyperbridging is implemented. - /// NOTE: this function may be removed in the future, don't rely on it! - mapping(uint256 chainId => mapping(bytes32 assetId => uint256 balance)) public chainBalance; + /// This mapping was deprecated in favor of AssetTracker component, now it will be responsible for tracking chain balances. + /// We have a `chainBalance` function now, which returns the values in this mapping, for backwards compatibility. + // slither-disable-next-line uninitialized-state + mapping(uint256 chainId => mapping(bytes32 assetId => uint256 balance)) internal DEPRECATED_chainBalance; + + /// @dev Returns the value of `DEPRECATED_chainBalance` for backwards compatibility. + /// The function body will be replaced with revert in the next release. + /// @param _chainId The ID of the chain for which the chainBalance gets queried. + /// @param _assetId Asset, the balance of which is being queried. + function chainBalance(uint256 _chainId, bytes32 _assetId) external view returns (uint256) { + return DEPRECATED_chainBalance[_chainId][_assetId]; + } + + /// @dev Returns the AssetTracker component address on L1. + function _assetTracker() internal view override returns (IAssetTrackerBase) { + return IAssetTrackerBase(address(l1AssetTracker)); + } + + modifier onlyAssetTracker() { + if (msg.sender != address(l1AssetTracker)) { + revert Unauthorized(msg.sender); + } + _; + } + + /*////////////////////////////////////////////////////////////// + Initialization + //////////////////////////////////////////////////////////////*/ /// @dev Contract is expected to be used as proxy implementation. /// @dev Initialize the implementation to prevent Parity hack. @@ -89,20 +122,11 @@ contract L1NativeTokenVault is IL1NativeTokenVault, IL1AssetHandler, NativeToken L1_NULLIFIER = _l1Nullifier; } - /// @dev Accepts ether only from the contract that was the shared Bridge. - receive() external payable { - if (address(L1_NULLIFIER) != msg.sender) { - revert Unauthorized(msg.sender); - } - } - /// @dev Initializes a contract for later use. Expected to be used in the proxy /// @param _owner Address which can change pause / unpause the NTV /// implementation. The owner is the Governor and separate from the ProxyAdmin from now on, so that the Governor can call the bridge. function initialize(address _owner, address _bridgedTokenBeacon) external initializer { - if (_owner == address(0)) { - revert ZeroAddress(); - } + require(_owner != address(0), ZeroAddress()); bridgedTokenBeacon = IBeacon(_bridgedTokenBeacon); _transferOwnership(_owner); } @@ -112,46 +136,30 @@ contract L1NativeTokenVault is IL1NativeTokenVault, IL1AssetHandler, NativeToken _unsafeRegisterNativeToken(ETH_TOKEN_ADDRESS); } - /// @notice Transfers tokens from shared bridge as part of the migration process. - /// The shared bridge becomes the L1Nullifier contract. - /// @dev Both ETH and ERC20 tokens can be transferred. Exhausts balance of shared bridge after the first call. - /// @dev Calling second time for the same token will revert. - /// @param _token The address of token to be transferred (address(1) for ether and contract address for ERC20). - function transferFundsFromSharedBridge(address _token) external { - ensureTokenIsRegistered(_token); - if (_token == ETH_TOKEN_ADDRESS) { - uint256 balanceBefore = address(this).balance; - L1_NULLIFIER.transferTokenToNTV(_token); - uint256 balanceAfter = address(this).balance; - if (balanceAfter <= balanceBefore) { - revert NoFundsTransferred(); - } - } else { - uint256 balanceBefore = IERC20(_token).balanceOf(address(this)); - uint256 nullifierChainBalance = IERC20(_token).balanceOf(address(L1_NULLIFIER)); - if (nullifierChainBalance == 0) { - revert ZeroAmountToTransfer(); - } - L1_NULLIFIER.transferTokenToNTV(_token); - uint256 balanceAfter = IERC20(_token).balanceOf(address(this)); - if (balanceAfter - balanceBefore < nullifierChainBalance) { - revert WrongAmountTransferred(balanceAfter - balanceBefore, nullifierChainBalance); - } - } + /// @dev Function used to set AssetTracker component address. + /// Only callable by owner. + /// @param _l1AssetTracker The address of the AssetTracker component. + function setAssetTracker(address _l1AssetTracker) external onlyOwner { + l1AssetTracker = IL1AssetTracker(_l1AssetTracker); } - /// @notice Updates chain token balance within NTV to account for tokens transferred from the shared bridge (part of the migration process). - /// @dev Clears chain balance on the shared bridge after the first call. Subsequent calls will not affect the state. - /// @param _token The address of token to be transferred (address(1) for ether and contract address for ERC20). - /// @param _targetChainId The chain ID of the corresponding ZK chain. - function updateChainBalancesFromSharedBridge(address _token, uint256 _targetChainId) external { - uint256 nullifierChainBalance = L1_NULLIFIER.chainBalance(_targetChainId, _token); - bytes32 assetId = DataEncoding.encodeNTVAssetId(block.chainid, _token); - chainBalance[_targetChainId][assetId] = chainBalance[_targetChainId][assetId] + nullifierChainBalance; - originChainId[assetId] = block.chainid; - L1_NULLIFIER.nullifyChainBalanceByNTV(_targetChainId, _token); + /*////////////////////////////////////////////////////////////// + V30 migration + //////////////////////////////////////////////////////////////*/ + + function migrateTokenBalanceToAssetTracker( + uint256 _chainId, + bytes32 _assetId + ) external onlyAssetTracker returns (uint256) { + uint256 amount = DEPRECATED_chainBalance[_chainId][_assetId]; + DEPRECATED_chainBalance[_chainId][_assetId] = 0; + return amount; } + /*////////////////////////////////////////////////////////////// + Check counterpart Functions + //////////////////////////////////////////////////////////////*/ + /// @notice Used to register the Asset Handler asset in L2 AssetRouter. /// @param _assetHandlerAddressOnCounterpart the address of the asset handler on the counterpart chain. function bridgeCheckCounterpartAddress( @@ -160,9 +168,7 @@ contract L1NativeTokenVault is IL1NativeTokenVault, IL1AssetHandler, NativeToken address, address _assetHandlerAddressOnCounterpart ) external view override onlyAssetRouter { - if (_assetHandlerAddressOnCounterpart != L2_NATIVE_TOKEN_VAULT_ADDR) { - revert WrongCounterpart(); - } + require(_assetHandlerAddressOnCounterpart == L2_NATIVE_TOKEN_VAULT_ADDR, WrongCounterpart()); } function _getOriginChainId(bytes32 _assetId) internal view returns (uint256) { @@ -218,20 +224,23 @@ contract L1NativeTokenVault is IL1NativeTokenVault, IL1AssetHandler, NativeToken //////////////////////////////////////////////////////////////*/ /// @inheritdoc IL1AssetHandler - function bridgeRecoverFailedTransfer( + function bridgeConfirmTransferResult( uint256 _chainId, + TxStatus _txStatus, bytes32 _assetId, address _depositSender, bytes calldata _data ) external payable override requireZeroValue(msg.value) onlyAssetRouter whenNotPaused { + require(_txStatus == TxStatus.Failure, OnlyFailureStatusAllowed()); // slither-disable-next-line unused-return (uint256 _amount, , ) = DataEncoding.decodeBridgeBurnData(_data); address l1Token = tokenAddress[_assetId]; - if (_amount == 0) { - revert NoFundsTransferred(); - } + require(_amount != 0, NoFundsTransferred()); - _handleChainBalanceDecrease(_chainId, _assetId, _amount, false); + // IMPORTANT: We must handle chain balance decrease before giving out funds to the user, + // because otherwise the latter operation (via a malicious token or ETH recipient) + // could've overwritten the transient values from L1Nullifier. + _handleBridgeFromChain({_chainId: _chainId, _assetId: _assetId, _amount: _amount}); if (l1Token == ETH_TOKEN_ADDRESS) { bool callSuccess; @@ -239,9 +248,7 @@ contract L1NativeTokenVault is IL1NativeTokenVault, IL1AssetHandler, NativeToken assembly { callSuccess := call(gas(), _depositSender, _amount, 0, 0, 0, 0) } - if (!callSuccess) { - revert ClaimFailedDepositFailed(); - } + require(callSuccess, ClaimFailedDepositFailed()); } else { uint256 originChainId = _getOriginChainId(_assetId); if (originChainId == block.chainid) { @@ -287,9 +294,7 @@ contract L1NativeTokenVault is IL1NativeTokenVault, IL1AssetHandler, NativeToken assembly { callSuccess := call(gas(), _to, _amount, 0, 0, 0, 0) } - if (!callSuccess) { - revert WithdrawFailed(); - } + require(callSuccess, WithdrawFailed()); } else { // Withdraw funds IERC20(_token).safeTransfer(_to, _amount); @@ -306,43 +311,16 @@ contract L1NativeTokenVault is IL1NativeTokenVault, IL1AssetHandler, NativeToken return BeaconProxy(payable(proxyAddress)); } - function _handleChainBalanceIncrease( - uint256 _chainId, - bytes32 _assetId, - uint256 _amount, - bool _isNative - ) internal override { - // Note, that we do not update balances for chains where the assetId comes from, - // since these chains can mint new instances of the token. - if (!_hasInfiniteBalance(_isNative, _assetId, _chainId)) { - chainBalance[_chainId][_assetId] += _amount; - } - } - - function _handleChainBalanceDecrease( - uint256 _chainId, - bytes32 _assetId, - uint256 _amount, - bool _isNative - ) internal override { - // Note, that we do not update balances for chains where the assetId comes from, - // since these chains can mint new instances of the token. - if (!_hasInfiniteBalance(_isNative, _assetId, _chainId)) { - // Check that the chain has sufficient balance - if (chainBalance[_chainId][_assetId] < _amount) { - revert InsufficientChainBalance(); - } - chainBalance[_chainId][_assetId] -= _amount; - } + function _handleBridgeToChain(uint256 _chainId, bytes32 _assetId, uint256 _amount) internal override { + l1AssetTracker.handleChainBalanceIncreaseOnL1(_chainId, _assetId, _amount, _getOriginChainId(_assetId)); } - /// @dev Returns whether a chain `_chainId` has infinite balance for an asset `_assetId`, i.e. - /// it can be minted by it. - /// @param _isNative Whether the asset is native to the L1 chain. - /// @param _assetId The asset id - /// @param _chainId An id of a chain which we test against. - /// @return Whether The chain `_chainId` has infinite balance of the token - function _hasInfiniteBalance(bool _isNative, bytes32 _assetId, uint256 _chainId) private view returns (bool) { - return !_isNative && originChainId[_assetId] == _chainId; + function _handleBridgeFromChain(uint256 _chainId, bytes32 _assetId, uint256 _amount) internal override { + l1AssetTracker.handleChainBalanceDecreaseOnL1({ + _chainId: _chainId, + _assetId: _assetId, + _amount: _amount, + _tokenOriginChainId: _getOriginChainId(_assetId) + }); } } diff --git a/l1-contracts/contracts/bridge/ntv/L2NativeTokenVault.sol b/l1-contracts/contracts/bridge/ntv/L2NativeTokenVault.sol index 8526f83302..44652bdac2 100644 --- a/l1-contracts/contracts/bridge/ntv/L2NativeTokenVault.sol +++ b/l1-contracts/contracts/bridge/ntv/L2NativeTokenVault.sol @@ -13,15 +13,15 @@ import {NativeTokenVaultBase} from "./NativeTokenVaultBase.sol"; import {IL2SharedBridgeLegacy} from "../interfaces/IL2SharedBridgeLegacy.sol"; import {IL2AssetRouter} from "../asset-router/IL2AssetRouter.sol"; +import {IAssetTrackerBase} from "../asset-tracker/IAssetTrackerBase.sol"; -import {L2_ASSET_ROUTER_ADDR, L2_COMPLEX_UPGRADER_ADDR, L2_DEPLOYER_SYSTEM_CONTRACT_ADDR} from "../../common/l2-helpers/L2ContractAddresses.sol"; +import {L2_ASSET_ROUTER_ADDR, L2_ASSET_TRACKER, L2_ASSET_TRACKER_ADDR, L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR, L2_COMPLEX_UPGRADER_ADDR, L2_DEPLOYER_SYSTEM_CONTRACT_ADDR} from "../../common/l2-helpers/L2ContractAddresses.sol"; import {IContractDeployer, L2ContractHelper} from "../../common/l2-helpers/L2ContractHelper.sol"; import {SystemContractsCaller} from "../../common/l2-helpers/SystemContractsCaller.sol"; import {DataEncoding} from "../../common/libraries/DataEncoding.sol"; import {AddressMismatch, AssetIdAlreadyRegistered, AssetIdNotSupported, DeployFailed, EmptyAddress, EmptyBytes32, InvalidCaller, NoLegacySharedBridge, TokenIsLegacy, TokenNotLegacy} from "../../common/L1ContractErrors.sol"; - import {IAssetRouterBase} from "../asset-router/IAssetRouterBase.sol"; /// @author Matter Labs @@ -57,28 +57,20 @@ contract L2NativeTokenVault is IL2NativeTokenVault, NativeTokenVaultBase { /// the old version where it was an immutable. bytes32 public L2_TOKEN_PROXY_BYTECODE_HASH; - /*////////////////////////////////////////////////////////////// - INTERNAL FUNCTIONS - //////////////////////////////////////////////////////////////*/ - - /// @dev Returns the L2 asset router for internal use. - function _assetRouter() internal view override returns (IAssetRouterBase) { - return IAssetRouterBase(L2_ASSET_ROUTER_ADDR); - } - - /// @dev Returns the L1 chain ID for internal use. - function _l1ChainId() internal view override returns (uint256) { - return L1_CHAIN_ID; - } + /// @dev The address of the L2 asset router. + /// @dev Note, that while it is a simple storage variable, the name is in capslock for the backward compatibility with + /// the old version where it was an immutable. + IAssetRouterBase public ASSET_ROUTER; - /// @dev Returns the base token asset ID for internal use. - function _baseTokenAssetId() internal view override returns (bytes32) { - return BASE_TOKEN_ASSET_ID; - } + /// @dev The address of the base token on its origin chain + address public BASE_TOKEN_ORIGIN_TOKEN; - /// @dev Returns the WETH token address for internal use. - function _wethToken() internal view override returns (address) { - return WETH_TOKEN; + /// @dev Only allows calls from the complex upgrader contract on L2. + modifier onlyUpgrader() { + if (msg.sender != L2_COMPLEX_UPGRADER_ADDR) { + revert InvalidCaller(msg.sender); + } + _; } /// @notice Initializes the contract. @@ -97,11 +89,21 @@ contract L2NativeTokenVault is IL2NativeTokenVault, NativeTokenVaultBase { address _legacySharedBridge, address _bridgedTokenBeacon, address _wethToken, - bytes32 _baseTokenAssetId + bytes32 _baseTokenAssetId, + address _baseTokenOriginToken, + uint256 _baseTokenOriginChainId ) public onlyUpgrader { _disableInitializers(); // solhint-disable-next-line func-named-parameters - updateL2(_l1ChainId, _l2TokenProxyBytecodeHash, _legacySharedBridge, _wethToken, _baseTokenAssetId); + updateL2( + _l1ChainId, + _l2TokenProxyBytecodeHash, + _legacySharedBridge, + _wethToken, + _baseTokenAssetId, + _baseTokenOriginToken, + _baseTokenOriginChainId + ); if (_aliasedOwner == address(0)) { revert EmptyAddress(); } @@ -110,14 +112,6 @@ contract L2NativeTokenVault is IL2NativeTokenVault, NativeTokenVaultBase { emit L2TokenBeaconUpdated(address(bridgedTokenBeacon), _l2TokenProxyBytecodeHash); } - /// @dev Only allows calls from the complex upgrader contract on L2. - modifier onlyUpgrader() { - if (msg.sender != L2_COMPLEX_UPGRADER_ADDR) { - revert InvalidCaller(msg.sender); - } - _; - } - /// @notice Updates the contract. /// @dev This function is used to initialize the new implementation of L2NativeTokenVault on existing chains during /// the upgrade. @@ -131,20 +125,34 @@ contract L2NativeTokenVault is IL2NativeTokenVault, NativeTokenVaultBase { bytes32 _l2TokenProxyBytecodeHash, address _legacySharedBridge, address _wethToken, - bytes32 _baseTokenAssetId + bytes32 _baseTokenAssetId, + address _baseTokenOriginToken, + uint256 _baseTokenOriginChainId ) public onlyUpgrader { WETH_TOKEN = _wethToken; BASE_TOKEN_ASSET_ID = _baseTokenAssetId; L1_CHAIN_ID = _l1ChainId; L2_LEGACY_SHARED_BRIDGE = IL2SharedBridgeLegacy(_legacySharedBridge); + BASE_TOKEN_ORIGIN_TOKEN = _baseTokenOriginToken; - if (_l2TokenProxyBytecodeHash == bytes32(0)) { - revert EmptyBytes32(); - } + tokenAddress[_baseTokenAssetId] = L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR; + assetId[L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR] = _baseTokenAssetId; + originChainId[_baseTokenAssetId] = _baseTokenOriginChainId; + + require(_l2TokenProxyBytecodeHash != bytes32(0), EmptyBytes32()); L2_TOKEN_PROXY_BYTECODE_HASH = _l2TokenProxyBytecodeHash; } + function _assetTracker() internal view override returns (IAssetTrackerBase) { + return IAssetTrackerBase(L2_ASSET_TRACKER_ADDR); + } + + function setAddresses(uint256 _baseTokenOriginChainId) external onlyUpgrader { + originChainId[BASE_TOKEN_ASSET_ID] = _baseTokenOriginChainId; + tokenAddress[BASE_TOKEN_ASSET_ID] = L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR; + } + function _registerTokenIfBridgedLegacy(address _tokenAddress) internal override returns (bytes32) { // In zkEVM immutables are stored in a storage of a system contract, // so it makes sense to cache them for efficiency. @@ -167,16 +175,10 @@ contract L2NativeTokenVault is IL2NativeTokenVault, NativeTokenVaultBase { function setLegacyTokenAssetId(address _l2TokenAddress) public override { // some legacy tokens were bridged without setting the originChainId on testnets bytes32 assetId = assetId[_l2TokenAddress]; - if (assetId != bytes32(0) && originChainId[assetId] != 0) { - revert AssetIdAlreadyRegistered(); - } - if (address(L2_LEGACY_SHARED_BRIDGE) == address(0)) { - revert NoLegacySharedBridge(); - } + require(assetId == bytes32(0) || originChainId[assetId] == 0, AssetIdAlreadyRegistered()); + require(address(L2_LEGACY_SHARED_BRIDGE) != address(0), NoLegacySharedBridge()); address l1TokenAddress = L2_LEGACY_SHARED_BRIDGE.l1TokenAddress(_l2TokenAddress); - if (l1TokenAddress == address(0)) { - revert TokenNotLegacy(); - } + require(l1TokenAddress != address(0), TokenNotLegacy()); _registerLegacyTokenAssetId(_l2TokenAddress, l1TokenAddress); } @@ -187,9 +189,7 @@ contract L2NativeTokenVault is IL2NativeTokenVault, NativeTokenVaultBase { ) internal returns (bytes32 newAssetId) { newAssetId = DataEncoding.encodeNTVAssetId(L1_CHAIN_ID, _l1TokenAddress); IL2AssetRouter(L2_ASSET_ROUTER_ADDR).setLegacyTokenAssetHandler(newAssetId); - tokenAddress[newAssetId] = _l2TokenAddress; - assetId[_l2TokenAddress] = newAssetId; - originChainId[newAssetId] = L1_CHAIN_ID; + _setLegacyTokenData(newAssetId, _l2TokenAddress); } /// @notice Ensures that the token is deployed. @@ -234,16 +234,20 @@ contract L2NativeTokenVault is IL2NativeTokenVault, NativeTokenVaultBase { address _expectedToken, address _l1LegacyToken ) internal { - _assetIdCheck(L1_CHAIN_ID, _assetId, _originToken); + DataEncoding.assetIdCheck(L1_CHAIN_ID, _assetId, _originToken); /// token is a legacy token, no need to deploy - if (_l1LegacyToken != _originToken) { - revert AddressMismatch(_originToken, _l1LegacyToken); - } + require(_l1LegacyToken == _originToken, AddressMismatch(_originToken, _l1LegacyToken)); + _setLegacyTokenData(_assetId, _expectedToken); + } + function _setLegacyTokenData(bytes32 _assetId, address _expectedToken) internal { tokenAddress[_assetId] = _expectedToken; assetId[_expectedToken] = _assetId; originChainId[_assetId] = L1_CHAIN_ID; + bridgedTokens[bridgedTokensCount] = _assetId; + ++bridgedTokensCount; + L2_ASSET_TRACKER.registerLegacyTokenOnChain(_assetId); } /// @notice Deploys the beacon proxy for the L2 token, while using ContractDeployer system contract. @@ -270,9 +274,7 @@ contract L2NativeTokenVault is IL2NativeTokenVault, NativeTokenVaultBase { ); // The deployment should be successful and return the address of the proxy - if (!success) { - revert DeployFailed(); - } + require(success, DeployFailed()); proxy = BeaconProxy(abi.decode(returndata, (address))); } else { // Deploy the beacon proxy for the L2 token @@ -282,18 +284,34 @@ contract L2NativeTokenVault is IL2NativeTokenVault, NativeTokenVaultBase { } function _withdrawFunds(bytes32 _assetId, address _to, address _token, uint256 _amount) internal override { - if (_assetId == BASE_TOKEN_ASSET_ID) { - revert AssetIdNotSupported(BASE_TOKEN_ASSET_ID); - } else { - // Withdraw funds - IERC20(_token).safeTransfer(_to, _amount); - } + require(_assetId != BASE_TOKEN_ASSET_ID, AssetIdNotSupported(BASE_TOKEN_ASSET_ID)); + IERC20(_token).safeTransfer(_to, _amount); } /*////////////////////////////////////////////////////////////// INTERNAL & HELPER FUNCTIONS //////////////////////////////////////////////////////////////*/ + /// @dev Returns the L2 asset router for internal use. + function _assetRouter() internal view override returns (IAssetRouterBase) { + return IAssetRouterBase(L2_ASSET_ROUTER_ADDR); + } + + /// @dev Returns the L1 chain ID for internal use. + function _l1ChainId() internal view override returns (uint256) { + return L1_CHAIN_ID; + } + + /// @dev Returns the base token asset ID for internal use. + function _baseTokenAssetId() internal view override returns (bytes32) { + return BASE_TOKEN_ASSET_ID; + } + + /// @dev Returns the WETH token address for internal use. + function _wethToken() internal view override returns (address) { + return WETH_TOKEN; + } + /// @notice Calculates L2 wrapped token address given the currently stored beacon proxy bytecode hash and beacon address. /// @param _tokenOriginChainId The chain id of the origin token. /// @param _nonNativeToken The address of token on its origin chain. @@ -327,22 +345,19 @@ contract L2NativeTokenVault is IL2NativeTokenVault, NativeTokenVaultBase { : keccak256(abi.encode(_tokenOriginChainId, _l1Token)); } - function _handleChainBalanceIncrease( - uint256 _chainId, - bytes32 _assetId, - uint256 _amount, - bool _isNative - ) internal override { - // on L2s we don't track the balance + function _handleBridgeToChain(uint256, bytes32 _assetId, uint256 _amount) internal override { + // on L2s we don't track the balance. + // Note GW->L2 txs are not allowed. Even for GW, transactions go through L1, + // so L2NativeTokenVault doesn't have to handle balance changes on GW. + // We need to check the migration number. + L2_ASSET_TRACKER.handleInitiateBridgingOnL2(_assetId, _amount, originChainId[_assetId]); } - function _handleChainBalanceDecrease( - uint256 _chainId, - bytes32 _assetId, - uint256 _amount, - bool _isNative - ) internal override { - // on L2s we don't track the balance + function _handleBridgeFromChain(uint256, bytes32 _assetId, uint256 _amount) internal override { + // on L2s we don't track the balance. + // Note GW->L2 txs are not allowed. Even for GW, transactions go through L1, + // so L2NativeTokenVault doesn't have to handle balance changes on GW. + L2_ASSET_TRACKER.handleFinalizeBridgingOnL2(_assetId, _amount, originChainId[_assetId], tokenAddress[_assetId]); } function _registerToken(address _nativeToken) internal override returns (bytes32) { @@ -367,4 +382,11 @@ contract L2NativeTokenVault is IL2NativeTokenVault, NativeTokenVaultBase { bytes32 expectedAssetId = DataEncoding.encodeNTVAssetId(L1_CHAIN_ID, _l1Token); expectedToken = tokenAddress[expectedAssetId]; } + + function _getOriginTokenFromAddress(address _token) internal view override returns (address) { + if (_token == L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR) { + return BASE_TOKEN_ORIGIN_TOKEN; + } + return super._getOriginTokenFromAddress(_token); + } } diff --git a/l1-contracts/contracts/bridge/ntv/NativeTokenVaultBase.sol b/l1-contracts/contracts/bridge/ntv/NativeTokenVaultBase.sol index 00e072b942..b9b1a956dc 100644 --- a/l1-contracts/contracts/bridge/ntv/NativeTokenVaultBase.sol +++ b/l1-contracts/contracts/bridge/ntv/NativeTokenVaultBase.sol @@ -20,9 +20,10 @@ import {DataEncoding} from "../../common/libraries/DataEncoding.sol"; import {BridgedStandardERC20} from "../BridgedStandardERC20.sol"; import {BridgeHelper} from "../BridgeHelper.sol"; -import {EmptyToken} from "../L1BridgeContractErrors.sol"; -import {AddressMismatch, AmountMustBeGreaterThanZero, AssetIdAlreadyRegistered, AssetIdMismatch, BurningNativeWETHNotSupported, DeployingBridgedTokenForNativeToken, EmptyDeposit, NonEmptyMsgValue, TokenNotSupported, TokensWithFeesNotSupported, Unauthorized, ValueMismatch, ZeroAddress} from "../../common/L1ContractErrors.sol"; +import {EmptyToken, TokenAlreadyInBridgedTokensList} from "../L1BridgeContractErrors.sol"; +import {AddressMismatch, AmountMustBeGreaterThanZero, AssetIdAlreadyRegistered, AssetIdMismatch, BurningNativeWETHNotSupported, DeployingBridgedTokenForNativeToken, EmptyDeposit, NonEmptyMsgValue, TokenNotLegacy, TokenNotSupported, TokensWithFeesNotSupported, Unauthorized, ValueMismatch, ZeroAddress} from "../../common/L1ContractErrors.sol"; import {AssetHandlerModifiers} from "../interfaces/AssetHandlerModifiers.sol"; +import {IAssetTrackerBase} from "../asset-tracker/IAssetTrackerBase.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -61,21 +62,46 @@ abstract contract NativeTokenVaultBase is /// @dev A mapping tokenAddress => assetId mapping(address tokenAddress => bytes32 assetId) public assetId; + /// @dev The number of bridged tokens. + uint256 public bridgedTokensCount; + + /// @dev The mapping of bridged tokens, count => assetId + mapping(uint256 count => bytes32 assetId) public bridgedTokens; + + /// @dev Used to record the index of the bridged token in the bridgedTokens array. + mapping(bytes32 assetId => uint256 tokenIndex) public tokenIndex; + /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ - uint256[46] private __gap; + uint256[43] private __gap; /// @notice Checks that the message sender is the bridgehub. modifier onlyAssetRouter() { - if (msg.sender != address(_assetRouter())) { - revert Unauthorized(msg.sender); - } + require(msg.sender == address(_assetRouter()), Unauthorized(msg.sender)); _; } + function _assetTracker() internal view virtual returns (IAssetTrackerBase); + + function originToken(bytes32 _assetId) public view virtual returns (address) { + address token = tokenAddress[_assetId]; + if (token == address(0)) { + return address(0); + } + if (originChainId[_assetId] == block.chainid) { + return token; + } else { + return _getOriginTokenFromAddress(token); + } + } + + function _getOriginTokenFromAddress(address _token) internal view virtual returns (address) { + return IBridgedStandardToken(_token).originToken(); + } + /// @inheritdoc INativeTokenVaultBase function registerToken(address _nativeToken) external virtual { _registerToken(_nativeToken); @@ -86,15 +112,9 @@ abstract contract NativeTokenVaultBase is // It is needed to allow withdrawing such assets. We restrict all WETH-related // operations to deposits from L1 only to be able to upgrade their logic more easily in the // future. - if (_nativeToken == _wethToken() && block.chainid != _l1ChainId()) { - revert TokenNotSupported(_wethToken()); - } - if (_nativeToken.code.length == 0) { - revert EmptyToken(); - } - if (assetId[_nativeToken] != bytes32(0)) { - revert AssetIdAlreadyRegistered(); - } + require(_nativeToken != _wethToken() || block.chainid == _l1ChainId(), TokenNotSupported(_wethToken())); + require(_nativeToken.code.length > 0, EmptyToken()); + require(assetId[_nativeToken] == bytes32(0), AssetIdAlreadyRegistered()); newAssetId = _unsafeRegisterNativeToken(_nativeToken); } @@ -103,11 +123,32 @@ abstract contract NativeTokenVaultBase is bytes32 currentAssetId = assetId[_nativeToken]; if (currentAssetId == bytes32(0)) { tokenAssetId = _registerToken(_nativeToken); + _assetTracker().registerNewToken(tokenAssetId, block.chainid); } else { tokenAssetId = currentAssetId; } } + /// @notice Adds a legacy token to the bridged tokens list. + /// @dev This function is used to add a legacy token to the bridged tokens list. + /// @param _token The address of the token to be added to the bridged tokens list. + function addLegacyTokenToBridgedTokensList(address _token) external { + bytes32 tokenAssetId = assetId[_token]; + if (tokenAssetId == bytes32(0)) { + revert TokenNotLegacy(); + } + if (tokenIndex[tokenAssetId] != 0) { + revert TokenAlreadyInBridgedTokensList(); + } + _addTokenToTokensList(tokenAssetId); + } + + function _addTokenToTokensList(bytes32 _tokenAssetId) internal { + bridgedTokens[bridgedTokensCount] = _tokenAssetId; + tokenIndex[_tokenAssetId] = bridgedTokensCount; + ++bridgedTokensCount; + } + /*////////////////////////////////////////////////////////////// FINISH TRANSACTION FUNCTIONS //////////////////////////////////////////////////////////////*/ @@ -150,7 +191,11 @@ abstract contract NativeTokenVaultBase is if (token == address(0)) { token = _ensureAndSaveTokenDeployed(_assetId, originToken, erc20Data); } - _handleChainBalanceDecrease(_chainId, _assetId, amount, false); + + // IMPORTANT: We must handle chain balance decrease before giving out funds to the user, + // because otherwise the latter operation (via a malicious token or ETH recipient) + // could've overwritten the transient values from L1Nullifier. + _handleBridgeFromChain({_chainId: _chainId, _assetId: _assetId, _amount: amount}); IBridgedStandardToken(token).bridgeMint(receiver, amount); } @@ -163,7 +208,10 @@ abstract contract NativeTokenVaultBase is // slither-disable-next-line unused-return (, receiver, , amount, ) = DataEncoding.decodeBridgeMintData(_data); - _handleChainBalanceDecrease(_chainId, _assetId, amount, true); + // IMPORTANT: We must handle chain balance decrease before giving out funds to the user, + // because otherwise the latter operation (via a malicious token or ETH recipient) + // could've overwritten the transient values from L1Nullifier. + _handleBridgeFromChain({_chainId: _chainId, _assetId: _assetId, _amount: amount}); _withdrawFunds(_assetId, receiver, token, amount); } @@ -218,14 +266,10 @@ abstract contract NativeTokenVaultBase is // slither-disable-next-line unused-return (, , address tokenAddress) = DataEncoding.decodeBridgeBurnData(_burnData); - if (tokenAddress == address(0)) { - revert ZeroAddress(); - } + require(tokenAddress != address(0), ZeroAddress()); bytes32 storedAssetId = assetId[tokenAddress]; - if (storedAssetId != bytes32(0)) { - revert AssetIdAlreadyRegistered(); - } + require(storedAssetId == bytes32(0), AssetIdAlreadyRegistered()); // This token has not been registered within this NTV yet. Usually this means that the // token is native to the chain and the user would prefer to get it registered as such. @@ -240,9 +284,7 @@ abstract contract NativeTokenVaultBase is newAssetId = _registerToken(tokenAddress); } - if (newAssetId != _expectedAssetId) { - revert AssetIdMismatch(_expectedAssetId, newAssetId); - } + require(newAssetId == _expectedAssetId, AssetIdMismatch(_expectedAssetId, newAssetId)); } function _decodeBurnAndCheckAssetId( @@ -258,14 +300,10 @@ abstract contract NativeTokenVaultBase is } // If it is still zero, it means that the token has not been registered. - if (parsedTokenAddress == address(0)) { - revert ZeroAddress(); - } + require(parsedTokenAddress != address(0), ZeroAddress()); bytes32 storedAssetId = assetId[parsedTokenAddress]; - if (_suppliedAssetId != storedAssetId) { - revert AssetIdMismatch(storedAssetId, _suppliedAssetId); - } + require(_suppliedAssetId == storedAssetId, AssetIdMismatch(storedAssetId, _suppliedAssetId)); } function _registerTokenIfBridgedLegacy(address _token) internal virtual returns (bytes32); @@ -278,13 +316,10 @@ abstract contract NativeTokenVaultBase is address _receiver, address _tokenAddress ) internal requireZeroValue(msg.value) returns (bytes memory _bridgeMintData) { - if (_amount == 0) { - // "Amount cannot be zero"); - revert AmountMustBeGreaterThanZero(); - } + require(_amount != 0, AmountMustBeGreaterThanZero()); IBridgedStandardToken(_tokenAddress).bridgeBurn(_originalCaller, _amount); - _handleChainBalanceIncrease(_chainId, _assetId, _amount, false); + _handleBridgeToChain(_chainId, _assetId, _amount); emit BridgeBurn({ chainId: _chainId, @@ -298,17 +333,14 @@ abstract contract NativeTokenVaultBase is // we set all originChainId for all already bridged tokens with the setLegacyTokenAssetId and updateChainBalancesFromSharedBridge functions. // for native tokens the originChainId is set when they register. uint256 originChainId = originChainId[_assetId]; - if (originChainId == 0) { - revert ZeroAddress(); - } + require(originChainId != 0, ZeroAddress()); erc20Metadata = getERC20Getters(_tokenAddress, originChainId); } address originToken; + /// Note L2->L2 asset transfers will accrue a fee in some form in later versions. { originToken = IBridgedStandardToken(_tokenAddress).originToken(); - if (originToken == address(0)) { - revert ZeroAddress(); - } + require(originToken != address(0), ZeroAddress()); } _bridgeMintData = DataEncoding.encodeBridgeMintData({ @@ -329,35 +361,26 @@ abstract contract NativeTokenVaultBase is address _receiver, address _nativeToken ) internal virtual returns (bytes memory _bridgeMintData) { - if (_nativeToken == _wethToken()) { - // This ensures that _wethToken() can never be bridged from chains it is native to. - // It can only be withdrawn from the chain where it has already gotten. - revert BurningNativeWETHNotSupported(); - } + // This ensures that WETH_TOKEN can never be bridged from chains it is native to. + // It can only be withdrawn from the chain where it has already gotten. + require(_nativeToken != _wethToken(), BurningNativeWETHNotSupported()); if (_assetId == _baseTokenAssetId()) { - if (_depositAmount != msg.value) { - revert ValueMismatch(_depositAmount, msg.value); - } + require(_depositAmount == msg.value, ValueMismatch(_depositAmount, msg.value)); - _handleChainBalanceIncrease(_chainId, _assetId, _depositAmount, true); + _handleBridgeToChain(_chainId, _assetId, _depositAmount); } else { - if (msg.value != 0) { - revert NonEmptyMsgValue(); - } - _handleChainBalanceIncrease(_chainId, _assetId, _depositAmount, true); + require(msg.value == 0, NonEmptyMsgValue()); + _handleBridgeToChain(_chainId, _assetId, _depositAmount); if (!_depositChecked) { uint256 expectedDepositAmount = _depositFunds(_originalCaller, IERC20(_nativeToken), _depositAmount); // note if _originalCaller is this contract, this will return 0. This does not happen. // The token has non-standard transfer logic - if (_depositAmount != expectedDepositAmount) { - revert TokensWithFeesNotSupported(); - } + require(_depositAmount == expectedDepositAmount, TokensWithFeesNotSupported()); } } - if (_depositAmount == 0) { - // empty deposit amount - revert EmptyDeposit(); - } + // empty deposit amount + require(_depositAmount != 0, EmptyDeposit()); + /// Note L2->L2 asset transfers will accrue a fee in some form in later versions. bytes memory erc20Metadata; { @@ -409,28 +432,16 @@ abstract contract NativeTokenVaultBase is /// @param _nativeToken The address of the token to be registered. function _unsafeRegisterNativeToken(address _nativeToken) internal returns (bytes32 newAssetId) { newAssetId = DataEncoding.encodeNTVAssetId(block.chainid, _nativeToken); - tokenAddress[newAssetId] = _nativeToken; - assetId[_nativeToken] = newAssetId; - originChainId[newAssetId] = block.chainid; + _setNewTokenStorage(newAssetId, _nativeToken, block.chainid); AssetRouterBase(address(_assetRouter())).setAssetHandlerAddressThisChain( bytes32(uint256(uint160(_nativeToken))), address(this) ); } - function _handleChainBalanceIncrease( - uint256 _chainId, - bytes32 _assetId, - uint256 _amount, - bool _isNative - ) internal virtual; + function _handleBridgeToChain(uint256 _chainId, bytes32 _assetId, uint256 _amount) internal virtual; - function _handleChainBalanceDecrease( - uint256 _chainId, - bytes32 _assetId, - uint256 _amount, - bool _isNative - ) internal virtual; + function _handleBridgeFromChain(uint256 _chainId, bytes32 _assetId, uint256 _amount) internal virtual; /*////////////////////////////////////////////////////////////// TOKEN DEPLOYER FUNCTIONS @@ -471,15 +482,6 @@ abstract contract NativeTokenVaultBase is } } - /// @notice Checks that the assetId is correct for the origin token and chain. - function _assetIdCheck(uint256 _tokenOriginChainId, bytes32 _assetId, address _originToken) internal view { - bytes32 expectedAssetId = DataEncoding.encodeNTVAssetId(_tokenOriginChainId, _originToken); - if (_assetId != expectedAssetId) { - // Make sure that a NativeTokenVault sent the message - revert AssetIdMismatch(expectedAssetId, _assetId); - } - } - function _ensureAndSaveTokenDeployedInner( uint256 _tokenOriginChainId, bytes32 _assetId, @@ -487,15 +489,20 @@ abstract contract NativeTokenVaultBase is bytes memory _erc20Data, address _expectedToken ) internal { - _assetIdCheck(_tokenOriginChainId, _assetId, _originToken); + DataEncoding.assetIdCheck(_tokenOriginChainId, _assetId, _originToken); address deployedToken = _deployBridgedToken(_tokenOriginChainId, _assetId, _originToken, _erc20Data); - if (deployedToken != _expectedToken) { - revert AddressMismatch(_expectedToken, deployedToken); - } + require(deployedToken == _expectedToken, AddressMismatch(_expectedToken, deployedToken)); - tokenAddress[_assetId] = _expectedToken; - assetId[_expectedToken] = _assetId; + _setNewTokenStorage(_assetId, _expectedToken, _tokenOriginChainId); + } + + function _setNewTokenStorage(bytes32 _assetId, address _tokenAddress, uint256 _originChainId) internal { + tokenAddress[_assetId] = _tokenAddress; + assetId[_tokenAddress] = _assetId; + originChainId[_assetId] = _originChainId; + _addTokenToTokensList(_assetId); + _assetTracker().registerNewToken(_assetId, _originChainId); } /// @notice Calculates the bridged token address corresponding to native token counterpart. @@ -518,15 +525,12 @@ abstract contract NativeTokenVaultBase is address _originToken, bytes memory _erc20Data ) internal returns (address) { - if (_tokenOriginChainId == block.chainid) { - revert DeployingBridgedTokenForNativeToken(); - } + require(_tokenOriginChainId != block.chainid, DeployingBridgedTokenForNativeToken()); bytes32 salt = _getCreate2Salt(_tokenOriginChainId, _originToken); BeaconProxy l2Token = _deployBeaconProxy(salt, _tokenOriginChainId); BridgedStandardERC20(address(l2Token)).bridgeInitialize(_assetId, _originToken, _erc20Data); - originChainId[_assetId] = _tokenOriginChainId; return address(l2Token); } diff --git a/l1-contracts/contracts/bridgehub/BridgehubBase.sol b/l1-contracts/contracts/bridgehub/BridgehubBase.sol index aaf194fb6c..71fe30a235 100644 --- a/l1-contracts/contracts/bridgehub/BridgehubBase.sol +++ b/l1-contracts/contracts/bridgehub/BridgehubBase.sol @@ -8,6 +8,7 @@ import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/ac import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/security/PausableUpgradeable.sol"; import {IBridgehubBase} from "./IBridgehubBase.sol"; + import {IAssetRouterBase} from "../bridge/asset-router/IAssetRouterBase.sol"; import {IL1BaseTokenAssetHandler} from "../bridge/interfaces/IL1BaseTokenAssetHandler.sol"; import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; @@ -19,8 +20,8 @@ import {BridgehubL2TransactionRequest, L2Log, L2Message, TxStatus} from "../comm import {AddressAliasHelper} from "../vendor/AddressAliasHelper.sol"; import {IMessageRoot} from "./IMessageRoot.sol"; import {ICTMDeploymentTracker} from "./ICTMDeploymentTracker.sol"; -import {AlreadyCurrentSL, NotChainAssetHandler, NotCurrentSL, NotRelayedSender, SLNotWhitelisted} from "./L1BridgehubErrors.sol"; -import {AssetHandlerNotRegistered, AssetIdAlreadyRegistered, AssetIdNotSupported, BridgeHubAlreadyRegistered, CTMAlreadyRegistered, CTMNotRegistered, ChainIdCantBeCurrentChain, ChainIdNotRegistered, ChainIdTooBig, EmptyAssetId, NoCTMForAssetId, SettlementLayersMustSettleOnL1, SharedBridgeNotSet, Unauthorized, ZKChainLimitReached, ZeroAddress, ZeroChainId} from "../common/L1ContractErrors.sol"; +import {AlreadyCurrentSL, NotChainAssetHandler, NotRelayedSender, SLNotWhitelisted} from "./L1BridgehubErrors.sol"; +import {AssetHandlerNotRegistered, AssetIdAlreadyRegistered, AssetIdNotSupported, BridgeHubAlreadyRegistered, CTMAlreadyRegistered, CTMNotRegistered, ChainIdCantBeCurrentChain, ChainIdNotRegistered, ChainIdTooBig, EmptyAssetId, NoCTMForAssetId, NotCurrentSettlementLayer, SettlementLayersMustSettleOnL1, SharedBridgeNotSet, Unauthorized, ZKChainLimitReached, ZeroAddress, ZeroChainId} from "../common/L1ContractErrors.sol"; import {L2_COMPLEX_UPGRADER_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; /// @author Matter Labs @@ -101,6 +102,12 @@ abstract contract BridgehubBase is IBridgehubBase, ReentrancyGuard, Ownable2Step /// @notice the chain asset handler used for chain migration. address public chainAssetHandler; + /// @notice the chain registration sender used for chain registration. + /// @notice the chainRegistrationSender is only deployed on L1. + /// @dev If the Bridgehub is on L1 it is the address just the chainRegistrationSender address. + /// @dev If the Bridgehub is on L2 the address is aliased. + address public chainRegistrationSender; + /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. @@ -192,9 +199,14 @@ abstract contract BridgehubBase is IBridgehubBase, ReentrancyGuard, Ownable2Step address _assetRouter, ICTMDeploymentTracker _l1CtmDeployer, IMessageRoot _messageRoot, - address _chainAssetHandler + address _chainAssetHandler, + address _chainRegistrationSender ) external virtual; + function setAddressesV30(address _chainRegistrationSender) external onlyOwnerOrUpgrader { + chainRegistrationSender = _chainRegistrationSender; + } + /// @notice Used to set the chain asset handler address. /// @dev Called during v29 upgrade. /// @param _chainAssetHandler the chain asset handler address @@ -257,7 +269,7 @@ abstract contract BridgehubBase is IBridgehubBase, ReentrancyGuard, Ownable2Step // // For simpler handling we allow anyone to call this method. It is okay, since during bridging operations // it is double checked that `assetId` is indeed derived from the `l1CtmDeployer`. - // TODO(EVM-703): This logic should be revised once interchain communication is implemented. + // TODO(EVM-703): This logic should be revised once interchain communication with aliasing (either standard trigger or shadow accounts) is implemented. address sender = _l1ChainId() == block.chainid ? msg.sender : AddressAliasHelper.undoL1ToL2Alias(msg.sender); // This method can be accessed by l1CtmDeployer only @@ -373,8 +385,14 @@ abstract contract BridgehubBase is IBridgehubBase, ReentrancyGuard, Ownable2Step L2Message calldata _message, bytes32[] calldata _proof ) external view override returns (bool) { - address zkChain = zkChainMap.get(_chainId); - return IZKChain(zkChain).proveL2MessageInclusion(_batchNumber, _index, _message, _proof); + return + messageRoot.proveL2MessageInclusionShared({ + _chainId: _chainId, + _blockOrBatchNumber: _batchNumber, + _index: _index, + _message: _message, + _proof: _proof + }); } /// @notice forwards function call to Mailbox based on ChainId @@ -391,8 +409,14 @@ abstract contract BridgehubBase is IBridgehubBase, ReentrancyGuard, Ownable2Step L2Log calldata _log, bytes32[] calldata _proof ) external view override returns (bool) { - address zkChain = zkChainMap.get(_chainId); - return IZKChain(zkChain).proveL2LogInclusion(_batchNumber, _index, _log, _proof); + return + messageRoot.proveL2LogInclusionShared({ + _chainId: _chainId, + _blockOrBatchNumber: _batchNumber, + _index: _index, + _log: _log, + _proof: _proof + }); } /// @notice forwards function call to Mailbox based on ChainId @@ -414,9 +438,9 @@ abstract contract BridgehubBase is IBridgehubBase, ReentrancyGuard, Ownable2Step bytes32[] calldata _merkleProof, TxStatus _status ) external view override returns (bool) { - address zkChain = zkChainMap.get(_chainId); return - IZKChain(zkChain).proveL1ToL2TransactionStatus({ + messageRoot.proveL1ToL2TransactionStatusShared({ + _chainId: _chainId, _l2TxHash: _l2TxHash, _l2BatchNumber: _l2BatchNumber, _l2MessageIndex: _l2MessageIndex, @@ -455,7 +479,7 @@ abstract contract BridgehubBase is IBridgehubBase, ReentrancyGuard, Ownable2Step } if (settlementLayer[_chainId] != block.chainid) { - revert NotCurrentSL(settlementLayer[_chainId], block.chainid); + revert NotCurrentSettlementLayer(); } settlementLayer[_chainId] = _newSettlementLayerChainId; @@ -499,12 +523,15 @@ abstract contract BridgehubBase is IBridgehubBase, ReentrancyGuard, Ownable2Step /// @param _chainId The chain ID of the chain. /// @return zkChain The address of the ZK chain. /// @return ctm The address of the CTM of the chain. - function forwardedBridgeRecoverFailedTransfer( - uint256 _chainId + function forwardedBridgeConfirmTransferResult( + uint256 _chainId, + TxStatus _txStatus ) external onlyChainAssetHandler returns (address zkChain, address ctm) { - settlementLayer[_chainId] = block.chainid; zkChain = getZKChain(_chainId); ctm = chainTypeManager[_chainId]; + if (_txStatus == TxStatus.Failure) { + settlementLayer[_chainId] = block.chainid; + } } /*//////////////////////////////////////////////////////////// diff --git a/l1-contracts/contracts/bridgehub/CTMDeploymentTracker.sol b/l1-contracts/contracts/bridgehub/CTMDeploymentTracker.sol index 1970e49e7e..845e35dcba 100644 --- a/l1-contracts/contracts/bridgehub/CTMDeploymentTracker.sol +++ b/l1-contracts/contracts/bridgehub/CTMDeploymentTracker.sol @@ -6,6 +6,7 @@ import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/ac import {IBridgehubBase, L2TransactionRequestTwoBridgesInner} from "./IBridgehubBase.sol"; import {ICTMDeploymentTracker} from "./ICTMDeploymentTracker.sol"; +import {IL1CrossChainSender} from "../bridge/interfaces/IL1CrossChainSender.sol"; import {IAssetRouterBase} from "../bridge/asset-router/IAssetRouterBase.sol"; import {AssetRouterBase} from "../bridge/asset-router/AssetRouterBase.sol"; @@ -20,7 +21,7 @@ bytes1 constant CTM_DEPLOYMENT_TRACKER_ENCODING_VERSION = 0x01; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev /// @dev Contract to be deployed on L1, can link together other contracts based on AssetInfo. -contract CTMDeploymentTracker is ICTMDeploymentTracker, Ownable2StepUpgradeable { +contract CTMDeploymentTracker is ICTMDeploymentTracker, IL1CrossChainSender, Ownable2StepUpgradeable { /// @dev Bridgehub smart contract that is used to operate with L2 via asynchronous L2 <-> L1 communication. IBridgehubBase public immutable override BRIDGE_HUB; @@ -102,7 +103,7 @@ contract CTMDeploymentTracker is ICTMDeploymentTracker, Ownable2StepUpgradeable address _originalCaller, uint256, bytes calldata _data - ) external payable onlyBridgehub returns (L2TransactionRequestTwoBridgesInner memory request) { + ) external payable override onlyBridgehub returns (L2TransactionRequestTwoBridgesInner memory request) { if (msg.value != 0) { revert NoEthAllowed(); } @@ -125,7 +126,7 @@ contract CTMDeploymentTracker is ICTMDeploymentTracker, Ownable2StepUpgradeable uint256 _chainId, bytes32 _txDataHash, bytes32 _txHash - ) external onlyBridgehub {} + ) external override onlyBridgehub {} /// @notice Used to register the ctm asset in L2 AssetRouter. /// @param _originalCaller the address that called the Router diff --git a/l1-contracts/contracts/bridgehub/ChainAssetHandlerBase.sol b/l1-contracts/contracts/bridgehub/ChainAssetHandlerBase.sol index d1ac7a0aa5..949d668a7d 100644 --- a/l1-contracts/contracts/bridgehub/ChainAssetHandlerBase.sol +++ b/l1-contracts/contracts/bridgehub/ChainAssetHandlerBase.sol @@ -17,8 +17,9 @@ import {IAssetRouterBase} from "../bridge/asset-router/IAssetRouterBase.sol"; import {L1_SETTLEMENT_LAYER_VIRTUAL_ADDRESS} from "../common/Config.sol"; import {IMessageRoot} from "./IMessageRoot.sol"; -import {HyperchainNotRegistered, IncorrectChainAssetId, IncorrectSender, NotAssetRouter, SLHasDifferentCTM} from "./L1BridgehubErrors.sol"; -import {ChainIdNotRegistered, MigrationPaused} from "../common/L1ContractErrors.sol"; +import {IncorrectChainAssetId, IncorrectSender, MigrationNotToL1, MigrationNumberAlreadySet, MigrationNumberMismatch, NotSystemContext, OnlyChain, SLHasDifferentCTM, ZKChainNotRegistered, IteratedMigrationsNotSupported} from "./L1BridgehubErrors.sol"; +import {ChainIdNotRegistered, MigrationPaused, NotAssetRouter} from "../common/L1ContractErrors.sol"; +import {L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; import {AssetHandlerModifiers} from "../bridge/interfaces/AssetHandlerModifiers.sol"; import {IChainAssetHandler} from "./IChainAssetHandler.sol"; @@ -70,6 +71,8 @@ abstract contract ChainAssetHandlerBase is function _assetRouter() internal view virtual returns (IAssetRouterBase); + function _assetTracker() internal view virtual returns (address); + /// @notice Used to pause the migrations of chains. Used for upgrades. bool public migrationPaused; @@ -93,12 +96,16 @@ abstract contract ChainAssetHandlerBase is /// @dev Kept here for storage layout compatibility with previous versions. IAssetRouterBase internal DEPRECATED_ASSET_ROUTER; + /// @notice Used to track the number of times each chain has migrated. + /// NOTE: this mapping may be deprecated in the future, don't rely on it! + mapping(uint256 chainId => uint256 migrationNumber) public migrationNumber; + /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ - uint256[44] private __gap; + uint256[43] private __gap; /// @notice Only the asset router can call. modifier onlyAssetRouter() { @@ -116,6 +123,38 @@ abstract contract ChainAssetHandlerBase is _; } + modifier onlySystemContext() { + if (msg.sender != L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR) { + revert NotSystemContext(msg.sender); + } + _; + } + + /*////////////////////////////////////////////////////////////// + V30 Upgrade + //////////////////////////////////////////////////////////////*/ + + /// @notice Checks that the message sender is the specified ZK Chain. + /// @param _chainId The ID of the chain that is required to be the caller. + modifier onlyChain(uint256 _chainId) { + if (msg.sender != IBridgehubBase(_bridgehub()).getZKChain(_chainId)) { + revert OnlyChain(msg.sender, IBridgehubBase(_bridgehub()).getZKChain(_chainId)); + } + _; + } + + /// @notice Sets the migration number for a chain on the Gateway when the chain's DiamondProxy upgrades. + function setMigrationNumberForV30(uint256 _chainId) external onlyChain(_chainId) { + require(migrationNumber[_chainId] == 0, MigrationNumberAlreadySet()); + bool isOnThisSettlementLayer = block.chainid == IBridgehubBase(_bridgehub()).settlementLayer(_chainId); + bool shouldIncrementMigrationNumber = (isOnThisSettlementLayer && block.chainid != _l1ChainId()) || + (!isOnThisSettlementLayer && block.chainid == _l1ChainId()); + /// Note we don't increment the migration number if the chain migrated to GW and back to L1 previously. + if (shouldIncrementMigrationNumber) { + migrationNumber[_chainId] = 1; + } + } + /*////////////////////////////////////////////////////////////// Chain migration //////////////////////////////////////////////////////////////*/ @@ -143,14 +182,15 @@ abstract contract ChainAssetHandlerBase is returns (bytes memory bridgehubMintData) { BridgehubBurnCTMAssetData memory bridgehubBurnData = abi.decode(_data, (BridgehubBurnCTMAssetData)); - if (_assetId != IBridgehubBase(_bridgehub()).ctmAssetIdFromChainId(bridgehubBurnData.chainId)) { - revert IncorrectChainAssetId( + require( + _assetId == IBridgehubBase(_bridgehub()).ctmAssetIdFromChainId(bridgehubBurnData.chainId), + IncorrectChainAssetId( _assetId, IBridgehubBase(_bridgehub()).ctmAssetIdFromChainId(bridgehubBurnData.chainId) - ); - } + ) + ); + address zkChain = IBridgehubBase(_bridgehub()).getZKChain(bridgehubBurnData.chainId); - address zkChain; bytes memory ctmMintData; // to avoid stack too deep { @@ -161,7 +201,7 @@ abstract contract ChainAssetHandlerBase is ); if (zkChain == address(0)) { - revert HyperchainNotRegistered(); + revert ZKChainNotRegistered(); } if (_originalCaller != IZKChain(zkChain).getAdmin()) { revert IncorrectSender(_originalCaller, IZKChain(zkChain).getAdmin()); @@ -179,6 +219,11 @@ abstract contract ChainAssetHandlerBase is ) { revert SLHasDifferentCTM(); } + + if (block.chainid != _l1ChainId()) { + require(_settlementChainId == _l1ChainId(), MigrationNotToL1()); + } + _setMigrationInProgressOnL1(bridgehubBurnData.chainId); } bytes memory chainMintData = IZKChain(zkChain).forwardedBridgeBurn( _settlementChainId == _l1ChainId() @@ -187,17 +232,31 @@ abstract contract ChainAssetHandlerBase is _originalCaller, bridgehubBurnData.chainData ); + // Iterated migrations are not supported to avoid asset migration number complications related to token balance migration. + // This means a chain can migrate to GW and back to L1 but only once. + require(migrationNumber[bridgehubBurnData.chainId] < 2, IteratedMigrationsNotSupported()); + ++migrationNumber[bridgehubBurnData.chainId]; + + uint256 batchNumber = IMessageRoot(_messageRoot()).currentChainBatchNumber(bridgehubBurnData.chainId); + BridgehubMintCTMAssetData memory bridgeMintStruct = BridgehubMintCTMAssetData({ chainId: bridgehubBurnData.chainId, baseTokenAssetId: IBridgehubBase(_bridgehub()).baseTokenAssetId(bridgehubBurnData.chainId), + batchNumber: batchNumber, ctmData: ctmMintData, - chainData: chainMintData + chainData: chainMintData, + migrationNumber: migrationNumber[bridgehubBurnData.chainId], + v30UpgradeChainBatchNumber: IMessageRoot(_messageRoot()).v30UpgradeChainBatchNumber( + bridgehubBurnData.chainId + ) }); bridgehubMintData = abi.encode(bridgeMintStruct); emit MigrationStarted(bridgehubBurnData.chainId, _assetId, _settlementChainId); } + function _setMigrationInProgressOnL1(uint256 _chainId) internal virtual {} + /// @dev IL1AssetHandler interface, used to receive a chain on the settlement layer. /// @param _assetId the assetId of the chain's CTM /// @param _bridgehubMintData the data for the mint @@ -212,6 +271,16 @@ abstract contract ChainAssetHandlerBase is (BridgehubMintCTMAssetData) ); + uint256 currentMigrationNumber = migrationNumber[bridgehubMintData.chainId]; + /// If we are not migrating for the first time, we check that the migration number is correct. + if (currentMigrationNumber != 0 && block.chainid == _l1ChainId()) { + require( + currentMigrationNumber + 1 == bridgehubMintData.migrationNumber, + MigrationNumberMismatch(currentMigrationNumber + 1, bridgehubMintData.migrationNumber) + ); + } + migrationNumber[bridgehubMintData.chainId] = bridgehubMintData.migrationNumber; + (address zkChain, address ctm) = IBridgehubBase(_bridgehub()).forwardedBridgeMint( _assetId, bridgehubMintData.chainId, @@ -226,7 +295,17 @@ abstract contract ChainAssetHandlerBase is } // We want to allow any chain to be migrated, IBridgehubBase(_bridgehub()).registerNewZKChain(bridgehubMintData.chainId, zkChain, false); - IMessageRoot(_messageRoot()).addNewChain(bridgehubMintData.chainId); + IMessageRoot(_messageRoot()).addNewChain(bridgehubMintData.chainId, bridgehubMintData.batchNumber); + } else { + // Note, that here we rely on the correctness of the provided data. + // A malicious settlement layer could provide invalid values here. + // To support untrusted CTMs, we would need to at the very least enforce + // that the `v30UpgradeChainBatchNumber` is not in conflict with the existing values. + IMessageRoot(_messageRoot()).setMigratingChainBatchRoot( + bridgehubMintData.chainId, + bridgehubMintData.batchNumber, + bridgehubMintData.v30UpgradeChainBatchNumber + ); } IZKChain(zkChain).forwardedBridgeMint(bridgehubMintData.chainData, contractAlreadyDeployed); @@ -234,6 +313,24 @@ abstract contract ChainAssetHandlerBase is emit MigrationFinalized(bridgehubMintData.chainId, _assetId, zkChain); } + /*////////////////////////////////////////////////////////////// + L2 functions + //////////////////////////////////////////////////////////////*/ + + /// @notice This function is called at the start of each batch. + function setSettlementLayerChainId( + uint256 _previousSettlementLayerChainId, + uint256 _currentSettlementLayerChainId + ) external onlySystemContext { + if (_previousSettlementLayerChainId == 0 && _currentSettlementLayerChainId == _l1ChainId()) { + /// For the initial call if we are settling on L1, we return, as there is no real migration. + return; + } + if (_previousSettlementLayerChainId != _currentSettlementLayerChainId) { + ++migrationNumber[block.chainid]; + } + } + /*////////////////////////////////////////////////////////////// PAUSE //////////////////////////////////////////////////////////////*/ diff --git a/l1-contracts/contracts/bridgehub/ChainRegistrationSender.sol b/l1-contracts/contracts/bridgehub/ChainRegistrationSender.sol new file mode 100644 index 0000000000..6037df0bf7 --- /dev/null +++ b/l1-contracts/contracts/bridgehub/ChainRegistrationSender.sol @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; + +import {IChainRegistrationSender} from "./IChainRegistrationSender.sol"; +import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; +import {IL1CrossChainSender} from "../bridge/interfaces/IL1CrossChainSender.sol"; + +import {IBridgehubBase, L2TransactionRequestTwoBridgesInner} from "./IBridgehubBase.sol"; +import {IMailbox} from "../state-transition/chain-interfaces/IMailbox.sol"; + +import {L2_BRIDGEHUB_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; +import {TWO_BRIDGES_MAGIC_VALUE} from "../common/Config.sol"; + +import {Unauthorized, UnsupportedEncodingVersion} from "../common/L1ContractErrors.sol"; +import {ChainAlreadyRegistered, NoEthAllowed, ZKChainNotRegistered} from "./L1BridgehubErrors.sol"; +import {IL2Bridgehub} from "./IL2Bridgehub.sol"; + +/// @dev The encoding version of the data. +bytes1 constant CHAIN_REGISTRATION_SENDER_ENCODING_VERSION = 0x01; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +/// @dev The ChainRegistrationSender contract is used to register chains in other chains for interop via a service transaction. +contract ChainRegistrationSender is + IChainRegistrationSender, + IL1CrossChainSender, + ReentrancyGuard, + Ownable2StepUpgradeable +{ + IBridgehubBase public immutable BRIDGE_HUB; + + mapping(uint256 chainToBeRegistered => mapping(uint256 chainRegisteredOn => bool isRegistered)) + public chainRegisteredOnChain; + + /// @notice Checks that the message sender is the bridgehub. + modifier onlyBridgehub() { + if (msg.sender != address(BRIDGE_HUB)) { + revert Unauthorized(msg.sender); + } + _; + } + + constructor(IBridgehubBase _bridgehub) { + BRIDGE_HUB = _bridgehub; + } + + /// @notice used to initialize the contract + /// @notice this contract is also deployed on L2 as a system contract there the owner and the related functions will not be used + /// @param _owner the owner of the contract + function initialize(address _owner) external reentrancyGuardInitializer { + _transferOwnership(_owner); + } + + /// @notice used to register a chain for interop via a service transaction.abi + /// @notice this is provided for ease of use, base tokens does not have to be provided. + /// @notice to prevent spamming, we only allow this to be called once. + /// @param chainToBeRegistered the chain to be registered + /// @param chainRegisteredOn the chain to register on + function registerChain(uint256 chainToBeRegistered, uint256 chainRegisteredOn) external { + require(!chainRegisteredOnChain[chainToBeRegistered][chainRegisteredOn], ChainAlreadyRegistered()); + chainRegisteredOnChain[chainToBeRegistered][chainRegisteredOn] = true; + + IMailbox chainRegisteredOnAddress = IMailbox(BRIDGE_HUB.getZKChain(chainRegisteredOn)); + // slither-disable-next-line unused-return + chainRegisteredOnAddress.requestL2ServiceTransaction( + address(L2_BRIDGEHUB_ADDR), + _getL2TxCalldata(chainToBeRegistered) + ); + } + + /// @inheritdoc IL1CrossChainSender + /// @notice Registers a chain on the L2 via a normal deposit. + /// @notice this is can be called by anyone (via the bridgehub), but baseTokens need to be provided. + // slither-disable-next-line locked-ether + function bridgehubDeposit( + uint256, + address, + uint256, + bytes calldata _data + ) external payable virtual override onlyBridgehub returns (L2TransactionRequestTwoBridgesInner memory request) { + if (msg.value != 0) { + revert NoEthAllowed(); + } + bytes1 encodingVersion = _data[0]; + if (encodingVersion != CHAIN_REGISTRATION_SENDER_ENCODING_VERSION) { + revert UnsupportedEncodingVersion(); + } + + uint256 chainToBeRegistered = abi.decode(_data[1:], (uint256)); + address chainToBeRegisteredAddress = BRIDGE_HUB.getZKChain(chainToBeRegistered); + if (chainToBeRegisteredAddress == address(0)) { + revert ZKChainNotRegistered(); + } + request = L2TransactionRequestTwoBridgesInner({ + magicValue: TWO_BRIDGES_MAGIC_VALUE, + l2Contract: L2_BRIDGEHUB_ADDR, + l2Calldata: _getL2TxCalldata(chainToBeRegistered), + factoryDeps: new bytes[](0), + // The `txDataHash` is typically used in usual ERC20 bridges to commit to the transaction data + // so that the user can recover funds in case the bridging fails on L2. + // However, this contract uses the `requestL2TransactionTwoBridges` method just to perform an L1->L2 transaction. + // We do not need to recover anything and so `bytes32(0)` here is okay. + txDataHash: bytes32(0) + }); + } + + /// @notice Used to get the L2 transaction calldata for the chain registration. + /// @param chainToBeRegistered the chain to be registered + /// @return the L2 transaction calldata + function _getL2TxCalldata(uint256 chainToBeRegistered) internal view returns (bytes memory) { + bytes32 baseTokenAssetId = BRIDGE_HUB.baseTokenAssetId(chainToBeRegistered); + return abi.encodeCall(IL2Bridgehub.registerChainForInterop, (chainToBeRegistered, baseTokenAssetId)); + } + + /// @inheritdoc IL1CrossChainSender + /// @notice This function is not used for ChainRegistrationSender, since we do not need to support failed L1->L2 transactions. + function bridgehubConfirmL2Transaction(uint256 _chainId, bytes32 _txDataHash, bytes32 _txHash) external override {} +} diff --git a/l1-contracts/contracts/bridgehub/IBridgehubBase.sol b/l1-contracts/contracts/bridgehub/IBridgehubBase.sol index 40cd351a1e..b1a683ad8a 100644 --- a/l1-contracts/contracts/bridgehub/IBridgehubBase.sol +++ b/l1-contracts/contracts/bridgehub/IBridgehubBase.sol @@ -5,6 +5,7 @@ pragma solidity ^0.8.21; import {L2Log, L2Message, TxStatus} from "../common/Messaging.sol"; import {ICTMDeploymentTracker} from "./ICTMDeploymentTracker.sol"; import {IMessageRoot} from "./IMessageRoot.sol"; +import {TxStatus} from "../common/Messaging.sol"; import {IAssetRouterBase} from "../bridge/asset-router/IAssetRouterBase.sol"; struct L2TransactionRequestDirect { @@ -42,8 +43,11 @@ struct L2TransactionRequestTwoBridgesInner { struct BridgehubMintCTMAssetData { uint256 chainId; bytes32 baseTokenAssetId; + uint256 batchNumber; bytes ctmData; bytes chainData; + uint256 migrationNumber; + uint256 v30UpgradeChainBatchNumber; } struct BridgehubBurnCTMAssetData { @@ -111,6 +115,8 @@ interface IBridgehubBase { function assetRouter() external view returns (IAssetRouterBase); + function chainRegistrationSender() external view returns (address); + function whitelistedSettlementLayers(uint256 _chainId) external view returns (bool); function settlementLayer(uint256 _chainId) external view returns (uint256); @@ -184,5 +190,8 @@ interface IBridgehubBase { function registerNewZKChain(uint256 _chainId, address _zkChain, bool _checkMaxNumberOfZKChains) external; - function forwardedBridgeRecoverFailedTransfer(uint256 _chainId) external returns (address zkChain, address ctm); + function forwardedBridgeConfirmTransferResult( + uint256 _chainId, + TxStatus _txStatus + ) external returns (address zkChain, address ctm); } diff --git a/l1-contracts/contracts/bridgehub/ICTMDeploymentTracker.sol b/l1-contracts/contracts/bridgehub/ICTMDeploymentTracker.sol index f3c56d0be4..9c1bd50a4a 100644 --- a/l1-contracts/contracts/bridgehub/ICTMDeploymentTracker.sol +++ b/l1-contracts/contracts/bridgehub/ICTMDeploymentTracker.sol @@ -2,20 +2,13 @@ pragma solidity 0.8.28; -import {IBridgehubBase, L2TransactionRequestTwoBridgesInner} from "./IBridgehubBase.sol"; +import {IBridgehubBase} from "./IBridgehubBase.sol"; import {IAssetRouterBase} from "../bridge/asset-router/IAssetRouterBase.sol"; import {IL1AssetDeploymentTracker} from "../bridge/interfaces/IL1AssetDeploymentTracker.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev interface ICTMDeploymentTracker is IL1AssetDeploymentTracker { - function bridgehubDeposit( - uint256 _chainId, - address _originalCaller, - uint256 _l2Value, - bytes calldata _data - ) external payable returns (L2TransactionRequestTwoBridgesInner memory request); - function BRIDGE_HUB() external view returns (IBridgehubBase); function L1_ASSET_ROUTER() external view returns (IAssetRouterBase); diff --git a/l1-contracts/contracts/bridgehub/IChainAssetHandler.sol b/l1-contracts/contracts/bridgehub/IChainAssetHandler.sol index 387fdc6562..7fe7ccc9c3 100644 --- a/l1-contracts/contracts/bridgehub/IChainAssetHandler.sol +++ b/l1-contracts/contracts/bridgehub/IChainAssetHandler.sol @@ -19,6 +19,10 @@ interface IChainAssetHandler is IAssetHandler { /// @param zkChain The address of the ZK chain on the chain where it is migrated to. event MigrationFinalized(uint256 indexed chainId, bytes32 indexed assetId, address indexed zkChain); + function migrationNumber(uint256 _chainId) external view returns (uint256); + + function setMigrationNumberForV30(uint256 _chainId) external; + /// @dev Denotes whether the migrations of chains is paused. function migrationPaused() external view returns (bool); diff --git a/l1-contracts/contracts/state-transition/l2-deps/ISystemContext.sol b/l1-contracts/contracts/bridgehub/IChainRegistrationSender.sol similarity index 62% rename from l1-contracts/contracts/state-transition/l2-deps/ISystemContext.sol rename to l1-contracts/contracts/bridgehub/IChainRegistrationSender.sol index 8448cb4e41..576b84bb40 100644 --- a/l1-contracts/contracts/state-transition/l2-deps/ISystemContext.sol +++ b/l1-contracts/contracts/bridgehub/IChainRegistrationSender.sol @@ -4,6 +4,8 @@ pragma solidity ^0.8.21; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev -interface ISystemContext { - function setChainId(uint256 _newChainId) external; +interface IChainRegistrationSender { + function initialize(address _owner) external; + + function registerChain(uint256 chainToBeRegistered, uint256 chainRegisteredOn) external; } diff --git a/l1-contracts/contracts/bridgehub/IL1Bridgehub.sol b/l1-contracts/contracts/bridgehub/IL1Bridgehub.sol index ec53c63891..775cadfc90 100644 --- a/l1-contracts/contracts/bridgehub/IL1Bridgehub.sol +++ b/l1-contracts/contracts/bridgehub/IL1Bridgehub.sol @@ -8,6 +8,8 @@ import {IBridgehubBase, L2TransactionRequestDirect, L2TransactionRequestTwoBridg /// @custom:security-contact security@matterlabs.dev /// @dev Interface for L1-specific Bridgehub functionality interface IL1Bridgehub is IBridgehubBase { + /// @notice Get L1 chain ID + function L1_CHAIN_ID() external view returns (uint256); /// @notice Request L2 transaction directly function requestL2TransactionDirect( L2TransactionRequestDirect calldata _request @@ -32,9 +34,15 @@ interface IL1Bridgehub is IBridgehubBase { /// @notice Register settlement layer function registerSettlementLayer(uint256 _newSettlementLayerChainId, bool _isWhitelisted) external; + /// @notice Set addresses (L1 specific) + // function setAddresses( + // address _assetRouter, + // ICTMDeploymentTracker _l1CtmDeployer, + // IMessageRoot _messageRoot, + // address _chainAssetHandler, + // address _chainRegistrationSender + // ) external; + /// @notice Register already deployed ZK chain function registerAlreadyDeployedZKChain(uint256 _chainId, address _hyperchain) external; - - /// @notice Register legacy chain - function registerLegacyChain(uint256 _chainId) external; } diff --git a/l1-contracts/contracts/bridgehub/IL1ChainAssetHandler.sol b/l1-contracts/contracts/bridgehub/IL1ChainAssetHandler.sol new file mode 100644 index 0000000000..12b6ae00e9 --- /dev/null +++ b/l1-contracts/contracts/bridgehub/IL1ChainAssetHandler.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IL1ChainAssetHandler { + function isMigrationInProgress(uint256 _chainId) external view returns (bool); +} diff --git a/l1-contracts/contracts/bridgehub/IL2Bridgehub.sol b/l1-contracts/contracts/bridgehub/IL2Bridgehub.sol index 8c99879ffb..fd50698a95 100644 --- a/l1-contracts/contracts/bridgehub/IL2Bridgehub.sol +++ b/l1-contracts/contracts/bridgehub/IL2Bridgehub.sol @@ -7,4 +7,15 @@ import {IBridgehubBase} from "./IBridgehubBase.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev /// @dev Interface for L2-specific Bridgehub functionality -interface IL2Bridgehub is IBridgehubBase {} +interface IL2Bridgehub is IBridgehubBase { + /// @notice Set addresses + // function setAddresses( + // address _assetRouter, + // ICTMDeploymentTracker _l1CtmDeployer, + // IMessageRoot _messageRoot, + // address _chainAssetHandler, + // address _chainRegistrationSender + // ) external; + + function registerChainForInterop(uint256 _chainId, bytes32 _baseTokenAssetId) external; +} diff --git a/l1-contracts/contracts/bridgehub/IMessageRoot.sol b/l1-contracts/contracts/bridgehub/IMessageRoot.sol index 40fb53a4bf..03d257ef10 100644 --- a/l1-contracts/contracts/bridgehub/IMessageRoot.sol +++ b/l1-contracts/contracts/bridgehub/IMessageRoot.sol @@ -2,15 +2,91 @@ pragma solidity 0.8.28; +import {IMessageVerification} from "../common/interfaces/IMessageVerification.sol"; +import {ProofData} from "../common/Messaging.sol"; + +// Chain tree consists of batch commitments as their leaves. We use hash of "new bytes(96)" as the hash of an empty leaf. +bytes32 constant CHAIN_TREE_EMPTY_ENTRY_HASH = bytes32( + 0x46700b4d40ac5c35af2c22dda2787a91eb567b06c924a8fb8ae9a05b20c08c21 +); + +// The single shared tree consists of the roots of chain trees as its leaves. We use hash of "new bytes(96)" as the hash of an empty leaf. +bytes32 constant SHARED_ROOT_TREE_EMPTY_HASH = bytes32( + 0x46700b4d40ac5c35af2c22dda2787a91eb567b06c924a8fb8ae9a05b20c08c21 +); + +// The value that is saved in the v30UpgradeChainBatchNumber mapping for all deployed chains until the chain upgrades to v30. +uint256 constant V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_GATEWAY = uint256( + keccak256(abi.encodePacked("V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_GATEWAY")) +); + +// The value that is saved in the v30UpgradeChainBatchNumber mapping for all deployed chains until the chain upgrades to v30. +uint256 constant V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_L1 = uint256( + keccak256(abi.encodePacked("V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_L1")) +); + /** * @author Matter Labs * @notice MessageRoot contract is responsible for storing and aggregating the roots of the batches from different chains into the MessageRoot. * @custom:security-contact security@matterlabs.dev */ -interface IMessageRoot { +interface IMessageRoot is IMessageVerification { + /// @notice Emitted when a new chain is added to the MessageRoot. + /// @param chainId The ID of the chain that is being added to the MessageRoot. + /// @param chainIndex The index of the chain that is being added. Note, that chain where + /// the MessageRoot contract was deployed has chainIndex of 0, and this event is not emitted for it. + event AddedChain(uint256 indexed chainId, uint256 indexed chainIndex); + + /// @notice Emitted when a new chain batch root is appended to the chainTree. + /// @param chainId The ID of the chain whose chain batch root is being added to the chainTree. + /// @param batchNumber The number of the batch to which chain batch root belongs. + /// @param chainBatchRoot The value of chain batch root which is being added. + event AppendedChainBatchRoot(uint256 indexed chainId, uint256 indexed batchNumber, bytes32 chainBatchRoot); + + /// @notice Emitted when a new chainTree root is produced and its corresponding leaf in sharedTree is updated. + /// @param chainId The ID of the chain whose chainTree root is being updated. + /// @param chainRoot The updated Merkle root of the chainTree after appending the latest batch root. + /// @param chainIdLeafHash The Merkle leaf value computed from `chainRoot` and the chain’s ID, used to update the shared tree. + event NewChainRoot(uint256 indexed chainId, bytes32 chainRoot, bytes32 chainIdLeafHash); + + /// @notice Emitted whenever the sharedTree is updated, and the new InteropRoot (root of the sharedTree) is generated. + /// @param chainId The ID of the chain where the sharedTree was updated. + /// @param blockNumber The block number of the block in which the sharedTree was updated. + /// @param logId The ID of the log emitted when a new InteropRoot. In this release always equal to 0. + /// @param sides The "sides" of the interop root. In this release which uses proof-based interop the sides is an array + /// of length one, which only include the interop root itself. More on that in `L2InteropRootStorage` contract. + event NewInteropRoot(uint256 indexed chainId, uint256 indexed blockNumber, uint256 indexed logId, bytes32[] sides); + function BRIDGE_HUB() external view returns (address); - function addNewChain(uint256 _chainId) external; + function ERA_GATEWAY_CHAIN_ID() external view returns (uint256); + + function addNewChain(uint256 _chainId, uint256 _startingBatchNumber) external; + + function addChainBatchRoot(uint256 _chainId, uint256 _batchNumber, bytes32 _chainBatchRoot) external; + + function chainBatchRoots(uint256 _chainId, uint256 _batchNumber) external view returns (bytes32); function historicalRoot(uint256 _blockNumber) external view returns (bytes32); + + function v30UpgradeChainBatchNumber(uint256 _chainId) external view returns (uint256); + + function saveV30UpgradeChainBatchNumber(uint256 _chainId) external; + + /// @dev Used to parse the merkle proof data, this function calls a library function. + function getProofData( + uint256 _chainId, + uint256 _batchNumber, + uint256 _leafProofMask, + bytes32 _leaf, + bytes32[] calldata _proof + ) external pure returns (ProofData memory); + + function setMigratingChainBatchRoot( + uint256 _chainId, + uint256 _batchNumber, + uint256 _v30UpgradeChainBatchNumber + ) external; + + function currentChainBatchNumber(uint256 _chainId) external view returns (uint256); } diff --git a/l1-contracts/contracts/bridgehub/L1Bridgehub.sol b/l1-contracts/contracts/bridgehub/L1Bridgehub.sol index 383f8538bf..2b40b8fe09 100644 --- a/l1-contracts/contracts/bridgehub/L1Bridgehub.sol +++ b/l1-contracts/contracts/bridgehub/L1Bridgehub.sol @@ -16,9 +16,10 @@ import {IZKChain} from "../state-transition/chain-interfaces/IZKChain.sol"; import {ICTMDeploymentTracker} from "./ICTMDeploymentTracker.sol"; import {IMessageRoot} from "./IMessageRoot.sol"; import {BridgehubL2TransactionRequest} from "../common/Messaging.sol"; -import {ChainIdAlreadyPresent, ChainNotLegacy, ChainNotPresentInCTM, SecondBridgeAddressTooLow} from "./L1BridgehubErrors.sol"; +import {SecondBridgeAddressTooLow} from "./L1BridgehubErrors.sol"; import {SettlementLayersMustSettleOnL1} from "../common/L1ContractErrors.sol"; import {ChainIdAlreadyExists, ChainIdMismatch, IncorrectBridgeHubAddress, MsgValueMismatch, WrongMagicValue, ZeroAddress} from "../common/L1ContractErrors.sol"; +import {IL1CrossChainSender} from "../bridge/interfaces/IL1CrossChainSender.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -80,42 +81,6 @@ contract L1Bridgehub is BridgehubBase, IL1Bridgehub { return L1_CHAIN_ID; } - /// @notice Used to set the legacy chain data for the upgrade. - /// @param _chainId The chainId of the legacy chain we are migrating. - function registerLegacyChain(uint256 _chainId) external override { - address ctm = chainTypeManager[_chainId]; - if (ctm == address(0)) { - revert ChainNotLegacy(); - } - // slither-disable-next-line unused-return - (bool exists, ) = zkChainMap.tryGet(_chainId); - if (exists) { - revert ChainIdAlreadyPresent(); - } - - // From now on, since `zkChainMap` did not contain the chain, we assume - // that the chain is a legacy chain in the process of migration, i.e. - // its stored `baseTokenAssetId`, etc. - - address token = __DEPRECATED_baseToken[_chainId]; - if (token == address(0)) { - revert ChainNotLegacy(); - } - - bytes32 assetId = DataEncoding.encodeNTVAssetId(block.chainid, token); - - baseTokenAssetId[_chainId] = assetId; - assetIdIsRegistered[assetId] = true; - - address chainAddress = IChainTypeManager(ctm).getZKChainLegacy(_chainId); - if (chainAddress == address(0)) { - revert ChainNotPresentInCTM(); - } - _registerNewZKChain(_chainId, chainAddress, false); - messageRoot.addNewChain(_chainId); - settlementLayer[_chainId] = block.chainid; - } - /// @notice Used to register a chain as a settlement layer. /// @param _newSettlementLayerChainId the chainId of the chain /// @param _isWhitelisted whether the chain is a whitelisted settlement layer @@ -161,7 +126,7 @@ contract L1Bridgehub is BridgehubBase, IL1Bridgehub { _factoryDeps: _factoryDeps }); _registerNewZKChain(_chainId, chainAddress, true); - messageRoot.addNewChain(_chainId); + messageRoot.addNewChain(_chainId, 0); emit NewChain(_chainId, _chainTypeManager, _admin); return _chainId; @@ -258,7 +223,7 @@ contract L1Bridgehub is BridgehubBase, IL1Bridgehub { } // slither-disable-next-line arbitrary-send-eth - L2TransactionRequestTwoBridgesInner memory outputRequest = IL1AssetRouter(_request.secondBridgeAddress) + L2TransactionRequestTwoBridgesInner memory outputRequest = IL1CrossChainSender(_request.secondBridgeAddress) .bridgehubDeposit{value: _request.secondBridgeValue}( _request.chainId, msg.sender, @@ -298,12 +263,14 @@ contract L1Bridgehub is BridgehubBase, IL1Bridgehub { address _assetRouter, ICTMDeploymentTracker _l1CtmDeployer, IMessageRoot _messageRoot, - address _chainAssetHandler + address _chainAssetHandler, + address _chainRegistrationSender ) external override onlyOwnerOrUpgrader { assetRouter = IAssetRouterBase(_assetRouter); l1CtmDeployer = _l1CtmDeployer; messageRoot = _messageRoot; chainAssetHandler = _chainAssetHandler; + chainRegistrationSender = _chainRegistrationSender; } /// @dev Registers an already deployed chain with the bridgehub @@ -326,6 +293,7 @@ contract L1Bridgehub is BridgehubBase, IL1Bridgehub { address chainAdmin = IZKChain(_zkChain).getAdmin(); bytes32 chainBaseTokenAssetId = IZKChain(_zkChain).getBaseTokenAssetId(); address bridgeHub = IZKChain(_zkChain).getBridgehub(); + uint256 batchNumber = IZKChain(_zkChain).getTotalBatchesExecuted(); if (bridgeHub != address(this)) { revert IncorrectBridgeHubAddress(bridgeHub); @@ -339,7 +307,7 @@ contract L1Bridgehub is BridgehubBase, IL1Bridgehub { settlementLayer[_chainId] = block.chainid; _registerNewZKChain(_chainId, _zkChain, true); - messageRoot.addNewChain(_chainId); + messageRoot.addNewChain(_chainId, batchNumber); emit NewChain(_chainId, ctm, chainAdmin); } diff --git a/l1-contracts/contracts/bridgehub/L1BridgehubErrors.sol b/l1-contracts/contracts/bridgehub/L1BridgehubErrors.sol index a7dc9d2f64..1c77ac9acd 100644 --- a/l1-contracts/contracts/bridgehub/L1BridgehubErrors.sol +++ b/l1-contracts/contracts/bridgehub/L1BridgehubErrors.sol @@ -4,34 +4,48 @@ pragma solidity ^0.8.21; // 0x587df426 error AlreadyCurrentSL(uint256 blockChainId); +// 0xa695b1ef +error BatchZeroNotAllowed(); +// 0xb0b5006f +error ChainAlreadyRegistered(); +// 0xbe263463 +error ChainBatchRootAlreadyExists(uint256 chainId, uint256 batchNumber); +// 0x655c373c +error ChainBatchRootZero(); // 0x65e8a019 error ChainExists(); -// 0xff514c10 -error ChainIdAlreadyPresent(); -// 0x5de72107 -error ChainNotLegacy(); -// 0x4bd4ae07 -error ChainNotPresentInCTM(); -// 0xeab895aa -error HyperchainNotRegistered(); +// 0x5d03f19d +error CurrentBatchNumberAlreadySet(); +// 0x68d91b49 +error DepthMoreThanOneForRecursiveMerkleProof(); // 0x48857c1d error IncorrectChainAssetId(bytes32 assetId, bytes32 assetIdFromChainId); +// 0xdb495273 +error IncorrectFunctionSignature(); // 0xf5e39c1f error IncorrectSender(address prevMsgSender, address chainAdmin); +// 0x47d42b1b +error IteratedMigrationsNotSupported(); +// 0xc3bd3c65 +error LocallyNoChainsAtGenesis(); // 0x913183d8 error MessageRootNotRegistered(); +// 0x4010a88d +error MigrationNotToL1(); +// 0x12b08c62 +error MigrationNumberAlreadySet(); +// 0xde1362a2 +error MigrationNumberMismatch(uint256 _expected, uint256 _actual); // 0x7f4316f3 error NoEthAllowed(); -// 0xf306a770 -error NotAssetRouter(address msgSender, address sharedBridge); +// 0x366c42f8 +error NonConsecutiveBatchNumber(uint256 chainId, uint256 batchNumber); // 0x8beee3a3 error NotChainAssetHandler(address sender, address chainAssetHandler); -// 0xc0ca9182 -error NotCurrentSL(uint256 settlementLayerChainId, uint256 blockChainId); +// 0x88d9dae3 +error NotCurrentSettlementLayer(uint256 currentSettlementLayer, uint256 newSettlementLayer); // 0x472477e2 error NotInGatewayMode(); -// 0xecb34449 -error NotL1(uint256 l1ChainId, uint256 blockChainId); // 0x8eb4fc01 error NotL2(); // 0x23295f0e @@ -40,17 +54,43 @@ error NotOwner(address sender, address owner); error NotOwnerViaRouter(address msgSender, address originalCaller); // 0xa2ac02a0 error NotRelayedSender(address msgSender, address settlementLayerRelaySender); +// 0xb35a7373 +error NotSystemContext(address _sender); +// 0xb30ebfd8 +error NotWhitelistedSettlementLayer(uint256 chainId); +// 0x3db511f4 +error OnlyAssetTracker(address, address); // 0x527b87c7 error OnlyBridgehub(address msgSender, address bridgehub); // 0x2d396674 error OnlyBridgehubOrChainAssetHandler(address sender, address bridgehub, address chainAssetHandler); // 0x73fe6c1b error OnlyChain(address msgSender, address zkChainAddress); +// 0xec76af13 +error OnlyGateway(); +// 0x8d14ca84 +error OnlyL1(); +// 0x605d6b86 +error OnlyL2MessageRoot(); +// 0x6b75db8c +error OnlyOnSettlementLayer(); +// 0x26d10385 +error OnlyPreV30Chain(uint256 chainId); // 0xb78dbaa7 error SecondBridgeAddressTooLow(address secondBridgeAddress, address minSecondBridgeAddress); -// 0x90c7cbf1 -error SLNotWhitelisted(); // 0x36917565 error SLHasDifferentCTM(); +// 0x90c7cbf1 +error SLNotWhitelisted(); +// 0x8732442d +error TotalBatchesExecutedLessThanV30UpgradeChainBatchNumber(); +// 0x70a472bd +error TotalBatchesExecutedZero(); +// 0x246de5b7 +error V30UpgradeChainBatchNumberAlreadySet(); +// 0x862f0039 +error V30UpgradeChainBatchNumberNotSet(); // 0x92626457 error WrongCounterPart(address addressOnCounterPart, address l2BridgehubAddress); +// 0x7b968d06 +error ZKChainNotRegistered(); diff --git a/l1-contracts/contracts/bridgehub/L1ChainAssetHandler.sol b/l1-contracts/contracts/bridgehub/L1ChainAssetHandler.sol index 8d9394879d..27858a43c2 100644 --- a/l1-contracts/contracts/bridgehub/L1ChainAssetHandler.sol +++ b/l1-contracts/contracts/bridgehub/L1ChainAssetHandler.sol @@ -5,6 +5,8 @@ pragma solidity 0.8.28; import {ChainAssetHandlerBase} from "./ChainAssetHandlerBase.sol"; import {ETH_TOKEN_ADDRESS} from "../common/Config.sol"; import {DataEncoding} from "../common/libraries/DataEncoding.sol"; +import {IL1Nullifier} from "../bridge/interfaces/IL1Nullifier.sol"; +import {TxStatus} from "../common/Messaging.sol"; import {IBridgehubBase, BridgehubBurnCTMAssetData} from "./IBridgehubBase.sol"; import {IChainTypeManager} from "../state-transition/IChainTypeManager.sol"; import {IZKChain} from "../state-transition/chain-interfaces/IZKChain.sol"; @@ -35,6 +37,15 @@ contract L1ChainAssetHandler is ChainAssetHandlerBase, IL1AssetHandler { /// @dev The asset router contract. IAssetRouterBase public immutable override ASSET_ROUTER; + /// @dev The asset tracker contract. + address internal immutable ASSET_TRACKER; + + /// @dev The L1 nullifier contract. + IL1Nullifier internal immutable L1_NULLIFIER; + + /// @dev The mapping showing for each chain if migration is in progress or not, used for freezing deposits.abi + mapping(uint256 chainId => bool isMigrationInProgress) public isMigrationInProgress; + /*////////////////////////////////////////////////////////////// IMMUTABLE GETTERS //////////////////////////////////////////////////////////////*/ @@ -55,11 +66,17 @@ contract L1ChainAssetHandler is ChainAssetHandlerBase, IL1AssetHandler { return ASSET_ROUTER; } + function _assetTracker() internal view override returns (address) { + return ASSET_TRACKER; + } + constructor( address _owner, address _bridgehub, address _assetRouter, - address _messageRoot + address _messageRoot, + address _assetTracker, + IL1Nullifier _l1Nullifier ) reentrancyGuardInitializer { _disableInitializers(); BRIDGEHUB = IL1Bridgehub(_bridgehub); @@ -67,6 +84,8 @@ contract L1ChainAssetHandler is ChainAssetHandlerBase, IL1AssetHandler { MESSAGE_ROOT = IMessageRoot(_messageRoot); L1_CHAIN_ID = block.chainid; ETH_TOKEN_ASSET_ID = DataEncoding.encodeNTVAssetId(block.chainid, ETH_TOKEN_ADDRESS); + ASSET_TRACKER = _assetTracker; + L1_NULLIFIER = _l1Nullifier; _transferOwnership(_owner); } @@ -77,36 +96,48 @@ contract L1ChainAssetHandler is ChainAssetHandlerBase, IL1AssetHandler { } /// @dev IL1AssetHandler interface, used to undo a failed migration of a chain. - /// @param _chainId the chainId of the chain /// @param _assetId the assetId of the chain's CTM /// @param _data the data for the recovery. /// @param _depositSender the address of the entity that initiated the deposit. // slither-disable-next-line locked-ether - function bridgeRecoverFailedTransfer( - // solhint-disable-next-line no-unused-vars - uint256 _chainId, + function bridgeConfirmTransferResult( + uint256, + TxStatus _txStatus, bytes32 _assetId, address _depositSender, bytes calldata _data - ) external payable override requireZeroValue(msg.value) onlyAssetRouter { + ) external payable requireZeroValue(msg.value) onlyAssetRouter { BridgehubBurnCTMAssetData memory bridgehubBurnData = abi.decode(_data, (BridgehubBurnCTMAssetData)); - (address zkChain, address ctm) = IBridgehubBase(_bridgehub()).forwardedBridgeRecoverFailedTransfer( - bridgehubBurnData.chainId + (address zkChain, address ctm) = IBridgehubBase(_bridgehub()).forwardedBridgeConfirmTransferResult( + bridgehubBurnData.chainId, + _txStatus ); - IChainTypeManager(ctm).forwardedBridgeRecoverFailedTransfer({ + IChainTypeManager(ctm).forwardedBridgeConfirmTransferResult({ _chainId: bridgehubBurnData.chainId, + _txStatus: _txStatus, _assetInfo: _assetId, _depositSender: _depositSender, _ctmData: bridgehubBurnData.ctmData }); - IZKChain(zkChain).forwardedBridgeRecoverFailedTransfer({ + if (_txStatus == TxStatus.Failure) { + --migrationNumber[bridgehubBurnData.chainId]; + } + + isMigrationInProgress[bridgehubBurnData.chainId] = false; + + IZKChain(zkChain).forwardedBridgeConfirmTransferResult({ _chainId: bridgehubBurnData.chainId, + _txStatus: _txStatus, _assetInfo: _assetId, _originalCaller: _depositSender, _chainData: bridgehubBurnData.chainData }); } + + function _setMigrationInProgressOnL1(uint256 _chainId) internal override { + isMigrationInProgress[_chainId] = true; + } } diff --git a/l1-contracts/contracts/bridgehub/L1MessageRoot.sol b/l1-contracts/contracts/bridgehub/L1MessageRoot.sol index 00337f3a94..ff771ec94b 100644 --- a/l1-contracts/contracts/bridgehub/L1MessageRoot.sol +++ b/l1-contracts/contracts/bridgehub/L1MessageRoot.sol @@ -3,6 +3,13 @@ pragma solidity 0.8.28; import {MessageRootBase} from "./MessageRootBase.sol"; +import {FinalizeL1DepositParams} from "../bridge/interfaces/IL1Nullifier.sol"; +import {UnsafeBytes} from "../common/libraries/UnsafeBytes.sol"; +import {IncorrectFunctionSignature, LocallyNoChainsAtGenesis, NotWhitelistedSettlementLayer, OnlyGateway, OnlyL2MessageRoot, V30UpgradeChainBatchNumberAlreadySet} from "./L1BridgehubErrors.sol"; +import {L2_MESSAGE_ROOT_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; +import {InvalidProof} from "../common/L1ContractErrors.sol"; +import {L2MessageRoot} from "./L2MessageRoot.sol"; +import {IBridgehubBase} from "./IBridgehubBase.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -11,18 +18,67 @@ contract L1MessageRoot is MessageRootBase { /// @dev Bridgehub smart contract that is used to operate with L2 via asynchronous L2 <-> L1 communication. address public immutable BRIDGE_HUB; + /// @notice The chain id of the Gateway chain. + uint256 public immutable override ERA_GATEWAY_CHAIN_ID; + /// @dev Contract is expected to be used as proxy implementation on L1, but as a system contract on L2. /// This means we call the _initialize in both the constructor and the initialize functions. + /// Used for V30 upgrade deployment and local deployments. /// @dev Initialize the implementation to prevent Parity hack. - constructor(address _bridgehub) { + /// @param _bridgehub Address of the Bridgehub. + /// @param _eraGatewayChainId Chain ID of the Gateway chain. + constructor(address _bridgehub, uint256 _eraGatewayChainId) { BRIDGE_HUB = _bridgehub; + ERA_GATEWAY_CHAIN_ID = _eraGatewayChainId; + uint256[] memory allZKChains = IBridgehubBase(_bridgehub).getAllZKChainChainIDs(); + _v30InitializeInner(allZKChains); _initialize(); _disableInitializers(); } /// @dev Initializes a contract for later use. Expected to be used in the proxy on L1, on L2 it is a system contract without a proxy. - function initialize() external initializer { + function initialize() external reinitializer(2) { _initialize(); + uint256[] memory allZKChains = IBridgehubBase(BRIDGE_HUB).getAllZKChainChainIDs(); + uint256 allZKChainsLength = allZKChains.length; + /// locally there are no chains deployed before. + require(allZKChainsLength == 0, LocallyNoChainsAtGenesis()); + } + + /// @dev The initialized used for the V30 upgrade. + /// On L2s the initializers are disabled. + function initializeL1V30Upgrade() external reinitializer(2) onlyL1 { + uint256[] memory allZKChains = IBridgehubBase(BRIDGE_HUB).getAllZKChainChainIDs(); + _v30InitializeInner(allZKChains); + } + function saveV30UpgradeChainBatchNumberOnL1(FinalizeL1DepositParams calldata _finalizeWithdrawalParams) external { + require(_finalizeWithdrawalParams.l2Sender == L2_MESSAGE_ROOT_ADDR, OnlyL2MessageRoot()); + bool success = proveL1DepositParamsInclusion(_finalizeWithdrawalParams); + if (!success) { + revert InvalidProof(); + } + + require(_finalizeWithdrawalParams.chainId == ERA_GATEWAY_CHAIN_ID, OnlyGateway()); + require( + IBridgehubBase(BRIDGE_HUB).whitelistedSettlementLayers(_finalizeWithdrawalParams.chainId), + NotWhitelistedSettlementLayer(_finalizeWithdrawalParams.chainId) + ); + + (uint32 functionSignature, uint256 offset) = UnsafeBytes.readUint32(_finalizeWithdrawalParams.message, 0); + require( + bytes4(functionSignature) == L2MessageRoot.sendV30UpgradeBlockNumberFromGateway.selector, + IncorrectFunctionSignature() + ); + + // slither-disable-next-line unused-return + (uint256 chainId, ) = UnsafeBytes.readUint256(_finalizeWithdrawalParams.message, offset); + // slither-disable-next-line unused-return + (uint256 receivedV30UpgradeChainBatchNumber, ) = UnsafeBytes.readUint256( + _finalizeWithdrawalParams.message, + offset + ); + require(v30UpgradeChainBatchNumber[chainId] == 0, V30UpgradeChainBatchNumberAlreadySet()); + v30UpgradeChainBatchNumber[chainId] = receivedV30UpgradeChainBatchNumber; } /*////////////////////////////////////////////////////////////// @@ -36,4 +92,8 @@ contract L1MessageRoot is MessageRootBase { function L1_CHAIN_ID() public view override returns (uint256) { return block.chainid; } + + function _eraGatewayChainId() internal view override returns (uint256) { + return ERA_GATEWAY_CHAIN_ID; + } } diff --git a/l1-contracts/contracts/bridgehub/L2Bridgehub.sol b/l1-contracts/contracts/bridgehub/L2Bridgehub.sol index 968bbad45e..f8bf3b1c83 100644 --- a/l1-contracts/contracts/bridgehub/L2Bridgehub.sol +++ b/l1-contracts/contracts/bridgehub/L2Bridgehub.sol @@ -5,6 +5,9 @@ pragma solidity 0.8.28; import {DataEncoding} from "../common/libraries/DataEncoding.sol"; import {EnumerableMap} from "@openzeppelin/contracts-v4/utils/structs/EnumerableMap.sol"; +import {SERVICE_TRANSACTION_SENDER} from "../common/Config.sol"; +import {AddressAliasHelper} from "../vendor/AddressAliasHelper.sol"; +import {Unauthorized} from "../common/L1ContractErrors.sol"; import {ETH_TOKEN_ADDRESS, SETTLEMENT_LAYER_RELAY_SENDER} from "../common/Config.sol"; import {BridgehubBase} from "./BridgehubBase.sol"; import {IL2Bridgehub} from "./IL2Bridgehub.sol"; @@ -40,6 +43,16 @@ contract L2Bridgehub is BridgehubBase, IL2Bridgehub { /// the old version where it was an immutable. uint256 public MAX_NUMBER_OF_ZK_CHAINS; + modifier onlyChainRegistrationSender() { + if ( + msg.sender != AddressAliasHelper.undoL1ToL2Alias(chainRegistrationSender) && + msg.sender != SERVICE_TRANSACTION_SENDER + ) { + revert Unauthorized(msg.sender); + } + _; + } + /// @notice Initializes the contract. /// @dev This function is used to initialize the contract with the initial values. /// @param _l1ChainId The chain id of L1. @@ -71,6 +84,17 @@ contract L2Bridgehub is BridgehubBase, IL2Bridgehub { ETH_TOKEN_ASSET_ID = DataEncoding.encodeNTVAssetId(L1_CHAIN_ID, ETH_TOKEN_ADDRESS); } + /// @notice used to register chains on L2 for the purpose of interop. + /// @param _chainId the chainId of the chain to be registered. + /// @param _baseTokenAssetId the base token asset id of the chain. + function registerChainForInterop(uint256 _chainId, bytes32 _baseTokenAssetId) external onlyChainRegistrationSender { + baseTokenAssetId[_chainId] = _baseTokenAssetId; + } + + /*////////////////////////////////////////////////////////////// + IMMUTABLE GETTERS + //////////////////////////////////////////////////////////////*/ + /// @dev Returns the asset ID of ETH token for internal use. function _ethTokenAssetId() internal view override returns (bytes32) { return ETH_TOKEN_ASSET_ID; @@ -115,11 +139,13 @@ contract L2Bridgehub is BridgehubBase, IL2Bridgehub { address _assetRouter, ICTMDeploymentTracker _l1CtmDeployer, IMessageRoot _messageRoot, - address _chainAssetHandler + address _chainAssetHandler, + address _chainRegistrationSender ) external override onlyOwnerOrUpgrader { assetRouter = IAssetRouterBase(_assetRouter); l1CtmDeployer = _l1CtmDeployer; messageRoot = _messageRoot; chainAssetHandler = _chainAssetHandler; + chainRegistrationSender = _chainRegistrationSender; } } diff --git a/l1-contracts/contracts/bridgehub/L2ChainAssetHandler.sol b/l1-contracts/contracts/bridgehub/L2ChainAssetHandler.sol index 22a1eec9b3..a4dd00205c 100644 --- a/l1-contracts/contracts/bridgehub/L2ChainAssetHandler.sol +++ b/l1-contracts/contracts/bridgehub/L2ChainAssetHandler.sol @@ -5,7 +5,7 @@ pragma solidity 0.8.28; import {ChainAssetHandlerBase} from "./ChainAssetHandlerBase.sol"; import {ETH_TOKEN_ADDRESS} from "../common/Config.sol"; import {DataEncoding} from "../common/libraries/DataEncoding.sol"; -import {L2_COMPLEX_UPGRADER_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; +import {L2_COMPLEX_UPGRADER_ADDR, L2_ASSET_TRACKER_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; import {InvalidCaller} from "../common/L1ContractErrors.sol"; import {IL1Bridgehub} from "./IL1Bridgehub.sol"; import {IMessageRoot} from "./IMessageRoot.sol"; @@ -67,6 +67,10 @@ contract L2ChainAssetHandler is ChainAssetHandlerBase { return ASSET_ROUTER; } + function _assetTracker() internal view override returns (address) { + return L2_ASSET_TRACKER_ADDR; + } + /// @dev Only allows calls from the complex upgrader contract on L2. modifier onlyUpgrader() { if (msg.sender != L2_COMPLEX_UPGRADER_ADDR) { diff --git a/l1-contracts/contracts/bridgehub/L2MessageRoot.sol b/l1-contracts/contracts/bridgehub/L2MessageRoot.sol index 00be1d5370..3e64b12758 100644 --- a/l1-contracts/contracts/bridgehub/L2MessageRoot.sol +++ b/l1-contracts/contracts/bridgehub/L2MessageRoot.sol @@ -4,15 +4,18 @@ pragma solidity 0.8.28; import {MessageRootBase} from "./MessageRootBase.sol"; -import {L2_BRIDGEHUB_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; +import {L2_BRIDGEHUB_ADDR, L2_COMPLEX_UPGRADER_ADDR, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT} from "../common/l2-helpers/L2ContractAddresses.sol"; -import {MessageRootNotRegistered} from "./L1BridgehubErrors.sol"; +import {V30UpgradeChainBatchNumberNotSet, OnlyGateway} from "./L1BridgehubErrors.sol"; import {MessageHashing} from "../common/libraries/MessageHashing.sol"; import {FullMerkle} from "../common/libraries/FullMerkle.sol"; import {DynamicIncrementalMerkle} from "../common/libraries/DynamicIncrementalMerkle.sol"; +import {V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_GATEWAY} from "./IMessageRoot.sol"; +import {InvalidCaller, Unauthorized} from "../common/L1ContractErrors.sol"; +import {SERVICE_TRANSACTION_SENDER} from "../common/Config.sol"; import {L2_COMPLEX_UPGRADER_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; -import {InvalidCaller} from "../common/L1ContractErrors.sol"; +import {IBridgehubBase} from "./IBridgehubBase.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -25,6 +28,9 @@ contract L2MessageRoot is MessageRootBase { /// @dev Chain ID of L1 for bridging reasons. uint256 internal l1ChainId; + /// @notice The chain id of the Gateway chain. + uint256 public override ERA_GATEWAY_CHAIN_ID; + /*////////////////////////////////////////////////////////////// IMMUTABLE GETTERS //////////////////////////////////////////////////////////////*/ @@ -33,8 +39,8 @@ contract L2MessageRoot is MessageRootBase { return L2_BRIDGEHUB_ADDR; } - function L1_CHAIN_ID() public view override returns (uint256) { - return l1ChainId; + function _eraGatewayChainId() internal view override returns (uint256) { + return ERA_GATEWAY_CHAIN_ID; } // A method for backwards compatibility with the old implementation @@ -42,6 +48,10 @@ contract L2MessageRoot is MessageRootBase { return L2_BRIDGEHUB_ADDR; } + function L1_CHAIN_ID() public view override returns (uint256) { + return l1ChainId; + } + /// @dev Only allows calls from the complex upgrader contract on L2. modifier onlyUpgrader() { if (msg.sender != L2_COMPLEX_UPGRADER_ADDR) { @@ -50,28 +60,55 @@ contract L2MessageRoot is MessageRootBase { _; } + modifier onlyServiceTransactionSender() { + require(msg.sender == SERVICE_TRANSACTION_SENDER, Unauthorized(msg.sender)); + _; + } + + /// @notice Checks that the Chain ID is the Gateway chain id. + modifier onlyGateway() { + if (block.chainid != _eraGatewayChainId()) { + revert OnlyGateway(); + } + _; + } + /// @notice Initializes the contract. /// @dev This function is used to initialize the contract with the initial values. /// @param _l1ChainId The chain id of L1. - function initL2(uint256 _l1ChainId) public onlyUpgrader { + function initL2(uint256 _l1ChainId, uint256 _eraGatewayChainId) public onlyUpgrader { _disableInitializers(); + ERA_GATEWAY_CHAIN_ID = _eraGatewayChainId; l1ChainId = _l1ChainId; _initialize(); } + /// On L2s the initializer/reinitializer is not called. + function initializeL2V30Upgrade() external onlyL2 onlyUpgrader { + uint256[] memory allZKChains = IBridgehubBase(_bridgehub()).getAllZKChainChainIDs(); + _v30InitializeInner(allZKChains); + } + + /// @notice This function is used to send the V30 upgrade block number from the Gateway to the L1 chain. + function sendV30UpgradeBlockNumberFromGateway(uint256 _chainId, uint256) external onlyGateway { + uint256 sentBlockNumber = v30UpgradeChainBatchNumber[_chainId]; + require( + sentBlockNumber != V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_GATEWAY && sentBlockNumber != 0, + V30UpgradeChainBatchNumberNotSet() + ); + + // slither-disable-next-line unused-return + L2_TO_L1_MESSENGER_SYSTEM_CONTRACT.sendToL1( + abi.encodeCall(this.sendV30UpgradeBlockNumberFromGateway, (_chainId, sentBlockNumber)) + ); + } + /// @notice Adds a new chainBatchRoot to the chainTree. /// @param _chainId The ID of the chain whose chainBatchRoot is being added to the chainTree. /// @param _batchNumber The number of the batch to which _chainBatchRoot belongs. /// @param _chainBatchRoot The value of chainBatchRoot which is being added. - function addChainBatchRoot( - uint256 _chainId, - uint256 _batchNumber, - bytes32 _chainBatchRoot - ) external onlyChain(_chainId) { - // Make sure that chain is registered. - if (!chainRegistered(_chainId)) { - revert MessageRootNotRegistered(); - } + function addChainBatchRoot(uint256 _chainId, uint256 _batchNumber, bytes32 _chainBatchRoot) public override { + super.addChainBatchRoot(_chainId, _batchNumber, _chainBatchRoot); // Push chainBatchRoot to the chainTree related to specified chainId and get the new root. bytes32 chainRoot; @@ -86,11 +123,7 @@ contract L2MessageRoot is MessageRootBase { emit NewChainRoot(_chainId, chainRoot, cachedChainIdLeafHash); - // What happens here is we query for the current sharedTreeRoot and emit the event stating that new InteropRoot is "created". - // The reason for the usage of "bytes32[] memory _sides" to store the InteropRoot is explained in L2InteropRootStorage contract. - bytes32[] memory _sides = new bytes32[](1); - _sides[0] = sharedTreeRoot; - emit NewInteropRoot(block.chainid, block.number, 0, _sides); + _emitRoot(sharedTreeRoot); historicalRoot[block.number] = sharedTreeRoot; } } diff --git a/l1-contracts/contracts/bridgehub/MessageRootBase.sol b/l1-contracts/contracts/bridgehub/MessageRootBase.sol index 5771a4484a..3020edc641 100644 --- a/l1-contracts/contracts/bridgehub/MessageRootBase.sol +++ b/l1-contracts/contracts/bridgehub/MessageRootBase.sol @@ -5,26 +5,27 @@ pragma solidity 0.8.28; import {Initializable} from "@openzeppelin/contracts-v4/proxy/utils/Initializable.sol"; import {DynamicIncrementalMerkle} from "../common/libraries/DynamicIncrementalMerkle.sol"; + +import {CHAIN_TREE_EMPTY_ENTRY_HASH, IMessageRoot, SHARED_ROOT_TREE_EMPTY_HASH, V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_GATEWAY, V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_L1} from "./IMessageRoot.sol"; +import {BatchZeroNotAllowed, ChainBatchRootAlreadyExists, ChainBatchRootZero, ChainExists, CurrentBatchNumberAlreadySet, DepthMoreThanOneForRecursiveMerkleProof, MessageRootNotRegistered, NonConsecutiveBatchNumber, NotL2, NotWhitelistedSettlementLayer, OnlyAssetTracker, OnlyBridgehubOrChainAssetHandler, OnlyChain, OnlyL1, OnlyOnSettlementLayer, OnlyPreV30Chain, TotalBatchesExecutedLessThanV30UpgradeChainBatchNumber, TotalBatchesExecutedZero, V30UpgradeChainBatchNumberAlreadySet} from "./L1BridgehubErrors.sol"; + +import {GW_ASSET_TRACKER_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; + +import {MessageHashing, ProofData} from "../common/libraries/MessageHashing.sol"; import {IBridgehubBase} from "./IBridgehubBase.sol"; import {IMessageRoot} from "./IMessageRoot.sol"; -import {ChainExists, MessageRootNotRegistered, NotL2, OnlyBridgehubOrChainAssetHandler, OnlyChain} from "./L1BridgehubErrors.sol"; import {FullMerkle} from "../common/libraries/FullMerkle.sol"; -import {MessageHashing} from "../common/libraries/MessageHashing.sol"; -// Chain tree consists of batch commitments as their leaves. We use hash of "new bytes(96)" as the hash of an empty leaf. -bytes32 constant CHAIN_TREE_EMPTY_ENTRY_HASH = bytes32( - 0x46700b4d40ac5c35af2c22dda2787a91eb567b06c924a8fb8ae9a05b20c08c21 -); +import {MessageVerification} from "../common/MessageVerification.sol"; -// The single shared tree consists of the roots of chain trees as its leaves. We use hash of "new bytes(96)" as the hash of an empty leaf. -bytes32 constant SHARED_ROOT_TREE_EMPTY_HASH = bytes32( - 0x46700b4d40ac5c35af2c22dda2787a91eb567b06c924a8fb8ae9a05b20c08c21 -); +import {IGetters} from "../state-transition/chain-interfaces/IGetters.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev /// @dev The MessageRoot contract is responsible for storing the cross message roots of the chains and the aggregated root of all chains. -abstract contract MessageRootBase is IMessageRoot, Initializable { +/// @dev From V30 onwards it is also used for L2->L1 message verification, this allows bypassing the Mailbox of individual chains. +/// This is especially useful for chains settling on Gateway. +abstract contract MessageRootBase is IMessageRoot, Initializable, MessageVerification { using FullMerkle for FullMerkle.FullTree; using DynamicIncrementalMerkle for DynamicIncrementalMerkle.Bytes32PushTree; @@ -36,31 +37,7 @@ abstract contract MessageRootBase is IMessageRoot, Initializable { function L1_CHAIN_ID() public view virtual returns (uint256); - /// @notice Emitted when a new chain is added to the MessageRoot. - /// @param chainId The ID of the chain that is being added to the MessageRoot. - /// @param chainIndex The index of the chain that is being added. Note, that chain where - /// the MessageRoot contract was deployed has chainIndex of 0, and this event is not emitted for it. - event AddedChain(uint256 indexed chainId, uint256 indexed chainIndex); - - /// @notice Emitted when a new chain batch root is appended to the chainTree. - /// @param chainId The ID of the chain whose chain batch root is being added to the chainTree. - /// @param batchNumber The number of the batch to which chain batch root belongs. - /// @param chainBatchRoot The value of chain batch root which is being added. - event AppendedChainBatchRoot(uint256 indexed chainId, uint256 indexed batchNumber, bytes32 chainBatchRoot); - - /// @notice Emitted when a new chainTree root is produced and its corresponding leaf in sharedTree is updated. - /// @param chainId The ID of the chain whose chainTree root is being updated. - /// @param chainRoot The updated Merkle root of the chainTree after appending the latest batch root. - /// @param chainIdLeafHash The Merkle leaf value computed from `chainRoot` and the chain’s ID, used to update the shared tree. - event NewChainRoot(uint256 indexed chainId, bytes32 chainRoot, bytes32 chainIdLeafHash); - - /// @notice Emitted whenever the sharedTree is updated, and the new InteropRoot (root of the sharedTree) is generated. - /// @param chainId The ID of the chain where the sharedTree was updated. - /// @param blockNumber The block number of the block in which the sharedTree was updated. - /// @param logId The ID of the log emitted when a new InteropRoot. In this release always equal to 0. - /// @param sides The "sides" of the interop root. In this release which uses proof-based interop the sides is an array - /// of length one, which only include the interop root itself. More on that in `L2InteropRootStorage` contract. - event NewInteropRoot(uint256 indexed chainId, uint256 indexed blockNumber, uint256 indexed logId, bytes32[] sides); + function _eraGatewayChainId() internal view virtual returns (uint256); /// @notice The number of chains that are registered. uint256 public chainCount; @@ -87,12 +64,41 @@ abstract contract MessageRootBase is IMessageRoot, Initializable { /// @dev Kept here for storage layout compatibility with previous versions. uint256 internal DEPRECATED_l1ChainId; + /// @notice The mapping from chainId to its current executed batch number. + /// @dev We store the current batch number for each chain once it upgrades to v30. This value is moved between settlement layers + /// during migration to ensure consistency. For now, only using a settlement layer from the same CTM is allowed, + /// so the value can be trusted on top of the settlement layer. + mapping(uint256 chainId => uint256 currentChainBatchNumber) public currentChainBatchNumber; + + /// @notice The mapping from chainId to batchNumber to chainBatchRoot. + /// @dev These are the same values as the leaves of the chainTree. + /// @dev We store these values for message verification on L1 and Gateway. + /// @dev We only update the chainTree on GW as of V30. + mapping(uint256 chainId => mapping(uint256 batchNumber => bytes32 chainRoot)) public chainBatchRoots; + + /// @notice The mapping storing the batch number at the moment the chain was updated to V30. + /// Starting from this batch, if a settlement layer has agreed to a proof, it will be held accountable for the content of the message, e.g. + /// if a withdrawal happens, the balance of the settlement layer will be reduced and not the chain. + /// @notice This is also the first batch starting from which we store batch roots on L1. + /// @notice Due to the definition above, this mapping will have the default value (0) for newly added chains, so all their batches are under v30 rules. + /// For chains that existed at the moment of the upgrade, its value will be populated either with V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE until + /// they call this contract to establish the batch when the upgrade has happened. + /// @notice Also, as a consequence of the above, the MessageRoot on a settlement layer will require that all messages after this batch go through the asset tracker + /// to ensure balance consistency. + /// @notice This value should contain the same value for both MessageRoot on L1 and on any settlement layer where the chain settles. This is ensured by the fact + /// that on the settlement layer the chain will provide its totalBatchesExecuted at the moment of upgrade, and only then the value will be moved to L1 and other settlement layers + /// via bridgeMint/bridgeBurn during migration. + /// @dev The attack that could be possible by a completely compromised chain is that it will provide an overly small `v30UpgradeChainBatchNumber` value and then migrate + /// to a settlement layer and then finalize messages that were not actually approved by the settlement layer. However, since before v30 release chains can only migrate within the same CTM, + /// this attack is not considered viable as the chains belong to the same CTM as the settlement layer and so the SL can trust their `getTotalBatchesExecuted` value. + mapping(uint256 chainId => uint256 batchNumber) public v30UpgradeChainBatchNumber; + /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ - uint256[40] private __gap; + uint256[37] private __gap; /// @notice Checks that the message sender is the bridgehub or the chain asset handler. modifier onlyBridgehubOrChainAssetHandler() { @@ -115,6 +121,39 @@ abstract contract MessageRootBase is IMessageRoot, Initializable { _; } + /// On L1, the chain can add it directly. + /// On GW, the asset tracker should add it, + /// except for PreV30 chains, which can add it directly. + modifier addChainBatchRootRestriction(uint256 _chainId) { + if (block.chainid != L1_CHAIN_ID()) { + if (msg.sender == GW_ASSET_TRACKER_ADDR) { + // this case is valid. + } else if (v30UpgradeChainBatchNumber[_chainId] != 0) { + address chain = IBridgehubBase(_bridgehub()).getZKChain(_chainId); + uint32 minor; + // slither-disable-next-line unused-return + (, minor, ) = IGetters(chain).getSemverProtocolVersion(); + /// This might be a security issue if v29 has prover bugs. We should upgrade GW chains to v30 quickly. + require(msg.sender == chain, OnlyChain(msg.sender, chain)); + require(minor < 30, OnlyPreV30Chain(_chainId)); + } else { + revert OnlyAssetTracker(msg.sender, GW_ASSET_TRACKER_ADDR); + } + } else { + if (msg.sender != IBridgehubBase(_bridgehub()).getZKChain(_chainId)) { + revert OnlyChain(msg.sender, IBridgehubBase(_bridgehub()).getZKChain(_chainId)); + } + } + _; + } + + modifier onlyL1() { + if (block.chainid != L1_CHAIN_ID()) { + revert OnlyL1(); + } + _; + } + /// @notice Checks that the Chain ID is not L1 when adding chain batch root. modifier onlyL2() { if (block.chainid == L1_CHAIN_ID()) { @@ -123,19 +162,111 @@ abstract contract MessageRootBase is IMessageRoot, Initializable { _; } + function _initialize() internal { + // slither-disable-next-line unused-return + sharedTree.setup(SHARED_ROOT_TREE_EMPTY_HASH); + _addNewChain(block.chainid, 0); + } + + function _v30InitializeInner(uint256[] memory _allZKChains) internal { + uint256 allZKChainsLength = _allZKChains.length; + for (uint256 i = 0; i < allZKChainsLength; ++i) { + uint256 batchNumberToWrite = V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_GATEWAY; + if (IBridgehubBase(_bridgehub()).settlementLayer(_allZKChains[i]) == L1_CHAIN_ID()) { + /// If we are settling on L1. + batchNumberToWrite = V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_L1; + } + v30UpgradeChainBatchNumber[_allZKChains[i]] = batchNumberToWrite; + } + } + + function saveV30UpgradeChainBatchNumber(uint256 _chainId) external onlyChain(_chainId) { + require(block.chainid == IBridgehubBase(_bridgehub()).settlementLayer(_chainId), OnlyOnSettlementLayer()); + uint256 totalBatchesExecuted = IGetters(msg.sender).getTotalBatchesExecuted(); + require(totalBatchesExecuted > 0, TotalBatchesExecutedZero()); + require( + totalBatchesExecuted != V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_GATEWAY && + totalBatchesExecuted != V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_L1, + TotalBatchesExecutedLessThanV30UpgradeChainBatchNumber() + ); + require( + v30UpgradeChainBatchNumber[_chainId] == V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_GATEWAY || + v30UpgradeChainBatchNumber[_chainId] == V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_L1, + V30UpgradeChainBatchNumberAlreadySet() + ); + require(currentChainBatchNumber[_chainId] == 0, CurrentBatchNumberAlreadySet()); + + currentChainBatchNumber[_chainId] = totalBatchesExecuted; + v30UpgradeChainBatchNumber[_chainId] = totalBatchesExecuted + 1; + } + /// @notice Adds a single chain to the message root. /// @param _chainId The ID of the chain that is being added to the message root. - function addNewChain(uint256 _chainId) external onlyBridgehubOrChainAssetHandler { + function addNewChain(uint256 _chainId, uint256 _startingBatchNumber) external onlyBridgehubOrChainAssetHandler { if (chainRegistered(_chainId)) { revert ChainExists(); } - _addNewChain(_chainId); + _addNewChain(_chainId, _startingBatchNumber); + } + + /// @notice we set the chainBatchRoot to be nonempty for when a chain migrates. + function setMigratingChainBatchRoot( + uint256 _chainId, + uint256 _batchNumber, + uint256 _v30UpgradeChainBatchNumber + ) external onlyBridgehubOrChainAssetHandler { + require( + chainBatchRoots[_chainId][_batchNumber] == bytes32(0), + ChainBatchRootAlreadyExists(_chainId, _batchNumber) + ); + currentChainBatchNumber[_chainId] = _batchNumber; + v30UpgradeChainBatchNumber[_chainId] = _v30UpgradeChainBatchNumber; } function chainRegistered(uint256 _chainId) public view returns (bool) { return (_chainId == block.chainid || chainIndex[_chainId] != 0); } + /// @notice Adds a new chainBatchRoot to the chainTree. + /// @param _chainId The ID of the chain whose chainBatchRoot is being added to the chainTree. + /// @param _batchNumber The number of the batch to which _chainBatchRoot belongs. + /// @param _chainBatchRoot The value of chainBatchRoot which is being added. + function addChainBatchRoot( + uint256 _chainId, + uint256 _batchNumber, + bytes32 _chainBatchRoot + ) public virtual addChainBatchRootRestriction(_chainId) { + // Make sure that chain is registered. + if (!chainRegistered(_chainId)) { + revert MessageRootNotRegistered(); + } + require(_chainBatchRoot != bytes32(0), ChainBatchRootZero()); + require( + chainBatchRoots[_chainId][_batchNumber] == bytes32(0), + ChainBatchRootAlreadyExists(_chainId, _batchNumber) + ); + require( + _batchNumber == currentChainBatchNumber[_chainId] + 1, + NonConsecutiveBatchNumber(_chainId, _batchNumber) + ); + + chainBatchRoots[_chainId][_batchNumber] = _chainBatchRoot; + ++currentChainBatchNumber[_chainId]; + if (block.chainid == L1_CHAIN_ID()) { + /// On L1 we only store the chainBatchRoot, but don't update the chainTree or sharedTree. + return; + } + } + + /// @notice emit a new message root when committing a new batch + function _emitRoot(bytes32 _root) internal { + // What happens here is we query for the current sharedTreeRoot and emit the event stating that new InteropRoot is "created". + // The reason for the usage of "bytes32[] memory _sides" to store the InteropRoot is explained in L2InteropRootStorage contract. + bytes32[] memory _sides = new bytes32[](1); + _sides[0] = _root; + emit NewInteropRoot(block.chainid, block.number, 0, _sides); + } + /// @notice Gets the aggregated root of all chains. function getAggregatedRoot() external view returns (bytes32) { if (chainCount == 0) { @@ -162,21 +293,13 @@ abstract contract MessageRootBase is IMessageRoot, Initializable { newLeaves[i] = MessageHashing.chainIdLeafHash(chainTree[chainId].root(), chainId); } bytes32 newRoot = sharedTree.updateAllLeaves(newLeaves); - bytes32[] memory _sides = new bytes32[](1); - _sides[0] = newRoot; - emit NewInteropRoot(block.chainid, block.number, 0, _sides); + _emitRoot(newRoot); historicalRoot[block.number] = newRoot; } - function _initialize() internal { - // slither-disable-next-line unused-return - sharedTree.setup(SHARED_ROOT_TREE_EMPTY_HASH); - _addNewChain(block.chainid); - } - /// @dev Adds a single chain to the message root. /// @param _chainId The ID of the chain that is being added to the message root. - function _addNewChain(uint256 _chainId) internal { + function _addNewChain(uint256 _chainId, uint256 _startingBatchNumber) internal { uint256 cachedChainCount = chainCount; // Since only the bridgehub can add new chains to the message root, it is expected that @@ -184,6 +307,7 @@ abstract contract MessageRootBase is IMessageRoot, Initializable { ++chainCount; chainIndex[_chainId] = cachedChainCount; chainIndexToId[cachedChainCount] = _chainId; + currentChainBatchNumber[_chainId] = _startingBatchNumber; // slither-disable-next-line unused-return bytes32 initialHash = chainTree[_chainId].setup(CHAIN_TREE_EMPTY_ENTRY_HASH); @@ -193,4 +317,90 @@ abstract contract MessageRootBase is IMessageRoot, Initializable { emit AddedChain(_chainId, cachedChainCount); } + + ////////////////////////////// + //// IMessageVerification //// + ////////////////////////////// + + function _proveL2LeafInclusionRecursive( + uint256 _chainId, + uint256 _batchNumber, + uint256 _leafProofMask, + bytes32 _leaf, + bytes32[] calldata _proof, + uint256 _depth + ) internal view override returns (bool) { + ProofData memory proofData = MessageHashing._getProofData({ + _chainId: _chainId, + _batchNumber: _batchNumber, + _leafProofMask: _leafProofMask, + _leaf: _leaf, + _proof: _proof + }); + if (proofData.finalProofNode) { + // For proof based interop this is the SL InteropRoot at block number _batchNumber + bytes32 correctBatchRoot = _getChainBatchRoot(_chainId, _batchNumber); + return correctBatchRoot == proofData.batchSettlementRoot && correctBatchRoot != bytes32(0); + } + if (_depth == 1) { + revert DepthMoreThanOneForRecursiveMerkleProof(); + } + + // Assuming that `settlementLayerChainId` is an honest chain, the `chainIdLeaf` should belong + // to a chain's message root only if the chain has indeed executed its batch on top of it. + // + // We trust all chains whitelisted by the Bridgehub governance. + require( + IBridgehubBase(_bridgehub()).whitelistedSettlementLayers(proofData.settlementLayerChainId), + NotWhitelistedSettlementLayer(proofData.settlementLayerChainId) + ); + + return + this.proveL2LeafInclusionSharedRecursive({ + _chainId: proofData.settlementLayerChainId, + _blockOrBatchNumber: proofData.settlementLayerBatchNumber, // SL block number + _leafProofMask: proofData.settlementLayerBatchRootMask, + _leaf: proofData.chainIdLeaf, + _proof: MessageHashing.extractSliceUntilEnd(_proof, proofData.ptr), + _depth: _depth + 1 + }); + } + + /// @notice Internal to get the historical batch root for chains before the v30 upgrade. + function _getChainBatchRoot(uint256 _chainId, uint256 _batchNumber) internal view returns (bytes32) { + /// In current server the zeroth batch does not have L2->L1 logs. + require(_batchNumber > 0, BatchZeroNotAllowed()); + bytes32 savedChainBatchRoot = chainBatchRoots[_chainId][_batchNumber]; + if (savedChainBatchRoot != bytes32(0)) { + return savedChainBatchRoot; + } + return IGetters(IBridgehubBase(_bridgehub()).getZKChain(_chainId)).l2LogsRootHash(_batchNumber); + } + + /// @notice Extracts and returns proof data for settlement layer verification. + /// @dev Wrapper function around MessageHashing._getProofData for public access. + /// @dev The caller should check that the proof has recursion at most depth 1, i.e. only a single intermediate Gateway between the chain and L1. + /// @dev This check is performed when the MessageRoot verifies the proof, so often it can be skipped. + /// @param _chainId The chain ID where the proof was generated. + /// @param _batchNumber The batch number containing the proof. + /// @param _leafProofMask The leaf proof mask for merkle verification. + /// @param _leaf The leaf hash to verify. + /// @param _proof The merkle proof array. + /// @return The extracted proof data including settlement layer information. + function getProofData( + uint256 _chainId, + uint256 _batchNumber, + uint256 _leafProofMask, + bytes32 _leaf, + bytes32[] calldata _proof + ) public pure returns (ProofData memory) { + return + MessageHashing._getProofData({ + _chainId: _chainId, + _batchNumber: _batchNumber, + _leafProofMask: _leafProofMask, + _leaf: _leaf, + _proof: _proof + }); + } } diff --git a/l1-contracts/contracts/common/Config.sol b/l1-contracts/contracts/common/Config.sol index 6ce6a2cc40..4995f8dff9 100644 --- a/l1-contracts/contracts/common/Config.sol +++ b/l1-contracts/contracts/common/Config.sol @@ -227,3 +227,27 @@ enum L2DACommitmentScheme { /// @dev The L2 data availability commitment scheme that permanent rollups are expected to use. L2DACommitmentScheme constant ROLLUP_L2_DA_COMMITMENT_SCHEME = L2DACommitmentScheme.BLOBS_AND_PUBDATA_KECCAK256; + +uint256 constant L2_TO_L1_LOGS_MERKLE_TREE_LEAVES = 16_384; + +uint256 constant L2_TO_L1_LOGS_MERKLE_TREE_DEPTH = 14 + 1; + +/// @dev The start of the pause deposits time window. We pause when migrating to/from gateway. +uint256 constant PAUSE_DEPOSITS_TIME_WINDOW_START_MAINNET = 3 days + 12 hours; + +/// @dev The start of the chain migration window, it equals the PAUSE_DEPOSITS_TIME_WINDOW_START. +uint256 constant CHAIN_MIGRATION_TIME_WINDOW_START_MAINNET = 3 days + 12 hours; + +/// @dev The end of the chain migration window. +uint256 constant CHAIN_MIGRATION_TIME_WINDOW_END_MAINNET = 4 days + 12 hours; + +/// @dev The end of the pause deposits time window. We pause when migrating to/from gateway. +uint256 constant PAUSE_DEPOSITS_TIME_WINDOW_END_MAINNET = 7 days; + +uint256 constant PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET = 1; + +uint256 constant CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET = 1; + +uint256 constant CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET = 1 days; + +uint256 constant PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET = 2 days; diff --git a/l1-contracts/contracts/common/L1ContractErrors.sol b/l1-contracts/contracts/common/L1ContractErrors.sol index 48d95ce225..3c6e2a7659 100644 --- a/l1-contracts/contracts/common/L1ContractErrors.sol +++ b/l1-contracts/contracts/common/L1ContractErrors.sol @@ -31,6 +31,8 @@ error AssetIdMismatch(bytes32 expected, bytes32 supplied); error AssetIdNotSupported(bytes32 assetId); // 0x11832de8 error AssetRouterAllowanceNotZero(); +// 0x9b821ed7 +error BadTransferDataLength(); // 0x6ef9a972 error BaseTokenGasPriceDenominatorNotSet(); // 0x55ad3fd3 @@ -87,8 +89,8 @@ error DenominatorIsZero(); error DeployFailed(); // 0x138ee1a3 error DeployingBridgedTokenForNativeToken(); -// 0xc7c9660f -error DepositDoesNotExist(); +// 0x42bce528 +error DepositDoesNotExist(bytes32, bytes32); // 0xad2fa98e error DepositExists(); // 0x0e7ee319 @@ -111,6 +113,8 @@ error EmptyPrecommitData(uint256 batchNumber); error EmptyProofLength(); // 0x627e0872 error ETHDepositNotSupported(); +// 0xf4072616 +error ExecuteMessageFailed(); // 0xac4a3f98 error FacetExists(bytes4 selector, address); // 0xc91cf3b1 @@ -140,8 +144,6 @@ error IncorrectBatchChainId(uint256, uint256); error IncorrectBridgeHubAddress(address bridgehub); // 0x1929b7de error IncorrectTokenAddressFromNTV(bytes32 assetId, address tokenAddress); -// 0x826fb11e -error InsufficientChainBalance(); // 0x9bf8b9aa error InvalidBatchNumber(uint256 provided, uint256 expected); // 0xcbd9d2e0 @@ -152,10 +154,14 @@ error InvalidChainId(); error InvalidDAForPermanentRollup(); // 0x4fbe5dba error InvalidDelay(); +// 0x075aaa80 +error InvalidInteropCalldata(bytes4); // 0x3f98a77e error InvalidL2DACommitmentScheme(uint8); // 0xc1780bd6 error InvalidLogSender(address sender, uint256 logKey); +// 0x6eca2e4b +error InvalidMessage(); // 0xa1ec1876 error InvalidMessageRoot(bytes32 expectedMessageRoot, bytes32 providedMessageRoot); // 0xd08a97e6 @@ -256,10 +262,18 @@ error NonZeroBlobToVerifyZKsyncOS(uint256 index, bytes32 blobLinearHash, bytes32 error NotAllowed(address addr); // 0x64846fe4 error NotARestriction(address addr); +// 0xf306a770 +error NotAssetRouter(address _sender, address _assetRouter); // 0xb49df1f2 error NotAZKChain(address addr); +// 0x5e67e793 +error NotCurrentSettlementLayer(); // 0xdd7e3621 error NotInitializedReentrancyGuard(); +// 0xecb34449 +error NotL1(uint256 l1ChainId, uint256 blockChainId); +// 0xc5441a63 +error NotL2ToL2(uint256 sourceChainId, uint256 destinationChainId); // 0xdf17e316 error NotWhitelisted(address); // 0xf3ed9dfa @@ -274,6 +288,8 @@ error OperationMustBePending(); error OperationMustBeReady(); // 0xb926450e error OriginChainIdNotFound(); +// 0x97da9c1c +error PayloadTooShort(); // 0x688c63e5 error PrecommitmentMismatch(uint256 batchNumber, bytes32 expected, bytes32 found); // 0x9b48e060 @@ -290,6 +306,8 @@ error ProtocolIdNotGreater(); error PubdataGreaterThanLimit(uint256 limit, uint256 length); // 0x63c36549 error QueueIsEmpty(); +// 0x0a6c1a5c +error ReconstructionMismatch(bytes32, bytes32); // 0xab143c06 error Reentrancy(); // 0x667d17de diff --git a/l1-contracts/contracts/state-transition/chain-deps/facets/MessageVerification.sol b/l1-contracts/contracts/common/MessageVerification.sol similarity index 52% rename from l1-contracts/contracts/state-transition/chain-deps/facets/MessageVerification.sol rename to l1-contracts/contracts/common/MessageVerification.sol index 078cd4ea4e..ff196a48b3 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/facets/MessageVerification.sol +++ b/l1-contracts/contracts/common/MessageVerification.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.24; -import {L2Log, L2Message} from "../../../common/Messaging.sol"; -import {IMessageVerification} from "../../chain-interfaces/IMessageVerification.sol"; -import {L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from "../../../common/l2-helpers/L2ContractAddresses.sol"; +import {L2Log, L2Message, TxStatus} from "./Messaging.sol"; +import {FinalizeL1DepositParams, IMessageVerification} from "./interfaces/IMessageVerification.sol"; +import {MessageHashing} from "./libraries/MessageHashing.sol"; /// @title The interface of the ZKsync MessageVerification contract that can be used to prove L2 message inclusion. /// @dev This contract is abstract and is inherited by the Mailbox and L2MessageVerification contracts. @@ -25,7 +25,7 @@ abstract contract MessageVerification is IMessageVerification { _chainId: _chainId, _blockOrBatchNumber: _blockOrBatchNumber, _index: _index, - _log: _l2MessageToLog(_message), + _log: MessageHashing._l2MessageToLog(_message), _proof: _proof }); } @@ -48,12 +48,50 @@ abstract contract MessageVerification is IMessageVerification { }); } + function proveL2LeafInclusionSharedRecursive( + uint256 _chainId, + uint256 _blockOrBatchNumber, + uint256 _leafProofMask, + bytes32 _leaf, + bytes32[] calldata _proof, + uint256 _depth + ) public view virtual returns (bool) { + return + _proveL2LeafInclusionRecursive({ + _chainId: _chainId, + _blockOrBatchNumber: _blockOrBatchNumber, + _leafProofMask: _leafProofMask, + _leaf: _leaf, + _proof: _proof, + _depth: _depth + }); + } + function _proveL2LeafInclusion( uint256 _chainId, uint256 _blockOrBatchNumber, uint256 _leafProofMask, bytes32 _leaf, bytes32[] calldata _proof + ) internal view virtual returns (bool) { + return + _proveL2LeafInclusionRecursive({ + _chainId: _chainId, + _blockOrBatchNumber: _blockOrBatchNumber, + _leafProofMask: _leafProofMask, + _leaf: _leaf, + _proof: _proof, + _depth: 0 + }); + } + + function _proveL2LeafInclusionRecursive( + uint256 _chainId, + uint256 _blockOrBatchNumber, + uint256 _leafProofMask, + bytes32 _leaf, + bytes32[] calldata _proof, + uint256 _depth ) internal view virtual returns (bool); /// @dev Prove that a specific L2 log was sent in a specific L2 batch number @@ -64,10 +102,7 @@ abstract contract MessageVerification is IMessageVerification { L2Log memory _log, bytes32[] calldata _proof ) internal view returns (bool) { - bytes32 hashedLog = keccak256( - // solhint-disable-next-line func-named-parameters - abi.encodePacked(_log.l2ShardId, _log.isService, _log.txNumberInBatch, _log.sender, _log.key, _log.value) - ); + bytes32 hashedLog = MessageHashing.getLeafHashFromLog(_log); // It is ok to not check length of `_proof` array, as length // of leaf preimage (which is `L2_TO_L1_LOG_SERIALIZE_SIZE`) is not @@ -85,19 +120,6 @@ abstract contract MessageVerification is IMessageVerification { }); } - /// @dev Convert arbitrary-length message to the raw L2 log - function _l2MessageToLog(L2Message calldata _message) internal pure returns (L2Log memory) { - return - L2Log({ - l2ShardId: 0, - isService: true, - txNumberInBatch: _message.txNumberInBatch, - sender: L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, - key: bytes32(uint256(uint160(_message.sender))), - value: keccak256(_message.data) - }); - } - /// @inheritdoc IMessageVerification function proveL2LogInclusionShared( uint256 _chainId, @@ -115,4 +137,43 @@ abstract contract MessageVerification is IMessageVerification { _proof: _proof }); } + + /// @inheritdoc IMessageVerification + function proveL1ToL2TransactionStatusShared( + uint256 _chainId, + bytes32 _l2TxHash, + uint256 _l2BatchNumber, + uint256 _l2MessageIndex, + uint16 _l2TxNumberInBatch, + bytes32[] calldata _merkleProof, + TxStatus _status + ) public view returns (bool) { + L2Log memory l2Log = MessageHashing.getL2LogFromL1ToL2Transaction(_l2TxNumberInBatch, _l2TxHash, _status); + return + _proveL2LogInclusion({ + _chainId: _chainId, + _blockOrBatchNumber: _l2BatchNumber, + _index: _l2MessageIndex, + _log: l2Log, + _proof: _merkleProof + }); + } + + function proveL1DepositParamsInclusion( + FinalizeL1DepositParams calldata _finalizeWithdrawalParams + ) public view returns (bool success) { + L2Message memory l2ToL1Message = L2Message({ + txNumberInBatch: _finalizeWithdrawalParams.l2TxNumberInBatch, + sender: _finalizeWithdrawalParams.l2Sender, + data: _finalizeWithdrawalParams.message + }); + + success = this.proveL2MessageInclusionShared({ + _chainId: _finalizeWithdrawalParams.chainId, + _blockOrBatchNumber: _finalizeWithdrawalParams.l2BatchNumber, + _index: _finalizeWithdrawalParams.l2MessageIndex, + _message: l2ToL1Message, + _proof: _finalizeWithdrawalParams.merkleProof + }); + } } diff --git a/l1-contracts/contracts/common/Messaging.sol b/l1-contracts/contracts/common/Messaging.sol index 7ad4ceabec..45394c52d0 100644 --- a/l1-contracts/contracts/common/Messaging.sol +++ b/l1-contracts/contracts/common/Messaging.sol @@ -2,6 +2,10 @@ // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.21; +bytes1 constant BUNDLE_IDENTIFIER = 0x01; +bytes1 constant INTEROP_BUNDLE_VERSION = 0x01; +bytes1 constant INTEROP_CALL_VERSION = 0x01; + /// @dev The enum that represents the transaction execution status /// @param Failure The transaction execution failed /// @param Success The transaction execution succeeded @@ -40,8 +44,7 @@ struct L2Message { bytes data; } -/// @dev Internal structure that contains the parameters for the writePriorityOp -/// internal function. +/// @dev Internal structure that contains the parameters for the writePriorityOp internal function. /// @param txId The id of the priority transaction. /// @param l2GasPrice The gas price for the l2 priority operation. /// @param expirationTimestamp The timestamp by which the priority operation must be processed by the operator. @@ -113,8 +116,8 @@ struct L2CanonicalTransaction { } /// @param sender The sender's address. -/// @param contractAddressL2 The address of the contract on L2 to call. -/// @param valueToMint The amount of base token that should be minted on L2 as the result of this transaction. +/// @param contractL2 The address of the contract on L2 to call. +/// @param mintValue The amount of base token that should be minted on L2 as the result of this transaction. /// @param l2Value The msg.value of the L2 transaction. /// @param l2Calldata The calldata for the L2 transaction. /// @param l2GasLimit The limit of the L2 gas for the L2 transaction @@ -148,3 +151,232 @@ struct InteropRoot { // Second overloading: if the length is 1, we are importing a chainBatchRoot/messageRoot instead of sides. bytes32[] sides; } + +/// @param chainId The chain ID of the transaction to check. +/// @param l2BatchNumber The L2 batch number where the withdrawal was processed. +/// @param l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message. +/// @param l2Sender The address of the message sender on L2 (base token system contract address or asset handler) +/// @param l2TxNumberInBatch The L2 transaction number in the batch, in which the log was sent. +/// @param message The L2 withdraw data, stored in an L2 -> L1 message. +/// @param merkleProof The Merkle proof of the inclusion L2 -> L1 message about withdrawal initialization. +struct FinalizeL1DepositParams { + uint256 chainId; + uint256 l2BatchNumber; + uint256 l2MessageIndex; + address l2Sender; + uint16 l2TxNumberInBatch; + bytes message; + bytes32[] merkleProof; +} + +/// @dev Struct used to define parameters for adding a single call in an interop bundle. +/// @param to ERC-7930 address to call on the destination chain. Note, that it will have empty ChainReference. +/// This is due to the fact that chain ID is always provided on a bundle level, as a destination chain ID. +/// And in case of sendMessage the chain ID is also provided via the sendMessage interface, so it's redundant to store it here. +/// @param data Calldata payload to send to `to` address on the destination chain. +/// @param callAttributes EIP-7786 Attributes. +struct InteropCallStarter { + bytes to; + bytes data; + bytes[] callAttributes; +} + +/// @dev Internal representation of an InteropCallStarter after parsing its parameters. +/// @param to Address to call on the destination chain. +/// @param data Calldata payload to send. +/// @param callAttributes EIP-7786 Attributes. +struct InteropCallStarterInternal { + address to; + bytes data; + CallAttributes callAttributes; +} + +/// @param interopCallValue Base token value on destination chain to send for interop call. +/// @param indirectCall An indirect call first calls a contract as specified by the call starter which returns an actual call starter that will be used to form an interop call. In particular, this is used for interop token transfers. In contrast, a direct call uses the call starter to form an interop call. +/// @param indirectCallMessageValue Base token value on sending chain to send for indirect call. +struct CallAttributes { + uint256 interopCallValue; + bool indirectCall; + uint256 indirectCallMessageValue; +} + +/// @param executionAddress ERC-7930 Address allowed to execute the bundle on the destination chain. If the byte array is empty then execution is permissionless. +/// @param unbundlerAddress ERC-7930 Address allowed to unbundle the bundle on the destination chain. Note, that it is required to be nonempty, unlike `executionAddress`. +struct BundleAttributes { + bytes executionAddress; + bytes unbundlerAddress; +} + +/// @dev A single call. +/// @param version Version of the InteropCall. +/// @param shadowAccount If true, execute via a shadow account, otherwise normal. In current release always false, as it's not yet implemented. +/// Shadow accounts help with interop when `to` doesn't support 7786. In this case, a "shadow" account could be deployed, allowing +/// the user to hold funds securely on the destination chain, and interact with anything on destination chain using this shadow account. +/// @param to Destination contract address on the target chain. +/// @param from Original sender address that initiated the call. +/// @param value Amount of base token to send with the call. +/// @param data Calldata payload for the call. +struct InteropCall { + bytes1 version; + bool shadowAccount; + address to; + address from; + uint256 value; + bytes data; +} + +/// @dev Execution status of an individual call within a bundle. +/// @param Unprocessed Call not yet processed. +/// @param Executed Call was successfully executed. +/// @param Cancelled Call was cancelled during unbundling. +enum CallStatus { + Unprocessed, + Executed, + Cancelled +} + +/// @dev A set of `InteropCall`s to send to another chain. +/// @param version Version of the InteropBundle. +/// @param destinationChainId ChainId of the target chain. +/// @param interopBundleSalt Salt of the interopBundle. It's required to ensure that all bundles have distinct hashes. +/// It's equal to the keccak256(abi.encodePacked(senderOfTheBundle, NumberOfBundleSentByTheSender)) +/// @param calls Array of InteropCall structs to execute. +/// @param bundleAttributes Bundle execution and unbundling attributes. +struct InteropBundle { + bytes1 version; + uint256 sourceChainId; + uint256 destinationChainId; + bytes32 interopBundleSalt; + InteropCall[] calls; + BundleAttributes bundleAttributes; +} + +/// @dev Processing status of an `InteropBundle`. +/// @param Unreceived Bundle is not processed in any way yet. +/// @param Verified Bundle inclusion proof accepted, but not processed. +/// @param FullyExecuted All calls in the bundle have been executed atomically via executeBundle. +/// @param Unbundled Bundle was processed via unbundling flow. +enum BundleStatus { + Unreceived, + Verified, + FullyExecuted, + Unbundled +} + +/// @dev Inclusion proof for a cross-chain message payload (bundle) coming from L2→L1. +/// @param chainId Source chain identifier. +/// @param l1BatchNumber Batch number on L1 where the message root was committed. +/// @param l2MessageIndex Position in the L2 logs Merkle tree of this message. +/// @param message The raw L2 message payload (including `BUNDLE_IDENTIFIER` prefix). +/// @param proof Merkle‐proof for verifying the message inclusion. +struct MessageInclusionProof { + uint256 chainId; + uint256 l1BatchNumber; + uint256 l2MessageIndex; + L2Message message; + bytes32[] proof; +} + +/// @dev Inclusion proof for a single L2 log entry passed to L1. +/// @param chainId Source chain identifier. +/// @param l1BatchNumber Batch number on L1 where the message root was committed. +/// @param l2LogIndex Position in the L2 logs Merkle tree of this log. +/// @param log The decoded `L2Log` entry. +/// @param proof Merkle‐proof for verifying the log inclusion. +struct LogInclusionProof { + uint256 chainId; + uint256 l1BatchNumber; + uint256 l2LogIndex; + L2Log log; + bytes32[] proof; +} + +/// @dev Generic inclusion proof for an arbitrary 32‐byte leaf in the L2→L1 Merkle tree. +/// @param chainId Source chain identifier. +/// @param l1BatchNumber Batch number on L1 where the message root was committed. +/// @param l2LeafProofMask Bitmask indicating this leaf’s position, given as integer. +/// @param leaf The 32-byte leaf whose inclusion is being proven. +/// @param proof Merkle‐proof for verifying the leaf inclusion. +struct LeafInclusionProof { + uint256 chainId; + uint256 l1BatchNumber; + uint256 l2LeafProofMask; + bytes32 leaf; + bytes32[] proof; +} + +struct ProofData { + uint256 settlementLayerChainId; + uint256 settlementLayerBatchNumber; + uint256 settlementLayerBatchRootMask; + uint256 batchLeafProofLen; + bytes32 batchSettlementRoot; + bytes32 chainIdLeaf; + uint256 ptr; + bool finalProofNode; +} + +struct TokenBalanceMigrationData { + bytes1 version; + bool isL1ToGateway; + address originToken; + uint256 chainId; + bytes32 assetId; + uint256 tokenOriginChainId; + uint256 amount; + uint256 chainMigrationNumber; + uint256 assetMigrationNumber; +} + +struct ConfirmBalanceMigrationData { + bytes1 version; + bool isL1ToGateway; + uint256 chainId; + bytes32 assetId; + uint256 migrationNumber; + uint256 amount; +} + +struct BalanceChange { + bytes1 version; + address originToken; + bytes32 baseTokenAssetId; + uint256 baseTokenAmount; + bytes32 assetId; + uint256 amount; + uint256 tokenOriginChainId; +} + +struct AssetBalanceChange { + bytes32 assetId; + uint256 amount; +} + +struct InteropBalanceChange { + bytes1 version; + uint256 baseTokenAmount; + AssetBalanceChange[] assetBalanceChanges; +} + +/// @param _chainId The ZK chain id to which deposit was initiated. +/// @param _depositSender The address of the entity that initiated the deposit. +/// @param _assetId The unique identifier of the deposited L1 token. +/// @param _assetData The encoded data, which is used by the asset handler to determine L2 recipient and amount. Might include extra information. +/// @param _l2TxHash The L2 transaction hash. +/// @param _l2BatchNumber The L2 batch number where the deposit finalization was processed. +/// @param _l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message. +/// @param _l2TxNumberInBatch The L2 transaction number in a batch, in which the log was sent. +/// @param _merkleProof The Merkle proof of the processing L1 -> L2 transaction with deposit finalization. +/// @param _txStatus The status of the transaction. +struct ConfirmTransferResultData { + uint256 _chainId; + address _depositSender; + uint16 _l2TxNumberInBatch; + TxStatus _txStatus; + bytes32 _assetId; + bytes _assetData; + bytes32 _l2TxHash; + uint256 _l2BatchNumber; + uint256 _l2MessageIndex; + bytes32[] _merkleProof; +} diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IMessageVerification.sol b/l1-contracts/contracts/common/interfaces/IMessageVerification.sol similarity index 66% rename from l1-contracts/contracts/state-transition/chain-interfaces/IMessageVerification.sol rename to l1-contracts/contracts/common/interfaces/IMessageVerification.sol index cf62b0a8ec..a340216e3b 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IMessageVerification.sol +++ b/l1-contracts/contracts/common/interfaces/IMessageVerification.sol @@ -2,7 +2,7 @@ // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.21; -import {L2Log, L2Message} from "../../common/Messaging.sol"; +import {FinalizeL1DepositParams, L2Log, L2Message, TxStatus} from "../Messaging.sol"; /// @title The interface of the ZKsync MessageVerification contract that can be used to prove L2 message inclusion. /// @author Matter Labs @@ -55,4 +55,28 @@ interface IMessageVerification { bytes32 _leaf, bytes32[] calldata _proof ) external view returns (bool); + + /// @notice Prove that the L1 -> L2 transaction was processed with the specified status. + /// @param _l2TxHash The L2 canonical transaction hash. + /// @param _l2BatchNumber The L2 batch number where the transaction was processed. + /// @param _l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message. + /// @param _l2TxNumberInBatch The L2 transaction number in the batch, in which the log was sent. + /// @param _merkleProof The Merkle proof of the processing L1 -> L2 transaction. + /// @param _status The execution status of the L1 -> L2 transaction (true - success & 0 - fail). + /// @return Whether the proof is correct and the transaction was actually executed with provided status. + /// NOTE: It may return `false` for incorrect proof, but it doesn't mean that the L1 -> L2 transaction has an opposite status! + function proveL1ToL2TransactionStatusShared( + uint256 _chainId, + bytes32 _l2TxHash, + uint256 _l2BatchNumber, + uint256 _l2MessageIndex, + uint16 _l2TxNumberInBatch, + bytes32[] calldata _merkleProof, + TxStatus _status + ) external view returns (bool); + + /// @notice Prove that the L2 -> L1 transaction was processed with the specified status. + function proveL1DepositParamsInclusion( + FinalizeL1DepositParams calldata _finalizeWithdrawalParams + ) external view returns (bool success); } diff --git a/l1-contracts/contracts/common/interfaces/ISystemContext.sol b/l1-contracts/contracts/common/interfaces/ISystemContext.sol index ff083fd0b5..191cfcb46b 100644 --- a/l1-contracts/contracts/common/interfaces/ISystemContext.sol +++ b/l1-contracts/contracts/common/interfaces/ISystemContext.sol @@ -41,6 +41,8 @@ interface ISystemContext { function baseFee() external view returns (uint256); + function currentSettlementLayerChainId() external view returns (uint256); + function txNumberInBlock() external view returns (uint16); function getBlockHashEVM(uint256 _block) external view returns (bytes32); diff --git a/l1-contracts/contracts/common/l2-helpers/IBaseToken.sol b/l1-contracts/contracts/common/l2-helpers/IBaseToken.sol new file mode 100644 index 0000000000..9b8da8d6a3 --- /dev/null +++ b/l1-contracts/contracts/common/l2-helpers/IBaseToken.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.20; + +interface IBaseToken { + function balanceOf(uint256) external view returns (uint256); + + function transferFromTo(address _from, address _to, uint256 _amount) external; + + function totalSupply() external view returns (uint256); + + function name() external pure returns (string memory); + + function symbol() external pure returns (string memory); + + function decimals() external pure returns (uint8); + + function mint(address _account, uint256 _amount) external; + + function withdraw(address _l1Receiver) external payable; + + function withdrawWithMessage(address _l1Receiver, bytes calldata _additionalData) external payable; + + function burnMsgValue() external payable; + + event Mint(address indexed account, uint256 amount); + + event Transfer(address indexed from, address indexed to, uint256 value); + + event Withdrawal(address indexed _l2Sender, address indexed _l1Receiver, uint256 _amount); + + event WithdrawalWithMessage( + address indexed _l2Sender, + address indexed _l1Receiver, + uint256 _amount, + bytes _additionalData + ); +} diff --git a/l1-contracts/contracts/common/l2-helpers/L2ContractAddresses.sol b/l1-contracts/contracts/common/l2-helpers/L2ContractAddresses.sol index 3ce1bb29c0..730ba73259 100644 --- a/l1-contracts/contracts/common/l2-helpers/L2ContractAddresses.sol +++ b/l1-contracts/contracts/common/l2-helpers/L2ContractAddresses.sol @@ -4,13 +4,27 @@ pragma solidity ^0.8.21; import {IL2ToL1Messenger} from "./IL2ToL1Messenger.sol"; import {IL2InteropRootStorage} from "../interfaces/IL2InteropRootStorage.sol"; -import {IMessageVerification} from "../../state-transition/chain-interfaces/IMessageVerification.sol"; +import {IMessageVerification} from "../interfaces/IMessageVerification.sol"; +import {IBaseToken} from "./IBaseToken.sol"; +import {IL2ContractDeployer} from "../interfaces/IL2ContractDeployer.sol"; +import {IL2NativeTokenVault} from "../../bridge/ntv/IL2NativeTokenVault.sol"; +import {IBridgehubBase} from "../../bridgehub/IBridgehubBase.sol"; +import {IChainAssetHandler} from "../../bridgehub/IChainAssetHandler.sol"; +import {IInteropCenter} from "../../interop/IInteropCenter.sol"; +import {IL2AssetRouter} from "../../bridge/asset-router/IL2AssetRouter.sol"; +import {IL2AssetTracker} from "../../bridge/asset-tracker/IL2AssetTracker.sol"; +import {IGWAssetTracker} from "../../bridge/asset-tracker/IGWAssetTracker.sol"; +import {ISystemContext} from "../interfaces/ISystemContext.sol"; +import {IMessageRoot} from "../../bridgehub/IMessageRoot.sol"; /// @dev the offset for the system contracts uint160 constant SYSTEM_CONTRACTS_OFFSET = 0x8000; // 2^15 /// @dev The offset from which the built-in, but user space contracts are located. -uint160 constant USER_CONTRACTS_OFFSET = 0x10000; // 2^16 +uint160 constant BUILT_IN_CONTRACTS_OFFSET = 0x10000; // 2^16 + +/// @dev The maximum address of the built-in contracts. +uint160 constant MAX_BUILT_IN_CONTRACT_ADDR = BUILT_IN_CONTRACTS_OFFSET + 0x1ffff; /// @dev The formal address of the initial program of the system: the bootloader address constant L2_BOOTLOADER_ADDRESS = address(SYSTEM_CONTRACTS_OFFSET + 0x01); @@ -21,6 +35,8 @@ address constant L2_KNOWN_CODE_STORAGE_SYSTEM_CONTRACT_ADDR = address(SYSTEM_CON /// @dev The address of the L2 deployer system contract. address constant L2_DEPLOYER_SYSTEM_CONTRACT_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x06); +IL2ContractDeployer constant L2_CONTRACT_DEPLOYER = IL2ContractDeployer(L2_DEPLOYER_SYSTEM_CONTRACT_ADDR); + /// @dev The special reserved L2 address. It is located in the system contracts space but doesn't have deployed /// bytecode. /// @dev The L2 deployer system contract allows changing bytecodes on any address if the `msg.sender` is this address. @@ -37,65 +53,91 @@ IL2ToL1Messenger constant L2_TO_L1_MESSENGER_SYSTEM_CONTRACT = IL2ToL1Messenger( L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR ); +/// @dev the address of the msg value system contract +address constant MSG_VALUE_SYSTEM_CONTRACT = address(SYSTEM_CONTRACTS_OFFSET + 0x09); + /// @dev The address of the eth token system contract address constant L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x0a); +IBaseToken constant L2_BASE_TOKEN_SYSTEM_CONTRACT = IBaseToken(L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR); /// @dev The address of the context system contract address constant L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x0b); +ISystemContext constant L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT = ISystemContext(L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR); /// @dev The address of the pubdata chunk publisher contract address constant L2_PUBDATA_CHUNK_PUBLISHER_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x11); +// @dev The address of the compressor contract. +address constant L2_COMPRESSOR_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x0e); + /// @dev The address used to execute complex upgragedes, also used for the genesis upgrade address constant L2_COMPLEX_UPGRADER_ADDR = address(SYSTEM_CONTRACTS_OFFSET + 0x0f); -/// @dev the address of the msg value system contract -address constant MSG_VALUE_SYSTEM_CONTRACT = address(SYSTEM_CONTRACTS_OFFSET + 0x09); - /// @dev The address of the create2 factory contract -address constant L2_CREATE2_FACTORY_ADDR = address(USER_CONTRACTS_OFFSET + 0x00); +address constant L2_CREATE2_FACTORY_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x00); /// @dev The address used to execute the genesis upgrade -address constant L2_GENESIS_UPGRADE_ADDR = address(USER_CONTRACTS_OFFSET + 0x01); +address constant L2_GENESIS_UPGRADE_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x01); /// @dev The genesis upgrade address is reused for all version specific upgrades address constant L2_VERSION_SPECIFIC_UPGRADER_ADDR = L2_GENESIS_UPGRADE_ADDR; /// @dev The address of the L2 bridge hub system contract, used to start L1->L2 transactions -address constant L2_BRIDGEHUB_ADDR = address(USER_CONTRACTS_OFFSET + 0x02); +address constant L2_BRIDGEHUB_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x02); + +IBridgehubBase constant L2_BRIDGEHUB = IBridgehubBase(L2_BRIDGEHUB_ADDR); /// @dev the address of the l2 asset router. -address constant L2_ASSET_ROUTER_ADDR = address(USER_CONTRACTS_OFFSET + 0x03); +address constant L2_ASSET_ROUTER_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x03); +IL2AssetRouter constant L2_ASSET_ROUTER = IL2AssetRouter(L2_ASSET_ROUTER_ADDR); /// @dev An l2 system contract address, used in the assetId calculation for native assets. /// This is needed for automatic bridging, i.e. without deploying the AssetHandler contract, /// if the assetId can be calculated with this address then it is in fact an NTV asset -address constant L2_NATIVE_TOKEN_VAULT_ADDR = address(USER_CONTRACTS_OFFSET + 0x04); +address constant L2_NATIVE_TOKEN_VAULT_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x04); +IL2NativeTokenVault constant L2_NATIVE_TOKEN_VAULT = IL2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR); /// @dev the address of the l2 asset router. -address constant L2_MESSAGE_ROOT_ADDR = address(USER_CONTRACTS_OFFSET + 0x05); - -/// @dev The address of the l2 wrapped base token. -address constant L2_WRAPPED_BASE_TOKEN_IMPL_ADDR = address(USER_CONTRACTS_OFFSET + 0x07); +address constant L2_MESSAGE_ROOT_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x05); +IMessageRoot constant L2_MESSAGE_ROOT = IMessageRoot(L2_MESSAGE_ROOT_ADDR); /// @dev The address of the SloadContract system contract, which provides a method to read values from arbitrary storage slots -address constant SLOAD_CONTRACT_ADDR = address(USER_CONTRACTS_OFFSET + 0x06); +address constant SLOAD_CONTRACT_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x06); -/// @dev The address of the WETH implementation contract -address constant L2_WETH_IMPL_ADDR = address(USER_CONTRACTS_OFFSET + 0x07); +/// @dev The address of the l2 wrapped base token. +address constant L2_WRAPPED_BASE_TOKEN_IMPL_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x07); /// @dev The address of the L2 interop root storage system contract -IL2InteropRootStorage constant L2_INTEROP_ROOT_STORAGE = IL2InteropRootStorage(address(USER_CONTRACTS_OFFSET + 0x08)); +IL2InteropRootStorage constant L2_INTEROP_ROOT_STORAGE = IL2InteropRootStorage( + address(BUILT_IN_CONTRACTS_OFFSET + 0x08) +); /// @dev The address of the L2 message verification system contract -IMessageVerification constant L2_MESSAGE_VERIFICATION = IMessageVerification(address(USER_CONTRACTS_OFFSET + 0x09)); +IMessageVerification constant L2_MESSAGE_VERIFICATION = IMessageVerification(address(BUILT_IN_CONTRACTS_OFFSET + 0x09)); /// @dev The address of the L2 chain handler system contract -address constant L2_CHAIN_ASSET_HANDLER_ADDR = address(USER_CONTRACTS_OFFSET + 0x0a); +address constant L2_CHAIN_ASSET_HANDLER_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x0a); +IChainAssetHandler constant L2_CHAIN_ASSET_HANDLER = IChainAssetHandler(L2_CHAIN_ASSET_HANDLER_ADDR); /// @dev UpgradeableBeaconDeployer that's responsible for deploying the upgradeable beacons for the bridged standard ERC20 tokens /// @dev Besides separation of concerns, we need it as a separate contract to ensure that L2NativeTokenVaultZKOS /// does not have to include BridgedStandardERC20 and UpgradeableBeacon and so can fit into the code size limit. -address constant L2_NTV_BEACON_DEPLOYER_ADDR = address(USER_CONTRACTS_OFFSET + 0x0b); +address constant L2_NTV_BEACON_DEPLOYER_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x0b); + +/// @dev the address of the L2 interop center +address constant L2_INTEROP_CENTER_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x0c); +IInteropCenter constant L2_INTEROP_CENTER = IInteropCenter(L2_INTEROP_CENTER_ADDR); + +/// @dev the address of the L2 interop handler +address constant L2_INTEROP_HANDLER_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x0d); + +/// @dev the address of the L2 asset tracker +address constant L2_ASSET_TRACKER_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x0e); +IL2AssetTracker constant L2_ASSET_TRACKER = IL2AssetTracker(L2_ASSET_TRACKER_ADDR); + +/// @dev the address of the GW asset tracker +address constant GW_ASSET_TRACKER_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x0f); +IGWAssetTracker constant GW_ASSET_TRACKER = IGWAssetTracker(GW_ASSET_TRACKER_ADDR); -address constant L2_SYSTEM_CONTRACT_PROXY_ADMIN_ADDR = address(USER_CONTRACTS_OFFSET + 0x0c); +/// @dev the address of the L2 system contract proxy admin +address constant L2_SYSTEM_CONTRACT_PROXY_ADMIN_ADDR = address(BUILT_IN_CONTRACTS_OFFSET + 0x10); diff --git a/l1-contracts/contracts/common/l2-helpers/L2ContractHelper.sol b/l1-contracts/contracts/common/l2-helpers/L2ContractHelper.sol index f89f0db4b3..359ee15f38 100644 --- a/l1-contracts/contracts/common/l2-helpers/L2ContractHelper.sol +++ b/l1-contracts/contracts/common/l2-helpers/L2ContractHelper.sol @@ -192,3 +192,52 @@ library L2ContractHelper { } } } + +/// @notice Structure used to represent a ZKsync transaction. +struct Transaction { + // The type of the transaction. + uint256 txType; + // The caller. + uint256 from; + // The callee. + uint256 to; + // The gasLimit to pass with the transaction. + // It has the same meaning as Ethereum's gasLimit. + uint256 gasLimit; + // The maximum amount of gas the user is willing to pay for a byte of pubdata. + uint256 gasPerPubdataByteLimit; + // The maximum fee per gas that the user is willing to pay. + // It is akin to EIP1559's maxFeePerGas. + uint256 maxFeePerGas; + // The maximum priority fee per gas that the user is willing to pay. + // It is akin to EIP1559's maxPriorityFeePerGas. + uint256 maxPriorityFeePerGas; + // The transaction's paymaster. If there is no paymaster, it is equal to 0. + uint256 paymaster; + // The nonce of the transaction. + uint256 nonce; + // The value to pass with the transaction. + uint256 value; + // In the future, we might want to add some + // new fields to the struct. The `txData` struct + // is to be passed to account and any changes to its structure + // would mean a breaking change to these accounts. In order to prevent this, + // we should keep some fields as "reserved". + // It is also recommended that their length is fixed, since + // it would allow easier proof integration (in case we will need + // some special circuit for preprocessing transactions). + uint256[4] reserved; + // The transaction's calldata. + bytes data; + // The signature of the transaction. + bytes signature; + // The properly formatted hashes of bytecodes that must be published on L1 + // with the inclusion of this transaction. Note, that a bytecode has been published + // before, the user won't pay fees for its republishing. + bytes32[] factoryDeps; + // The input to the paymaster. + bytes paymasterInput; + // Reserved dynamic type for the future use-case. Using it should be avoided, + // But it is still here, just in case we want to enable some additional functionality. + bytes reservedDynamic; +} diff --git a/l1-contracts/contracts/common/libraries/DataEncoding.sol b/l1-contracts/contracts/common/libraries/DataEncoding.sol index 85132acdd1..3eb0dfe680 100644 --- a/l1-contracts/contracts/common/libraries/DataEncoding.sol +++ b/l1-contracts/contracts/common/libraries/DataEncoding.sol @@ -4,8 +4,11 @@ pragma solidity 0.8.28; import {L2_NATIVE_TOKEN_VAULT_ADDR} from "../l2-helpers/L2ContractAddresses.sol"; import {LEGACY_ENCODING_VERSION, NEW_ENCODING_VERSION} from "../../bridge/asset-router/IAssetRouterBase.sol"; +import {AssetIdMismatch, IncorrectTokenAddressFromNTV, InvalidNTVBurnData, L2WithdrawalMessageWrongLength, UnsupportedEncodingVersion} from "../L1ContractErrors.sol"; +import {WrongMsgLength} from "../../bridge/L1BridgeContractErrors.sol"; +import {UnsafeBytes} from "./UnsafeBytes.sol"; +import {TokenBalanceMigrationData} from "../../common/Messaging.sol"; import {INativeTokenVaultBase} from "../../bridge/ntv/INativeTokenVaultBase.sol"; -import {IncorrectTokenAddressFromNTV, InvalidNTVBurnData, UnsupportedEncodingVersion} from "../L1ContractErrors.sol"; /** * @author Matter Labs @@ -193,4 +196,134 @@ library DataEncoding { ) internal pure returns (bytes memory) { return bytes.concat(NEW_ENCODING_VERSION, abi.encode(_chainId, _name, _symbol, _decimals)); } + + /// @notice Encodes the asset tracker data by combining chain id, asset id, amount, minting chain status and settlement layer balance. + /// @param _chainId The id of the chain being migrated. + /// @param _assetId The id of the asset being migrated. + /// @param _amount The amount being migrated. + /// @param _migratingChainIsMinter Whether the migrating chain is a minter. + /// @param _hasSettlingMintingChains Whether there are still settling minting chains. + /// @param _newSLBalance The new settlement layer balance. + /// @return The encoded asset tracker data. + function encodeAssetTrackerData( + uint256 _chainId, + bytes32 _assetId, + uint256 _amount, + bool _migratingChainIsMinter, + bool _hasSettlingMintingChains, + uint256 _newSLBalance + ) internal pure returns (bytes memory) { + return + abi.encode(_chainId, _assetId, _amount, _migratingChainIsMinter, _hasSettlingMintingChains, _newSLBalance); + } + + /// @notice Decodes the asset tracker data into its component parts. + /// @param _data The encoded asset tracker data. + /// @return chainId The id of the chain being migrated. + /// @return assetId The id of the asset being migrated. + /// @return amount The amount being migrated. + /// @return migratingChainIsMinter Whether the migrating chain is a minter. + /// @return hasSettlingMintingChains Whether there are still settling minting chains. + /// @return newSLBalance The new settlement layer balance. + function decodeAssetTrackerData( + bytes calldata _data + ) + internal + pure + returns ( + uint256 chainId, + bytes32 assetId, + uint256 amount, + bool migratingChainIsMinter, + bool hasSettlingMintingChains, + uint256 newSLBalance + ) + { + return abi.decode(_data, (uint256, bytes32, uint256, bool, bool, uint256)); + } + + /// @notice Checks if the assetId is correct. + /// @param _tokenOriginChainId The chain id of the token origin. + /// @param _assetId The asset id to check. + /// @param _originToken The origin token address. + function assetIdCheck(uint256 _tokenOriginChainId, bytes32 _assetId, address _originToken) internal pure { + bytes32 expectedAssetId = encodeNTVAssetId(_tokenOriginChainId, _originToken); + if (_assetId != expectedAssetId) { + // Make sure that a NativeTokenVault sent the message + revert AssetIdMismatch(expectedAssetId, _assetId); + } + } + + function decodeBaseTokenFinalizeWithdrawalData( + bytes memory _l2ToL1message + ) internal pure returns (bytes4 functionSignature, address l1Receiver, uint256 amount) { + (uint32 functionSignatureUint, uint256 offset) = UnsafeBytes.readUint32(_l2ToL1message, 0); + functionSignature = bytes4(functionSignatureUint); + + // The data is expected to be at least 56 bytes long. + require(_l2ToL1message.length >= 56, L2WithdrawalMessageWrongLength(_l2ToL1message.length)); + // this message is a base token withdrawal + (l1Receiver, offset) = UnsafeBytes.readAddress(_l2ToL1message, offset); + // slither-disable-next-line unused-return + (amount, ) = UnsafeBytes.readUint256(_l2ToL1message, offset); + } + + function decodeLegacyFinalizeWithdrawalData( + bytes memory _l2ToL1message + ) internal pure returns (bytes4 functionSignature, address l1Token, bytes memory transferData) { + (uint32 functionSignatureUint, uint256 offset) = UnsafeBytes.readUint32(_l2ToL1message, 0); + functionSignature = bytes4(functionSignatureUint); + // Check that the message length is correct. + // It should be equal to the length of the function signature + address + address + uint256 = 4 + 20 + 20 + 32 = + // 76 (bytes). + require(_l2ToL1message.length == 76, L2WithdrawalMessageWrongLength(_l2ToL1message.length)); + address l1Receiver; + uint256 amount; + (l1Receiver, offset) = UnsafeBytes.readAddress(_l2ToL1message, offset); + // We use the IL1ERC20Bridge for backward compatibility with old withdrawals. + (l1Token, offset) = UnsafeBytes.readAddress(_l2ToL1message, offset); + // slither-disable-next-line unused-return + (amount, ) = UnsafeBytes.readUint256(_l2ToL1message, offset); + + // We also convert the data into the new format. + transferData = DataEncoding.encodeBridgeMintData({ + _originalCaller: address(0), + _remoteReceiver: l1Receiver, + _originToken: l1Token, + _amount: amount, + _erc20Metadata: new bytes(0) + }); + } + + function decodeAssetRouterFinalizeDepositData( + bytes memory _l2ToL1message + ) + internal + pure + returns (bytes4 functionSignature, uint256 originChainId, bytes32 assetId, bytes memory transferData) + { + (uint32 functionSignatureUint, uint256 offset) = UnsafeBytes.readUint32(_l2ToL1message, 0); + functionSignature = bytes4(functionSignatureUint); + + // The data is expected to be at least 68 bytes long to contain assetId. + require(_l2ToL1message.length >= 68, WrongMsgLength(68, _l2ToL1message.length)); + // slither-disable-next-line unused-return + (originChainId, offset) = UnsafeBytes.readUint256(_l2ToL1message, offset); // originChainId, not used for L2->L1 txs + (assetId, offset) = UnsafeBytes.readBytes32(_l2ToL1message, offset); + transferData = UnsafeBytes.readRemainingBytes(_l2ToL1message, offset); + } + + function decodeTokenBalanceMigrationData( + bytes memory _l2ToL1message + ) internal pure returns (bytes4 functionSignature, TokenBalanceMigrationData memory data) { + (uint32 functionSignatureUint, uint256 offset) = UnsafeBytes.readUint32(_l2ToL1message, 0); + functionSignature = bytes4(functionSignatureUint); + bytes memory transferData = UnsafeBytes.readRemainingBytes(_l2ToL1message, offset); + data = abi.decode(transferData, (TokenBalanceMigrationData)); + } + + function getSelector(bytes memory _data) internal pure returns (bytes4) { + (uint32 functionSignatureUint, ) = UnsafeBytes.readUint32(_data, 0); + return bytes4(functionSignatureUint); + } } diff --git a/l1-contracts/contracts/common/libraries/DynamicIncrementalMerkle.sol b/l1-contracts/contracts/common/libraries/DynamicIncrementalMerkle.sol index 680604feb6..0e80b943b1 100644 --- a/l1-contracts/contracts/common/libraries/DynamicIncrementalMerkle.sol +++ b/l1-contracts/contracts/common/libraries/DynamicIncrementalMerkle.sol @@ -64,6 +64,14 @@ library DynamicIncrementalMerkle { * @return initialRoot The initial root of the tree. */ function reset(Bytes32PushTree storage self, bytes32 zero) internal returns (bytes32 initialRoot) { + clear(self); + setup(self, zero); + } + + /** + * @dev Clears the trees internal state. + */ + function clear(Bytes32PushTree storage self) internal { self._nextLeafIndex = 0; uint256 length = self._zeros.length; for (uint256 i = length; 0 < i; --i) { @@ -73,9 +81,6 @@ library DynamicIncrementalMerkle { for (uint256 i = length; 0 < i; --i) { self._sides.pop(); } - self._zeros.push(zero); - self._sides.push(bytes32(0)); - return bytes32(0); } /** @@ -131,6 +136,25 @@ library DynamicIncrementalMerkle { return (index, currentLevelHash); } + /** + * @dev Extend until end. + * @dev here we can extend the array, so the depth is not predetermined. + */ + function extendUntilEnd(Bytes32PushTree storage self, uint256 finalDepth) internal { + bytes32 currentZero = self._zeros[self._zeros.length - 1]; + if (self._nextLeafIndex == 0) { + self._sides[0] = currentZero; + } + bytes32 currentSide = self._sides[self._sides.length - 1]; + for (uint256 i = self._sides.length; i < finalDepth; ++i) { + currentSide = Merkle.efficientHash(currentSide, currentZero); + currentZero = Merkle.efficientHash(currentZero, currentZero); + // at i + self._zeros.push(currentZero); + self._sides.push(currentSide); + } + } + /** * @dev Tree's root. */ diff --git a/l1-contracts/contracts/common/libraries/DynamicIncrementalMerkleMemory.sol b/l1-contracts/contracts/common/libraries/DynamicIncrementalMerkleMemory.sol new file mode 100644 index 0000000000..1074414238 --- /dev/null +++ b/l1-contracts/contracts/common/libraries/DynamicIncrementalMerkleMemory.sol @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {Merkle} from "./Merkle.sol"; + +/** + * @dev Library for managing https://wikipedia.org/wiki/Merkle_Tree[Merkle Tree] data structures. + * + * Each tree is a complete binary tree with the ability to sequentially insert leaves, changing them from a zero to a + * non-zero value and updating its root. This structure allows inserting commitments (or other entries) that are not + * stored, but can be proven to be part of the tree at a later time if the root is kept. See {MerkleProof}. + * + * A tree is defined by the following parameters: + * + * * Depth: The number of levels in the tree, it also defines the maximum number of leaves as 2**depth. + * * Zero value: The value that represents an empty leaf. Used to avoid regular zero values to be part of the tree. + * * Hashing function: A cryptographic hash function used to produce internal nodes. + * + * This is a fork of OpenZeppelin's [`MerkleTree`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/9af280dc4b45ee5bda96ba47ff829b407eaab67e/contracts/utils/structs/MerkleTree.sol) + * library, with the changes to support dynamic tree growth (doubling the size when full). + */ +library DynamicIncrementalMerkleMemory { + /** + * @dev A complete `bytes32` Merkle tree. + * + * The `sides` and `zero` arrays are set to have a length equal to the depth of the tree during setup. + * + * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to + * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and + * lead to unexpected behavior. + * + * NOTE: The `root` and the updates history is not stored within the tree. Consider using a secondary structure to + * store a list of historical roots from the values returned from {setup} and {push} (e.g. a mapping, {BitMaps} or + * {Checkpoints}). + * + * WARNING: Updating any of the tree's parameters after the first insertion will result in a corrupted tree. + */ + struct Bytes32PushTree { + uint256 _nextLeafIndex; + bytes32[] _sides; + bytes32[] _zeros; + uint256 _sidesLengthMemory; + uint256 _zerosLengthMemory; + bool _needsRootRecalculation; + bytes32 _lastLeafValue; + } + + /// @dev The function used to allocate memory for a tree with a given depth. + function createTree(Bytes32PushTree memory self, uint256 _treeDepth) internal pure { + self._sides = new bytes32[](_treeDepth); + self._zeros = new bytes32[](_treeDepth); + self._sidesLengthMemory = 0; + self._zerosLengthMemory = 0; + self._needsRootRecalculation = false; + } + + /** + * @dev Initialize a {Bytes32PushTree} using {Hashes-Keccak256} to hash internal nodes. + * The capacity of the tree (i.e. number of leaves) is set to `2**levels`. + * + * IMPORTANT: The zero value should be carefully chosen since it will be stored in the tree representing + * empty leaves. It should be a value that is not expected to be part of the tree. + */ + function setup(Bytes32PushTree memory self, bytes32 zero) internal pure returns (bytes32 initialRoot) { + self._nextLeafIndex = 0; + self._zeros[0] = zero; + self._zerosLengthMemory = 1; + self._sides[0] = bytes32(0); + self._sidesLengthMemory = 1; + self._lastLeafValue = bytes32(0); + return bytes32(0); + } + + /** + * @dev Internal function that handles both lazy and non-lazy push operations. + * Returns the index of the newly inserted leaf and optionally the new root (if not lazy). + */ + function _pushInner( + Bytes32PushTree memory self, + bytes32 leaf, + bool isLazy + ) internal pure returns (uint256 leafIndex, bytes32 newRoot) { + // Cache read + uint256 levels = self._zerosLengthMemory - 1; + + // Get leaf index + // solhint-disable-next-line gas-increment-by-one + leafIndex = self._nextLeafIndex++; + + // Always store the last leaf value for potential reconstruction + self._lastLeafValue = leaf; + + // Check if tree is full. + if (leafIndex == 1 << levels) { + bytes32 zero = self._zeros[levels]; + bytes32 newZero = Merkle.efficientHash(zero, zero); + self._zeros[self._zerosLengthMemory] = newZero; + ++self._zerosLengthMemory; + self._sides[self._sidesLengthMemory] = bytes32(0); + ++self._sidesLengthMemory; + ++levels; + } + + // Rebuild branch from leaf to root + uint256 currentIndex = leafIndex; + bytes32 currentLevelHash = leaf; + bool updatedSides = false; + for (uint32 i = 0; i < levels; ++i) { + // Reaching the parent node, is currentLevelHash the left child? + bool isLeft = currentIndex % 2 == 0; + + // If so, next time we will come from the right, so we need to save it + if (isLeft && !updatedSides) { + self._sides[i] = currentLevelHash; + updatedSides = true; + if (isLazy) { + // Mark that root needs recalculation due to lazy update + self._needsRootRecalculation = true; + // Early return when sides are updated - we don't need to continue + return (leafIndex, bytes32(0)); + } + // Note: in order to update the sides we should stop here. We continue in order to store the new root. + } + + // Compute the current node hash by using the hash function + // with either its sibling (side) or the zero value for that level. + currentLevelHash = Merkle.efficientHash( + isLeft ? currentLevelHash : self._sides[i], + isLeft ? self._zeros[i] : currentLevelHash + ); + + // Update node index + currentIndex >>= 1; + } + // Note this is overloading the sides array with the root. + self._sides[levels] = currentLevelHash; + self._needsRootRecalculation = false; + return (leafIndex, currentLevelHash); + } + + /** + * @dev Insert a new leaf in the tree, and compute the new root. Returns the position of the inserted leaf in the + * tree, and the resulting root. + * + * Hashing the leaf before calling this function is recommended as a protection against + * second pre-image attacks. + */ + function push(Bytes32PushTree memory self, bytes32 leaf) internal pure returns (uint256 index, bytes32 newRoot) { + return _pushInner(self, leaf, false); + } + + /** + * @dev Insert a new leaf in the memory tree lazily. Returns the position of the inserted leaf in the + * tree. This is the lazy version that updates only the needed side array entry and defers + * root computation until root() is called. + * + * Hashing the leaf before calling this function is recommended as a protection against + * second pre-image attacks. + */ + function pushLazy(Bytes32PushTree memory self, bytes32 leaf) internal pure returns (uint256 index) { + (index, ) = _pushInner(self, leaf, true); + } + + /** + * @dev Extend until end. + */ + /// @dev here we can extend the array, so the depth is not predetermined. + function extendUntilEnd(Bytes32PushTree memory self) internal pure { + bytes32 currentZero = self._zeros[self._zerosLengthMemory - 1]; + if (self._nextLeafIndex == 0) { + self._sides[0] = currentZero; + } + bytes32 currentSide = self._sides[self._sidesLengthMemory - 1]; + uint256 finalDepth = self._sides.length; + for (uint256 i = self._sidesLengthMemory; i < finalDepth; ++i) { + currentSide = Merkle.efficientHash(currentSide, currentZero); + currentZero = Merkle.efficientHash(currentZero, currentZero); + self._zeros[i] = currentZero; + self._sides[i] = currentSide; + } + self._sidesLengthMemory = self._sides.length; + self._zerosLengthMemory = self._zeros.length; + self._needsRootRecalculation = false; + } + + /** + * @dev Recalculate the root from current tree state when lazy updates have been made. + * This simulates what a complete pushes sequence would have computed. + */ + function _recalculateRoot(Bytes32PushTree memory self) internal pure returns (bytes32) { + uint256 levels = self._zerosLengthMemory - 1; + uint256 leafCount = self._nextLeafIndex; + + if (leafCount == 0) { + return bytes32(0); + } + + uint256 currentIndex = leafCount - 1; + bytes32 currentLevelHash; + + if (currentIndex % 2 == 0) { + currentLevelHash = self._sides[0]; + } else { + currentLevelHash = self._lastLeafValue; + } + + for (uint32 i = 0; i < levels; ++i) { + bool isLeft = currentIndex % 2 == 0; + + currentLevelHash = Merkle.efficientHash( + isLeft ? currentLevelHash : self._sides[i], + isLeft ? self._zeros[i] : currentLevelHash + ); + + currentIndex >>= 1; + } + + return currentLevelHash; + } + + /** + * @dev Tree's root. + */ + function root(Bytes32PushTree memory self) internal pure returns (bytes32) { + if (self._needsRootRecalculation) { + bytes32 newRoot = _recalculateRoot(self); + self._sides[self._sidesLengthMemory - 1] = newRoot; + self._needsRootRecalculation = false; + return newRoot; + } + // note the last element of the sides array is the root, and is not really a side. + return self._sides[self._sidesLengthMemory - 1]; + } + + /** + * @dev Tree's height (does not include the root node). + */ + function height(Bytes32PushTree memory self) internal pure returns (uint256) { + return self._sidesLengthMemory - 1; + } + + /** + * @dev Current number of leaves in the tree (next leaf index). + */ + function index(Bytes32PushTree memory self) internal pure returns (uint256) { + return self._nextLeafIndex; + } +} diff --git a/l1-contracts/contracts/common/libraries/FullMerkleMemory.sol b/l1-contracts/contracts/common/libraries/FullMerkleMemory.sol new file mode 100644 index 0000000000..1fcf7c0061 --- /dev/null +++ b/l1-contracts/contracts/common/libraries/FullMerkleMemory.sol @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {UncheckedMath} from "../../common/libraries/UncheckedMath.sol"; +import {Merkle} from "./Merkle.sol"; +import {MerkleWrongIndex, MerkleWrongLength} from "../L1ContractErrors.sol"; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +library FullMerkleMemory { + using UncheckedMath for uint256; + + struct FullTree { + uint256 _height; + uint256 _leafNumber; + uint256 _nodesLengthMemory; + uint256 _zerosLengthMemory; + bytes32[][] _nodes; + bytes32[] _zeros; + } + + error InvalidMaxLeafNumber(uint256 _maxLeafNumber); + + function createTree(FullTree memory self, uint256 _maxLeafNumber) internal view { + if (_maxLeafNumber == 0) { + revert InvalidMaxLeafNumber(0); + } + + uint256 height = 0; + uint256 tempLeafNumber = _maxLeafNumber; + + while (tempLeafNumber > 1) { + ++height; + tempLeafNumber = (tempLeafNumber + 1) / 2; + } + + bytes32[][] memory nodes = new bytes32[][](height + 1); + nodes[0] = new bytes32[](_maxLeafNumber); + + uint256 currentLevelSize = _maxLeafNumber; + for (uint256 i = 1; i <= height; ++i) { + currentLevelSize = (currentLevelSize + 1) / 2; + nodes[i] = new bytes32[](currentLevelSize); + } + + bytes32[] memory zeros = new bytes32[](height + 1); + + self._zeros = zeros; + self._nodes = nodes; + self._height = height; + self._leafNumber = 0; + self._nodesLengthMemory = height + 1; + self._zerosLengthMemory = height + 1; + } + + /** + * @dev Initialize a {FullTree} using {Merkle.efficientHash} to hash internal nodes. + * The capacity of the tree (i.e. number of leaves) is set to `2**levels`. + * + * IMPORTANT: The zero value should be carefully chosen since it will be stored in the tree representing + * empty leaves. It should be a value that is not expected to be part of the tree. + * @param zero The zero value to be used in the tree. + */ + function setup(FullTree memory self, bytes32 zero) internal view returns (bytes32 initialRoot) { + self._zeros[0] = zero; + bytes32 currentZero = zero; + for (uint256 i = 1; i <= self._height; ++i) { + currentZero = Merkle.efficientHash(currentZero, currentZero); + self._zeros[i] = currentZero; + } + self._zerosLengthMemory = self._height + 1; + self._nodesLengthMemory = self._height + 1; + + self._nodes[self._height][0] = self._zeros[self._height]; + + return self._zeros[self._height]; + } + + /** + * @dev Push a new leaf to the tree. + * @param _leaf The leaf to be added to the tree. + */ + function pushNewLeaf(FullTree memory self, bytes32 _leaf) internal view returns (bytes32 newRoot) { + // solhint-disable-next-line gas-increment-by-one + uint256 index = self._leafNumber++; + + if (index == 1 << self._height) { + uint256 newHeight = self._height.uncheckedInc(); + self._height = newHeight; + bytes32 topZero = self._zeros[newHeight - 1]; + bytes32 newZero = Merkle.efficientHash(topZero, topZero); + self._zeros[self._zerosLengthMemory] = newZero; + ++self._zerosLengthMemory; + bytes32[] memory newLevelZero = new bytes32[](1); + newLevelZero[0] = newZero; + self._nodes[self._nodesLengthMemory] = newLevelZero; + ++self._nodesLengthMemory; + } + + if (index != 0) { + uint256 oldMaxNodeNumber = index - 1; + uint256 maxNodeNumber = index; + + for (uint256 i = 1; i <= self._height; i = i.uncheckedInc()) { + maxNodeNumber /= 2; + oldMaxNodeNumber /= 2; + + if (oldMaxNodeNumber == maxNodeNumber) { + break; + } + + if (self._nodes[i].length == 0) { + self._nodes[i] = new bytes32[](self._nodes[i - 1].length / 2 + 1); + } + + self._nodes[i][maxNodeNumber] = self._zeros[i]; + } + } + return updateLeaf(self, index, _leaf); + } + + /** + * @dev Update a leaf at index in the tree. + * @param _index The index of the leaf to be updated. + * @param _itemHash The new hash of the leaf. + */ + function updateLeaf(FullTree memory self, uint256 _index, bytes32 _itemHash) internal view returns (bytes32) { + uint256 maxNodeNumber = self._leafNumber - 1; + if (_index > maxNodeNumber) { + revert MerkleWrongIndex(_index, maxNodeNumber); + } + + self._nodes[0][_index] = _itemHash; + bytes32 currentHash = _itemHash; + for (uint256 i; i < self._height; i = i.uncheckedInc()) { + if (_index % 2 == 0) { + currentHash = Merkle.efficientHash( + currentHash, + maxNodeNumber == _index ? self._zeros[i] : self._nodes[i][_index + 1] + ); + } else { + currentHash = Merkle.efficientHash(self._nodes[i][_index - 1], currentHash); + } + _index /= 2; + maxNodeNumber /= 2; + + if (self._nodes[i + 1].length == 0) { + self._nodes[i + 1] = new bytes32[](self._nodes[i].length / 2 + 1); + } + + self._nodes[i + 1][_index] = currentHash; + } + return currentHash; + } + + /** + * @dev Updated all leaves in the tree. + * @param _newLeaves The new leaves to be added to the tree. + */ + function updateAllLeaves(FullTree memory self, bytes32[] memory _newLeaves) internal view returns (bytes32) { + if (_newLeaves.length != self._leafNumber) { + revert MerkleWrongLength(_newLeaves.length, self._leafNumber); + } + return updateAllNodesAtHeight(self, 0, _newLeaves); + } + + /** + * @dev Update all nodes at a certain height in the tree. + * @param _height The height of the nodes to be updated. + * @param _newNodes The new nodes to be added to the tree. + */ + function updateAllNodesAtHeight( + FullTree memory self, + uint256 _height, + bytes32[] memory _newNodes + ) internal view returns (bytes32) { + if (_height == self._height) { + self._nodes[_height][0] = _newNodes[0]; + return _newNodes[0]; + } + + uint256 newRowLength = (_newNodes.length + 1) / 2; + bytes32[] memory _newRow = new bytes32[](newRowLength); + + uint256 length = _newNodes.length; + for (uint256 i; i < length; i = i.uncheckedAdd(2)) { + self._nodes[_height][i] = _newNodes[i]; + if (i + 1 < length) { + self._nodes[_height][i + 1] = _newNodes[i + 1]; + _newRow[i / 2] = Merkle.efficientHash(_newNodes[i], _newNodes[i + 1]); + } else { + // Handle odd number of nodes by hashing the last node with zero + _newRow[i / 2] = Merkle.efficientHash(_newNodes[i], self._zeros[_height]); + } + } + return updateAllNodesAtHeight(self, _height + 1, _newRow); + } + + /** + * @dev Returns the root of the tree. + */ + function root(FullTree memory self) internal view returns (bytes32) { + return self._nodes[self._height][0]; + } +} diff --git a/l1-contracts/contracts/common/libraries/MessageHashing.sol b/l1-contracts/contracts/common/libraries/MessageHashing.sol index 1e8540f74e..4d716f9a7e 100644 --- a/l1-contracts/contracts/common/libraries/MessageHashing.sol +++ b/l1-contracts/contracts/common/libraries/MessageHashing.sol @@ -6,6 +6,8 @@ import {Merkle} from "./Merkle.sol"; import {L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH, SUPPORTED_PROOF_METADATA_VERSION} from "../Config.sol"; import {MerklePathEmpty} from "../L1ContractErrors.sol"; import {UncheckedMath} from "./UncheckedMath.sol"; +import {L2Log, L2Message, ProofData, TxStatus} from "../Messaging.sol"; +import {L2_BOOTLOADER_ADDRESS, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from "../l2-helpers/L2ContractAddresses.sol"; import {UnsupportedProofMetadataVersion} from "../../state-transition/L1StateTransitionErrors.sol"; import {HashedLogIsDefault, InvalidProofLengthForFinalNode} from "../../common/L1ContractErrors.sol"; @@ -13,20 +15,59 @@ import {HashedLogIsDefault, InvalidProofLengthForFinalNode} from "../../common/L bytes32 constant BATCH_LEAF_PADDING = keccak256("zkSync:BatchLeaf"); bytes32 constant CHAIN_ID_LEAF_PADDING = keccak256("zkSync:ChainIdLeaf"); -struct ProofData { - uint256 settlementLayerChainId; - uint256 settlementLayerBatchNumber; - uint256 settlementLayerBatchRootMask; - uint256 batchLeafProofLen; - bytes32 batchSettlementRoot; - bytes32 chainIdLeaf; - uint256 ptr; - bool finalProofNode; -} - library MessageHashing { using UncheckedMath for uint256; + function getLeafHashFromMessage(L2Message memory _message) internal pure returns (bytes32 hashedLog) { + L2Log memory l2Log = _l2MessageToLog(_message); + hashedLog = getLeafHashFromLog(l2Log); + } + + /// @dev Convert arbitrary-length message to the raw L2 log + function _l2MessageToLog(L2Message memory _message) internal pure returns (L2Log memory) { + return + L2Log({ + l2ShardId: 0, + isService: true, + txNumberInBatch: _message.txNumberInBatch, + sender: L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + key: bytes32(uint256(uint160(_message.sender))), + value: keccak256(_message.data) + }); + } + + function getL2LogFromL1ToL2Transaction( + uint16 _l2TxNumberInBatch, + bytes32 _l2TxHash, + TxStatus _status + ) internal pure returns (L2Log memory l2Log) { + // Bootloader sends an L2 -> L1 log only after processing the L1 -> L2 transaction. + // Thus, we can verify that the L1 -> L2 transaction was included in the L2 batch with specified status. + // + // The semantics of such L2 -> L1 log is always: + // - sender = L2_BOOTLOADER_ADDRESS + // - key = hash(L1ToL2Transaction) + // - value = status of the processing transaction (1 - success & 0 - fail) + // - isService = true (just a conventional value) + // - l2ShardId = 0 (means that L1 -> L2 transaction was processed in a rollup shard, other shards are not available yet anyway) + // - txNumberInBatch = number of transaction in the batch + l2Log = L2Log({ + l2ShardId: 0, + isService: true, + txNumberInBatch: _l2TxNumberInBatch, + sender: L2_BOOTLOADER_ADDRESS, + key: _l2TxHash, + value: bytes32(uint256(_status)) + }); + } + + function getLeafHashFromLog(L2Log memory _log) internal pure returns (bytes32 hashedLog) { + hashedLog = keccak256( + // solhint-disable-next-line func-named-parameters + abi.encodePacked(_log.l2ShardId, _log.isService, _log.txNumberInBatch, _log.sender, _log.key, _log.value) + ); + } + /// @dev Returns the leaf hash for a chain with batch number and batch root. /// @param batchRoot The root hash of the batch. /// @param batchNumber The number of the batch. diff --git a/l1-contracts/contracts/common/libraries/TransientPrimitives/TransientPrimitives.sol b/l1-contracts/contracts/common/libraries/TransientPrimitives/TransientPrimitives.sol new file mode 100644 index 0000000000..d468a4ab69 --- /dev/null +++ b/l1-contracts/contracts/common/libraries/TransientPrimitives/TransientPrimitives.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @author philogy +/// @notice TransientPrimitivesLib is a library for storing and retrieving transient values in the EVM. +library TransientPrimitivesLib { + function getUint256(uint256 slot) internal view returns (uint256 value) { + /// @solidity memory-safe-assembly + assembly { + value := tload(slot) + } + } + + function set(uint256 slot, uint256 value) internal { + /// @solidity memory-safe-assembly + assembly { + tstore(slot, value) + } + } +} diff --git a/l1-contracts/contracts/dev-contracts/L1NullifierDev.sol b/l1-contracts/contracts/dev-contracts/L1NullifierDev.sol index f21461caab..ca56221af4 100644 --- a/l1-contracts/contracts/dev-contracts/L1NullifierDev.sol +++ b/l1-contracts/contracts/dev-contracts/L1NullifierDev.sol @@ -3,13 +3,17 @@ pragma solidity 0.8.28; import {IL1Bridgehub, L1Nullifier} from "../bridge/L1Nullifier.sol"; +import {IMessageRoot} from "../bridgehub/IMessageRoot.sol"; +import {IInteropCenter} from "../interop/IInteropCenter.sol"; contract L1NullifierDev is L1Nullifier { constructor( IL1Bridgehub _bridgehub, + IMessageRoot _messageRoot, + IInteropCenter _interopCenter, uint256 _eraChainId, address _eraDiamondProxy - ) L1Nullifier(_bridgehub, _eraChainId, _eraDiamondProxy) {} + ) L1Nullifier(_bridgehub, _messageRoot, _eraChainId, _eraDiamondProxy) {} function setL2LegacySharedBridge(uint256 _chainId, address _l2Bridge) external { __DEPRECATED_l2BridgeAddress[_chainId] = _l2Bridge; diff --git a/l1-contracts/contracts/dev-contracts/test/AdminFacetTest.sol b/l1-contracts/contracts/dev-contracts/test/AdminFacetTest.sol index 851c08dd8f..d918209762 100644 --- a/l1-contracts/contracts/dev-contracts/test/AdminFacetTest.sol +++ b/l1-contracts/contracts/dev-contracts/test/AdminFacetTest.sol @@ -4,12 +4,24 @@ pragma solidity 0.8.28; import {AdminFacet} from "../../state-transition/chain-deps/facets/Admin.sol"; import {RollupDAManager} from "../../state-transition/data-availability/RollupDAManager.sol"; +import {CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "../../common/Config.sol"; contract AdminFacetTest is AdminFacet { // add this to be excluded from coverage report function test() internal virtual {} - constructor(uint256 _l1ChainId) AdminFacet(_l1ChainId, RollupDAManager(address(0))) { + constructor( + uint256 _l1ChainId + ) + AdminFacet( + _l1ChainId, + RollupDAManager(address(0)), + CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, + CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ) + { s.admin = msg.sender; s.chainTypeManager = msg.sender; } diff --git a/l1-contracts/contracts/dev-contracts/test/BridgeHelperTest.sol b/l1-contracts/contracts/dev-contracts/test/BridgeHelperTest.sol new file mode 100644 index 0000000000..bc17494f0a --- /dev/null +++ b/l1-contracts/contracts/dev-contracts/test/BridgeHelperTest.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {BridgeHelper} from "../../bridge/BridgeHelper.sol"; + +contract BridgeHelperTest { + function callGetters(address _token, uint256 _originChainId) external view returns (bytes memory) { + return BridgeHelper.getERC20Getters(_token, _originChainId); + } +} diff --git a/l1-contracts/contracts/dev-contracts/test/CustomUpgradeTest.sol b/l1-contracts/contracts/dev-contracts/test/CustomUpgradeTest.sol index 5e0b542de8..be25dba5bb 100644 --- a/l1-contracts/contracts/dev-contracts/test/CustomUpgradeTest.sol +++ b/l1-contracts/contracts/dev-contracts/test/CustomUpgradeTest.sol @@ -14,7 +14,7 @@ contract CustomUpgradeTest is BaseZkSyncUpgrade { /// @notice Placeholder function for custom logic for upgrading L1 contract. /// Typically this function will never be used. /// @param _customCallDataForUpgrade Custom data for upgrade, which may be interpreted differently for each upgrade. - function _upgradeL1Contract(bytes calldata _customCallDataForUpgrade) internal override { + function _upgradeL1Contract(bytes memory _customCallDataForUpgrade) internal override { keccak256(_customCallDataForUpgrade); // called to suppress compilation warning emit Test(); } @@ -23,11 +23,11 @@ contract CustomUpgradeTest is BaseZkSyncUpgrade { /// Typically this function will never be used. /// @param _customCallDataForUpgrade Custom data for an upgrade, which may be interpreted differently for each /// upgrade. - function _postUpgrade(bytes calldata _customCallDataForUpgrade) internal override {} + function _postUpgrade(bytes memory _customCallDataForUpgrade) internal override {} /// @notice The main function that will be delegate-called by the chain. /// @param _proposedUpgrade The upgrade to be executed. - function upgrade(ProposedUpgrade calldata _proposedUpgrade) public override returns (bytes32) { + function upgrade(ProposedUpgrade memory _proposedUpgrade) public override returns (bytes32) { (uint32 newMinorVersion, bool isPatchOnly) = _setNewProtocolVersion(_proposedUpgrade.newProtocolVersion, true); _upgradeL1Contract(_proposedUpgrade.l1ContractsUpgradeCalldata); _upgradeVerifier(_proposedUpgrade.verifier, _proposedUpgrade.verifierParams); diff --git a/l1-contracts/contracts/dev-contracts/test/DummyBaseTokenSystemContract.sol b/l1-contracts/contracts/dev-contracts/test/DummyBaseTokenSystemContract.sol new file mode 100644 index 0000000000..6acef18f6c --- /dev/null +++ b/l1-contracts/contracts/dev-contracts/test/DummyBaseTokenSystemContract.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +/// @title DummyL2BaseTokenSystemContract +/// @notice A test smart contract that allows to set State Transition Manager for a given chain +contract DummyL2BaseTokenSystemContract { + function burnMsgValue() external payable { + // do nothing + } +} diff --git a/l1-contracts/contracts/dev-contracts/test/DummyBridgehub.sol b/l1-contracts/contracts/dev-contracts/test/DummyBridgehub.sol index ec7096a359..5833b7f44d 100644 --- a/l1-contracts/contracts/dev-contracts/test/DummyBridgehub.sol +++ b/l1-contracts/contracts/dev-contracts/test/DummyBridgehub.sol @@ -17,6 +17,8 @@ contract DummyBridgehub { address public sharedBridge; + address public chainAssetHandler; + // add this to be excluded from coverage report function test() internal virtual {} @@ -36,6 +38,10 @@ contract DummyBridgehub { messageRoot = IMessageRoot(_messageRoot); } + function setChainAssetHandler(address _chainAssetHandler) public { + chainAssetHandler = _chainAssetHandler; + } + function setZKChain(uint256, address _zkChain) external { zkChain = _zkChain; } @@ -44,6 +50,12 @@ contract DummyBridgehub { return zkChain; } + function getAllZKChainChainIDs() external view returns (uint256[] memory) { + uint256[] memory allZKChainChainIDs = new uint256[](0); + // allZKChainChainIDs[0] = 271; + return allZKChainChainIDs; + } + function setSharedBridge(address addr) external { sharedBridge = addr; } @@ -51,4 +63,8 @@ contract DummyBridgehub { function assetRouter() external view returns (address) { return sharedBridge; } + + function settlementLayer(uint256) external view returns (uint256) { + return 0; + } } diff --git a/l1-contracts/contracts/dev-contracts/test/DummyChainTypeManager.sol b/l1-contracts/contracts/dev-contracts/test/DummyChainTypeManager.sol index 706059cd6b..17a255c60a 100644 --- a/l1-contracts/contracts/dev-contracts/test/DummyChainTypeManager.sol +++ b/l1-contracts/contracts/dev-contracts/test/DummyChainTypeManager.sol @@ -14,7 +14,7 @@ contract DummyChainTypeManager is EraChainTypeManager { address zkChain; /// @notice Constructor - constructor() EraChainTypeManager(address(0)) {} + constructor() EraChainTypeManager(address(0), address(0)) {} function setZKChain(uint256 _chainId, address _zkChain) external { zkChain = _zkChain; diff --git a/l1-contracts/contracts/dev-contracts/test/DummyChainTypeManagerWithBridgeHubAddress.sol b/l1-contracts/contracts/dev-contracts/test/DummyChainTypeManagerWithBridgeHubAddress.sol index b7a2298e5e..498e612491 100644 --- a/l1-contracts/contracts/dev-contracts/test/DummyChainTypeManagerWithBridgeHubAddress.sol +++ b/l1-contracts/contracts/dev-contracts/test/DummyChainTypeManagerWithBridgeHubAddress.sol @@ -13,7 +13,7 @@ contract DummyChainTypeManagerWBH is EraChainTypeManager { address zkChain; /// @notice Constructor - constructor(address bridgeHub) EraChainTypeManager(bridgeHub) {} + constructor(address bridgeHub) EraChainTypeManager(bridgeHub, address(0)) {} function setZKChain(uint256 _chainId, address _zkChain) external { zkChain = _zkChain; diff --git a/l1-contracts/contracts/dev-contracts/test/DummyL2InteropAccount.sol b/l1-contracts/contracts/dev-contracts/test/DummyL2InteropAccount.sol new file mode 100644 index 0000000000..74b55c42db --- /dev/null +++ b/l1-contracts/contracts/dev-contracts/test/DummyL2InteropAccount.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; +event ReturnMessage(bytes indexed error); + +contract DummyL2InteropAccount { + function forwardFromIC(address _to, uint256 _value, bytes memory _data) external payable { + // IC mints value here manually. + (bool success, bytes memory returnData) = _to.call{value: _value}(_data); // + if (!success) { + emit ReturnMessage(returnData); + revert("Forwarding call failed"); + } + } +} diff --git a/l1-contracts/contracts/dev-contracts/test/DummyL2L1Messenger.sol b/l1-contracts/contracts/dev-contracts/test/DummyL2L1Messenger.sol new file mode 100644 index 0000000000..3d5da956c1 --- /dev/null +++ b/l1-contracts/contracts/dev-contracts/test/DummyL2L1Messenger.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +event L1MessageSent(address indexed _sender, bytes32 indexed _hash, bytes _message); + +contract DummyL2L1Messenger { + function sendToL1(bytes calldata _message) external returns (bytes32 hash) { + emit L1MessageSent(msg.sender, hash, _message); + } +} diff --git a/l1-contracts/contracts/dev-contracts/test/DummyL2MessageRootStorage.sol b/l1-contracts/contracts/dev-contracts/test/DummyL2MessageRootStorage.sol new file mode 100644 index 0000000000..7c60811847 --- /dev/null +++ b/l1-contracts/contracts/dev-contracts/test/DummyL2MessageRootStorage.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +// import {Unauthorized} from "./SystemContractErrors.sol"; +// import {BOOTLOADER_FORMAL_ADDRESS} from "./Constants.sol"; + +/** + * @author Matter Labs + * @custom:security-contact security@matterlabs.dev + * @notice MessageRootStorage contract for imported L2 message roots.. + * @dev + */ +contract DummyL2InteropRootStorage { + mapping(uint256 chainId => mapping(uint256 batchNumber => bytes32 msgRoot)) public msgRoots; + mapping(bytes32 msgRoot => uint256 batchNumber) public batchNumberFromMsgRoot; + mapping(bytes32 msgRoot => uint256 chainId) public chainIdFromMsgRoot; + + mapping(uint256 chainId => mapping(uint256 batchNumber => bytes32[] msgRootSides)) public msgRootSides; + uint256 public pendingMessageRootIdsLength; + struct PendingMessageRootId { + uint256 chainId; + uint256 batchNumber; + } + mapping(uint256 index => PendingMessageRootId) public pendingMessageRootIds; + // mapping(bytes32 msgRoot => uint256 batchNumber) public batchNumberFromMsgRoot; + + event MessageRootAdded(uint256 indexed chainId, uint256 indexed batchNumber, bytes32[] sides); + + function addMessageRoot(uint256 chainId, uint256 batchNumber, bytes32[] memory sides) external { + emit MessageRootAdded(chainId, batchNumber, sides); + if (sides.length == 1) { + msgRoots[chainId][batchNumber] = sides[0]; + batchNumberFromMsgRoot[sides[0]] = batchNumber; + chainIdFromMsgRoot[sides[0]] = chainId; + } else { + // msgRootSides[chainId][batchNumber] = sides; + // pendingMessageRootIds[pendingMessageRootIdsLength] = PendingMessageRootId({ + // chainId: chainId, + // batchNumber: batchNumber + // }); + // pendingMessageRootIdsLength++; + } + } + + function addThisChainMessageRoot(uint256 batchNumber, bytes32[] memory sides) external { + msgRoots[block.chainid][batchNumber] = sides[0]; + batchNumberFromMsgRoot[sides[0]] = batchNumber; + chainIdFromMsgRoot[sides[0]] = block.chainid; + } +} diff --git a/l1-contracts/contracts/dev-contracts/test/DummyL2StandardTriggerAccount.sol b/l1-contracts/contracts/dev-contracts/test/DummyL2StandardTriggerAccount.sol new file mode 100644 index 0000000000..693aa1f140 --- /dev/null +++ b/l1-contracts/contracts/dev-contracts/test/DummyL2StandardTriggerAccount.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {IInteropHandler} from "../../interop/IInteropHandler.sol"; +import {L2Message, MessageInclusionProof} from "../../common/Messaging.sol"; +import {GasFields, InteropTrigger, TRIGGER_IDENTIFIER} from "./Utils.sol"; +import {L2_INTEROP_HANDLER_ADDR, L2_MESSAGE_VERIFICATION} from "../../common/l2-helpers/L2ContractAddresses.sol"; +import {Transaction} from "../../common/l2-helpers/L2ContractHelper.sol"; + +IInteropHandler constant L2_INTEROP_HANDLER = IInteropHandler(L2_INTEROP_HANDLER_ADDR); + +event MessageNotIncluded2(); + +contract DummyL2StandardTriggerAccount { + function process(Transaction calldata _transaction) external returns (bool success) { + /// trigger verification + { + (bytes memory executionBundle, ) = abi.decode(_transaction.data, (bytes, bytes)); + ( + bytes memory paymasterBundle, + , + address sender, + address refundRecipient, + bytes memory triggerProofBytes + ) = abi.decode(_transaction.signature, (bytes, bytes, address, address, bytes)); + MessageInclusionProof memory triggerProof = abi.decode(triggerProofBytes, (MessageInclusionProof)); + InteropTrigger memory interopTrigger = InteropTrigger({ + sender: address(uint160(sender)), + recipient: address(this), + destinationChainId: block.chainid, + feeBundleHash: keccak256(paymasterBundle), + executionBundleHash: keccak256(executionBundle), + gasFields: GasFields({ + gasLimit: _transaction.gasLimit, + gasPerPubdataByteLimit: _transaction.gasPerPubdataByteLimit, + refundRecipient: refundRecipient, + paymaster: address(0), + paymasterInput: "" + }) + }); + triggerProof.message.data = bytes.concat(TRIGGER_IDENTIFIER, abi.encode(interopTrigger)); + bool isIncluded = L2_MESSAGE_VERIFICATION.proveL2MessageInclusionShared( + triggerProof.chainId, + triggerProof.l1BatchNumber, + triggerProof.l2MessageIndex, + triggerProof.message, + triggerProof.proof + ); + if (!isIncluded) { + emit MessageNotIncluded2(); + } + } + + /// paymaster bundle + { + (bytes memory paymasterBundle, bytes memory paymasterProof, , , ) = abi.decode( + _transaction.signature, + (bytes, bytes, address, address, bytes) + ); + MessageInclusionProof memory paymasterInclusionProof = abi.decode(paymasterProof, (MessageInclusionProof)); + L2_INTEROP_HANDLER.executeBundle(paymasterBundle, paymasterInclusionProof); + } + + /// execution bundle + { + (bytes memory executionBundle, bytes memory executionProof) = abi.decode(_transaction.data, (bytes, bytes)); + MessageInclusionProof memory executionInclusionProof = abi.decode(executionProof, (MessageInclusionProof)); + L2_INTEROP_HANDLER.executeBundle(executionBundle, executionInclusionProof); + } + return true; + } + + receive() external payable { + // If the contract is called directly, behave like an EOA + } +} diff --git a/l1-contracts/contracts/dev-contracts/test/DummyZKChain.sol b/l1-contracts/contracts/dev-contracts/test/DummyZKChain.sol index 2edc9155d2..93a033db91 100644 --- a/l1-contracts/contracts/dev-contracts/test/DummyZKChain.sol +++ b/l1-contracts/contracts/dev-contracts/test/DummyZKChain.sol @@ -4,14 +4,25 @@ pragma solidity 0.8.28; import {IEIP7702Checker} from "../../state-transition/chain-interfaces/IEIP7702Checker.sol"; import {MailboxFacet} from "../../state-transition/chain-deps/facets/Mailbox.sol"; import {FeeParams, PubdataPricingMode} from "../../state-transition/chain-deps/ZKChainStorage.sol"; +import {PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "../../common/Config.sol"; contract DummyZKChain is MailboxFacet { constructor( address bridgeHubAddress, uint256 _eraChainId, uint256 _l1ChainId, + address _chainAssetHandler, IEIP7702Checker _eip7702Checker - ) MailboxFacet(_eraChainId, _l1ChainId, _eip7702Checker) { + ) + MailboxFacet( + _eraChainId, + _l1ChainId, + _chainAssetHandler, + _eip7702Checker, + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ) + { s.bridgehub = bridgeHubAddress; } diff --git a/l1-contracts/contracts/dev-contracts/test/IncrementalMerkleTest.sol b/l1-contracts/contracts/dev-contracts/test/IncrementalMerkleTest.sol index 8294160ee9..c4abb899c7 100644 --- a/l1-contracts/contracts/dev-contracts/test/IncrementalMerkleTest.sol +++ b/l1-contracts/contracts/dev-contracts/test/IncrementalMerkleTest.sol @@ -33,7 +33,27 @@ contract IncrementalMerkleTest { return tree._sides[_index]; } + function sidesLength() external view returns (uint256) { + return tree._sides.length; + } + function zeros(uint256 _index) external view returns (bytes32) { return tree._zeros[_index]; } + + function zerosLength() external view returns (uint256) { + return tree._zeros.length; + } + + function extendUntilEnd(uint256 _finalDepth) external { + tree.extendUntilEnd(_finalDepth); + } + + function reset(bytes32 zero) external returns (bytes32) { + return tree.reset(zero); + } + + function clear() external { + tree.clear(); + } } diff --git a/l1-contracts/contracts/dev-contracts/test/MailboxFacetTest.sol b/l1-contracts/contracts/dev-contracts/test/MailboxFacetTest.sol index f020b556b2..bca82ced66 100644 --- a/l1-contracts/contracts/dev-contracts/test/MailboxFacetTest.sol +++ b/l1-contracts/contracts/dev-contracts/test/MailboxFacetTest.sol @@ -6,6 +6,7 @@ import {IEIP7702Checker} from "../../state-transition/chain-interfaces/IEIP7702C import {FeeParams} from "../../state-transition/chain-deps/ZKChainStorage.sol"; import {MailboxFacet} from "../../state-transition/chain-deps/facets/Mailbox.sol"; import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "../../common/Config.sol"; +import {PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "../../common/Config.sol"; contract MailboxFacetTest is MailboxFacet { // add this to be excluded from coverage report @@ -14,8 +15,18 @@ contract MailboxFacetTest is MailboxFacet { constructor( uint256 _eraChainId, uint256 _l1ChainId, + address _chainAssetHandler, IEIP7702Checker _eip7702Checker - ) MailboxFacet(_eraChainId, _l1ChainId, _eip7702Checker) { + ) + MailboxFacet( + _eraChainId, + _l1ChainId, + _chainAssetHandler, + _eip7702Checker, + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ) + { s.admin = msg.sender; } diff --git a/l1-contracts/contracts/dev-contracts/test/Utils.sol b/l1-contracts/contracts/dev-contracts/test/Utils.sol new file mode 100644 index 0000000000..92a4d88eeb --- /dev/null +++ b/l1-contracts/contracts/dev-contracts/test/Utils.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +bytes1 constant TRIGGER_IDENTIFIER = 0x02; + +struct GasFields { + uint256 gasLimit; + uint256 gasPerPubdataByteLimit; + address refundRecipient; + address paymaster; + bytes paymasterInput; +} + +struct InteropTrigger { + uint256 destinationChainId; + address sender; + address recipient; + bytes32 feeBundleHash; + bytes32 executionBundleHash; + GasFields gasFields; +} diff --git a/l1-contracts/contracts/interop/AttributesDecoder.sol b/l1-contracts/contracts/interop/AttributesDecoder.sol new file mode 100644 index 0000000000..e987f7287e --- /dev/null +++ b/l1-contracts/contracts/interop/AttributesDecoder.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +/// @title IERC7786AttributesDecoder +/// @notice Interface for the ERC7786 attributes decoder +/// https://github.com/ethereum/ERCs/blob/023a7d657666308568d3d1391c578d5972636093/ERCS/erc-7786.md +library AttributesDecoder { + function decodeAddress(bytes calldata _data) internal pure returns (address) { + return (address(uint160(bytes20(_data[16:36])))); + } + + function decodeUint256(bytes calldata _data) internal pure returns (uint256) { + return (uint256(bytes32(_data[4:36]))); + } + + function decodeInteroperableAddress(bytes calldata _data) internal pure returns (bytes calldata) { + return _data[4:]; + } +} diff --git a/l1-contracts/contracts/interop/IERC7786Attributes.sol b/l1-contracts/contracts/interop/IERC7786Attributes.sol new file mode 100644 index 0000000000..ec45ecaefb --- /dev/null +++ b/l1-contracts/contracts/interop/IERC7786Attributes.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +/// @title IERC778Attributes +/// @notice Interface for the ERC7786 gateway source +/// @dev When adding/removing a function here the InteropCenter must be updated to reflect the changes. +/// https://github.com/ethereum/ERCs/blob/023a7d657666308568d3d1391c578d5972636093/ERCS/erc-7786.md +interface IERC7786Attributes { + function indirectCall(uint256 _indirectCallMessageValue) external pure; + + function interopCallValue(uint256 _interopCallValue) external pure; + + // Attribute assumes that _executionAddress is an ERC-7930 address. + function executionAddress(bytes calldata _executionAddress) external pure; + + // Attribute assumes that _executionAddress is an ERC-7930 address. + function unbundlerAddress(bytes calldata _unbundlerAddress) external pure; +} diff --git a/l1-contracts/contracts/interop/IERC7786GatewaySource.sol b/l1-contracts/contracts/interop/IERC7786GatewaySource.sol new file mode 100644 index 0000000000..2864a6842f --- /dev/null +++ b/l1-contracts/contracts/interop/IERC7786GatewaySource.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +/// @title IERC7786GatewaySource +/// @notice Interface for the ERC7786 gateway source +/// https://github.com/ethereum/ERCs/blob/023a7d657666308568d3d1391c578d5972636093/ERCS/erc-7786.md +interface IERC7786GatewaySource { + event MessageSent( + bytes32 indexed sendId, + bytes sender, // ERC-7930 address + bytes recipient, // ERC-7930 address + bytes payload, + uint256 value, + bytes[] attributes + ); + + error UnsupportedAttribute(bytes4 selector); + + function supportsAttribute(bytes4 selector) external view returns (bool); + + function sendMessage( + bytes calldata recipient, // ERC-7930 address + bytes calldata payload, + bytes[] calldata attributes + ) external payable returns (bytes32 sendId); +} diff --git a/l1-contracts/contracts/interop/IERC7786Recipient.sol b/l1-contracts/contracts/interop/IERC7786Recipient.sol new file mode 100644 index 0000000000..d2882ddc54 --- /dev/null +++ b/l1-contracts/contracts/interop/IERC7786Recipient.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +/// @title IERC7786Recipient +/// @notice Interface for the ERC7786 recipient +/// https://github.com/ethereum/ERCs/blob/023a7d657666308568d3d1391c578d5972636093/ERCS/erc-7786.md +interface IERC7786Recipient { + function receiveMessage( + bytes32 receiveId, // Unique identifier + bytes calldata sender, // ERC-7930 address + bytes calldata payload + ) external payable returns (bytes4); +} diff --git a/l1-contracts/contracts/interop/IInteropCenter.sol b/l1-contracts/contracts/interop/IInteropCenter.sol new file mode 100644 index 0000000000..65b0bea4ef --- /dev/null +++ b/l1-contracts/contracts/interop/IInteropCenter.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.21; + +import {BalanceChange, InteropBundle, InteropCallStarter} from "../common/Messaging.sol"; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IInteropCenter { + event InteropBundleSent(bytes32 l2l1MsgHash, bytes32 interopBundleHash, InteropBundle interopBundle); + + event NewAssetRouter(address indexed oldAssetRouter, address indexed newAssetRouter); + event NewAssetTracker(address indexed oldAssetTracker, address indexed newAssetTracker); + + /// @notice Restrictions for parsing attributes. + /// @param OnlyInteropCallValue: Only attribute for interop call value is allowed. + /// @param OnlyCallAttributes: Only call attributes are allowed. + /// @param OnlyBundleAttributes: Only bundle attributes are allowed. + /// @param CallAndBundleAttributes: Both call and bundle attributes are allowed. + enum AttributeParsingRestrictions { + OnlyInteropCallValue, + OnlyCallAttributes, + OnlyBundleAttributes, + CallAndBundleAttributes + } + + function initL2(uint256 _l1ChainId, address _owner) external; + + /// Mailbox forwarder + + function forwardTransactionOnGatewayWithBalanceChange( + uint256 _chainId, + bytes32 _canonicalTxHash, + uint64 _expirationTimestamp, + BalanceChange memory _balanceChange + ) external; + + function sendBundle( + bytes calldata _destinationChainId, + InteropCallStarter[] calldata _callStarters, + bytes[] calldata _bundleAttributes + ) external payable returns (bytes32); +} diff --git a/l1-contracts/contracts/interop/IInteropHandler.sol b/l1-contracts/contracts/interop/IInteropHandler.sol new file mode 100644 index 0000000000..2c211a7c02 --- /dev/null +++ b/l1-contracts/contracts/interop/IInteropHandler.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.20; + +import {CallStatus, MessageInclusionProof} from "../common/Messaging.sol"; + +interface IInteropHandler { + event BundleVerified(bytes32 indexed bundleHash); + + event BundleExecuted(bytes32 indexed bundleHash); + + event BundleUnbundled(bytes32 indexed bundleHash); + + event CallProcessed(bytes32 indexed bundleHash, uint256 indexed callIndex, CallStatus status); + + function executeBundle(bytes memory _bundle, MessageInclusionProof memory _proof) external; + + function verifyBundle(bytes memory _bundle, MessageInclusionProof memory _proof) external; + + function unbundleBundle(uint256 _sourceChainId, bytes memory _bundle, CallStatus[] calldata _callStatus) external; +} diff --git a/l1-contracts/contracts/interop/InteropCenter.sol b/l1-contracts/contracts/interop/InteropCenter.sol new file mode 100644 index 0000000000..21ef1b7291 --- /dev/null +++ b/l1-contracts/contracts/interop/InteropCenter.sol @@ -0,0 +1,541 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; +import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/security/PausableUpgradeable.sol"; + +import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; +import {DataEncoding} from "../common/libraries/DataEncoding.sol"; +import {IZKChain} from "../state-transition/chain-interfaces/IZKChain.sol"; +import {IInteropCenter} from "./IInteropCenter.sol"; + +import {GW_ASSET_TRACKER, L2_ASSET_ROUTER, L2_BASE_TOKEN_SYSTEM_CONTRACT, L2_BRIDGEHUB, L2_COMPLEX_UPGRADER_ADDR, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT} from "../common/l2-helpers/L2ContractAddresses.sol"; + +import {ETH_TOKEN_ADDRESS, SETTLEMENT_LAYER_RELAY_SENDER} from "../common/Config.sol"; +import {BUNDLE_IDENTIFIER, BalanceChange, BundleAttributes, CallAttributes, INTEROP_BUNDLE_VERSION, INTEROP_CALL_VERSION, InteropBundle, InteropCall, InteropCallStarter, InteropCallStarterInternal} from "../common/Messaging.sol"; +import {MsgValueMismatch, NotL1, NotL2ToL2, Unauthorized} from "../common/L1ContractErrors.sol"; +import {NotInGatewayMode} from "../bridgehub/L1BridgehubErrors.sol"; + +import {AttributeAlreadySet, AttributeViolatesRestriction, IndirectCallValueMismatch, InteroperableAddressChainReferenceNotEmpty, InteroperableAddressNotEmpty} from "./InteropErrors.sol"; + +import {IERC7786GatewaySource} from "./IERC7786GatewaySource.sol"; +import {IERC7786Attributes} from "./IERC7786Attributes.sol"; +import {AttributesDecoder} from "./AttributesDecoder.sol"; +import {InteropDataEncoding} from "./InteropDataEncoding.sol"; +import {InteroperableAddress} from "../vendor/draft-InteroperableAddress.sol"; +import {IL2CrossChainSender} from "../bridge/interfaces/IL2CrossChainSender.sol"; + +/// @title InteropCenter +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +/// @dev This contract serves as the primary entry point for communication between chains connected to the interop, facilitating interactions between end user and bridges. +/// @dev as of V30 only deployed on the L2s, not on L1. +contract InteropCenter is + IInteropCenter, + IERC7786GatewaySource, + ReentrancyGuard, + Ownable2StepUpgradeable, + PausableUpgradeable +{ + /// @notice The chain ID of L1. This contract can be deployed on multiple layers, but this value is still equal to the + /// L1 that is at the most base layer. + uint256 public L1_CHAIN_ID; + + /// @notice The asset ID of ETH on L1. + bytes32 internal ETH_TOKEN_ASSET_ID; + + /// @notice This mapping stores a number of interop bundles sent by an individual sender. + /// It's being used to derive interopBundleSalt in InteropBundle struct, whose role + /// is to ensure that each bundle has a unique hash. + mapping(address sender => uint256 numberOfBundlesSent) public interopBundleNonce; + + modifier onlyL1() { + require(L1_CHAIN_ID == block.chainid, NotL1(L1_CHAIN_ID, block.chainid)); + _; + } + + modifier onlyL2ToL2(uint256 _destinationChainId) { + _ensureL2ToL2(_destinationChainId); + _; + } + + modifier onlySettlementLayerRelayedSender() { + require(msg.sender == SETTLEMENT_LAYER_RELAY_SENDER, Unauthorized(msg.sender)); + _; + } + + /// @dev Only allows calls from the complex upgrader contract on L2. + modifier onlyUpgrader() { + if (msg.sender != L2_COMPLEX_UPGRADER_ADDR) { + revert Unauthorized(msg.sender); + } + _; + } + + /// @notice To avoid parity hack + function initL2(uint256 _l1ChainId, address _owner) public reentrancyGuardInitializer onlyUpgrader { + _disableInitializers(); + L1_CHAIN_ID = _l1ChainId; + ETH_TOKEN_ASSET_ID = DataEncoding.encodeNTVAssetId(L1_CHAIN_ID, ETH_TOKEN_ADDRESS); + + _transferOwnership(_owner); + } + + /*////////////////////////////////////////////////////////////// + InteropCenter entry points + //////////////////////////////////////////////////////////////*/ + + /// @notice Sends a single ERC-7786 message to another chain. + /// @param recipient ERC-7930 address corresponding to the destination of a message. It must be corresponding to an EIP-155 chain. + /// @param payload Payload to send. + /// @param attributes Attributes of the call. + /// @return sendId Hash of the sent bundle containing a single call. + function sendMessage( + bytes calldata recipient, + bytes calldata payload, + bytes[] calldata attributes + ) external payable whenNotPaused returns (bytes32 sendId) { + (uint256 recipientChainId, address recipientAddress) = InteroperableAddress.parseEvmV1Calldata(recipient); + + _ensureL2ToL2(recipientChainId); + + (CallAttributes memory callAttributes, BundleAttributes memory bundleAttributes) = parseAttributes( + attributes, + AttributeParsingRestrictions.CallAndBundleAttributes + ); + + // If the unbundler was not set for a call, we set the unbundler to be equal to the original sender, so that it's + // still possible to unbundle the bundle containing the call. If the original sender is the contract, it'll still + // be able to unbundle the bundle either via direct call to `unbundleBundle`, or via `sendMessage` to `InteropHandler`, + // with specific payload. Refer to `InteropHandler` for details. + if (bundleAttributes.unbundlerAddress.length == 0) { + bundleAttributes.unbundlerAddress = InteroperableAddress.formatEvmV1(block.chainid, msg.sender); + } + + InteropCallStarterInternal[] memory callStartersInternal = new InteropCallStarterInternal[](1); + callStartersInternal[0] = InteropCallStarterInternal({ + to: recipientAddress, + data: payload, + callAttributes: callAttributes + }); + + // Prepare original attributes array for the single call + bytes[][] memory originalCallAttributes = new bytes[][](1); + originalCallAttributes[0] = attributes; + + bytes32 bundleHash = _sendBundle( + recipientChainId, + callStartersInternal, + bundleAttributes, + originalCallAttributes + ); + + // We return the sendId of the only message that was sent in the bundle above. We always send messages in bundles, even if there's only one message being sent. + // Note, that bundleHash is unique for every bundle. Each sendId is determined as keccak256 of bundleHash where the message (call) is contained, + // and the index of the call inside the bundle. + sendId = keccak256(abi.encodePacked(bundleHash, uint256(0))); + } + + /// @notice Sends an interop bundle. + /// Same as above, but more than one call can be given, and they are given in InteropCallStarter format. + /// @param _destinationChainId Chain ID to send to. It's an ERC-7930 address that MUST have an empty address field, and encodes an EVM destination chain ID. + /// @param _callStarters Array of call descriptors. The ERC-7930 address in each callStarter.to + /// MUST have an empty ChainReference field. We assume all of the calls should go to the _destinationChainId, + /// so specifying the chain ID in _callStarters is redundant. + /// @param _bundleAttributes Attributes of the bundle. + /// @return bundleHash Hash of the sent bundle. + function sendBundle( + bytes calldata _destinationChainId, + InteropCallStarter[] calldata _callStarters, + bytes[] calldata _bundleAttributes + ) external payable whenNotPaused returns (bytes32 bundleHash) { + // Validate that the destination chain ERC-7930 address has an empty address field. + _ensureEmptyAddress(_destinationChainId); + + // Extract the actual chain ID from the ERC-7930 address + // slither-disable-next-line unused-return + (uint256 destinationChainId, ) = InteroperableAddress.parseEvmV1Calldata(_destinationChainId); + + // Ensure this is an L2 to L2 transaction + _ensureL2ToL2(destinationChainId); + InteropCallStarterInternal[] memory callStartersInternal = new InteropCallStarterInternal[]( + _callStarters.length + ); + uint256 callStartersLength = _callStarters.length; + + // Prepare original attributes array for all calls + bytes[][] memory originalCallAttributes = new bytes[][](callStartersLength); + + for (uint256 i = 0; i < callStartersLength; ++i) { + _ensureEmptyChainReference(_callStarters[i].to); + + // slither-disable-next-line unused-return + (, address recipientAddress) = InteroperableAddress.parseEvmV1Calldata(_callStarters[i].to); + + // Store original attributes for MessageSent event emission + originalCallAttributes[i] = _callStarters[i].callAttributes; + + // solhint-disable-next-line no-unused-vars + (CallAttributes memory callAttributes, ) = parseAttributes( + _callStarters[i].callAttributes, + AttributeParsingRestrictions.OnlyCallAttributes + ); + callStartersInternal[i] = InteropCallStarterInternal({ + to: recipientAddress, + data: _callStarters[i].data, + callAttributes: callAttributes + }); + } + // solhint-disable-next-line no-unused-vars + (, BundleAttributes memory bundleAttributes) = parseAttributes( + _bundleAttributes, + AttributeParsingRestrictions.OnlyBundleAttributes + ); + + // If the unbundler was not set for a bundle, we set the unbundler to be equal to the original sender, so + // that it's still possible to unbundle the bundle. If the original sender is the contract, it'll still be + // able to unbundle the bundle either via direct call to `unbundleBundle`, or via `sendMessage` to `InteropHandler`, + // with specific payload. Refer to `InteropHandler` for details. + if (bundleAttributes.unbundlerAddress.length == 0) { + bundleAttributes.unbundlerAddress = InteroperableAddress.formatEvmV1(block.chainid, msg.sender); + } + + bundleHash = _sendBundle({ + _destinationChainId: destinationChainId, + _callStarters: callStartersInternal, + _bundleAttributes: bundleAttributes, + _originalCallAttributes: originalCallAttributes + }); + } + + /*////////////////////////////////////////////////////////////// + Internal functions + //////////////////////////////////////////////////////////////*/ + + /// @notice Verifies that the ERC-7930 address has an empty ChainReference field. + /// @dev This function is used to ensure that CallStarters in sendBundle do not include ChainReference, as required + /// by our implementation. The ChainReference length is stored at byte offset 0x04 in the ERC-7930 format. + /// @param _interoperableAddress The ERC-7930 address to verify. + function _ensureEmptyChainReference(bytes calldata _interoperableAddress) internal pure { + require( + _interoperableAddress.length >= 5, + InteroperableAddress.InteroperableAddressParsingError(_interoperableAddress) + ); + uint8 chainReferenceLength = uint8(_interoperableAddress[0x04]); + require(chainReferenceLength == 0, InteroperableAddressChainReferenceNotEmpty(_interoperableAddress)); + } + + /// @notice Verifies that the ERC-7930 address has an empty address field. + /// @dev This function is used to ensure that the address does not contain an address field. + /// The address length is stored at byte offset (0x05 + chainReferenceLength) in the ERC-7930 format. + /// @param _interoperableAddress The ERC-7930 address to verify. + function _ensureEmptyAddress(bytes calldata _interoperableAddress) internal pure { + require( + _interoperableAddress.length >= 5, + InteroperableAddress.InteroperableAddressParsingError(_interoperableAddress) + ); + uint8 chainReferenceLength = uint8(_interoperableAddress[0x04]); + require( + _interoperableAddress.length >= 6 + chainReferenceLength, + InteroperableAddress.InteroperableAddressParsingError(_interoperableAddress) + ); + uint8 addressLength = uint8(_interoperableAddress[0x05 + chainReferenceLength]); + require(addressLength == 0, InteroperableAddressNotEmpty(_interoperableAddress)); + } + + function _ensureL2ToL2(uint256 _destinationChainId) internal view { + require( + L1_CHAIN_ID != block.chainid && _destinationChainId != L1_CHAIN_ID, + NotL2ToL2(block.chainid, _destinationChainId) + ); + } + + /// @notice Ensures the received base token value matches expected for the destination chain. + /// @param _destinationChainId Destination chain ID. + /// @param _totalBurnedCallsValue Sum of requested interop call values. + /// @param _totalIndirectCallsValue Sum of requested indirect call values. + function _ensureCorrectTotalValue( + uint256 _destinationChainId, + uint256 _totalBurnedCallsValue, + uint256 _totalIndirectCallsValue + ) internal { + bytes32 destinationChainBaseTokenAssetId = L2_BRIDGEHUB.baseTokenAssetId(_destinationChainId); + // We burn the value that is passed along the bundle here, on source chain. + bytes32 thisChainBaseTokenAssetId = L2_BRIDGEHUB.baseTokenAssetId(block.chainid); + if (destinationChainBaseTokenAssetId == thisChainBaseTokenAssetId) { + require( + msg.value == _totalBurnedCallsValue + _totalIndirectCallsValue, + MsgValueMismatch(_totalBurnedCallsValue + _totalIndirectCallsValue, msg.value) + ); + // slither-disable-next-line arbitrary-send-eth + L2_BASE_TOKEN_SYSTEM_CONTRACT.burnMsgValue{value: _totalBurnedCallsValue}(); + } else { + require(msg.value == _totalIndirectCallsValue, MsgValueMismatch(_totalIndirectCallsValue, msg.value)); + L2_ASSET_ROUTER.bridgehubDepositBaseToken( + _destinationChainId, + destinationChainBaseTokenAssetId, + msg.sender, + _totalBurnedCallsValue + ); + } + } + + /// @notice Constructs and sends an InteropBundle, that includes sending a message corresponding to the bundle via the L2 to L1 messenger. + /// @param _destinationChainId Chain ID to send to. + /// @param _callStarters Array of InteropCallStarterInternal structs, corresponding to the calls in bundle. + /// @param _bundleAttributes Attributes of the bundle. + /// @param _originalCallAttributes Original ERC-7786 attributes for each call to emit in MessageSent events. + /// @return bundleHash Hash of the sent bundle. + function _sendBundle( + uint256 _destinationChainId, + InteropCallStarterInternal[] memory _callStarters, + BundleAttributes memory _bundleAttributes, + bytes[][] memory _originalCallAttributes + ) internal returns (bytes32 bundleHash) { + require(L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT.currentSettlementLayerChainId() != L1_CHAIN_ID, NotInGatewayMode()); + + // Form an InteropBundle. + InteropBundle memory bundle = InteropBundle({ + version: INTEROP_BUNDLE_VERSION, + sourceChainId: block.chainid, + destinationChainId: _destinationChainId, + interopBundleSalt: keccak256(abi.encodePacked(msg.sender, interopBundleNonce[msg.sender])), + calls: new InteropCall[](_callStarters.length), + bundleAttributes: _bundleAttributes + }); + + // Update interopBundleNonce for the msg.sender + ++interopBundleNonce[msg.sender]; + + // This will calculate how much value does all of the calls use cumulatively. + uint256 totalBurnedCallsValue; + uint256 totalIndirectCallsValue; + + // Fill the formed InteropBundle with calls. + uint256 callStartersLength = _callStarters.length; + for (uint256 i = 0; i < callStartersLength; ++i) { + InteropCall memory interopCall = _processCallStarter(_callStarters[i], _destinationChainId, msg.sender); + bundle.calls[i] = interopCall; + totalBurnedCallsValue += _callStarters[i].callAttributes.interopCallValue; + // For indirect calls, also account for the bridge message value that gets sent to the AssetRouter + if (_callStarters[i].callAttributes.indirectCall) { + totalIndirectCallsValue += _callStarters[i].callAttributes.indirectCallMessageValue; + } + } + + // Ensure that tokens required for bundle execution were received. + _ensureCorrectTotalValue(bundle.destinationChainId, totalBurnedCallsValue, totalIndirectCallsValue); + + bytes32 msgHash; + /// To avoid stack too deep error + { + bytes memory interopBundleBytes = abi.encode(bundle); + + // Send the message corresponding to the relevant InteropBundle to L1. + msgHash = L2_TO_L1_MESSENGER_SYSTEM_CONTRACT.sendToL1(bytes.concat(BUNDLE_IDENTIFIER, interopBundleBytes)); + bundleHash = InteropDataEncoding.encodeInteropBundleHash(block.chainid, interopBundleBytes); + } + + // Emit ERC-7786 MessageSent event for each call in the bundle + for (uint256 i = 0; i < callStartersLength; ++i) { + InteropCall memory currentCall = bundle.calls[i]; + emit MessageSent({ + sendId: keccak256(abi.encodePacked(bundleHash, i)), + sender: InteroperableAddress.formatEvmV1(block.chainid, currentCall.from), + recipient: InteroperableAddress.formatEvmV1(_destinationChainId, currentCall.to), + payload: _callStarters[i].data, + value: _callStarters[i].callAttributes.interopCallValue, + attributes: _originalCallAttributes[i] + }); + } + + // Emit event stating that the bundle was sent out successfully. + emit InteropBundleSent(msgHash, bundleHash, bundle); + } + + function _processCallStarter( + InteropCallStarterInternal memory _callStarter, + uint256 _destinationChainId, + address _sender + ) internal returns (InteropCall memory interopCall) { + // Use the already-parsed address from InteropCallStarterInternal + address recipientAddress = _callStarter.to; + + if (_callStarter.callAttributes.indirectCall) { + // slither-disable-next-line arbitrary-send-eth + InteropCallStarter memory actualCallStarter = IL2CrossChainSender(recipientAddress).initiateIndirectCall{ + value: _callStarter.callAttributes.indirectCallMessageValue + }(_destinationChainId, _sender, _callStarter.callAttributes.interopCallValue, _callStarter.data); + // solhint-disable-next-line no-unused-vars + // slither-disable-next-line unused-return + (CallAttributes memory indirectCallAttributes, ) = this.parseAttributes( + actualCallStarter.callAttributes, + AttributeParsingRestrictions.OnlyInteropCallValue + ); + require( + _callStarter.callAttributes.interopCallValue == indirectCallAttributes.interopCallValue, + IndirectCallValueMismatch( + _callStarter.callAttributes.interopCallValue, + indirectCallAttributes.interopCallValue + ) + ); + // Parse the returned 7930 address from actualCallStarter.to + // slither-disable-next-line unused-return + (, address actualCallRecipient) = InteroperableAddress.parseEvmV1(actualCallStarter.to); + interopCall = InteropCall({ + version: INTEROP_CALL_VERSION, + shadowAccount: false, + to: actualCallRecipient, + data: actualCallStarter.data, + value: _callStarter.callAttributes.interopCallValue, + from: recipientAddress + }); + } else { + interopCall = InteropCall({ + version: INTEROP_CALL_VERSION, + shadowAccount: false, + to: recipientAddress, + data: _callStarter.data, + value: _callStarter.callAttributes.interopCallValue, + from: _sender + }); + } + } + + /*////////////////////////////////////////////////////////////// + GW function + //////////////////////////////////////////////////////////////*/ + + /// @notice Forwards a transaction from the gateway to a chain mailbox (from L1). + /// @dev Note, that `_canonicalTxHash` is provided by the chain and so should not be trusted to be unique, + /// while the rest of the fields are trusted to be populated correctly inside the `Mailbox` of the Gateway. + /// @param _chainId Target chain ID. + /// @param _canonicalTxHash Canonical L1 transaction hash. + /// @param _expirationTimestamp Expiration for gateway replay protection. + /// @param _balanceChange Balance change for the transaction. + function forwardTransactionOnGatewayWithBalanceChange( + uint256 _chainId, + bytes32 _canonicalTxHash, + uint64 _expirationTimestamp, + BalanceChange memory _balanceChange + ) external override onlySettlementLayerRelayedSender { + if (L1_CHAIN_ID == block.chainid) { + revert NotInGatewayMode(); + } + _balanceChange.baseTokenAssetId = L2_BRIDGEHUB.baseTokenAssetId(_chainId); + GW_ASSET_TRACKER.handleChainBalanceIncreaseOnGateway({ + _chainId: _chainId, + _canonicalTxHash: _canonicalTxHash, + _balanceChange: _balanceChange + }); + + address zkChain = L2_BRIDGEHUB.getZKChain(_chainId); + IZKChain(zkChain).bridgehubRequestL2TransactionOnGateway(_canonicalTxHash, _expirationTimestamp); + } + + /*////////////////////////////////////////////////////////////// + ERC 7786 + //////////////////////////////////////////////////////////////*/ + + /// @notice Parses the attributes of the call or bundle. + /// @param _attributes ERC-7786 Attributes of the call or bundle. + /// @param _restriction Restriction for parsing attributes. + function parseAttributes( + bytes[] calldata _attributes, + AttributeParsingRestrictions _restriction + ) public pure returns (CallAttributes memory callAttributes, BundleAttributes memory bundleAttributes) { + // Default value is direct call. + callAttributes.indirectCall = false; + + bytes4[4] memory ATTRIBUTE_SELECTORS = _getERC7786AttributeSelectors(); + // We can only pass each attribute once. + bool[] memory attributeUsed = new bool[](ATTRIBUTE_SELECTORS.length); + + uint256 attributesLength = _attributes.length; + for (uint256 i = 0; i < attributesLength; ++i) { + bytes4 selector = bytes4(_attributes[i]); + + if (selector == IERC7786Attributes.interopCallValue.selector) { + require(!attributeUsed[0], AttributeAlreadySet(selector)); + require( + _restriction == AttributeParsingRestrictions.OnlyInteropCallValue || + _restriction == AttributeParsingRestrictions.OnlyCallAttributes || + _restriction == AttributeParsingRestrictions.CallAndBundleAttributes, + AttributeViolatesRestriction(selector, uint256(_restriction)) + ); + attributeUsed[0] = true; + callAttributes.interopCallValue = AttributesDecoder.decodeUint256(_attributes[i]); + } else if (selector == IERC7786Attributes.indirectCall.selector) { + require(!attributeUsed[1], AttributeAlreadySet(selector)); + require( + _restriction == AttributeParsingRestrictions.OnlyCallAttributes || + _restriction == AttributeParsingRestrictions.CallAndBundleAttributes, + AttributeViolatesRestriction(selector, uint256(_restriction)) + ); + attributeUsed[1] = true; + callAttributes.indirectCall = true; + callAttributes.indirectCallMessageValue = AttributesDecoder.decodeUint256(_attributes[i]); + } else if (selector == IERC7786Attributes.executionAddress.selector) { + require(!attributeUsed[2], AttributeAlreadySet(selector)); + require( + _restriction == AttributeParsingRestrictions.OnlyBundleAttributes || + _restriction == AttributeParsingRestrictions.CallAndBundleAttributes, + AttributeViolatesRestriction(selector, uint256(_restriction)) + ); + attributeUsed[2] = true; + bundleAttributes.executionAddress = AttributesDecoder.decodeInteroperableAddress(_attributes[i]); + } else if (selector == IERC7786Attributes.unbundlerAddress.selector) { + require(!attributeUsed[3], AttributeAlreadySet(selector)); + require( + _restriction == AttributeParsingRestrictions.OnlyBundleAttributes || + _restriction == AttributeParsingRestrictions.CallAndBundleAttributes, + AttributeViolatesRestriction(selector, uint256(_restriction)) + ); + attributeUsed[3] = true; + bundleAttributes.unbundlerAddress = AttributesDecoder.decodeInteroperableAddress(_attributes[i]); + } else { + revert IERC7786GatewaySource.UnsupportedAttribute(selector); + } + } + } + + /// @notice Checks if the attribute selector is supported by the InteropCenter. + /// @param _attributeSelector The attribute selector to check. + /// @return True if the attribute selector is supported, false otherwise. + function supportsAttribute(bytes4 _attributeSelector) external pure returns (bool) { + bytes4[4] memory ATTRIBUTE_SELECTORS = _getERC7786AttributeSelectors(); + uint256 attributeSelectorsLength = ATTRIBUTE_SELECTORS.length; + for (uint256 i = 0; i < attributeSelectorsLength; ++i) { + if (_attributeSelector == ATTRIBUTE_SELECTORS[i]) { + return true; + } + } + return false; + } + + /// @notice Returns the attribute selectors supported by the InteropCenter. + /// @return The attribute selectors supported by the InteropCenter. + function _getERC7786AttributeSelectors() internal pure returns (bytes4[4] memory) { + return [ + IERC7786Attributes.interopCallValue.selector, + IERC7786Attributes.indirectCall.selector, + IERC7786Attributes.executionAddress.selector, + IERC7786Attributes.unbundlerAddress.selector + ]; + } + + /*////////////////////////////////////////////////////////////// + PAUSE + //////////////////////////////////////////////////////////////*/ + + /// @notice Pauses all functions marked with the `whenNotPaused` modifier. + function pause() external onlyOwner { + _pause(); + } + + /// @notice Unpauses the contract, allowing all functions marked with the `whenNotPaused` modifier to be called again. + function unpause() external onlyOwner { + _unpause(); + } +} diff --git a/l1-contracts/contracts/interop/InteropDataEncoding.sol b/l1-contracts/contracts/interop/InteropDataEncoding.sol new file mode 100644 index 0000000000..eb10110820 --- /dev/null +++ b/l1-contracts/contracts/interop/InteropDataEncoding.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +/** + * @author Matter Labs + * @custom:security-contact security@matterlabs.dev + * @notice Helper library for interop data encoding and decoding to reduce possibility of errors. + */ +library InteropDataEncoding { + function encodeInteropBundleHash(uint256 _sourceChainId, bytes memory _bundle) internal pure returns (bytes32) { + return keccak256(abi.encode(_sourceChainId, _bundle)); + } +} diff --git a/l1-contracts/contracts/interop/InteropErrors.sol b/l1-contracts/contracts/interop/InteropErrors.sol new file mode 100644 index 0000000000..6f5ce27650 --- /dev/null +++ b/l1-contracts/contracts/interop/InteropErrors.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +// 0x9031f751 +error AttributeAlreadySet(bytes4 selector); +// 0xbcb41ec7 +error AttributeViolatesRestriction(bytes4 selector, uint256 restriction); +// 0x5bba5111 +error BundleAlreadyProcessed(bytes32 bundleHash); +// 0xa43d2953 +error BundleVerifiedAlready(bytes32 bundleHash); +// 0xd5c7a376 +error CallAlreadyExecuted(bytes32 bundleHash, uint256 callIndex); +// 0xc087b727 +error CallNotExecutable(bytes32 bundleHash, uint256 callIndex); +// 0xf729f26d +error CanNotUnbundle(bytes32 bundleHash); +// 0xe845be4c +error ExecutingNotAllowed(bytes32 bundleHash, bytes callerAddress, bytes executionAddress); +// 0x62d214aa +error IndirectCallValueMismatch(uint256 expected, uint256 actual); +// 0xfe8b1b16 +error InteroperableAddressChainReferenceNotEmpty(bytes interoperableAddress); +// 0x884f49ba +error InteroperableAddressNotEmpty(bytes interoperableAddress); +// 0x32c2e156 +error MessageNotIncluded(); +// 0x89fd2c76 +error UnauthorizedMessageSender(address expected, address actual); +// 0x0345c281 +error UnbundlingNotAllowed(bytes32 bundleHash, bytes callerAddress, bytes unbundlerAddress); +// 0x801534e9 +error WrongCallStatusLength(uint256 bundleCallsLength, uint256 providedCallStatusLength); +// 0x4534e972 +error WrongDestinationChainId(bytes32 bundleHash, uint256 expected, uint256 actual); +// 0x534ab1b2 +error WrongSourceChainId(bytes32 bundleHash, uint256 expected, uint256 actual); diff --git a/l1-contracts/contracts/interop/InteropHandler.sol b/l1-contracts/contracts/interop/InteropHandler.sol new file mode 100644 index 0000000000..3858521322 --- /dev/null +++ b/l1-contracts/contracts/interop/InteropHandler.sol @@ -0,0 +1,439 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {InteroperableAddress} from "../vendor/draft-InteroperableAddress.sol"; + +import {L2_BASE_TOKEN_SYSTEM_CONTRACT, L2_INTEROP_CENTER_ADDR, L2_MESSAGE_VERIFICATION, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT, L2_COMPLEX_UPGRADER_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; +import {IInteropHandler} from "./IInteropHandler.sol"; +import {BUNDLE_IDENTIFIER, BundleStatus, CallStatus, InteropBundle, InteropCall, MessageInclusionProof} from "../common/Messaging.sol"; +import {IERC7786Recipient} from "./IERC7786Recipient.sol"; +import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; +import {InteropDataEncoding} from "./InteropDataEncoding.sol"; +import {BundleAlreadyProcessed, BundleVerifiedAlready, CallAlreadyExecuted, CallNotExecutable, CanNotUnbundle, ExecutingNotAllowed, MessageNotIncluded, UnauthorizedMessageSender, UnbundlingNotAllowed, WrongCallStatusLength, WrongDestinationChainId, WrongSourceChainId} from "./InteropErrors.sol"; +import {InvalidSelector, Unauthorized} from "../common/L1ContractErrors.sol"; +import {NotInGatewayMode} from "../bridgehub/L1BridgehubErrors.sol"; + +/// @title InteropHandler +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +/// @dev This contract serves as the entry-point for executing, verifying and unbundling interop bundles. +contract InteropHandler is IInteropHandler, ReentrancyGuard { + /// @notice The chain ID of L1. This contract can be deployed on multiple layers, but this value is still equal to the + /// L1 that is at the most base layer. + uint256 public L1_CHAIN_ID; + + /// @notice Tracks the processing status of a bundle by its hash. + mapping(bytes32 bundleHash => BundleStatus bundleStatus) public bundleStatus; + + /// @notice Tracks the individual call statuses within a bundle. + mapping(bytes32 bundleHash => mapping(uint256 callIndex => CallStatus callStatus)) public callStatus; + + /// @dev Only allows calls from the complex upgrader contract on L2. + modifier onlyUpgrader() { + if (msg.sender != L2_COMPLEX_UPGRADER_ADDR) { + revert Unauthorized(msg.sender); + } + _; + } + + /// @notice Initializes the reentrancy guard. + function initL2(uint256 _l1ChainId) public reentrancyGuardInitializer onlyUpgrader { + L1_CHAIN_ID = _l1ChainId; + } + + /// @notice Executes a full bundle atomically. + /// @dev Reverts if any call fails, or if bundle has been processed already. + /// @param _bundle ABI-encoded InteropBundle to execute. + /// @param _proof Inclusion proof for the bundle message. The bundle message itself gets broadcasted by InteropCenter contract whenever a bundle is sent. + function executeBundle(bytes memory _bundle, MessageInclusionProof memory _proof) public nonReentrant { + // Decode the bundle data, calculate its hash and get the current status of the bundle. + (InteropBundle memory interopBundle, bytes32 bundleHash, BundleStatus status) = _getBundleData( + _bundle, + _proof.chainId + ); + + // Verify that the source chainId of the bundle matches the proof's chainId + require( + interopBundle.sourceChainId == _proof.chainId, + WrongSourceChainId(bundleHash, interopBundle.sourceChainId, _proof.chainId) + ); + + // Verify that the destination chainId of the bundle is equal to the chainId where it's trying to get executed + require( + interopBundle.destinationChainId == block.chainid, + WrongDestinationChainId(bundleHash, interopBundle.destinationChainId, block.chainid) + ); + + // If the execution address is not specified then the execution is permissionless. + if (interopBundle.bundleAttributes.executionAddress.length != 0) { + (uint256 executionChainId, address executionAddress) = InteroperableAddress.parseEvmV1( + interopBundle.bundleAttributes.executionAddress + ); + + // Verify that the caller has permission to execute the bundle. + // Note, that in case the executionAddress wasn't specified in the bundle then executing is permissionless, as documented in Messaging.sol + // It's also possible that the caller is InteropHandler itself, in case the execution was initiated through receiveMessage. + require( + (msg.sender == address(this) || + ((executionChainId == block.chainid || executionChainId == 0) && executionAddress == msg.sender)), + ExecutingNotAllowed( + bundleHash, + InteroperableAddress.formatEvmV1(block.chainid, msg.sender), + interopBundle.bundleAttributes.executionAddress + ) + ); + } + + // We can only process bundles that are either unreceived (first time processing) or verified (already verified but not executed). + // This whitelist approach ensures that if new bundle statuses are added in the future, they will be explicitly rejected + // until they are explicitly allowed, preventing potential security vulnerabilities. + require( + status == BundleStatus.Unreceived || status == BundleStatus.Verified, + BundleAlreadyProcessed(bundleHash) + ); + + // Verify the bundle inclusion, if not done yet. + if (status != BundleStatus.Verified) _verifyBundle(_bundle, _proof, bundleHash); + + // Mark the given bundle as fully executed, following CEI pattern. + bundleStatus[bundleHash] = BundleStatus.FullyExecuted; + + // Update callStatus of the calls which are to be executed. + uint256 callsLength = interopBundle.calls.length; + for (uint256 i = 0; i < callsLength; ++i) { + callStatus[bundleHash][i] = CallStatus.Executed; + } + + // Execute all of the calls. + // Since we provide the flag `_executeAllCalls` to be true, if either of the calls fail, + // the `_executeCalls` will fail as well, thus making the whole flow revert, no changes will be applied to the state. + _executeCalls({ + _sourceChainId: interopBundle.sourceChainId, + _bundleHash: bundleHash, + _interopBundle: interopBundle, + _executeAllCalls: true, + _providedCallStatus: new CallStatus[](0) + }); + + // Emit event stating that the bundle was executed. + emit BundleExecuted(bundleHash); + } + + /// @notice Verifies receipt of a bundle without executing calls. + /// @dev Marks bundle as Verified on success. + /// @param _bundle ABI-encoded InteropBundle to verify. + /// @param _proof Inclusion proof for the bundle message. The bundle message itself gets broadcasted by InteropCenter contract whenever a bundle is sent. + function verifyBundle(bytes memory _bundle, MessageInclusionProof memory _proof) public nonReentrant { + // Decode the bundle data, calculate its hash and get the current status of the bundle. + (InteropBundle memory interopBundle, bytes32 bundleHash, BundleStatus status) = _getBundleData( + _bundle, + _proof.chainId + ); + + // Verify that the source chainId of the bundle matches the proof's chainId + require( + interopBundle.sourceChainId == _proof.chainId, + WrongSourceChainId(bundleHash, interopBundle.sourceChainId, _proof.chainId) + ); + + // Verify that the destination chainId of the bundle is equal to the chainId where it's trying to get verified + require( + interopBundle.destinationChainId == block.chainid, + WrongDestinationChainId(bundleHash, interopBundle.destinationChainId, block.chainid) + ); + + // If the bundle was already fully executed or unbundled, we revert stating that it was processed already. + require( + status == BundleStatus.Unreceived || status == BundleStatus.Verified, + BundleAlreadyProcessed(bundleHash) + ); + + // Revert if the bundle was verified already. + require(status != BundleStatus.Verified, BundleVerifiedAlready(bundleHash)); + + // Verify the bundle inclusion + _verifyBundle(_bundle, _proof, bundleHash); + } + + /// @notice Function used to unbundle the bundle. It's present to give more flexibility in cancelling and overall processing of bundles. + /// Can be invoked multiple times until all calls are processed. + /// @param _sourceChainId Originating chain ID of the bundle. + /// @param _bundle ABI-encoded InteropBundle to unbundle. + /// @param _providedCallStatus Array of desired statuses per call. + function unbundleBundle( + uint256 _sourceChainId, + bytes memory _bundle, + CallStatus[] calldata _providedCallStatus + ) public nonReentrant { + // Decode the bundle data, calculate its hash and get the current status of the bundle. + (InteropBundle memory interopBundle, bytes32 bundleHash, BundleStatus status) = _getBundleData( + _bundle, + _sourceChainId + ); + + // Verify that the source chainId of the bundle matches the provided source chainId + require( + interopBundle.sourceChainId == _sourceChainId, + WrongSourceChainId(bundleHash, interopBundle.sourceChainId, _sourceChainId) + ); + + // Verify that the destination chainId of the bundle is equal to the chainId where it's trying to get unbundled + require( + interopBundle.destinationChainId == block.chainid, + WrongDestinationChainId(bundleHash, interopBundle.destinationChainId, block.chainid) + ); + + (uint256 unbundlerChainId, address unbundlerAddress) = InteroperableAddress.parseEvmV1( + interopBundle.bundleAttributes.unbundlerAddress + ); + + // Verify that the caller has permission to unbundle the bundle. + // It's also possible that the caller is InteropHandler itself, in case the unbundling was initiated through receiveMessage. + require( + msg.sender == address(this) || + ((unbundlerChainId == block.chainid || unbundlerChainId == 0) && unbundlerAddress == msg.sender), + UnbundlingNotAllowed( + bundleHash, + InteroperableAddress.formatEvmV1(block.chainid, msg.sender), + interopBundle.bundleAttributes.unbundlerAddress + ) + ); + + // Verify that the provided call statuses array has the same length as the number of calls in the bundle. + // That's a measure to protect user from unintended unbundling calls. + require( + interopBundle.calls.length == _providedCallStatus.length, + WrongCallStatusLength(interopBundle.calls.length, _providedCallStatus.length) + ); + + // The bundle status have to be either verified (we know that it's received, but not processed yet), or unbundled. + // Note, that on the first call to unbundle the status of the bundle should be verified. + require(status == BundleStatus.Verified || status == BundleStatus.Unbundled, CanNotUnbundle(bundleHash)); + + // Mark the given bundle as unbundled, following CEI pattern. + bundleStatus[bundleHash] = BundleStatus.Unbundled; + + // We iterate over provided desired statuses of the calls and verify if they are valid (i.e. noncontradictory with current state of the bundle). + uint256 callsLength = interopBundle.calls.length; + for (uint256 i = 0; i < callsLength; ++i) { + CallStatus recordedCallStatus = callStatus[bundleHash][i]; + CallStatus requestedCallStatus = _providedCallStatus[i]; + if (requestedCallStatus == CallStatus.Executed) { + // We can only execute unprocessed calls. + require(recordedCallStatus == CallStatus.Unprocessed, CallNotExecutable(bundleHash, i)); + callStatus[bundleHash][i] = CallStatus.Executed; + emit CallProcessed(bundleHash, i, CallStatus.Executed); + } else if (requestedCallStatus == CallStatus.Cancelled) { + // We can only cancel calls which haven't been executed yet. + require(recordedCallStatus != CallStatus.Executed, CallAlreadyExecuted(bundleHash, i)); + if (recordedCallStatus == CallStatus.Unprocessed) { + // We update the call status if needed. + callStatus[bundleHash][i] = CallStatus.Cancelled; + emit CallProcessed(bundleHash, i, CallStatus.Cancelled); + } + } // If the specified requestedCallStatus is neither Executed or Cancelled, it means we should skip it. + } + + _executeCalls({ + _sourceChainId: _sourceChainId, + _bundleHash: bundleHash, + _interopBundle: interopBundle, + _executeAllCalls: false, + _providedCallStatus: _providedCallStatus + }); + + // Emit event stating that the bundle was unbundled. + emit BundleUnbundled(bundleHash); + } + + /*////////////////////////////////////////////////////////////// + Internal functions + //////////////////////////////////////////////////////////////*/ + + /// @notice Decode an ABI-encoded bundle, compute its hash, and fetch its current status. + /// @param _bundle ABI-encoded InteropBundle. + /// @param _sourceChainId Origin chain ID. + /// @return interopBundle The decoded InteropBundle struct. + /// @return bundleHash Hash corresponding to the bundle that gets decoded. + /// @return currentStatus The current BundleStatus of the bundle that gets decoded. + function _getBundleData( + bytes memory _bundle, + uint256 _sourceChainId + ) internal view returns (InteropBundle memory interopBundle, bytes32 bundleHash, BundleStatus currentStatus) { + interopBundle = abi.decode(_bundle, (InteropBundle)); + bundleHash = InteropDataEncoding.encodeInteropBundleHash(_sourceChainId, _bundle); + currentStatus = bundleStatus[bundleHash]; + } + + /// @notice Executes calls in a bundle according to provided or default statuses. + /// @param _sourceChainId Origin chain ID. + /// @param _bundleHash Precomputed hash of the bundle. + /// @param _interopBundle Decoded InteropBundle struct. + /// @param _executeAllCalls If true, executes all calls; otherwise uses providedCallStatus. + /// @param _providedCallStatus Desired status array when not executing all calls. + function _executeCalls( + uint256 _sourceChainId, + bytes32 _bundleHash, + InteropBundle memory _interopBundle, + bool _executeAllCalls, + CallStatus[] memory _providedCallStatus + ) internal { + uint256 callsLength = _interopBundle.calls.length; + for (uint256 i = 0; i < callsLength; ++i) { + if (!_executeAllCalls) { + CallStatus requestedCallStatus = _providedCallStatus[i]; + if (requestedCallStatus != CallStatus.Executed) { + // We skip the call. + continue; + } + } + InteropCall memory interopCall = _interopBundle.calls[i]; + + if (interopCall.value > 0) { + L2_BASE_TOKEN_SYSTEM_CONTRACT.mint(address(this), interopCall.value); + } + // slither-disable-next-line arbitrary-send-eth + bytes4 selector = IERC7786Recipient(interopCall.to).receiveMessage{value: interopCall.value}({ + receiveId: keccak256(abi.encodePacked(_bundleHash, i)), + sender: InteroperableAddress.formatEvmV1(_sourceChainId, interopCall.from), + payload: interopCall.data + }); // attributes are not supported yet + require(selector == IERC7786Recipient.receiveMessage.selector, InvalidSelector(selector)); + } + } + + /// @notice Verifies the bundle, meaning checking that the message corresponding to the bundle was received. + /// @param _bundle The abi-encoded InteropBundle struct corresponding to the bundle that is to be verified. + /// @param _proof Proof for the message that corresponds to the bundle that is to be verified. + /// @param _bundleHash Hash corresponding to the bundle that is to be verified. + /// That message gets sent to L1 by origin chain in InteropCenter contract, and is picked up and included in receiving chain by sequencer. + function _verifyBundle(bytes memory _bundle, MessageInclusionProof memory _proof, bytes32 _bundleHash) internal { + // Verify that the message came from the legitimate InteropCenter + require( + _proof.message.sender == L2_INTEROP_CENTER_ADDR, + UnauthorizedMessageSender(L2_INTEROP_CENTER_ADDR, _proof.message.sender) + ); + + // Substitute provided message data with data corresponding to the bundle currently being verified. + _proof.message.data = bytes.concat(BUNDLE_IDENTIFIER, _bundle); + + bool isIncluded = L2_MESSAGE_VERIFICATION.proveL2MessageInclusionShared({ + _chainId: _proof.chainId, + _blockOrBatchNumber: _proof.l1BatchNumber, + _index: _proof.l2MessageIndex, + _message: _proof.message, + _proof: _proof.proof + }); + + require(isIncluded, MessageNotIncluded()); + + bundleStatus[_bundleHash] = BundleStatus.Verified; + + /// We send the fact of verification to L1 so that the GWAssetTracker can process the chainBalance changes. + require(L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT.currentSettlementLayerChainId() != L1_CHAIN_ID, NotInGatewayMode()); + + // slither-disable-next-line reentrancy-no-eth,unused-return + L2_TO_L1_MESSENGER_SYSTEM_CONTRACT.sendToL1(bytes.concat(this.verifyBundle.selector, _bundleHash)); + + // Emit event stating that the bundle was verified. + emit BundleVerified(_bundleHash); + } + + /// @notice The sole purpose of this function is to serve as a rescue mechanism in case the sender is a contract, + /// the unbundler chainid is set to the sender chainid and the unbundler address is set to the contract's address. + /// In particular, this happens when the unbundler is not specified. + /// In such a case, the contract might nol be able to call `InteropHandler.unbundleBundle` directly. + /// Instead, it's able to send another bundle which calls `InteropHandler.unbundleBundle` via the `receiveMessage` function. + /// @dev Implements ERC-7786 recipient interface. The payload must be encoded using abi.encodeCall + /// with one of the following function selectors: + /// - executeBundle: payload = abi.encodeCall(InteropHandler.executeBundle, (bundle, proof)) + /// - unbundleBundle: payload = abi.encodeCall(InteropHandler.unbundleBundle, (sourceChainId, bundle, providedCallStatus)) + /// The sender must have appropriate permissions (executionAddress or unbundlerAddress) which are + /// validated before calling the respective internal functions. Since this function validates + /// permissions, the called functions (executeBundle/unbundleBundle) will bypass their own + /// permission checks when called from this contract (msg.sender == address(this)). + /// @param sender ERC-7930 interoperable address of the message sender. + /// @param payload ABI-encoded function call data with selector and parameters. + /// @return selector The function selector of this receiveMessage function, as per ERC-7786. + function receiveMessage( + bytes32 /* receiveId */, + bytes calldata sender, + bytes calldata payload + ) external payable nonReentrant returns (bytes4) { + // Verify that call to this function is a result of a call being executed, meaning this message came from a valid bundle. + // This is the only way receiveMessage can be invoked on InteropHandler by itself. + require(msg.sender == address(this), Unauthorized(msg.sender)); + + bytes4 selector = bytes4(payload[:4]); + + (uint256 senderChainId, address senderAddress) = InteroperableAddress.parseEvmV1Calldata(sender); + + if (selector == this.executeBundle.selector) { + _handleExecuteBundle(payload, senderChainId, senderAddress, sender); + } else if (selector == this.unbundleBundle.selector) { + _handleUnbundleBundle(payload, senderChainId, senderAddress, sender); + } else { + revert InvalidSelector(selector); + } + + return IERC7786Recipient.receiveMessage.selector; + } + + function _handleExecuteBundle( + bytes calldata payload, + uint256 senderChainId, + address senderAddress, + bytes calldata sender + ) internal { + (bytes memory bundle, MessageInclusionProof memory proof) = abi.decode( + payload[4:], + (bytes, MessageInclusionProof) + ); + + // Decode the bundle to get execution permissions + (InteropBundle memory interopBundle, , ) = _getBundleData(bundle, proof.chainId); + + // If the execution address is not specified then the execution is permissionless. + if (interopBundle.bundleAttributes.executionAddress.length != 0) { + (uint256 executionChainId, address executionAddress) = InteroperableAddress.parseEvmV1( + interopBundle.bundleAttributes.executionAddress + ); + + // Verify sender has execution permission + require( + (executionChainId == senderChainId || executionChainId == 0) && executionAddress == senderAddress, + ExecutingNotAllowed(keccak256(bundle), sender, interopBundle.bundleAttributes.executionAddress) + ); + } + + this.executeBundle(bundle, proof); + } + + function _handleUnbundleBundle( + bytes calldata payload, + uint256 senderChainId, + address senderAddress, + bytes calldata sender + ) internal { + (uint256 sourceChainId, bytes memory bundle, CallStatus[] memory providedCallStatus) = abi.decode( + payload[4:], + (uint256, bytes, CallStatus[]) + ); + + // Decode the bundle to get unbundling permissions + (InteropBundle memory interopBundle, , ) = _getBundleData(bundle, sourceChainId); + + (uint256 unbundlerChainId, address unbundlerAddress) = InteroperableAddress.parseEvmV1( + interopBundle.bundleAttributes.unbundlerAddress + ); + + // Verify sender has unbundling permission + require( + (unbundlerChainId == senderChainId || unbundlerChainId == 0) && unbundlerAddress == senderAddress, + UnbundlingNotAllowed(keccak256(bundle), sender, interopBundle.bundleAttributes.unbundlerAddress) + ); + + this.unbundleBundle(sourceChainId, bundle, providedCallStatus); + } +} diff --git a/l1-contracts/contracts/bridgehub/L2MessageVerification.sol b/l1-contracts/contracts/interop/L2MessageVerification.sol similarity index 73% rename from l1-contracts/contracts/bridgehub/L2MessageVerification.sol rename to l1-contracts/contracts/interop/L2MessageVerification.sol index 75eb367545..a6f4d53dab 100644 --- a/l1-contracts/contracts/bridgehub/L2MessageVerification.sol +++ b/l1-contracts/contracts/interop/L2MessageVerification.sol @@ -2,20 +2,22 @@ pragma solidity ^0.8.24; -import {MessageVerification} from "../state-transition/chain-deps/facets/MessageVerification.sol"; +import {MessageVerification} from "../common/MessageVerification.sol"; import {MessageHashing, ProofData} from "../common/libraries/MessageHashing.sol"; import {L2_INTEROP_ROOT_STORAGE} from "../common/l2-helpers/L2ContractAddresses.sol"; +import {DepthMoreThanOneForRecursiveMerkleProof} from "../bridgehub/L1BridgehubErrors.sol"; /// @title The interface of the ZKsync L2MessageVerification contract that can be used to prove L2 message inclusion on the L2. /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev contract L2MessageVerification is MessageVerification { - function _proveL2LeafInclusion( + function _proveL2LeafInclusionRecursive( uint256 _chainId, uint256 _blockOrBatchNumber, uint256 _leafProofMask, bytes32 _leaf, - bytes32[] calldata _proof + bytes32[] calldata _proof, + uint256 _depth ) internal view override returns (bool) { ProofData memory proofData = MessageHashing._getProofData({ _chainId: _chainId, @@ -29,6 +31,13 @@ contract L2MessageVerification is MessageVerification { bytes32 correctBatchRoot = L2_INTEROP_ROOT_STORAGE.interopRoots(_chainId, _blockOrBatchNumber); return correctBatchRoot == proofData.batchSettlementRoot && correctBatchRoot != bytes32(0); } + if (_depth == 1) { + revert DepthMoreThanOneForRecursiveMerkleProof(); + } + + // Note that here we assume that all settlement layers that the chain has ever settled on are trustworthy, + // i.e. all chains inside the ecosystem trust that they will not accept a message for a batch + // that never happened. return this.proveL2LeafInclusionShared({ diff --git a/l1-contracts/contracts/l2-upgrades/L2GenesisForceDeploymentsHelper.sol b/l1-contracts/contracts/l2-upgrades/L2GenesisForceDeploymentsHelper.sol index 56318788c1..d67a533605 100644 --- a/l1-contracts/contracts/l2-upgrades/L2GenesisForceDeploymentsHelper.sol +++ b/l1-contracts/contracts/l2-upgrades/L2GenesisForceDeploymentsHelper.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.28; -import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR, L2_DEPLOYER_SYSTEM_CONTRACT_ADDR, L2_MESSAGE_ROOT_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR, L2_NTV_BEACON_DEPLOYER_ADDR, L2_WRAPPED_BASE_TOKEN_IMPL_ADDR, L2_SYSTEM_CONTRACT_PROXY_ADMIN_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; +import {GW_ASSET_TRACKER_ADDR, L2_ASSET_TRACKER_ADDR, L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR, L2_DEPLOYER_SYSTEM_CONTRACT_ADDR, L2_INTEROP_HANDLER_ADDR, L2_MESSAGE_ROOT_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR, L2_NTV_BEACON_DEPLOYER_ADDR, L2_WRAPPED_BASE_TOKEN_IMPL_ADDR, L2_SYSTEM_CONTRACT_PROXY_ADMIN_ADDR, L2_INTEROP_CENTER_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; import {IL2ContractDeployer} from "../common/interfaces/IL2ContractDeployer.sol"; import {FixedForceDeploymentsData, ZKChainSpecificForceDeploymentsData} from "../state-transition/l2-deps/IL2GenesisUpgrade.sol"; import {IL2WrappedBaseToken} from "../bridge/interfaces/IL2WrappedBaseToken.sol"; @@ -13,15 +13,19 @@ import {L2NativeTokenVault} from "../bridge/ntv/L2NativeTokenVault.sol"; import {L2MessageRoot} from "../bridgehub/L2MessageRoot.sol"; import {L2Bridgehub} from "../bridgehub/L2Bridgehub.sol"; import {L2AssetRouter} from "../bridge/asset-router/L2AssetRouter.sol"; +import {L2AssetTracker} from "../bridge/asset-tracker/L2AssetTracker.sol"; +import {GWAssetTracker} from "../bridge/asset-tracker/GWAssetTracker.sol"; +import {L2ChainAssetHandler} from "../bridgehub/L2ChainAssetHandler.sol"; +import {InteropHandler} from "../interop/InteropHandler.sol"; import {IL1AssetRouter} from "../bridge/asset-router/IL1AssetRouter.sol"; import {IL2SharedBridgeLegacy} from "../bridge/interfaces/IL2SharedBridgeLegacy.sol"; -import {L2ChainAssetHandler} from "../bridgehub/L2ChainAssetHandler.sol"; import {DeployFailed, UnsupportedUpgradeType, ZKsyncOSNotForceDeployForExistingContract} from "../common/L1ContractErrors.sol"; import {L2NativeTokenVaultZKOS} from "../bridge/ntv/L2NativeTokenVaultZKOS.sol"; import {ICTMDeploymentTracker} from "../bridgehub/ICTMDeploymentTracker.sol"; import {IMessageRoot} from "../bridgehub/IMessageRoot.sol"; +import {InteropCenter} from "../interop/InteropCenter.sol"; import {UpgradeableBeaconDeployer} from "../bridge/UpgradeableBeaconDeployer.sol"; import {ISystemContractProxy} from "./ISystemContractProxy.sol"; @@ -146,6 +150,23 @@ library L2GenesisForceDeploymentsHelper { ? IComplexUpgrader.ContractUpgradeType.ZKsyncOSSystemProxyUpgrade : IComplexUpgrader.ContractUpgradeType.EraForceDeployment; + _setupProxyAdmin(); + _deployCoreContracts( + expectedUpgradeType, + fixedForceDeploymentsData, + additionalForceDeploymentsData, + _isGenesisUpgrade + ); + _deployTokenInfrastructure( + expectedUpgradeType, + fixedForceDeploymentsData, + additionalForceDeploymentsData, + _isGenesisUpgrade + ); + _finalizeDeployments(_ctmDeployer, fixedForceDeploymentsData, additionalForceDeploymentsData); + } + + function _setupProxyAdmin() private { // For Era chains, the SystemContractProxyAdmin is never used during deployment, but it is expected to be present // just in case. This line is just for consistency. // For ZKsyncOS chains, we expect that both the contract and the owner has been populated at the time of the genesis. @@ -154,7 +175,14 @@ library L2GenesisForceDeploymentsHelper { if (SystemContractProxyAdmin(L2_SYSTEM_CONTRACT_PROXY_ADMIN_ADDR).owner() != address(this)) { SystemContractProxyAdmin(L2_SYSTEM_CONTRACT_PROXY_ADMIN_ADDR).forceSetOwner(address(this)); } + } + function _deployCoreContracts( + IComplexUpgrader.ContractUpgradeType expectedUpgradeType, + FixedForceDeploymentsData memory fixedForceDeploymentsData, + ZKChainSpecificForceDeploymentsData memory additionalForceDeploymentsData, + bool _isGenesisUpgrade + ) private { conductContractUpgrade( expectedUpgradeType, fixedForceDeploymentsData.messageRootBytecodeInfo, @@ -163,7 +191,10 @@ library L2GenesisForceDeploymentsHelper { // If this is a genesis upgrade, we need to initialize the MessageRoot contract. // We dont need to do anything for already deployed chains. if (_isGenesisUpgrade) { - L2MessageRoot(L2_MESSAGE_ROOT_ADDR).initL2(fixedForceDeploymentsData.l1ChainId); + L2MessageRoot(L2_MESSAGE_ROOT_ADDR).initL2( + fixedForceDeploymentsData.l1ChainId, + fixedForceDeploymentsData.gatewayChainId + ); } conductContractUpgrade( @@ -215,7 +246,14 @@ library L2GenesisForceDeploymentsHelper { additionalForceDeploymentsData.baseTokenAssetId ); } + } + function _deployTokenInfrastructure( + IComplexUpgrader.ContractUpgradeType expectedUpgradeType, + FixedForceDeploymentsData memory fixedForceDeploymentsData, + ZKChainSpecificForceDeploymentsData memory additionalForceDeploymentsData, + bool _isGenesisUpgrade + ) private { address predeployedL2WethAddress = _isGenesisUpgrade ? address(0) : L2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR).WETH_TOKEN(); @@ -268,16 +306,21 @@ library L2GenesisForceDeploymentsHelper { additionalForceDeploymentsData.l2LegacySharedBridge, deployedTokenBeacon, wrappedBaseTokenAddress, - additionalForceDeploymentsData.baseTokenAssetId + additionalForceDeploymentsData.baseTokenAssetId, + additionalForceDeploymentsData.baseTokenOriginAddress, + additionalForceDeploymentsData.baseTokenOriginChainId ); } else { + address l2LegacySharedBridge = address(L2AssetRouter(L2_ASSET_ROUTER_ADDR).L2_LEGACY_SHARED_BRIDGE()); // solhint-disable-next-line func-named-parameters L2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR).updateL2( fixedForceDeploymentsData.l1ChainId, previousL2TokenProxyBytecodeHash, l2LegacySharedBridge, wrappedBaseTokenAddress, - additionalForceDeploymentsData.baseTokenAssetId + additionalForceDeploymentsData.baseTokenAssetId, + additionalForceDeploymentsData.baseTokenOriginAddress, + additionalForceDeploymentsData.baseTokenOriginChainId ); } @@ -304,15 +347,59 @@ library L2GenesisForceDeploymentsHelper { ); } + conductContractUpgrade( + expectedUpgradeType, + fixedForceDeploymentsData.assetTrackerBytecodeInfo, + L2_ASSET_TRACKER_ADDR + ); + + conductContractUpgrade( + expectedUpgradeType, + fixedForceDeploymentsData.interopCenterBytecodeInfo, + L2_INTEROP_CENTER_ADDR + ); + if (_isGenesisUpgrade) { + InteropCenter(L2_INTEROP_CENTER_ADDR).initL2( + fixedForceDeploymentsData.l1ChainId, + fixedForceDeploymentsData.aliasedL1Governance + ); + } + + conductContractUpgrade( + expectedUpgradeType, + fixedForceDeploymentsData.interopHandlerBytecodeInfo, + L2_INTEROP_HANDLER_ADDR + ); + } + + function _finalizeDeployments( + address _ctmDeployer, + FixedForceDeploymentsData memory fixedForceDeploymentsData, + ZKChainSpecificForceDeploymentsData memory additionalForceDeploymentsData + ) private { // It is expected that either through the force deployments above // or upon initialization, both the L2 deployment of BridgeHub, AssetRouter, and MessageRoot are deployed. // However, there is still some follow-up finalization that needs to be done. - L2Bridgehub(L2_BRIDGEHUB_ADDR).setAddresses( - L2_ASSET_ROUTER_ADDR, - ICTMDeploymentTracker(_ctmDeployer), - IMessageRoot(L2_MESSAGE_ROOT_ADDR), - L2_CHAIN_ASSET_HANDLER_ADDR + L2Bridgehub(L2_BRIDGEHUB_ADDR).setAddresses({ + _assetRouter: L2_ASSET_ROUTER_ADDR, + _l1CtmDeployer: ICTMDeploymentTracker(_ctmDeployer), + _messageRoot: IMessageRoot(L2_MESSAGE_ROOT_ADDR), + _chainAssetHandler: L2_CHAIN_ASSET_HANDLER_ADDR, + _chainRegistrationSender: fixedForceDeploymentsData.aliasedChainRegistrationSender + }); + + L2AssetTracker(L2_ASSET_TRACKER_ADDR).setAddresses( + fixedForceDeploymentsData.l1ChainId, + additionalForceDeploymentsData.baseTokenAssetId ); + + GWAssetTracker(GW_ASSET_TRACKER_ADDR).setAddresses(fixedForceDeploymentsData.l1ChainId); + + L2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR).setAddresses( + additionalForceDeploymentsData.baseTokenOriginChainId + ); + + InteropHandler(L2_INTEROP_HANDLER_ADDR).initL2(fixedForceDeploymentsData.l1ChainId); } /// @notice Constructs the initialization calldata for the L2WrappedBaseToken. diff --git a/l1-contracts/contracts/l2-upgrades/L2GenesisUpgrade.sol b/l1-contracts/contracts/l2-upgrades/L2GenesisUpgrade.sol index 171df7e058..c2f09d2a90 100644 --- a/l1-contracts/contracts/l2-upgrades/L2GenesisUpgrade.sol +++ b/l1-contracts/contracts/l2-upgrades/L2GenesisUpgrade.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.28; import {L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; -import {ISystemContext} from "../state-transition/l2-deps/ISystemContext.sol"; +import {ISystemContext} from "../common/interfaces/ISystemContext.sol"; import {IL2GenesisUpgrade} from "../state-transition/l2-deps/IL2GenesisUpgrade.sol"; import {L2GenesisForceDeploymentsHelper} from "./L2GenesisForceDeploymentsHelper.sol"; diff --git a/l1-contracts/contracts/l2-upgrades/L2V30Upgrade.sol b/l1-contracts/contracts/l2-upgrades/L2V30Upgrade.sol new file mode 100644 index 0000000000..620d3dd882 --- /dev/null +++ b/l1-contracts/contracts/l2-upgrades/L2V30Upgrade.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +/// @dev Storage slot with the admin of the contract used for EIP‑1967 proxies (e.g., TUP, BeaconProxy, etc.). +bytes32 constant PROXY_ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + +/// @custom:security-contact security@matterlabs.dev +/// @author Matter Labs +/// @title L2V30Upgrade, contains v30 upgrade fixes. +/// @dev This contract is neither predeployed nor a system contract. It resides in this folder to facilitate code reuse. +/// @dev This contract is called during the forceDeployAndUpgrade function of the ComplexUpgrader system contract. +contract L2V30Upgrade { + /// @notice Executes the one‑time migration/patch. + /// @dev Intended to be delegate‑called by the `ComplexUpgrader` contract. + /// @param _baseTokenOriginChainId The chainId of the origin chain of the base token. + /// @param _baseTokenOriginAddress The address of the base token on the origin chain. + function upgrade(uint256 _baseTokenOriginChainId, address _baseTokenOriginAddress) external { + // kl todo set baseTokenOriginChainId and baseTokenOriginAddress in some location. + // kl todo add all setAddresses, initL2 and updateL2s from genesis upgrade. + } +} diff --git a/l1-contracts/contracts/script-interfaces/IAdminFunction.sol b/l1-contracts/contracts/script-interfaces/IAdminFunction.sol new file mode 100644 index 0000000000..9fdee1b649 --- /dev/null +++ b/l1-contracts/contracts/script-interfaces/IAdminFunction.sol @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IAdminFunction { + function initConfig() external; + + function governanceAcceptOwner(address governor, address target) external; + + function governanceAcceptAdmin(address governor, address target) external; + + function chainAdminAcceptAdmin(address chainAdmin, address target) external; + + function chainSetTokenMultiplierSetter( + address chainAdmin, + address accessControlRestriction, + address diamondProxyAddress, + address setter + ) external; + + function governanceExecuteCalls(bytes calldata callsToExecute, address governanceAddr) external; + + function ecosystemAdminExecuteCalls(bytes calldata callsToExecute, address ecosystemAdminAddr) external; + + function adminEncodeMulticall(bytes calldata callsToExecute) external; + + function adminExecuteUpgrade( + bytes calldata diamondCut, + address adminAddr, + address accessControlRestriction, + address chainDiamondProxy + ) external; + + function adminScheduleUpgrade( + address adminAddr, + address accessControlRestriction, + uint256 newProtocolVersion, + uint256 timestamp + ) external; + + function makePermanentRollup(address chainAdmin, address target) external; + + function updateValidator( + address adminAddr, + address accessControlRestriction, + address validatorTimelock, + uint256 chainId, + address validatorAddress, + bool addValidator + ) external; + + function addL2WethToStore( + address storeAddress, + address ecosystemAdmin, + uint256 chainId, + address l2WBaseToken + ) external; + + function setPubdataPricingMode( + address chainAdmin, + address target, + uint8 pricingMode // Use uint8 for PubdataPricingMode + ) external; + + function notifyServerMigrationToGateway(address bridgehub, uint256 chainId, bool shouldSend) external; + + function notifyServerMigrationFromGateway(address bridgehub, uint256 chainId, bool shouldSend) external; + + function prepareUpgradeZKChainOnGateway( + uint256 l1GasPrice, + uint256 oldProtocolVersion, + bytes calldata upgradeCutData, + address chainDiamondProxyOnGateway, + uint256 gatewayChainId, + uint256 chainId, + address bridgehub, + address l1AssetRouterProxy, + address refundRecipient, + bool shouldSend + ) external; + + function grantGatewayWhitelist( + address bridgehub, + uint256 chainId, + address[] calldata grantees, + bool shouldSend + ) external; + + function revokeGatewayWhitelist(address bridgehub, uint256 chainId, address toRevoke, bool shouldSend) external; + + function setTransactionFilterer( + address bridgehub, + uint256 chainId, + address transactionFiltererAddress, + bool shouldSend + ) external; + + function pauseDepositsBeforeInitiatingMigration(address bridgehub, uint256 chainId, bool shouldSend) external; + + function unpauseDeposits(address bridgehub, uint256 chainId, bool shouldSend) external; + + function setDAValidatorPair( + address bridgehub, + uint256 chainId, + address l1DaValidator, + uint8 l2DaCommitmentScheme, // Use uint8 for L2DACommitmentScheme + bool shouldSend + ) external; + + function migrateChainToGateway( + address bridgehub, + uint256 l1GasPrice, + uint256 l2ChainId, + uint256 gatewayChainId, + bytes calldata gatewayDiamondCutData, + address refundRecipient, + bool shouldSend + ) external; + + function setDAValidatorPairWithGateway( + address bridgehub, + uint256 l1GasPrice, + uint256 l2ChainId, + uint256 gatewayChainId, + address l1DAValidator, + uint8 l2DACommitmentScheme, // Use uint8 for L2DACommitmentScheme + address chainDiamondProxyOnGateway, + address refundRecipient, + bool shouldSend + ) external; + + function enableValidatorViaGateway( + address bridgehub, + uint256 l1GasPrice, + uint256 l2ChainId, + uint256 gatewayChainId, + address validatorAddress, + address gatewayValidatorTimelock, + address refundRecipient, + bool shouldSend + ) external; + + function enableValidator( + address bridgehub, + uint256 l2ChainId, + address validatorAddress, + address validatorTimelock, + bool shouldSend + ) external; + + function startMigrateChainFromGateway( + address bridgehub, + uint256 l1GasPrice, + uint256 l2ChainId, + uint256 gatewayChainId, + bytes calldata l1DiamondCutData, + address refundRecipient, + bool shouldSend + ) external; + + function adminL1L2Tx( + address bridgehub, + uint256 l1GasPrice, + uint256 chainId, + address to, + uint256 value, + bytes calldata data, + address refundRecipient, + bool shouldSend + ) external; +} diff --git a/l1-contracts/contracts/state-transition/ChainTypeManagerBase.sol b/l1-contracts/contracts/state-transition/ChainTypeManagerBase.sol index b515a9bfb1..ccb3833837 100644 --- a/l1-contracts/contracts/state-transition/ChainTypeManagerBase.sol +++ b/l1-contracts/contracts/state-transition/ChainTypeManagerBase.sol @@ -21,6 +21,7 @@ import {SemVer} from "../common/libraries/SemVer.sol"; import {IL1Bridgehub} from "../bridgehub/IL1Bridgehub.sol"; import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; +import {TxStatus} from "../common/Messaging.sol"; /// @title Chain Type Manager Base contract /// @author Matter Labs @@ -32,6 +33,9 @@ abstract contract ChainTypeManagerBase is IChainTypeManager, ReentrancyGuard, Ow /// @notice Address of the bridgehub address public immutable BRIDGE_HUB; + /// @notice Address of the interop center + address public immutable INTEROP_CENTER; + /// @notice The map from chainId => zkChain contract EnumerableMap.UintToAddressMap internal __DEPRECATED_zkChainMap; @@ -80,8 +84,9 @@ abstract contract ChainTypeManagerBase is IChainTypeManager, ReentrancyGuard, Ow /// - It prevents the function from being called twice (including in the proxy impl). /// - It makes the local version consistent with the one in production, which already had the reentrancy guard /// initialized. - constructor(address _bridgehub) reentrancyGuardInitializer { + constructor(address _bridgehub, address _interopCenter) reentrancyGuardInitializer { BRIDGE_HUB = _bridgehub; + INTEROP_CENTER = _interopCenter; // While this does not provide a protection in the production, it is needed for local testing // Length of the L2Log encoding should not be equal to the length of other L2Logs' tree nodes preimages @@ -444,6 +449,7 @@ abstract contract ChainTypeManagerBase is IChainTypeManager, ReentrancyGuard, Ow IDiamondInit.initialize.selector, bytes32(_chainId), bytes32(uint256(uint160(BRIDGE_HUB))), + bytes32(uint256(uint160(INTEROP_CENTER))), bytes32(uint256(uint160(address(this)))), bytes32(protocolVersion), bytes32(uint256(uint160(_admin))), @@ -495,6 +501,9 @@ abstract contract ChainTypeManagerBase is IChainTypeManager, ReentrancyGuard, Ow _forceDeploymentData, _factoryDeps ); + // Deposits start paused by default to allow immediate Gateway migration. + // Otherwise, any deposit would trigger the PAUSE_DEPOSITS_TIME_WINDOW_START delay. + IAdmin(zkChainAddress).pauseDepositsBeforeInitiatingMigration(); } /// @param _chainId the chainId of the chain @@ -562,8 +571,9 @@ abstract contract ChainTypeManagerBase is IChainTypeManager, ReentrancyGuard, Ow /// param _assetInfo the assetInfo of the chain /// param _depositSender the address of that sent the deposit /// param _ctmData the data of the migration - function forwardedBridgeRecoverFailedTransfer( + function forwardedBridgeConfirmTransferResult( uint256 /* _chainId */, + TxStatus /* _txStatus */, bytes32 /* _assetInfo */, address /* _depositSender */, bytes calldata /* _ctmData */ diff --git a/l1-contracts/contracts/state-transition/EraChainTypeManager.sol b/l1-contracts/contracts/state-transition/EraChainTypeManager.sol index 3bf4cb289f..36337a4414 100644 --- a/l1-contracts/contracts/state-transition/EraChainTypeManager.sol +++ b/l1-contracts/contracts/state-transition/EraChainTypeManager.sol @@ -14,7 +14,7 @@ import {IChainAssetHandler} from "../bridgehub/IChainAssetHandler.sol"; /// @custom:security-contact security@matterlabs.dev contract EraChainTypeManager is ChainTypeManagerBase { /// @dev Contract is expected to be used as proxy implementation. - constructor(address _bridgehub) ChainTypeManagerBase(_bridgehub) {} + constructor(address _bridgehub, address _interopCenter) ChainTypeManagerBase(_bridgehub, _interopCenter) {} /// @notice Updates the parameters with which a new chain is created /// @param _chainCreationParams The new chain creation parameters diff --git a/l1-contracts/contracts/state-transition/IChainTypeManager.sol b/l1-contracts/contracts/state-transition/IChainTypeManager.sol index 6e91c491dc..5f9e947476 100644 --- a/l1-contracts/contracts/state-transition/IChainTypeManager.sol +++ b/l1-contracts/contracts/state-transition/IChainTypeManager.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.21; import {Diamond} from "./libraries/Diamond.sol"; -import {L2CanonicalTransaction} from "../common/Messaging.sol"; +import {L2CanonicalTransaction, TxStatus} from "../common/Messaging.sol"; import {FeeParams} from "./chain-deps/ZKChainStorage.sol"; /// @notice Struct that holds all data needed for initializing CTM Proxy. @@ -183,8 +183,9 @@ interface IChainTypeManager { function forwardedBridgeMint(uint256 _chainId, bytes calldata _data) external returns (address); - function forwardedBridgeRecoverFailedTransfer( + function forwardedBridgeConfirmTransferResult( uint256 _chainId, + TxStatus _txStatus, bytes32 _assetInfo, address _depositSender, bytes calldata _ctmData diff --git a/l1-contracts/contracts/state-transition/L1StateTransitionErrors.sol b/l1-contracts/contracts/state-transition/L1StateTransitionErrors.sol index db54f0f295..7612618462 100644 --- a/l1-contracts/contracts/state-transition/L1StateTransitionErrors.sol +++ b/l1-contracts/contracts/state-transition/L1StateTransitionErrors.sol @@ -14,6 +14,12 @@ error CommitBasedInteropNotSupported(); error ContractNotDeployed(); // 0xdf2c5fa5 error DependencyRootsRollingHashMismatch(bytes32 _expected, bytes32 _actual); +// 0xacf542ab +error DepositsAlreadyPaused(); +// 0xa4d3098c +error DepositsNotPaused(); +// 0xdeeb6943 +error DepositsPaused(); // 0xedae13f3 error ExecutedIsNotConsistentWithVerified(uint256 batchesExecuted, uint256 batchesVerified); // 0xc866ff2c @@ -48,6 +54,8 @@ error LocalRootIsZero(); error LocalRootMustBeZero(); // 0x9b5f85eb error MessageRootIsZero(); +// 0xf148c8da +error MigrationInProgress(); // 0x32fff278 error MismatchL2DACommitmentScheme(uint256 operatorProvidedScheme, uint256 expectedScheme); // 0x2c01a4af @@ -74,12 +82,16 @@ error OnlyOneBlobWithCalldataAllowed(); error OperatorDAInputTooSmall(uint256 operatorDAInputLength, uint256 minAllowedLength); // 0x681150be error OutdatedProtocolVersion(uint256 protocolVersion, uint256 currentProtocolVersion); +// 0xfe26193e +error PriorityQueueNotFullyProcessed(); // 0xc59d372c error ProtocolVersionNotUpToDate(uint256 currentProtocolVersion, uint256 protocolVersion); // 0x2dc9747d error PubdataInputTooSmall(uint256 pubdataInputLength, uint256 totalBlobsCommitmentSize); // 0x9044dff9 error PubdataLengthTooBig(uint256 pubdataLength, uint256 totalBlobSizeBytes); +// 0x89935a14 +error SettlementLayerChainIdMismatch(); // 0x0baf1d48 error UnknownVerifierVersion(); // 0x79274f04 diff --git a/l1-contracts/contracts/state-transition/ZKsyncOSChainTypeManager.sol b/l1-contracts/contracts/state-transition/ZKsyncOSChainTypeManager.sol index e112271860..c5affffb1f 100644 --- a/l1-contracts/contracts/state-transition/ZKsyncOSChainTypeManager.sol +++ b/l1-contracts/contracts/state-transition/ZKsyncOSChainTypeManager.sol @@ -11,7 +11,7 @@ import {ChainCreationParams} from "./IChainTypeManager.sol"; /// @custom:security-contact security@matterlabs.dev contract ZKsyncOSChainTypeManager is ChainTypeManagerBase { /// @dev Contract is expected to be used as proxy implementation. - constructor(address _bridgehub) ChainTypeManagerBase(_bridgehub) {} + constructor(address _bridgehub, address _interopCenter) ChainTypeManagerBase(_bridgehub, _interopCenter) {} /// @notice Updates the parameters with which a new chain is created /// @param _chainCreationParams The new chain creation parameters diff --git a/l1-contracts/contracts/state-transition/chain-deps/DiamondInit.sol b/l1-contracts/contracts/state-transition/chain-deps/DiamondInit.sol index 83b14b955f..72c6681fdd 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/DiamondInit.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/DiamondInit.sol @@ -9,6 +9,10 @@ import {IDiamondInit, InitializeData} from "../chain-interfaces/IDiamondInit.sol import {PriorityQueue} from "../libraries/PriorityQueue.sol"; import {PriorityTree} from "../libraries/PriorityTree.sol"; import {EmptyAssetId, EmptyBytes32, TooMuchGas, ZeroAddress} from "../../common/L1ContractErrors.sol"; +import {L2_ASSET_TRACKER_ADDR, L2_BRIDGEHUB_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR} from "../../common/l2-helpers/L2ContractAddresses.sol"; +import {IL1AssetRouter} from "../../bridge/asset-router/IL1AssetRouter.sol"; +import {IL1NativeTokenVault} from "../../bridge/ntv/IL1NativeTokenVault.sol"; +import {IBridgehubBase} from "../../bridgehub/IBridgehubBase.sol"; /// @author Matter Labs /// @dev The contract is used only once to initialize the diamond proxy. @@ -67,6 +71,16 @@ contract DiamondInit is ZKChainBase, IDiamondInit { s.chainId = _initializeData.chainId; s.bridgehub = _initializeData.bridgehub; s.chainTypeManager = _initializeData.chainTypeManager; + if (_initializeData.bridgehub == L2_BRIDGEHUB_ADDR) { + s.nativeTokenVault = L2_NATIVE_TOKEN_VAULT_ADDR; + s.assetTracker = L2_ASSET_TRACKER_ADDR; + } else { + address nativeTokenVault = address( + IL1AssetRouter(address(IBridgehubBase(_initializeData.bridgehub).assetRouter())).nativeTokenVault() + ); + s.nativeTokenVault = nativeTokenVault; + s.assetTracker = address(IL1NativeTokenVault(nativeTokenVault).l1AssetTracker()); + } s.baseTokenAssetId = _initializeData.baseTokenAssetId; s.protocolVersion = _initializeData.protocolVersion; diff --git a/l1-contracts/contracts/state-transition/chain-deps/GatewayCTMDeployer.sol b/l1-contracts/contracts/state-transition/chain-deps/GatewayCTMDeployer.sol index 046bd72fae..cf82fd2c31 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/GatewayCTMDeployer.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/GatewayCTMDeployer.sol @@ -34,7 +34,7 @@ import {Diamond} from "../libraries/Diamond.sol"; import {ZKsyncOSChainTypeManager} from "../ZKsyncOSChainTypeManager.sol"; import {EraChainTypeManager} from "../EraChainTypeManager.sol"; -import {L2_BRIDGEHUB_ADDR} from "../../common/l2-helpers/L2ContractAddresses.sol"; +import {L2_BRIDGEHUB_ADDR, L2_INTEROP_CENTER_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR} from "../../common/l2-helpers/L2ContractAddresses.sol"; import {ROLLUP_L2_DA_COMMITMENT_SCHEME} from "../../common/Config.sol"; import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; @@ -43,6 +43,7 @@ import {InitializeDataNewChain as DiamondInitializeDataNewChain} from "../chain- import {ChainCreationParams, ChainTypeManagerInitializeData, IChainTypeManager} from "../IChainTypeManager.sol"; import {ServerNotifier} from "../../governance/ServerNotifier.sol"; +import {CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_START_MAINNET, CHAIN_MIGRATION_TIME_WINDOW_END_MAINNET, PAUSE_DEPOSITS_TIME_WINDOW_START_MAINNET, PAUSE_DEPOSITS_TIME_WINDOW_END_MAINNET} from "contracts/common/Config.sol"; /// @notice Configuration parameters for deploying the GatewayCTMDeployer contract. // solhint-disable-next-line gas-struct-packing struct GatewayCTMDeployerConfig { @@ -191,7 +192,8 @@ contract GatewayCTMDeployer { _eraChainId: eraChainId, _l1ChainId: l1ChainId, _aliasedGovernanceAddress: _config.aliasedGovernanceAddress, - _deployedContracts: contracts + _deployedContracts: contracts, + _testnetVerifier: _config.testnetVerifier }); // solhint-disable-next-line func-named-parameters _deployVerifier(salt, _config.testnetVerifier, _config.isZKsyncOS, contracts, _config.aliasedGovernanceAddress); @@ -225,10 +227,22 @@ contract GatewayCTMDeployer { uint256 _eraChainId, uint256 _l1ChainId, address _aliasedGovernanceAddress, - DeployedContracts memory _deployedContracts + DeployedContracts memory _deployedContracts, + bool _testnetVerifier ) internal { _deployedContracts.stateTransition.mailboxFacet = address( - new MailboxFacet{salt: _salt}(_eraChainId, _l1ChainId, IEIP7702Checker(address(0))) + new MailboxFacet{salt: _salt}({ + _eraChainId: _eraChainId, + _l1ChainId: _l1ChainId, + _chainAssetHandler: L2_CHAIN_ASSET_HANDLER_ADDR, + _eip7702Checker: IEIP7702Checker(address(0)), + _pauseDepositsTimeWindowStart: _testnetVerifier + ? PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET + : PAUSE_DEPOSITS_TIME_WINDOW_START_MAINNET, + _pauseDepositsTimeWindowEnd: _testnetVerifier + ? PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + : PAUSE_DEPOSITS_TIME_WINDOW_END_MAINNET + }) ); _deployedContracts.stateTransition.executorFacet = address(new ExecutorFacet{salt: _salt}(_l1ChainId)); _deployedContracts.stateTransition.gettersFacet = address(new GettersFacet{salt: _salt}()); @@ -239,7 +253,22 @@ contract GatewayCTMDeployer { _deployedContracts ); _deployedContracts.stateTransition.adminFacet = address( - new AdminFacet{salt: _salt}(_l1ChainId, rollupDAManager) + new AdminFacet{salt: _salt}({ + _l1ChainId: _l1ChainId, + _rollupDAManager: rollupDAManager, + _chainMigrationTimeWindowStart: _testnetVerifier + ? CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET + : CHAIN_MIGRATION_TIME_WINDOW_START_MAINNET, + _chainMigrationTimeWindowEnd: _testnetVerifier + ? CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET + : CHAIN_MIGRATION_TIME_WINDOW_END_MAINNET, + _pauseDepositsTimeWindowStart: _testnetVerifier + ? PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET + : PAUSE_DEPOSITS_TIME_WINDOW_START_MAINNET, + _pauseDepositsTimeWindowEnd: _testnetVerifier + ? PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + : PAUSE_DEPOSITS_TIME_WINDOW_END_MAINNET + }) ); _deployedContracts.stateTransition.diamondInit = address(new DiamondInit{salt: _salt}(false)); @@ -394,11 +423,11 @@ contract GatewayCTMDeployer { ) internal { if (_config.isZKsyncOS) { _deployedContracts.stateTransition.chainTypeManagerImplementation = address( - new ZKsyncOSChainTypeManager{salt: _salt}(L2_BRIDGEHUB_ADDR) + new ZKsyncOSChainTypeManager{salt: _salt}(L2_BRIDGEHUB_ADDR, L2_INTEROP_CENTER_ADDR) ); } else { _deployedContracts.stateTransition.chainTypeManagerImplementation = address( - new EraChainTypeManager{salt: _salt}(L2_BRIDGEHUB_ADDR) + new EraChainTypeManager{salt: _salt}(L2_BRIDGEHUB_ADDR, L2_INTEROP_CENTER_ADDR) ); } diff --git a/l1-contracts/contracts/state-transition/chain-deps/ZKChainStorage.sol b/l1-contracts/contracts/state-transition/chain-deps/ZKChainStorage.sol index a05f7858e0..9d0695a5e9 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/ZKChainStorage.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/ZKChainStorage.sol @@ -165,6 +165,8 @@ struct ZKChainStorage { bytes32 baseTokenAssetId; /// @dev If this ZKchain settles on this chain, then this is zero. Otherwise it is the address of the ZKchain that is a /// settlement layer for this ZKchain. (think about it as a 'forwarding' address for the chain that migrated away). + /// @dev Note, that while we cannot trust the operator of the settlement layer, it is assumed that the settlement layer + /// belongs to the same CTM and has a trusted implementation, i.e., its implementation consists of the expected facets: Mailbox, Executor, etc. address settlementLayer; /// @dev Priority tree, the new data structure for priority queue PriorityTree.Tree priorityTree; @@ -182,4 +184,10 @@ struct ZKChainStorage { bool zksyncOS; /// @dev The scheme of L2 DA commitment. Different L1 validators may use different schemes. L2DACommitmentScheme l2DACommitmentScheme; + /// @dev The address of the asset tracker + address assetTracker; + /// @dev The address of the native token vault + address nativeTokenVault; + /// @dev Timestamp when deposits were paused for chain migration to/from Gateway. 0 = not paused. + uint256 pausedDepositsTimestamp; } diff --git a/l1-contracts/contracts/state-transition/chain-deps/facets/Admin.sol b/l1-contracts/contracts/state-transition/chain-deps/facets/Admin.sol index b00496abbb..fa99848c28 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/facets/Admin.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/facets/Admin.sol @@ -5,7 +5,7 @@ pragma solidity 0.8.28; import {IAdmin} from "../../chain-interfaces/IAdmin.sol"; import {IMailbox} from "../../chain-interfaces/IMailbox.sol"; import {Diamond} from "../../libraries/Diamond.sol"; -import {MAX_GAS_PER_TRANSACTION, ZKChainCommitment, L2DACommitmentScheme} from "../../../common/Config.sol"; +import {L1_SETTLEMENT_LAYER_VIRTUAL_ADDRESS, L2DACommitmentScheme, MAX_GAS_PER_TRANSACTION, ZKChainCommitment} from "../../../common/Config.sol"; import {FeeParams, PubdataPricingMode} from "../ZKChainStorage.sol"; import {PriorityTree} from "../../../state-transition/libraries/PriorityTree.sol"; import {PriorityQueue} from "../../../state-transition/libraries/PriorityQueue.sol"; @@ -14,15 +14,17 @@ import {IL1Bridgehub} from "../../../bridgehub/IL1Bridgehub.sol"; import {ZKChainBase} from "./ZKChainBase.sol"; import {IChainTypeManager} from "../../IChainTypeManager.sol"; import {IL1GenesisUpgrade} from "../../../upgrades/IL1GenesisUpgrade.sol"; -import {AlreadyPermanentRollup, DenominatorIsZero, DiamondAlreadyFrozen, DiamondNotFrozen, HashMismatch, InvalidDAForPermanentRollup, InvalidPubdataPricingMode, PriorityTxPubdataExceedsMaxPubDataPerBatch, NotAZKChain, ProtocolIdMismatch, ProtocolIdNotGreater, TooMuchGas, Unauthorized, InvalidL2DACommitmentScheme} from "../../../common/L1ContractErrors.sol"; -import {AlreadyMigrated, ContractNotDeployed, ExecutedIsNotConsistentWithVerified, InvalidNumberOfBatchHashes, L1DAValidatorAddressIsZero, NotAllBatchesExecuted, NotChainAdmin, NotEraChain, NotHistoricalRoot, NotL1, NotMigrated, OutdatedProtocolVersion, ProtocolVersionNotUpToDate, VerifiedIsNotConsistentWithCommitted} from "../../L1StateTransitionErrors.sol"; +import {IL1ChainAssetHandler} from "../../../bridgehub/IL1ChainAssetHandler.sol"; +import {AlreadyMigrated, PriorityQueueNotFullyProcessed, ContractNotDeployed, DepositsAlreadyPaused, DepositsNotPaused, ExecutedIsNotConsistentWithVerified, InvalidNumberOfBatchHashes, L1DAValidatorAddressIsZero, NotAllBatchesExecuted, NotChainAdmin, NotEraChain, NotHistoricalRoot, NotL1, NotMigrated, OutdatedProtocolVersion, ProtocolVersionNotUpToDate, VerifiedIsNotConsistentWithCommitted, MigrationInProgress} from "../../L1StateTransitionErrors.sol"; +import {AlreadyPermanentRollup, DenominatorIsZero, DiamondAlreadyFrozen, DiamondNotFrozen, HashMismatch, InvalidDAForPermanentRollup, InvalidL2DACommitmentScheme, InvalidPubdataPricingMode, NotAZKChain, PriorityTxPubdataExceedsMaxPubDataPerBatch, ProtocolIdMismatch, ProtocolIdNotGreater, TooMuchGas, Unauthorized} from "../../../common/L1ContractErrors.sol"; import {RollupDAManager} from "../../data-availability/RollupDAManager.sol"; import {L2_DEPLOYER_SYSTEM_CONTRACT_ADDR} from "../../../common/l2-helpers/L2ContractAddresses.sol"; import {AllowedBytecodeTypes, IL2ContractDeployer} from "../../../common/interfaces/IL2ContractDeployer.sol"; -import {L1_SETTLEMENT_LAYER_VIRTUAL_ADDRESS} from "../../../common/Config.sol"; +import {IL1AssetTracker} from "../../../bridge/asset-tracker/IL1AssetTracker.sol"; // While formally the following import is not used, it is needed to inherit documentation from it import {IZKChainBase} from "../../chain-interfaces/IZKChainBase.sol"; +import {TxStatus} from "../../../common/Messaging.sol"; /// @title Admin Contract controls access rights for contract management. /// @author Matter Labs @@ -41,16 +43,39 @@ contract AdminFacet is ZKChainBase, IAdmin { /// @notice The address that is responsible for determining whether a certain DA pair is allowed for rollups. RollupDAManager internal immutable ROLLUP_DA_MANAGER; - constructor(uint256 _l1ChainId, RollupDAManager _rollupDAManager) { + uint256 internal immutable CHAIN_MIGRATION_TIME_WINDOW_START; + + uint256 internal immutable CHAIN_MIGRATION_TIME_WINDOW_END; + + uint256 internal immutable PAUSE_DEPOSITS_TIME_WINDOW_START; + + uint256 internal immutable PAUSE_DEPOSITS_TIME_WINDOW_END; + + constructor( + uint256 _l1ChainId, + RollupDAManager _rollupDAManager, + uint256 _chainMigrationTimeWindowStart, + uint256 _chainMigrationTimeWindowEnd, + uint256 _pauseDepositsTimeWindowStart, + uint256 _pauseDepositsTimeWindowEnd + ) { L1_CHAIN_ID = _l1ChainId; ROLLUP_DA_MANAGER = _rollupDAManager; + CHAIN_MIGRATION_TIME_WINDOW_START = _chainMigrationTimeWindowStart; + CHAIN_MIGRATION_TIME_WINDOW_END = _chainMigrationTimeWindowEnd; + PAUSE_DEPOSITS_TIME_WINDOW_START = _pauseDepositsTimeWindowStart; + PAUSE_DEPOSITS_TIME_WINDOW_END = _pauseDepositsTimeWindowEnd; } modifier onlyL1() { + _onlyL1(); + _; + } + + function _onlyL1() internal { if (block.chainid != L1_CHAIN_ID) { revert NotL1(block.chainid); } - _; } /// @inheritdoc IAdmin @@ -293,6 +318,44 @@ contract AdminFacet is ZKChainBase, IAdmin { CHAIN MIGRATION //////////////////////////////////////////////////////////////*/ + /// @inheritdoc IAdmin + function pauseDepositsBeforeInitiatingMigration() external onlyAdminOrChainTypeManager onlyL1 { + require(s.pausedDepositsTimestamp + PAUSE_DEPOSITS_TIME_WINDOW_END < block.timestamp, DepositsAlreadyPaused()); + uint256 timestamp; + // Note, if the chain is new (total number of priority transactions is 0) we allow admin to pause the deposits with immediate effect. + // This is in place to allow for faster migration for newly spawned chains. + if (s.priorityTree.getTotalPriorityTxs() == 0) { + // We mark the start of pausedDeposits window as current timestamp - PAUSE_DEPOSITS_TIME_WINDOW_START, + // meaning that starting from this point in time the deposits are immediately paused. + timestamp = block.timestamp - PAUSE_DEPOSITS_TIME_WINDOW_START; + } else { + timestamp = block.timestamp; + } + s.pausedDepositsTimestamp = timestamp; + if (s.settlementLayer != address(0)) { + IL1AssetTracker(s.assetTracker).requestPauseDepositsForChainOnGateway(s.chainId, timestamp); + } + emit DepositsPaused(s.chainId, timestamp); + } + + /// @inheritdoc IAdmin + function unpauseDeposits() external onlyAdmin onlyL1 { + uint256 timestamp = s.pausedDepositsTimestamp; + bool inPausedWindow = timestamp + PAUSE_DEPOSITS_TIME_WINDOW_START <= block.timestamp && + block.timestamp < timestamp + PAUSE_DEPOSITS_TIME_WINDOW_END; + require(inPausedWindow, DepositsNotPaused()); + require( + !IL1ChainAssetHandler(IL1Bridgehub(s.bridgehub).chainAssetHandler()).isMigrationInProgress(s.chainId), + MigrationInProgress() + ); + _unpauseDeposits(); + } + + function _unpauseDeposits() internal { + s.pausedDepositsTimestamp = 0; + emit DepositsUnpaused(s.chainId); + } + /// @inheritdoc IAdmin function forwardedBridgeBurn( address _settlementLayer, @@ -306,6 +369,16 @@ contract AdminFacet is ZKChainBase, IAdmin { revert NotChainAdmin(_originalCaller, s.admin); } + /// We require that all the priority transactions are processed. + require(s.priorityTree.getSize() == 0, PriorityQueueNotFullyProcessed()); + + uint256 timestamp = s.pausedDepositsTimestamp; + require( + timestamp + CHAIN_MIGRATION_TIME_WINDOW_START < block.timestamp && + block.timestamp < timestamp + CHAIN_MIGRATION_TIME_WINDOW_END, + DepositsNotPaused() + ); + // We want to trust interop messages coming from Era chains which implies they can use only trusted settlement layers, // ie, controlled by the governance, which is currently Era Gateways and Ethereum. // Otherwise a malicious settlement layer could forge an interop message from an Era chain. @@ -328,12 +401,11 @@ contract AdminFacet is ZKChainBase, IAdmin { revert ProtocolVersionNotUpToDate(currentProtocolVersion, protocolVersion); } - if (block.chainid != L1_CHAIN_ID) { - // We assume that GW -> L1 transactions can never fail and provide no recovery mechanism from it. - // That's why we need to bound the gas that can be consumed during such a migration. - if (s.totalBatchesCommitted != s.totalBatchesExecuted) { - revert NotAllBatchesExecuted(); - } + // We require all committed batches to be executed, since each batch has a predefined settlement layer. + // Also we assume that GW -> L1 transactions can never fail and provide no recovery mechanism from it. + // That's why we need to bound the gas that can be consumed during a GW->L1 migration. + if (s.totalBatchesCommitted != s.totalBatchesExecuted) { + revert NotAllBatchesExecuted(); } s.settlementLayer = _settlementLayer; @@ -425,12 +497,18 @@ contract AdminFacet is ZKChainBase, IAdmin { } /// @inheritdoc IAdmin - function forwardedBridgeRecoverFailedTransfer( + function forwardedBridgeConfirmTransferResult( uint256 /* _chainId */, + TxStatus _txStatus, bytes32 /* _assetInfo */, address /* _depositSender */, bytes calldata _chainData ) external payable override onlyChainAssetHandler { + _unpauseDeposits(); + + if (_txStatus == TxStatus.Success) { + return; + } // As of now all we need in this function is the chainId so we encode it and pass it down in the _chainData field uint256 protocolVersion = abi.decode(_chainData, (uint256)); diff --git a/l1-contracts/contracts/state-transition/chain-deps/facets/Executor.sol b/l1-contracts/contracts/state-transition/chain-deps/facets/Executor.sol index 993b7c2346..3f50a02aef 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/facets/Executor.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/facets/Executor.sol @@ -3,24 +3,23 @@ pragma solidity 0.8.28; import {ZKChainBase} from "./ZKChainBase.sol"; -import {IL1Bridgehub} from "../../../bridgehub/IL1Bridgehub.sol"; +import {IBridgehubBase} from "../../../bridgehub/IBridgehubBase.sol"; import {IMessageRoot} from "../../../bridgehub/IMessageRoot.sol"; -import {L2MessageRoot} from "../../../bridgehub/L2MessageRoot.sol"; -import {COMMIT_TIMESTAMP_APPROXIMATION_DELTA, EMPTY_STRING_KECCAK, L2_TO_L1_LOG_SERIALIZE_SIZE, MAINNET_CHAIN_ID, MAINNET_COMMIT_TIMESTAMP_NOT_OLDER, MAX_L2_TO_L1_LOGS_COMMITMENT_BYTES, PACKED_L2_BLOCK_TIMESTAMP_MASK, PUBLIC_INPUT_SHIFT, TESTNET_COMMIT_TIMESTAMP_NOT_OLDER, DEFAULT_PRECOMMITMENT_FOR_THE_LAST_BATCH, PACKED_L2_PRECOMMITMENT_LENGTH} from "../../../common/Config.sol"; -import {IExecutor, L2_LOG_ADDRESS_OFFSET, L2_LOG_KEY_OFFSET, L2_LOG_VALUE_OFFSET, LogProcessingOutput, MAX_LOG_KEY, SystemLogKey, TOTAL_BLOBS_IN_COMMITMENT} from "../../chain-interfaces/IExecutor.sol"; +import {COMMIT_TIMESTAMP_APPROXIMATION_DELTA, DEFAULT_PRECOMMITMENT_FOR_THE_LAST_BATCH, EMPTY_STRING_KECCAK, L2_TO_L1_LOG_SERIALIZE_SIZE, MAINNET_CHAIN_ID, MAINNET_COMMIT_TIMESTAMP_NOT_OLDER, MAX_L2_TO_L1_LOGS_COMMITMENT_BYTES, PACKED_L2_BLOCK_TIMESTAMP_MASK, PACKED_L2_PRECOMMITMENT_LENGTH, PUBLIC_INPUT_SHIFT, TESTNET_COMMIT_TIMESTAMP_NOT_OLDER, DEFAULT_PRECOMMITMENT_FOR_THE_LAST_BATCH, PACKED_L2_PRECOMMITMENT_LENGTH} from "../../../common/Config.sol"; +import {IExecutor, L2_LOG_ADDRESS_OFFSET, L2_LOG_KEY_OFFSET, L2_LOG_VALUE_OFFSET, LogProcessingOutput, MAX_LOG_KEY, ProcessLogsInput, SystemLogKey, TOTAL_BLOBS_IN_COMMITMENT} from "../../chain-interfaces/IExecutor.sol"; import {BatchDecoder} from "../../libraries/BatchDecoder.sol"; import {UncheckedMath} from "../../../common/libraries/UncheckedMath.sol"; import {UnsafeBytes} from "../../../common/libraries/UnsafeBytes.sol"; -import {L2_BOOTLOADER_ADDRESS, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from "../../../common/l2-helpers/L2ContractAddresses.sol"; +import {GW_ASSET_TRACKER, L2_BOOTLOADER_ADDRESS, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from "../../../common/l2-helpers/L2ContractAddresses.sol"; import {IChainTypeManager} from "../../IChainTypeManager.sol"; import {PriorityOpsBatchInfo, PriorityTree} from "../../libraries/PriorityTree.sol"; import {IL1DAValidator, L1DAValidatorOutput} from "../../chain-interfaces/IL1DAValidator.sol"; -import {IncorrectBatchChainId, BatchHashMismatch, BatchNumberMismatch, CanOnlyProcessOneBatch, CantExecuteUnprovenBatches, CantRevertExecutedBatch, HashMismatch, InvalidLogSender, InvalidMessageRoot, InvalidNumberOfBlobs, InvalidProof, InvalidProtocolVersion, InvalidSystemLogsLength, L2TimestampTooBig, LogAlreadyProcessed, MissingSystemLogs, NonIncreasingTimestamp, NonSequentialBatch, PriorityOperationsRollingHashMismatch, RevertedBatchNotAfterNewLastBatch, SystemLogsSizeTooBig, TimeNotReached, TimestampError, TxHashMismatch, UnexpectedSystemLog, UpgradeBatchNumberIsNotZero, ValueMismatch, VerifiedBatchesExceedsCommittedBatches, InvalidBatchNumber, EmptyPrecommitData, PrecommitmentMismatch, InvalidPackedPrecommitmentLength, NonZeroBlobToVerifyZKsyncOS} from "../../../common/L1ContractErrors.sol"; -import {CommitBasedInteropNotSupported, DependencyRootsRollingHashMismatch, InvalidBatchesDataLength, MessageRootIsZero, MismatchNumberOfLayer1Txs, MismatchL2DACommitmentScheme} from "../../L1StateTransitionErrors.sol"; +import {BatchHashMismatch, BatchNumberMismatch, CanOnlyProcessOneBatch, CantExecuteUnprovenBatches, CantRevertExecutedBatch, EmptyPrecommitData, HashMismatch, IncorrectBatchChainId, InvalidBatchNumber, InvalidLogSender, InvalidMessageRoot, InvalidNumberOfBlobs, InvalidPackedPrecommitmentLength, InvalidProof, InvalidProtocolVersion, InvalidSystemLogsLength, L2TimestampTooBig, LogAlreadyProcessed, MissingSystemLogs, NonIncreasingTimestamp, NonSequentialBatch, PrecommitmentMismatch, PriorityOperationsRollingHashMismatch, RevertedBatchNotAfterNewLastBatch, SystemLogsSizeTooBig, TimeNotReached, TimestampError, TxHashMismatch, UnexpectedSystemLog, UpgradeBatchNumberIsNotZero, ValueMismatch, VerifiedBatchesExceedsCommittedBatches, InvalidBatchNumber, EmptyPrecommitData, PrecommitmentMismatch, InvalidPackedPrecommitmentLength, NonZeroBlobToVerifyZKsyncOS} from "../../../common/L1ContractErrors.sol"; +import {CommitBasedInteropNotSupported, DependencyRootsRollingHashMismatch, InvalidBatchesDataLength, MessageRootIsZero, MismatchL2DACommitmentScheme, MismatchNumberOfLayer1Txs, SettlementLayerChainIdMismatch} from "../../L1StateTransitionErrors.sol"; // While formally the following import is not used, it is needed to inherit documentation from it import {IZKChainBase} from "../../chain-interfaces/IZKChainBase.sol"; -import {InteropRoot} from "../../../common/Messaging.sol"; +import {InteropRoot, L2Log} from "../../../common/Messaging.sol"; /// @dev The version that is used for the `Executor` calldata used for relaying the /// stored batch info. @@ -292,7 +291,6 @@ contract ExecutorFacet is ZKChainBase, IExecutor { } uint256 lastL2BlockTimestamp = _packedBatchAndL2BlockTimestamp & PACKED_L2_BLOCK_TIMESTAMP_MASK; - // All L2 blocks have timestamps within the range of [batchTimestamp, lastL2BlockTimestamp]. // So here we need to only double check that: // - The timestamp of the batch is not too small. @@ -399,6 +397,12 @@ contract ExecutorFacet is ZKChainBase, IExecutor { revert InvalidLogSender(logSender, logKey); } logOutput.dependencyRootsRollingHash = logValue; + } else if (logKey == uint256(SystemLogKey.SETTLEMENT_LAYER_CHAIN_ID_KEY)) { + if (logSender != L2_BOOTLOADER_ADDRESS) { + revert InvalidLogSender(logSender, logKey); + } + uint256 settlementLayerChainId = uint256(logValue); + require(settlementLayerChainId == block.chainid, SettlementLayerChainIdMismatch()); } else if (logKey > MAX_LOG_KEY) { revert UnexpectedSystemLog(logKey); } @@ -486,6 +490,25 @@ contract ExecutorFacet is ZKChainBase, IExecutor { } } + /// @dev Checks that the batch hash is correct and matches the expected hash. + /// @param _lastCommittedBatchData The last committed batch. + /// @param _batchNumber The batch number to check. + /// @param _checkLegacy Whether to check the legacy hash. + function _checkBatchHashMismatch( + StoredBatchInfo memory _lastCommittedBatchData, + uint256 _batchNumber, + bool _checkLegacy + ) internal view { + bytes32 cachedStoredBatchHashes = s.storedBatchHashes[_batchNumber]; + if ( + cachedStoredBatchHashes != _hashStoredBatchInfo(_lastCommittedBatchData) && + (!_checkLegacy || cachedStoredBatchHashes != _hashLegacyStoredBatchInfo(_lastCommittedBatchData)) + ) { + // incorrect previous batch data + revert BatchHashMismatch(cachedStoredBatchHashes, _hashStoredBatchInfo(_lastCommittedBatchData)); + } + } + function _commitBatchesSharedBridgeEra( uint256 _processFrom, uint256 _processTo, @@ -500,25 +523,27 @@ contract ExecutorFacet is ZKChainBase, IExecutor { revert CanOnlyProcessOneBatch(); } // Check that we commit batches after last committed batch - bytes32 cachedStoredBatchHashes = s.storedBatchHashes[s.totalBatchesCommitted]; - if ( - cachedStoredBatchHashes != _hashStoredBatchInfo(lastCommittedBatchData) && - cachedStoredBatchHashes != _hashLegacyStoredBatchInfo(lastCommittedBatchData) - ) { - // incorrect previous batch data - revert BatchHashMismatch(cachedStoredBatchHashes, _hashStoredBatchInfo(lastCommittedBatchData)); - } + _checkBatchHashMismatch(lastCommittedBatchData, s.totalBatchesCommitted, true); bytes32 systemContractsUpgradeTxHash = s.l2SystemContractsUpgradeTxHash; // Upgrades are rarely done so we optimize a case with no active system contracts upgrade. if (systemContractsUpgradeTxHash == bytes32(0) || s.l2SystemContractsUpgradeBatchNumber != 0) { - _commitBatchesWithoutSystemContractsUpgrade(lastCommittedBatchData, newBatchesData); + _commitBatchesEra(lastCommittedBatchData, newBatchesData, bytes32(0)); } else { - _commitBatchesWithSystemContractsUpgrade( - lastCommittedBatchData, - newBatchesData, - systemContractsUpgradeTxHash - ); + // The system contract upgrade is designed to be executed atomically with the new bootloader, a default account, + // ZKP verifier, and other system parameters. Hence, we ensure that the upgrade transaction is + // carried out within the first batch committed after the upgrade. + + // While the logic of the contract ensures that the s.l2SystemContractsUpgradeBatchNumber is 0 when this branch is entered, + // this check is added just in case. Since it is a hot read, it does not incur noticeable gas cost. + if (s.l2SystemContractsUpgradeBatchNumber != 0) { + revert UpgradeBatchNumberIsNotZero(); + } + + // Save the batch number where the upgrade transaction was executed. + s.l2SystemContractsUpgradeBatchNumber = newBatchesData[0].batchNumber; + + _commitBatchesEra(lastCommittedBatchData, newBatchesData, systemContractsUpgradeTxHash); } s.totalBatchesCommitted = s.totalBatchesCommitted + newBatchesData.length; @@ -538,13 +563,7 @@ contract ExecutorFacet is ZKChainBase, IExecutor { revert CanOnlyProcessOneBatch(); } // Check that we commit batches after last committed batch - if (s.storedBatchHashes[s.totalBatchesCommitted] != _hashStoredBatchInfo(lastCommittedBatchData)) { - // incorrect previous batch data - revert BatchHashMismatch( - s.storedBatchHashes[s.totalBatchesCommitted], - _hashStoredBatchInfo(lastCommittedBatchData) - ); - } + _checkBatchHashMismatch(lastCommittedBatchData, s.totalBatchesCommitted, false); bytes32 systemContractsUpgradeTxHash = s.l2SystemContractsUpgradeTxHash; bool processSystemUpgradeTx = systemContractsUpgradeTxHash != bytes32(0) && @@ -578,58 +597,22 @@ contract ExecutorFacet is ZKChainBase, IExecutor { } } - /// @dev Commits new batches without any system contracts upgrade. + /// @dev Commits new batches, optionally handling a system contracts upgrade transaction. /// @param _lastCommittedBatchData The data of the last committed batch. /// @param _newBatchesData An array of batch data that needs to be committed. - function _commitBatchesWithoutSystemContractsUpgrade( - StoredBatchInfo memory _lastCommittedBatchData, - CommitBatchInfo[] memory _newBatchesData - ) internal { - // We disable this check because calldata array length is cheap. - // solhint-disable-next-line gas-length-in-loops - for (uint256 i = 0; i < _newBatchesData.length; i = i.uncheckedInc()) { - _lastCommittedBatchData = _commitOneBatch(_lastCommittedBatchData, _newBatchesData[i], bytes32(0)); - - s.storedBatchHashes[_lastCommittedBatchData.batchNumber] = _hashStoredBatchInfo(_lastCommittedBatchData); - emit BlockCommit( - _lastCommittedBatchData.batchNumber, - _lastCommittedBatchData.batchHash, - _lastCommittedBatchData.commitment - ); - } - } - - /// @dev Commits new batches with a system contracts upgrade transaction. - /// @param _lastCommittedBatchData The data of the last committed batch. - /// @param _newBatchesData An array of batch data that needs to be committed. - /// @param _systemContractUpgradeTxHash The transaction hash of the system contract upgrade. - function _commitBatchesWithSystemContractsUpgrade( + /// @param _systemContractUpgradeTxHash The transaction hash of the system contract upgrade (bytes32(0) if none). + function _commitBatchesEra( StoredBatchInfo memory _lastCommittedBatchData, CommitBatchInfo[] memory _newBatchesData, bytes32 _systemContractUpgradeTxHash ) internal { - // The system contract upgrade is designed to be executed atomically with the new bootloader, a default account, - // ZKP verifier, and other system parameters. Hence, we ensure that the upgrade transaction is - // carried out within the first batch committed after the upgrade. - - // While the logic of the contract ensures that the s.l2SystemContractsUpgradeBatchNumber is 0 when this function is called, - // this check is added just in case. Since it is a hot read, it does not incur noticeable gas cost. - if (s.l2SystemContractsUpgradeBatchNumber != 0) { - revert UpgradeBatchNumberIsNotZero(); - } - - // Save the batch number where the upgrade transaction was executed. - s.l2SystemContractsUpgradeBatchNumber = _newBatchesData[0].batchNumber; - // We disable this check because calldata array length is cheap. // solhint-disable-next-line gas-length-in-loops for (uint256 i = 0; i < _newBatchesData.length; i = i.uncheckedInc()) { - // The upgrade transaction must only be included in the first batch. - bytes32 expectedUpgradeTxHash = i == 0 ? _systemContractUpgradeTxHash : bytes32(0); _lastCommittedBatchData = _commitOneBatch( _lastCommittedBatchData, _newBatchesData[i], - expectedUpgradeTxHash + _systemContractUpgradeTxHash ); s.storedBatchHashes[_lastCommittedBatchData.batchNumber] = _hashStoredBatchInfo(_lastCommittedBatchData); @@ -638,6 +621,11 @@ contract ExecutorFacet is ZKChainBase, IExecutor { _lastCommittedBatchData.batchHash, _lastCommittedBatchData.commitment ); + + if (i == 0) { + // The upgrade transaction must only be included in the first batch. + _systemContractUpgradeTxHash = bytes32(0); + } } } @@ -703,9 +691,7 @@ contract ExecutorFacet is ZKChainBase, IExecutor { if (currentBatchNumber != s.totalBatchesExecuted + _executedBatchIdx + 1) { revert NonSequentialBatch(); } - if (_hashStoredBatchInfo(_storedBatch) != s.storedBatchHashes[currentBatchNumber]) { - revert BatchHashMismatch(s.storedBatchHashes[currentBatchNumber], _hashStoredBatchInfo(_storedBatch)); - } + _checkBatchHashMismatch(_storedBatch, currentBatchNumber, false); if (_priorityOperationsHash != _storedBatch.priorityOperationsHash) { revert PriorityOperationsRollingHashMismatch(); } @@ -739,7 +725,6 @@ contract ExecutorFacet is ZKChainBase, IExecutor { // Save root hash of L2 -> L1 logs tree s.l2LogsRootHashes[currentBatchNumber] = _storedBatch.l2LogsTreeRoot; - _appendMessageRoot(currentBatchNumber, _storedBatch.l2LogsTreeRoot); } /// @notice Verifies the dependency message roots that the chain relied on. @@ -747,7 +732,7 @@ contract ExecutorFacet is ZKChainBase, IExecutor { InteropRoot[] memory _dependencyRoots ) internal view returns (bytes32 dependencyRootsRollingHash) { uint256 length = _dependencyRoots.length; - IMessageRoot messageRootContract = IL1Bridgehub(s.bridgehub).messageRoot(); + IMessageRoot messageRootContract = IBridgehubBase(s.bridgehub).messageRoot(); for (uint256 i = 0; i < length; i = i.uncheckedInc()) { InteropRoot memory interopRoot = _dependencyRoots[i]; @@ -780,17 +765,11 @@ contract ExecutorFacet is ZKChainBase, IExecutor { /// @notice Appends the batch message root to the global message. /// @param _batchNumber The number of the batch /// @param _messageRoot The root of the merkle tree of the messages to L1. - /// @dev The logic of this function depends on the settlement layer as we support - /// message root aggregation only on non-L1 settlement layers for ease for migration. + /// @dev We only call this function on L1. function _appendMessageRoot(uint256 _batchNumber, bytes32 _messageRoot) internal { - // During migration to the new protocol version, there will be a period when - // the bridgehub does not yet provide the `messageRoot` functionality. - // To ease up the migration, we never append messages to message root on L1. - if (block.chainid != L1_CHAIN_ID) { - // Once the batch is executed, we include its message to the message root. - L2MessageRoot messageRootContract = L2MessageRoot(address(IL1Bridgehub(s.bridgehub).messageRoot())); - messageRootContract.addChainBatchRoot(s.chainId, _batchNumber, _messageRoot); - } + // Once the batch is executed, we include its message to the message root. + IMessageRoot messageRootContract = IBridgehubBase(s.bridgehub).messageRoot(); + messageRootContract.addChainBatchRoot(s.chainId, _batchNumber, _messageRoot); } /// @inheritdoc IExecutor @@ -803,12 +782,48 @@ contract ExecutorFacet is ZKChainBase, IExecutor { ( StoredBatchInfo[] memory batchesData, PriorityOpsBatchInfo[] memory priorityOpsData, - InteropRoot[][] memory dependencyRoots + InteropRoot[][] memory dependencyRoots, + L2Log[][] memory logs, + bytes[][] memory messages, + bytes32[] memory messageRoots ) = BatchDecoder.decodeAndCheckExecuteData(_executeData, _processFrom, _processTo); uint256 nBatches = batchesData.length; if (batchesData.length != priorityOpsData.length) { revert InvalidBatchesDataLength(batchesData.length, priorityOpsData.length); } + if (block.chainid == L1_CHAIN_ID) { + require(logs.length == 0, InvalidBatchesDataLength(0, logs.length)); + require(messages.length == 0, InvalidBatchesDataLength(0, messages.length)); + } else { + require(batchesData.length == logs.length, InvalidBatchesDataLength(batchesData.length, logs.length)); + require( + batchesData.length == messages.length, + InvalidBatchesDataLength(batchesData.length, messages.length) + ); + } + + // Interop is only allowed on GW currently, so we go through the Asset Tracker when on Gateway. + // When on L1, we append directly to the Message Root, though interop is not allowed there, it is only used for + // message verification. + if (block.chainid != L1_CHAIN_ID) { + uint256 messagesLength = messages.length; + for (uint256 i = 0; i < messagesLength; i = i.uncheckedInc()) { + ProcessLogsInput memory processLogsInput = ProcessLogsInput({ + logs: logs[i], + messages: messages[i], + chainId: s.chainId, + batchNumber: batchesData[i].batchNumber, + chainBatchRoot: batchesData[i].l2LogsTreeRoot, + messageRoot: messageRoots[i] + }); + GW_ASSET_TRACKER.processLogsAndMessages(processLogsInput); + } + } else { + uint256 batchesDataLength = batchesData.length; + for (uint256 i = 0; i < batchesDataLength; i = i.uncheckedInc()) { + _appendMessageRoot(batchesData[i].batchNumber, batchesData[i].l2LogsTreeRoot); + } + } for (uint256 i = 0; i < nBatches; i = i.uncheckedInc()) { _executeOneBatch(batchesData[i], priorityOpsData[i], dependencyRoots[i], i); @@ -849,24 +864,13 @@ contract ExecutorFacet is ZKChainBase, IExecutor { uint256[] memory proofPublicInput = new uint256[](committedBatchesLength); // Check that the batch passed by the validator is indeed the first unverified batch - bytes32 cachedStoredBatchHashes = s.storedBatchHashes[currentTotalBatchesVerified]; - if ( - _hashStoredBatchInfo(prevBatch) != cachedStoredBatchHashes && - _hashLegacyStoredBatchInfo(prevBatch) != cachedStoredBatchHashes - ) { - revert BatchHashMismatch(cachedStoredBatchHashes, _hashStoredBatchInfo(prevBatch)); - } + _checkBatchHashMismatch(prevBatch, currentTotalBatchesVerified, true); bytes32 prevBatchCommitment = prevBatch.commitment; bytes32 prevBatchStateCommitment = prevBatch.batchHash; for (uint256 i = 0; i < committedBatchesLength; i = i.uncheckedInc()) { currentTotalBatchesVerified = currentTotalBatchesVerified.uncheckedInc(); - if (_hashStoredBatchInfo(committedBatches[i]) != s.storedBatchHashes[currentTotalBatchesVerified]) { - revert BatchHashMismatch( - s.storedBatchHashes[currentTotalBatchesVerified], - _hashStoredBatchInfo(committedBatches[i]) - ); - } + _checkBatchHashMismatch(committedBatches[i], currentTotalBatchesVerified, false); bytes32 currentBatchCommitment = committedBatches[i].commitment; bytes32 currentBatchStateCommitment = committedBatches[i].batchHash; diff --git a/l1-contracts/contracts/state-transition/chain-deps/facets/Mailbox.sol b/l1-contracts/contracts/state-transition/chain-deps/facets/Mailbox.sol index d4f7105590..3cf9811d4e 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/facets/Mailbox.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/facets/Mailbox.sol @@ -6,14 +6,14 @@ import {Math} from "@openzeppelin/contracts-v4/utils/math/Math.sol"; import {IMailbox} from "../../chain-interfaces/IMailbox.sol"; import {IMailboxImpl} from "../../chain-interfaces/IMailboxImpl.sol"; +import {IInteropCenter} from "../../../interop/IInteropCenter.sol"; import {IBridgehubBase} from "../../../bridgehub/IBridgehubBase.sol"; -import {L2Bridgehub} from "../../../bridgehub/L2Bridgehub.sol"; import {ITransactionFilterer} from "../../chain-interfaces/ITransactionFilterer.sol"; import {IEIP7702Checker} from "../../chain-interfaces/IEIP7702Checker.sol"; import {PriorityTree} from "../../libraries/PriorityTree.sol"; import {TransactionValidator} from "../../libraries/TransactionValidator.sol"; -import {BridgehubL2TransactionRequest, L2CanonicalTransaction, L2Log, L2Message, TxStatus, WritePriorityOpParams} from "../../../common/Messaging.sol"; +import {BalanceChange, BridgehubL2TransactionRequest, L2CanonicalTransaction, L2Log, L2Message, TxStatus, WritePriorityOpParams} from "../../../common/Messaging.sol"; import {MessageHashing, ProofData} from "../../../common/libraries/MessageHashing.sol"; import {FeeParams, PubdataPricingMode} from "../ZKChainStorage.sol"; import {UncheckedMath} from "../../../common/libraries/UncheckedMath.sol"; @@ -21,16 +21,24 @@ import {L2ContractHelper} from "../../../common/l2-helpers/L2ContractHelper.sol" import {AddressAliasHelper} from "../../../vendor/AddressAliasHelper.sol"; import {ZKChainBase} from "./ZKChainBase.sol"; import {L1_GAS_PER_PUBDATA_BYTE, MAX_NEW_FACTORY_DEPS, PRIORITY_EXPIRATION, REQUIRED_L2_GAS_PRICE_PER_PUBDATA, SERVICE_TRANSACTION_SENDER, SETTLEMENT_LAYER_RELAY_SENDER} from "../../../common/Config.sol"; -import {L2_BOOTLOADER_ADDRESS, L2_BRIDGEHUB_ADDR} from "../../../common/l2-helpers/L2ContractAddresses.sol"; +import {L2_INTEROP_CENTER_ADDR} from "../../../common/l2-helpers/L2ContractAddresses.sol"; import {IL1AssetRouter} from "../../../bridge/asset-router/IL1AssetRouter.sol"; -import {AddressNotZero, BaseTokenGasPriceDenominatorNotSet, BatchNotExecuted, GasPerPubdataMismatch, InvalidChainId, MsgValueTooLow, OnlyEraSupported, TooManyFactoryDeps, TransactionNotAllowed, ZeroAddress} from "../../../common/L1ContractErrors.sol"; -import {LocalRootIsZero, LocalRootMustBeZero, NotHyperchain, NotL1, NotSettlementLayer} from "../../L1StateTransitionErrors.sol"; +import {AddressNotZero, BaseTokenGasPriceDenominatorNotSet, BatchNotExecuted, GasPerPubdataMismatch, InvalidChainId, MsgValueTooLow, NotAssetRouter, OnlyEraSupported, TooManyFactoryDeps, TransactionNotAllowed, ZeroAddress} from "../../../common/L1ContractErrors.sol"; +import {DepositsPaused, LocalRootIsZero, LocalRootMustBeZero, NotHyperchain, NotL1, NotSettlementLayer} from "../../L1StateTransitionErrors.sol"; +import {DepthMoreThanOneForRecursiveMerkleProof} from "../../../bridgehub/L1BridgehubErrors.sol"; // While formally the following import is not used, it is needed to inherit documentation from it import {IZKChainBase} from "../../chain-interfaces/IZKChainBase.sol"; -import {IMessageVerification, MessageVerification} from "./MessageVerification.sol"; +import {IMessageVerification, MessageVerification} from "../../../common/MessageVerification.sol"; +import {IL1AssetTracker} from "../../../bridge/asset-tracker/IL1AssetTracker.sol"; +import {BALANCE_CHANGE_VERSION} from "../../../bridge/asset-tracker/IAssetTrackerBase.sol"; +import {INativeTokenVaultBase} from "../../../bridge/ntv/INativeTokenVaultBase.sol"; +import {V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_GATEWAY} from "../../../bridgehub/IMessageRoot.sol"; +import {OnlyGateway} from "../../../bridgehub/L1BridgehubErrors.sol"; +import {IAdmin} from "../../chain-interfaces/IAdmin.sol"; +import {IL1ChainAssetHandler} from "../../../bridgehub/IL1ChainAssetHandler.sol"; /// @title ZKsync Mailbox contract providing interfaces for L1 <-> L2 interaction. /// @author Matter Labs @@ -52,6 +60,13 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { /// L1 that is at the most base layer. uint256 internal immutable L1_CHAIN_ID; + /// @dev The address of the L1ChainAssetHandler system contract. Only used on L1. + address internal immutable CHAIN_ASSET_HANDLER; + + uint256 internal immutable PAUSE_DEPOSITS_TIME_WINDOW_START; + + uint256 internal immutable PAUSE_DEPOSITS_TIME_WINDOW_END; + modifier onlyL1() { if (block.chainid != L1_CHAIN_ID) { revert NotL1(block.chainid); @@ -59,7 +74,21 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { _; } - constructor(uint256 _eraChainId, uint256 _l1ChainId, IEIP7702Checker _eip7702Checker) { + modifier onlyGateway() { + if (block.chainid == L1_CHAIN_ID) { + revert OnlyGateway(); + } + _; + } + + constructor( + uint256 _eraChainId, + uint256 _l1ChainId, + address _chainAssetHandler, + IEIP7702Checker _eip7702Checker, + uint256 _pauseDepositsTimeWindowStart, + uint256 _pauseDepositsTimeWindowEnd + ) { if (address(_eip7702Checker) == address(0) && block.chainid == _l1ChainId) { revert ZeroAddress(); } else if (address(_eip7702Checker) != address(0) && block.chainid != _l1ChainId) { @@ -67,13 +96,16 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { } ERA_CHAIN_ID = _eraChainId; L1_CHAIN_ID = _l1ChainId; + CHAIN_ASSET_HANDLER = _chainAssetHandler; EIP_7702_CHECKER = _eip7702Checker; + PAUSE_DEPOSITS_TIME_WINDOW_START = _pauseDepositsTimeWindowStart; + PAUSE_DEPOSITS_TIME_WINDOW_END = _pauseDepositsTimeWindowEnd; } /// @inheritdoc IMailboxImpl function bridgehubRequestL2Transaction( BridgehubL2TransactionRequest calldata _request - ) external onlyBridgehub returns (bytes32 canonicalTxHash) { + ) external onlyBridgehubOrInteropCenter returns (bytes32 canonicalTxHash) { canonicalTxHash = _requestL2TransactionSender(_request); } @@ -110,7 +142,7 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { _chainId: s.chainId, _blockOrBatchNumber: _batchNumber, _index: _index, - _log: _l2MessageToLog(_message), + _log: MessageHashing._l2MessageToLog(_message), _proof: _proof }); } @@ -162,31 +194,15 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { bytes32[] calldata _merkleProof, TxStatus _status ) public view returns (bool) { - // Bootloader sends an L2 -> L1 log only after processing the L1 -> L2 transaction. - // Thus, we can verify that the L1 -> L2 transaction was included in the L2 batch with specified status. - // - // The semantics of such L2 -> L1 log is always: - // - sender = L2_BOOTLOADER_ADDRESS - // - key = hash(L1ToL2Transaction) - // - value = status of the processing transaction (1 - success & 0 - fail) - // - isService = true (just a conventional value) - // - l2ShardId = 0 (means that L1 -> L2 transaction was processed in a rollup shard, other shards are not available yet anyway) - // - txNumberInBatch = number of transaction in the batch - L2Log memory l2Log = L2Log({ - l2ShardId: 0, - isService: true, - txNumberInBatch: _l2TxNumberInBatch, - sender: L2_BOOTLOADER_ADDRESS, - key: _l2TxHash, - value: bytes32(uint256(_status)) - }); return - _proveL2LogInclusion({ + proveL1ToL2TransactionStatusShared({ _chainId: s.chainId, - _blockOrBatchNumber: _l2BatchNumber, - _index: _l2MessageIndex, - _log: l2Log, - _proof: _merkleProof + _l2TxHash: _l2TxHash, + _l2BatchNumber: _l2BatchNumber, + _l2MessageIndex: _l2MessageIndex, + _l2TxNumberInBatch: _l2TxNumberInBatch, + _merkleProof: _merkleProof, + _status: _status }); } @@ -221,19 +237,20 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { return _proveL2LeafInclusion({ _chainId: s.chainId, - _batchNumber: _batchNumber, + _blockOrBatchNumber: _batchNumber, _leafProofMask: _leafProofMask, _leaf: _leaf, _proof: _proof }); } - function _proveL2LeafInclusion( + function _proveL2LeafInclusionRecursive( uint256 _chainId, uint256 _batchNumber, uint256 _leafProofMask, bytes32 _leaf, - bytes32[] calldata _proof + bytes32[] calldata _proof, + uint256 _depth ) internal view override returns (bool) { ProofData memory proofData = MessageHashing._getProofData({ _chainId: _chainId, @@ -257,6 +274,9 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { } return correctBatchRoot == proofData.batchSettlementRoot; } + if (_depth == 1) { + revert DepthMoreThanOneForRecursiveMerkleProof(); + } if (s.l2LogsRootHashes[_batchNumber] != bytes32(0)) { revert LocalRootMustBeZero(); @@ -319,22 +339,58 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { } /// @inheritdoc IMailboxImpl - function requestL2TransactionToGatewayMailbox( + function requestL2TransactionToGatewayMailboxWithBalanceChange( uint256 _chainId, bytes32 _canonicalTxHash, - uint64 _expirationTimestamp - ) external override onlyL1 returns (bytes32 canonicalTxHash) { + uint64 _expirationTimestamp, + uint256 _baseTokenAmount, + bool _getBalanceChange + ) public override onlyL1 returns (bytes32 canonicalTxHash) { if (!IBridgehubBase(s.bridgehub).whitelistedSettlementLayers(s.chainId)) { revert NotSettlementLayer(); } if (IBridgehubBase(s.bridgehub).getZKChain(_chainId) != msg.sender) { revert NotHyperchain(); } + // We pause L1->GW->L2 deposits. + require(_checkV30UpgradeProcessed(_chainId), DepositsPaused()); + + BalanceChange memory balanceChange; + if (_getBalanceChange) { + IL1AssetTracker assetTracker = IL1AssetTracker(s.assetTracker); + INativeTokenVaultBase nativeTokenVault = INativeTokenVaultBase(s.nativeTokenVault); + + (bytes32 assetId, uint256 amount) = (assetTracker.consumeBalanceChange(s.chainId, _chainId)); + uint256 tokenOriginChainId = nativeTokenVault.originChainId(assetId); + address originToken = nativeTokenVault.originToken(assetId); + balanceChange = BalanceChange({ + version: BALANCE_CHANGE_VERSION, + // baseTokenAssetId is known on Gateway. + baseTokenAssetId: bytes32(0), + baseTokenAmount: _baseTokenAmount, + assetId: assetId, + amount: amount, + tokenOriginChainId: tokenOriginChainId, + originToken: originToken + }); + } else { + balanceChange = BalanceChange({ + version: BALANCE_CHANGE_VERSION, + // baseTokenAssetId is known on Gateway. + baseTokenAssetId: bytes32(0), + baseTokenAmount: _baseTokenAmount, + assetId: bytes32(0), + amount: 0, + tokenOriginChainId: 0, + originToken: address(0) + }); + } BridgehubL2TransactionRequest memory wrappedRequest = _wrapRequest({ _chainId: _chainId, _canonicalTxHash: _canonicalTxHash, - _expirationTimestamp: _expirationTimestamp + _expirationTimestamp: _expirationTimestamp, + _balanceChange: balanceChange }); canonicalTxHash = _requestL2TransactionFree(wrappedRequest); } @@ -343,7 +399,7 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { function bridgehubRequestL2TransactionOnGateway( bytes32 _canonicalTxHash, uint64 _expirationTimestamp - ) external override onlyBridgehub { + ) external override onlyBridgehubOrInteropCenter { _writePriorityOpHash(_canonicalTxHash, _expirationTimestamp); emit NewRelayedPriorityTransaction(_getTotalPriorityTxs(), _canonicalTxHash, _expirationTimestamp); emit NewPriorityRequestId(_getTotalPriorityTxs(), _canonicalTxHash); @@ -352,18 +408,19 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { function _wrapRequest( uint256 _chainId, bytes32 _canonicalTxHash, - uint64 _expirationTimestamp + uint64 _expirationTimestamp, + BalanceChange memory _balanceChange ) internal view returns (BridgehubL2TransactionRequest memory) { // solhint-disable-next-line func-named-parameters bytes memory data = abi.encodeCall( - L2Bridgehub.forwardTransactionOnGateway, - (_chainId, _canonicalTxHash, _expirationTimestamp) + IInteropCenter.forwardTransactionOnGatewayWithBalanceChange, + (_chainId, _canonicalTxHash, _expirationTimestamp, _balanceChange) ); return BridgehubL2TransactionRequest({ /// There is no sender for the wrapping, we use a virtual address. sender: SETTLEMENT_LAYER_RELAY_SENDER, - contractL2: L2_BRIDGEHUB_ADDR, + contractL2: L2_INTEROP_CENTER_ADDR, mintValue: 0, l2Value: 0, // Very large amount @@ -376,11 +433,11 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { }); } - /// @inheritdoc IMailboxImpl + /// @inheritdoc IMailboxImpl function requestL2ServiceTransaction( address _contractL2, bytes calldata _l2Calldata - ) external onlySelf returns (bytes32 canonicalTxHash) { + ) external onlyServiceTransaction onlyL1 returns (bytes32 canonicalTxHash) { canonicalTxHash = _requestL2TransactionFree( BridgehubL2TransactionRequest({ sender: SERVICE_TRANSACTION_SENDER, @@ -399,14 +456,21 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { if (s.settlementLayer != address(0)) { // slither-disable-next-line unused-return - IMailbox(s.settlementLayer).requestL2TransactionToGatewayMailbox({ + IMailbox(s.settlementLayer).requestL2TransactionToGatewayMailboxWithBalanceChange({ _chainId: s.chainId, _canonicalTxHash: canonicalTxHash, - _expirationTimestamp: uint64(block.timestamp + PRIORITY_EXPIRATION) + _expirationTimestamp: uint64(block.timestamp + PRIORITY_EXPIRATION), + _baseTokenAmount: 0, + _getBalanceChange: false }); } } + function pauseDepositsOnGateway(uint256 _timestamp) external onlyGatewayAssetTracker onlyGateway { + s.pausedDepositsTimestamp = _timestamp; + emit IAdmin.DepositsPaused(s.chainId, _timestamp); + } + function _requestL2TransactionSender( BridgehubL2TransactionRequest memory _request ) internal nonReentrant returns (bytes32 canonicalTxHash) { @@ -485,11 +549,16 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { _writePriorityOp(transaction, _params.request.factoryDeps, canonicalTxHash, _params.expirationTimestamp); if (s.settlementLayer != address(0)) { + address assetRouter = address(IBridgehubBase(s.bridgehub).assetRouter()); + bool getBalanceChange = _params.request.sender == AddressAliasHelper.applyL1ToL2Alias(assetRouter); + // slither-disable-next-line unused-return - IMailbox(s.settlementLayer).requestL2TransactionToGatewayMailbox({ + IMailbox(s.settlementLayer).requestL2TransactionToGatewayMailboxWithBalanceChange({ _chainId: s.chainId, _canonicalTxHash: canonicalTxHash, - _expirationTimestamp: _params.expirationTimestamp + _expirationTimestamp: _params.expirationTimestamp, + _baseTokenAmount: _params.request.mintValue, + _getBalanceChange: getBalanceChange }); } } @@ -554,6 +623,31 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { canonicalTxHash = keccak256(transactionEncoding); } + /// @notice Deposits are paused when a chain migrates to/from GW. + function depositsPaused() public view returns (bool) { + uint256 timestamp = s.pausedDepositsTimestamp; + /// We provide 3.5 days window to process all deposits. + /// After that, the deposits are not being processed for 3.5 days. + bool inPausedWindow = timestamp + PAUSE_DEPOSITS_TIME_WINDOW_START <= block.timestamp && + block.timestamp < timestamp + PAUSE_DEPOSITS_TIME_WINDOW_END; + return inPausedWindow || IL1ChainAssetHandler(CHAIN_ASSET_HANDLER).isMigrationInProgress(s.chainId); + } + + /// @notice Returns whether the chain has upgraded to V30 on GW. + /// if the chain is on L1 at V30, or is deployed V30 or after, then it returns true. + function _checkV30UpgradeProcessed(uint256 _chainId) internal view returns (bool) { + IBridgehubBase bridgehub = IBridgehubBase(s.bridgehub); + + if ( + bridgehub.messageRoot().v30UpgradeChainBatchNumber(_chainId) == + V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_GATEWAY + ) { + /// We pause deposits until the chain has upgraded on GW + return false; + } + return true; + } + /// @notice Stores a transaction record in storage & send event about that function _writePriorityOp( L2CanonicalTransaction memory _transaction, @@ -563,6 +657,11 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { ) internal { _writePriorityOpHash(_canonicalTxHash, _expirationTimestamp); + /// We only check deposits paused on L1 to keep the GW and L1 Priority queues the same. + if (block.chainid == L1_CHAIN_ID) { + require(!depositsPaused(), DepositsPaused()); + } + // Data that is needed for the operator to simulate priority queue offchain // solhint-disable-next-line func-named-parameters emit NewPriorityRequest(_transaction.nonce, _canonicalTxHash, _expirationTimestamp, _transaction, _factoryDeps); @@ -612,6 +711,8 @@ contract MailboxFacet is ZKChainBase, IMailboxImpl, MessageVerification { if (s.chainId != ERA_CHAIN_ID) { revert OnlyEraSupported(); } + address assetRouter = address(IBridgehubBase(s.bridgehub).assetRouter()); + require(msg.sender != assetRouter, NotAssetRouter(msg.sender, assetRouter)); canonicalTxHash = _requestL2TransactionSender( BridgehubL2TransactionRequest({ sender: msg.sender, diff --git a/l1-contracts/contracts/state-transition/chain-deps/facets/ZKChainBase.sol b/l1-contracts/contracts/state-transition/chain-deps/facets/ZKChainBase.sol index 93e94b27b4..1821a2779a 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/facets/ZKChainBase.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/facets/ZKChainBase.sol @@ -8,7 +8,9 @@ import {PriorityQueue} from "../../libraries/PriorityQueue.sol"; import {PriorityTree} from "../../libraries/PriorityTree.sol"; import {NotSettlementLayer} from "../../L1StateTransitionErrors.sol"; import {Unauthorized} from "../../../common/L1ContractErrors.sol"; +import {L2_INTEROP_CENTER_ADDR, GW_ASSET_TRACKER_ADDR} from "../../../common/l2-helpers/L2ContractAddresses.sol"; import {IL1Bridgehub} from "../../../bridgehub/IL1Bridgehub.sol"; +import {IBridgehubBase} from "../../../bridgehub/IBridgehubBase.sol"; import {PRIORITY_OPERATION_L2_TX_TYPE, SYSTEM_UPGRADE_L2_TX_TYPE, ZKSYNC_OS_PRIORITY_OPERATION_L2_TX_TYPE, ZKSYNC_OS_SYSTEM_UPGRADE_L2_TX_TYPE} from "../../../common/Config.sol"; /// @title Base contract containing functions accessible to the other facets. @@ -51,6 +53,20 @@ contract ZKChainBase is ReentrancyGuard { _; } + modifier onlyBridgehubOrInteropCenter() { + if ((msg.sender != s.bridgehub) && (msg.sender != L2_INTEROP_CENTER_ADDR)) { + revert Unauthorized(msg.sender); + } + _; + } + + modifier onlyGatewayAssetTracker() { + if (msg.sender != GW_ASSET_TRACKER_ADDR) { + revert Unauthorized(msg.sender); + } + _; + } + modifier onlyChainAssetHandler() { if (msg.sender != IL1Bridgehub(s.bridgehub).chainAssetHandler()) { revert Unauthorized(msg.sender); @@ -86,6 +102,26 @@ contract ZKChainBase is ReentrancyGuard { _; } + modifier onlyServiceTransaction() { + IBridgehubBase bridgehub = IBridgehubBase(s.bridgehub); + if ( + /// Purposes. + /// 1. Allow EVM emulation. + msg.sender != address(this) && + /// For registering chains in the L2Bridgehub. This is used for interop initiation. + msg.sender != bridgehub.chainRegistrationSender() && + /// For sending the token balance migration confirmation txs to L2s and the Gateway. + /// confirmMigrationOnL2, confirmMigrationOnGateway. + msg.sender != address(s.assetTracker) && + /// 1. For setting the legacy shared bridge in the L2Asset Tracker. + /// 2. Also for sending the demarcation txs for token balance migration. It might be deleted. + msg.sender != address(bridgehub.chainAssetHandler()) + ) { + revert Unauthorized(msg.sender); + } + _; + } + /// @notice Returns whether the priority queue is still active, i.e. /// the chain has not processed all transactions from it function _isPriorityQueueActive() internal view returns (bool) { diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IAdmin.sol b/l1-contracts/contracts/state-transition/chain-interfaces/IAdmin.sol index d45b830d0d..ffed31017e 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IAdmin.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/IAdmin.sol @@ -6,7 +6,8 @@ import {IZKChainBase} from "../chain-interfaces/IZKChainBase.sol"; import {Diamond} from "../libraries/Diamond.sol"; import {FeeParams, PubdataPricingMode} from "../chain-deps/ZKChainStorage.sol"; -import {ZKChainCommitment, L2DACommitmentScheme} from "../../common/Config.sol"; +import {L2DACommitmentScheme, ZKChainCommitment} from "../../common/Config.sol"; +import {TxStatus} from "../../common/Messaging.sol"; /// @title The interface of the Admin Contract that controls access rights for contract management. /// @author Matter Labs @@ -150,6 +151,16 @@ interface IAdmin is IZKChainBase { event BridgeMint(address indexed _account, uint256 _amount); + event DepositsPaused(uint256 chainId, uint256 pausedDepositsTimestamp); + + event DepositsUnpaused(uint256 chainId); + + /// @notice Pauses deposits before initiating migration to the Gateway. + function pauseDepositsBeforeInitiatingMigration() external; + + /// @notice Unpauses deposits, used after the chain is initialized + function unpauseDeposits() external; + /// @dev Similar to IL1AssetHandler interface, used to send chains. function forwardedBridgeBurn( address _settlementLayer, @@ -158,8 +169,9 @@ interface IAdmin is IZKChainBase { ) external payable returns (bytes memory _bridgeMintData); /// @dev Similar to IL1AssetHandler interface, used to claim failed chain transfers. - function forwardedBridgeRecoverFailedTransfer( + function forwardedBridgeConfirmTransferResult( uint256 _chainId, + TxStatus _txStatus, bytes32 _assetInfo, address _originalCaller, bytes calldata _chainData diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IDiamondInit.sol b/l1-contracts/contracts/state-transition/chain-interfaces/IDiamondInit.sol index 721e202513..a9428a91e1 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IDiamondInit.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/IDiamondInit.sol @@ -24,6 +24,7 @@ import {FeeParams} from "../chain-deps/ZKChainStorage.sol"; struct InitializeData { uint256 chainId; address bridgehub; + address interopCenter; address chainTypeManager; uint256 protocolVersion; address admin; diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IExecutor.sol b/l1-contracts/contracts/state-transition/chain-interfaces/IExecutor.sol index 0cfb937e24..1a4c6195c7 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IExecutor.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/IExecutor.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.21; import {IZKChainBase} from "./IZKChainBase.sol"; +import {L2Log} from "../../common/Messaging.sol"; import {L2DACommitmentScheme} from "../../common/Config.sol"; /// @dev Enum used by L2 System Contracts to differentiate logs. @@ -19,6 +20,7 @@ enum SystemLogKey { USED_L2_DA_VALIDATOR_ADDRESS_KEY, MESSAGE_ROOT_ROLLING_HASH_KEY, L2_TXS_STATUS_ROLLING_HASH_KEY, + SETTLEMENT_LAYER_CHAIN_ID_KEY, EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY } @@ -38,6 +40,16 @@ struct LogProcessingOutput { /// @dev Maximal value that SystemLogKey variable can have. uint256 constant MAX_LOG_KEY = uint256(type(SystemLogKey).max); +/// @notice The struct passed to the assetTracker. +struct ProcessLogsInput { + L2Log[] logs; + bytes[] messages; + uint256 chainId; + uint256 batchNumber; + bytes32 chainBatchRoot; + bytes32 messageRoot; +} + /// @dev Offset used to pull Address From Log. Equal to 4 (bytes for shardId, isService and txNumberInBatch) uint256 constant L2_LOG_ADDRESS_OFFSET = 4; diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IMailbox.sol b/l1-contracts/contracts/state-transition/chain-interfaces/IMailbox.sol index 80dbf7064d..d62be106d5 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IMailbox.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/IMailbox.sol @@ -2,7 +2,7 @@ // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.21; -import {IMessageVerification} from "./IMessageVerification.sol"; +import {IMessageVerification} from "../../common/interfaces/IMessageVerification.sol"; import {IMailboxImpl} from "./IMailboxImpl.sol"; /// @title The interface of the ZKsync Mailbox contract that provides interfaces for L1 <-> L2 interaction. diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IMailboxImpl.sol b/l1-contracts/contracts/state-transition/chain-interfaces/IMailboxImpl.sol index 4fb064b73d..9709d44123 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IMailboxImpl.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/IMailboxImpl.sol @@ -116,14 +116,24 @@ interface IMailboxImpl is IZKChainBase { bytes calldata _l2Calldata ) external returns (bytes32 canonicalTxHash); + /// @notice Pauses deposits on Gateway, needed as migration is only allowed with this timestamp. + function pauseDepositsOnGateway(uint256 _timestamp) external; + /// @dev On L1 we have to forward to the Gateway's mailbox which sends to the Bridgehub on the Gateway. + /// @dev Note that this function is callable by any chain, including potentially malicious ones, so all inputs + /// need to be validated (or ensured that their validation will happen on L2). /// @param _chainId the chainId of the chain. /// @param _canonicalTxHash the canonical transaction hash. /// @param _expirationTimestamp the expiration timestamp. - function requestL2TransactionToGatewayMailbox( + /// @param _baseTokenAmount the base token amount that is sent with the transaction. + /// @param _getBalanceChange whether a second token is passed with the transaction, + /// the amount of which will be fetched from the L1 asset tracker. If false it is not fetched for gas savings. + function requestL2TransactionToGatewayMailboxWithBalanceChange( uint256 _chainId, bytes32 _canonicalTxHash, - uint64 _expirationTimestamp + uint64 _expirationTimestamp, + uint256 _baseTokenAmount, + bool _getBalanceChange ) external returns (bytes32 canonicalTxHash); /// @notice Estimates the cost in Ether of requesting execution of an L2 transaction from L1. @@ -153,6 +163,10 @@ interface IMailboxImpl is IZKChainBase { bytes32[] calldata _proof ) external view returns (bool); + /// @notice Returns whether deposits are paused on the chain. + /// @return Whether deposits are paused on the chain. + function depositsPaused() external view returns (bool); + /// @notice New priority request event. Emitted when a request is placed into the priority queue. /// @param txId Serial number of the priority operation. /// @param txHash keccak256 hash of encoded transaction representation. diff --git a/l1-contracts/contracts/state-transition/l2-deps/IL2GatewayUpgrade.sol b/l1-contracts/contracts/state-transition/l2-deps/IL2GatewayUpgrade.sol deleted file mode 100644 index f58c43bdcf..0000000000 --- a/l1-contracts/contracts/state-transition/l2-deps/IL2GatewayUpgrade.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.28; - -import {IL2ContractDeployer} from "../../common/interfaces/IL2ContractDeployer.sol"; - -interface IL2GatewayUpgrade { - function upgrade( - IL2ContractDeployer.ForceDeployment[] calldata _forceDeployments, - address _ctmDeployer, - bytes calldata _fixedForceDeploymentsData, - bytes calldata _additionalForceDeploymentsData - ) external payable; -} diff --git a/l1-contracts/contracts/state-transition/l2-deps/IL2GenesisUpgrade.sol b/l1-contracts/contracts/state-transition/l2-deps/IL2GenesisUpgrade.sol index 22a406f39f..d4f3c023bc 100644 --- a/l1-contracts/contracts/state-transition/l2-deps/IL2GenesisUpgrade.sol +++ b/l1-contracts/contracts/state-transition/l2-deps/IL2GenesisUpgrade.sol @@ -25,6 +25,9 @@ struct ZKChainSpecificForceDeploymentsData { /// needed to deploy weth token in case it is not present string baseTokenName; string baseTokenSymbol; + uint256 baseTokenOriginChainId; + /// The address of the base token on the origin chain. + address baseTokenOriginAddress; } /// @notice The structure that describes force deployments that are the same for each chain. @@ -33,6 +36,7 @@ struct ZKChainSpecificForceDeploymentsData { // solhint-disable-next-line gas-struct-packing struct FixedForceDeploymentsData { uint256 l1ChainId; + uint256 gatewayChainId; uint256 eraChainId; address l1AssetRouter; bytes32 l2TokenProxyBytecodeHash; @@ -43,9 +47,13 @@ struct FixedForceDeploymentsData { bytes l2NtvBytecodeInfo; bytes messageRootBytecodeInfo; bytes chainAssetHandlerBytecodeInfo; + bytes interopCenterBytecodeInfo; + bytes interopHandlerBytecodeInfo; + bytes assetTrackerBytecodeInfo; bytes beaconDeployerInfo; address l2SharedBridgeLegacyImpl; address l2BridgedStandardERC20Impl; + address aliasedChainRegistrationSender; // The forced beacon address. It is needed only for internal testing. // MUST be equal to 0 in production. // It will be the job of the governance to ensure that this value is set correctly. diff --git a/l1-contracts/contracts/state-transition/libraries/BatchDecoder.sol b/l1-contracts/contracts/state-transition/libraries/BatchDecoder.sol index 2a508c017d..35176fda49 100644 --- a/l1-contracts/contracts/state-transition/libraries/BatchDecoder.sol +++ b/l1-contracts/contracts/state-transition/libraries/BatchDecoder.sol @@ -5,7 +5,7 @@ pragma solidity ^0.8.21; import {IExecutor} from "../chain-interfaces/IExecutor.sol"; import {PriorityOpsBatchInfo} from "./PriorityTree.sol"; import {EmptyData, IncorrectBatchBounds, UnsupportedCommitBatchEncoding, UnsupportedExecuteBatchEncoding, UnsupportedProofBatchEncoding} from "../../common/L1ContractErrors.sol"; -import {InteropRoot} from "../../common/Messaging.sol"; +import {InteropRoot, L2Log} from "../../common/Messaging.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -244,7 +244,10 @@ library BatchDecoder { returns ( IExecutor.StoredBatchInfo[] memory executeData, PriorityOpsBatchInfo[] memory priorityOpsData, - InteropRoot[][] memory dependencyRoots + InteropRoot[][] memory dependencyRoots, + L2Log[][] memory logs, + bytes[][] memory messages, + bytes32[] memory messageRoots ) { if (_executeData.length == 0) { @@ -253,9 +256,9 @@ library BatchDecoder { uint8 encodingVersion = uint8(_executeData[0]); if (encodingVersion == SUPPORTED_ENCODING_VERSION) { - (executeData, priorityOpsData, dependencyRoots) = abi.decode( + (executeData, priorityOpsData, dependencyRoots, logs, messages, messageRoots) = abi.decode( _executeData[1:], - (IExecutor.StoredBatchInfo[], PriorityOpsBatchInfo[], InteropRoot[][]) + (IExecutor.StoredBatchInfo[], PriorityOpsBatchInfo[], InteropRoot[][], L2Log[][], bytes[][], bytes32[]) ); } else { revert UnsupportedExecuteBatchEncoding(encodingVersion); @@ -280,10 +283,15 @@ library BatchDecoder { returns ( IExecutor.StoredBatchInfo[] memory executeData, PriorityOpsBatchInfo[] memory priorityOpsData, - InteropRoot[][] memory dependencyRoots + InteropRoot[][] memory dependencyRoots, + L2Log[][] memory logs, + bytes[][] memory messages, + bytes32[] memory messageRoots ) { - (executeData, priorityOpsData, dependencyRoots) = _decodeExecuteData(_executeData); + (executeData, priorityOpsData, dependencyRoots, logs, messages, messageRoots) = _decodeExecuteData( + _executeData + ); if (executeData.length == 0) { revert EmptyData(); diff --git a/l1-contracts/contracts/state-transition/libraries/PriorityTree.sol b/l1-contracts/contracts/state-transition/libraries/PriorityTree.sol index f930cf8aa1..7c4e658583 100644 --- a/l1-contracts/contracts/state-transition/libraries/PriorityTree.sol +++ b/l1-contracts/contracts/state-transition/libraries/PriorityTree.sol @@ -44,6 +44,7 @@ library PriorityTree { /// @notice Add the priority operation to the end of the priority queue function push(Tree storage _tree, bytes32 _hash) internal { + // slither-disable-next-line unused-return (, bytes32 newRoot) = _tree.tree.push(_hash); _tree.historicalRoots[newRoot] = true; } diff --git a/l1-contracts/contracts/state-transition/verifiers/EraTestnetVerifier.sol b/l1-contracts/contracts/state-transition/verifiers/EraTestnetVerifier.sol index c36f14162d..79f2892716 100644 --- a/l1-contracts/contracts/state-transition/verifiers/EraTestnetVerifier.sol +++ b/l1-contracts/contracts/state-transition/verifiers/EraTestnetVerifier.sol @@ -14,6 +14,7 @@ import {IVerifier} from "../chain-interfaces/IVerifier.sol"; /// otherwise, it will skip the verification. contract EraTestnetVerifier is IVerifier { EraDualVerifier public immutable dualVerifier; + bool public constant isTestnetVerifier = true; constructor(IVerifierV2 _fflonkVerifier, IVerifier _plonkVerifier) { assert(block.chainid != 1); diff --git a/l1-contracts/contracts/upgrades/BaseZkSyncUpgrade.sol b/l1-contracts/contracts/upgrades/BaseZkSyncUpgrade.sol index 439c496a5c..2b384a268e 100644 --- a/l1-contracts/contracts/upgrades/BaseZkSyncUpgrade.sol +++ b/l1-contracts/contracts/upgrades/BaseZkSyncUpgrade.sol @@ -10,9 +10,10 @@ import {L2ContractHelper} from "../common/l2-helpers/L2ContractHelper.sol"; import {TransactionValidator} from "../state-transition/libraries/TransactionValidator.sol"; import {MAX_ALLOWED_MINOR_VERSION_DELTA, MAX_NEW_FACTORY_DEPS} from "../common/Config.sol"; import {L2CanonicalTransaction} from "../common/Messaging.sol"; -import {InvalidTxType, L2UpgradeNonceNotEqualToNewProtocolVersion, NewProtocolMajorVersionNotZero, PatchCantSetUpgradeTxn, PatchUpgradeCantSetBootloader, PatchUpgradeCantSetDefaultAccount, PatchUpgradeCantSetEvmEmulator, PreviousProtocolMajorVersionNotZero, PreviousUpgradeNotCleaned, PreviousUpgradeNotFinalized, ProtocolVersionMinorDeltaTooBig, ProtocolVersionTooSmall} from "./ZkSyncUpgradeErrors.sol"; +import {InvalidTxType, L2UpgradeNonceNotEqualToNewProtocolVersion, NewProtocolMajorVersionNotZero, PatchCantSetUpgradeTxn, PatchUpgradeCantSetBootloader, PatchUpgradeCantSetDefaultAccount, PatchUpgradeCantSetEvmEmulator, PreviousProtocolMajorVersionNotZero, PreviousUpgradeNotCleaned, PreviousUpgradeNotFinalized, ProtocolVersionMinorDeltaTooBig, ProtocolVersionTooSmall, SettlementLayerUpgradeMustPrecedeChainUpgrade} from "./ZkSyncUpgradeErrors.sol"; import {TimeNotReached, TooManyFactoryDeps} from "../common/L1ContractErrors.sol"; import {SemVer} from "../common/libraries/SemVer.sol"; +import {IZKChain} from "../state-transition/chain-interfaces/IZKChain.sol"; /// @notice The struct that represents the upgrade proposal. /// @param l2ProtocolUpgradeTx The system upgrade transaction. @@ -41,6 +42,8 @@ struct ProposedUpgrade { uint256 newProtocolVersion; } +error UpgradeInnerFailed(); + /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev /// @notice Interface to which all the upgrade implementations should adhere @@ -75,7 +78,7 @@ abstract contract BaseZkSyncUpgrade is ZKChainBase { /// do not validate any variants about the upgrade transaction or generally don't do anything related to the upgrade transaction. /// Updates on diamond proxy located not on settlement layer are needed to ensure that the logic of the contracts remains compatible with /// the diamond proxy on the settlement layer and so are still needed to update facets, verifiers and so on. - function upgrade(ProposedUpgrade calldata _proposedUpgrade) public virtual returns (bytes32 txHash) { + function upgrade(ProposedUpgrade memory _proposedUpgrade) public virtual returns (bytes32 txHash) { // Note that due to commitment delay, the timestamp of the L2 upgrade batch may be earlier than the timestamp // of the L1 block at which the upgrade occurred. This means that using timestamp as a signifier of "upgraded" // on the L2 side would be inaccurate. The effects of this "back-dating" of L2 upgrade batches will be reduced @@ -86,6 +89,13 @@ abstract contract BaseZkSyncUpgrade is ZKChainBase { // If settlement layer is 0, it means that this diamond proxy is located on the settlement layer. bool isOnSettlementLayer = s.settlementLayer == address(0); + if (!isOnSettlementLayer) { + require( + _proposedUpgrade.newProtocolVersion <= IZKChain(s.settlementLayer).getProtocolVersion(), + SettlementLayerUpgradeMustPrecedeChainUpgrade() + ); + } + (uint32 newMinorVersion, bool isPatchOnly) = _setNewProtocolVersion( _proposedUpgrade.newProtocolVersion, isOnSettlementLayer @@ -194,7 +204,7 @@ abstract contract BaseZkSyncUpgrade is ZKChainBase { /// @notice Change the verifier parameters /// @param _newVerifierParams New parameters for the verifier - function _setVerifierParams(VerifierParams calldata _newVerifierParams) private { + function _setVerifierParams(VerifierParams memory _newVerifierParams) private { // An upgrade to the verifier params must be done carefully to ensure there aren't batches in the committed state // during the transition. If verifier is upgraded, it will immediately be used to prove all committed batches. // Batches committed expecting the old verifier params will fail. Ensure all committed batches are finalized before the @@ -215,7 +225,7 @@ abstract contract BaseZkSyncUpgrade is ZKChainBase { /// @notice Updates the verifier and the verifier params /// @param _newVerifier The address of the new verifier. If 0, the verifier will not be updated. /// @param _verifierParams The new verifier params. If all of the fields are 0, the params will not be updated. - function _upgradeVerifier(address _newVerifier, VerifierParams calldata _verifierParams) internal { + function _upgradeVerifier(address _newVerifier, VerifierParams memory _verifierParams) internal { _setVerifier(IVerifier(_newVerifier)); _setVerifierParams(_verifierParams); } @@ -244,7 +254,7 @@ abstract contract BaseZkSyncUpgrade is ZKChainBase { /// @param _patchOnly Whether only the patch part of the protocol version semver has changed. /// @return System contracts upgrade transaction hash. Zero if no upgrade transaction is set. function _setL2SystemContractUpgrade( - L2CanonicalTransaction calldata _l2ProtocolUpgradeTx, + L2CanonicalTransaction memory _l2ProtocolUpgradeTx, uint32 _newMinorProtocolVersion, bool _patchOnly ) internal returns (bytes32) { @@ -293,7 +303,7 @@ abstract contract BaseZkSyncUpgrade is ZKChainBase { /// @dev Note, that unlike normal L1->L2 transactions, factory dependencies for /// an upgrade transaction should be made available prior to the upgrade via publishing those /// to the `BytecodesSupplier` contract. - function _verifyFactoryDeps(uint256[] calldata _hashes) private pure { + function _verifyFactoryDeps(uint256[] memory _hashes) private pure { if (_hashes.length > MAX_NEW_FACTORY_DEPS) { revert TooManyFactoryDeps(); } @@ -362,11 +372,11 @@ abstract contract BaseZkSyncUpgrade is ZKChainBase { /// Typically this function will never be used. /// @param _customCallDataForUpgrade Custom data for an upgrade, which may be interpreted differently for each /// upgrade. - function _upgradeL1Contract(bytes calldata _customCallDataForUpgrade) internal virtual {} + function _upgradeL1Contract(bytes memory _customCallDataForUpgrade) internal virtual {} /// @notice placeholder function for custom logic for post-upgrade logic. /// Typically this function will never be used. /// @param _customCallDataForUpgrade Custom data for an upgrade, which may be interpreted differently for each /// upgrade. - function _postUpgrade(bytes calldata _customCallDataForUpgrade) internal virtual {} + function _postUpgrade(bytes memory _customCallDataForUpgrade) internal virtual {} } diff --git a/l1-contracts/contracts/upgrades/DefaultUpgrade.sol b/l1-contracts/contracts/upgrades/DefaultUpgrade.sol index bfd1241b69..48f979634c 100644 --- a/l1-contracts/contracts/upgrades/DefaultUpgrade.sol +++ b/l1-contracts/contracts/upgrades/DefaultUpgrade.sol @@ -10,7 +10,7 @@ import {BaseZkSyncUpgrade, ProposedUpgrade} from "./BaseZkSyncUpgrade.sol"; contract DefaultUpgrade is BaseZkSyncUpgrade { /// @notice The main function that will be delegate-called by the chain. /// @param _proposedUpgrade The upgrade to be executed. - function upgrade(ProposedUpgrade calldata _proposedUpgrade) public override returns (bytes32) { + function upgrade(ProposedUpgrade memory _proposedUpgrade) public override returns (bytes32) { super.upgrade(_proposedUpgrade); return Diamond.DIAMOND_INIT_SUCCESS_RETURN_VALUE; } diff --git a/l1-contracts/contracts/upgrades/GatewayUpgrade.sol b/l1-contracts/contracts/upgrades/GatewayUpgrade.sol deleted file mode 100644 index 3bafe9d16c..0000000000 --- a/l1-contracts/contracts/upgrades/GatewayUpgrade.sol +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.28; - -import {BaseZkSyncUpgrade, ProposedUpgrade} from "./BaseZkSyncUpgrade.sol"; - -import {DataEncoding} from "../common/libraries/DataEncoding.sol"; - -import {Diamond} from "../state-transition/libraries/Diamond.sol"; -import {PriorityQueue} from "../state-transition/libraries/PriorityQueue.sol"; -import {PriorityTree} from "../state-transition/libraries/PriorityTree.sol"; -import {GatewayUpgradeFailed} from "./ZkSyncUpgradeErrors.sol"; - -import {IGatewayUpgrade} from "./IGatewayUpgrade.sol"; -import {IL2ContractDeployer} from "../common/interfaces/IL2ContractDeployer.sol"; -import {L1FixedForceDeploymentsHelper} from "./L1FixedForceDeploymentsHelper.sol"; - -// solhint-disable-next-line gas-struct-packing -struct GatewayUpgradeEncodedInput { - IL2ContractDeployer.ForceDeployment[] forceDeployments; - uint256 l2GatewayUpgradePosition; - bytes fixedForceDeploymentsData; - address ctmDeployer; - address oldValidatorTimelock; - address newValidatorTimelock; - address wrappedBaseTokenStore; -} - -/// @author Matter Labs -/// @custom:security-contact security@matterlabs.dev -/// @notice This upgrade will be used to migrate Era to be part of the ZK chain ecosystem contracts. -contract GatewayUpgrade is BaseZkSyncUpgrade, L1FixedForceDeploymentsHelper, IGatewayUpgrade { - using PriorityQueue for PriorityQueue.Queue; - using PriorityTree for PriorityTree.Tree; - - /// @notice The address of this contract. - /// @dev needed as this address is delegateCalled, and we delegateCall it again. - address public immutable THIS_ADDRESS; - - constructor() { - THIS_ADDRESS = address(this); - } - - /// @notice The main function that will be delegate-called by the chain. - /// @param _proposedUpgrade The upgrade to be executed. - /// @dev Doesn't require any access-control restrictions as the contract is used in the delegate call. - function upgrade(ProposedUpgrade calldata _proposedUpgrade) public override returns (bytes32) { - GatewayUpgradeEncodedInput memory encodedInput = abi.decode( - _proposedUpgrade.postUpgradeCalldata, - (GatewayUpgradeEncodedInput) - ); - - bytes32 baseTokenAssetId = DataEncoding.encodeNTVAssetId(block.chainid, s.__DEPRECATED_baseToken); - - s.baseTokenAssetId = baseTokenAssetId; - s.priorityTree.setup(s.__DEPRECATED_priorityQueue.getTotalPriorityTxs()); - s.validators[encodedInput.oldValidatorTimelock] = false; - s.validators[encodedInput.newValidatorTimelock] = true; - ProposedUpgrade memory proposedUpgrade = _proposedUpgrade; - - bytes memory gatewayUpgradeCalldata = abi.encode( - encodedInput.ctmDeployer, - encodedInput.fixedForceDeploymentsData, - getZKChainSpecificForceDeploymentsData(s, encodedInput.wrappedBaseTokenStore, s.__DEPRECATED_baseToken) - ); - encodedInput.forceDeployments[encodedInput.l2GatewayUpgradePosition].input = gatewayUpgradeCalldata; - - proposedUpgrade.l2ProtocolUpgradeTx.data = abi.encodeCall( - IL2ContractDeployer.forceDeployOnAddresses, - (encodedInput.forceDeployments) - ); - - // slither-disable-next-line controlled-delegatecall - (bool success, ) = THIS_ADDRESS.delegatecall(abi.encodeCall(IGatewayUpgrade.upgradeExternal, proposedUpgrade)); - if (!success) { - revert GatewayUpgradeFailed(); - } - return Diamond.DIAMOND_INIT_SUCCESS_RETURN_VALUE; - } - - /// @notice The function that will be called from this same contract, we need an external call to be able to modify _proposedUpgrade (memory/calldata). - /// @dev Doesn't require any access-control restrictions as the contract is used in the delegate call. - function upgradeExternal(ProposedUpgrade calldata _proposedUpgrade) external override { - super.upgrade(_proposedUpgrade); - } -} diff --git a/l1-contracts/contracts/upgrades/IDefaultUpgrade.sol b/l1-contracts/contracts/upgrades/IDefaultUpgrade.sol index 0762d4a65b..d653783337 100644 --- a/l1-contracts/contracts/upgrades/IDefaultUpgrade.sol +++ b/l1-contracts/contracts/upgrades/IDefaultUpgrade.sol @@ -6,4 +6,6 @@ import {ProposedUpgrade} from "./BaseZkSyncUpgrade.sol"; interface IDefaultUpgrade { function upgrade(ProposedUpgrade calldata _upgrade) external returns (bytes32); + + function upgradeInner(ProposedUpgrade calldata _upgrade) external returns (bytes32); } diff --git a/l1-contracts/contracts/upgrades/IGatewayUpgrade.sol b/l1-contracts/contracts/upgrades/IGatewayUpgrade.sol deleted file mode 100644 index 41d906ceb6..0000000000 --- a/l1-contracts/contracts/upgrades/IGatewayUpgrade.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.28; - -import {ProposedUpgrade} from "./BaseZkSyncUpgrade.sol"; - -/** - * @author Matter Labs - * @custom:security-contact security@matterlabs.dev - * @notice Gateway upgrade interface. Used for the protocol upgrade that introduces the Gateway. - */ -interface IGatewayUpgrade { - /// @notice The upgrade function called from within this same contract - /// @dev This is needed for memory -> calldata conversion of the _upgrade arg. - /// @param _upgrade The upgrade to be executed. - function upgradeExternal(ProposedUpgrade calldata _upgrade) external; -} diff --git a/l1-contracts/contracts/upgrades/IL2V30Upgrade.sol b/l1-contracts/contracts/upgrades/IL2V30Upgrade.sol new file mode 100644 index 0000000000..c115b1636d --- /dev/null +++ b/l1-contracts/contracts/upgrades/IL2V30Upgrade.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IL2V30Upgrade { + function upgrade(uint256 _baseTokenOriginChainId, address _baseTokenOriginAddress) external; +} diff --git a/l1-contracts/contracts/upgrades/L1FixedForceDeploymentsHelper.sol b/l1-contracts/contracts/upgrades/L1FixedForceDeploymentsHelper.sol index d62f7c4e95..1cac61d3de 100644 --- a/l1-contracts/contracts/upgrades/L1FixedForceDeploymentsHelper.sol +++ b/l1-contracts/contracts/upgrades/L1FixedForceDeploymentsHelper.sol @@ -13,6 +13,8 @@ import {L2WrappedBaseTokenStore} from "../bridge/L2WrappedBaseTokenStore.sol"; import {IERC20Metadata} from "@openzeppelin/contracts-v4/token/ERC20/extensions/IERC20Metadata.sol"; import {UnsafeBytes} from "../common/libraries/UnsafeBytes.sol"; +import {IL1AssetRouter} from "../bridge/asset-router/IL1AssetRouter.sol"; +import {INativeTokenVaultBase} from "../bridge/ntv/INativeTokenVaultBase.sol"; /// @title L1FixedForceDeploymentsHelper /// @author Matter Labs @@ -69,6 +71,9 @@ abstract contract L1FixedForceDeploymentsHelper { } } + INativeTokenVaultBase nativeTokenVault = IL1AssetRouter(sharedBridge).nativeTokenVault(); + bytes32 baseTokenAssetId = s.baseTokenAssetId; + ZKChainSpecificForceDeploymentsData memory additionalForceDeploymentsData = ZKChainSpecificForceDeploymentsData({ baseTokenAssetId: s.baseTokenAssetId, @@ -76,7 +81,9 @@ abstract contract L1FixedForceDeploymentsHelper { predeployedL2WethAddress: l2WBaseToken, baseTokenL1Address: _baseTokenAddress, baseTokenName: baseTokenName, - baseTokenSymbol: baseTokenSymbol + baseTokenSymbol: baseTokenSymbol, + baseTokenOriginChainId: nativeTokenVault.originChainId(baseTokenAssetId), + baseTokenOriginAddress: nativeTokenVault.originToken(baseTokenAssetId) }); return abi.encode(additionalForceDeploymentsData); } diff --git a/l1-contracts/contracts/upgrades/L1GenesisUpgrade.sol b/l1-contracts/contracts/upgrades/L1GenesisUpgrade.sol index 73ff24f01d..c2df30805d 100644 --- a/l1-contracts/contracts/upgrades/L1GenesisUpgrade.sol +++ b/l1-contracts/contracts/upgrades/L1GenesisUpgrade.sol @@ -118,7 +118,7 @@ contract L1GenesisUpgrade is IL1GenesisUpgrade, BaseZkSyncUpgradeGenesis, L1Fixe } /// @notice the upgrade function. - function upgrade(ProposedUpgrade calldata _proposedUpgrade) public override returns (bytes32) { + function upgrade(ProposedUpgrade memory _proposedUpgrade) public override returns (bytes32) { super.upgrade(_proposedUpgrade); return Diamond.DIAMOND_INIT_SUCCESS_RETURN_VALUE; } diff --git a/l1-contracts/contracts/upgrades/L1V29Upgrade.sol b/l1-contracts/contracts/upgrades/L1V29Upgrade.sol index c29c19601d..a6757dd41e 100644 --- a/l1-contracts/contracts/upgrades/L1V29Upgrade.sol +++ b/l1-contracts/contracts/upgrades/L1V29Upgrade.sol @@ -25,7 +25,7 @@ contract L1V29Upgrade is BaseZkSyncUpgrade { /// @notice The main function that will be delegate-called by the chain. /// @param _proposedUpgrade The upgrade to be executed. - function upgrade(ProposedUpgrade calldata _proposedUpgrade) public override returns (bytes32) { + function upgrade(ProposedUpgrade memory _proposedUpgrade) public override returns (bytes32) { if (IGetters(address(this)).isPriorityQueueActive() == true) { revert PriorityQueueNotReady(); } @@ -35,7 +35,7 @@ contract L1V29Upgrade is BaseZkSyncUpgrade { } /// @inheritdoc BaseZkSyncUpgrade - function _postUpgrade(bytes calldata _postUpgradeCalldata) internal override { + function _postUpgrade(bytes memory _postUpgradeCalldata) internal override { V29UpgradeParams memory params = abi.decode(_postUpgradeCalldata, (V29UpgradeParams)); uint256 cachedLength = params.oldValidatorTimelocks.length; diff --git a/l1-contracts/contracts/upgrades/SettlementLayerV30Upgrade.sol b/l1-contracts/contracts/upgrades/SettlementLayerV30Upgrade.sol new file mode 100644 index 0000000000..410648d043 --- /dev/null +++ b/l1-contracts/contracts/upgrades/SettlementLayerV30Upgrade.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {Diamond} from "../state-transition/libraries/Diamond.sol"; +import {BaseZkSyncUpgrade, ProposedUpgrade} from "./BaseZkSyncUpgrade.sol"; +import {IBridgehubBase} from "../bridgehub/IBridgehubBase.sol"; +import {L2_GENESIS_UPGRADE_ADDR} from "../common/l2-helpers/L2ContractAddresses.sol"; +import {IMessageRoot} from "../bridgehub/IMessageRoot.sol"; +import {IL1AssetRouter} from "../bridge/asset-router/IL1AssetRouter.sol"; +import {IChainAssetHandler} from "../bridgehub/IChainAssetHandler.sol"; +import {INativeTokenVaultBase} from "../bridge/ntv/INativeTokenVaultBase.sol"; +import {IL1NativeTokenVault} from "../bridge/ntv/IL1NativeTokenVault.sol"; +import {IL2V30Upgrade} from "./IL2V30Upgrade.sol"; +import {IComplexUpgrader} from "../state-transition/l2-deps/IComplexUpgrader.sol"; +import {IGetters} from "../state-transition/chain-interfaces/IGetters.sol"; + +error PriorityQueueNotReady(); +error V30UpgradeGatewayBlockNumberNotSet(); +error GWNotV30(uint256 chainId); +error NotAllBatchesExecuted(); + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +contract SettlementLayerV30Upgrade is BaseZkSyncUpgrade { + /// @notice The main function that will be delegate-called by the chain. + /// @param _proposedUpgrade The upgrade to be executed. + function upgrade(ProposedUpgrade memory _proposedUpgrade) public override returns (bytes32) { + IBridgehubBase bridgehub = IBridgehubBase(s.bridgehub); + + /// We write to storage to avoid reentrancy. + s.nativeTokenVault = address(IL1AssetRouter(address(bridgehub.assetRouter())).nativeTokenVault()); + + // Note that this call will revert if the native token vault has not been upgraded, i.e. + // if a chain settling on Gateway tries to upgrade before ZK Gateway has done the upgrade. + s.assetTracker = address(IL1NativeTokenVault(s.nativeTokenVault).l1AssetTracker()); + s.__DEPRECATED_l2DAValidator = address(0); + + require(s.totalBatchesCommitted == s.totalBatchesExecuted, NotAllBatchesExecuted()); + + bytes32 baseTokenAssetId = bridgehub.baseTokenAssetId(s.chainId); + INativeTokenVaultBase nativeTokenVault = INativeTokenVaultBase( + IL1AssetRouter(address(bridgehub.assetRouter())).nativeTokenVault() + ); + + uint256 baseTokenOriginChainId = nativeTokenVault.originChainId(baseTokenAssetId); + address baseTokenOriginAddress = nativeTokenVault.originToken(baseTokenAssetId); + bytes memory l2GenesisUpgradeCalldata = abi.encodeCall( + IL2V30Upgrade.upgrade, + (baseTokenOriginChainId, baseTokenOriginAddress) + ); + bytes memory complexUpgraderCalldata = abi.encodeCall( + IComplexUpgrader.upgrade, + (L2_GENESIS_UPGRADE_ADDR, l2GenesisUpgradeCalldata) + ); + ProposedUpgrade memory proposedUpgrade = _proposedUpgrade; + proposedUpgrade.l2ProtocolUpgradeTx.data = complexUpgraderCalldata; + super.upgrade(proposedUpgrade); + IChainAssetHandler chainAssetHandler = IChainAssetHandler(bridgehub.chainAssetHandler()); + IMessageRoot messageRoot = IMessageRoot(bridgehub.messageRoot()); + + // The lines below ensure that chains can only upgrade once the ZK Gateway itself is upgraded, + // i.e. its minor protocol version is at least 30. Note, we use The tuple of (major, minor, patch) + // to denote protocol version. + uint256 gwChainId = messageRoot.ERA_GATEWAY_CHAIN_ID(); + address gwChain = bridgehub.getZKChain(gwChainId); + // slither-disable-next-line unused-return + (, uint256 gwMinor, ) = IGetters(gwChain).getSemverProtocolVersion(); + require(gwMinor >= 30, GWNotV30(gwChainId)); + + chainAssetHandler.setMigrationNumberForV30(s.chainId); + + if (s.settlementLayer == address(0)) { + messageRoot.saveV30UpgradeChainBatchNumber(s.chainId); + } + + if (bridgehub.whitelistedSettlementLayers(s.chainId)) { + require(IGetters(address(this)).getPriorityQueueSize() == 0, PriorityQueueNotReady()); + } + + return Diamond.DIAMOND_INIT_SUCCESS_RETURN_VALUE; + } +} diff --git a/l1-contracts/contracts/upgrades/ZkSyncUpgradeErrors.sol b/l1-contracts/contracts/upgrades/ZkSyncUpgradeErrors.sol index 9138aa58aa..206f954dbb 100644 --- a/l1-contracts/contracts/upgrades/ZkSyncUpgradeErrors.sol +++ b/l1-contracts/contracts/upgrades/ZkSyncUpgradeErrors.sol @@ -2,8 +2,6 @@ pragma solidity ^0.8.21; -// 0x388b6f68 -error GatewayUpgradeFailed(); // 0xb334f781 error GenesisUpgradeExpectedOnSettlementLayer(); // 0x5cb29523 @@ -36,3 +34,5 @@ error ProtocolVersionDeltaTooLarge(uint256 _proposedDelta, uint256 _maxDelta); error ProtocolVersionMinorDeltaTooBig(uint256 limit, uint256 proposed); // 0x88d7b498 error ProtocolVersionTooSmall(); +// 0x364b6f8b +error SettlementLayerUpgradeMustPrecedeChainUpgrade(); diff --git a/l1-contracts/contracts/vendor/Bytes.sol b/l1-contracts/contracts/vendor/Bytes.sol new file mode 100644 index 0000000000..4ff5e25add --- /dev/null +++ b/l1-contracts/contracts/vendor/Bytes.sol @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.4.0) (utils/Bytes.sol) + +pragma solidity ^0.8.24; + +import {Math} from "@openzeppelin/contracts-v4/utils/math/Math.sol"; + +/** + * @dev Bytes operations. + * @dev FIXME: some functions (lastIndexOf) are commented out due to the lack of `Math.saturatingAdd` in the used OpenZeppelin version. + */ +library Bytes { + /** + * @dev Forward search for `s` in `buffer` + * * If `s` is present in the buffer, returns the index of the first instance + * * If `s` is not present in the buffer, returns type(uint256).max + * + * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`] + */ + function indexOf(bytes memory buffer, bytes1 s) internal pure returns (uint256) { + return indexOf(buffer, s, 0); + } + + /** + * @dev Forward search for `s` in `buffer` starting at position `pos` + * * If `s` is present in the buffer (at or after `pos`), returns the index of the next instance + * * If `s` is not present in the buffer (at or after `pos`), returns type(uint256).max + * + * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`] + */ + function indexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) { + uint256 length = buffer.length; + for (uint256 i = pos; i < length; ++i) { + if (bytes1(_unsafeReadBytesOffset(buffer, i)) == s) { + return i; + } + } + return type(uint256).max; + } + + // /** + // * @dev Backward search for `s` in `buffer` + // * * If `s` is present in the buffer, returns the index of the last instance + // * * If `s` is not present in the buffer, returns type(uint256).max + // * + // * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf[Javascript's `Array.lastIndexOf`] + // */ + // function lastIndexOf(bytes memory buffer, bytes1 s) internal pure returns (uint256) { + // return lastIndexOf(buffer, s, type(uint256).max); + // } + + // /** + // * @dev Backward search for `s` in `buffer` starting at position `pos` + // * * If `s` is present in the buffer (at or before `pos`), returns the index of the previous instance + // * * If `s` is not present in the buffer (at or before `pos`), returns type(uint256).max + // * + // * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf[Javascript's `Array.lastIndexOf`] + // */ + // function lastIndexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) { + // unchecked { + // uint256 length = buffer.length; + // for (uint256 i = Math.min(Math.saturatingAdd(pos, 1), length); i > 0; --i) { + // if (bytes1(_unsafeReadBytesOffset(buffer, i - 1)) == s) { + // return i - 1; + // } + // } + // return type(uint256).max; + // } + // } + + /** + * @dev Copies the content of `buffer`, from `start` (included) to the end of `buffer` into a new bytes object in + * memory. + * + * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`] + */ + function slice(bytes memory buffer, uint256 start) internal pure returns (bytes memory) { + return slice(buffer, start, buffer.length); + } + + /** + * @dev Copies the content of `buffer`, from `start` (included) to `end` (excluded) into a new bytes object in + * memory. The `end` argument is truncated to the length of the `buffer`. + * + * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`] + */ + function slice(bytes memory buffer, uint256 start, uint256 end) internal pure returns (bytes memory) { + // sanitize + uint256 length = buffer.length; + end = Math.min(end, length); + start = Math.min(start, end); + + // allocate and copy + bytes memory result = new bytes(end - start); + assembly ("memory-safe") { + mcopy(add(result, 0x20), add(add(buffer, 0x20), start), sub(end, start)) + } + + return result; + } + + /** + * @dev Moves the content of `buffer`, from `start` (included) to the end of `buffer` to the start of that buffer. + * + * NOTE: This function modifies the provided buffer in place. If you need to preserve the original buffer, use {slice} instead + */ + function splice(bytes memory buffer, uint256 start) internal pure returns (bytes memory) { + return splice(buffer, start, buffer.length); + } + + /** + * @dev Moves the content of `buffer`, from `start` (included) to end (excluded) to the start of that buffer. The + * `end` argument is truncated to the length of the `buffer`. + * + * NOTE: This function modifies the provided buffer in place. If you need to preserve the original buffer, use {slice} instead + */ + function splice(bytes memory buffer, uint256 start, uint256 end) internal pure returns (bytes memory) { + // sanitize + uint256 length = buffer.length; + end = Math.min(end, length); + start = Math.min(start, end); + + // allocate and copy + assembly ("memory-safe") { + mcopy(add(buffer, 0x20), add(add(buffer, 0x20), start), sub(end, start)) + mstore(buffer, sub(end, start)) + } + + return buffer; + } + + /* + * @dev Returns true if the two byte buffers are equal. + */ + function equal(bytes memory a, bytes memory b) internal pure returns (bool) { + return a.length == b.length && keccak256(a) == keccak256(b); + } + + /** + * @dev Reverses the byte order of a bytes32 value, converting between little-endian and big-endian. + * Inspired in https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel[Reverse Parallel] + */ + function reverseBytes32(bytes32 value) internal pure returns (bytes32) { + value = // swap bytes + ((value >> 8) & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) | + ((value & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8); + value = // swap 2-byte long pairs + ((value >> 16) & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) | + ((value & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16); + value = // swap 4-byte long pairs + ((value >> 32) & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) | + ((value & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32); + value = // swap 8-byte long pairs + ((value >> 64) & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) | + ((value & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64); + return (value >> 128) | (value << 128); // swap 16-byte long pairs + } + + /// @dev Same as {reverseBytes32} but optimized for 128-bit values. + function reverseBytes16(bytes16 value) internal pure returns (bytes16) { + value = // swap bytes + ((value & 0xFF00FF00FF00FF00FF00FF00FF00FF00) >> 8) | + ((value & 0x00FF00FF00FF00FF00FF00FF00FF00FF) << 8); + value = // swap 2-byte long pairs + ((value & 0xFFFF0000FFFF0000FFFF0000FFFF0000) >> 16) | + ((value & 0x0000FFFF0000FFFF0000FFFF0000FFFF) << 16); + value = // swap 4-byte long pairs + ((value & 0xFFFFFFFF00000000FFFFFFFF00000000) >> 32) | + ((value & 0x00000000FFFFFFFF00000000FFFFFFFF) << 32); + return (value >> 64) | (value << 64); // swap 8-byte long pairs + } + + /// @dev Same as {reverseBytes32} but optimized for 64-bit values. + function reverseBytes8(bytes8 value) internal pure returns (bytes8) { + value = ((value & 0xFF00FF00FF00FF00) >> 8) | ((value & 0x00FF00FF00FF00FF) << 8); // swap bytes + value = ((value & 0xFFFF0000FFFF0000) >> 16) | ((value & 0x0000FFFF0000FFFF) << 16); // swap 2-byte long pairs + return (value >> 32) | (value << 32); // swap 4-byte long pairs + } + + /// @dev Same as {reverseBytes32} but optimized for 32-bit values. + function reverseBytes4(bytes4 value) internal pure returns (bytes4) { + value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); // swap bytes + return (value >> 16) | (value << 16); // swap 2-byte long pairs + } + + /// @dev Same as {reverseBytes32} but optimized for 16-bit values. + function reverseBytes2(bytes2 value) internal pure returns (bytes2) { + return (value >> 8) | (value << 8); + } + + /** + * @dev Reads a bytes32 from a bytes array without bounds checking. + * + * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the + * assembly block as such would prevent some optimizations. + */ + function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) { + // This is not memory safe in the general case, but all calls to this private function are within bounds. + assembly ("memory-safe") { + value := mload(add(add(buffer, 0x20), offset)) + } + } +} diff --git a/l1-contracts/contracts/vendor/Calldata.sol b/l1-contracts/contracts/vendor/Calldata.sol new file mode 100644 index 0000000000..41860b29fd --- /dev/null +++ b/l1-contracts/contracts/vendor/Calldata.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.3.0) (utils/Calldata.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Helper library for manipulating objects in calldata. + */ +library Calldata { + // slither-disable-next-line write-after-write + function emptyBytes() internal pure returns (bytes calldata result) { + assembly ("memory-safe") { + result.offset := 0 + result.length := 0 + } + } + + // slither-disable-next-line write-after-write + function emptyString() internal pure returns (string calldata result) { + assembly ("memory-safe") { + result.offset := 0 + result.length := 0 + } + } +} diff --git a/l1-contracts/contracts/vendor/draft-InteroperableAddress.sol b/l1-contracts/contracts/vendor/draft-InteroperableAddress.sol new file mode 100644 index 0000000000..c36312dddc --- /dev/null +++ b/l1-contracts/contracts/vendor/draft-InteroperableAddress.sol @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.26; + +import {Math} from "@openzeppelin/contracts-v4/utils/math/Math.sol"; +import {SafeCast} from "@openzeppelin/contracts-v4/utils/math/SafeCast.sol"; +import {Bytes} from "./Bytes.sol"; +import {Calldata} from "./Calldata.sol"; + +/** + * @dev Helper library to format and parse https://ethereum-magicians.org/t/erc-7930-interoperable-addresses/23365[ERC-7930] interoperable + * addresses. + */ +library InteroperableAddress { + using SafeCast for uint256; + using Bytes for bytes; + + error InteroperableAddressParsingError(bytes); + error InteroperableAddressEmptyReferenceAndAddress(); + + /** + * @dev Format an ERC-7930 interoperable address (version 1) from its components `chainType`, `chainReference` + * and `addr`. This is a generic function that supports any chain type, chain reference and address supported by + * ERC-7390, including interoperable addresses with empty chain reference or empty address. + */ + function formatV1( + bytes2 chainType, + bytes memory chainReference, + bytes memory addr + ) internal pure returns (bytes memory) { + require(chainReference.length > 0 || addr.length > 0, InteroperableAddressEmptyReferenceAndAddress()); + return + abi.encodePacked( + bytes2(0x0001), + chainType, + chainReference.length.toUint8(), + chainReference, + addr.length.toUint8(), + addr + ); + } + + /** + * @dev Variant of {formatV1-bytes2-bytes-bytes-} specific to EVM chains. Returns the ERC-7930 interoperable + * address (version 1) for a given chainid and ethereum address. + */ + function formatEvmV1(uint256 chainid, address addr) internal pure returns (bytes memory) { + bytes memory chainReference = _toChainReference(chainid); + return abi.encodePacked(bytes4(0x00010000), uint8(chainReference.length), chainReference, uint8(20), addr); + } + + /** + * @dev Variant of {formatV1-bytes2-bytes-bytes-} that specifies an EVM chain without an address. + */ + function formatEvmV1(uint256 chainid) internal pure returns (bytes memory) { + bytes memory chainReference = _toChainReference(chainid); + return abi.encodePacked(bytes4(0x00010000), uint8(chainReference.length), chainReference, uint8(0)); + } + + /** + * @dev Variant of {formatV1-bytes2-bytes-bytes-} that specifies an EVM address without a chain reference. + */ + function formatEvmV1(address addr) internal pure returns (bytes memory) { + return abi.encodePacked(bytes6(0x000100000014), addr); + } + + /** + * @dev Parse a ERC-7930 interoperable address (version 1) into its different components. Reverts if the input is + * not following a version 1 of ERC-7930 + */ + function parseV1( + bytes memory self + ) internal pure returns (bytes2 chainType, bytes memory chainReference, bytes memory addr) { + bool success; + (success, chainType, chainReference, addr) = tryParseV1(self); + require(success, InteroperableAddressParsingError(self)); + } + + /** + * @dev Variant of {parseV1} that handles calldata slices to reduce memory copy costs. + */ + function parseV1Calldata( + bytes calldata self + ) internal pure returns (bytes2 chainType, bytes calldata chainReference, bytes calldata addr) { + bool success; + (success, chainType, chainReference, addr) = tryParseV1Calldata(self); + require(success, InteroperableAddressParsingError(self)); + } + + /** + * @dev Variant of {parseV1} that does not revert on invalid input. Instead, it returns `false` as the first + * return value to indicate parsing failure when the input does not follow version 1 of ERC-7930. + */ + function tryParseV1( + bytes memory self + ) internal pure returns (bool success, bytes2 chainType, bytes memory chainReference, bytes memory addr) { + unchecked { + success = true; + if (self.length < 0x06) return (false, 0x0000, _emptyBytesMemory(), _emptyBytesMemory()); + + bytes2 version = _readBytes2(self, 0x00); + if (version != bytes2(0x0001)) return (false, 0x0000, _emptyBytesMemory(), _emptyBytesMemory()); + chainType = _readBytes2(self, 0x02); + + uint8 chainReferenceLength = uint8(self[0x04]); + if (self.length < 0x06 + chainReferenceLength) + return (false, 0x0000, _emptyBytesMemory(), _emptyBytesMemory()); + chainReference = self.slice(0x05, 0x05 + chainReferenceLength); + + uint8 addrLength = uint8(self[0x05 + chainReferenceLength]); + if (self.length < 0x06 + chainReferenceLength + addrLength) + return (false, 0x0000, _emptyBytesMemory(), _emptyBytesMemory()); + addr = self.slice(0x06 + chainReferenceLength, 0x06 + chainReferenceLength + addrLength); + } + } + + /** + * @dev Variant of {tryParseV1} that handles calldata slices to reduce memory copy costs. + */ + function tryParseV1Calldata( + bytes calldata self + ) internal pure returns (bool success, bytes2 chainType, bytes calldata chainReference, bytes calldata addr) { + unchecked { + success = true; + if (self.length < 0x06) return (false, 0x0000, Calldata.emptyBytes(), Calldata.emptyBytes()); + + bytes2 version = _readBytes2Calldata(self, 0x00); + if (version != bytes2(0x0001)) return (false, 0x0000, Calldata.emptyBytes(), Calldata.emptyBytes()); + chainType = _readBytes2Calldata(self, 0x02); + + uint8 chainReferenceLength = uint8(self[0x04]); + if (self.length < 0x06 + chainReferenceLength) + return (false, 0x0000, Calldata.emptyBytes(), Calldata.emptyBytes()); + chainReference = self[0x05:0x05 + chainReferenceLength]; + + uint8 addrLength = uint8(self[0x05 + chainReferenceLength]); + if (self.length < 0x06 + chainReferenceLength + addrLength) + return (false, 0x0000, Calldata.emptyBytes(), Calldata.emptyBytes()); + addr = self[0x06 + chainReferenceLength:0x06 + chainReferenceLength + addrLength]; + } + } + + /** + * @dev Parse a ERC-7930 interoperable address (version 1) corresponding to an EIP-155 chain. The `chainId` and + * `addr` return values will be zero if the input doesn't include a chainReference or an address, respectively. + * + * Requirements: + * + * * The input must be a valid ERC-7930 interoperable address (version 1) + * * The underlying chainType must be "eip-155" + */ + function parseEvmV1(bytes memory self) internal pure returns (uint256 chainId, address addr) { + bool success; + (success, chainId, addr) = tryParseEvmV1(self); + require(success, InteroperableAddressParsingError(self)); + } + + /** + * @dev Variant of {parseEvmV1} that handles calldata slices to reduce memory copy costs. + */ + function parseEvmV1Calldata(bytes calldata self) internal pure returns (uint256 chainId, address addr) { + bool success; + (success, chainId, addr) = tryParseEvmV1Calldata(self); + require(success, InteroperableAddressParsingError(self)); + } + + /** + * @dev Variant of {parseEvmV1} that does not revert on invalid input. Instead, it returns `false` as the first + * return value to indicate parsing failure when the input does not follow version 1 of ERC-7930. + */ + function tryParseEvmV1(bytes memory self) internal pure returns (bool success, uint256 chainId, address addr) { + (bool success_, bytes2 chainType_, bytes memory chainReference_, bytes memory addr_) = tryParseV1(self); + return + (success_ && + chainType_ == 0x0000 && + chainReference_.length < 33 && + (addr_.length == 0 || addr_.length == 20)) + ? ( + true, + uint256(bytes32(chainReference_)) >> (256 - 8 * chainReference_.length), + address(bytes20(addr_)) + ) + : (false, 0, address(0)); + } + + /** + * @dev Variant of {tryParseEvmV1} that handles calldata slices to reduce memory copy costs. + */ + function tryParseEvmV1Calldata( + bytes calldata self + ) internal pure returns (bool success, uint256 chainId, address addr) { + (bool success_, bytes2 chainType_, bytes calldata chainReference_, bytes calldata addr_) = tryParseV1Calldata( + self + ); + return + (success_ && + chainType_ == 0x0000 && + chainReference_.length < 33 && + (addr_.length == 0 || addr_.length == 20)) + ? ( + true, + uint256(bytes32(chainReference_)) >> (256 - 8 * chainReference_.length), + address(bytes20(addr_)) + ) + : (false, 0, address(0)); + } + + function _toChainReference(uint256 chainid) private pure returns (bytes memory) { + unchecked { + // length fits in a uint8: log256(type(uint256).max) is 31 + uint256 length = Math.log256(chainid) + 1; + return abi.encodePacked(chainid).slice(32 - length); + } + } + + function _readBytes2(bytes memory buffer, uint256 offset) private pure returns (bytes2 value) { + // This is not memory safe in the general case, but all calls to this private function are within bounds. + assembly ("memory-safe") { + value := shl(240, shr(240, mload(add(add(buffer, 0x20), offset)))) + } + } + + function _readBytes2Calldata(bytes calldata buffer, uint256 offset) private pure returns (bytes2 value) { + assembly ("memory-safe") { + value := shl(240, shr(240, calldataload(add(buffer.offset, offset)))) + } + } + + function _emptyBytesMemory() private pure returns (bytes memory result) { + assembly ("memory-safe") { + result := 0x60 // mload(0x60) is always 0 + } + } +} diff --git a/l1-contracts/deploy-script-config-template/config-deploy-ctm.toml b/l1-contracts/deploy-script-config-template/config-deploy-ctm.toml new file mode 100644 index 0000000000..36f23b19ee --- /dev/null +++ b/l1-contracts/deploy-script-config-template/config-deploy-ctm.toml @@ -0,0 +1,29 @@ +era_chain_id = 9 +owner_address = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" +testnet_verifier = true +support_l2_legacy_shared_bridge_test = false +is_zk_sync_os = false + +[gateway] +chain_id = 123 + +[contracts] +create2_factory_salt = "0x00000000000000000000000000000000000000000000000000000000000000ff" +create2_factory_addr = "0x0000000000000000000000000000000000000000" +governance_security_council_address = "0x0000000000000000000000000000000000000000" +governance_min_delay = 0 +validator_timelock_execution_delay = 0 +genesis_root = "0x1000000000000000000000000000000000000000000000000000000000000000" +genesis_rollup_leaf_index = 1 +genesis_batch_commitment = "0x1000000000000000000000000000000000000000000000000000000000000000" +latest_protocol_version = 0 +priority_tx_max_gas_limit = 80000000 +diamond_init_pubdata_pricing_mode = 0 +diamond_init_batch_overhead_l1_gas = 1000000 +diamond_init_max_pubdata_per_batch = 120000 +diamond_init_max_l2_gas_per_batch = 80000000 +diamond_init_priority_tx_max_pubdata = 99000 +diamond_init_minimal_l2_gas_price = 250000000 +bootloader_hash = "0x0100000000000000000000000000000000000000000000000000000000000000" +default_aa_hash = "0x0100000000000000000000000000000000000000000000000000000000000000" +evm_emulator_hash = "0x0100000000000000000000000000000000000000000000000000000000000000" diff --git a/l1-contracts/deploy-script-config-template/config-deploy-l1.toml b/l1-contracts/deploy-script-config-template/config-deploy-l1.toml index 9d8ccff407..d7cc0c0ebc 100644 --- a/l1-contracts/deploy-script-config-template/config-deploy-l1.toml +++ b/l1-contracts/deploy-script-config-template/config-deploy-l1.toml @@ -1,6 +1,5 @@ era_chain_id = 9 owner_address = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" -testnet_verifier = true support_l2_legacy_shared_bridge_test = false is_zk_sync_os = false @@ -8,30 +7,11 @@ is_zk_sync_os = false chain_id = 123 [contracts] +create2_factory_salt = "0x00000000000000000000000000000000000000000000000000000000000000ff" +create2_factory_addr = "0x0000000000000000000000000000000000000000" governance_security_council_address = "0x0000000000000000000000000000000000000000" governance_min_delay = 0 max_number_of_chains = 100 -create2_factory_salt = "0x00000000000000000000000000000000000000000000000000000000000000ff" -create2_factory_addr = "0x0000000000000000000000000000000000000000" -validator_timelock_execution_delay = 0 -genesis_root = "0x1000000000000000000000000000000000000000000000000000000000000000" -genesis_rollup_leaf_index = 1 -genesis_batch_commitment = "0x1000000000000000000000000000000000000000000000000000000000000000" -latest_protocol_version = 0 -recursion_node_level_vk_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" -recursion_leaf_level_vk_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" -recursion_circuits_set_vks_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" -priority_tx_max_gas_limit = 80000000 -diamond_init_pubdata_pricing_mode = 0 -diamond_init_batch_overhead_l1_gas = 1000000 -diamond_init_max_pubdata_per_batch = 120000 -diamond_init_max_l2_gas_per_batch = 80000000 -diamond_init_priority_tx_max_pubdata = 99000 -diamond_init_minimal_l2_gas_price = 250000000 -bootloader_hash = "0x0100000000000000000000000000000000000000000000000000000000000000" -default_aa_hash = "0x0100000000000000000000000000000000000000000000000000000000000000" -evm_emulator_hash = "0x0100000000000000000000000000000000000000000000000000000000000000" -force_deployments_data = "0x" [tokens] token_weth_address = "0x0000000000000000000000000000000000000000" diff --git a/l1-contracts/deploy-script-config-template/register-hyperchain.toml b/l1-contracts/deploy-script-config-template/register-hyperchain.toml index 5f953b4e1e..7b3f4450f8 100644 --- a/l1-contracts/deploy-script-config-template/register-hyperchain.toml +++ b/l1-contracts/deploy-script-config-template/register-hyperchain.toml @@ -4,7 +4,7 @@ chain_chain_id = 9 base_token_addr = "0x0000000000000000000000000000000000000001" bridgehub_create_new_chain_salt = 0 validium_mode = false -validator_sender_operator_eth = "0x0000000000000000000000000000000000000000" +validator_sender_operator_commit_eth = "0x0000000000000000000000000000000000000000" validator_sender_operator_blobs_eth = "0x0000000000000000000000000000000000000001" validator_sender_operator_prove = "0x0000000000000000000000000000000000000002" validator_sender_operator_execute = "0x0000000000000000000000000000000000000003" diff --git a/l1-contracts/deploy-scripts/AddressIntrospector.sol b/l1-contracts/deploy-scripts/AddressIntrospector.sol new file mode 100644 index 0000000000..04d657e2b0 --- /dev/null +++ b/l1-contracts/deploy-scripts/AddressIntrospector.sol @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.21; + +import {L2DACommitmentScheme} from "contracts/common/Config.sol"; +import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; +import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; +import {ICTMDeploymentTracker} from "contracts/bridgehub/ICTMDeploymentTracker.sol"; +import {ChainTypeManagerBase} from "contracts/state-transition/ChainTypeManagerBase.sol"; +import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol"; +import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; +import {IAssetRouterBase} from "contracts/bridge/asset-router/IAssetRouterBase.sol"; +import {IL1BaseTokenAssetHandler} from "contracts/bridge/interfaces/IL1BaseTokenAssetHandler.sol"; +import {IL1ERC20Bridge} from "contracts/bridge/interfaces/IL1ERC20Bridge.sol"; +import {IOwnable} from "contracts/common/interfaces/IOwnable.sol"; +import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; +import {Utils} from "./Utils.sol"; + +library AddressIntrospector { + struct BridgehubAddresses { + address bridgehubProxy; + address assetRouter; + address messageRoot; + address l1CtmDeployer; + address admin; + address governance; + address chainRegistrationSenderProxy; + address transparentProxyAdmin; + address chainAssetHandler; + address interopCenterProxy; + address sharedBridgeLegacy; // optional legacy alias, if present on implementation + AssetRouterAddresses assetRouterAddresses; + } + + struct CTMAddresses { + address ctmProxy; + address l1GenesisUpgrade; + address validatorTimelockPostV29; + address legacyValidatorTimelock; + address admin; + address serverNotifier; + } + + struct ZkChainAddresses { + address zkChainProxy; + address verifier; + address admin; + address pendingAdmin; + address chainTypeManager; + address baseToken; + address transactionFilterer; + address settlementLayer; + address l1DAValidator; + L2DACommitmentScheme l2DAValidatorScheme; + } + + struct AssetRouterAddresses { + address l1Nullifier; + address l1WethToken; + address nativeTokenVault; + bytes32 ethTokenAssetId; + } + + struct BaseTokenRoute { + bytes32 baseTokenAssetId; + address assetHandlerAddress; + address baseTokenAddress; + } + + struct L1ERC20BridgeAddresses { + address l1Nullifier; + address l1AssetRouter; + address l1NativeTokenVault; + address l2TokenBeacon; + address l2Bridge; + uint256 eraChainId; + bytes32 l2TokenProxyBytecodeHash; + } + + struct NonDisoverable { + address rollupDAManager; + address bytecodesSupplier; + } + + function getBridgehubAddresses(IL1Bridgehub _bridgehub) public view returns (BridgehubAddresses memory info) { + info.bridgehubProxy = address(_bridgehub); + info.assetRouter = address(_bridgehub.assetRouter()); + info.messageRoot = address(_bridgehub.messageRoot()); + info.l1CtmDeployer = address(_bridgehub.l1CtmDeployer()); + info.admin = address(_bridgehub.admin()); + info.chainAssetHandler = _bridgehub.chainAssetHandler(); + if (info.assetRouter != address(0)) { + info.assetRouterAddresses = getAssetRouterAddresses(IL1AssetRouter(info.assetRouter)); + } + info.governance = IOwnable(info.bridgehubProxy).owner(); + info.transparentProxyAdmin = Utils.getProxyAdmin(info.bridgehubProxy); + } + + function getCTMAddresses(ChainTypeManagerBase _ctm) public view returns (CTMAddresses memory info) { + address ctmAddr = address(_ctm); + info.ctmProxy = ctmAddr; + info.l1GenesisUpgrade = _ctm.l1GenesisUpgrade(); + info.validatorTimelockPostV29 = _tryAddress(ctmAddr, "validatorTimelockPostV29()"); + info.legacyValidatorTimelock = _ctm.validatorTimelock(); + info.admin = _ctm.admin(); + info.serverNotifier = _ctm.serverNotifierAddress(); + } + + function getZkChainAddresses(IZKChain _zkChain) public view returns (ZkChainAddresses memory info) { + info.zkChainProxy = address(_zkChain); + info.verifier = _zkChain.getVerifier(); + info.admin = _zkChain.getAdmin(); + info.pendingAdmin = _zkChain.getPendingAdmin(); + info.chainTypeManager = _zkChain.getChainTypeManager(); + info.baseToken = _zkChain.getBaseToken(); + info.transactionFilterer = _zkChain.getTransactionFilterer(); + info.settlementLayer = _zkChain.getSettlementLayer(); + (uint256 major, uint256 minor, uint256 patch) = _zkChain.getSemverProtocolVersion(); + if (minor >= 29) { + (info.l1DAValidator, info.l2DAValidatorScheme) = _zkChain.getDAValidatorPair(); + } else { + (bool ok, bytes memory data) = address(_zkChain).staticcall( + abi.encodeWithSignature("getDAValidatorPair()") + ); + if (ok && data.length >= 32) { + (info.l1DAValidator, ) = abi.decode(data, (address, address)); + } + } + } + + function getAssetRouterAddresses( + IL1AssetRouter _assetRouter + ) public view returns (AssetRouterAddresses memory info) { + info.l1Nullifier = address(_assetRouter.L1_NULLIFIER()); + info.l1WethToken = _assetRouter.L1_WETH_TOKEN(); + info.nativeTokenVault = address(_assetRouter.nativeTokenVault()); + info.ethTokenAssetId = _assetRouter.ETH_TOKEN_ASSET_ID(); + } + + function getBaseTokenRoute( + IL1Bridgehub _bridgehub, + uint256 _chainId + ) public view returns (BaseTokenRoute memory info) { + info.baseTokenAssetId = _bridgehub.baseTokenAssetId(_chainId); + info.assetHandlerAddress = IAssetRouterBase(_bridgehub.assetRouter()).assetHandlerAddress( + info.baseTokenAssetId + ); + if (info.assetHandlerAddress != address(0)) { + info.baseTokenAddress = IL1BaseTokenAssetHandler(info.assetHandlerAddress).tokenAddress( + info.baseTokenAssetId + ); + } + } + + function getZkChainFacetAddresses(IZKChain _zkChain) public view returns (address[] memory) { + return _zkChain.facetAddresses(); + } + + /// @notice Convenience method to fetch everything for a specific chainId via a Bridgehub instance + function getAllForChain( + IL1Bridgehub _bridgehub, + uint256 _chainId + ) + external + view + returns ( + BridgehubAddresses memory bh, + CTMAddresses memory ctm, + ZkChainAddresses memory zk, + AssetRouterAddresses memory ar, + BaseTokenRoute memory baseRoute, + address[] memory zkFacets, + L1ERC20BridgeAddresses memory legacyBridge + ) + { + return _getAllForChainInternal(_bridgehub, _chainId); + } + + function _getAllForChainInternal( + IL1Bridgehub _bridgehub, + uint256 _chainId + ) + private + view + returns ( + BridgehubAddresses memory bh, + CTMAddresses memory ctm, + ZkChainAddresses memory zk, + AssetRouterAddresses memory ar, + BaseTokenRoute memory baseRoute, + address[] memory zkFacets, + L1ERC20BridgeAddresses memory legacyBridge + ) + { + bh = getBridgehubAddresses(_bridgehub); + + address ctmAddr = _bridgehub.chainTypeManager(_chainId); + ctm = getCTMAddresses(ChainTypeManagerBase(ctmAddr)); + + address zkAddr = _bridgehub.getZKChain(_chainId); + zk = getZkChainAddresses(IZKChain(zkAddr)); + + ar = getAssetRouterAddresses(IL1AssetRouter(payable(address(_bridgehub.assetRouter())))); + baseRoute = getBaseTokenRoute(_bridgehub, _chainId); + zkFacets = getZkChainFacetAddresses(IZKChain(zkAddr)); + + // Optional: if legacy ERC20 bridge is known/set on the asset router, caller can provide it separately. + } + + function _tryAddress(address _target, string memory _sig) private view returns (address value) { + (bool ok, bytes memory data) = _target.staticcall(abi.encodeWithSignature(_sig)); + if (ok && data.length >= 32) { + return abi.decode(data, (address)); + } + return address(0); + } +} diff --git a/l1-contracts/deploy-scripts/AdminFunctions.s.sol b/l1-contracts/deploy-scripts/AdminFunctions.s.sol index 4b6fe03f5d..5b4119b3f9 100644 --- a/l1-contracts/deploy-scripts/AdminFunctions.s.sol +++ b/l1-contracts/deploy-scripts/AdminFunctions.s.sol @@ -425,6 +425,28 @@ contract AdminFunctions is Script { saveAndSendAdminTx(chainInfo.admin, calls, _shouldSend); } + function pauseDepositsBeforeInitiatingMigration(address _bridgehub, uint256 _chainId, bool _shouldSend) public { + ChainInfoFromBridgehub memory chainInfo = Utils.chainInfoFromBridgehubAndChainId(_bridgehub, _chainId); + + Call[] memory calls = new Call[](1); + calls[0] = Call({ + target: chainInfo.diamondProxy, + value: 0, + data: abi.encodeCall(IAdmin.pauseDepositsBeforeInitiatingMigration, ()) + }); + + saveAndSendAdminTx(chainInfo.admin, calls, _shouldSend); + } + + function unpauseDeposits(address _bridgehub, uint256 _chainId, bool _shouldSend) public { + ChainInfoFromBridgehub memory chainInfo = Utils.chainInfoFromBridgehubAndChainId(_bridgehub, _chainId); + + Call[] memory calls = new Call[](1); + calls[0] = Call({target: chainInfo.diamondProxy, value: 0, data: abi.encodeCall(IAdmin.unpauseDeposits, ())}); + + saveAndSendAdminTx(chainInfo.admin, calls, _shouldSend); + } + function setDAValidatorPair( address _bridgehub, uint256 _chainId, diff --git a/l1-contracts/deploy-scripts/ContractsBytecodesLib.sol b/l1-contracts/deploy-scripts/ContractsBytecodesLib.sol index 8e76c8c8d3..ba7354cc45 100644 --- a/l1-contracts/deploy-scripts/ContractsBytecodesLib.sol +++ b/l1-contracts/deploy-scripts/ContractsBytecodesLib.sol @@ -51,8 +51,9 @@ library ContractsBytecodesLib { // Defines the contract identifiers for L1 contracts that follow the // pattern: ContractIdentifier.sol and contract class ContractIdentifier. // These are handled by the generic L1 case in getCreationCode. - string[44] memory L1_GENERIC_CONTRACT_IDENTIFIERS = [ + string[47] memory L1_GENERIC_CONTRACT_IDENTIFIERS = [ "AccessControlRestriction", /// ?? + "L2AssetTracker", "BeaconProxy", "BridgedStandardERC20", "BridgedTokenBeacon", @@ -70,6 +71,8 @@ library ContractsBytecodesLib { "DiamondInit", "DiamondProxy", "DefaultUpgrade", + "InteropCenter", + "InteropHandler", "EraDualVerifier", "ZKsyncOSDualVerifier", "L1GenesisUpgrade", @@ -98,20 +101,14 @@ library ContractsBytecodesLib { "UpgradeableBeaconDeployer" ]; - string[6] memory L2_GENERIC_CONTRACT_IDENTIFIERS = [ + string[4] memory L2_GENERIC_CONTRACT_IDENTIFIERS = [ "ForceDeployUpgrader", "RollupL2DAValidator", "ConsensusRegistry", - "AvailL2DAValidator", - "ValidiumL2DAValidator", "TimestampAsserter" ]; - string[3] memory SYSTEM_CONTRACT_IDENTIFIERS = [ - "SystemTransparentUpgradeableProxy", - "L2GatewayUpgrade", - "L2V29Upgrade" - ]; + string[2] memory SYSTEM_CONTRACT_IDENTIFIERS = ["SystemTransparentUpgradeableProxy", "L2V29Upgrade"]; // --- Special Cases: System Contracts --- // These contracts are typically read from a 'system-contracts' or similar directory. diff --git a/l1-contracts/deploy-scripts/DeployCTM.s.sol b/l1-contracts/deploy-scripts/DeployCTM.s.sol index b233aab3a2..ee3a842b5a 100644 --- a/l1-contracts/deploy-scripts/DeployCTM.s.sol +++ b/l1-contracts/deploy-scripts/DeployCTM.s.sol @@ -5,69 +5,64 @@ pragma solidity ^0.8.24; import {Script, console2 as console} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; -import {StateTransitionDeployedAddresses, Utils} from "./Utils.sol"; +import {StateTransitionDeployedAddresses} from "./Types.sol"; +import {Utils} from "./Utils.sol"; import {Multicall3} from "contracts/dev-contracts/Multicall3.sol"; import {IEIP7702Checker} from "contracts/state-transition/chain-interfaces/IEIP7702Checker.sol"; import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; +import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol"; + import {RollupDAManager} from "contracts/state-transition/data-availability/RollupDAManager.sol"; import {L2ContractHelper} from "contracts/common/l2-helpers/L2ContractHelper.sol"; -import {L2DACommitmentScheme, ROLLUP_L2_DA_COMMITMENT_SCHEME} from "contracts/common/Config.sol"; -import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol"; +import {L2DACommitmentScheme} from "contracts/common/Config.sol"; import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; import {L1Nullifier} from "contracts/bridge/L1Nullifier.sol"; import {L1NullifierDev} from "contracts/dev-contracts/L1NullifierDev.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; -import {DiamondProxy} from "contracts/state-transition/chain-deps/DiamondProxy.sol"; import {IRollupDAManager} from "./interfaces/IRollupDAManager.sol"; import {ChainRegistrar} from "contracts/chain-registrar/ChainRegistrar.sol"; import {L2LegacySharedBridgeTestHelper} from "./L2LegacySharedBridgeTestHelper.sol"; import {IOwnable} from "contracts/common/interfaces/IOwnable.sol"; +import {ZKsyncOSDualVerifier} from "contracts/state-transition/verifiers/ZKsyncOSDualVerifier.sol"; +import {IVerifierV2} from "contracts/state-transition/chain-interfaces/IVerifierV2.sol"; +import {IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; + import {DefaultUpgrade} from "contracts/upgrades/DefaultUpgrade.sol"; import {Governance} from "contracts/governance/Governance.sol"; import {L1GenesisUpgrade} from "contracts/upgrades/L1GenesisUpgrade.sol"; import {ChainAdmin} from "contracts/governance/ChainAdmin.sol"; import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; -import {CTMDeploymentTracker} from "contracts/bridgehub/CTMDeploymentTracker.sol"; +import {L1Bridgehub} from "contracts/bridgehub/L1Bridgehub.sol"; +import {L1ChainAssetHandler} from "contracts/bridgehub/L1ChainAssetHandler.sol"; +import {L1MessageRoot} from "contracts/bridgehub/L1MessageRoot.sol"; +import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-deps/ZKChainStorage.sol"; + import {L1NativeTokenVault} from "contracts/bridge/ntv/L1NativeTokenVault.sol"; + import {ExecutorFacet} from "contracts/state-transition/chain-deps/facets/Executor.sol"; import {AdminFacet} from "contracts/state-transition/chain-deps/facets/Admin.sol"; import {MailboxFacet} from "contracts/state-transition/chain-deps/facets/Mailbox.sol"; import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; -import {DiamondInit} from "contracts/state-transition/chain-deps/DiamondInit.sol"; -import {EraChainTypeManager} from "contracts/state-transition/EraChainTypeManager.sol"; -import {ZKsyncOSChainTypeManager} from "contracts/state-transition/ZKsyncOSChainTypeManager.sol"; import {L1AssetRouter} from "contracts/bridge/asset-router/L1AssetRouter.sol"; -import {L1ERC20Bridge} from "contracts/bridge/L1ERC20Bridge.sol"; -import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol"; import {ValidiumL1DAValidator} from "contracts/state-transition/data-availability/ValidiumL1DAValidator.sol"; import {RollupDAManager} from "contracts/state-transition/data-availability/RollupDAManager.sol"; import {BytecodesSupplier} from "contracts/upgrades/BytecodesSupplier.sol"; import {ChainAdminOwnable} from "contracts/governance/ChainAdminOwnable.sol"; import {ServerNotifier} from "contracts/governance/ServerNotifier.sol"; -import {Config, DeployedAddresses, GeneratedData} from "./DeployUtils.s.sol"; -import {DeployL1HelperScript} from "./DeployL1HelperScript.s.sol"; +import {Config, DeployedAddresses, DeployCTMUtils} from "./DeployCTMUtils.s.sol"; +import {AddressIntrospector} from "./AddressIntrospector.sol"; import {FixedForceDeploymentsData} from "contracts/state-transition/l2-deps/IL2GenesisUpgrade.sol"; - -import {L2AssetRouter} from "contracts/bridge/asset-router/L2AssetRouter.sol"; -import {L2NativeTokenVaultZKOS} from "contracts/bridge/ntv/L2NativeTokenVaultZKOS.sol"; -import {L2MessageRoot} from "contracts/bridgehub/L2MessageRoot.sol"; -import {L2Bridgehub} from "contracts/bridgehub/L2Bridgehub.sol"; -import {ZKsyncOSDualVerifier} from "contracts/state-transition/verifiers/ZKsyncOSDualVerifier.sol"; -import {IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; -import {IVerifierV2} from "contracts/state-transition/chain-interfaces/IVerifierV2.sol"; -import {EraTestnetVerifier} from "contracts/state-transition/verifiers/EraTestnetVerifier.sol"; - -import {Utils} from "./Utils.sol"; - +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; +import {PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET} from "contracts/common/Config.sol"; // TODO: pass this value from zkstack_cli uint32 constant DEFAULT_ZKSYNC_OS_VERIFIER_VERSION = 3; -contract DeployCTMScript is Script, DeployL1HelperScript { +contract DeployCTMScript is Script, DeployCTMUtils { using stdToml for string; function run() public virtual { @@ -79,16 +74,17 @@ contract DeployCTMScript is Script, DeployL1HelperScript { console.log("Deploying CTM related contracts"); runInner( - "/script-config/config-deploy-l1.toml", - "/script-out/output-deploy-l1.toml", + "/script-config/config-deploy-ctm.toml", + "/script-out/output-deploy-ctm.toml", bridgehub, - reuseGovAndAdmin + reuseGovAndAdmin, + false ); } - function runForTest(address bridgehub) public { + function runForTest(address bridgehub, bool skipL1Deployments) public { saveDiamondSelectors(); - runInner(vm.envString("L1_CONFIG"), vm.envString("L1_OUTPUT"), bridgehub, false); + runInner(vm.envString("CTM_CONFIG"), vm.envString("CTM_OUTPUT"), bridgehub, false, skipL1Deployments); } function getAddresses() public view returns (DeployedAddresses memory) { @@ -103,7 +99,8 @@ contract DeployCTMScript is Script, DeployL1HelperScript { string memory inputPath, string memory outputPath, address bridgehub, - bool reuseGovAndAdmin + bool reuseGovAndAdmin, + bool skipL1Deployments ) internal { string memory root = vm.projectRoot(); inputPath = string.concat(root, inputPath); @@ -111,40 +108,19 @@ contract DeployCTMScript is Script, DeployL1HelperScript { initializeConfig(inputPath); - instantiateCreate2Factory(); + if (!skipL1Deployments) { + instantiateCreate2Factory(); + } console.log("Initializing core contracts from BH"); IL1Bridgehub bridgehubProxy = IL1Bridgehub(bridgehub); - L1AssetRouter assetRouter = L1AssetRouter(address(bridgehubProxy.assetRouter())); - address messageRoot = address(bridgehubProxy.messageRoot()); - address l1CtmDeployer = address(bridgehubProxy.l1CtmDeployer()); - address chainAssetHandler = address(bridgehubProxy.chainAssetHandler()); - address nativeTokenVault = address(assetRouter.nativeTokenVault()); - address erc20Bridge = address(assetRouter.legacyBridge()); - address l1Nullifier = address(assetRouter.L1_NULLIFIER()); - - addresses.bridgehub.bridgehubProxy = bridgehub; - addresses.bridgehub.bridgehubImplementation = Utils.getImplementation(bridgehub); - addresses.bridgehub.ctmDeploymentTrackerProxy = l1CtmDeployer; - addresses.bridgehub.ctmDeploymentTrackerImplementation = Utils.getImplementation(l1CtmDeployer); - addresses.bridgehub.messageRootProxy = messageRoot; - addresses.bridgehub.messageRootImplementation = Utils.getImplementation(messageRoot); - addresses.bridgehub.chainAssetHandlerProxy = chainAssetHandler; - addresses.bridgehub.chainAssetHandlerImplementation = Utils.getImplementation(chainAssetHandler); - - // Bridges - addresses.bridges.erc20BridgeProxy = erc20Bridge; - addresses.bridges.erc20BridgeImplementation = Utils.getImplementation(erc20Bridge); - addresses.bridges.l1NullifierProxy = l1Nullifier; - addresses.bridges.l1NullifierImplementation = Utils.getImplementation(l1Nullifier); - addresses.bridges.l1AssetRouterProxy = address(assetRouter); - addresses.bridges.l1AssetRouterImplementation = Utils.getImplementation(address(assetRouter)); - addresses.vaults.l1NativeTokenVaultProxy = nativeTokenVault; + // Populate discovered addresses via inspector + discoveredBridgehub = AddressIntrospector.getBridgehubAddresses(bridgehubProxy); if (reuseGovAndAdmin) { - addresses.governance = IOwnable(bridgehub).owner(); - addresses.chainAdmin = bridgehubProxy.admin(); - addresses.transparentProxyAdmin = Utils.getProxyAdmin(bridgehub); + addresses.governance = discoveredBridgehub.governance; + addresses.chainAdmin = discoveredBridgehub.admin; + addresses.transparentProxyAdmin = discoveredBridgehub.transparentProxyAdmin; } else { (addresses.governance) = deploySimpleContract("Governance", false); (addresses.chainAdmin) = deploySimpleContract("ChainAdminOwnable", false); @@ -203,10 +179,6 @@ contract DeployCTMScript is Script, DeployL1HelperScript { } } - function getRollupL2DACommitmentScheme() internal returns (L2DACommitmentScheme) { - return ROLLUP_L2_DA_COMMITMENT_SCHEME; - } - function deployVerifiers() internal { if (config.isZKsyncOS) { (addresses.stateTransition.verifierFflonk) = deploySimpleContract("ZKsyncOSVerifierFflonk", false); @@ -266,7 +238,7 @@ contract DeployCTMScript is Script, DeployL1HelperScript { if (config.isZKsyncOS) { rollupDAManager.updateDAPair( addresses.daAddresses.l1BlobsDAValidatorZKsyncOS, - L2DACommitmentScheme.BLOBS_ZKSYNC_OS, + getRollupL2DACommitmentScheme(), true ); } @@ -285,27 +257,6 @@ contract DeployCTMScript is Script, DeployL1HelperScript { } } - function deployDiamondProxy() internal { - Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](1); - facetCuts[0] = Diamond.FacetCut({ - facet: addresses.stateTransition.adminFacet, - action: Diamond.Action.Add, - isFreezable: false, - selectors: Utils.getAllSelectors(addresses.stateTransition.adminFacet.code) - }); - Diamond.DiamondCutData memory diamondCut = Diamond.DiamondCutData({ - facetCuts: facetCuts, - initAddress: address(0), - initCalldata: "" - }); - address contractAddress = deployViaCreate2( - type(DiamondProxy).creationCode, - abi.encode(config.l1ChainId, diamondCut) - ); - console.log("DiamondProxy deployed at:", contractAddress); - addresses.stateTransition.diamondProxy = contractAddress; - } - function updateOwners() internal { vm.startBroadcast(msg.sender); @@ -331,118 +282,35 @@ contract DeployCTMScript is Script, DeployL1HelperScript { } function saveOutput(string memory outputPath) internal virtual { - vm.serializeAddress("bridgehub", "bridgehub_proxy_addr", addresses.bridgehub.bridgehubProxy); - vm.serializeAddress("bridgehub", "bridgehub_implementation_addr", addresses.bridgehub.bridgehubImplementation); - vm.serializeAddress( - "bridgehub", - "chain_asset_handler_implementation_addr", - addresses.bridgehub.chainAssetHandlerImplementation - ); - vm.serializeAddress("bridgehub", "chain_asset_handler_proxy_addr", addresses.bridgehub.chainAssetHandlerProxy); - vm.serializeAddress( - "bridgehub", - "ctm_deployment_tracker_proxy_addr", - addresses.bridgehub.ctmDeploymentTrackerProxy - ); - vm.serializeAddress( - "bridgehub", - "ctm_deployment_tracker_implementation_addr", - addresses.bridgehub.ctmDeploymentTrackerImplementation - ); - vm.serializeAddress("bridgehub", "message_root_proxy_addr", addresses.bridgehub.messageRootProxy); string memory bridgehub = vm.serializeAddress( "bridgehub", - "message_root_implementation_addr", - addresses.bridgehub.messageRootImplementation + "bridgehub_proxy_addr", + discoveredBridgehub.bridgehubProxy + ); + // Note: AssetRouterAddresses doesn't have legacyBridge, so we get it directly + L1AssetRouter assetRouter = L1AssetRouter(discoveredBridgehub.assetRouter); + vm.serializeAddress("bridges", "erc20_bridge_proxy_addr", address(assetRouter.legacyBridge())); + vm.serializeAddress("bridges", "l1_nullifier_proxy_addr", discoveredBridgehub.assetRouterAddresses.l1Nullifier); + string memory bridges = vm.serializeAddress( + "bridges", + "shared_bridge_proxy_addr", + discoveredBridgehub.assetRouter ); - // TODO(EVM-744): this has to be renamed to chain type manager vm.serializeAddress( "state_transition", "state_transition_proxy_addr", addresses.stateTransition.chainTypeManagerProxy ); - vm.serializeAddress( - "state_transition", - "state_transition_implementation_addr", - addresses.stateTransition.chainTypeManagerImplementation - ); vm.serializeAddress("state_transition", "verifier_addr", addresses.stateTransition.verifier); - vm.serializeAddress("state_transition", "admin_facet_addr", addresses.stateTransition.adminFacet); - vm.serializeAddress("state_transition", "mailbox_facet_addr", addresses.stateTransition.mailboxFacet); - vm.serializeAddress("state_transition", "executor_facet_addr", addresses.stateTransition.executorFacet); - vm.serializeAddress("state_transition", "getters_facet_addr", addresses.stateTransition.gettersFacet); - vm.serializeAddress("state_transition", "diamond_init_addr", addresses.stateTransition.diamondInit); vm.serializeAddress("state_transition", "genesis_upgrade_addr", addresses.stateTransition.genesisUpgrade); vm.serializeAddress("state_transition", "default_upgrade_addr", addresses.stateTransition.defaultUpgrade); - vm.serializeAddress("state_transition", "bytecodes_supplier_addr", addresses.stateTransition.bytecodesSupplier); string memory stateTransition = vm.serializeAddress( "state_transition", - "diamond_proxy_addr", - addresses.stateTransition.diamondProxy + "bytecodes_supplier_addr", + addresses.stateTransition.bytecodesSupplier ); - vm.serializeAddress("bridges", "erc20_bridge_implementation_addr", addresses.bridges.erc20BridgeImplementation); - vm.serializeAddress("bridges", "erc20_bridge_proxy_addr", addresses.bridges.erc20BridgeProxy); - vm.serializeAddress("bridges", "l1_nullifier_implementation_addr", addresses.bridges.l1NullifierImplementation); - vm.serializeAddress("bridges", "l1_nullifier_proxy_addr", addresses.bridges.l1NullifierProxy); - vm.serializeAddress( - "bridges", - "shared_bridge_implementation_addr", - addresses.bridges.l1AssetRouterImplementation - ); - string memory bridges = vm.serializeAddress( - "bridges", - "shared_bridge_proxy_addr", - addresses.bridges.l1AssetRouterProxy - ); - - vm.serializeUint( - "contracts_config", - "diamond_init_max_l2_gas_per_batch", - config.contracts.diamondInitMaxL2GasPerBatch - ); - vm.serializeUint( - "contracts_config", - "diamond_init_batch_overhead_l1_gas", - config.contracts.diamondInitBatchOverheadL1Gas - ); - vm.serializeUint( - "contracts_config", - "diamond_init_max_pubdata_per_batch", - config.contracts.diamondInitMaxPubdataPerBatch - ); - vm.serializeUint( - "contracts_config", - "diamond_init_minimal_l2_gas_price", - config.contracts.diamondInitMinimalL2GasPrice - ); - vm.serializeUint( - "contracts_config", - "diamond_init_priority_tx_max_pubdata", - config.contracts.diamondInitPriorityTxMaxPubdata - ); - vm.serializeUint( - "contracts_config", - "diamond_init_pubdata_pricing_mode", - uint256(config.contracts.diamondInitPubdataPricingMode) - ); - vm.serializeUint("contracts_config", "priority_tx_max_gas_limit", config.contracts.priorityTxMaxGasLimit); - vm.serializeBytes32( - "contracts_config", - "recursion_circuits_set_vks_hash", - config.contracts.recursionCircuitsSetVksHash - ); - vm.serializeBytes32( - "contracts_config", - "recursion_leaf_level_vk_hash", - config.contracts.recursionLeafLevelVkHash - ); - vm.serializeBytes32( - "contracts_config", - "recursion_node_level_vk_hash", - config.contracts.recursionNodeLevelVkHash - ); vm.serializeBytes("contracts_config", "diamond_cut_data", config.contracts.diamondCutData); string memory contractsConfig = vm.serializeBytes( @@ -450,19 +318,15 @@ contract DeployCTMScript is Script, DeployL1HelperScript { "force_deployments_data", generatedData.forceDeploymentsData ); - vm.serializeAddress( "deployed_addresses", "server_notifier_proxy_addr", addresses.stateTransition.serverNotifierProxy ); - vm.serializeAddress( - "deployed_addresses", - "server_notifier_implementation_address", - addresses.stateTransition.serverNotifierImplementation - ); + vm.serializeAddress("deployed_addresses", "governance_addr", addresses.governance); vm.serializeAddress("deployed_addresses", "chain_admin", addresses.chainAdmin); + vm.serializeString("deployed_addresses", "bridges", bridges); vm.serializeAddress("deployed_addresses", "transparent_proxy_admin_addr", addresses.transparentProxyAdmin); vm.serializeAddress( @@ -470,15 +334,6 @@ contract DeployCTMScript is Script, DeployL1HelperScript { "validator_timelock_addr", addresses.stateTransition.validatorTimelock ); - vm.serializeAddress( - "deployed_addresses", - "access_control_restriction_addr", - addresses.accessControlRestrictionAddress - ); - vm.serializeString("deployed_addresses", "bridgehub", bridgehub); - vm.serializeString("deployed_addresses", "bridges", bridges); - vm.serializeString("deployed_addresses", "state_transition", stateTransition); - vm.serializeAddress("deployed_addresses", "l1_rollup_da_manager", addresses.daAddresses.rollupDAManager); vm.serializeAddress( "deployed_addresses", @@ -495,42 +350,47 @@ contract DeployCTMScript is Script, DeployL1HelperScript { "avail_l1_da_validator_addr", addresses.daAddresses.availL1DAValidator ); - - string memory deployedAddresses = vm.serializeAddress( - "deployed_addresses", - "native_token_vault_addr", - addresses.vaults.l1NativeTokenVaultProxy - ); - - vm.serializeAddress("root", "create2_factory_addr", create2FactoryState.create2FactoryAddress); - vm.serializeBytes32("root", "create2_factory_salt", create2FactoryParams.factorySalt); + string memory deployedAddresses = vm.serializeString("deployed_addresses", "state_transition", stateTransition); vm.serializeAddress("root", "multicall3_addr", config.contracts.multicall3Addr); - vm.serializeUint("root", "l1_chain_id", config.l1ChainId); - vm.serializeUint("root", "era_chain_id", config.eraChainId); - vm.serializeAddress("root", "deployer_addr", config.deployerAddress); vm.serializeString("root", "deployed_addresses", deployedAddresses); - vm.serializeString("root", "contracts_config", contractsConfig); - string memory toml = vm.serializeAddress("root", "owner_address", config.ownerAddress); - + vm.serializeAddress("root", "create2_factory_addr", create2FactoryState.create2FactoryAddress); + vm.serializeBytes32("root", "create2_factory_salt", create2FactoryParams.factorySalt); + string memory toml = vm.serializeString("root", "contracts_config", contractsConfig); vm.writeToml(toml, outputPath); } function prepareForceDeploymentsData() internal returns (bytes memory) { require(addresses.governance != address(0), "Governance address is not set"); - address dangerousTestOnlyForcedBeacon; - if (config.supportL2LegacySharedBridgeTest) { - (dangerousTestOnlyForcedBeacon, ) = L2LegacySharedBridgeTestHelper.calculateTestL2TokenBeaconAddress( - addresses.bridges.erc20BridgeProxy, - addresses.bridges.l1NullifierProxy, - addresses.governance - ); + address dangerousTestOnlyForcedBeacon = _getDangerousTestOnlyForcedBeacon(); + + FixedForceDeploymentsData memory data = _buildForceDeploymentsData(dangerousTestOnlyForcedBeacon); + + return abi.encode(data); + } + + function _getDangerousTestOnlyForcedBeacon() private returns (address) { + if (!config.supportL2LegacySharedBridgeTest) { + return address(0); } - FixedForceDeploymentsData memory data = FixedForceDeploymentsData({ + L1AssetRouter assetRouter = L1AssetRouter(discoveredBridgehub.assetRouter); + (address beacon, ) = L2LegacySharedBridgeTestHelper.calculateTestL2TokenBeaconAddress( + address(assetRouter.legacyBridge()), + discoveredBridgehub.assetRouterAddresses.l1Nullifier, + addresses.governance + ); + return beacon; + } + + function _buildForceDeploymentsData( + address dangerousTestOnlyForcedBeacon + ) private returns (FixedForceDeploymentsData memory data) { + data = FixedForceDeploymentsData({ l1ChainId: config.l1ChainId, + gatewayChainId: config.gatewayChainId, eraChainId: config.eraChainId, - l1AssetRouter: addresses.bridges.l1AssetRouterProxy, + l1AssetRouter: discoveredBridgehub.assetRouter, l2TokenProxyBytecodeHash: getL2BytecodeHash("BeaconProxy"), aliasedL1Governance: AddressAliasHelper.applyL1ToL2Alias(addresses.governance), maxNumberOfZKChains: config.contracts.maxNumberOfChains, @@ -552,14 +412,24 @@ contract DeployCTMScript is Script, DeployL1HelperScript { chainAssetHandlerBytecodeInfo: config.isZKsyncOS ? Utils.getZKOSProxyUpgradeBytecodeInfo("L2ChainAssetHandler.sol", "L2ChainAssetHandler") : abi.encode(getL2BytecodeHash("L2ChainAssetHandler")), + interopCenterBytecodeInfo: config.isZKsyncOS + ? Utils.getZKOSProxyUpgradeBytecodeInfo("InteropCenter.sol", "InteropCenter") + : abi.encode(getL2BytecodeHash("InteropCenter")), + interopHandlerBytecodeInfo: config.isZKsyncOS + ? Utils.getZKOSProxyUpgradeBytecodeInfo("InteropHandler.sol", "InteropHandler") + : abi.encode(getL2BytecodeHash("InteropHandler")), + assetTrackerBytecodeInfo: config.isZKsyncOS + ? Utils.getZKOSProxyUpgradeBytecodeInfo("L2AssetTracker.sol", "L2AssetTracker") + : abi.encode(getL2BytecodeHash("L2AssetTracker")), // For newly created chains it it is expected that the following bridges are not present at the moment // of creation of the chain l2SharedBridgeLegacyImpl: address(0), l2BridgedStandardERC20Impl: address(0), + aliasedChainRegistrationSender: AddressAliasHelper.applyL1ToL2Alias( + discoveredBridgehub.chainRegistrationSenderProxy + ), dangerousTestOnlyForcedBeacon: dangerousTestOnlyForcedBeacon }); - - return abi.encode(data); } function deployServerNotifier() internal returns (address implementation, address proxy) { @@ -570,9 +440,23 @@ contract DeployCTMScript is Script, DeployL1HelperScript { } function saveDiamondSelectors() public { - AdminFacet adminFacet = new AdminFacet(1, RollupDAManager(address(0))); + AdminFacet adminFacet = new AdminFacet( + 1, + RollupDAManager(address(0)), + CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, + CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ); GettersFacet gettersFacet = new GettersFacet(); - MailboxFacet mailboxFacet = new MailboxFacet(1, 1, IEIP7702Checker(address(0))); + MailboxFacet mailboxFacet = new MailboxFacet( + 1, + 1, + discoveredBridgehub.chainAssetHandler, + IEIP7702Checker(address(0)), + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ); ExecutorFacet executorFacet = new ExecutorFacet(1); bytes4[] memory adminFacetSelectors = Utils.getAllSelectors(address(adminFacet).code); bytes4[] memory gettersFacetSelectors = Utils.getAllSelectors(address(gettersFacet).code); @@ -599,46 +483,6 @@ contract DeployCTMScript is Script, DeployL1HelperScript { vm.writeToml(toml, outputPath); } - /// @notice Get all four facet cuts - function getChainCreationFacetCuts( - StateTransitionDeployedAddresses memory stateTransition - ) internal virtual override returns (Diamond.FacetCut[] memory facetCuts) { - // Note: we use the provided stateTransition for the facet address, but not to get the selectors, as we use this feature for Gateway, which we cannot query. - // If we start to use different selectors for Gateway, we should change this. - facetCuts = new Diamond.FacetCut[](4); - facetCuts[0] = Diamond.FacetCut({ - facet: stateTransition.adminFacet, - action: Diamond.Action.Add, - isFreezable: false, - selectors: Utils.getAllSelectors(addresses.stateTransition.adminFacet.code) - }); - facetCuts[1] = Diamond.FacetCut({ - facet: stateTransition.gettersFacet, - action: Diamond.Action.Add, - isFreezable: false, - selectors: Utils.getAllSelectors(addresses.stateTransition.gettersFacet.code) - }); - facetCuts[2] = Diamond.FacetCut({ - facet: stateTransition.mailboxFacet, - action: Diamond.Action.Add, - isFreezable: true, - selectors: Utils.getAllSelectors(addresses.stateTransition.mailboxFacet.code) - }); - facetCuts[3] = Diamond.FacetCut({ - facet: stateTransition.executorFacet, - action: Diamond.Action.Add, - isFreezable: true, - selectors: Utils.getAllSelectors(addresses.stateTransition.executorFacet.code) - }); - } - - function getUpgradeAddedFacetCuts( - StateTransitionDeployedAddresses memory stateTransition - ) internal virtual override returns (Diamond.FacetCut[] memory facetCuts) { - // This function is not used in this script - revert("not implemented"); - } - // add this to be excluded from coverage report function test() internal virtual override {} } diff --git a/l1-contracts/deploy-scripts/DeployCTMAdditional.s.sol b/l1-contracts/deploy-scripts/DeployCTMAdditional.s.sol deleted file mode 100644 index 83c1e4b4c8..0000000000 --- a/l1-contracts/deploy-scripts/DeployCTMAdditional.s.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; - -import {DeployCTMScript} from "./DeployCTM.s.sol"; -import {L2ContractHelper} from "contracts/common/l2-helpers/L2ContractHelper.sol"; - -contract DeployCTMAdditional is DeployCTMScript { - function getL2BytecodeHash(string memory contractName) public view virtual override returns (bytes32) { - return L2ContractHelper.hashL2Bytecode(getCreationCode(contractName, true)); - } -} diff --git a/l1-contracts/deploy-scripts/DeployCTML1OrGateway.sol b/l1-contracts/deploy-scripts/DeployCTML1OrGateway.sol new file mode 100644 index 0000000000..a2a733f70b --- /dev/null +++ b/l1-contracts/deploy-scripts/DeployCTML1OrGateway.sol @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_START_MAINNET, CHAIN_MIGRATION_TIME_WINDOW_END_MAINNET, PAUSE_DEPOSITS_TIME_WINDOW_START_MAINNET, PAUSE_DEPOSITS_TIME_WINDOW_END_MAINNET} from "contracts/common/Config.sol"; + +struct CTMCoreDeploymentConfig { + bool isZKsyncOS; + bool testnetVerifier; + uint256 eraChainId; + uint256 l1ChainId; + address bridgehubProxy; + address interopCenterProxy; + address rollupDAManager; + address chainAssetHandler; + address eip7702Checker; + address verifierFflonk; + address verifierPlonk; + address ownerAddress; +} + +enum CTMContract { + AdminFacet, + MailboxFacet, + ExecutorFacet, + DiamondInit, + ValidatorTimelock, + Verifier, + ZKsyncOSChainTypeManager, + EraChainTypeManager +} + +library DeployCTML1OrGateway { + function getCreationCalldata( + CTMCoreDeploymentConfig memory config, + CTMContract contractName, + bool isZKBytecode + ) internal view returns (bytes memory) { + if (contractName == CTMContract.AdminFacet) { + uint256 chainMigrationTimeWindowStart = config.testnetVerifier + ? CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET + : CHAIN_MIGRATION_TIME_WINDOW_START_MAINNET; + uint256 chainMigrationTimeWindowEnd = config.testnetVerifier + ? CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET + : CHAIN_MIGRATION_TIME_WINDOW_END_MAINNET; + uint256 pauseDepositsTimeWindowStart = config.testnetVerifier + ? PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET + : PAUSE_DEPOSITS_TIME_WINDOW_START_MAINNET; + uint256 pauseDepositsTimeWindowEnd = config.testnetVerifier + ? PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + : PAUSE_DEPOSITS_TIME_WINDOW_END_MAINNET; + return + abi.encode( + config.l1ChainId, + config.rollupDAManager, + chainMigrationTimeWindowStart, + chainMigrationTimeWindowEnd, + pauseDepositsTimeWindowStart, + pauseDepositsTimeWindowEnd + ); + } else if (contractName == CTMContract.MailboxFacet) { + uint256 pauseDepositsTimeWindowStart = config.testnetVerifier + ? PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET + : PAUSE_DEPOSITS_TIME_WINDOW_START_MAINNET; + uint256 pauseDepositsTimeWindowEnd = config.testnetVerifier + ? PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + : PAUSE_DEPOSITS_TIME_WINDOW_END_MAINNET; + return + abi.encode( + config.eraChainId, + config.l1ChainId, + config.chainAssetHandler, + config.eip7702Checker, + pauseDepositsTimeWindowStart, + pauseDepositsTimeWindowEnd + ); + } else if (contractName == CTMContract.ValidatorTimelock) { + return abi.encode(config.bridgehubProxy); + } else if (contractName == CTMContract.ExecutorFacet) { + return abi.encode(config.l1ChainId); + } else if (contractName == CTMContract.DiamondInit) { + return abi.encode(config.isZKsyncOS); + } else if (contractName == CTMContract.Verifier) { + if (config.testnetVerifier) { + if (config.isZKsyncOS) { + return abi.encode(config.verifierFflonk, config.verifierPlonk, config.ownerAddress); + } else { + return abi.encode(config.verifierFflonk, config.verifierPlonk); + } + } else { + if (config.isZKsyncOS) { + return abi.encode(config.verifierFflonk, config.verifierPlonk, config.ownerAddress); + } else { + return abi.encode(config.verifierFflonk, config.verifierPlonk); + } + } + } else if (contractName == CTMContract.ZKsyncOSChainTypeManager) { + return abi.encode(config.bridgehubProxy, config.interopCenterProxy); + } else if (contractName == CTMContract.EraChainTypeManager) { + return abi.encode(config.bridgehubProxy, config.interopCenterProxy); + } + } + + function getCTMContractFromName(string memory contractName) internal view returns (CTMContract) { + if (compareStrings(contractName, "AdminFacet")) { + return CTMContract.AdminFacet; + } else if (compareStrings(contractName, "ExecutorFacet")) { + return CTMContract.ExecutorFacet; + } else if (compareStrings(contractName, "MailboxFacet")) { + return CTMContract.MailboxFacet; + } else if (compareStrings(contractName, "DiamondInit")) { + return CTMContract.DiamondInit; + } else if (compareStrings(contractName, "ValidatorTimelock")) { + return CTMContract.ValidatorTimelock; + } else if (compareStrings(contractName, "Verifier")) { + return CTMContract.Verifier; + } else if (compareStrings(contractName, "ZKsyncOSChainTypeManager")) { + return CTMContract.ZKsyncOSChainTypeManager; + } else if (compareStrings(contractName, "EraChainTypeManager")) { + return CTMContract.EraChainTypeManager; + } else if (compareStrings(contractName, "EraTestnetVerifier")) { + // The EraTestnetVerifier contract maps to the Verifier slot for testnets. + return CTMContract.Verifier; + } else { + revert(string.concat("Contract ", contractName, " not CTM contract, creation calldata could not be set")); + } + } + + function compareStrings(string memory a, string memory b) public pure returns (bool) { + return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b)); + } +} diff --git a/l1-contracts/deploy-scripts/DeployCTMUtils.s.sol b/l1-contracts/deploy-scripts/DeployCTMUtils.s.sol new file mode 100644 index 0000000000..61017f8ee4 --- /dev/null +++ b/l1-contracts/deploy-scripts/DeployCTMUtils.s.sol @@ -0,0 +1,542 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +// solhint-disable no-console, gas-custom-errors + +import {console2 as console} from "forge-std/Script.sol"; +import {stdToml} from "forge-std/StdToml.sol"; +import {IVerifier, VerifierParams} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; +import {ChainCreationParams, ChainTypeManagerInitializeData} from "contracts/state-transition/IChainTypeManager.sol"; +import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; +import {InitializeDataNewChain as DiamondInitializeDataNewChain} from "contracts/state-transition/chain-interfaces/IDiamondInit.sol"; +import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-deps/ZKChainStorage.sol"; +import {L2ContractHelper} from "contracts/common/l2-helpers/L2ContractHelper.sol"; +import {Utils} from "./Utils.sol"; + +import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; +import {L2ContractHelper} from "contracts/common/l2-helpers/L2ContractHelper.sol"; +import {ICTMDeploymentTracker} from "contracts/bridgehub/ICTMDeploymentTracker.sol"; +import {IOwnable} from "contracts/common/interfaces/IOwnable.sol"; +import {L2DACommitmentScheme, ROLLUP_L2_DA_COMMITMENT_SCHEME} from "contracts/common/Config.sol"; + +import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; +import {Governance} from "contracts/governance/Governance.sol"; +import {ChainAdmin} from "contracts/governance/ChainAdmin.sol"; +import {L1NativeTokenVault} from "contracts/bridge/ntv/L1NativeTokenVault.sol"; +import {L1AssetRouter} from "contracts/bridge/asset-router/L1AssetRouter.sol"; +import {L1ERC20Bridge} from "contracts/bridge/L1ERC20Bridge.sol"; +import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol"; +import {ChainAdminOwnable} from "contracts/governance/ChainAdminOwnable.sol"; +import {ContractsBytecodesLib} from "./ContractsBytecodesLib.sol"; +import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; +import {IRollupDAManager} from "./interfaces/IRollupDAManager.sol"; +import {EraDualVerifier} from "contracts/state-transition/verifiers/EraDualVerifier.sol"; +import {EraVerifierPlonk} from "contracts/state-transition/verifiers/EraVerifierPlonk.sol"; +import {EraVerifierFflonk} from "contracts/state-transition/verifiers/EraVerifierFflonk.sol"; +import {EraTestnetVerifier} from "contracts/state-transition/verifiers/EraTestnetVerifier.sol"; +import {ZKsyncOSTestnetVerifier} from "contracts/state-transition/verifiers/ZKsyncOSTestnetVerifier.sol"; +import {IVerifier, VerifierParams} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; +import {DefaultUpgrade} from "contracts/upgrades/DefaultUpgrade.sol"; +import {L1GenesisUpgrade} from "contracts/upgrades/L1GenesisUpgrade.sol"; +import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; +import {ExecutorFacet} from "contracts/state-transition/chain-deps/facets/Executor.sol"; +import {AdminFacet} from "contracts/state-transition/chain-deps/facets/Admin.sol"; +import {MailboxFacet} from "contracts/state-transition/chain-deps/facets/Mailbox.sol"; +import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; +import {DiamondInit} from "contracts/state-transition/chain-deps/DiamondInit.sol"; +import {ZKsyncOSChainTypeManager} from "contracts/state-transition/ZKsyncOSChainTypeManager.sol"; +import {EraChainTypeManager} from "contracts/state-transition/EraChainTypeManager.sol"; +import {ChainTypeManagerBase} from "contracts/state-transition/ChainTypeManagerBase.sol"; + +import {ValidiumL1DAValidator} from "contracts/state-transition/data-availability/ValidiumL1DAValidator.sol"; +import {RollupDAManager} from "contracts/state-transition/data-availability/RollupDAManager.sol"; +import {BytecodesSupplier} from "contracts/upgrades/BytecodesSupplier.sol"; +import {ServerNotifier} from "contracts/governance/ServerNotifier.sol"; +import {UpgradeStageValidator} from "contracts/upgrades/UpgradeStageValidator.sol"; +import {DeployUtils} from "./DeployUtils.sol"; +import {AddressIntrospector} from "./AddressIntrospector.sol"; +import {CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_START_MAINNET, CHAIN_MIGRATION_TIME_WINDOW_END_MAINNET, PAUSE_DEPOSITS_TIME_WINDOW_START_MAINNET, PAUSE_DEPOSITS_TIME_WINDOW_END_MAINNET} from "contracts/common/Config.sol"; + +import {Create2FactoryUtils} from "./Create2FactoryUtils.s.sol"; +import {StateTransitionDeployedAddresses, DataAvailabilityDeployedAddresses, ChainCreationParamsConfig} from "./Types.sol"; + +import {DeployCTML1OrGateway, CTMCoreDeploymentConfig, CTMContract} from "./DeployCTML1OrGateway.sol"; + +// solhint-disable-next-line gas-struct-packing +struct DeployedAddresses { + StateTransitionDeployedAddresses stateTransition; + DataAvailabilityDeployedAddresses daAddresses; + address transparentProxyAdmin; + address governance; + address chainAdmin; + address accessControlRestrictionAddress; + address eip7702Checker; +} + +// solhint-disable-next-line gas-struct-packing +struct BridgesDeployedAddresses { + address erc20BridgeProxy; + address l1AssetRouterProxy; + address l1NullifierProxy; +} + +// solhint-disable-next-line gas-struct-packing +struct Config { + uint256 l1ChainId; + address deployerAddress; + uint256 eraChainId; + uint256 gatewayChainId; + address ownerAddress; + bool testnetVerifier; + bool supportL2LegacySharedBridgeTest; + bool isZKsyncOS; + ContractsConfig contracts; +} + +// solhint-disable-next-line gas-struct-packing +struct ContractsConfig { + address multicall3Addr; + uint256 validatorTimelockExecutionDelay; + address governanceSecurityCouncilAddress; + uint256 governanceMinDelay; + bytes diamondCutData; + uint256 maxNumberOfChains; + // questionable + address availL1DAValidator; + ChainCreationParamsConfig chainCreationParams; +} + +// solhint-disable-next-line gas-struct-packing +struct GeneratedData { + bytes forceDeploymentsData; +} + +abstract contract DeployCTMUtils is DeployUtils { + using stdToml for string; + + Config public config; + GeneratedData internal generatedData; + DeployedAddresses internal addresses; + // Addresses discovered from already deployed core contracts (Bridgehub, AssetRouter, etc.) + AddressIntrospector.BridgehubAddresses internal discoveredBridgehub; + + function deployStateTransitionDiamondFacets() internal { + addresses.stateTransition.executorFacet = deploySimpleContract("ExecutorFacet", false); + addresses.stateTransition.adminFacet = deploySimpleContract("AdminFacet", false); + addresses.stateTransition.mailboxFacet = deploySimpleContract("MailboxFacet", false); + addresses.stateTransition.gettersFacet = deploySimpleContract("GettersFacet", false); + addresses.stateTransition.diamondInit = deploySimpleContract("DiamondInit", false); + } + + function initializeConfig(string memory configPath) internal virtual { + string memory toml = vm.readFile(configPath); + + config.l1ChainId = block.chainid; + config.deployerAddress = msg.sender; + + // Config file must be parsed key by key, otherwise values returned + // are parsed alfabetically and not by key. + // https://book.getfoundry.sh/cheatcodes/parse-toml + config.ownerAddress = toml.readAddress("$.owner_address"); + config.testnetVerifier = toml.readBool("$.testnet_verifier"); + config.eraChainId = toml.readUint("$.era_chain_id"); + config.supportL2LegacySharedBridgeTest = toml.readBool("$.support_l2_legacy_shared_bridge_test"); + if (toml.keyExists("$.is_zk_sync_os")) { + config.isZKsyncOS = toml.readBool("$.is_zk_sync_os"); + } + bytes32 create2FactorySalt = toml.readBytes32("$.contracts.create2_factory_salt"); + address create2FactoryAddr; + if (vm.keyExistsToml(toml, "$.contracts.create2_factory_addr")) { + create2FactoryAddr = toml.readAddress("$.contracts.create2_factory_addr"); + } + _initCreate2FactoryParams(create2FactoryAddr, create2FactorySalt); + config.contracts.governanceSecurityCouncilAddress = toml.readAddress( + "$.contracts.governance_security_council_address" + ); + config.contracts.governanceMinDelay = toml.readUint("$.contracts.governance_min_delay"); + + config.contracts.validatorTimelockExecutionDelay = toml.readUint( + "$.contracts.validator_timelock_execution_delay" + ); + config.contracts.chainCreationParams.genesisRoot = toml.readBytes32("$.contracts.genesis_root"); + config.contracts.chainCreationParams.genesisRollupLeafIndex = toml.readUint( + "$.contracts.genesis_rollup_leaf_index" + ); + config.contracts.chainCreationParams.genesisBatchCommitment = toml.readBytes32( + "$.contracts.genesis_batch_commitment" + ); + config.contracts.chainCreationParams.latestProtocolVersion = toml.readUint( + "$.contracts.latest_protocol_version" + ); + config.contracts.chainCreationParams.priorityTxMaxGasLimit = toml.readUint( + "$.contracts.priority_tx_max_gas_limit" + ); + config.contracts.chainCreationParams.diamondInitPubdataPricingMode = PubdataPricingMode( + toml.readUint("$.contracts.diamond_init_pubdata_pricing_mode") + ); + config.contracts.chainCreationParams.diamondInitBatchOverheadL1Gas = toml.readUint( + "$.contracts.diamond_init_batch_overhead_l1_gas" + ); + config.contracts.chainCreationParams.diamondInitMaxPubdataPerBatch = toml.readUint( + "$.contracts.diamond_init_max_pubdata_per_batch" + ); + config.contracts.chainCreationParams.diamondInitMaxL2GasPerBatch = toml.readUint( + "$.contracts.diamond_init_max_l2_gas_per_batch" + ); + config.contracts.chainCreationParams.diamondInitPriorityTxMaxPubdata = toml.readUint( + "$.contracts.diamond_init_priority_tx_max_pubdata" + ); + config.contracts.chainCreationParams.diamondInitMinimalL2GasPrice = toml.readUint( + "$.contracts.diamond_init_minimal_l2_gas_price" + ); + config.contracts.chainCreationParams.defaultAAHash = toml.readBytes32("$.contracts.default_aa_hash"); + config.contracts.chainCreationParams.bootloaderHash = toml.readBytes32("$.contracts.bootloader_hash"); + config.contracts.chainCreationParams.evmEmulatorHash = toml.readBytes32("$.contracts.evm_emulator_hash"); + + if (vm.keyExistsToml(toml, "$.contracts.avail_l1_da_validator")) { + config.contracts.availL1DAValidator = toml.readAddress("$.contracts.avail_l1_da_validator"); + } + } + + /// @notice Get all four facet cuts + function getChainCreationFacetCuts( + StateTransitionDeployedAddresses memory stateTransition + ) internal virtual returns (Diamond.FacetCut[] memory facetCuts) { + // Note: we use the provided stateTransition for the facet address, but not to get the selectors, as we use this feature for Gateway, which we cannot query. + // If we start to use different selectors for Gateway, we should change this. + facetCuts = new Diamond.FacetCut[](4); + facetCuts[0] = Diamond.FacetCut({ + facet: stateTransition.adminFacet, + action: Diamond.Action.Add, + isFreezable: false, + selectors: Utils.getAllSelectors(addresses.stateTransition.adminFacet.code) + }); + facetCuts[1] = Diamond.FacetCut({ + facet: stateTransition.gettersFacet, + action: Diamond.Action.Add, + isFreezable: false, + selectors: Utils.getAllSelectors(addresses.stateTransition.gettersFacet.code) + }); + facetCuts[2] = Diamond.FacetCut({ + facet: stateTransition.mailboxFacet, + action: Diamond.Action.Add, + isFreezable: true, + selectors: Utils.getAllSelectors(addresses.stateTransition.mailboxFacet.code) + }); + facetCuts[3] = Diamond.FacetCut({ + facet: stateTransition.executorFacet, + action: Diamond.Action.Add, + isFreezable: true, + selectors: Utils.getAllSelectors(addresses.stateTransition.executorFacet.code) + }); + } + + function getChainCreationDiamondCutData( + StateTransitionDeployedAddresses memory stateTransition + ) internal returns (Diamond.DiamondCutData memory diamondCut) { + Diamond.FacetCut[] memory facetCuts = getChainCreationFacetCuts(stateTransition); + + DiamondInitializeDataNewChain memory initializeData = getInitializeData(stateTransition); + + diamondCut = Diamond.DiamondCutData({ + facetCuts: facetCuts, + initAddress: stateTransition.diamondInit, + initCalldata: abi.encode(initializeData) + }); + if (!stateTransition.isOnGateway) { + config.contracts.diamondCutData = abi.encode(diamondCut); + } + } + + function getChainCreationParams( + StateTransitionDeployedAddresses memory stateTransition + ) internal returns (ChainCreationParams memory) { + require(generatedData.forceDeploymentsData.length != 0, "force deployments data is empty"); + Diamond.DiamondCutData memory diamondCut = getChainCreationDiamondCutData(stateTransition); + return + ChainCreationParams({ + genesisUpgrade: stateTransition.genesisUpgrade, + genesisBatchHash: config.contracts.chainCreationParams.genesisRoot, + genesisIndexRepeatedStorageChanges: uint64(config.contracts.chainCreationParams.genesisRollupLeafIndex), + genesisBatchCommitment: config.contracts.chainCreationParams.genesisBatchCommitment, + diamondCut: diamondCut, + forceDeploymentsData: generatedData.forceDeploymentsData + }); + } + + function getChainTypeManagerInitializeData( + StateTransitionDeployedAddresses memory stateTransition + ) internal returns (ChainTypeManagerInitializeData memory) { + ChainCreationParams memory chainCreationParams = getChainCreationParams(stateTransition); + return + ChainTypeManagerInitializeData({ + owner: msg.sender, + validatorTimelock: stateTransition.validatorTimelock, + chainCreationParams: chainCreationParams, + protocolVersion: config.contracts.chainCreationParams.latestProtocolVersion, + serverNotifier: stateTransition.serverNotifierProxy + }); + } + + function getVerifierParams() internal returns (VerifierParams memory) { + return + VerifierParams({ + recursionNodeLevelVkHash: bytes32(0), + recursionLeafLevelVkHash: bytes32(0), + recursionCircuitsSetVksHash: bytes32(0) + }); + } + + function getFeeParams() internal returns (FeeParams memory) { + return + FeeParams({ + pubdataPricingMode: config.contracts.chainCreationParams.diamondInitPubdataPricingMode, + batchOverheadL1Gas: uint32(config.contracts.chainCreationParams.diamondInitBatchOverheadL1Gas), + maxPubdataPerBatch: uint32(config.contracts.chainCreationParams.diamondInitMaxPubdataPerBatch), + maxL2GasPerBatch: uint32(config.contracts.chainCreationParams.diamondInitMaxL2GasPerBatch), + priorityTxMaxPubdata: uint32(config.contracts.chainCreationParams.diamondInitPriorityTxMaxPubdata), + minimalL2GasPrice: uint64(config.contracts.chainCreationParams.diamondInitMinimalL2GasPrice) + }); + } + + function getInitializeData( + StateTransitionDeployedAddresses memory stateTransition + ) internal returns (DiamondInitializeDataNewChain memory) { + VerifierParams memory verifierParams = getVerifierParams(); + + FeeParams memory feeParams = getFeeParams(); + + require(stateTransition.verifier != address(0), "verifier is zero"); + require(config.contracts.chainCreationParams.bootloaderHash != bytes32(0), "bootloader hash is zero"); + require(config.contracts.chainCreationParams.defaultAAHash != bytes32(0), "default aa hash is zero"); + require(config.contracts.chainCreationParams.evmEmulatorHash != bytes32(0), "evm emulator hash is zero"); + + return + DiamondInitializeDataNewChain({ + verifier: IVerifier(stateTransition.verifier), + verifierParams: verifierParams, + l2BootloaderBytecodeHash: config.contracts.chainCreationParams.bootloaderHash, + l2DefaultAccountBytecodeHash: config.contracts.chainCreationParams.defaultAAHash, + l2EvmEmulatorBytecodeHash: config.contracts.chainCreationParams.evmEmulatorHash, + priorityTxMaxGasLimit: config.contracts.chainCreationParams.priorityTxMaxGasLimit, + feeParams: feeParams + }); + } + + ////////////////////////////// Contract deployment modes ///////////////////////////////// + + function getCreationCode( + string memory contractName, + bool isZKBytecode + ) internal view virtual override returns (bytes memory) { + if (!isZKBytecode) { + if (compareStrings(contractName, "L1AssetRouter")) { + return type(L1AssetRouter).creationCode; + } else if (compareStrings(contractName, "L1ERC20Bridge")) { + return type(L1ERC20Bridge).creationCode; + } else if (compareStrings(contractName, "L1NativeTokenVault")) { + return type(L1NativeTokenVault).creationCode; + } else if (compareStrings(contractName, "BridgedStandardERC20")) { + return type(BridgedStandardERC20).creationCode; + } else if (compareStrings(contractName, "Governance")) { + return type(Governance).creationCode; + } else if (compareStrings(contractName, "ChainAdminOwnable")) { + return type(ChainAdminOwnable).creationCode; + } else if (compareStrings(contractName, "ChainAdmin")) { + return type(ChainAdmin).creationCode; + } else if (compareStrings(contractName, "ProxyAdmin")) { + return type(ProxyAdmin).creationCode; + } else if (compareStrings(contractName, "RollupDAManager")) { + return type(RollupDAManager).creationCode; + } else if (compareStrings(contractName, "ValidiumL1DAValidator")) { + return type(ValidiumL1DAValidator).creationCode; + } else if (compareStrings(contractName, "Verifier")) { + if (config.testnetVerifier) { + if (config.isZKsyncOS) { + return type(ZKsyncOSTestnetVerifier).creationCode; + } else { + return type(EraTestnetVerifier).creationCode; + } + } else { + return type(EraDualVerifier).creationCode; + } + } else if (compareStrings(contractName, "EraVerifierFflonk")) { + return type(EraVerifierFflonk).creationCode; + } else if (compareStrings(contractName, "EraVerifierPlonk")) { + return type(EraVerifierPlonk).creationCode; + } else if (compareStrings(contractName, "DefaultUpgrade")) { + return type(DefaultUpgrade).creationCode; + } else if (compareStrings(contractName, "L1GenesisUpgrade")) { + return type(L1GenesisUpgrade).creationCode; + } else if (compareStrings(contractName, "ValidatorTimelock")) { + return type(ValidatorTimelock).creationCode; + } else if (compareStrings(contractName, "EraChainTypeManager")) { + return type(EraChainTypeManager).creationCode; + } else if (compareStrings(contractName, "ZKsyncOSChainTypeManager")) { + return type(ZKsyncOSChainTypeManager).creationCode; + } else if (compareStrings(contractName, "BytecodesSupplier")) { + return type(BytecodesSupplier).creationCode; + } else if (compareStrings(contractName, "ExecutorFacet")) { + return type(ExecutorFacet).creationCode; + } else if (compareStrings(contractName, "AdminFacet")) { + return type(AdminFacet).creationCode; + } else if (compareStrings(contractName, "MailboxFacet")) { + return type(MailboxFacet).creationCode; + } else if (compareStrings(contractName, "GettersFacet")) { + return type(GettersFacet).creationCode; + } else if (compareStrings(contractName, "DiamondInit")) { + return type(DiamondInit).creationCode; + } else if (compareStrings(contractName, "ServerNotifier")) { + return type(ServerNotifier).creationCode; + } else if (compareStrings(contractName, "UpgradeStageValidator")) { + return type(UpgradeStageValidator).creationCode; + } + } else { + if (compareStrings(contractName, "Verifier")) { + if (config.testnetVerifier) { + return getCreationCode("TestnetVerifier", true); + } else { + return getCreationCode("DualVerifier", true); + } + } + } + return ContractsBytecodesLib.getCreationCode(contractName, isZKBytecode); + } + + function getRollupL2DACommitmentScheme() internal returns (L2DACommitmentScheme) { + return ROLLUP_L2_DA_COMMITMENT_SCHEME; + } + + function getCreationCalldata( + string memory contractName, + bool isZKBytecode + ) internal view virtual override returns (bytes memory) { + if (compareStrings(contractName, "BridgedStandardERC20")) { + return abi.encode(); + } else if (compareStrings(contractName, "EIP7702Checker")) { + return abi.encode(); + } else if (compareStrings(contractName, "RollupDAManager")) { + return abi.encode(); + } else if (compareStrings(contractName, "RollupL1DAValidator")) { + return abi.encode(addresses.daAddresses.l1RollupDAValidator); + } else if (compareStrings(contractName, "ValidiumL1DAValidator")) { + return abi.encode(); + } else if (compareStrings(contractName, "AvailL1DAValidator")) { + return abi.encode(addresses.daAddresses.availBridge); + } else if (compareStrings(contractName, "DummyAvailBridge")) { + return abi.encode(); + } else if (compareStrings(contractName, "EraVerifierFflonk")) { + return abi.encode(); + } else if (compareStrings(contractName, "EraVerifierPlonk")) { + return abi.encode(); + } else if (compareStrings(contractName, "ZKsyncOSVerifierFflonk")) { + return abi.encode(); + } else if (compareStrings(contractName, "ZKsyncOSVerifierPlonk")) { + return abi.encode(); + } else if (compareStrings(contractName, "DefaultUpgrade")) { + return abi.encode(); + } else if (compareStrings(contractName, "L1GenesisUpgrade")) { + return abi.encode(); + } else if (compareStrings(contractName, "Governance")) { + return + abi.encode( + config.ownerAddress, + config.contracts.governanceSecurityCouncilAddress, + config.contracts.governanceMinDelay + ); + } else if (compareStrings(contractName, "ChainAdminOwnable")) { + return abi.encode(config.ownerAddress, address(0)); + } else if (compareStrings(contractName, "AccessControlRestriction")) { + return abi.encode(uint256(0), config.ownerAddress); + } else if (compareStrings(contractName, "ChainAdmin")) { + address[] memory restrictions = new address[](1); + restrictions[0] = addresses.accessControlRestrictionAddress; + return abi.encode(restrictions); + } else if (compareStrings(contractName, "BytecodesSupplier")) { + return abi.encode(); + } else if (compareStrings(contractName, "ProxyAdmin")) { + return abi.encode(); + } else if (compareStrings(contractName, "GettersFacet")) { + return abi.encode(); + } else if (compareStrings(contractName, "ServerNotifier")) { + return abi.encode(); + } else if (compareStrings(contractName, "L1AssetTracker")) { + return + abi.encode( + config.l1ChainId, + discoveredBridgehub.bridgehubProxy, + discoveredBridgehub.assetRouter, + discoveredBridgehub.assetRouterAddresses.nativeTokenVault, + discoveredBridgehub.messageRoot + ); + } else { + return + DeployCTML1OrGateway.getCreationCalldata( + getCTMCoreDeploymentConfig(config), + DeployCTML1OrGateway.getCTMContractFromName(contractName), + isZKBytecode + ); + } + } + + function getCTMCoreDeploymentConfig(Config memory config) internal view returns (CTMCoreDeploymentConfig memory) { + return + CTMCoreDeploymentConfig({ + isZKsyncOS: config.isZKsyncOS, + testnetVerifier: config.testnetVerifier, + eraChainId: config.eraChainId, + l1ChainId: config.l1ChainId, + bridgehubProxy: discoveredBridgehub.bridgehubProxy, + interopCenterProxy: discoveredBridgehub.interopCenterProxy, + rollupDAManager: addresses.daAddresses.rollupDAManager, + chainAssetHandler: discoveredBridgehub.chainAssetHandler, + eip7702Checker: addresses.eip7702Checker, + verifierFflonk: addresses.stateTransition.verifierFflonk, + verifierPlonk: addresses.stateTransition.verifierPlonk, + ownerAddress: config.ownerAddress + }); + } + + function calculateExpectedL2Address(string memory contractName) internal returns (address) { + return Utils.getL2AddressViaCreate2Factory(bytes32(0), getL2BytecodeHash(contractName), hex""); + } + + function getL2BytecodeHash(string memory contractName) public view virtual returns (bytes32) { + return L2ContractHelper.hashL2Bytecode(getCreationCode(contractName, true)); + } + + function getInitializeCalldata( + string memory contractName, + bool isZKBytecode + ) internal virtual override returns (bytes memory) { + if (compareStrings(contractName, "EraChainTypeManager")) { + return + abi.encodeCall( + ChainTypeManagerBase.initialize, + getChainTypeManagerInitializeData(addresses.stateTransition) + ); + } else if (compareStrings(contractName, "ZKsyncOSChainTypeManager")) { + return + abi.encodeCall( + ChainTypeManagerBase.initialize, + getChainTypeManagerInitializeData(addresses.stateTransition) + ); + } else if (compareStrings(contractName, "ServerNotifier")) { + return abi.encodeCall(ServerNotifier.initialize, (config.deployerAddress)); + } else if (compareStrings(contractName, "ValidatorTimelock")) { + return + abi.encodeCall( + ValidatorTimelock.initialize, + (config.deployerAddress, uint32(config.contracts.validatorTimelockExecutionDelay)) + ); + } else { + revert(string.concat("Contract ", contractName, " initialize calldata not set")); + } + } + + function transparentProxyAdmin() internal view override returns (address) { + return addresses.transparentProxyAdmin; + } + + function test() internal virtual {} +} diff --git a/l1-contracts/deploy-scripts/DeployErc20.s.sol b/l1-contracts/deploy-scripts/DeployErc20.s.sol index 29916a6fd1..f61c541973 100644 --- a/l1-contracts/deploy-scripts/DeployErc20.s.sol +++ b/l1-contracts/deploy-scripts/DeployErc20.s.sol @@ -60,7 +60,7 @@ contract DeployErc20Script is Script { string memory root = vm.projectRoot(); // Grab config from output of l1 deployment - string memory path = string.concat(root, vm.envString("L1_OUTPUT")); + string memory path = string.concat(root, vm.envString("CTM_OUTPUT")); string memory toml = vm.readFile(path); // Config file must be parsed key by key, otherwise values returned diff --git a/l1-contracts/deploy-scripts/DeployL1CoreContracts.s.sol b/l1-contracts/deploy-scripts/DeployL1CoreContracts.s.sol index 4cfd9624a5..5f8ef7c4fa 100644 --- a/l1-contracts/deploy-scripts/DeployL1CoreContracts.s.sol +++ b/l1-contracts/deploy-scripts/DeployL1CoreContracts.s.sol @@ -5,12 +5,11 @@ pragma solidity ^0.8.24; import {Script, console2 as console} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; -import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; -import {StateTransitionDeployedAddresses} from "./Utils.sol"; import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; import {BridgehubBase} from "contracts/bridgehub/BridgehubBase.sol"; import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; +import {IL1AssetTracker, L1AssetTracker} from "contracts/bridge/asset-tracker/L1AssetTracker.sol"; import {INativeTokenVaultBase} from "contracts/bridge/ntv/INativeTokenVaultBase.sol"; import {IL1Nullifier, L1Nullifier} from "contracts/bridge/L1Nullifier.sol"; import {IL1NativeTokenVault} from "contracts/bridge/ntv/IL1NativeTokenVault.sol"; @@ -34,14 +33,13 @@ import {ServerNotifier} from "contracts/governance/ServerNotifier.sol"; import {UpgradeStageValidator} from "contracts/upgrades/UpgradeStageValidator.sol"; import {L2DACommitmentScheme, ROLLUP_L2_DA_COMMITMENT_SCHEME} from "contracts/common/Config.sol"; -import {Config, DeployedAddresses} from "./DeployUtils.s.sol"; -import {DeployL1HelperScript} from "./DeployL1HelperScript.s.sol"; +import {Config, DeployedAddresses, DeployL1CoreUtils} from "./DeployL1CoreUtils.s.sol"; -contract DeployL1CoreContractsScript is Script, DeployL1HelperScript { +contract DeployL1CoreContractsScript is Script, DeployL1CoreUtils { using stdToml for string; function run() public virtual { - console.log("Deploying L1 contracts"); + console.log("Deploying L1 core contracts"); runInner("/script-config/config-deploy-l1.toml", "/script-out/output-deploy-l1.toml"); } @@ -113,6 +111,10 @@ contract DeployL1CoreContractsScript is Script, DeployL1HelperScript { "L1ERC20Bridge", false ); + ( + addresses.bridgehub.assetTrackerImplementation, + addresses.bridgehub.assetTrackerProxy + ) = deployTuppWithContract("L1AssetTracker", false); updateSharedBridge(); ( addresses.bridgehub.ctmDeploymentTrackerImplementation, @@ -123,6 +125,10 @@ contract DeployL1CoreContractsScript is Script, DeployL1HelperScript { addresses.bridgehub.chainAssetHandlerImplementation, addresses.bridgehub.chainAssetHandlerProxy ) = deployTuppWithContract("L1ChainAssetHandler", false); + ( + addresses.bridgehub.chainRegistrationSenderImplementation, + addresses.bridgehub.chainRegistrationSenderProxy + ) = deployTuppWithContract("ChainRegistrationSender", false); setBridgehubParams(); updateOwners(); @@ -132,14 +138,18 @@ contract DeployL1CoreContractsScript is Script, DeployL1HelperScript { function setBridgehubParams() internal { IL1Bridgehub bridgehub = IL1Bridgehub(addresses.bridgehub.bridgehubProxy); + IMessageRoot messageRoot = IMessageRoot(addresses.bridgehub.messageRootProxy); + IL1AssetTracker assetTracker = L1AssetTracker(addresses.bridgehub.assetTrackerProxy); vm.startBroadcast(msg.sender); bridgehub.addTokenAssetId(bridgehub.baseTokenAssetId(config.eraChainId)); BridgehubBase(address(bridgehub)).setAddresses( addresses.bridges.l1AssetRouterProxy, ICTMDeploymentTracker(addresses.bridgehub.ctmDeploymentTrackerProxy), IMessageRoot(addresses.bridgehub.messageRootProxy), - addresses.bridgehub.chainAssetHandlerProxy + addresses.bridgehub.chainAssetHandlerProxy, + addresses.bridgehub.chainRegistrationSenderProxy ); + assetTracker.setAddresses(); vm.stopBroadcast(); console.log("SharedBridge registered"); } @@ -149,6 +159,14 @@ contract DeployL1CoreContractsScript is Script, DeployL1HelperScript { vm.broadcast(msg.sender); sharedBridge.setL1Erc20Bridge(IL1ERC20Bridge(addresses.bridges.erc20BridgeProxy)); console.log("SharedBridge updated with ERC20Bridge address"); + + L1NativeTokenVault ntv = L1NativeTokenVault(payable(addresses.vaults.l1NativeTokenVaultProxy)); + vm.broadcast(msg.sender); + ntv.setAssetTracker(addresses.bridgehub.assetTrackerProxy); + console.log("L1NativeTokenVault updated with AssetTracker address"); + + vm.broadcast(msg.sender); + IL1NativeTokenVault(addresses.vaults.l1NativeTokenVaultProxy).registerEthToken(); } function setL1NativeTokenVaultParams() internal { @@ -161,9 +179,6 @@ contract DeployL1CoreContractsScript is Script, DeployL1HelperScript { l1Nullifier.setL1NativeTokenVault(IL1NativeTokenVault(addresses.vaults.l1NativeTokenVaultProxy)); vm.broadcast(msg.sender); l1Nullifier.setL1AssetRouter(addresses.bridges.l1AssetRouterProxy); - - vm.broadcast(msg.sender); - IL1NativeTokenVault(addresses.vaults.l1NativeTokenVaultProxy).registerEthToken(); } function updateOwners() internal { @@ -176,6 +191,12 @@ contract DeployL1CoreContractsScript is Script, DeployL1HelperScript { IL1AssetRouter sharedBridge = IL1AssetRouter(addresses.bridges.l1AssetRouterProxy); IOwnable(address(sharedBridge)).transferOwnership(addresses.governance); + IL1AssetTracker assetTracker = IL1AssetTracker(addresses.bridgehub.assetTrackerProxy); + IOwnable(address(assetTracker)).transferOwnership(addresses.governance); + + L1NativeTokenVault l1NativeTokenVault = L1NativeTokenVault(payable(addresses.vaults.l1NativeTokenVaultProxy)); + l1NativeTokenVault.transferOwnership(config.ownerAddress); + ICTMDeploymentTracker ctmDeploymentTracker = ICTMDeploymentTracker( addresses.bridgehub.ctmDeploymentTrackerProxy ); @@ -196,6 +217,16 @@ contract DeployL1CoreContractsScript is Script, DeployL1HelperScript { addresses.bridgehub.chainAssetHandlerImplementation ); vm.serializeAddress("bridgehub", "chain_asset_handler_proxy_addr", addresses.bridgehub.chainAssetHandlerProxy); + vm.serializeAddress( + "bridgehub", + "chain_registration_sender_proxy_addr", + addresses.bridgehub.chainRegistrationSenderProxy + ); + vm.serializeAddress( + "bridgehub", + "chain_registration_sender_implementation_addr", + addresses.bridgehub.chainRegistrationSenderImplementation + ); vm.serializeAddress( "bridgehub", "ctm_deployment_tracker_proxy_addr", @@ -206,6 +237,18 @@ contract DeployL1CoreContractsScript is Script, DeployL1HelperScript { "ctm_deployment_tracker_implementation_addr", addresses.bridgehub.ctmDeploymentTrackerImplementation ); + vm.serializeAddress("bridgehub", "chain_asset_handler_proxy_addr", addresses.bridgehub.chainAssetHandlerProxy); + vm.serializeAddress( + "bridgehub", + "chain_asset_handler_implementation_addr", + addresses.bridgehub.chainAssetHandlerImplementation + ); + vm.serializeAddress( + "bridgehub", + "l1_asset_tracker_implementation_addr", + addresses.bridgehub.assetTrackerImplementation + ); + vm.serializeAddress("bridgehub", "l1_asset_tracker_proxy_addr", addresses.bridgehub.assetTrackerProxy); vm.serializeAddress("bridgehub", "message_root_proxy_addr", addresses.bridgehub.messageRootProxy); string memory bridgehub = vm.serializeAddress( "bridgehub", @@ -256,22 +299,6 @@ contract DeployL1CoreContractsScript is Script, DeployL1HelperScript { vm.writeToml(toml, outputPath); } - /// @notice Get all four facet cuts - function getChainCreationFacetCuts( - StateTransitionDeployedAddresses memory stateTransition - ) internal virtual override returns (Diamond.FacetCut[] memory facetCuts) { - // We still want to reuse DeployUtils, but this function is not used in this script - revert("not implemented"); - } - - /// @notice Get new facet cuts that were added in the upgrade - function getUpgradeAddedFacetCuts( - StateTransitionDeployedAddresses memory stateTransition - ) internal virtual override returns (Diamond.FacetCut[] memory facetCuts) { - // We still want to reuse DeployUtils, but this function is not used in this script - revert("not implemented"); - } - // add this to be excluded from coverage report function test() internal virtual override {} } diff --git a/l1-contracts/deploy-scripts/DeployL1CoreUtils.s.sol b/l1-contracts/deploy-scripts/DeployL1CoreUtils.s.sol new file mode 100644 index 0000000000..a2bfba5cdc --- /dev/null +++ b/l1-contracts/deploy-scripts/DeployL1CoreUtils.s.sol @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +// solhint-disable no-console, gas-custom-errors + +import {console2 as console} from "forge-std/Script.sol"; +import {stdToml} from "forge-std/StdToml.sol"; +import {L1Bridgehub} from "contracts/bridgehub/L1Bridgehub.sol"; +import {DeployUtils} from "./DeployUtils.sol"; +import {L1Nullifier} from "contracts/bridge/L1Nullifier.sol"; +import {L1AssetRouter} from "contracts/bridge/asset-router/L1AssetRouter.sol"; +import {Governance} from "contracts/governance/Governance.sol"; +import {CTMDeploymentTracker} from "contracts/bridgehub/CTMDeploymentTracker.sol"; +import {ChainAdmin} from "contracts/governance/ChainAdmin.sol"; +import {L1NullifierDev} from "contracts/dev-contracts/L1NullifierDev.sol"; +import {L1ERC20Bridge} from "contracts/bridge/L1ERC20Bridge.sol"; +import {ChainAdminOwnable} from "contracts/governance/ChainAdminOwnable.sol"; +import {L1MessageRoot} from "contracts/bridgehub/L1MessageRoot.sol"; +import {L1ChainAssetHandler} from "contracts/bridgehub/L1ChainAssetHandler.sol"; +import {L1NativeTokenVault} from "contracts/bridge/ntv/L1NativeTokenVault.sol"; +import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol"; +import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; +import {ContractsBytecodesLib} from "./ContractsBytecodesLib.sol"; +import {BridgehubDeployedAddresses, BridgesDeployedAddresses, L1NativeTokenVaultAddresses} from "./Types.sol"; +import {L1AssetTracker} from "contracts/bridge/asset-tracker/L1AssetTracker.sol"; +import {ChainRegistrationSender} from "contracts/bridgehub/ChainRegistrationSender.sol"; + +// solhint-disable-next-line gas-struct-packing +struct DeployedAddresses { + BridgehubDeployedAddresses bridgehub; + BridgesDeployedAddresses bridges; + L1NativeTokenVaultAddresses vaults; + address transparentProxyAdmin; + address governance; + address chainAdmin; + address accessControlRestrictionAddress; + address create2Factory; +} + +// solhint-disable-next-line gas-struct-packing +struct Config { + uint256 l1ChainId; + address ownerAddress; + address deployerAddress; + uint256 eraChainId; + address eraDiamondProxyAddress; + bool supportL2LegacySharedBridgeTest; + ContractsConfig contracts; + TokensConfig tokens; +} + +// solhint-disable-next-line gas-struct-packing +struct ContractsConfig { + address governanceSecurityCouncilAddress; + uint256 governanceMinDelay; + uint256 maxNumberOfChains; +} + +struct TokensConfig { + address tokenWethAddress; +} + +contract DeployL1CoreUtils is DeployUtils { + using stdToml for string; + + Config public config; + DeployedAddresses internal addresses; + + function initializeConfig(string memory configPath) public virtual { + string memory toml = vm.readFile(configPath); + + config.l1ChainId = block.chainid; + config.deployerAddress = msg.sender; + + // Config file must be parsed key by key, otherwise values returned + // are parsed alfabetically and not by key. + // https://book.getfoundry.sh/cheatcodes/parse-toml + config.eraChainId = toml.readUint("$.era_chain_id"); + config.ownerAddress = toml.readAddress("$.owner_address"); + config.supportL2LegacySharedBridgeTest = toml.readBool("$.support_l2_legacy_shared_bridge_test"); + + config.contracts.governanceSecurityCouncilAddress = toml.readAddress( + "$.contracts.governance_security_council_address" + ); + config.contracts.governanceMinDelay = toml.readUint("$.contracts.governance_min_delay"); + config.contracts.maxNumberOfChains = toml.readUint("$.contracts.max_number_of_chains"); + + bytes32 create2FactorySalt = toml.readBytes32("$.contracts.create2_factory_salt"); + address create2FactoryAddr; + if (vm.keyExistsToml(toml, "$.contracts.create2_factory_addr")) { + create2FactoryAddr = toml.readAddress("$.contracts.create2_factory_addr"); + } + _initCreate2FactoryParams(create2FactoryAddr, create2FactorySalt); + + if (vm.keyExistsToml(toml, "$.contracts.era_diamond_proxy_addr")) { + config.eraDiamondProxyAddress = toml.readAddress("$.contracts.era_diamond_proxy_addr"); + } + config.tokens.tokenWethAddress = toml.readAddress("$.tokens.token_weth_address"); + } + + ////////////////////////////// Contract deployment modes ///////////////////////////////// + + function getCreationCalldata( + string memory contractName, + bool isZKBytecode + ) internal view virtual override returns (bytes memory) { + if (compareStrings(contractName, "ChainRegistrar")) { + return abi.encode(); + } else if (compareStrings(contractName, "ProxyAdmin")) { + return abi.encode(); + } else if (compareStrings(contractName, "ChainRegistrationSender")) { + return abi.encode(addresses.bridgehub.bridgehubProxy); + } else if (compareStrings(contractName, "InteropCenter")) { + return abi.encode(addresses.bridgehub.bridgehubProxy, config.l1ChainId, config.ownerAddress); + } else if (compareStrings(contractName, "BridgedStandardERC20")) { + return abi.encode(); + } else if (compareStrings(contractName, "BridgedTokenBeacon")) { + return abi.encode(addresses.bridges.bridgedStandardERC20Implementation); + } else if (compareStrings(contractName, "L1Bridgehub")) { + return abi.encode(config.l1ChainId, config.ownerAddress, (config.contracts.maxNumberOfChains)); + } else if (compareStrings(contractName, "L1MessageRoot")) { + return abi.encode(addresses.bridgehub.bridgehubProxy, config.l1ChainId); + } else if (compareStrings(contractName, "CTMDeploymentTracker")) { + return abi.encode(addresses.bridgehub.bridgehubProxy, addresses.bridges.l1AssetRouterProxy); + } else if (compareStrings(contractName, "ChainAssetHandler")) { + return + abi.encode( + config.l1ChainId, + config.ownerAddress, + addresses.bridgehub.bridgehubProxy, + addresses.bridges.l1AssetRouterProxy, + addresses.bridgehub.messageRootProxy + ); + } else if (compareStrings(contractName, "L1Nullifier")) { + if (config.supportL2LegacySharedBridgeTest) { + return + abi.encode( + addresses.bridgehub.bridgehubProxy, + addresses.bridgehub.messageRootProxy, + addresses.bridgehub.interopCenterProxy, + config.eraChainId, + config.eraDiamondProxyAddress + ); + } else { + return + abi.encode( + addresses.bridgehub.bridgehubProxy, + addresses.bridgehub.messageRootProxy, + config.eraChainId, + config.eraDiamondProxyAddress + ); + } + } else if (compareStrings(contractName, "L1ChainAssetHandler")) { + return + abi.encode( + config.ownerAddress, + addresses.bridgehub.bridgehubProxy, + addresses.bridges.l1AssetRouterProxy, + addresses.bridgehub.messageRootProxy, + addresses.bridgehub.assetTrackerProxy, + addresses.bridges.l1NullifierProxy + ); + } else if (compareStrings(contractName, "L1AssetRouter")) { + return + abi.encode( + config.tokens.tokenWethAddress, + addresses.bridgehub.bridgehubProxy, + addresses.bridges.l1NullifierProxy, + config.eraChainId, + config.eraDiamondProxyAddress + ); + } else if (compareStrings(contractName, "L1ERC20Bridge")) { + return + abi.encode( + addresses.bridges.l1NullifierProxy, + addresses.bridges.l1AssetRouterProxy, + addresses.vaults.l1NativeTokenVaultProxy, + config.eraChainId + ); + } else if (compareStrings(contractName, "L1NativeTokenVault")) { + return + abi.encode( + config.tokens.tokenWethAddress, + addresses.bridges.l1AssetRouterProxy, + addresses.bridges.l1NullifierProxy + ); + } else if (compareStrings(contractName, "Governance")) { + return + abi.encode( + config.ownerAddress, + config.contracts.governanceSecurityCouncilAddress, + config.contracts.governanceMinDelay + ); + } else if (compareStrings(contractName, "ChainAdminOwnable")) { + return abi.encode(config.ownerAddress, address(0)); + } else if (compareStrings(contractName, "L1AssetTracker")) { + return + abi.encode( + config.l1ChainId, + addresses.bridgehub.bridgehubProxy, + addresses.bridges.l1AssetRouterProxy, + addresses.vaults.l1NativeTokenVaultProxy, + addresses.bridgehub.messageRootProxy + ); + } else if (compareStrings(contractName, "ChainAdmin")) { + address[] memory restrictions = new address[](1); + restrictions[0] = addresses.accessControlRestrictionAddress; + return abi.encode(restrictions); + } else { + revert(string.concat("Contract ", contractName, " creation calldata not set")); + } + } + + function transparentProxyAdmin() internal virtual override returns (address) { + return addresses.transparentProxyAdmin; + } + + function getCreationCode( + string memory contractName, + bool isZKBytecode + ) internal view virtual override returns (bytes memory) { + if (!isZKBytecode) { + if (compareStrings(contractName, "L1Bridgehub")) { + return type(L1Bridgehub).creationCode; + } else if (compareStrings(contractName, "L1ChainAssetHandler")) { + return type(L1ChainAssetHandler).creationCode; + } else if (compareStrings(contractName, "ChainRegistrationSender")) { + return type(ChainRegistrationSender).creationCode; + } else if (compareStrings(contractName, "L1MessageRoot")) { + return type(L1MessageRoot).creationCode; + } else if (compareStrings(contractName, "CTMDeploymentTracker")) { + return type(CTMDeploymentTracker).creationCode; + } else if (compareStrings(contractName, "L1Nullifier")) { + if (config.supportL2LegacySharedBridgeTest) { + return type(L1NullifierDev).creationCode; + } else { + return type(L1Nullifier).creationCode; + } + } else if (compareStrings(contractName, "L1AssetRouter")) { + return type(L1AssetRouter).creationCode; + } else if (compareStrings(contractName, "L1AssetTracker")) { + return type(L1AssetTracker).creationCode; + } else if (compareStrings(contractName, "L1ERC20Bridge")) { + return type(L1ERC20Bridge).creationCode; + } else if (compareStrings(contractName, "L1NativeTokenVault")) { + return type(L1NativeTokenVault).creationCode; + } else if (compareStrings(contractName, "BridgedStandardERC20")) { + return type(BridgedStandardERC20).creationCode; + } else if (compareStrings(contractName, "BridgedTokenBeacon")) { + return type(UpgradeableBeacon).creationCode; + } else if (compareStrings(contractName, "Governance")) { + return type(Governance).creationCode; + } else if (compareStrings(contractName, "ChainAdminOwnable")) { + return type(ChainAdminOwnable).creationCode; + } else if (compareStrings(contractName, "ChainAdmin")) { + return type(ChainAdmin).creationCode; + } else if (compareStrings(contractName, "ProxyAdmin")) { + return type(ProxyAdmin).creationCode; + } + } + return ContractsBytecodesLib.getCreationCode(contractName, isZKBytecode); + } + + function getInitializeCalldata( + string memory contractName, + bool isZKBytecode + ) internal virtual override returns (bytes memory) { + if (!isZKBytecode) { + if (compareStrings(contractName, "L1Bridgehub")) { + return abi.encodeCall(L1Bridgehub.initialize, (config.deployerAddress)); + } else if (compareStrings(contractName, "L1MessageRoot")) { + return abi.encodeCall(L1MessageRoot.initialize, ()); + } else if (compareStrings(contractName, "ChainRegistrationSender")) { + return abi.encodeCall(ChainRegistrationSender.initialize, (config.deployerAddress)); + } else if (compareStrings(contractName, "L1AssetTracker")) { + return abi.encodeCall(L1AssetTracker.initialize, (config.deployerAddress)); + } else if (compareStrings(contractName, "L1ChainAssetHandler")) { + return abi.encodeCall(L1ChainAssetHandler.initialize, (config.deployerAddress)); + } else if (compareStrings(contractName, "CTMDeploymentTracker")) { + return abi.encodeCall(CTMDeploymentTracker.initialize, (config.deployerAddress)); + } else if (compareStrings(contractName, "L1Nullifier")) { + return abi.encodeCall(L1Nullifier.initialize, (config.deployerAddress, 1, 1, 1, 0)); + } else if (compareStrings(contractName, "L1AssetRouter")) { + return abi.encodeCall(L1AssetRouter.initialize, (config.deployerAddress)); + } else if (compareStrings(contractName, "L1ERC20Bridge")) { + return abi.encodeCall(L1ERC20Bridge.initialize, ()); + } else if (compareStrings(contractName, "L1NativeTokenVault")) { + return + abi.encodeCall( + L1NativeTokenVault.initialize, + (config.deployerAddress, addresses.bridges.bridgedTokenBeacon) + ); + } else { + revert(string.concat("Contract ", contractName, " initialize calldata not set")); + } + } else { + revert(string.concat("Contract ", contractName, " ZK initialize calldata not set")); + } + } + + function test() internal virtual {} +} diff --git a/l1-contracts/deploy-scripts/DeployL1HelperScript.s.sol b/l1-contracts/deploy-scripts/DeployL1HelperScript.s.sol deleted file mode 100644 index 5ac1fb7bbf..0000000000 --- a/l1-contracts/deploy-scripts/DeployL1HelperScript.s.sol +++ /dev/null @@ -1,340 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; - -// solhint-disable no-console, gas-custom-errors -import {Script, console2 as console} from "forge-std/Script.sol"; -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; -import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol"; -import {Action, FacetCut, StateTransitionDeployedAddresses, Utils} from "./Utils.sol"; - -import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; -import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; -import {L2ContractHelper} from "contracts/common/l2-helpers/L2ContractHelper.sol"; -import {IL1Nullifier, L1Nullifier} from "contracts/bridge/L1Nullifier.sol"; -import {IL1NativeTokenVault} from "contracts/bridge/ntv/IL1NativeTokenVault.sol"; -import {IL1ERC20Bridge} from "contracts/bridge/interfaces/IL1ERC20Bridge.sol"; -import {ICTMDeploymentTracker} from "contracts/bridgehub/ICTMDeploymentTracker.sol"; -import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; -import {IOwnable} from "contracts/common/interfaces/IOwnable.sol"; - -import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol"; -import {Multicall3} from "contracts/dev-contracts/Multicall3.sol"; - -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; -import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; -import {Governance} from "contracts/governance/Governance.sol"; -import {ChainAdmin} from "contracts/governance/ChainAdmin.sol"; -import {L1Bridgehub} from "contracts/bridgehub/L1Bridgehub.sol"; -import {L1ChainAssetHandler} from "contracts/bridgehub/L1ChainAssetHandler.sol"; -import {L1MessageRoot} from "contracts/bridgehub/L1MessageRoot.sol"; -import {CTMDeploymentTracker} from "contracts/bridgehub/CTMDeploymentTracker.sol"; -import {L1NativeTokenVault} from "contracts/bridge/ntv/L1NativeTokenVault.sol"; -import {L1AssetRouter} from "contracts/bridge/asset-router/L1AssetRouter.sol"; -import {L1ERC20Bridge} from "contracts/bridge/L1ERC20Bridge.sol"; -import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol"; -import {ChainAdminOwnable} from "contracts/governance/ChainAdminOwnable.sol"; -import {L1NullifierDev} from "contracts/dev-contracts/L1NullifierDev.sol"; -import {MockEIP7702Checker} from "contracts/dev-contracts/MockEIP7702Checker.sol"; -import {ContractsBytecodesLib} from "./ContractsBytecodesLib.sol"; -import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; - -import {EraDualVerifier} from "contracts/state-transition/verifiers/EraDualVerifier.sol"; -import {ZKsyncOSDualVerifier} from "contracts/state-transition/verifiers/ZKsyncOSDualVerifier.sol"; -import {EraVerifierFflonk} from "contracts/state-transition/verifiers/EraVerifierFflonk.sol"; -import {EraVerifierPlonk} from "contracts/state-transition/verifiers/EraVerifierPlonk.sol"; -import {ZKsyncOSVerifierFflonk} from "contracts/state-transition/verifiers/ZKsyncOSVerifierFflonk.sol"; -import {ZKsyncOSVerifierPlonk} from "contracts/state-transition/verifiers/ZKsyncOSVerifierPlonk.sol"; -import {EraTestnetVerifier} from "contracts/state-transition/verifiers/EraTestnetVerifier.sol"; -import {ZKsyncOSTestnetVerifier} from "contracts/state-transition/verifiers/ZKsyncOSTestnetVerifier.sol"; -import {IVerifier, VerifierParams} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; -import {DefaultUpgrade} from "contracts/upgrades/DefaultUpgrade.sol"; -import {L1GenesisUpgrade} from "contracts/upgrades/L1GenesisUpgrade.sol"; -import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; -import {ExecutorFacet} from "contracts/state-transition/chain-deps/facets/Executor.sol"; -import {AdminFacet} from "contracts/state-transition/chain-deps/facets/Admin.sol"; -import {MailboxFacet} from "contracts/state-transition/chain-deps/facets/Mailbox.sol"; -import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; -import {DiamondInit} from "contracts/state-transition/chain-deps/DiamondInit.sol"; -import {EraChainTypeManager} from "contracts/state-transition/EraChainTypeManager.sol"; -import {ZKsyncOSChainTypeManager} from "contracts/state-transition/ZKsyncOSChainTypeManager.sol"; -import {ValidiumL1DAValidator} from "contracts/state-transition/data-availability/ValidiumL1DAValidator.sol"; -import {RollupDAManager} from "contracts/state-transition/data-availability/RollupDAManager.sol"; -import {BytecodesSupplier} from "contracts/upgrades/BytecodesSupplier.sol"; -import {ServerNotifier} from "contracts/governance/ServerNotifier.sol"; -import {UpgradeStageValidator} from "contracts/upgrades/UpgradeStageValidator.sol"; - -import {Config, DeployUtils, DeployedAddresses, GeneratedData} from "./DeployUtils.s.sol"; -import {FixedForceDeploymentsData} from "contracts/state-transition/l2-deps/IL2GenesisUpgrade.sol"; - -import {L2Bridgehub} from "contracts/bridgehub/L2Bridgehub.sol"; -import {L2AssetRouter} from "contracts/bridge/asset-router/L2AssetRouter.sol"; -import {L2NativeTokenVaultZKOS} from "contracts/bridge/ntv/L2NativeTokenVaultZKOS.sol"; -import {L2MessageRoot} from "contracts/bridgehub/L2MessageRoot.sol"; -import {CTMDeploymentTracker} from "contracts/bridgehub/CTMDeploymentTracker.sol"; - -abstract contract DeployL1HelperScript is Script, DeployUtils { - function deployTuppWithContract( - string memory contractName, - bool isZKBytecode - ) internal virtual override returns (address implementation, address proxy) { - (implementation, proxy) = deployTuppWithContractAndProxyAdmin( - contractName, - addresses.transparentProxyAdmin, - isZKBytecode - ); - } - - function deployTuppWithContractAndProxyAdmin( - string memory contractName, - address proxyAdmin, - bool isZKBytecode - ) internal returns (address implementation, address proxy) { - implementation = deployViaCreate2AndNotify( - getCreationCode(contractName, false), - getCreationCalldata(contractName, false), - contractName, - string.concat(contractName, " Implementation"), - isZKBytecode - ); - - proxy = deployViaCreate2AndNotify( - type(TransparentUpgradeableProxy).creationCode, - abi.encode(implementation, proxyAdmin, getInitializeCalldata(contractName, false)), - contractName, - string.concat(contractName, " Proxy"), - isZKBytecode - ); - return (implementation, proxy); - } - - ////////////////////////////// GetContract data ///////////////////////////////// - - function getCreationCode( - string memory contractName, - bool isZKBytecode - ) internal view virtual override returns (bytes memory) { - if (!isZKBytecode) { - if (compareStrings(contractName, "L1Bridgehub")) { - return type(L1Bridgehub).creationCode; - } else if (compareStrings(contractName, "L1ChainAssetHandler")) { - return type(L1ChainAssetHandler).creationCode; - } else if (compareStrings(contractName, "L1MessageRoot")) { - return type(L1MessageRoot).creationCode; - } else if (compareStrings(contractName, "CTMDeploymentTracker")) { - return type(CTMDeploymentTracker).creationCode; - } else if (compareStrings(contractName, "L1Nullifier")) { - if (config.supportL2LegacySharedBridgeTest) { - return type(L1NullifierDev).creationCode; - } else { - return type(L1Nullifier).creationCode; - } - } else if (compareStrings(contractName, "L1AssetRouter")) { - return type(L1AssetRouter).creationCode; - } else if (compareStrings(contractName, "L1ERC20Bridge")) { - return type(L1ERC20Bridge).creationCode; - } else if (compareStrings(contractName, "L1NativeTokenVault")) { - return type(L1NativeTokenVault).creationCode; - } else if (compareStrings(contractName, "BridgedStandardERC20")) { - return type(BridgedStandardERC20).creationCode; - } else if (compareStrings(contractName, "BridgedTokenBeacon")) { - return type(UpgradeableBeacon).creationCode; - } else if (compareStrings(contractName, "Governance")) { - return type(Governance).creationCode; - } else if (compareStrings(contractName, "ChainAdminOwnable")) { - return type(ChainAdminOwnable).creationCode; - } else if (compareStrings(contractName, "ChainAdmin")) { - return type(ChainAdmin).creationCode; - } else if (compareStrings(contractName, "ProxyAdmin")) { - return type(ProxyAdmin).creationCode; - } else if (compareStrings(contractName, "RollupDAManager")) { - return type(RollupDAManager).creationCode; - } else if (compareStrings(contractName, "ValidiumL1DAValidator")) { - return type(ValidiumL1DAValidator).creationCode; - } else if (compareStrings(contractName, "Verifier")) { - if (config.testnetVerifier) { - if (config.isZKsyncOS) { - return type(ZKsyncOSTestnetVerifier).creationCode; - } else { - return type(EraTestnetVerifier).creationCode; - } - } else { - if (config.isZKsyncOS) { - return type(ZKsyncOSDualVerifier).creationCode; - } else { - return type(EraDualVerifier).creationCode; - } - } - } else if (compareStrings(contractName, "EraVerifierFflonk")) { - return type(EraVerifierFflonk).creationCode; - } else if (compareStrings(contractName, "EraVerifierPlonk")) { - return type(EraVerifierPlonk).creationCode; - } else if (compareStrings(contractName, "ZKsyncOSVerifierFflonk")) { - return type(ZKsyncOSVerifierFflonk).creationCode; - } else if (compareStrings(contractName, "ZKsyncOSVerifierPlonk")) { - return type(ZKsyncOSVerifierPlonk).creationCode; - } else if (compareStrings(contractName, "DefaultUpgrade")) { - return type(DefaultUpgrade).creationCode; - } else if (compareStrings(contractName, "L1GenesisUpgrade")) { - return type(L1GenesisUpgrade).creationCode; - } else if (compareStrings(contractName, "ValidatorTimelock")) { - return type(ValidatorTimelock).creationCode; - } else if (compareStrings(contractName, "EraChainTypeManager")) { - return type(EraChainTypeManager).creationCode; - } else if (compareStrings(contractName, "ZKsyncOSChainTypeManager")) { - return type(ZKsyncOSChainTypeManager).creationCode; - } else if (compareStrings(contractName, "BytecodesSupplier")) { - return type(BytecodesSupplier).creationCode; - } else if (compareStrings(contractName, "ExecutorFacet")) { - return type(ExecutorFacet).creationCode; - } else if (compareStrings(contractName, "AdminFacet")) { - return type(AdminFacet).creationCode; - } else if (compareStrings(contractName, "MailboxFacet")) { - return type(MailboxFacet).creationCode; - } else if (compareStrings(contractName, "GettersFacet")) { - return type(GettersFacet).creationCode; - } else if (compareStrings(contractName, "DiamondInit")) { - return type(DiamondInit).creationCode; - } else if (compareStrings(contractName, "ServerNotifier")) { - return type(ServerNotifier).creationCode; - } else if (compareStrings(contractName, "UpgradeStageValidator")) { - return type(UpgradeStageValidator).creationCode; - } else if (compareStrings(contractName, "MockEIP7702Checker")) { - return type(MockEIP7702Checker).creationCode; - } else if (compareStrings(contractName, "EIP7702Checker")) { - return ContractsBytecodesLib.getCreationCodeEVM(contractName); - } - } else { - if (compareStrings(contractName, "L2Bridgehub")) { - return Utils.readZKFoundryBytecodeL1("L2Bridgehub.sol", "L2Bridgehub"); - } else if (compareStrings(contractName, "L2MessageRoot")) { - return Utils.readZKFoundryBytecodeL1("L2MessageRoot.sol", "L2MessageRoot"); - } else if (compareStrings(contractName, "L2ChainAssetHandler")) { - return Utils.readZKFoundryBytecodeL1("L2ChainAssetHandler.sol", "L2ChainAssetHandler"); - } else if (compareStrings(contractName, "UpgradeableBeaconDeployer")) { - return Utils.readZKFoundryBytecodeL1("UpgradeableBeaconDeployer.sol", "UpgradeableBeaconDeployer"); - } else if (compareStrings(contractName, "ICTMDeploymentTracker")) { - return Utils.readZKFoundryBytecodeL1("ICTMDeploymentTracker.sol", "ICTMDeploymentTracker"); - } else if (compareStrings(contractName, "L2AssetRouter")) { - return Utils.readZKFoundryBytecodeL1("L2AssetRouter.sol", "L2AssetRouter"); - } else if (compareStrings(contractName, "L1ERC20Bridge")) { - return Utils.readZKFoundryBytecodeL1("L1ERC20Bridge.sol", "L1ERC20Bridge"); - } else if (compareStrings(contractName, "L2NativeTokenVault")) { - return Utils.readZKFoundryBytecodeL1("L2NativeTokenVault.sol", "L2NativeTokenVault"); - } else if (compareStrings(contractName, "BridgedStandardERC20")) { - return Utils.readZKFoundryBytecodeL1("BridgedStandardERC20.sol", "BridgedStandardERC20"); - } else if (compareStrings(contractName, "BridgedTokenBeacon")) { - return Utils.readZKFoundryBytecodeL1("UpgradeableBeacon.sol", "UpgradeableBeacon"); - } else if (compareStrings(contractName, "BlobVersionedHashRetriever")) { - return hex"600b600b5f39600b5ff3fe5f358049805f5260205ff3"; - } else if (compareStrings(contractName, "RollupDAManager")) { - return Utils.readZKFoundryBytecodeL1("RollupDAManager.sol", "RollupDAManager"); - } else if (compareStrings(contractName, "ValidiumL1DAValidator")) { - return Utils.readZKFoundryBytecodeL1("ValidiumL1DAValidator.sol", "ValidiumL1DAValidator"); - } else if (compareStrings(contractName, "Verifier")) { - if (config.testnetVerifier) { - return getCreationCode("EraTestnetVerifier", true); - } else { - return getCreationCode("DualVerifier", true); - } - } else if (compareStrings(contractName, "VerifierFflonk")) { - return Utils.readZKFoundryBytecodeL1("L1VerifierFflonk.sol", "L1VerifierFflonk"); - } else if (compareStrings(contractName, "VerifierPlonk")) { - return Utils.readZKFoundryBytecodeL1("L1VerifierPlonk.sol", "L1VerifierPlonk"); - } else if (compareStrings(contractName, "DefaultUpgrade")) { - return Utils.readZKFoundryBytecodeL1("DefaultUpgrade.sol", "DefaultUpgrade"); - } else if (compareStrings(contractName, "L1GenesisUpgrade")) { - return Utils.readZKFoundryBytecodeL1("L1GenesisUpgrade.sol", "L1GenesisUpgrade"); - } else if (compareStrings(contractName, "ValidatorTimelock")) { - return Utils.readZKFoundryBytecodeL1("ValidatorTimelock.sol", "ValidatorTimelock"); - } else if (compareStrings(contractName, "Governance")) { - return Utils.readZKFoundryBytecodeL1("Governance.sol", "Governance"); - } else if (compareStrings(contractName, "ChainAdminOwnable")) { - return Utils.readZKFoundryBytecodeL1("ChainAdminOwnable.sol", "ChainAdminOwnable"); - } else if (compareStrings(contractName, "AccessControlRestriction")) { - // TODO(EVM-924): this function is unused - return Utils.readZKFoundryBytecodeL1("AccessControlRestriction.sol", "AccessControlRestriction"); - } else if (compareStrings(contractName, "ChainAdmin")) { - return Utils.readZKFoundryBytecodeL1("ChainAdmin.sol", "ChainAdmin"); - } else if (compareStrings(contractName, "ChainTypeManager")) { - return Utils.readZKFoundryBytecodeL1("ChainTypeManager.sol", "ChainTypeManager"); - } else if (compareStrings(contractName, "BytecodesSupplier")) { - return Utils.readZKFoundryBytecodeL1("BytecodesSupplier.sol", "BytecodesSupplier"); - } else if (compareStrings(contractName, "ProxyAdmin")) { - return Utils.readZKFoundryBytecodeL1("ProxyAdmin.sol", "ProxyAdmin"); - } else if (compareStrings(contractName, "ExecutorFacet")) { - return Utils.readZKFoundryBytecodeL1("Executor.sol", "ExecutorFacet"); - } else if (compareStrings(contractName, "AdminFacet")) { - return Utils.readZKFoundryBytecodeL1("Admin.sol", "AdminFacet"); - } else if (compareStrings(contractName, "MailboxFacet")) { - return Utils.readZKFoundryBytecodeL1("Mailbox.sol", "MailboxFacet"); - } else if (compareStrings(contractName, "GettersFacet")) { - return Utils.readZKFoundryBytecodeL1("Getters.sol", "GettersFacet"); - } else if (compareStrings(contractName, "DiamondInit")) { - return Utils.readZKFoundryBytecodeL1("DiamondInit.sol", "DiamondInit"); - } else if (compareStrings(contractName, "ServerNotifier")) { - return Utils.readZKFoundryBytecodeL1("ServerNotifier.sol", "ServerNotifier"); - } else if (compareStrings(contractName, "BeaconProxy")) { - return Utils.readZKFoundryBytecodeL1("BeaconProxy.sol", "BeaconProxy"); - } else if (compareStrings(contractName, "RollupL2DAValidator")) { - return Utils.readZKFoundryBytecodeL2("RollupL2DAValidator.sol", "RollupL2DAValidator"); - } else if (compareStrings(contractName, "ValidiumL2DAValidator")) { - return Utils.readZKFoundryBytecodeL2("ValidiumL2DAValidator.sol", "ValidiumL2DAValidator"); - } else if (compareStrings(contractName, "AvailL2DAValidator")) { - return Utils.readZKFoundryBytecodeL2("AvailL2DAValidator.sol", "AvailL2DAValidator"); - } else { - revert(string.concat("Contract ", contractName, " creation code not set")); - } - } - return ContractsBytecodesLib.getCreationCode(contractName, isZKBytecode); - } - - function getInitializeCalldata( - string memory contractName, - bool isZKBytecode - ) internal virtual override returns (bytes memory) { - if (!isZKBytecode) { - if (compareStrings(contractName, "L1Bridgehub")) { - return abi.encodeCall(L1Bridgehub.initialize, (config.deployerAddress)); - } else if (compareStrings(contractName, "L1MessageRoot")) { - return abi.encodeCall(L1MessageRoot.initialize, ()); - } else if (compareStrings(contractName, "L1ChainAssetHandler")) { - return abi.encodeCall(L1ChainAssetHandler.initialize, (config.deployerAddress)); - } else if (compareStrings(contractName, "CTMDeploymentTracker")) { - return abi.encodeCall(CTMDeploymentTracker.initialize, (config.deployerAddress)); - } else if (compareStrings(contractName, "L1Nullifier")) { - return abi.encodeCall(L1Nullifier.initialize, (config.deployerAddress, 1, 1, 1, 0)); - } else if (compareStrings(contractName, "L1AssetRouter")) { - return abi.encodeCall(L1AssetRouter.initialize, (config.deployerAddress)); - } else if (compareStrings(contractName, "L1ERC20Bridge")) { - return abi.encodeCall(L1ERC20Bridge.initialize, ()); - } else if (compareStrings(contractName, "L1NativeTokenVault")) { - return - abi.encodeCall( - L1NativeTokenVault.initialize, - (config.ownerAddress, addresses.bridges.bridgedTokenBeacon) - ); - } else if ( - compareStrings(contractName, "EraChainTypeManager") || - compareStrings(contractName, "ZKsyncOSChainTypeManager") - ) { - return - abi.encodeCall( - IChainTypeManager.initialize, - getChainTypeManagerInitializeData(addresses.stateTransition) - ); - } else if (compareStrings(contractName, "ServerNotifier")) { - return abi.encodeCall(ServerNotifier.initialize, (msg.sender)); - } else if (compareStrings(contractName, "ValidatorTimelock")) { - return - abi.encodeCall( - ValidatorTimelock.initialize, - (config.deployerAddress, uint32(config.contracts.validatorTimelockExecutionDelay)) - ); - } else { - revert(string.concat("Contract ", contractName, " initialize calldata not set")); - } - } else { - revert(string.concat("Contract ", contractName, " ZK initialize calldata not set")); - } - } -} diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 92f3715368..e2533ab63c 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -13,7 +13,7 @@ import {ContractsBytecodesLib} from "./ContractsBytecodesLib.sol"; import {IGovernance} from "contracts/governance/IGovernance.sol"; import {Ownable2Step} from "@openzeppelin/contracts-v4/access/Ownable2Step.sol"; import {Call} from "contracts/governance/Common.sol"; -// + contract DeployL2Script is Script { using stdToml for string; diff --git a/l1-contracts/deploy-scripts/DeployUtils.s.sol b/l1-contracts/deploy-scripts/DeployUtils.s.sol deleted file mode 100644 index 55fdb61f02..0000000000 --- a/l1-contracts/deploy-scripts/DeployUtils.s.sol +++ /dev/null @@ -1,493 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; - -// solhint-disable no-console, gas-custom-errors - -import {console2 as console} from "forge-std/Script.sol"; -import {stdToml} from "forge-std/StdToml.sol"; -import {StateTransitionDeployedAddresses, Utils} from "./Utils.sol"; -import {IVerifier, VerifierParams} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; -import {ChainCreationParams, ChainTypeManagerInitializeData} from "contracts/state-transition/IChainTypeManager.sol"; -import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; -import {InitializeDataNewChain as DiamondInitializeDataNewChain} from "contracts/state-transition/chain-interfaces/IDiamondInit.sol"; -import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-deps/ZKChainStorage.sol"; -import {L2ContractHelper} from "contracts/common/l2-helpers/L2ContractHelper.sol"; - -import {Create2FactoryUtils} from "./Create2FactoryUtils.s.sol"; - -// solhint-disable-next-line gas-struct-packing -struct DeployedAddresses { - BridgehubDeployedAddresses bridgehub; - StateTransitionDeployedAddresses stateTransition; - BridgesDeployedAddresses bridges; - L1NativeTokenVaultAddresses vaults; - DataAvailabilityDeployedAddresses daAddresses; - address transparentProxyAdmin; - address governance; - address chainAdmin; - address accessControlRestrictionAddress; - address create2Factory; - address chainRegistrar; - address eip7702Checker; -} - -// solhint-disable-next-line gas-struct-packing -struct L1NativeTokenVaultAddresses { - address l1NativeTokenVaultImplementation; - address l1NativeTokenVaultProxy; -} - -struct DataAvailabilityDeployedAddresses { - address rollupDAManager; - address l1RollupDAValidator; - address l1BlobsDAValidatorZKsyncOS; - address noDAValidiumL1DAValidator; - address availBridge; - address availL1DAValidator; -} - -// solhint-disable-next-line gas-struct-packing -struct BridgehubDeployedAddresses { - address bridgehubImplementation; - address bridgehubProxy; - address ctmDeploymentTrackerImplementation; - address ctmDeploymentTrackerProxy; - address messageRootImplementation; - address messageRootProxy; - address chainAssetHandlerImplementation; - address chainAssetHandlerProxy; -} - -// solhint-disable-next-line gas-struct-packing -struct BridgesDeployedAddresses { - address erc20BridgeImplementation; - address erc20BridgeProxy; - address l1AssetRouterImplementation; - address l1AssetRouterProxy; - address l1NullifierImplementation; - address l1NullifierProxy; - address bridgedStandardERC20Implementation; - address bridgedTokenBeacon; -} - -// solhint-disable-next-line gas-struct-packing -struct Config { - uint256 l1ChainId; - address deployerAddress; - uint256 eraChainId; - uint256 gatewayChainId; - address ownerAddress; - bool testnetVerifier; - bool supportL2LegacySharedBridgeTest; - bool isZKsyncOS; - ContractsConfig contracts; - TokensConfig tokens; -} - -// solhint-disable-next-line gas-struct-packing -struct ContractsConfig { - address multicall3Addr; - uint256 validatorTimelockExecutionDelay; - bytes32 genesisRoot; - uint256 genesisRollupLeafIndex; - bytes32 genesisBatchCommitment; - uint256 latestProtocolVersion; - bytes32 recursionNodeLevelVkHash; - bytes32 recursionLeafLevelVkHash; - bytes32 recursionCircuitsSetVksHash; - uint256 priorityTxMaxGasLimit; - PubdataPricingMode diamondInitPubdataPricingMode; - uint256 diamondInitBatchOverheadL1Gas; - uint256 diamondInitMaxPubdataPerBatch; - uint256 diamondInitMaxL2GasPerBatch; - uint256 diamondInitPriorityTxMaxPubdata; - uint256 diamondInitMinimalL2GasPrice; - address governanceSecurityCouncilAddress; - uint256 governanceMinDelay; - uint256 maxNumberOfChains; - bytes diamondCutData; - bytes32 bootloaderHash; - bytes32 defaultAAHash; - bytes32 evmEmulatorHash; - address availL1DAValidator; -} - -struct TokensConfig { - address tokenWethAddress; -} - -// solhint-disable-next-line gas-struct-packing -struct GeneratedData { - bytes forceDeploymentsData; -} - -abstract contract DeployUtils is Create2FactoryUtils { - using stdToml for string; - - Config public config; - GeneratedData internal generatedData; - DeployedAddresses internal addresses; - - function initializeConfig(string memory configPath) internal virtual { - string memory toml = vm.readFile(configPath); - - config.l1ChainId = block.chainid; - config.deployerAddress = msg.sender; - - // Config file must be parsed key by key, otherwise values returned - // are parsed alfabetically and not by key. - // https://book.getfoundry.sh/cheatcodes/parse-toml - config.eraChainId = toml.readUint("$.era_chain_id"); - config.ownerAddress = toml.readAddress("$.owner_address"); - config.testnetVerifier = toml.readBool("$.testnet_verifier"); - config.supportL2LegacySharedBridgeTest = toml.readBool("$.support_l2_legacy_shared_bridge_test"); - config.isZKsyncOS = toml.readBool("$.is_zk_sync_os"); - - config.contracts.governanceSecurityCouncilAddress = toml.readAddress( - "$.contracts.governance_security_council_address" - ); - config.contracts.governanceMinDelay = toml.readUint("$.contracts.governance_min_delay"); - config.contracts.maxNumberOfChains = toml.readUint("$.contracts.max_number_of_chains"); - - bytes32 create2FactorySalt = toml.readBytes32("$.contracts.create2_factory_salt"); - address create2FactoryAddr; - if (vm.keyExistsToml(toml, "$.contracts.create2_factory_addr")) { - create2FactoryAddr = toml.readAddress("$.contracts.create2_factory_addr"); - } - _initCreate2FactoryParams(create2FactoryAddr, create2FactorySalt); - - config.contracts.validatorTimelockExecutionDelay = toml.readUint( - "$.contracts.validator_timelock_execution_delay" - ); - config.contracts.genesisRoot = toml.readBytes32("$.contracts.genesis_root"); - config.contracts.genesisRollupLeafIndex = toml.readUint("$.contracts.genesis_rollup_leaf_index"); - config.contracts.genesisBatchCommitment = toml.readBytes32("$.contracts.genesis_batch_commitment"); - config.contracts.latestProtocolVersion = toml.readUint("$.contracts.latest_protocol_version"); - config.contracts.recursionNodeLevelVkHash = toml.readBytes32("$.contracts.recursion_node_level_vk_hash"); - config.contracts.recursionLeafLevelVkHash = toml.readBytes32("$.contracts.recursion_leaf_level_vk_hash"); - config.contracts.recursionCircuitsSetVksHash = toml.readBytes32("$.contracts.recursion_circuits_set_vks_hash"); - config.contracts.priorityTxMaxGasLimit = toml.readUint("$.contracts.priority_tx_max_gas_limit"); - config.contracts.diamondInitPubdataPricingMode = PubdataPricingMode( - toml.readUint("$.contracts.diamond_init_pubdata_pricing_mode") - ); - config.contracts.diamondInitBatchOverheadL1Gas = toml.readUint( - "$.contracts.diamond_init_batch_overhead_l1_gas" - ); - config.contracts.diamondInitMaxPubdataPerBatch = toml.readUint( - "$.contracts.diamond_init_max_pubdata_per_batch" - ); - config.contracts.diamondInitMaxL2GasPerBatch = toml.readUint("$.contracts.diamond_init_max_l2_gas_per_batch"); - config.contracts.diamondInitPriorityTxMaxPubdata = toml.readUint( - "$.contracts.diamond_init_priority_tx_max_pubdata" - ); - config.contracts.diamondInitMinimalL2GasPrice = toml.readUint("$.contracts.diamond_init_minimal_l2_gas_price"); - config.contracts.defaultAAHash = toml.readBytes32("$.contracts.default_aa_hash"); - config.contracts.bootloaderHash = toml.readBytes32("$.contracts.bootloader_hash"); - config.contracts.evmEmulatorHash = toml.readBytes32("$.contracts.evm_emulator_hash"); - - if (vm.keyExistsToml(toml, "$.contracts.avail_l1_da_validator")) { - config.contracts.availL1DAValidator = toml.readAddress("$.contracts.avail_l1_da_validator"); - } - - config.tokens.tokenWethAddress = toml.readAddress("$.tokens.token_weth_address"); - } - - function deployStateTransitionDiamondFacets() internal { - addresses.stateTransition.executorFacet = deploySimpleContract("ExecutorFacet", false); - addresses.stateTransition.adminFacet = deploySimpleContract("AdminFacet", false); - addresses.stateTransition.mailboxFacet = deploySimpleContract("MailboxFacet", false); - addresses.stateTransition.gettersFacet = deploySimpleContract("GettersFacet", false); - addresses.stateTransition.diamondInit = deploySimpleContract("DiamondInit", false); - } - - function getChainCreationFacetCuts( - StateTransitionDeployedAddresses memory stateTransition - ) internal virtual returns (Diamond.FacetCut[] memory facetCuts); - - function getUpgradeAddedFacetCuts( - StateTransitionDeployedAddresses memory stateTransition - ) internal virtual returns (Diamond.FacetCut[] memory facetCuts); - - function getChainCreationDiamondCutData( - StateTransitionDeployedAddresses memory stateTransition - ) internal returns (Diamond.DiamondCutData memory diamondCut) { - Diamond.FacetCut[] memory facetCuts = getChainCreationFacetCuts(stateTransition); - - DiamondInitializeDataNewChain memory initializeData = getInitializeData(stateTransition); - - diamondCut = Diamond.DiamondCutData({ - facetCuts: facetCuts, - initAddress: stateTransition.diamondInit, - initCalldata: abi.encode(initializeData) - }); - if (!stateTransition.isOnGateway) { - config.contracts.diamondCutData = abi.encode(diamondCut); - } - } - - function getChainCreationParams( - StateTransitionDeployedAddresses memory stateTransition - ) internal returns (ChainCreationParams memory) { - Diamond.DiamondCutData memory diamondCut = getChainCreationDiamondCutData(stateTransition); - return - ChainCreationParams({ - genesisUpgrade: stateTransition.genesisUpgrade, - genesisBatchHash: config.contracts.genesisRoot, - genesisIndexRepeatedStorageChanges: uint64(config.contracts.genesisRollupLeafIndex), - genesisBatchCommitment: config.contracts.genesisBatchCommitment, - diamondCut: diamondCut, - forceDeploymentsData: generatedData.forceDeploymentsData - }); - } - - function getChainTypeManagerInitializeData( - StateTransitionDeployedAddresses memory stateTransition - ) internal returns (ChainTypeManagerInitializeData memory) { - ChainCreationParams memory chainCreationParams = getChainCreationParams(stateTransition); - return - ChainTypeManagerInitializeData({ - owner: msg.sender, - validatorTimelock: stateTransition.validatorTimelock, - chainCreationParams: chainCreationParams, - protocolVersion: config.contracts.latestProtocolVersion, - serverNotifier: stateTransition.serverNotifierProxy - }); - } - - function getVerifierParams() internal returns (VerifierParams memory) { - return - VerifierParams({ - recursionNodeLevelVkHash: config.contracts.recursionNodeLevelVkHash, - recursionLeafLevelVkHash: config.contracts.recursionLeafLevelVkHash, - recursionCircuitsSetVksHash: config.contracts.recursionCircuitsSetVksHash - }); - } - - function getFeeParams() internal returns (FeeParams memory) { - return - FeeParams({ - pubdataPricingMode: config.contracts.diamondInitPubdataPricingMode, - batchOverheadL1Gas: uint32(config.contracts.diamondInitBatchOverheadL1Gas), - maxPubdataPerBatch: uint32(config.contracts.diamondInitMaxPubdataPerBatch), - maxL2GasPerBatch: uint32(config.contracts.diamondInitMaxL2GasPerBatch), - priorityTxMaxPubdata: uint32(config.contracts.diamondInitPriorityTxMaxPubdata), - minimalL2GasPrice: uint64(config.contracts.diamondInitMinimalL2GasPrice) - }); - } - - function getInitializeData( - StateTransitionDeployedAddresses memory stateTransition - ) internal returns (DiamondInitializeDataNewChain memory) { - VerifierParams memory verifierParams = getVerifierParams(); - - FeeParams memory feeParams = getFeeParams(); - - require(stateTransition.verifier != address(0), "verifier is zero"); - require(config.contracts.bootloaderHash != bytes32(0), "bootloader hash is zero"); - require(config.contracts.defaultAAHash != bytes32(0), "default aa hash is zero"); - require(config.contracts.evmEmulatorHash != bytes32(0), "evm emulator hash is zero"); - - return - DiamondInitializeDataNewChain({ - verifier: IVerifier(stateTransition.verifier), - verifierParams: verifierParams, - l2BootloaderBytecodeHash: config.contracts.bootloaderHash, - l2DefaultAccountBytecodeHash: config.contracts.defaultAAHash, - l2EvmEmulatorBytecodeHash: config.contracts.evmEmulatorHash, - priorityTxMaxGasLimit: config.contracts.priorityTxMaxGasLimit, - feeParams: feeParams - }); - } - - ////////////////////////////// Contract deployment modes ///////////////////////////////// - - function deploySimpleContract( - string memory contractName, - bool isZKBytecode - ) internal returns (address contractAddress) { - contractAddress = deployViaCreate2AndNotify( - getCreationCode(contractName, false), - getCreationCalldata(contractName, false), - contractName, - isZKBytecode - ); - } - - function deployWithCreate2AndOwner( - string memory contractName, - address owner, - bool isZKBytecode - ) internal returns (address contractAddress) { - contractAddress = deployWithOwnerAndNotify( - getCreationCode(contractName, false), - getCreationCalldata(contractName, false), - owner, - contractName, - string.concat(contractName, " Implementation"), - isZKBytecode - ); - } - - function deployTuppWithContract( - string memory contractName, - bool isZKBytecode - ) internal virtual returns (address implementation, address proxy); - - function getCreationCode( - string memory contractName, - bool isZKBytecode - ) internal view virtual returns (bytes memory); - - function getCreationCalldata( - string memory contractName, - bool isZKBytecode - ) internal view virtual returns (bytes memory) { - if (compareStrings(contractName, "ChainRegistrar")) { - return abi.encode(); - } else if (compareStrings(contractName, "L1Bridgehub")) { - return abi.encode(config.ownerAddress, config.contracts.maxNumberOfChains); - } else if (compareStrings(contractName, "L1MessageRoot")) { - return abi.encode(addresses.bridgehub.bridgehubProxy); - } else if (compareStrings(contractName, "CTMDeploymentTracker")) { - return abi.encode(addresses.bridgehub.bridgehubProxy, addresses.bridges.l1AssetRouterProxy); - } else if (compareStrings(contractName, "L1ChainAssetHandler")) { - return - abi.encode( - config.ownerAddress, - addresses.bridgehub.bridgehubProxy, - addresses.bridges.l1AssetRouterProxy, - addresses.bridgehub.messageRootProxy - ); - } else if (compareStrings(contractName, "L1Nullifier")) { - return - abi.encode( - addresses.bridgehub.bridgehubProxy, - config.eraChainId, - addresses.stateTransition.diamondProxy - ); - } else if (compareStrings(contractName, "L1AssetRouter")) { - return - abi.encode( - config.tokens.tokenWethAddress, - addresses.bridgehub.bridgehubProxy, - addresses.bridges.l1NullifierProxy, - config.eraChainId, - addresses.stateTransition.diamondProxy - ); - } else if (compareStrings(contractName, "L1ERC20Bridge")) { - return - abi.encode( - addresses.bridges.l1NullifierProxy, - addresses.bridges.l1AssetRouterProxy, - addresses.vaults.l1NativeTokenVaultProxy, - config.eraChainId - ); - } else if (compareStrings(contractName, "L1NativeTokenVault")) { - return - abi.encode( - config.tokens.tokenWethAddress, - addresses.bridges.l1AssetRouterProxy, - addresses.bridges.l1NullifierProxy - ); - } else if (compareStrings(contractName, "BridgedStandardERC20")) { - return abi.encode(); - } else if (compareStrings(contractName, "BridgedTokenBeacon")) { - return abi.encode(addresses.bridges.bridgedStandardERC20Implementation); - } else if (compareStrings(contractName, "RollupDAManager")) { - return abi.encode(); - } else if (compareStrings(contractName, "RollupL1DAValidator")) { - return abi.encode(addresses.daAddresses.l1RollupDAValidator); - } else if (compareStrings(contractName, "BlobsL1DAValidatorZKsyncOS")) { - return abi.encode(); - } else if (compareStrings(contractName, "ValidiumL1DAValidator")) { - return abi.encode(); - } else if (compareStrings(contractName, "AvailL1DAValidator")) { - return abi.encode(addresses.daAddresses.availBridge); - } else if (compareStrings(contractName, "DummyAvailBridge")) { - return abi.encode(); - } else if (compareStrings(contractName, "EIP7702Checker")) { - return abi.encode(); - } else if (compareStrings(contractName, "MockEIP7702Checker")) { - return abi.encode(); - } else if (compareStrings(contractName, "Verifier")) { - if (config.isZKsyncOS) { - return - abi.encode( - addresses.stateTransition.verifierFflonk, - addresses.stateTransition.verifierPlonk, - msg.sender - ); - } else { - return abi.encode(addresses.stateTransition.verifierFflonk, addresses.stateTransition.verifierPlonk); - } - } else if (compareStrings(contractName, "EraVerifierFflonk")) { - return abi.encode(); - } else if (compareStrings(contractName, "EraVerifierPlonk")) { - return abi.encode(); - } else if (compareStrings(contractName, "ZKsyncOSVerifierFflonk")) { - return abi.encode(); - } else if (compareStrings(contractName, "ZKsyncOSVerifierPlonk")) { - return abi.encode(); - } else if (compareStrings(contractName, "DefaultUpgrade")) { - return abi.encode(); - } else if (compareStrings(contractName, "L1GenesisUpgrade")) { - return abi.encode(); - } else if (compareStrings(contractName, "ValidatorTimelock")) { - return abi.encode(addresses.bridgehub.bridgehubProxy); - } else if (compareStrings(contractName, "Governance")) { - return - abi.encode( - config.ownerAddress, - config.contracts.governanceSecurityCouncilAddress, - config.contracts.governanceMinDelay - ); - } else if (compareStrings(contractName, "ChainAdminOwnable")) { - return abi.encode(config.ownerAddress, address(0)); - } else if (compareStrings(contractName, "AccessControlRestriction")) { - return abi.encode(uint256(0), config.ownerAddress); - } else if (compareStrings(contractName, "ChainAdmin")) { - address[] memory restrictions = new address[](1); - restrictions[0] = addresses.accessControlRestrictionAddress; - return abi.encode(restrictions); - } else if (compareStrings(contractName, "ChainTypeManager")) { - return abi.encode(addresses.bridgehub.bridgehubProxy); - } else if (compareStrings(contractName, "EraChainTypeManager")) { - return abi.encode(addresses.bridgehub.bridgehubProxy); - } else if (compareStrings(contractName, "ZKsyncOSChainTypeManager")) { - return abi.encode(addresses.bridgehub.bridgehubProxy); - } else if (compareStrings(contractName, "BytecodesSupplier")) { - return abi.encode(); - } else if (compareStrings(contractName, "ProxyAdmin")) { - return abi.encode(); - } else if (compareStrings(contractName, "ExecutorFacet")) { - return abi.encode(config.l1ChainId); - } else if (compareStrings(contractName, "AdminFacet")) { - return abi.encode(config.l1ChainId, addresses.daAddresses.rollupDAManager); - } else if (compareStrings(contractName, "MailboxFacet")) { - return abi.encode(config.eraChainId, config.l1ChainId, addresses.eip7702Checker); - } else if (compareStrings(contractName, "GettersFacet")) { - return abi.encode(); - } else if (compareStrings(contractName, "ServerNotifier")) { - return abi.encode(); - } else if (compareStrings(contractName, "DiamondInit")) { - return abi.encode(config.isZKsyncOS); - } else { - revert(string.concat("Contract ", contractName, " creation calldata not set")); - } - } - - function calculateExpectedL2Address(string memory contractName) internal returns (address) { - return Utils.getL2AddressViaCreate2Factory(bytes32(0), getL2BytecodeHash(contractName), hex""); - } - - function getL2BytecodeHash(string memory contractName) public view virtual returns (bytes32) { - return L2ContractHelper.hashL2Bytecode(getCreationCode(contractName, true)); - } - - function getInitializeCalldata( - string memory contractName, - bool isZKBytecode - ) internal virtual returns (bytes memory); - - function test() internal virtual {} -} diff --git a/l1-contracts/deploy-scripts/DeployUtils.sol b/l1-contracts/deploy-scripts/DeployUtils.sol new file mode 100644 index 0000000000..f74276d51c --- /dev/null +++ b/l1-contracts/deploy-scripts/DeployUtils.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.10; + +import {Create2FactoryUtils} from "./Create2FactoryUtils.s.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; + +abstract contract DeployUtils is Create2FactoryUtils { + function deployTuppWithContract( + string memory contractName, + bool isZKBytecode + ) public returns (address implementation, address proxy) { + (implementation, proxy) = deployTuppWithContractAndProxyAdmin( + contractName, + transparentProxyAdmin(), + isZKBytecode + ); + } + + function deployTuppWithContractAndProxyAdmin( + string memory contractName, + address proxyAdmin, + bool isZKBytecode + ) public returns (address implementation, address proxy) { + implementation = deployViaCreate2AndNotify( + getCreationCode(contractName, false), + getCreationCalldata(contractName, false), + contractName, + string.concat(contractName, " Implementation"), + isZKBytecode + ); + + proxy = deployViaCreate2AndNotify( + type(TransparentUpgradeableProxy).creationCode, + abi.encode(implementation, proxyAdmin, getInitializeCalldata(contractName, false)), + contractName, + string.concat(contractName, " Proxy"), + isZKBytecode + ); + return (implementation, proxy); + } + + function getCreationCode( + string memory contractName, + bool isZKBytecode + ) internal view virtual returns (bytes memory); + + function getCreationCalldata( + string memory contractName, + bool isZKBytecode + ) internal view virtual returns (bytes memory); + + function getInitializeCalldata( + string memory contractName, + bool isZKBytecode + ) internal virtual returns (bytes memory); + + function transparentProxyAdmin() internal virtual returns (address); + + function deploySimpleContract( + string memory contractName, + bool isZKBytecode + ) public returns (address contractAddress) { + contractAddress = deployViaCreate2AndNotify( + getCreationCode(contractName, false), + getCreationCalldata(contractName, false), + contractName, + isZKBytecode + ); + } + + function deployWithCreate2AndOwner( + string memory contractName, + address owner, + bool isZKBytecode + ) public returns (address contractAddress) { + contractAddress = deployWithOwnerAndNotify( + getCreationCode(contractName, false), + getCreationCalldata(contractName, false), + owner, + contractName, + string.concat(contractName, " Implementation"), + isZKBytecode + ); + } +} diff --git a/l1-contracts/deploy-scripts/PrepareZKChainRegistrationCalldata.s.sol b/l1-contracts/deploy-scripts/PrepareZKChainRegistrationCalldata.s.sol index ea9fd56e10..7a916bd37c 100644 --- a/l1-contracts/deploy-scripts/PrepareZKChainRegistrationCalldata.s.sol +++ b/l1-contracts/deploy-scripts/PrepareZKChainRegistrationCalldata.s.sol @@ -143,7 +143,7 @@ contract PrepareZKChainRegistrationCalldataScript is Script { config.erc20BridgeProxy = toml.readAddress("$.deployed_addresses.erc20_bridge_proxy_addr"); ecosystem.bridgehub = IChainTypeManager(config.stateTransitionProxy).BRIDGE_HUB(); - ecosystem.l1SharedBridgeProxy = address(L1Bridgehub(ecosystem.bridgehub).sharedBridge()); + ecosystem.l1SharedBridgeProxy = address(L1Bridgehub(ecosystem.bridgehub).assetRouter()); ecosystem.governance = L1Bridgehub(ecosystem.bridgehub).owner(); config.chainId = toml.readUint("$.chain.chain_id"); diff --git a/l1-contracts/deploy-scripts/RegisterCTM.s.sol b/l1-contracts/deploy-scripts/RegisterCTM.s.sol index 744dc60911..7b80d7e695 100644 --- a/l1-contracts/deploy-scripts/RegisterCTM.s.sol +++ b/l1-contracts/deploy-scripts/RegisterCTM.s.sol @@ -23,7 +23,7 @@ contract RegisterCTM is Script { } function registerCTM(address bridgehub, address chainTypeManagerProxy, bool shouldSend) public virtual { - console.log("Registering CTM"); + console.log("Registering CTM for L1 contracts"); runInner("/script-out/register-ctm-l1.toml", bridgehub, chainTypeManagerProxy, shouldSend); } diff --git a/l1-contracts/deploy-scripts/RegisterOnAllChains.s.sol b/l1-contracts/deploy-scripts/RegisterOnAllChains.s.sol new file mode 100644 index 0000000000..37e9060b8f --- /dev/null +++ b/l1-contracts/deploy-scripts/RegisterOnAllChains.s.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.21; + +import {Script} from "forge-std/Script.sol"; +import {console2 as console} from "forge-std/console2.sol"; +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; +import {ChainRegistrationSender} from "contracts/bridgehub/ChainRegistrationSender.sol"; +import {IMailbox} from "contracts/state-transition/chain-interfaces/IMailbox.sol"; + +contract RegisterOnAllChainsScript is Script { + function registerOnOtherChains(address _bridgehub, uint256 _chainId) public { + IBridgehubBase bridgehub = IBridgehubBase(_bridgehub); + uint256[] memory chainsToRegisterOn = bridgehub.getAllZKChainChainIDs(); + ChainRegistrationSender chainRegistrationSender = ChainRegistrationSender(bridgehub.chainRegistrationSender()); + + for (uint256 i = 0; i < chainsToRegisterOn.length; i++) { + if (chainRegistrationSender.chainRegisteredOnChain(chainsToRegisterOn[i], _chainId)) { + continue; + } + vm.startBroadcast(); + chainRegistrationSender.registerChain(chainsToRegisterOn[i], _chainId); + vm.stopBroadcast(); + } + for (uint256 i = 0; i < chainsToRegisterOn.length; i++) { + if ( + chainRegistrationSender.chainRegisteredOnChain(_chainId, chainsToRegisterOn[i]) || + chainsToRegisterOn[i] == _chainId + ) { + continue; + } + if (_depositsPaused(bridgehub, chainsToRegisterOn[i])) { + console.log( + "Info: Deposits are paused on chain:", + chainsToRegisterOn[i], + ", skipping registration for chain:", + _chainId + ); + continue; + } + vm.startBroadcast(); + chainRegistrationSender.registerChain(_chainId, chainsToRegisterOn[i]); + vm.stopBroadcast(); + } + } + + function _depositsPaused(IBridgehubBase bridgehub, uint256 chainToRegisterOn) internal view returns (bool) { + address zkChain = bridgehub.getZKChain(chainToRegisterOn); + IMailbox mailbox = IMailbox(zkChain); + return mailbox.depositsPaused(); + } +} diff --git a/l1-contracts/deploy-scripts/RegisterZKChain.s.sol b/l1-contracts/deploy-scripts/RegisterZKChain.s.sol index 5ac1e3e381..2fd86b73fe 100644 --- a/l1-contracts/deploy-scripts/RegisterZKChain.s.sol +++ b/l1-contracts/deploy-scripts/RegisterZKChain.s.sol @@ -8,14 +8,16 @@ import {Script, console2 as console} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; -import {Ownable} from "@openzeppelin/contracts-v4/access/Ownable.sol"; +import {IChainRegistrationSender} from "contracts/bridgehub/IChainRegistrationSender.sol"; import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol"; import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; import {IValidatorTimelock} from "contracts/state-transition/IValidatorTimelock.sol"; import {Governance} from "contracts/governance/Governance.sol"; import {ChainAdmin} from "contracts/governance/ChainAdmin.sol"; import {ChainAdminOwnable} from "contracts/governance/ChainAdminOwnable.sol"; +import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; import {IChainAdminOwnable} from "contracts/governance/IChainAdminOwnable.sol"; import {AccessControlRestriction} from "contracts/governance/AccessControlRestriction.sol"; import {ADDRESS_ONE, Utils} from "./Utils.sol"; @@ -34,6 +36,8 @@ import {Call} from "contracts/governance/Common.sol"; import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; import {Create2AndTransfer} from "./Create2AndTransfer.sol"; +import {PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_MAINNET} from "contracts/common/Config.sol"; +import {ZkChainAddresses} from "./Types.sol"; // solhint-disable-next-line gas-struct-packing struct Config { @@ -76,15 +80,6 @@ contract RegisterZKChainScript is Script { bytes32 internal constant STATE_TRANSITION_NEW_CHAIN_HASH = keccak256("NewZKChain(uint256,address)"); - struct Output { - address governance; - address diamondProxy; - address chainAdmin; - address l2LegacySharedBridge; - address accessControlRestrictionAddress; - address chainProxyAdmin; - } - struct LegacySharedBridgeParams { bytes implementationConstructorParams; address implementationAddress; @@ -95,7 +90,7 @@ contract RegisterZKChainScript is Script { LegacySharedBridgeParams internal legacySharedBridgeParams; Config internal config; - Output internal output; + ZkChainAddresses internal output; function run() public { console.log("Deploying ZKChain"); @@ -108,6 +103,8 @@ contract RegisterZKChainScript is Script { function runForTest() public { console.log("Deploying ZKChain"); + // Timestamp needs to be late enough for `pauseDepositsBeforeInitiatingMigration` time checks + vm.warp(PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + 1); initializeConfigTest(); runInner(vm.envString("ZK_CHAIN_OUT")); } @@ -222,6 +219,9 @@ contract RegisterZKChainScript is Script { config.bridgehub = toml.readAddress("$.deployed_addresses.bridgehub.bridgehub_proxy_addr"); // TODO(EVM-744): name of the key is a bit inconsistent + + path = string.concat(root, vm.envString("CTM_OUTPUT")); + toml = vm.readFile(path); config.chainTypeManagerProxy = toml.readAddress( "$.deployed_addresses.state_transition.state_transition_proxy_addr" ); diff --git a/l1-contracts/deploy-scripts/Types.sol b/l1-contracts/deploy-scripts/Types.sol new file mode 100644 index 0000000000..01d5dcaf3d --- /dev/null +++ b/l1-contracts/deploy-scripts/Types.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.10; + +import {PubdataPricingMode} from "contracts/state-transition/chain-deps/ZKChainStorage.sol"; + +// solhint-disable-next-line gas-struct-packing +struct L1NativeTokenVaultAddresses { + address l1NativeTokenVaultImplementation; + address l1NativeTokenVaultProxy; +} + +// solhint-disable-next-line gas-struct-packing +struct BridgehubDeployedAddresses { + address bridgehubImplementation; + address bridgehubProxy; + address ctmDeploymentTrackerImplementation; + address ctmDeploymentTrackerProxy; + address messageRootImplementation; + address messageRootProxy; + address chainAssetHandlerImplementation; + address chainAssetHandlerProxy; + address interopCenterImplementation; + address interopCenterProxy; + address chainRegistrationSenderProxy; + address chainRegistrationSenderImplementation; + address assetTrackerProxy; + address assetTrackerImplementation; +} + +// solhint-disable-next-line gas-struct-packing +struct BridgesDeployedAddresses { + address erc20BridgeImplementation; + address erc20BridgeProxy; + address l1AssetRouterImplementation; + address l1AssetRouterProxy; + address l1NullifierImplementation; + address l1NullifierProxy; + address bridgedStandardERC20Implementation; + address bridgedTokenBeacon; +} + +struct DataAvailabilityDeployedAddresses { + address rollupDAManager; + address l1RollupDAValidator; + address noDAValidiumL1DAValidator; + address availBridge; + address availL1DAValidator; + address l1BlobsDAValidatorZKsyncOS; +} + +struct ZkChainAddresses { + address governance; + address diamondProxy; + address chainAdmin; + address l2LegacySharedBridge; + address accessControlRestrictionAddress; + address chainProxyAdmin; +} + +// solhint-disable-next-line gas-struct-packing +struct StateTransitionDeployedAddresses { + address chainTypeManagerProxy; + address chainTypeManagerProxyAdmin; + address chainTypeManagerImplementation; + address verifier; + address verifierFflonk; + address verifierPlonk; + address adminFacet; + address mailboxFacet; + address executorFacet; + address gettersFacet; + address diamondInit; + address genesisUpgrade; + address defaultUpgrade; + address validatorTimelockImplementation; + address validatorTimelock; + address diamondProxy; + address bytecodesSupplier; + address serverNotifierProxy; + address serverNotifierImplementation; + address rollupDAManager; + address rollupSLDAValidator; + bool isOnGateway; +} + +struct ChainCreationParamsConfig { + bytes32 genesisRoot; + uint256 genesisRollupLeafIndex; + bytes32 genesisBatchCommitment; + uint256 latestProtocolVersion; + uint256 priorityTxMaxGasLimit; + PubdataPricingMode diamondInitPubdataPricingMode; + uint256 diamondInitBatchOverheadL1Gas; + uint256 diamondInitMaxPubdataPerBatch; + uint256 diamondInitMaxL2GasPerBatch; + uint256 diamondInitPriorityTxMaxPubdata; + uint256 diamondInitMinimalL2GasPrice; + bytes32 bootloaderHash; + bytes32 defaultAAHash; + bytes32 evmEmulatorHash; +} diff --git a/l1-contracts/deploy-scripts/Utils.sol b/l1-contracts/deploy-scripts/Utils.sol index 90a11cb42a..b763544d24 100644 --- a/l1-contracts/deploy-scripts/Utils.sol +++ b/l1-contracts/deploy-scripts/Utils.sol @@ -6,11 +6,13 @@ pragma solidity ^0.8.24; import {Vm} from "forge-std/Vm.sol"; import {console2 as console} from "forge-std/Script.sol"; +import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; +import {Ownable} from "@openzeppelin/contracts-v4/access/Ownable.sol"; + import {IAccessControlDefaultAdminRules} from "@openzeppelin/contracts-v4/access/IAccessControlDefaultAdminRules.sol"; import {IL1Bridgehub, L2TransactionRequestDirect, L2TransactionRequestTwoBridgesOuter} from "contracts/bridgehub/IL1Bridgehub.sol"; import {IGovernance} from "contracts/governance/IGovernance.sol"; -import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {IOwnable} from "contracts/common/interfaces/IOwnable.sol"; import {Call} from "contracts/governance/Common.sol"; import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol"; @@ -54,38 +56,12 @@ address constant L2_BRIDGEHUB_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x02); address constant L2_ASSET_ROUTER_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x03); address constant L2_NATIVE_TOKEN_VAULT_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x04); address constant L2_MESSAGE_ROOT_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x05); -address constant L2_WETH_IMPL_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x07); +address constant L2_WRAPPED_BASE_TOKEN_IMPL_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x07); address constant L2_CREATE2_FACTORY_ADDRESS = address(USER_CONTRACTS_OFFSET); uint256 constant SECURITY_COUNCIL_SIZE = 12; -// solhint-disable-next-line gas-struct-packing -struct StateTransitionDeployedAddresses { - address chainTypeManagerProxy; - address chainTypeManagerProxyAdmin; - address chainTypeManagerImplementation; - address verifier; - address verifierFflonk; - address verifierPlonk; - address adminFacet; - address mailboxFacet; - address executorFacet; - address gettersFacet; - address diamondInit; - address genesisUpgrade; - address defaultUpgrade; - address validatorTimelockImplementation; - address validatorTimelock; - address diamondProxy; - address bytecodesSupplier; - address serverNotifierProxy; - address serverNotifierImplementation; - address rollupDAManager; - address rollupSLDAValidator; - bool isOnGateway; -} - /// @dev We need to use a struct instead of list of params to prevent stack too deep error struct PrepareL1L2TransactionParams { uint256 l1GasPrice; @@ -256,6 +232,88 @@ library Utils { return bytecode; } + /** + * @dev Returns the bytecode of a given system contract. + */ + // function readSystemContractsBytecode(string memory filename) internal view returns (bytes memory) { + // return readZKFoundryBytecodeSystemContracts(string.concat(filename, ".sol"), filename); + // } + + // /** + // * @dev Returns the bytecode of a given system contract. + // */ + // function readL1ContractsBytecode(string memory path, string memory filename) internal view returns (bytes memory) { + // string memory root = vm.projectRoot(); + // string memory CONTRACTS_PATH = vm.envString("CONTRACTS_PATH"); + // string memory file = vm.readFile( + // // solhint-disable-next-line func-named-parameters + // string.concat( + // root, + // "/", + // CONTRACTS_PATH, + // "/l1-contracts/artifacts-zk/contracts/", + // path, + // filename, + // ".sol/", + // filename, + // ".json" + // ) + // ); + // bytes memory bytecode = vm.parseJson(file, "$.bytecode"); + // return bytecode; + // } + + // /** + // * @dev Returns the bytecode of a given system contract. + // */ + // function getL1ContractsPath(string memory path, string memory filename) internal view returns (string memory) { + // string memory root = vm.projectRoot(); + // string memory CONTRACTS_PATH = vm.envString("CONTRACTS_PATH"); + + // // solhint-disable-next-line func-named-parameters + // return string.concat( + // root, + // "/", + // CONTRACTS_PATH, + // "/l1-contracts/artifacts-zk/contracts/", + // path, + // filename, + // ".sol/", + // filename, + // ".json" + // ); + // } + + // /** + // * @dev Returns the bytecode of a given system contract in yul. + // */ + // function readSystemContractsYulBytecode(string memory filename) internal view returns (bytes memory) { + // string memory path = string.concat( + // "/../system-contracts/zkout/", + // filename, + // ".yul/contracts-preprocessed/", + // filename, + // ".yul.json" + // ); + + // return readFoundryBytecode(path); + // } + + // /** + // * @dev Returns the bytecode of a given precompile system contract. + // */ + // function readPrecompileBytecode(string memory filename) internal view returns (bytes memory) { + // string memory path = string.concat( + // "/../system-contracts/zkout/", + // filename, + // ".yul/contracts-preprocessed/precompiles/", + // filename, + // ".yul.json" + // ); + + // return readFoundryBytecode(path); + // } + /** * @dev Deploy a Create2Factory contract. */ @@ -480,23 +538,22 @@ library Utils { address refundRecipient ) internal returns (bytes32 txHash) { IL1Bridgehub bridgehub = IL1Bridgehub(bridgehubAddress); + PrepareL1L2TransactionParams memory params = PrepareL1L2TransactionParams({ + l1GasPrice: bytesToUint256(vm.rpc("eth_gasPrice", "[]")), + l2Calldata: l2Calldata, + l2GasLimit: l2GasLimit, + l2Value: l2Value, + factoryDeps: factoryDeps, + dstAddress: dstAddress, + chainId: chainId, + bridgehubAddress: bridgehubAddress, + l1SharedBridgeProxy: l1SharedBridgeProxy, + refundRecipient: refundRecipient + }); ( L2TransactionRequestDirect memory l2TransactionRequestDirect, uint256 requiredValueToDeploy - ) = prepareL1L2Transaction( - PrepareL1L2TransactionParams({ - l1GasPrice: bytesToUint256(vm.rpc("eth_gasPrice", "[]")), - l2Calldata: l2Calldata, - l2GasLimit: l2GasLimit, - l2Value: l2Value, - factoryDeps: factoryDeps, - dstAddress: dstAddress, - chainId: chainId, - bridgehubAddress: bridgehubAddress, - l1SharedBridgeProxy: l1SharedBridgeProxy, - refundRecipient: refundRecipient - }) - ); + ) = prepareL1L2Transaction(params); address baseTokenAddress = bridgehub.baseToken(chainId); if (ADDRESS_ONE != baseTokenAddress) { @@ -520,6 +577,30 @@ library Utils { console.logBytes32(txHash); } + /// TODO(EVM-748): make that function support non-ETH based chains + function supplyChainWallet( + address addr, + uint256 amount, + uint256 chainId, + address bridgehubAddress, + address l1SharedBridgeProxy + ) public returns (bytes32 txHash) { + runL1L2Transaction({ + l2Calldata: hex"", + l2GasLimit: Utils.MAX_PRIORITY_TX_GAS, + l2Value: amount, + factoryDeps: new bytes[](0), + dstAddress: addr, + chainId: chainId, + bridgehubAddress: bridgehubAddress, + l1SharedBridgeProxy: l1SharedBridgeProxy, + refundRecipient: addr + }); + + // We record L2 tx hash only for governance operations + return bytes32(0); + } + function prepareGovernanceL1L2DirectTransaction( uint256 l1GasPrice, bytes memory l2Calldata, @@ -1010,7 +1091,18 @@ library Utils { string memory fileName, string memory contractName ) internal view returns (bytes memory) { - string memory path = string.concat("/../system-contracts/zkout/", fileName, "/", contractName, ".json"); + // kl todo add contracts path here + string memory CONTRACTS_PATH = vm.envString("CONTRACTS_PATH"); + + string memory path = string.concat( + "/", + CONTRACTS_PATH, + "/system-contracts/zkout/", + fileName, + "/", + contractName, + ".json" + ); bytes memory bytecode = readFoundryBytecode(path); return bytecode; } diff --git a/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol b/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol index 999504f223..772fd78506 100644 --- a/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol +++ b/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol @@ -13,6 +13,7 @@ import {L2ContractHelper} from "contracts/common/l2-helpers/L2ContractHelper.sol import {L2LegacySharedBridgeTestHelper} from "../L2LegacySharedBridgeTestHelper.sol"; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; import {L1NullifierDev} from "contracts/dev-contracts/L1NullifierDev.sol"; +import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; /// This scripts is only for developer contract SetupLegacyBridge is Script { @@ -99,9 +100,18 @@ contract SetupLegacyBridge is Script { } function deployL1NullifierImplementation() internal { + IL1Bridgehub bridgehub = IL1Bridgehub(addresses.bridgehub); + bytes memory bytecode = abi.encodePacked( type(L1NullifierDev).creationCode, - abi.encode(addresses.bridgehub, config.chainId, addresses.diamondProxy) + abi.encode( + addresses.bridgehub, + bridgehub.messageRoot(), + // This value ignored now, but supposed to be interop center + address(0), + config.chainId, + addresses.diamondProxy + ) ); address contractAddress = deployViaCreate2(bytecode); diff --git a/l1-contracts/deploy-scripts/gateway/GatewayCTMDeployerHelper.sol b/l1-contracts/deploy-scripts/gateway/GatewayCTMDeployerHelper.sol index ff03d6091a..cb83789b4a 100644 --- a/l1-contracts/deploy-scripts/gateway/GatewayCTMDeployerHelper.sol +++ b/l1-contracts/deploy-scripts/gateway/GatewayCTMDeployerHelper.sol @@ -8,7 +8,7 @@ import {ZKsyncOSChainTypeManager} from "contracts/state-transition/ZKsyncOSChain import {EraChainTypeManager} from "contracts/state-transition/EraChainTypeManager.sol"; import {ServerNotifier} from "contracts/governance/ServerNotifier.sol"; -import {L2_BRIDGEHUB_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {L2_BRIDGEHUB_ADDR, L2_INTEROP_CENTER_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {IEIP7702Checker} from "contracts/state-transition/chain-interfaces/IEIP7702Checker.sol"; import {IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; @@ -23,6 +23,9 @@ import {L2ContractHelper} from "contracts/common/l2-helpers/L2ContractHelper.sol import {DeployedContracts, GatewayCTMDeployerConfig} from "contracts/state-transition/chain-deps/GatewayCTMDeployer.sol"; +import {DeployCTML1OrGateway, CTMCoreDeploymentConfig} from "../DeployCTML1OrGateway.sol"; +import {CTMContract} from "../DeployCTML1OrGateway.sol"; + // solhint-disable gas-custom-errors struct InnerDeployConfig { @@ -53,7 +56,7 @@ library GatewayCTMDeployerHelper { uint256 eraChainId = config.eraChainId; uint256 l1ChainId = config.l1ChainId; - contracts.multicall3 = _deployInternal("Multicall3", "Multicall3.sol", hex"", innerConfig); + contracts.multicall3 = _deployInternalEmptyParams("Multicall3", "Multicall3.sol", innerConfig); contracts = _deployFacetsAndUpgrades( salt, @@ -61,12 +64,14 @@ library GatewayCTMDeployerHelper { l1ChainId, config.aliasedGovernanceAddress, config.isZKsyncOS, + config, contracts, innerConfig ); contracts = _deployVerifier( config.testnetVerifier, config.isZKsyncOS, + config, contracts, innerConfig, config.aliasedGovernanceAddress @@ -75,18 +80,18 @@ library GatewayCTMDeployerHelper { contracts.stateTransition.validatorTimelockImplementation = _deployInternal( "ValidatorTimelock", "ValidatorTimelock.sol", - abi.encode(L2_BRIDGEHUB_ADDR), - innerConfig + innerConfig, + config, + contracts ); - contracts.stateTransition.chainTypeManagerProxyAdmin = _deployInternal( + contracts.stateTransition.chainTypeManagerProxyAdmin = _deployInternalEmptyParams( "ProxyAdmin", "ProxyAdmin.sol", - hex"", innerConfig ); - contracts.stateTransition.validatorTimelock = _deployInternal( + contracts.stateTransition.validatorTimelock = _deployInternalWithParams( "TransparentUpgradeableProxy", "TransparentUpgradeableProxy.sol", abi.encode( @@ -100,26 +105,50 @@ library GatewayCTMDeployerHelper { contracts.stateTransition.serverNotifierProxy = _deployServerNotifier( contracts, innerConfig, + config, + contracts, ctmDeployerAddress ); contracts = _deployCTM(salt, config, contracts, innerConfig); } + function getCTMCoreDeploymentConfig( + GatewayCTMDeployerConfig memory _config, + DeployedContracts memory _deployedContracts + ) internal returns (CTMCoreDeploymentConfig memory) { + return + CTMCoreDeploymentConfig({ + isZKsyncOS: _config.isZKsyncOS, + testnetVerifier: _config.testnetVerifier, + eraChainId: _config.eraChainId, + l1ChainId: _config.l1ChainId, + bridgehubProxy: L2_BRIDGEHUB_ADDR, + interopCenterProxy: L2_INTEROP_CENTER_ADDR, + rollupDAManager: _deployedContracts.daContracts.rollupDAManager, + chainAssetHandler: L2_CHAIN_ASSET_HANDLER_ADDR, + eip7702Checker: address(0), + verifierFflonk: _deployedContracts.stateTransition.verifierFflonk, + verifierPlonk: _deployedContracts.stateTransition.verifierPlonk, + ownerAddress: _config.aliasedGovernanceAddress + }); + } + function _deployServerNotifier( DeployedContracts memory _deployedContracts, InnerDeployConfig memory innerConfig, + GatewayCTMDeployerConfig memory config, + DeployedContracts memory contracts, address ctmDeployerAddress ) internal returns (address) { - address serverNotifierImplementation = _deployInternal( + address serverNotifierImplementation = _deployInternalEmptyParams( "ServerNotifier", "ServerNotifier.sol", - abi.encode(), innerConfig ); _deployedContracts.stateTransition.serverNotifierImplementation = serverNotifierImplementation; - address serverNotifier = _deployInternal( + address serverNotifier = _deployInternalWithParams( "TransparentUpgradeableProxy", "TransparentUpgradeableProxy.sol", abi.encode( @@ -139,54 +168,51 @@ library GatewayCTMDeployerHelper { uint256 _l1ChainId, address _governanceAddress, bool _isZKsyncOS, + GatewayCTMDeployerConfig memory _config, DeployedContracts memory _deployedContracts, InnerDeployConfig memory innerConfig ) internal returns (DeployedContracts memory) { _deployedContracts.stateTransition.mailboxFacet = _deployInternal( "MailboxFacet", "Mailbox.sol", - abi.encode(_eraChainId, _l1ChainId, IEIP7702Checker(address(0))), - innerConfig + innerConfig, + _config, + _deployedContracts ); _deployedContracts.stateTransition.executorFacet = _deployInternal( "ExecutorFacet", "Executor.sol", - abi.encode(_l1ChainId), - innerConfig + innerConfig, + _config, + _deployedContracts ); - _deployedContracts.stateTransition.gettersFacet = _deployInternal( + _deployedContracts.stateTransition.gettersFacet = _deployInternalEmptyParams( "GettersFacet", "Getters.sol", - hex"", innerConfig ); - address rollupDAManager; - (_deployedContracts, rollupDAManager) = _deployRollupDAManager( - _salt, - _governanceAddress, - _deployedContracts, - innerConfig - ); + (_deployedContracts) = _deployRollupDAManager(_salt, _governanceAddress, _deployedContracts, innerConfig); _deployedContracts.stateTransition.adminFacet = _deployInternal( "AdminFacet", "Admin.sol", - abi.encode(_l1ChainId, rollupDAManager), - innerConfig + innerConfig, + _config, + _deployedContracts ); _deployedContracts.stateTransition.diamondInit = _deployInternal( "DiamondInit", "DiamondInit.sol", - abi.encode(_isZKsyncOS), - innerConfig + innerConfig, + _config, + _deployedContracts ); - _deployedContracts.stateTransition.genesisUpgrade = _deployInternal( + _deployedContracts.stateTransition.genesisUpgrade = _deployInternalEmptyParams( "L1GenesisUpgrade", "L1GenesisUpgrade.sol", - hex"", innerConfig ); @@ -196,6 +222,7 @@ library GatewayCTMDeployerHelper { function _deployVerifier( bool _testnetVerifier, bool _isZKsyncOS, + GatewayCTMDeployerConfig memory _config, DeployedContracts memory _deployedContracts, InnerDeployConfig memory innerConfig, address _verifierOwner @@ -204,16 +231,19 @@ library GatewayCTMDeployerHelper { address verifierPlonk; if (_isZKsyncOS) { - verifierFflonk = _deployInternal( + verifierFflonk = _deployInternalEmptyParams( "ZKsyncOSVerifierFflonk", "ZKsyncOSVerifierFflonk.sol", - hex"", innerConfig ); - verifierPlonk = _deployInternal("ZKsyncOSVerifierPlonk", "ZKsyncOSVerifierPlonk.sol", hex"", innerConfig); + verifierPlonk = _deployInternalEmptyParams( + "ZKsyncOSVerifierPlonk", + "ZKsyncOSVerifierPlonk.sol", + innerConfig + ); } else { - verifierFflonk = _deployInternal("EraVerifierFflonk", "EraVerifierFflonk.sol", hex"", innerConfig); - verifierPlonk = _deployInternal("EraVerifierPlonk", "EraVerifierPlonk.sol", hex"", innerConfig); + verifierFflonk = _deployInternalEmptyParams("EraVerifierFflonk", "EraVerifierFflonk.sol", innerConfig); + verifierPlonk = _deployInternalEmptyParams("EraVerifierPlonk", "EraVerifierPlonk.sol", innerConfig); } _deployedContracts.stateTransition.verifierFflonk = verifierFflonk; @@ -224,15 +254,17 @@ library GatewayCTMDeployerHelper { _deployedContracts.stateTransition.verifier = _deployInternal( "ZKsyncOSTestnetVerifier", "ZKsyncOSTestnetVerifier.sol", - abi.encode(verifierFflonk, verifierPlonk, _verifierOwner), - innerConfig + innerConfig, + _config, + _deployedContracts ); } else { _deployedContracts.stateTransition.verifier = _deployInternal( "EraTestnetVerifier", "EraTestnetVerifier.sol", - abi.encode(verifierFflonk, verifierPlonk), - innerConfig + innerConfig, + _config, + _deployedContracts ); } } else { @@ -240,15 +272,17 @@ library GatewayCTMDeployerHelper { _deployedContracts.stateTransition.verifier = _deployInternal( "ZKsyncOSDualVerifier", "ZKsyncOSDualVerifier.sol", - abi.encode(verifierFflonk, verifierPlonk, _verifierOwner), - innerConfig + innerConfig, + _config, + _deployedContracts ); } else { _deployedContracts.stateTransition.verifier = _deployInternal( "EraDualVerifier", "EraDualVerifier.sol", - abi.encode(verifierFflonk, verifierPlonk), - innerConfig + innerConfig, + _config, + _deployedContracts ); } } @@ -260,20 +294,18 @@ library GatewayCTMDeployerHelper { address _governanceAddress, DeployedContracts memory _deployedContracts, InnerDeployConfig memory innerConfig - ) internal returns (DeployedContracts memory, address) { - address daManager = _deployInternal("RollupDAManager", "RollupDAManager.sol", hex"", innerConfig); + ) internal returns (DeployedContracts memory) { + address daManager = _deployInternalEmptyParams("RollupDAManager", "RollupDAManager.sol", innerConfig); - address validiumDAValidator = _deployInternal( + address validiumDAValidator = _deployInternalEmptyParams( "ValidiumL1DAValidator", "ValidiumL1DAValidator.sol", - hex"", innerConfig ); - address relayedSLDAValidator = _deployInternal( + address relayedSLDAValidator = _deployInternalEmptyParams( "RelayedSLDAValidator", "RelayedSLDAValidator.sol", - hex"", innerConfig ); @@ -281,7 +313,7 @@ library GatewayCTMDeployerHelper { _deployedContracts.daContracts.relayedSLDAValidator = relayedSLDAValidator; _deployedContracts.daContracts.validiumDAValidator = validiumDAValidator; - return (_deployedContracts, daManager); + return (_deployedContracts); } function _deployCTM( @@ -294,15 +326,17 @@ library GatewayCTMDeployerHelper { _deployedContracts.stateTransition.chainTypeManagerImplementation = _deployInternal( "ZKsyncOSChainTypeManager", "ZKsyncOSChainTypeManager.sol", - abi.encode(L2_BRIDGEHUB_ADDR), - innerConfig + innerConfig, + _config, + _deployedContracts ); } else { _deployedContracts.stateTransition.chainTypeManagerImplementation = _deployInternal( "EraChainTypeManager", "EraChainTypeManager.sol", - abi.encode(L2_BRIDGEHUB_ADDR), - innerConfig + innerConfig, + _config, + _deployedContracts ); } @@ -369,7 +403,7 @@ library GatewayCTMDeployerHelper { bytes memory initCalldata = abi.encodeCall(IChainTypeManager.initialize, (diamondInitData)); - _deployedContracts.stateTransition.chainTypeManagerProxy = _deployInternal( + _deployedContracts.stateTransition.chainTypeManagerProxy = _deployInternalWithParams( "TransparentUpgradeableProxy", "TransparentUpgradeableProxy.sol", abi.encode( @@ -383,7 +417,44 @@ library GatewayCTMDeployerHelper { return _deployedContracts; } + function _deployInternalEmptyParams( + string memory contractName, + string memory fileName, + InnerDeployConfig memory config + ) private returns (address) { + return _deployInternalInner(contractName, fileName, hex"", config); + } + + function _deployInternalWithParams( + string memory contractName, + string memory fileName, + bytes memory params, + InnerDeployConfig memory config + ) private returns (address) { + return _deployInternalInner(contractName, fileName, params, config); + } + function _deployInternal( + string memory contractName, + string memory fileName, + InnerDeployConfig memory config, + GatewayCTMDeployerConfig memory _config, + DeployedContracts memory _deployedContracts + ) private returns (address) { + return + _deployInternalInner( + contractName, + fileName, + DeployCTML1OrGateway.getCreationCalldata( + getCTMCoreDeploymentConfig(_config, _deployedContracts), + DeployCTML1OrGateway.getCTMContractFromName(contractName), + false + ), + config + ); + } + + function _deployInternalInner( string memory contractName, string memory fileName, bytes memory params, diff --git a/l1-contracts/deploy-scripts/gateway/GatewayGovernanceUtils.s.sol b/l1-contracts/deploy-scripts/gateway/GatewayGovernanceUtils.s.sol index 227aa6db8b..e30badd8ca 100644 --- a/l1-contracts/deploy-scripts/gateway/GatewayGovernanceUtils.s.sol +++ b/l1-contracts/deploy-scripts/gateway/GatewayGovernanceUtils.s.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.0; // solhint-disable no-console, gas-custom-errors, reason-string import {Script, console2 as console} from "forge-std/Script.sol"; -// + // It's required to disable lints to force the compiler to compile the contracts // solhint-disable no-unused-import @@ -203,20 +203,21 @@ abstract contract GatewayGovernanceUtils is Script { prepareGWGovCallsStruct._refundRecipient ) ); - calls = Utils.mergeCalls( - calls, - Utils.prepareGovernanceL1L2DirectTransaction( - prepareGWGovCallsStruct._l1GasPrice, - data, - Utils.MAX_PRIORITY_TX_GAS, - new bytes[](0), - prepareGWGovCallsStruct._gatewayValidatorTimelock, - _gatewayGovernanceConfig.gatewayChainId, - _gatewayGovernanceConfig.bridgehubProxy, - _gatewayGovernanceConfig.l1AssetRouterProxy, - prepareGWGovCallsStruct._refundRecipient - ) - ); + // Todo: can probably delete since ValidatorTimelock is now TUPP. + // calls = Utils.mergeCalls( + // calls, + // Utils.prepareGovernanceL1L2DirectTransaction( + // prepareGWGovCallsStruct._l1GasPrice, + // data, + // Utils.MAX_PRIORITY_TX_GAS, + // new bytes[](0), + // prepareGWGovCallsStruct._gatewayValidatorTimelock, + // _gatewayGovernanceConfig.gatewayChainId, + // _gatewayGovernanceConfig.bridgehubProxy, + // _gatewayGovernanceConfig.l1AssetRouterProxy, + // prepareGWGovCallsStruct._refundRecipient + // ) + // ); calls = Utils.mergeCalls( calls, Utils.prepareGovernanceL1L2DirectTransaction( diff --git a/l1-contracts/deploy-scripts/gateway/GatewayMigrateTokenBalances.s.sol b/l1-contracts/deploy-scripts/gateway/GatewayMigrateTokenBalances.s.sol new file mode 100644 index 0000000000..aacf110dbf --- /dev/null +++ b/l1-contracts/deploy-scripts/gateway/GatewayMigrateTokenBalances.s.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +// solhint-disable no-console, gas-custom-errors, reason-string + +import {Script, console2 as console} from "forge-std/Script.sol"; +import {stdJson} from "forge-std/StdJson.sol"; + +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; + +import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; +import {IL2AssetTracker} from "contracts/bridge/asset-tracker/IL2AssetTracker.sol"; +import {IL1AssetTracker} from "contracts/bridge/asset-tracker/IL1AssetTracker.sol"; +import {IAssetTrackerBase} from "contracts/bridge/asset-tracker/IAssetTrackerBase.sol"; +import {TokenBalanceMigrationData} from "contracts/common/Messaging.sol"; +import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; +import {IAssetTrackerDataEncoding} from "contracts/bridge/asset-tracker/IAssetTrackerDataEncoding.sol"; +import {INativeTokenVaultBase} from "contracts/bridge/ntv/INativeTokenVaultBase.sol"; +import {IL1NativeTokenVault} from "contracts/bridge/ntv/IL1NativeTokenVault.sol"; +import {FinalizeL1DepositParams} from "contracts/bridge/interfaces/IL1Nullifier.sol"; + +import {GW_ASSET_TRACKER, L2_ASSET_ROUTER, L2_ASSET_TRACKER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {ZKSProvider} from "../provider/ZKSProvider.s.sol"; + +import {Utils} from "../Utils.sol"; + +/// @notice Scripts that is responsible for preparing the chain to become a gateway +/// @dev IMPORTANT: this script is not intended to be used in production. +/// TODO(EVM-925): support secure gateway deployment. +contract GatewayMigrateTokenBalances is ZKSProvider { + using stdJson for string; + + IAssetTrackerBase l2AssetTrackerBase = IAssetTrackerBase(L2_ASSET_TRACKER_ADDR); + IL2AssetTracker l2AssetTracker = IL2AssetTracker(L2_ASSET_TRACKER_ADDR); + INativeTokenVaultBase l2NativeTokenVault = INativeTokenVaultBase(L2_NATIVE_TOKEN_VAULT_ADDR); + + function getBridgedTokenAssetIds() public returns (uint256 bridgedTokenCountPlusOne, bytes32[] memory assetIds) { + // Get all registered tokens + uint256 bridgedTokenCount = l2NativeTokenVault.bridgedTokensCount(); + bridgedTokenCountPlusOne = bridgedTokenCount + 1; + assetIds = new bytes32[](bridgedTokenCountPlusOne); + for (uint256 i = 0; i < bridgedTokenCount; i++) { + assetIds[i] = l2NativeTokenVault.bridgedTokens(i); + } + assetIds[bridgedTokenCount] = L2_ASSET_ROUTER.BASE_TOKEN_ASSET_ID(); + } + + error InvalidFunctionSignature(bytes4 functionSignature); + + function finishMigrationOnL1( + bool toGateway, + IBridgehubBase bridgehub, + uint256 chainId, + uint256 gatewayChainId, + string memory l2RpcUrl, + string memory gwRpcUrl, + bool onlyWaitForFinalization, + bytes32[] memory txHashes + ) public { + IL1AssetRouter assetRouter = IL1AssetRouter(address(bridgehub.assetRouter())); + IL1NativeTokenVault l1NativeTokenVault = IL1NativeTokenVault(address(assetRouter.nativeTokenVault())); + + uint256 settlementLayer = IBridgehubBase(bridgehub).settlementLayer(chainId); + + if (txHashes.length == 0) { + console.log("No migration txs for chainId:", chainId); + return; + } + + uint256 bridgedTokenCount = txHashes.length; + FinalizeL1DepositParams[] memory finalizeL1DepositParams = new FinalizeL1DepositParams[](bridgedTokenCount); + + for (uint256 i = 0; i < bridgedTokenCount; i++) { + finalizeL1DepositParams[i] = getFinalizeWithdrawalParams( + toGateway ? chainId : gatewayChainId, + toGateway ? l2RpcUrl : gwRpcUrl, + txHashes[i], + 0 + ); + } + + for (uint256 i = 0; i < bridgedTokenCount; i++) { + if (finalizeL1DepositParams[i].merkleProof.length == 0) { + continue; + } + waitForBatchToBeExecuted(address(bridgehub), chainId, finalizeL1DepositParams[i]); + break; + } + + if (onlyWaitForFinalization) { + return; + } + + IL1AssetTracker l1AssetTracker = IL1AssetTracker(address(l1NativeTokenVault.l1AssetTracker())); + IAssetTrackerBase l1AssetTrackerBase = IAssetTrackerBase(address(l1AssetTracker)); + + for (uint256 i = 0; i < bridgedTokenCount; i++) { + if (finalizeL1DepositParams[i].merkleProof.length == 0) { + continue; + } + // console.logBytes(abi.encodeCall(l1AssetTracker.receiveMigrationOnL1, (finalizeL1DepositParams[i]))); + (bytes4 functionSignature, TokenBalanceMigrationData memory data) = DataEncoding + .decodeTokenBalanceMigrationData(finalizeL1DepositParams[i].message); + require( + functionSignature == IAssetTrackerDataEncoding.receiveMigrationOnL1.selector, + InvalidFunctionSignature(functionSignature) + ); + if (!l1AssetTrackerBase.tokenMigrated(data.chainId, data.assetId)) { + vm.broadcast(); + l1AssetTracker.receiveMigrationOnL1(finalizeL1DepositParams[i]); + } + } + } + + function checkAllMigrated(uint256 chainId, string memory l2RpcUrl) public { + (uint256 bridgedTokenCount, bytes32[] memory assetIds) = getBridgedTokenAssetIds(); + for (uint256 i = 0; i < bridgedTokenCount; i++) { + bytes32 assetId = assetIds[i]; + bool migrated = l2AssetTrackerBase.tokenMigratedThisChain(assetId); + require(migrated, "Token not migrated"); + } + } +} diff --git a/l1-contracts/deploy-scripts/gateway/GatewayUtils.s.sol b/l1-contracts/deploy-scripts/gateway/GatewayUtils.s.sol index a0fa87c523..26d6addbf1 100644 --- a/l1-contracts/deploy-scripts/gateway/GatewayUtils.s.sol +++ b/l1-contracts/deploy-scripts/gateway/GatewayUtils.s.sol @@ -8,18 +8,93 @@ import {Script, console2 as console} from "forge-std/Script.sol"; // It's required to disable lints to force the compiler to compile the contracts // solhint-disable no-unused-import +import {BridgehubBurnCTMAssetData} from "contracts/bridgehub/IBridgehubBase.sol"; import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; - +import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol"; +import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol"; import {L2_ASSET_ROUTER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; -import {Utils} from "../Utils.sol"; - -import {L1Nullifier} from "contracts/bridge/L1Nullifier.sol"; import {L1AssetRouter} from "contracts/bridge/asset-router/L1AssetRouter.sol"; - import {FinalizeL1DepositParams, IL1Nullifier} from "contracts/bridge/interfaces/IL1Nullifier.sol"; +import {TxStatus, ConfirmTransferResultData} from "contracts/common/Messaging.sol"; /// @notice Scripts that is responsible for preparing the chain to become a gateway contract GatewayUtils is Script { + struct FinishMigrateChainToGatewayParams { + address bridgehubAddr; + bytes gatewayDiamondCutData; + uint256 migratingChainId; + uint256 gatewayChainId; + bytes32 l2TxHash; + uint256 l2BatchNumber; + uint256 l2MessageIndex; + uint16 l2TxNumberInBatch; + bytes32[] merkleProof; + TxStatus txStatus; + } + + function finishMigrateChainToGateway( + address bridgehubAddr, + bytes memory gatewayDiamondCutData, + uint256 migratingChainId, + uint256 gatewayChainId, + bytes32 l2TxHash, + uint256 l2BatchNumber, + uint256 l2MessageIndex, + uint16 l2TxNumberInBatch, + bytes32[] calldata merkleProof, + TxStatus txStatus + ) public { + _finishMigrateChainToGatewayInner( + FinishMigrateChainToGatewayParams({ + bridgehubAddr: bridgehubAddr, + gatewayDiamondCutData: gatewayDiamondCutData, + migratingChainId: migratingChainId, + gatewayChainId: gatewayChainId, + l2TxHash: l2TxHash, + l2BatchNumber: l2BatchNumber, + l2MessageIndex: l2MessageIndex, + l2TxNumberInBatch: l2TxNumberInBatch, + merkleProof: merkleProof, + txStatus: txStatus + }) + ); + } + + // Using struct for input to avoid stack too deep errors + // The outer function does not expect it as input rightaway for easier encoding in zkstack Rust. + function _finishMigrateChainToGatewayInner(FinishMigrateChainToGatewayParams memory data) private { + IL1Bridgehub bridgehub = IL1Bridgehub(data.bridgehubAddr); + address assetRouter = address(bridgehub.assetRouter()); + IL1Nullifier l1Nullifier = L1AssetRouter(assetRouter).L1_NULLIFIER(); + + bytes32 assetId = bridgehub.ctmAssetIdFromChainId(data.migratingChainId); + address chainAdmin = IZKChain(bridgehub.getZKChain(data.migratingChainId)).getAdmin(); + + bytes memory transferData = abi.encode( + BridgehubBurnCTMAssetData({ + chainId: data.migratingChainId, + ctmData: abi.encode(AddressAliasHelper.applyL1ToL2Alias(chainAdmin), data.gatewayDiamondCutData), + chainData: abi.encode(IZKChain(bridgehub.getZKChain(data.migratingChainId)).getProtocolVersion()) + }) + ); + + vm.broadcast(); + l1Nullifier.bridgeConfirmTransferResult( + ConfirmTransferResultData({ + _chainId: data.gatewayChainId, + _depositSender: chainAdmin, + _assetId: assetId, + _assetData: transferData, + _l2TxHash: data.l2TxHash, + _l2BatchNumber: data.l2BatchNumber, + _l2MessageIndex: data.l2MessageIndex, + _l2TxNumberInBatch: data.l2TxNumberInBatch, + _merkleProof: data.merkleProof, + _txStatus: data.txStatus + }) + ); + } + function finishMigrateChainFromGateway( address bridgehubAddr, uint256 migratingChainId, diff --git a/l1-contracts/deploy-scripts/gateway/GatewayVotePreparation.s.sol b/l1-contracts/deploy-scripts/gateway/GatewayVotePreparation.s.sol index 4d8b24e6ac..3238b296d7 100644 --- a/l1-contracts/deploy-scripts/gateway/GatewayVotePreparation.s.sol +++ b/l1-contracts/deploy-scripts/gateway/GatewayVotePreparation.s.sol @@ -3,8 +3,7 @@ pragma solidity 0.8.28; // solhint-disable no-console, gas-custom-errors, reason-string -import {Script, console2 as console} from "forge-std/Script.sol"; -// import {Vm} from "forge-std/Vm.sol"; +import {console2 as console} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; // It's required to disable lints to force the compiler to compile the contracts @@ -14,7 +13,7 @@ import {Ownable} from "@openzeppelin/contracts-v4/access/Ownable.sol"; import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; import {L2_CREATE2_FACTORY_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; -import {StateTransitionDeployedAddresses, Utils} from "../Utils.sol"; +import {Utils} from "../Utils.sol"; import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol"; import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; @@ -29,9 +28,12 @@ import {RollupDAManager} from "contracts/state-transition/data-availability/Roll import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; +import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; import {ChainTypeManagerBase} from "contracts/state-transition/ChainTypeManagerBase.sol"; import {DeployCTMScript} from "../DeployCTM.s.sol"; +import {StateTransitionDeployedAddresses} from "../Types.sol"; +import {AddressIntrospector} from "../AddressIntrospector.sol"; import {GatewayCTMDeployerHelper} from "./GatewayCTMDeployerHelper.sol"; import {DeployedContracts, GatewayCTMDeployerConfig} from "contracts/state-transition/chain-deps/GatewayCTMDeployer.sol"; @@ -40,9 +42,10 @@ import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-de import {L1Bridgehub} from "contracts/bridgehub/L1Bridgehub.sol"; import {GatewayGovernanceUtils} from "./GatewayGovernanceUtils.s.sol"; +import {DeployCTMUtils} from "../DeployCTMUtils.s.sol"; /// @notice Scripts that is responsible for preparing the chain to become a gateway -contract GatewayVotePreparation is DeployCTMScript, GatewayGovernanceUtils { +contract GatewayVotePreparation is DeployCTMUtils, GatewayGovernanceUtils { using stdToml for string; struct GatewayCTMOutput { @@ -65,6 +68,7 @@ contract GatewayVotePreparation is DeployCTMScript, GatewayGovernanceUtils { address internal serverNotifier; address internal refundRecipient; + address ctm; GatewayCTMDeployerConfig internal gatewayCTMDeployerConfig; @@ -72,7 +76,7 @@ contract GatewayVotePreparation is DeployCTMScript, GatewayGovernanceUtils { super.initializeConfig(configPath); string memory toml = vm.readFile(configPath); - addresses.bridgehub.bridgehubProxy = toml.readAddress("$.contracts.bridgehub_proxy_address"); + address bridgehubProxy = toml.readAddress("$.contracts.bridgehub_proxy_address"); refundRecipient = toml.readAddress("$.refund_recipient"); eraChainId = toml.readUint("$.era_chain_id"); @@ -80,7 +84,7 @@ contract GatewayVotePreparation is DeployCTMScript, GatewayGovernanceUtils { gatewayChainId = toml.readUint("$.gateway_chain_id"); forceDeploymentsData = toml.readBytes(".force_deployments_data"); - setAddressesBasedOnBridgehub(ctmRepresentativeChainId); + setAddressesBasedOnBridgehub(ctmRepresentativeChainId, bridgehubProxy); address aliasedGovernor = AddressAliasHelper.applyL1ToL2Alias(config.ownerAddress); gatewayCTMDeployerConfig = GatewayCTMDeployerConfig({ @@ -95,65 +99,45 @@ contract GatewayVotePreparation is DeployCTMScript, GatewayGovernanceUtils { mailboxSelectors: Utils.getAllSelectorsForFacet("Mailbox"), gettersSelectors: Utils.getAllSelectorsForFacet("Getters"), verifierParams: VerifierParams({ - recursionNodeLevelVkHash: config.contracts.recursionNodeLevelVkHash, - recursionLeafLevelVkHash: config.contracts.recursionLeafLevelVkHash, - recursionCircuitsSetVksHash: config.contracts.recursionCircuitsSetVksHash + recursionNodeLevelVkHash: bytes32(0), + recursionLeafLevelVkHash: bytes32(0), + recursionCircuitsSetVksHash: bytes32(0) }), feeParams: FeeParams({ - pubdataPricingMode: config.contracts.diamondInitPubdataPricingMode, - batchOverheadL1Gas: uint32(config.contracts.diamondInitBatchOverheadL1Gas), - maxPubdataPerBatch: uint32(config.contracts.diamondInitMaxPubdataPerBatch), - maxL2GasPerBatch: uint32(config.contracts.diamondInitMaxL2GasPerBatch), - priorityTxMaxPubdata: uint32(config.contracts.diamondInitPriorityTxMaxPubdata), - minimalL2GasPrice: uint64(config.contracts.diamondInitMinimalL2GasPrice) + pubdataPricingMode: config.contracts.chainCreationParams.diamondInitPubdataPricingMode, + batchOverheadL1Gas: uint32(config.contracts.chainCreationParams.diamondInitBatchOverheadL1Gas), + maxPubdataPerBatch: uint32(config.contracts.chainCreationParams.diamondInitMaxPubdataPerBatch), + maxL2GasPerBatch: uint32(config.contracts.chainCreationParams.diamondInitMaxL2GasPerBatch), + priorityTxMaxPubdata: uint32(config.contracts.chainCreationParams.diamondInitPriorityTxMaxPubdata), + minimalL2GasPrice: uint64(config.contracts.chainCreationParams.diamondInitMinimalL2GasPrice) }), - bootloaderHash: config.contracts.bootloaderHash, - defaultAccountHash: config.contracts.defaultAAHash, - evmEmulatorHash: config.contracts.evmEmulatorHash, - priorityTxMaxGasLimit: config.contracts.priorityTxMaxGasLimit, - genesisRoot: config.contracts.genesisRoot, - genesisRollupLeafIndex: uint64(config.contracts.genesisRollupLeafIndex), - genesisBatchCommitment: config.contracts.genesisBatchCommitment, + bootloaderHash: config.contracts.chainCreationParams.bootloaderHash, + defaultAccountHash: config.contracts.chainCreationParams.defaultAAHash, + evmEmulatorHash: config.contracts.chainCreationParams.evmEmulatorHash, + priorityTxMaxGasLimit: config.contracts.chainCreationParams.priorityTxMaxGasLimit, + genesisRoot: config.contracts.chainCreationParams.genesisRoot, + genesisRollupLeafIndex: uint64(config.contracts.chainCreationParams.genesisRollupLeafIndex), + genesisBatchCommitment: config.contracts.chainCreationParams.genesisBatchCommitment, forceDeploymentsData: forceDeploymentsData, - protocolVersion: config.contracts.latestProtocolVersion + protocolVersion: config.contracts.chainCreationParams.latestProtocolVersion }); } - function setAddressesBasedOnBridgehub(uint256 ctmRepresentativeChainId) internal { - config.ownerAddress = L1Bridgehub(addresses.bridgehub.bridgehubProxy).owner(); - address ctm; + function setAddressesBasedOnBridgehub(uint256 ctmRepresentativeChainId, address bridgehubProxy) internal { + discoveredBridgehub = AddressIntrospector.getBridgehubAddresses(IL1Bridgehub(bridgehubProxy)); + config.ownerAddress = L1Bridgehub(bridgehubProxy).owner(); if (ctmRepresentativeChainId != 0) { - ctm = IL1Bridgehub(addresses.bridgehub.bridgehubProxy).chainTypeManager(ctmRepresentativeChainId); + ctm = IL1Bridgehub(bridgehubProxy).chainTypeManager(ctmRepresentativeChainId); } else { - ctm = IL1Bridgehub(addresses.bridgehub.bridgehubProxy).chainTypeManager(gatewayChainId); + ctm = IL1Bridgehub(bridgehubProxy).chainTypeManager(gatewayChainId); } - addresses.stateTransition.chainTypeManagerProxy = ctm; uint256 ctmProtocolVersion = IChainTypeManager(ctm).protocolVersion(); require( - ctmProtocolVersion == config.contracts.latestProtocolVersion, - "The latest protocol version is not correct" - ); - serverNotifier = ChainTypeManagerBase(ctm).serverNotifierAddress(); - addresses.bridges.l1AssetRouterProxy = L1Bridgehub(addresses.bridgehub.bridgehubProxy).assetRouter(); - - addresses.vaults.l1NativeTokenVaultProxy = address( - L1AssetRouter(addresses.bridges.l1AssetRouterProxy).nativeTokenVault() - ); - addresses.bridges.l1NullifierProxy = address( - L1AssetRouter(addresses.bridges.l1AssetRouterProxy).L1_NULLIFIER() - ); - - addresses.bridgehub.ctmDeploymentTrackerProxy = address( - L1Bridgehub(addresses.bridgehub.bridgehubProxy).l1CtmDeployer() - ); - - addresses.bridgehub.messageRootProxy = address(L1Bridgehub(addresses.bridgehub.bridgehubProxy).messageRoot()); - - addresses.bridges.erc20BridgeProxy = address( - L1AssetRouter(addresses.bridges.l1AssetRouterProxy).legacyBridge() + ctmProtocolVersion == config.contracts.chainCreationParams.latestProtocolVersion, + "CTM protocol version mismatch" ); // It is used as the ecosystem admin inside the `DeployL1` contract - addresses.chainAdmin = L1Bridgehub(addresses.bridgehub.bridgehubProxy).admin(); + addresses.chainAdmin = L1Bridgehub(bridgehubProxy).admin(); } function deployGatewayCTM() internal { @@ -172,8 +156,8 @@ contract GatewayVotePreparation is DeployCTMScript, GatewayGovernanceUtils { factoryDeps: localDeps, dstAddress: address(0), chainId: gatewayChainId, - bridgehubAddress: addresses.bridgehub.bridgehubProxy, - l1SharedBridgeProxy: addresses.bridges.l1AssetRouterProxy, + bridgehubAddress: discoveredBridgehub.bridgehubProxy, + l1SharedBridgeProxy: discoveredBridgehub.assetRouter, refundRecipient: msg.sender }); } @@ -185,8 +169,8 @@ contract GatewayVotePreparation is DeployCTMScript, GatewayGovernanceUtils { factoryDeps: new bytes[](0), dstAddress: L2_CREATE2_FACTORY_ADDR, chainId: gatewayChainId, - bridgehubAddress: addresses.bridgehub.bridgehubProxy, - l1SharedBridgeProxy: addresses.bridges.l1AssetRouterProxy, + bridgehubAddress: discoveredBridgehub.bridgehubProxy, + l1SharedBridgeProxy: discoveredBridgehub.assetRouter, refundRecipient: msg.sender }); @@ -230,10 +214,17 @@ contract GatewayVotePreparation is DeployCTMScript, GatewayGovernanceUtils { }); } - function run() public override { + function run() public { prepareForGWVoting(0); } + function deployServerNotifier() internal returns (address implementation, address proxy) { + // We will not store the address of the ProxyAdmin as it is trivial to query if needed. + address ecosystemProxyAdmin = deployWithCreate2AndOwner("ProxyAdmin", addresses.chainAdmin, false); + + (implementation, proxy) = deployTuppWithContractAndProxyAdmin("ServerNotifier", ecosystemProxyAdmin, false); + } + function prepareForGWVoting(uint256 ctmRepresentativeChainId) public { console.log("Setting up the Gateway script"); @@ -243,10 +234,10 @@ contract GatewayVotePreparation is DeployCTMScript, GatewayGovernanceUtils { initializeConfig(configPath, ctmRepresentativeChainId); _initializeGatewayGovernanceConfig( GatewayGovernanceConfig({ - bridgehubProxy: addresses.bridgehub.bridgehubProxy, - l1AssetRouterProxy: addresses.bridges.l1AssetRouterProxy, - chainTypeManagerProxy: addresses.stateTransition.chainTypeManagerProxy, - ctmDeploymentTrackerProxy: addresses.bridgehub.ctmDeploymentTrackerProxy, + bridgehubProxy: discoveredBridgehub.bridgehubProxy, + l1AssetRouterProxy: discoveredBridgehub.assetRouter, + chainTypeManagerProxy: ctm, + ctmDeploymentTrackerProxy: discoveredBridgehub.l1CtmDeployer, gatewayChainId: gatewayChainId }) ); @@ -257,9 +248,7 @@ contract GatewayVotePreparation is DeployCTMScript, GatewayGovernanceUtils { (, serverNotifier) = deployServerNotifier(); vm.startBroadcast(); - ServerNotifier(serverNotifier).setChainTypeManager( - IChainTypeManager(addresses.stateTransition.chainTypeManagerProxy) - ); + ServerNotifier(serverNotifier).setChainTypeManager(IChainTypeManager(ctm)); ServerNotifier(serverNotifier).transferOwnership(addresses.chainAdmin); vm.stopBroadcast(); diff --git a/l1-contracts/deploy-scripts/provider/BroadcastTypes.sol b/l1-contracts/deploy-scripts/provider/BroadcastTypes.sol new file mode 100644 index 0000000000..a2af648cf2 --- /dev/null +++ b/l1-contracts/deploy-scripts/provider/BroadcastTypes.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +struct Transaction { + string[] additionalContracts; + bytes32[] arguments; + address contractAddress; + string functionKey; + bytes32 hash; + bool isFixedGasLimit; + string transactionType; +} diff --git a/l1-contracts/deploy-scripts/provider/ReceipTypes.sol b/l1-contracts/deploy-scripts/provider/ReceipTypes.sol new file mode 100644 index 0000000000..ed041967cd --- /dev/null +++ b/l1-contracts/deploy-scripts/provider/ReceipTypes.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +struct L2ToL1LogProof { + uint64 id; + bytes32[] proof; +} + +struct AltL2ToL1Log { + bytes32 blockHash; + uint256 blockNumber; + // uint256 isService; + bytes32 key; + uint256 l1BatchNumber; + uint256 logIndex; + address sender; + uint256 shardId; + bytes32 transactionHash; + uint256 transactionIndex; + uint256 transactionLogIndex; + uint256 txIndexInL1Batch; + bytes32 value; +} + +struct L2ToL1Log { + uint64 blockNumber; + bytes32 blockHash; + // bool isService; + bytes32 key; + uint64 logIndex; + uint64 l1BatchNumber; + address sender; + uint64 shardId; + bytes32 transactionHash; + uint64 transactionIndex; + uint64 transactionLogIndex; + uint64 txIndexInL1Batch; + bytes32 value; +} + +struct AltLog { + uint256 addr; + bytes32 blockHash; + uint256 blockNumber; + uint256 blockTimestamp; + // string data; + uint256 l1BatchNumber; + uint256 logIndex; + // string logType; + // string removed; + // bytes32[] topics; + bytes32 transactionHash; + uint256 transactionIndex; + uint256 transactionLogIndex; +} + +struct Log { + address addr; + bytes32 blockHash; + uint64 blockNumber; + uint64 blockTimestamp; + bytes data; + uint64 logIndex; + // string logType; + uint64 l1BatchNumber; + // bool removed; + bytes32[] topics; + uint64 transactionIndex; + bytes32 transactionHash; + uint64 transactionLogIndex; +} + +struct TransactionReceipt { + uint64 blockNumber; + bytes32 blockHash; + // address contractAddress; + uint64 cumulativeGasUsed; + uint64 gasUsed; + Log[] logs; + L2ToL1Log[] l2ToL1Logs; + bool status; + bytes32 transactionHash; + uint64 transactionIndex; +} + +struct AltTransactionReceipt { + bytes32 blockHash; + uint256 blockNumber; + // address contractAddress; + uint256 cumulativeGasUsed; + uint256 effectiveGasPrice; + address from; + uint256 gasUsed; + // AltLog[] logs; + // L2ToL1Log[] l2ToL1Logs; + // bytes logsBloom; + uint256 l1BatchNumber; + uint256 l1BatchTxIndex; + uint256 status; + address to; + bytes32 transactionHash; + uint256 transactionIndex; + uint256 txType; +} diff --git a/l1-contracts/deploy-scripts/provider/ZKSProvider.s.sol b/l1-contracts/deploy-scripts/provider/ZKSProvider.s.sol new file mode 100644 index 0000000000..687f047255 --- /dev/null +++ b/l1-contracts/deploy-scripts/provider/ZKSProvider.s.sol @@ -0,0 +1,512 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +// solhint-disable no-console, gas-custom-errors, reason-string + +import {Script, console2 as console} from "forge-std/Script.sol"; + +import {stdJson} from "forge-std/StdJson.sol"; + +import {FinalizeL1DepositParams} from "contracts/common/Messaging.sol"; +import {Utils} from "../Utils.sol"; +import {AltL2ToL1Log, AltLog, AltTransactionReceipt, L2ToL1Log, L2ToL1LogProof, Log, TransactionReceipt} from "./ReceipTypes.sol"; + +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; +import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; +import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; +import {IL1Nullifier} from "contracts/bridge/L1Nullifier.sol"; +import {IGetters} from "contracts/state-transition/chain-deps/facets/Getters.sol"; +import {ProofData} from "contracts/common/libraries/MessageHashing.sol"; + +contract ZKSProvider is Script { + function finalizeWithdrawal( + uint256 chainId, + address l1Bridgehub, + string memory l2RpcUrl, + bytes32 withdrawalHash, + uint256 index + ) public { + FinalizeL1DepositParams memory params = getFinalizeWithdrawalParams(chainId, l2RpcUrl, withdrawalHash, index); + + IBridgehubBase bridgehub = IBridgehubBase(l1Bridgehub); + IL1AssetRouter assetRouter = IL1AssetRouter(address(bridgehub.assetRouter())); + IL1Nullifier nullifier = IL1Nullifier(assetRouter.L1_NULLIFIER()); + + waitForBatchToBeExecuted(l1Bridgehub, chainId, params); + + // Send the transaction + vm.startBroadcast(); + nullifier.finalizeDeposit(params); + vm.stopBroadcast(); + } + + function waitForWithdrawalToBeFinalized( + uint256 chainId, + address l1Bridgehub, + string memory l2RpcUrl, + bytes32 withdrawalHash, + uint256 index + ) public { + FinalizeL1DepositParams memory params = getFinalizeWithdrawalParams(chainId, l2RpcUrl, withdrawalHash, index); + waitForBatchToBeExecuted(l1Bridgehub, chainId, params); + } + + /// we might not need this. + /// nullifier.finalizeDeposit simulation probably happens at an earlier blocknumber. + /// It might be enough to wait for the merkle proof from the server. + function waitForBatchToBeExecuted( + address l1Bridgehub, + uint256 chainId, + FinalizeL1DepositParams memory params + ) public { + IBridgehubBase bridgehub = IBridgehubBase(l1Bridgehub); + // IL1AssetRouter assetRouter = IL1AssetRouter(bridgehub.assetRouter()); + // IL1Nullifier nullifier = IL1Nullifier(assetRouter.L1_NULLIFIER()); + IMessageRoot messageRoot = IMessageRoot(bridgehub.messageRoot()); + ProofData memory proofData = messageRoot.getProofData( + params.chainId, + params.l2BatchNumber, + params.l2MessageIndex, + bytes32(0), + params.merkleProof + ); + + // console.log("proofData"); + uint256 actualChainId = chainId; + uint256 actualBatchNumber = params.l2BatchNumber; + if (proofData.settlementLayerChainId != chainId && proofData.settlementLayerChainId != 0) { + actualChainId = proofData.settlementLayerChainId; + actualBatchNumber = proofData.settlementLayerBatchNumber; + } + + IGetters getters = IGetters(bridgehub.getZKChain(actualChainId)); + uint256 totalBatchesExecuted; + uint256 loopCount = 0; + // _initCreate2FactoryParams(address(0), bytes32(0)); + // instantiateCreate2Factory(); + + // IteratedReader reader = IteratedReader(deployViaCreate2(abi.encodePacked(type(IteratedReader).creationCode))); + // console.log("Reader deployed at", address(reader)); + + while (totalBatchesExecuted < actualBatchNumber && loopCount < 30) { + loopCount++; + // totalBatchesExecuted = getters.getTotalBatchesExecuted(); + totalBatchesExecuted = getTotalBatchesExecuted(address(getters)); + uint256 secondsToWait = 5; + vm.sleep(secondsToWait * 1000); + console.log("Waiting for batch to be executed", totalBatchesExecuted, actualBatchNumber); + console.log("Waited", loopCount * secondsToWait, "seconds"); + } + // require(totalBatchesExecuted >= actualBatchNumber, "Batch not executed"); + } + + /// we use this as forge caches the result + function getTotalBatchesExecuted(address chainAddress) public returns (uint256) { + string[] memory args = new string[](5); + args[0] = "cast"; + args[1] = "call"; + args[2] = vm.toString(chainAddress); + args[3] = "getTotalBatchesExecuted()(uint256)"; + args[4] = "--json"; + + bytes memory modifiedJsonBytes = vm.ffi(args); + string memory modifiedJson = vm.toString(modifiedJsonBytes); + string memory json2 = string(modifiedJsonBytes); + // console.log("Total batches executed", modifiedJson); + // console.log("json2", json2); + bytes memory res = vm.parseJson(json2, "$[0]"); + string memory resString = abi.decode(res, (string)); + uint256 val = vm.parseUint(resString); + return val; + } + + function getWithdrawalLog( + string memory l2RpcUrl, + bytes32 withdrawalHash, + uint256 index + ) public returns (Log memory log, uint64 l1BatchTxId) { + require(bytes(l2RpcUrl).length > 0, "L2 RPC URL not set"); + + // Get transaction receipt + TransactionReceipt memory receipt = getTransactionReceipt(l2RpcUrl, withdrawalHash); + + // Find withdrawal logs (logs from L1_MESSENGER_ADDRESS) + address L1_MESSENGER_ADDRESS = 0x0000000000000000000000000000000000008008; + bytes32 L1_MESSAGE_SENT_TOPIC = 0x3a36e47291f4201faf137fab081d92295bce2d53be2c6ca68ba82c7faa9ce241; + uint256 withdrawalLogCount = 0; + + for (uint256 i = 0; i < receipt.logs.length; i++) { + if (receipt.logs[i].addr == L1_MESSENGER_ADDRESS && receipt.logs[i].topics[0] == L1_MESSAGE_SENT_TOPIC) { + // console.log(receipt.logs[i].addr); + // console.log() + if (withdrawalLogCount == index) { + log = receipt.logs[i]; + l1BatchTxId = uint64(receipt.transactionIndex); + return (log, l1BatchTxId); + } + withdrawalLogCount++; + } + } + + console.log("Withdrawal log not found at specified index", index); + } + + function getWithdrawalL2ToL1Log( + string memory l2RpcUrl, + bytes32 withdrawalHash, + uint256 index + ) public returns (uint64 logIndex, L2ToL1Log memory log) { + require(bytes(l2RpcUrl).length > 0, "L2 RPC URL not set"); + + // Get transaction receipt + TransactionReceipt memory receipt = getTransactionReceipt(l2RpcUrl, withdrawalHash); + + // Find L2ToL1 logs from L1_MESSENGER_ADDRESS + address L1_MESSENGER_ADDRESS = 0x0000000000000000000000000000000000008008; + uint256 withdrawalLogCount = 0; + + for (uint256 i = 0; i < receipt.l2ToL1Logs.length; i++) { + // console.log("l2ToL1Logs"); + // console.log(i, receipt.l2ToL1Logs[i].logIndex); + if (receipt.l2ToL1Logs[i].sender == L1_MESSENGER_ADDRESS) { + if (withdrawalLogCount == index) { + log = receipt.l2ToL1Logs[i]; + logIndex = uint64(i); + return (logIndex, log); + } + withdrawalLogCount++; + } + } + + console.log("L2ToL1 log not found at specified index", index); + } + + function getFinalizeWithdrawalParams( + uint256 chainId, + string memory l2RpcUrl, + bytes32 withdrawalHash, + uint256 index + ) public returns (FinalizeL1DepositParams memory params) { + require(bytes(l2RpcUrl).length > 0, "L2 RPC URL not set"); + + // Get withdrawal log and L2ToL1 log + (Log memory log, uint64 l1BatchTxId) = getWithdrawalLog(l2RpcUrl, withdrawalHash, index); + (uint64 l2ToL1LogIndex, L2ToL1Log memory l2ToL1Log) = getWithdrawalL2ToL1Log(l2RpcUrl, withdrawalHash, index); + if (l2ToL1Log.key == bytes32(0)) { + return params; + } + + // Get L2ToL1 log proof + L2ToL1LogProof memory proof = getL2ToL1LogProof(l2RpcUrl, withdrawalHash, l2ToL1LogIndex); + // console.log("withdrawalHash"); + // console.logBytes32(withdrawalHash); + + // Extract sender and message from log + (address sender, bytes memory message) = getMessageFromLog(log); + + params = FinalizeL1DepositParams({ + chainId: chainId, + l2BatchNumber: log.l1BatchNumber, + l2MessageIndex: proof.id, + l2TxNumberInBatch: uint16(l2ToL1Log.txIndexInL1Batch), + message: message, + l2Sender: sender, + merkleProof: proof.proof + }); + } + + function getMessageFromLog(Log memory log) public pure returns (address sender, bytes memory message) { + // Extract sender from topic[1] (last 20 bytes) + // console.log("log.topics[1]"); + // console.log(log.topics.length); + // console.logBytes32(log.topics[0]); + sender = address(uint160(uint256(log.topics[1]))); + + // Decode message from log data + // Assuming the data contains the message directly + message = abi.decode(abi.decode(log.data, (bytes)), (bytes)); + } + + function getTransactionReceipt( + string memory l2RpcUrl, + bytes32 txHash + ) internal returns (TransactionReceipt memory receipt) { + string[] memory args = new string[](9); + args[0] = "curl"; + args[1] = "--request"; + args[2] = "POST"; + args[3] = "--url"; + args[4] = l2RpcUrl; + args[5] = "--header"; + args[6] = "Content-Type: application/json"; + args[7] = "--data"; + args[8] = string.concat( + '{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["', + vm.toString(txHash), + '"],"id":1}' + ); + + bytes memory result = vm.ffi(args); + + receipt = parseTransactionReceipt(result); + } + + function getL2ToL1LogProof( + string memory l2RpcUrl, + bytes32 txHash, + uint64 logIndex + ) internal returns (L2ToL1LogProof memory proof) { + string[] memory args = new string[](9); + args[0] = "curl"; + args[1] = "--request"; + args[2] = "POST"; + args[3] = "--url"; + args[4] = l2RpcUrl; + args[5] = "--header"; + args[6] = "Content-Type: application/json"; + args[7] = "--data"; + args[8] = string.concat( + '{"jsonrpc":"2.0","id":1,"method":"zks_getL2ToL1LogProof","params":["', + vm.toString(txHash), + '",', + vm.toString(logIndex), + "]}" + ); // todo later: add ,"proof_based_gw" for interop + // Execute RPC call + + bytes memory nullProofBytes = "0x7b226a736f6e727063223a22322e30222c226964223a312c22726573756c74223a6e756c6c7d"; + string memory nullProofString2 = '{"jsonrpc":"2.0","id":1,"result":null}'; + bytes memory result = nullProofBytes; + while ( + compareStrings(string(result), string(nullProofBytes)) || + compareStrings(string(result), string(nullProofString2)) + ) { + result = vm.ffi(args); + vm.sleep(4000); + } + + proof = parseL2ToL1LogProof(result); + } + + function parseTransactionReceipt(bytes memory jsonResponse) internal returns (TransactionReceipt memory receipt) { + // Parse the JSON response using stdJson + // This is a simplified implementation - you may need to enhance the parsing + string memory responseStr = string(jsonResponse); + + string memory modifiedJson = callParseAltLog(responseStr, "parse-transaction-receipt.sh"); + string memory altTransactionReceiptJson = callParseAltLog(responseStr, "parse-alt-transaction-receipt.sh"); + // console.log(responseStr); + // console.log(altTransactionReceiptJson); + bytes memory resultBytes = vm.parseJson(altTransactionReceiptJson, "$.result"); + AltTransactionReceipt memory result = abi.decode(resultBytes, (AltTransactionReceipt)); + + // console.log("successful result"); + // console.log("Block Number:", result.blockNumber); + // console.log("Block Hash:", vm.toString(result.blockHash)); + // // console.log("Contract Address:", result.contractAddress); + // console.log("Cumulative Gas Used:", result.cumulativeGasUsed); + // console.log("Effective Gas Price:", result.effectiveGasPrice); + // console.log("From:", result.from); + // console.log("Gas Used:", result.gasUsed); + // console.log("L1 Batch Number:", result.l1BatchNumber); + // console.log("L1 Batch Tx Index:", result.l1BatchTxIndex); + // console.log("Status:", result.status); + // console.log("To:", result.to); + // console.log("Transaction Hash:", vm.toString(result.transactionHash)); + // console.log("Transaction Index:", result.transactionIndex); + // console.log("Transaction Type:", result.txType); + + AltLog[] memory altLogs; + { + string memory altLogsJson = callParseAltLog(responseStr, "parse-alt-logs.sh"); + // console.log(altLogsJson); + + bytes memory logBytes = vm.parseJson(altLogsJson, "$.logs"); + altLogs = abi.decode(logBytes, (AltLog[])); + // console.log("altLogs"); + // console.log("length", altLogs.length); + // console.log("addr", altLogs[0].addr); + // console.log("blockHash", vm.toString(altLogs[0].blockHash)); + // console.log("blockNumber", altLogs[0].blockNumber); + // console.log("blockTimestamp", altLogs[0].blockTimestamp); + // console.log("logIndex", altLogs[0].logIndex); + // console.log("l1BatchNumber", altLogs[0].l1BatchNumber); + // console.log("transactionHash", vm.toString(altLogs[0].transactionHash)); + // console.log("transactionIndex", altLogs[0].transactionIndex); + // console.log("transactionLogIndex", altLogs[0].transactionLogIndex); + } + + bytes[] memory altLogsData = new bytes[](altLogs.length); + bytes32[][] memory altLogsTopics = new bytes32[][](altLogs.length); + { + for (uint256 i = 0; i < altLogs.length; i++) { + string memory altLogsDataJson = callParseAltLog(responseStr, "parse-alt-logs-data.sh", i); + string memory altLogsTopicsJson = callParseAltLog(responseStr, "parse-alt-logs-topics.sh", i); + // console.log(altLogsDataJson); + // console.log(altLogsTopicsJson); + bytes memory altLogsDataBytes = vm.parseJson(altLogsDataJson, "$.data"); + // console.logBytes(altLogsDataBytes); + bytes memory altLogsTopicsBytes = vm.parseJson(altLogsTopicsJson, "$.topics"); + altLogsData[i] = altLogsDataBytes; + altLogsTopics[i] = abi.decode(altLogsTopicsBytes, (bytes32[])); + } + } + + // console.log("successful logs"); + // console.log(altLogs.length); + // console.log(altLogs[0].addr); + // console.log(vm.toString(altLogs[0].blockHash)); + // console.log(vm.toString(altLogs[0].blockNumber)); + // console.log(vm.toString(altLogs[0].blockTimestamp)); + // console.log(vm.toString(altLogs[0].logIndex)); + // console.log(vm.toString(altLogs[0].l1BatchNumber)); + // console.log(vm.toString(altLogs[0].transactionHash)); + // console.log(vm.toString(altLogs[0].transactionIndex)); + + string memory altL2ToL1LogsJson = callParseAltLog(responseStr, "parse-alt-l2-to-l1-logs.sh"); + // console.log(altL2ToL1LogsJson); + + bytes memory l2ToL1LogsBytes = vm.parseJson(altL2ToL1LogsJson, "$.l2ToL1Logs"); + AltL2ToL1Log[] memory l2ToL1Logs = abi.decode(l2ToL1LogsBytes, (AltL2ToL1Log[])); + + // console.log("l2ToL1Logs"); + // console.log(l2ToL1Logs.length); + // console.log(l2ToL1Logs[0].logIndex); + // console.log(l2ToL1Logs[0].txIndexInL1Batch); + // for (uint256 i = 0; i < l2ToL1Logs.length; i++) { + // console.log("L2ToL1Log", i); + // console.log(" blockNumber:", l2ToL1Logs[i].blockNumber); + // console.log(" blockHash:", vm.toString(l2ToL1Logs[i].blockHash)); + // // console.log(" isService:", l2ToL1Logs[i].isService); + // console.log(" key:", vm.toString(l2ToL1Logs[i].key)); + // console.log(" logIndex:", l2ToL1Logs[i].logIndex); + // console.log(" l1BatchNumber:", l2ToL1Logs[i].l1BatchNumber); + // console.log(" sender:", vm.toString(l2ToL1Logs[i].sender)); + // console.log(" shardId:", l2ToL1Logs[i].shardId); + // console.log(" transactionHash:", vm.toString(l2ToL1Logs[i].transactionHash)); + // console.log(" transactionIndex:", l2ToL1Logs[i].transactionIndex); + // console.log(" transactionLogIndex:", l2ToL1Logs[i].transactionLogIndex); + // console.log(" txIndexInL1Batch:", l2ToL1Logs[i].txIndexInL1Batch); + // console.log(" value:", vm.toString(l2ToL1Logs[i].value)); + // } + + bool status; + if (result.status == 1) { + status = true; + } else { + status = false; + } + + Log[] memory logs = new Log[](altLogs.length); + for (uint256 i = 0; i < altLogs.length; i++) { + bool removed; + string memory trueString = "true"; + logs[i] = Log({ + addr: address(uint160(altLogs[i].addr)), + // addr: address(0), + blockHash: altLogs[i].blockHash, + blockNumber: uint64(altLogs[i].blockNumber), + blockTimestamp: uint64(altLogs[i].blockTimestamp), + data: altLogsData[i], + logIndex: uint64(altLogs[i].logIndex), + // logType: altLogs[i].logType, + l1BatchNumber: uint64(altLogs[i].l1BatchNumber), + // removed: compareStrings(altLogs[i].removed, trueString) ? true : false, + // topics: altLogs[i].topics, + topics: altLogsTopics[i], + transactionIndex: uint64(altLogs[i].transactionIndex), + transactionHash: altLogs[i].transactionHash, + transactionLogIndex: uint64(altLogs[i].transactionLogIndex) + }); + } + + L2ToL1Log[] memory realL2ToL1Logs = new L2ToL1Log[](l2ToL1Logs.length); + + for (uint256 i = 0; i < l2ToL1Logs.length; i++) { + realL2ToL1Logs[i] = L2ToL1Log({ + blockNumber: uint64(l2ToL1Logs[i].blockNumber), + blockHash: l2ToL1Logs[i].blockHash, + // isService: l2ToL1Logs[i].isService == 1 ? true : false, + key: l2ToL1Logs[i].key, + logIndex: uint64(l2ToL1Logs[i].logIndex), + l1BatchNumber: uint64(l2ToL1Logs[i].l1BatchNumber), + sender: l2ToL1Logs[i].sender, + shardId: uint64(l2ToL1Logs[i].shardId), + transactionHash: l2ToL1Logs[i].transactionHash, + transactionIndex: uint64(l2ToL1Logs[i].transactionIndex), + transactionLogIndex: uint64(l2ToL1Logs[i].transactionLogIndex), + txIndexInL1Batch: uint64(l2ToL1Logs[i].txIndexInL1Batch), + value: l2ToL1Logs[i].value + }); + } + + receipt = TransactionReceipt({ + blockNumber: uint64(result.blockNumber), + blockHash: result.blockHash, + // contractAddress: result.contractAddress, + cumulativeGasUsed: uint64(result.cumulativeGasUsed), + gasUsed: uint64(result.gasUsed), + logs: logs, + l2ToL1Logs: realL2ToL1Logs, + status: status, + transactionIndex: uint64(result.transactionIndex), + transactionHash: result.transactionHash + }); + } + + // todo import from Utils + function compareStrings(string memory a, string memory b) internal pure returns (bool) { + return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b)); + } + + function parseL2ToL1LogProof(bytes memory jsonResponse) internal returns (L2ToL1LogProof memory proof) { + string memory json = string(jsonResponse); + + bytes memory proofIdBytes = vm.parseJson(json, "$.result.id"); + proof.id = abi.decode(proofIdBytes, (uint64)); + + string memory proofJson = callParseAltLog(json, "parse-proof.sh"); + bytes memory lengthBytes = vm.parseJson(proofJson, "$.length"); + uint256 length = abi.decode(lengthBytes, (uint256)); + proof.proof = new bytes32[](length); + for (uint256 i = 0; i < length; i++) { + bytes memory proofBytes = vm.parseJson(proofJson, string.concat("$.proof[", vm.toString(i), "]")); + proof.proof[i] = bytes32(proofBytes); + // proof.proof = abi.decode(proofBytes, (bytes32[])); + } + } + + function getBashScriptPath(string memory scriptName) internal returns (string memory scriptPath) { + scriptPath = string.concat("./deploy-scripts/provider/bash-scripts/", scriptName); + } + + function callParseAltLog( + string memory jsonStr, + string memory scriptName + ) internal returns (string memory modifiedJson) { + string memory scriptPath = getBashScriptPath(scriptName); + string[] memory args = new string[](3); + args[0] = "sh"; + args[1] = scriptPath; + args[2] = jsonStr; + + bytes memory modifiedJsonBytes = vm.ffi(args); + modifiedJson = string(modifiedJsonBytes); + } + + function callParseAltLog( + string memory jsonStr, + string memory scriptName, + uint256 index + ) internal returns (string memory modifiedJson) { + string memory scriptPath = getBashScriptPath(scriptName); + string[] memory args = new string[](4); + args[0] = "sh"; + args[1] = scriptPath; + args[2] = jsonStr; + args[3] = vm.toString(index); + + bytes memory modifiedJsonBytes = vm.ffi(args); + modifiedJson = string(modifiedJsonBytes); + } +} diff --git a/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-l2-to-l1-logs.sh b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-l2-to-l1-logs.sh new file mode 100644 index 0000000000..822293e258 --- /dev/null +++ b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-l2-to-l1-logs.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Function to modify JSON string by changing "address" to "addr" and returning logs array +modify_json_address() { + local json_string="$1" + + # Use jq to extract logs array, then use sed to replace "address" with "addr" and "type" with "txType" + # Extract logs array and apply the field replacements + echo "$json_string" | jq '.result.l2ToL1Logs | map(del(.logType, .removed, .topics, .data, .isService) | to_entries | sort_by(.key) | from_entries)' | sed -e 's/"address":/"addr":/g' -e 's/"type":/"txType":/g' | jq 'walk(if type == "string" and test("^0x[0-9a-fA-F]+$") then if (length < 66) then "0x" + ("0" * (64 - (length - 2))) + .[2:] else . end else . end) | {l2ToL1Logs: .}' +# if .key == "logIndex" then "l1BatchNumber" elif .key == "l1BatchNumber" then "logIndex" else .key end +} + +# Check if JSON string is provided as argument +if [ $# -eq 0 ]; then + echo "Usage: $0 " + echo "Example: $0 '{\"address\": \"0x123...\", \"value\": 100}'" + exit 1 +fi + +# Get the JSON string from the first argument +json_string="$1" + +# Call the function and output the result +modify_json_address "$json_string" diff --git a/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-logs-data.sh b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-logs-data.sh new file mode 100755 index 0000000000..1832b314d4 --- /dev/null +++ b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-logs-data.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Function to modify JSON string by changing "address" to "addr" and returning logs array +modify_json_address() { + local json_string="$1" + local index="$2" + + # Use jq to extract logs array, then use sed to replace "address" with "addr" and "type" with "txType" + # Extract logs array and apply the field replacements + echo "$json_string" | jq '.result.logs | map(.data)' | jq ".[$index]" | sed -e 's/"address":/"addr":/g' -e 's/"type":/"txType":/g' | jq 'walk(if type == "string" and test("^0x[0-9a-fA-F]+$") then if (length < 66) then "0x" + ("0" * (64 - (length - 2))) + .[2:] else . end else . end) | {data: .}' +} + +# Check if JSON string is provided as argument +if [ $# -eq 0 ]; then + echo "Usage: $0 " + echo "Example: $0 '{\"address\": \"0x123...\", \"value\": 100}'" + exit 1 +fi + +# Get the JSON string from the first argument +json_string="$1" +index="$2" + + +# Call the function and output the result +modify_json_address "$json_string" "$index" + diff --git a/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-logs-topics.sh b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-logs-topics.sh new file mode 100755 index 0000000000..6f687cfa59 --- /dev/null +++ b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-logs-topics.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Function to modify JSON string by changing "address" to "addr" and returning logs array +modify_json_address() { + local json_string="$1" + local index="$2" + + # Use jq to extract logs array, then use sed to replace "address" with "addr" and "type" with "txType" + # Extract logs array and apply the field replacements + echo "$json_string" | jq '.result.logs | map(.topics)' | jq ".[$index]" | sed -e 's/"address":/"addr":/g' -e 's/"type":/"txType":/g' | jq 'walk(if type == "string" and test("^0x[0-9a-fA-F]+$") then if (length < 66) then "0x" + ("0" * (64 - (length - 2))) + .[2:] else . end else . end) | {topics: .}' +} + +# Check if JSON string is provided as argument +if [ $# -eq 0 ]; then + echo "Usage: $0 " + echo "Example: $0 '{\"address\": \"0x123...\", \"value\": 100}'" + exit 1 +fi + +# Get the JSON string from the first argument +json_string="$1" +index="$2" +# Call the function and output the result +modify_json_address "$json_string" "$index" diff --git a/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-logs.sh b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-logs.sh new file mode 100755 index 0000000000..2ec8a86fd7 --- /dev/null +++ b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-logs.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Function to modify JSON string by changing "address" to "addr" and returning logs array +modify_json_address() { + local json_string="$1" + + # Use jq to extract logs array, then use sed to replace "address" with "addr" and "type" with "txType" + # Extract logs array and apply the field replacements + echo "$json_string" | jq '.result.logs | map(del(.logType, .removed, .topics, .data) | to_entries | sort_by(.key) | from_entries)' | sed -e 's/"address":/"addr":/g' -e 's/"type":/"txType":/g' | jq 'walk(if type == "string" and test("^0x[0-9a-fA-F]+$") then if (length < 66) then "0x" + ("0" * (64 - (length - 2))) + .[2:] else . end else . end) | {logs: .}' +# if .key == "logIndex" then "l1BatchNumber" elif .key == "l1BatchNumber" then "logIndex" else .key end +} + +# Check if JSON string is provided as argument +if [ $# -eq 0 ]; then + echo "Usage: $0 " + echo "Example: $0 '{\"address\": \"0x123...\", \"value\": 100}'" + exit 1 +fi + +# Get the JSON string from the first argument +json_string="$1" + +# Call the function and output the result +modify_json_address "$json_string" diff --git a/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-transaction-receipt.sh b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-transaction-receipt.sh new file mode 100755 index 0000000000..c88db4a1c0 --- /dev/null +++ b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-alt-transaction-receipt.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Function to modify JSON string by changing "address" to "addr" and removing logs fields +modify_json_address() { + local json_string="$1" + + # Use jq to remove logs and l2ToL1Logs fields, then use sed to replace "address" with "addr" and "type" with "txType" + # First remove the unwanted fields using jq, then apply the field replacements + echo "$json_string" | jq 'del(.result.logs, .result.l2ToL1Logs, .result.logsBloom, .result.contractAddress) | .result |= (to_entries | sort_by(.key) | from_entries)' | sed -e 's/"address":/"addr":/g' -e 's/"type":/"txType":/g' | jq 'walk(if type == "string" and test("^0x[0-9a-fA-F]+$") then if (length < 66) then "0x" + ("0" * (64 - (length - 2))) + .[2:] else . end else . end)' +} + +# Check if JSON string is provided as argument +if [ $# -eq 0 ]; then + echo "Usage: $0 " + echo "Example: $0 '{\"address\": \"0x123...\", \"value\": 100}'" + exit 1 +fi + +# Get the JSON string from the first argument +json_string="$1" + +# Call the function and output the result +modify_json_address "$json_string" diff --git a/l1-contracts/deploy-scripts/provider/bash-scripts/parse-broadcast.sh b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-broadcast.sh new file mode 100755 index 0000000000..15b26ad4ea --- /dev/null +++ b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-broadcast.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# Check if a file path is provided +if [ $# -eq 0 ]; then + echo "Usage: $0 " + exit 1 +fi + +broadcast_file="$1" + +# Check if the file exists +if [ ! -f "$broadcast_file" ]; then + echo "Error: File '$broadcast_file' not found" + exit 1 +fi + +# Generate output filename by replacing .json with .parsed.json +output_file="${broadcast_file%.json}.parsed.json" + +# Use jq to transform the JSON +# Replace "function" with "functionKey", "returns" with "returnValues", remove paymasterData and contractName +jq ' + .transactions |= map( + if has("function") then + . + {"functionKey": .function} | del(.function) + else . end + ) | + .transactions |= map( + .transaction.zksync |= del(.paymasterData) + ) | + .transactions |= map( + del(.contractName) + ) | + if has("returns") then + . + {"returnValues": .returns} | del(.returns) + else . end +' "$broadcast_file" > "$output_file" + +# Check if jq transformation was successful +if [ $? -eq 0 ]; then + echo "Successfully created $output_file" + echo "Changes made:" + echo " - 'function' -> 'functionKey' in transactions" + echo " - 'returns' -> 'returnValues' at root level" + echo " - Removed 'paymasterData' from transactions.transaction.zksync" + echo " - Removed 'contractName' from transactions" +else + echo "Error: Failed to process JSON file" + rm -f "$output_file" + exit 1 +fi diff --git a/l1-contracts/deploy-scripts/provider/bash-scripts/parse-proof.sh b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-proof.sh new file mode 100644 index 0000000000..7495128a03 --- /dev/null +++ b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-proof.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Function to modify JSON string by changing "address" to "addr" and returning logs array +modify_json_address() { + local json_string="$1" + local index="$2" + + # Use jq to extract logs array, then use sed to replace "address" with "addr" and "type" with "txType" + # Extract logs array and apply the field replacements + echo "$json_string" | jq '.result.proof' | sed -e 's/"address":/"addr":/g' -e 's/"type":/"txType":/g' | jq 'walk(if type == "string" and test("^0x[0-9a-fA-F]+$") then if (length < 66) then "0x" + ("0" * (64 - (length - 2))) + .[2:] else . end else . end) | {proof: ., length: (. | length)}' +} + +# Check if JSON string is provided as argument +if [ $# -eq 0 ]; then + echo "Usage: $0 " + echo "Example: $0 '{\"address\": \"0x123...\", \"value\": 100}'" + exit 1 +fi + +# Get the JSON string from the first argument +json_string="$1" +index="$2" +# Call the function and output the result +modify_json_address "$json_string" "$index" \ No newline at end of file diff --git a/l1-contracts/deploy-scripts/provider/bash-scripts/parse-transaction-receipt.sh b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-transaction-receipt.sh new file mode 100755 index 0000000000..0306ea6718 --- /dev/null +++ b/l1-contracts/deploy-scripts/provider/bash-scripts/parse-transaction-receipt.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Function to modify JSON string by changing "address" to "addr" +modify_json_address() { + local json_string="$1" + + # Use sed to replace "address" with "addr" in the JSON string + # The -e flag allows multiple expressions + # We need to be careful to only replace "address" when it's a key, not a value + echo "$json_string" | sed -e 's/"address":/"addr":/g' +} + +# Check if JSON string is provided as argument +if [ $# -eq 0 ]; then + echo "Usage: $0 " + echo "Example: $0 '{\"address\": \"0x123...\", \"value\": 100}'" + exit 1 +fi + +# Get the JSON string from the first argument +json_string="$1" + +# Call the function and output the result +modify_json_address "$json_string" diff --git a/l1-contracts/deploy-scripts/upgrade/ChainUpgrade_v30.s.sol b/l1-contracts/deploy-scripts/upgrade/ChainUpgrade_v30.s.sol new file mode 100644 index 0000000000..2de79b4a64 --- /dev/null +++ b/l1-contracts/deploy-scripts/upgrade/ChainUpgrade_v30.s.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +// solhint-disable no-console, gas-custom-errors + +import {console2 as console} from "forge-std/Script.sol"; +import {stdToml} from "forge-std/StdToml.sol"; + +import {Bridgehub} from "contracts/bridgehub/Bridgehub.sol"; + +import {DefaultChainUpgrade} from "./DefaultChainUpgrade.s.sol"; + +/// @notice For V30 we need to migrate all token balances on L1 NTV to AssetTracker, and from L1AssetTracker to GW AssetTracker. +contract ChainUpgrade_v30 is DefaultChainUpgrade { + using stdToml for string; + + function run() public { + super.run(); + migrateTokenBalanceFromNTV(addresses.bridges.bridgehub, block.chainid); // todo fix inputs. + } + + function migrateTokenBalanceFromNTV(address _bridgehub, uint256 _chainId) public { + address l1AssetTrackerAddress = IBridgehubBase(_bridgehub).assetRouter().nativeTokenVault().l1AssetTracker(); + IL1AssetTracker l1AssetTracker = IL1AssetTracker(l1AssetTrackerAddress); + // For each token in the NTV bridgedTokens list, migrate the token balance to the L1AssetTracker + address ntvAddress = IBridgehubBase(_bridgehub).assetRouter().nativeTokenVault(); + INativeTokenVault ntv = INativeTokenVaultBase(ntvAddress); + + uint256 bridgedTokensCount = ntv.bridgedTokensCount(); + for (uint256 i = 0; i < bridgedTokensCount; ++i) { + bytes32 assetId = ntv.bridgedTokens(i); + l1AssetTracker.migrateTokenBalanceFromNTVV30(_chainId, assetId); + } + } + + /// we have to migrate the token balance to GW if the chain is on GW. +} diff --git a/l1-contracts/deploy-scripts/upgrade/DefaultChainUpgrade.s.sol b/l1-contracts/deploy-scripts/upgrade/DefaultChainUpgrade.s.sol index 91b6309553..e7e05d4205 100644 --- a/l1-contracts/deploy-scripts/upgrade/DefaultChainUpgrade.s.sol +++ b/l1-contracts/deploy-scripts/upgrade/DefaultChainUpgrade.s.sol @@ -12,7 +12,7 @@ import {IAdmin} from "contracts/state-transition/chain-interfaces/IAdmin.sol"; import {IChainAdminOwnable} from "contracts/governance/IChainAdminOwnable.sol"; -import {Bridgehub} from "contracts/bridgehub/Bridgehub.sol"; +import {L1Bridgehub} from "contracts/bridgehub/L1Bridgehub.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {Ownable} from "@openzeppelin/contracts-v4/access/Ownable.sol"; @@ -96,6 +96,6 @@ contract DefaultChainUpgrade is Script { toml = vm.readFile(ecosystemInputPath); config.bridgehubProxyAddress = toml.readAddress("$.contracts.bridgehub_proxy_address"); - config.chainDiamondProxyAddress = Bridgehub(config.bridgehubProxyAddress).getZKChain(config.chainChainId); + config.chainDiamondProxyAddress = L1Bridgehub(config.bridgehubProxyAddress).getZKChain(config.chainChainId); } } diff --git a/l1-contracts/deploy-scripts/upgrade/DefaultEcosystemUpgrade.s.sol b/l1-contracts/deploy-scripts/upgrade/DefaultEcosystemUpgrade.s.sol index 89bd2ab2ce..96eff34b66 100644 --- a/l1-contracts/deploy-scripts/upgrade/DefaultEcosystemUpgrade.s.sol +++ b/l1-contracts/deploy-scripts/upgrade/DefaultEcosystemUpgrade.s.sol @@ -12,25 +12,17 @@ import {SafeCast} from "@openzeppelin/contracts-v4/utils/math/SafeCast.sol"; import {ITransparentUpgradeableProxy, TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol"; -import {StateTransitionDeployedAddresses, Utils} from "../Utils.sol"; +import {Utils} from "../Utils.sol"; +import {StateTransitionDeployedAddresses} from "../Types.sol"; import {L2_BRIDGEHUB_ADDR, L2_DEPLOYER_SYSTEM_CONTRACT_ADDR, L2_FORCE_DEPLOYER_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; -import {IChainAssetHandler} from "contracts/bridgehub/IChainAssetHandler.sol"; - -import {EraVerifierFflonk} from "contracts/state-transition/verifiers/EraVerifierFflonk.sol"; -import {EraVerifierPlonk} from "contracts/state-transition/verifiers/EraVerifierPlonk.sol"; -import {ZKsyncOSVerifierFflonk} from "contracts/state-transition/verifiers/ZKsyncOSVerifierFflonk.sol"; -import {ZKsyncOSVerifierPlonk} from "contracts/state-transition/verifiers/ZKsyncOSVerifierPlonk.sol"; import {VerifierParams} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; import {DefaultUpgrade} from "contracts/upgrades/DefaultUpgrade.sol"; import {L1GenesisUpgrade} from "contracts/upgrades/L1GenesisUpgrade.sol"; -import {GatewayUpgrade} from "contracts/upgrades/GatewayUpgrade.sol"; import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; import {L1Bridgehub} from "contracts/bridgehub/L1Bridgehub.sol"; import {L1MessageRoot} from "contracts/bridgehub/L1MessageRoot.sol"; -import {CTMDeploymentTracker} from "contracts/bridgehub/CTMDeploymentTracker.sol"; -import {L1NativeTokenVault} from "contracts/bridge/ntv/L1NativeTokenVault.sol"; import {IAdmin} from "contracts/state-transition/chain-interfaces/IAdmin.sol"; import {ExecutorFacet} from "contracts/state-transition/chain-deps/facets/Executor.sol"; import {AdminFacet} from "contracts/state-transition/chain-deps/facets/Admin.sol"; @@ -38,19 +30,18 @@ import {MailboxFacet} from "contracts/state-transition/chain-deps/facets/Mailbox import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; import {DiamondInit} from "contracts/state-transition/chain-deps/DiamondInit.sol"; import {ChainCreationParams, IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; +import {ChainTypeManagerBase} from "contracts/state-transition/ChainTypeManagerBase.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {L1AssetRouter} from "contracts/bridge/asset-router/L1AssetRouter.sol"; -import {L1ERC20Bridge} from "contracts/bridge/L1ERC20Bridge.sol"; import {L1Nullifier} from "contracts/bridge/L1Nullifier.sol"; import {DiamondProxy} from "contracts/state-transition/chain-deps/DiamondProxy.sol"; -import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; +import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-deps/ZKChainStorage.sol"; +import {Governance} from "contracts/governance/Governance.sol"; import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol"; - -import {SYSTEM_UPGRADE_L2_TX_TYPE, ZKSYNC_OS_SYSTEM_UPGRADE_L2_TX_TYPE} from "contracts/common/Config.sol"; +import {SYSTEM_UPGRADE_L2_TX_TYPE} from "contracts/common/Config.sol"; import {IL2ContractDeployer} from "contracts/common/interfaces/IL2ContractDeployer.sol"; import {L2ContractHelper} from "contracts/common/l2-helpers/L2ContractHelper.sol"; import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol"; - import {ContractsBytecodesLib} from "../ContractsBytecodesLib.sol"; import {Call} from "contracts/governance/Common.sol"; import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; @@ -58,24 +49,29 @@ import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol import {ProposedUpgrade} from "contracts/upgrades/BaseZkSyncUpgrade.sol"; import {UpgradeStageValidator} from "contracts/upgrades/UpgradeStageValidator.sol"; import {SemVer} from "contracts/common/libraries/SemVer.sol"; +import {ZKSYNC_OS_SYSTEM_UPGRADE_L2_TX_TYPE} from "contracts/common/Config.sol"; +import {DeployCTMUtils, DeployedAddresses} from "../DeployCTMUtils.s.sol"; import {L2CanonicalTransaction} from "contracts/common/Messaging.sol"; - import {TransitionaryOwner} from "contracts/governance/TransitionaryOwner.sol"; import {SystemContractsProcessing} from "./SystemContractsProcessing.s.sol"; import {BytecodePublisher} from "./BytecodePublisher.s.sol"; import {BytecodesSupplier} from "contracts/upgrades/BytecodesSupplier.sol"; import {GovernanceUpgradeTimer} from "contracts/upgrades/GovernanceUpgradeTimer.sol"; +import {L2DACommitmentScheme} from "contracts/common/Config.sol"; +import {L1Bridgehub} from "contracts/bridgehub/L1Bridgehub.sol"; +import {IChainAssetHandler} from "contracts/bridgehub/IChainAssetHandler.sol"; import {RollupDAManager} from "contracts/state-transition/data-availability/RollupDAManager.sol"; +import {BridgehubDeployedAddresses, L1NativeTokenVaultAddresses, BridgesDeployedAddresses} from "../DeployL1CoreUtils.s.sol"; import {FixedForceDeploymentsData} from "contracts/state-transition/l2-deps/IL2GenesisUpgrade.sol"; -import {DeployCTMScript} from "../DeployCTM.s.sol"; +import {AddressIntrospector} from "../AddressIntrospector.sol"; /// @notice Script used for default upgrade flow /// @dev For more complex upgrades, this script can be inherited and its functionality overridden if needed. -contract DefaultEcosystemUpgrade is Script, DeployCTMScript { +contract DefaultEcosystemUpgrade is Script, DeployCTMUtils { using stdToml for string; /** @@ -90,12 +86,12 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { // solhint-disable-next-line gas-struct-packing struct UpgradeDeployedAddresses { ExpectedL2Addresses expectedL2Addresses; - address gatewayUpgrade; address transitionaryOwner; address upgradeTimer; address bytecodesSupplier; address l2WrappedBaseTokenStore; address upgradeStageValidator; + address nativeTokenVaultImplementation; } struct ExpectedL2Addresses { @@ -151,6 +147,12 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { Gateway internal gatewayConfig; NewlyGeneratedData internal newlyGeneratedData; UpgradeDeployedAddresses internal upgradeAddresses; + BridgehubDeployedAddresses internal bridgehubAddresses; + BridgesDeployedAddresses internal bridges; + AddressIntrospector.CTMAddresses internal discoveredCTM; + AddressIntrospector.ZkChainAddresses internal discoveredEraZkChain; + AddressIntrospector.NonDisoverable internal nonDisoverable; + L1Bridgehub internal bridgehub; uint256[] internal factoryDepsHashes; mapping(bytes32 => bool) internal isHashInFactoryDeps; @@ -185,45 +187,7 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { } /// @notice Deploy everything that should be deployed - function deployNewEcosystemContractsL1() public virtual { - require(upgradeConfig.initialized, "Not initialized"); - - instantiateCreate2Factory(); - - deployVerifiers(); - deployUpgradeStageValidator(); - - // Note, that this is the upgrade that will be used, despite the naming of the variable here. - // To use the custom upgrade simply override the `deployUsedUpgradeContract` function. - (addresses.stateTransition.defaultUpgrade) = deployUsedUpgradeContract(); - (addresses.stateTransition.genesisUpgrade) = deploySimpleContract("L1GenesisUpgrade", false); - - addresses.bridgehub.bridgehubImplementation = deploySimpleContract("L1Bridgehub", false); - - addresses.bridges.l1NullifierImplementation = deploySimpleContract("L1Nullifier", false); - addresses.bridges.l1AssetRouterImplementation = deploySimpleContract("L1AssetRouter", false); - addresses.vaults.l1NativeTokenVaultImplementation = deploySimpleContract("L1NativeTokenVault", false); - addresses.bridges.erc20BridgeImplementation = deploySimpleContract("L1ERC20Bridge", false); - addresses.bridges.bridgedStandardERC20Implementation = deploySimpleContract("BridgedStandardERC20", false); - - upgradeAddresses.upgradeTimer = deploySimpleContract("GovernanceUpgradeTimer", false); - addresses.bridgehub.messageRootImplementation = deploySimpleContract("L1MessageRoot", false); - addresses.bridgehub.ctmDeploymentTrackerImplementation = deploySimpleContract("CTMDeploymentTracker", false); - - deployStateTransitionDiamondFacets(); - - string memory ctmContractName = config.isZKsyncOS ? "ZKsyncOSChainTypeManager" : "EraChainTypeManager"; - addresses.stateTransition.chainTypeManagerImplementation = deploySimpleContract(ctmContractName, false); - - addresses.stateTransition.serverNotifierImplementation = deploySimpleContract("ServerNotifier", false); - - /// for forge verification. - deploySimpleContract("DiamondProxy", false); - - deployUpgradeSpecificContractsL1(); - - upgradeConfig.ecosystemContractsDeployed = true; - } + function deployNewEcosystemContractsL1() public virtual {} function deployUpgradeSpecificContractsL1() internal virtual { // Empty by default. @@ -246,8 +210,8 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { newConfig.priorityTxsL2GasLimit, new bytes[](0), gatewayConfig.chainId, - addresses.bridgehub.bridgehubProxy, - addresses.bridges.l1AssetRouterProxy + discoveredBridgehub.bridgehubProxy, + discoveredBridgehub.assetRouter ); notifyAboutDeployment(contractAddress, contractName, creationCalldata, contractName, true); } @@ -263,8 +227,8 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { newConfig.priorityTxsL2GasLimit, new bytes[](0), gatewayConfig.chainId, - addresses.bridgehub.bridgehubProxy, - addresses.bridges.l1AssetRouterProxy + discoveredBridgehub.bridgehubProxy, + discoveredBridgehub.assetRouter ); notifyAboutDeployment(implementationAddress, contractName, creationCalldata, contractName, true); @@ -280,8 +244,8 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { newConfig.priorityTxsL2GasLimit, new bytes[](0), gatewayConfig.chainId, - addresses.bridgehub.bridgehubProxy, - addresses.bridges.l1AssetRouterProxy + discoveredBridgehub.bridgehubProxy, + discoveredBridgehub.assetRouter ); notifyAboutDeployment( proxyAddress, @@ -312,7 +276,7 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { } /// @notice E2e upgrade generation - function run() public virtual override { + function run() public virtual { initialize(vm.envString("UPGRADE_ECOSYSTEM_INPUT"), vm.envString("UPGRADE_ECOSYSTEM_OUTPUT")); prepareEcosystemUpgrade(); @@ -326,11 +290,13 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { return config.ownerAddress; } + function getDiscoveredBridgehub() public view returns (AddressIntrospector.BridgehubAddresses memory) { + return discoveredBridgehub; + } + /// @notice Get facet cuts that should be removed function getFacetCutsForDeletion() internal virtual returns (Diamond.FacetCut[] memory facetCuts) { - address diamondProxy = IChainTypeManager(addresses.stateTransition.chainTypeManagerProxy).getHyperchain( - config.eraChainId - ); + address diamondProxy = discoveredEraZkChain.zkChainProxy; IZKChain.Facet[] memory facets = IZKChain(diamondProxy).facets(); // Freezability does not matter when deleting, so we just put false everywhere @@ -439,7 +405,7 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { } function getNewProtocolVersion() public virtual returns (uint256) { - return config.contracts.latestProtocolVersion; + return config.contracts.chainCreationParams.latestProtocolVersion; } function getProtocolUpgradeNonce() public virtual returns (uint256) { @@ -524,9 +490,9 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { proposedUpgrade = ProposedUpgrade({ l2ProtocolUpgradeTx: _composeUpgradeTx(forceDeployments), - bootloaderHash: config.contracts.bootloaderHash, - defaultAccountHash: config.contracts.defaultAAHash, - evmEmulatorHash: config.contracts.evmEmulatorHash, + bootloaderHash: config.contracts.chainCreationParams.bootloaderHash, + defaultAccountHash: config.contracts.chainCreationParams.defaultAAHash, + evmEmulatorHash: config.contracts.chainCreationParams.evmEmulatorHash, verifier: stateTransition.verifier, verifierParams: verifierParams, l1ContractsUpgradeCalldata: new bytes(0), @@ -574,34 +540,95 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { } function initializeConfig(string memory newConfigPath) internal virtual override { - super.initializeConfig(newConfigPath); string memory toml = vm.readFile(newConfigPath); - addresses.stateTransition.bytecodesSupplier = toml.readAddress("$.contracts.l1_bytecodes_supplier_addr"); + bytes32 create2FactorySalt = toml.readBytes32("$.contracts.create2_factory_salt"); + address create2FactoryAddr; + if (vm.keyExistsToml(toml, "$.contracts.create2_factory_addr")) { + create2FactoryAddr = toml.readAddress("$.contracts.create2_factory_addr"); + } + _initCreate2FactoryParams(create2FactoryAddr, create2FactorySalt); + + config.eraChainId = toml.readUint("$.era_chain_id"); + nonDisoverable.bytecodesSupplier = toml.readAddress("$.contracts.l1_bytecodes_supplier_addr"); + nonDisoverable.rollupDAManager = toml.readAddress("$.contracts.rollup_da_manager"); + bridgehub = L1Bridgehub(toml.readAddress("$.contracts.bridgehub_proxy_address")); + if (toml.keyExists("$.is_zk_sync_os")) { + config.isZKsyncOS = toml.readBool("$.is_zk_sync_os"); + } + setAddressesBasedOnBridgehub(); - addresses.bridgehub.bridgehubProxy = toml.readAddress("$.contracts.bridgehub_proxy_address"); + config.l1ChainId = block.chainid; + config.deployerAddress = msg.sender; + config.ownerAddress = discoveredBridgehub.governance; - setAddressesBasedOnBridgehub(); + (bool ok, bytes memory data) = discoveredEraZkChain.verifier.staticcall( + abi.encodeWithSignature("isTestnetVerifier()") + ); + if (ok) { + config.testnetVerifier = abi.decode(data, (bool)); + } + + config.contracts.governanceSecurityCouncilAddress = Governance(payable(discoveredBridgehub.governance)) + .securityCouncil(); + config.contracts.governanceMinDelay = Governance(payable(discoveredBridgehub.governance)).minDelay(); + config.contracts.maxNumberOfChains = bridgehub.MAX_NUMBER_OF_ZK_CHAINS(); - addresses.transparentProxyAdmin = address( - uint160(uint256(vm.load(addresses.bridgehub.bridgehubProxy, ADMIN_SLOT))) + config.contracts.validatorTimelockExecutionDelay = ValidatorTimelock(discoveredCTM.validatorTimelockPostV29) + .executionDelay(); + + // Default values for initializing the chain. They are part of the chain creation params, + // meanwhile they are not saved anywhere + config.contracts.chainCreationParams.latestProtocolVersion = toml.readUint( + "$.contracts.latest_protocol_version" + ); + config.contracts.chainCreationParams.priorityTxMaxGasLimit = toml.readUint( + "$.contracts.priority_tx_max_gas_limit" ); - require( - Ownable2StepUpgradeable(addresses.bridgehub.bridgehubProxy).owner() == config.ownerAddress, - "Incorrect owner" + config.contracts.chainCreationParams.diamondInitPubdataPricingMode = PubdataPricingMode( + toml.readUint("$.contracts.diamond_init_pubdata_pricing_mode") + ); + config.contracts.chainCreationParams.diamondInitBatchOverheadL1Gas = toml.readUint( + "$.contracts.diamond_init_batch_overhead_l1_gas" + ); + config.contracts.chainCreationParams.diamondInitMaxPubdataPerBatch = toml.readUint( + "$.contracts.diamond_init_max_pubdata_per_batch" + ); + config.contracts.chainCreationParams.diamondInitMaxL2GasPerBatch = toml.readUint( + "$.contracts.diamond_init_max_l2_gas_per_batch" + ); + config.contracts.chainCreationParams.diamondInitPriorityTxMaxPubdata = toml.readUint( + "$.contracts.diamond_init_priority_tx_max_pubdata" + ); + config.contracts.chainCreationParams.diamondInitMinimalL2GasPrice = toml.readUint( + "$.contracts.diamond_init_minimal_l2_gas_price" ); - config.tokens.tokenWethAddress = toml.readAddress("$.tokens.token_weth_address"); - newConfig.governanceUpgradeTimerInitialDelay = toml.readUint("$.governance_upgrade_timer_initial_delay"); + // Protocol specific params for the entire CTM + config.contracts.chainCreationParams.genesisRoot = toml.readBytes32("$.contracts.genesis_root"); + config.contracts.chainCreationParams.genesisRollupLeafIndex = toml.readUint( + "$.contracts.genesis_rollup_leaf_index" + ); + config.contracts.chainCreationParams.genesisBatchCommitment = toml.readBytes32( + "$.contracts.genesis_batch_commitment" + ); + config.contracts.chainCreationParams.defaultAAHash = toml.readBytes32("$.contracts.default_aa_hash"); + config.contracts.chainCreationParams.bootloaderHash = toml.readBytes32("$.contracts.bootloader_hash"); + config.contracts.chainCreationParams.evmEmulatorHash = toml.readBytes32("$.contracts.evm_emulator_hash"); - newConfig.oldProtocolVersion = toml.readUint("$.old_protocol_version"); + if (vm.keyExistsToml(toml, "$.contracts.avail_l1_da_validator")) { + config.contracts.availL1DAValidator = toml.readAddress("$.contracts.avail_l1_da_validator"); + } + newConfig.governanceUpgradeTimerInitialDelay = toml.readUint("$.governance_upgrade_timer_initial_delay"); + + // L2 transactions params newConfig.priorityTxsL2GasLimit = toml.readUint("$.priority_txs_l2_gas_limit"); newConfig.maxExpectedL1GasPrice = toml.readUint("$.max_expected_l1_gas_price"); - addresses.daAddresses.rollupDAManager = toml.readAddress("$.contracts.rollup_da_manager"); - + // Gateway params + gatewayConfig.chainId = toml.readUint("$.gateway.chain_id"); gatewayConfig.gatewayStateTransition.chainTypeManagerProxy = toml.readAddress( "$.gateway.gateway_state_transition.chain_type_manager_proxy_addr" ); @@ -617,33 +644,29 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { gatewayConfig.gatewayStateTransition.rollupSLDAValidator = toml.readAddress( "$.gateway.gateway_state_transition.rollup_sl_da_validator" ); - gatewayConfig.gatewayStateTransition.isOnGateway = true; - - gatewayConfig.chainId = toml.readUint("$.gateway.chain_id"); - config.gatewayChainId = gatewayConfig.chainId; } function getBridgehubAdmin() public virtual returns (address admin) { - admin = L1Bridgehub(addresses.bridgehub.bridgehubProxy).admin(); + admin = discoveredBridgehub.admin; } /// @notice This function is meant to only be used in tests function prepareCreateNewChainCall(uint256 chainId) public view virtual returns (Call[] memory result) { - require(addresses.bridgehub.bridgehubProxy != address(0), "bridgehubProxyAddress is zero in newConfig"); + require(bridgehubAddresses.bridgehubProxy != address(0), "bridgehubProxyAddress is zero in newConfig"); - bytes32 newChainAssetId = L1Bridgehub(addresses.bridgehub.bridgehubProxy).baseTokenAssetId( + bytes32 newChainAssetId = L1Bridgehub(discoveredBridgehub.bridgehubProxy).baseTokenAssetId( gatewayConfig.chainId ); result = new Call[](1); result[0] = Call({ - target: addresses.bridgehub.bridgehubProxy, + target: discoveredBridgehub.bridgehubProxy, value: 0, data: abi.encodeCall( IL1Bridgehub.createNewChain, ( chainId, - addresses.stateTransition.chainTypeManagerProxy, + discoveredCTM.ctmProxy, newChainAssetId, 5, msg.sender, @@ -655,54 +678,28 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { } function setAddressesBasedOnBridgehub() internal virtual { - config.ownerAddress = L1Bridgehub(addresses.bridgehub.bridgehubProxy).owner(); - address ctm = IL1Bridgehub(addresses.bridgehub.bridgehubProxy).chainTypeManager(config.eraChainId); - addresses.stateTransition.chainTypeManagerProxy = ctm; - // We have to set the diamondProxy address here - as it is used by multiple constructors (for example L1Nullifier etc) - addresses.stateTransition.diamondProxy = IL1Bridgehub(addresses.bridgehub.bridgehubProxy).getZKChain( - config.eraChainId + discoveredBridgehub = AddressIntrospector.getBridgehubAddresses(bridgehub); + config.ownerAddress = discoveredBridgehub.governance; + address ctm = bridgehub.chainTypeManager(config.eraChainId); + discoveredCTM = AddressIntrospector.getCTMAddresses(ChainTypeManagerBase(ctm)); + discoveredEraZkChain = AddressIntrospector.getZkChainAddresses( + IZKChain(bridgehub.getZKChain(config.eraChainId)) ); + + addresses.daAddresses.l1RollupDAValidator = discoveredEraZkChain.l1DAValidator; uint256 ctmProtocolVersion = IChainTypeManager(ctm).protocolVersion(); + newConfig.oldProtocolVersion = ctmProtocolVersion; require( ctmProtocolVersion != getNewProtocolVersion(), "The new protocol version is already present on the ChainTypeManager" ); - addresses.bridges.l1AssetRouterProxy = address(L1Bridgehub(addresses.bridgehub.bridgehubProxy).assetRouter()); - addresses.stateTransition.genesisUpgrade = address(IChainTypeManager(ctm).l1GenesisUpgrade()); - - addresses.vaults.l1NativeTokenVaultProxy = address( - L1AssetRouter(addresses.bridges.l1AssetRouterProxy).nativeTokenVault() - ); - addresses.bridges.l1NullifierProxy = address( - L1AssetRouter(addresses.bridges.l1AssetRouterProxy).L1_NULLIFIER() - ); - addresses.bridges.erc20BridgeProxy = address( - L1AssetRouter(addresses.bridges.l1AssetRouterProxy).legacyBridge() - ); - - addresses.bridgehub.ctmDeploymentTrackerProxy = address( - L1Bridgehub(addresses.bridgehub.bridgehubProxy).l1CtmDeployer() - ); - - addresses.bridgehub.messageRootProxy = address(L1Bridgehub(addresses.bridgehub.bridgehubProxy).messageRoot()); - - addresses.bridgehub.chainAssetHandlerProxy = address( - L1Bridgehub(addresses.bridgehub.bridgehubProxy).chainAssetHandler() - ); - - addresses.bridges.erc20BridgeProxy = address( - L1AssetRouter(addresses.bridges.l1AssetRouterProxy).legacyBridge() - ); - newConfig.oldValidatorTimelock = IChainTypeManager(addresses.stateTransition.chainTypeManagerProxy) - .validatorTimelock(); - addresses.stateTransition.serverNotifierProxy = IChainTypeManager( - addresses.stateTransition.chainTypeManagerProxy - ).serverNotifierAddress(); + bridges.l1AssetRouterProxy = discoveredBridgehub.assetRouter; - newConfig.ecosystemAdminAddress = L1Bridgehub(addresses.bridgehub.bridgehubProxy).admin(); + bridges.l1NullifierProxy = address(L1AssetRouter(bridges.l1AssetRouterProxy).L1_NULLIFIER()); + bridges.erc20BridgeProxy = address(L1AssetRouter(bridges.l1AssetRouterProxy).legacyBridge()); - address eraDiamondProxy = L1Bridgehub(addresses.bridgehub.bridgehubProxy).getZKChain(config.eraChainId); - (addresses.daAddresses.l1RollupDAValidator, ) = GettersFacet(eraDiamondProxy).getDAValidatorPair(); + newConfig.oldValidatorTimelock = discoveredCTM.validatorTimelockPostV29; + newConfig.ecosystemAdminAddress = discoveredBridgehub.admin; } function generateFixedForceDeploymentsData() internal virtual { @@ -738,7 +735,6 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { additionalDependencies[0] = ContractsBytecodesLib.getCreationCode("L2SharedBridgeLegacy"); additionalDependencies[1] = ContractsBytecodesLib.getCreationCode("BridgedStandardERC20"); additionalDependencies[2] = ContractsBytecodesLib.getCreationCode("RollupL2DAValidator"); - additionalDependencies[3] = ContractsBytecodesLib.getCreationCode("ValidiumL2DAValidator"); // TODO(refactor): do we need this? additionalDependencies[4] = ContractsBytecodesLib.getCreationCode("DiamondProxy"); additionalDependencies[5] = ContractsBytecodesLib.getCreationCode("L2V29Upgrade"); @@ -758,7 +754,8 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { data = FixedForceDeploymentsData({ l1ChainId: config.l1ChainId, eraChainId: config.eraChainId, - l1AssetRouter: addresses.bridges.l1AssetRouterProxy, + gatewayChainId: config.gatewayChainId, + l1AssetRouter: discoveredBridgehub.assetRouter, l2TokenProxyBytecodeHash: getL2BytecodeHash("BeaconProxy"), aliasedL1Governance: AddressAliasHelper.applyL1ToL2Alias(config.ownerAddress), maxNumberOfZKChains: config.contracts.maxNumberOfChains, @@ -768,46 +765,55 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { messageRootBytecodeInfo: abi.encode(getL2BytecodeHash("L2MessageRoot")), chainAssetHandlerBytecodeInfo: abi.encode(getL2BytecodeHash("L2ChainAssetHandler")), beaconDeployerInfo: abi.encode(getL2BytecodeHash("UpgradeableBeaconDeployer")), + interopCenterBytecodeInfo: abi.encode(getL2BytecodeHash("InteropCenter")), + interopHandlerBytecodeInfo: abi.encode(getL2BytecodeHash("InteropHandler")), + assetTrackerBytecodeInfo: abi.encode(getL2BytecodeHash("AssetTracker")), l2SharedBridgeLegacyImpl: address(0), l2BridgedStandardERC20Impl: address(0), + aliasedChainRegistrationSender: AddressAliasHelper.applyL1ToL2Alias( + discoveredBridgehub.chainRegistrationSenderProxy + ), + // upgradeAddresses.expectedL2Addresses.l2BridgedStandardERC20Impl, dangerousTestOnlyForcedBeacon: address(0) }); } function saveOutputVersionSpecific() internal virtual {} - function saveOutput(string memory outputPath) internal virtual override { - vm.serializeAddress("bridgehub", "bridgehub_proxy_addr", addresses.bridgehub.bridgehubProxy); - vm.serializeAddress("bridgehub", "bridgehub_implementation_addr", addresses.bridgehub.bridgehubImplementation); + function getUpgradeAddedFacetCuts( + StateTransitionDeployedAddresses memory stateTransition + ) internal virtual returns (Diamond.FacetCut[] memory facetCuts) { + return getChainCreationFacetCuts(stateTransition); + } + + function saveOutput(string memory outputPath) internal virtual { + // Serialize bridgehub addresses + vm.serializeAddress("bridgehub", "bridgehub_proxy_addr", discoveredBridgehub.bridgehubProxy); + vm.serializeAddress("bridgehub", "bridgehub_implementation_addr", bridgehubAddresses.bridgehubImplementation); vm.serializeAddress( "bridgehub", "ctm_deployment_tracker_implementation_addr", - addresses.bridgehub.ctmDeploymentTrackerImplementation + bridgehubAddresses.ctmDeploymentTrackerImplementation ); vm.serializeAddress( "bridgehub", "ctm_deployment_tracker_proxy_addr", - addresses.bridgehub.ctmDeploymentTrackerProxy + bridgehubAddresses.ctmDeploymentTrackerProxy ); vm.serializeAddress( "bridgehub", "chain_asset_handler_implementation_addr", - addresses.bridgehub.chainAssetHandlerImplementation + bridgehubAddresses.chainAssetHandlerImplementation ); - vm.serializeAddress("bridgehub", "chain_asset_handler_proxy_addr", addresses.bridgehub.chainAssetHandlerProxy); - vm.serializeAddress("bridgehub", "message_root_proxy_addr", addresses.bridgehub.messageRootProxy); + vm.serializeAddress("bridgehub", "chain_asset_handler_proxy_addr", bridgehubAddresses.chainAssetHandlerProxy); + vm.serializeAddress("bridgehub", "message_root_proxy_addr", bridgehubAddresses.messageRootProxy); string memory bridgehub = vm.serializeAddress( "bridgehub", "message_root_implementation_addr", - addresses.bridgehub.messageRootImplementation + bridgehubAddresses.messageRootImplementation ); - // TODO(EVM-744): this has to be renamed to chain type manager - vm.serializeAddress( - "state_transition", - "state_transition_implementation_addr", - addresses.stateTransition.chainTypeManagerImplementation - ); + // Serialize state transition addresses vm.serializeAddress( "state_transition", "chain_type_manager_implementation_addr", @@ -828,6 +834,7 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { addresses.stateTransition.defaultUpgrade ); + // Serialize gateway state transition addresses vm.serializeAddress( "gateway_state_transition", "chain_type_manager_implementation_addr", @@ -911,89 +918,71 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { gatewayConfig.gatewayStateTransition.verifierPlonk ); + // Serialize gateway configuration vm.serializeBytes("gateway", "diamond_cut_data", gatewayConfig.facetCutsData); vm.serializeBytes("gateway", "upgrade_cut_data", gatewayConfig.upgradeCutData); string memory gateway = vm.serializeString("gateway", "gateway_state_transition", gateway_state_transition); + // Serialize root configuration vm.serializeUint("root", "gateway_chain_id", gatewayConfig.chainId); vm.serializeUint("root", "priority_txs_l2_gas_limit", newConfig.priorityTxsL2GasLimit); vm.serializeUint("root", "max_expected_l1_gas_price", newConfig.maxExpectedL1GasPrice); - vm.serializeAddress("bridges", "erc20_bridge_implementation_addr", addresses.bridges.erc20BridgeImplementation); - vm.serializeAddress("bridges", "erc20_bridge_proxy_addr", addresses.bridges.erc20BridgeProxy); - vm.serializeAddress("bridges", "l1_nullifier_proxy_addr", addresses.bridges.l1NullifierProxy); - vm.serializeAddress("bridges", "l1_nullifier_implementation_addr", addresses.bridges.l1NullifierImplementation); - vm.serializeAddress( - "bridges", - "l1_asset_router_implementation_addr", - addresses.bridges.l1AssetRouterImplementation - ); - vm.serializeAddress("bridges", "l1_asset_router_proxy_addr", addresses.bridges.l1AssetRouterProxy); + // Serialize bridges addresses + vm.serializeAddress("bridges", "erc20_bridge_implementation_addr", bridges.erc20BridgeImplementation); + vm.serializeAddress("bridges", "erc20_bridge_proxy_addr", bridges.erc20BridgeProxy); + vm.serializeAddress("bridges", "l1_nullifier_proxy_addr", bridges.l1NullifierProxy); + vm.serializeAddress("bridges", "l1_nullifier_implementation_addr", bridges.l1NullifierImplementation); + vm.serializeAddress("bridges", "l1_asset_router_implementation_addr", bridges.l1AssetRouterImplementation); + vm.serializeAddress("bridges", "l1_asset_router_proxy_addr", bridges.l1AssetRouterProxy); // TODO: legacy name - vm.serializeAddress( - "bridges", - "shared_bridge_implementation_addr", - addresses.bridges.l1AssetRouterImplementation - ); - vm.serializeAddress( - "bridges", - "bridged_standard_erc20_impl", - addresses.bridges.bridgedStandardERC20Implementation - ); + vm.serializeAddress("bridges", "shared_bridge_implementation_addr", bridges.l1AssetRouterImplementation); + vm.serializeAddress("bridges", "bridged_standard_erc20_impl", bridges.bridgedStandardERC20Implementation); - string memory bridges = vm.serializeAddress( + string memory bridgesSerialized = vm.serializeAddress( "bridges", "bridged_token_beacon", - addresses.bridges.bridgedTokenBeacon + bridges.bridgedTokenBeacon ); + // Serialize contracts configuration vm.serializeUint( "contracts_newConfig", "diamond_init_max_l2_gas_per_batch", - config.contracts.diamondInitMaxL2GasPerBatch + config.contracts.chainCreationParams.diamondInitMaxL2GasPerBatch ); vm.serializeUint( "contracts_newConfig", "diamond_init_batch_overhead_l1_gas", - config.contracts.diamondInitBatchOverheadL1Gas + config.contracts.chainCreationParams.diamondInitBatchOverheadL1Gas ); vm.serializeUint( "contracts_newConfig", "diamond_init_max_pubdata_per_batch", - config.contracts.diamondInitMaxPubdataPerBatch + config.contracts.chainCreationParams.diamondInitMaxPubdataPerBatch ); vm.serializeUint( "contracts_newConfig", "diamond_init_minimal_l2_gas_price", - config.contracts.diamondInitMinimalL2GasPrice + config.contracts.chainCreationParams.diamondInitMinimalL2GasPrice ); vm.serializeUint( "contracts_newConfig", "diamond_init_priority_tx_max_pubdata", - config.contracts.diamondInitPriorityTxMaxPubdata + config.contracts.chainCreationParams.diamondInitPriorityTxMaxPubdata ); vm.serializeUint( "contracts_newConfig", "diamond_init_pubdata_pricing_mode", - uint256(config.contracts.diamondInitPubdataPricingMode) - ); - vm.serializeUint("contracts_newConfig", "priority_tx_max_gas_limit", config.contracts.priorityTxMaxGasLimit); - vm.serializeBytes32( - "contracts_newConfig", - "recursion_circuits_set_vks_hash", - config.contracts.recursionCircuitsSetVksHash + uint256(config.contracts.chainCreationParams.diamondInitPubdataPricingMode) ); - vm.serializeBytes32( - "contracts_newConfig", - "recursion_leaf_level_vk_hash", - config.contracts.recursionLeafLevelVkHash - ); - vm.serializeBytes32( + vm.serializeUint( "contracts_newConfig", - "recursion_node_level_vk_hash", - config.contracts.recursionNodeLevelVkHash + "priority_tx_max_gas_limit", + config.contracts.chainCreationParams.priorityTxMaxGasLimit ); + // Serialize upgrade addresses vm.serializeAddress( "contracts_newConfig", "expected_rollup_l2_da_validator", @@ -1021,7 +1010,7 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { string memory contractsConfig = vm.serializeAddress( "contracts_newConfig", "l1_legacy_shared_bridge", - addresses.bridges.l1AssetRouterProxy + bridges.l1AssetRouterProxy ); vm.serializeAddress( @@ -1041,18 +1030,22 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { addresses.accessControlRestrictionAddress ); vm.serializeString("deployed_addresses", "bridgehub", bridgehub); - vm.serializeString("deployed_addresses", "bridges", bridges); + vm.serializeString("deployed_addresses", "bridges", bridgesSerialized); vm.serializeString("deployed_addresses", "state_transition", stateTransition); vm.serializeAddress( "deployed_addresses", "l1_bytecodes_supplier_addr", addresses.stateTransition.bytecodesSupplier ); - vm.serializeAddress("deployed_addresses", "native_token_vault_addr", addresses.vaults.l1NativeTokenVaultProxy); + vm.serializeAddress( + "deployed_addresses", + "native_token_vault_addr", + discoveredBridgehub.assetRouterAddresses.nativeTokenVault + ); vm.serializeAddress( "deployed_addresses", "native_token_vault_implementation_addr", - addresses.vaults.l1NativeTokenVaultImplementation + upgradeAddresses.nativeTokenVaultImplementation ); vm.serializeAddress( @@ -1065,7 +1058,6 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { "validium_l1_da_validator_addr", addresses.daAddresses.noDAValidiumL1DAValidator ); - vm.serializeAddress("deployed_addresses", "l1_gateway_upgrade", upgradeAddresses.gatewayUpgrade); vm.serializeAddress("deployed_addresses", "l1_transitionary_owner", upgradeAddresses.transitionaryOwner); vm.serializeAddress("deployed_addresses", "upgrade_stage_validator", upgradeAddresses.upgradeStageValidator); vm.serializeAddress("deployed_addresses", "l1_rollup_da_manager", addresses.daAddresses.rollupDAManager); @@ -1117,10 +1109,7 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { uint256[] memory factoryDeps = new uint256[](allDeps.length); require(factoryDeps.length <= 64, "Too many deps"); - BytecodePublisher.publishBytecodesInBatches( - BytecodesSupplier(addresses.stateTransition.bytecodesSupplier), - allDeps - ); + BytecodePublisher.publishBytecodesInBatches(BytecodesSupplier(nonDisoverable.bytecodesSupplier), allDeps); for (uint256 i = 0; i < allDeps.length; i++) { bytes32 bytecodeHash = L2ContractHelper.hashL2Bytecode(allDeps[i]); @@ -1129,9 +1118,18 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { } // Double check for consistency: - require(bytes32(factoryDeps[0]) == config.contracts.bootloaderHash, "bootloader hash factory dep mismatch"); - require(bytes32(factoryDeps[1]) == config.contracts.defaultAAHash, "default aa hash factory dep mismatch"); - require(bytes32(factoryDeps[2]) == config.contracts.evmEmulatorHash, "EVM emulator hash factory dep mismatch"); + require( + bytes32(factoryDeps[0]) == config.contracts.chainCreationParams.bootloaderHash, + "bootloader hash factory dep mismatch" + ); + require( + bytes32(factoryDeps[1]) == config.contracts.chainCreationParams.defaultAAHash, + "default aa hash factory dep mismatch" + ); + require( + bytes32(factoryDeps[2]) == config.contracts.chainCreationParams.evmEmulatorHash, + "EVM emulator hash factory dep mismatch" + ); factoryDepsHashes = factoryDeps; @@ -1195,16 +1193,14 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { } function prepareUpgradeServerNotifierCall() public virtual returns (Call[] memory calls) { - address serverNotifierProxyAdmin = address( - uint160(uint256(vm.load(addresses.stateTransition.serverNotifierProxy, ADMIN_SLOT))) - ); + address serverNotifierProxyAdmin = address(uint160(uint256(vm.load(discoveredCTM.serverNotifier, ADMIN_SLOT)))); Call memory call = Call({ target: serverNotifierProxyAdmin, data: abi.encodeCall( ProxyAdmin.upgrade, ( - ITransparentUpgradeableProxy(payable(addresses.stateTransition.serverNotifierProxy)), + ITransparentUpgradeableProxy(payable(discoveredCTM.serverNotifier)), addresses.stateTransition.serverNotifierImplementation ) ), @@ -1301,10 +1297,7 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { } function provideSetNewVersionUpgradeCall() public virtual returns (Call[] memory calls) { - require( - addresses.stateTransition.chainTypeManagerProxy != address(0), - "stateTransitionManagerAddress is zero in newConfig" - ); + require(discoveredCTM.ctmProxy != address(0), "stateTransitionManagerAddress is zero in newConfig"); // Just retrieved it from the contract uint256 previousProtocolVersion = getOldProtocolVersion(); @@ -1315,7 +1308,7 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { (Diamond.DiamondCutData) ); Call memory ctmCall = Call({ - target: addresses.stateTransition.chainTypeManagerProxy, + target: discoveredCTM.ctmProxy, data: abi.encodeCall( IChainTypeManager.setNewVersionUpgrade, (upgradeCut, previousProtocolVersion, deadline, newProtocolVersion) @@ -1328,28 +1321,22 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { } function preparePauseGatewayMigrationsCall() public view virtual returns (Call[] memory result) { - require( - addresses.bridgehub.chainAssetHandlerProxy != address(0), - "chainAssetHandlerProxy is zero in newConfig" - ); + require(discoveredBridgehub.chainAssetHandler != address(0), "chainAssetHandlerProxy is zero in newConfig"); result = new Call[](1); result[0] = Call({ - target: addresses.bridgehub.chainAssetHandlerProxy, + target: discoveredBridgehub.bridgehubProxy, value: 0, data: abi.encodeCall(IChainAssetHandler.pauseMigration, ()) }); } function prepareUnpauseGatewayMigrationsCall() public view virtual returns (Call[] memory result) { - require( - addresses.bridgehub.chainAssetHandlerProxy != address(0), - "chainAssetHandlerProxy is zero in newConfig" - ); + require(discoveredBridgehub.bridgehubProxy != address(0), "bridgehubProxyAddress is zero in newConfig"); result = new Call[](1); result[0] = Call({ - target: addresses.bridgehub.chainAssetHandlerProxy, + target: discoveredBridgehub.bridgehubProxy, value: 0, data: abi.encodeCall(IChainAssetHandler.unpauseMigration, ()) }); @@ -1532,8 +1519,8 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { ) internal view returns (Call[] memory calls) { require(gatewayConfig.chainId != 0, "Chain id of gateway is zero in newConfig"); - require(addresses.bridgehub.bridgehubProxy != address(0), "bridgehubProxyAddress is zero in newConfig"); - require(addresses.bridges.l1AssetRouterProxy != address(0), "l1AssetRouterProxyAddress is zero in newConfig"); + require(discoveredBridgehub.bridgehubProxy != address(0), "bridgehubProxyAddress is zero in newConfig"); + require(discoveredBridgehub.assetRouter != address(0), "l1AssetRouterProxyAddress is zero in newConfig"); calls = Utils.prepareGovernanceL1L2DirectTransaction( l1GasPrice, @@ -1542,8 +1529,8 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { new bytes[](0), dstAddress, gatewayConfig.chainId, - addresses.bridgehub.bridgehubProxy, - addresses.bridges.l1AssetRouterProxy, + discoveredBridgehub.bridgehubProxy, + discoveredBridgehub.assetRouter, msg.sender ); } @@ -1552,7 +1539,7 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { address spender, uint256 amount ) public virtual returns (Call[] memory calls) { - address token = IL1Bridgehub(addresses.bridgehub.bridgehubProxy).baseToken(gatewayConfig.chainId); + address token = IL1Bridgehub(discoveredBridgehub.bridgehubProxy).baseToken(gatewayConfig.chainId); require(token != address(0), "Base token for Gateway is zero"); calls = new Call[](1); calls[0] = Call({target: token, data: abi.encodeCall(IERC20.approve, (spender, amount)), value: 0}); @@ -1584,14 +1571,11 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { } function prepareNewChainCreationParamsCall() public virtual returns (Call[] memory calls) { - require( - addresses.stateTransition.chainTypeManagerProxy != address(0), - "stateTransitionManagerAddress is zero in newConfig" - ); + require(discoveredCTM.ctmProxy != address(0), "stateTransitionManagerAddress is zero in newConfig"); calls = new Call[](1); calls[0] = Call({ - target: addresses.stateTransition.chainTypeManagerProxy, + target: discoveredCTM.ctmProxy, data: abi.encodeCall( IChainTypeManager.setChainCreationParams, (getChainCreationParams(addresses.stateTransition)) @@ -1644,55 +1628,46 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { calls = new Call[](8); calls[0] = _buildCallProxyUpgrade( - addresses.stateTransition.chainTypeManagerProxy, + discoveredCTM.ctmProxy, addresses.stateTransition.chainTypeManagerImplementation ); calls[1] = _buildCallProxyUpgrade( - addresses.bridgehub.bridgehubProxy, - addresses.bridgehub.bridgehubImplementation + discoveredBridgehub.bridgehubProxy, + bridgehubAddresses.bridgehubImplementation ); // Note, that we do not need to run the initializer - calls[2] = _buildCallProxyUpgrade( - addresses.bridges.l1NullifierProxy, - addresses.bridges.l1NullifierImplementation - ); + calls[2] = _buildCallProxyUpgrade(bridges.l1NullifierProxy, bridges.l1NullifierImplementation); - calls[3] = _buildCallProxyUpgrade( - addresses.bridges.l1AssetRouterProxy, - addresses.bridges.l1AssetRouterImplementation - ); + calls[3] = _buildCallProxyUpgrade(bridges.l1AssetRouterProxy, bridges.l1AssetRouterImplementation); calls[4] = _buildCallProxyUpgrade( - addresses.vaults.l1NativeTokenVaultProxy, - addresses.vaults.l1NativeTokenVaultImplementation + discoveredBridgehub.assetRouterAddresses.nativeTokenVault, + upgradeAddresses.nativeTokenVaultImplementation ); calls[5] = _buildCallProxyUpgrade( - addresses.bridgehub.messageRootProxy, - addresses.bridgehub.messageRootImplementation + discoveredBridgehub.messageRoot, + bridgehubAddresses.messageRootImplementation ); calls[6] = _buildCallProxyUpgrade( - addresses.bridgehub.ctmDeploymentTrackerProxy, - addresses.bridgehub.ctmDeploymentTrackerImplementation + discoveredBridgehub.l1CtmDeployer, + bridgehubAddresses.ctmDeploymentTrackerImplementation ); - calls[7] = _buildCallProxyUpgrade( - addresses.bridges.erc20BridgeProxy, - addresses.bridges.erc20BridgeImplementation - ); + calls[7] = _buildCallProxyUpgrade(bridges.erc20BridgeProxy, bridges.erc20BridgeImplementation); } function _buildCallProxyUpgrade( address proxyAddress, address newImplementationAddress ) internal virtual returns (Call memory call) { - require(addresses.transparentProxyAdmin != address(0), "transparentProxyAdmin not newConfigured"); + require(discoveredBridgehub.transparentProxyAdmin != address(0), "transparentProxyAdmin not newConfigured"); call = Call({ - target: addresses.transparentProxyAdmin, + target: discoveredBridgehub.transparentProxyAdmin, data: abi.encodeCall( ProxyAdmin.upgrade, (ITransparentUpgradeableProxy(payable(proxyAddress)), newImplementationAddress) @@ -1717,7 +1692,7 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { calls = new Call[](1); calls[0] = Call({ - target: addresses.daAddresses.rollupDAManager, + target: nonDisoverable.rollupDAManager, data: abi.encodeCall( RollupDAManager.updateDAPair, (addresses.daAddresses.l1RollupDAValidator, getRollupL2DACommitmentScheme(), true) @@ -1743,10 +1718,14 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { ); } + function getAddresses() public view returns (DeployedAddresses memory) { + return addresses; + } + /// @notice Tests that it is possible to upgrade a chain to the new version function TESTONLY_prepareTestUpgradeChainCall() private returns (Call[] memory calls, address admin) { - address chainDiamondProxyAddress = L1Bridgehub(addresses.bridgehub.bridgehubProxy).getZKChain( - config.gatewayChainId + address chainDiamondProxyAddress = L1Bridgehub(discoveredBridgehub.bridgehubProxy).getZKChain( + gatewayConfig.chainId ); uint256 oldProtocolVersion = getOldProtocolVersion(); Diamond.DiamondCutData memory upgradeCutData = generateUpgradeCutData(getAddresses().stateTransition); @@ -1793,9 +1772,7 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { return type(ValidatorTimelock).creationCode; } } else { - if (compareStrings(contractName, "GatewayUpgrade")) { - return Utils.readZKFoundryBytecodeL1("GatewayUpgrade.sol", "GatewayUpgrade"); - } else if (compareStrings(contractName, "DefaultUpgrade")) { + if (compareStrings(contractName, "DefaultUpgrade")) { return Utils.readZKFoundryBytecodeL1("DefaultUpgrade.sol", "DefaultUpgrade"); } else if (compareStrings(contractName, "BytecodesSupplier")) { return Utils.readZKFoundryBytecodeL1("BytecodesSupplier.sol", "BytecodesSupplier"); @@ -1818,83 +1795,6 @@ contract DefaultEcosystemUpgrade is Script, DeployCTMScript { return super.getCreationCode(contractName, isZKBytecode); } - function getCreationCalldata( - string memory contractName, - bool isZKBytecode - ) internal view virtual override returns (bytes memory) { - if (compareStrings(contractName, "GatewayUpgrade")) { - return abi.encode(); - } else if (compareStrings(contractName, "DefaultUpgrade")) { - return abi.encode(); - } else if (compareStrings(contractName, "BytecodesSupplier")) { - return abi.encode(); - } else if (compareStrings(contractName, "TransitionaryOwner")) { - return abi.encode(config.ownerAddress); - } else if (compareStrings(contractName, "GovernanceUpgradeTimer")) { - uint256 initialDelay = newConfig.governanceUpgradeTimerInitialDelay; - return abi.encode(initialDelay, MAX_ADDITIONAL_DELAY, config.ownerAddress, newConfig.ecosystemAdminAddress); - } else if (compareStrings(contractName, "L2LegacySharedBridge")) { - return abi.encode(); - } else if (compareStrings(contractName, "L2StandardERC20")) { - return abi.encode(); - } else if (compareStrings(contractName, "RollupL2DAValidator")) { - return abi.encode(); - } else if (compareStrings(contractName, "NoDAL2DAValidator")) { - return abi.encode(); - } else if ( - compareStrings(contractName, "EraChainTypeManager") || - compareStrings(contractName, "ZKsyncOSChainTypeManager") - ) { - if (!isZKBytecode) { - return abi.encode(addresses.bridgehub.bridgehubProxy); - } else { - return abi.encode(L2_BRIDGEHUB_ADDR); - } - } else if (compareStrings(contractName, "EraVerifierFflonk")) { - return abi.encode(); - } else if (compareStrings(contractName, "EraVerifierPlonk")) { - return abi.encode(); - } else if (compareStrings(contractName, "ZKsyncOSVerifierFflonk")) { - return abi.encode(); - } else if (compareStrings(contractName, "ZKsyncOSVerifierPlonk")) { - return abi.encode(); - } else if (compareStrings(contractName, "Verifier")) { - if (!isZKBytecode) { - return abi.encode(addresses.stateTransition.verifierFflonk, addresses.stateTransition.verifierPlonk); - } else { - return - abi.encode( - gatewayConfig.gatewayStateTransition.verifierFflonk, - gatewayConfig.gatewayStateTransition.verifierPlonk - ); - } - } else if (compareStrings(contractName, "AdminFacet")) { - if (!isZKBytecode) { - return abi.encode(config.l1ChainId, addresses.daAddresses.rollupDAManager); - } else { - return abi.encode(config.l1ChainId, gatewayConfig.gatewayStateTransition.rollupDAManager); - } - } else if (compareStrings(contractName, "UpgradeStageValidator")) { - return abi.encode(addresses.stateTransition.chainTypeManagerProxy, config.contracts.latestProtocolVersion); - } else if (compareStrings(contractName, "DiamondProxy")) { - Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](0); - Diamond.DiamondCutData memory diamondCut = Diamond.DiamondCutData({ - facetCuts: facetCuts, - initAddress: address(0), - initCalldata: "" - }); - return abi.encode(block.chainid, diamondCut); - } else if (compareStrings(contractName, "ValidatorTimelock")) { - if (!isZKBytecode) { - return abi.encode(addresses.bridgehub.bridgehubProxy); - } else { - return abi.encode(L2_BRIDGEHUB_ADDR); - } - } else { - return super.getCreationCalldata(contractName, isZKBytecode); - } - } - function deployUpgradeStageValidator() internal { upgradeAddresses.upgradeStageValidator = deploySimpleContract("UpgradeStageValidator", false); } diff --git a/l1-contracts/deploy-scripts/upgrade/EcosystemUpgrade_v29.s.sol b/l1-contracts/deploy-scripts/upgrade/EcosystemUpgrade_v29.s.sol index 819c5db31d..fe4b2bfd41 100644 --- a/l1-contracts/deploy-scripts/upgrade/EcosystemUpgrade_v29.s.sol +++ b/l1-contracts/deploy-scripts/upgrade/EcosystemUpgrade_v29.s.sol @@ -7,13 +7,14 @@ import {Script, console2 as console} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; -import {StateTransitionDeployedAddresses, Utils} from "../Utils.sol"; +import {Utils} from "../Utils.sol"; +import {StateTransitionDeployedAddresses} from "../Types.sol"; import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; + import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; import {Governance} from "contracts/governance/Governance.sol"; import {L1GenesisUpgrade} from "contracts/upgrades/L1GenesisUpgrade.sol"; -import {GatewayUpgrade, GatewayUpgradeEncodedInput} from "contracts/upgrades/GatewayUpgrade.sol"; import {ChainAdmin} from "contracts/governance/ChainAdmin.sol"; import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.sol"; @@ -41,6 +42,7 @@ import {L2_CHAIN_ASSET_HANDLER_ADDR, L2_COMPLEX_UPGRADER_ADDR, L2_VERSION_SPECIF import {IComplexUpgrader} from "contracts/state-transition/l2-deps/IComplexUpgrader.sol"; import {DefaultEcosystemUpgrade} from "../upgrade/DefaultEcosystemUpgrade.s.sol"; +import {DeployL1CoreUtils} from "../DeployL1CoreUtils.s.sol"; import {IL2V29Upgrade} from "contracts/upgrades/IL2V29Upgrade.sol"; import {L1V29Upgrade} from "contracts/upgrades/L1V29Upgrade.sol"; @@ -72,11 +74,18 @@ contract EcosystemUpgrade_v29 is Script, DefaultEcosystemUpgrade { prepareDefaultTestUpgradeCalls(); } + function deployNewEcosystemContractsL1() public virtual override { + DeployL1CoreUtils l1CoreDeployer = new DeployL1CoreUtils(); + l1CoreDeployer.initializeConfig(vm.envString("V29_UPGRADE_ECOSYSTEM_INPUT")); + l1CoreDeployer.deploySimpleContract("L1Bridgehub", false); + deploySimpleContract("L1ChainTypeManager", false); + } + function initializeConfig(string memory newConfigPath) internal override { super.initializeConfig(newConfigPath); string memory toml = vm.readFile(newConfigPath); - v28ProtocolVersion = toml.readUint("$.v28_protocol_version"); + v28ProtocolVersion = newConfig.oldProtocolVersion; bytes memory encodedOldValidatorTimelocks = toml.readBytes("$.V29.encoded_old_validator_timelocks"); oldValidatorTimelocks = abi.decode(encodedOldValidatorTimelocks, (address[])); @@ -110,7 +119,7 @@ contract EcosystemUpgrade_v29 is Script, DefaultEcosystemUpgrade { function _getL2UpgradeTargetAndData( IL2ContractDeployer.ForceDeployment[] memory _forceDeployments ) internal override returns (address, bytes memory) { - bytes32 ethAssetId = IL1AssetRouter(addresses.bridges.l1AssetRouterProxy).ETH_TOKEN_ASSET_ID(); + bytes32 ethAssetId = IL1AssetRouter(discoveredBridgehub.assetRouter).ETH_TOKEN_ASSET_ID(); bytes memory v29UpgradeCalldata = abi.encodeCall( IL2V29Upgrade.upgrade, (AddressAliasHelper.applyL1ToL2Alias(config.ownerAddress), ethAssetId) @@ -176,8 +185,8 @@ contract EcosystemUpgrade_v29 is Script, DefaultEcosystemUpgrade { super.deployUpgradeSpecificContractsL1(); ( - addresses.bridgehub.chainAssetHandlerImplementation, - addresses.bridgehub.chainAssetHandlerProxy + bridgehubAddresses.chainAssetHandlerImplementation, + bridgehubAddresses.chainAssetHandlerProxy ) = deployTuppWithContract("L1ChainAssetHandler", false); ( @@ -245,7 +254,7 @@ contract EcosystemUpgrade_v29 is Script, DefaultEcosystemUpgrade { calls = new Call[](1); calls[0] = Call({ - target: addresses.stateTransition.chainTypeManagerProxy, + target: discoveredCTM.ctmProxy, data: abi.encodeCall( IChainTypeManager.setValidatorTimelockPostV29, (addresses.stateTransition.validatorTimelock) @@ -294,8 +303,8 @@ contract EcosystemUpgrade_v29 is Script, DefaultEcosystemUpgrade { function prepareSetChainAssetHandlerOnBridgehubCall() public virtual returns (Call[] memory calls) { calls = new Call[](1); calls[0] = Call({ - target: addresses.bridgehub.bridgehubProxy, - data: abi.encodeCall(IBridgehubBase.setChainAssetHandler, (addresses.bridgehub.chainAssetHandlerProxy)), + target: discoveredBridgehub.bridgehubProxy, + data: abi.encodeCall(IBridgehubBase.setChainAssetHandler, (bridgehubAddresses.chainAssetHandlerProxy)), value: 0 }); } @@ -305,11 +314,8 @@ contract EcosystemUpgrade_v29 is Script, DefaultEcosystemUpgrade { calls = new Call[](1); calls[0] = Call({ - target: addresses.bridgehub.ctmDeploymentTrackerProxy, - data: abi.encodeCall( - CTMDeploymentTracker.setCtmAssetHandlerAddressOnL1, - (addresses.stateTransition.chainTypeManagerProxy) - ), + target: discoveredBridgehub.l1CtmDeployer, + data: abi.encodeCall(CTMDeploymentTracker.setCtmAssetHandlerAddressOnL1, (discoveredCTM.ctmProxy)), value: 0 }); } @@ -325,7 +331,7 @@ contract EcosystemUpgrade_v29 is Script, DefaultEcosystemUpgrade { ); calls[0] = Call({ - target: addresses.stateTransition.chainTypeManagerProxy, + target: discoveredCTM.ctmProxy, data: abi.encodeCall(IChainTypeManager.setUpgradeDiamondCut, (upgradeCut, oldProtocolVersion)), value: 0 }); @@ -353,8 +359,8 @@ contract EcosystemUpgrade_v29 is Script, DefaultEcosystemUpgrade { ) public virtual returns (Call[] memory calls) { bytes32 chainAssetId = DataEncoding.encodeAssetId( block.chainid, - bytes32(uint256(uint160(addresses.stateTransition.chainTypeManagerProxy))), - addresses.bridgehub.ctmDeploymentTrackerProxy + bytes32(uint256(uint160(discoveredCTM.ctmProxy))), + discoveredBridgehub.l1CtmDeployer ); bytes memory secondBridgeData = abi.encodePacked( @@ -368,9 +374,9 @@ contract EcosystemUpgrade_v29 is Script, DefaultEcosystemUpgrade { l1GasPrice, l2GasLimit, gatewayConfig.chainId, - addresses.bridgehub.bridgehubProxy, - addresses.bridges.l1AssetRouterProxy, - addresses.bridges.l1AssetRouterProxy, + discoveredBridgehub.bridgehubProxy, + discoveredBridgehub.assetRouter, + discoveredBridgehub.assetRouter, 0, secondBridgeData, msg.sender diff --git a/l1-contracts/deploy-scripts/upgrade/EcosystemUpgrade_v29_2.s.sol b/l1-contracts/deploy-scripts/upgrade/EcosystemUpgrade_v29_2.s.sol index a5d0b061c7..1c40549fa2 100644 --- a/l1-contracts/deploy-scripts/upgrade/EcosystemUpgrade_v29_2.s.sol +++ b/l1-contracts/deploy-scripts/upgrade/EcosystemUpgrade_v29_2.s.sol @@ -5,12 +5,9 @@ pragma solidity 0.8.28; import {Script, console2 as console} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; -import {StateTransitionDeployedAddresses, Utils} from "../Utils.sol"; -import {BytecodePublisher} from "./BytecodePublisher.s.sol"; +import {Utils} from "../Utils.sol"; +import {StateTransitionDeployedAddresses} from "../Types.sol"; import {MessageRoot} from "contracts/bridgehub/MessageRoot.sol"; -import {IAdmin} from "contracts/state-transition/chain-interfaces/IAdmin.sol"; -import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol"; -import {Bridgehub} from "contracts/bridgehub/Bridgehub.sol"; import {ChainAssetHandler} from "contracts/bridgehub/ChainAssetHandler.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; @@ -61,8 +58,8 @@ contract EcosystemUpgrade_v29_2 is Script, DefaultEcosystemUpgrade { addresses.stateTransition.defaultUpgrade = deployUsedUpgradeContract(); upgradeAddresses.upgradeTimer = deploySimpleContract("GovernanceUpgradeTimer", false); - addresses.bridgehub.messageRootImplementation = deploySimpleContract("MessageRoot", false); - addresses.bridgehub.chainAssetHandlerImplementation = deploySimpleContract("ChainAssetHandler", false); + bridgehubAddresses.messageRootImplementation = deploySimpleContract("MessageRoot", false); + bridgehubAddresses.chainAssetHandlerImplementation = deploySimpleContract("ChainAssetHandler", false); addresses.stateTransition.adminFacet = deploySimpleContract("AdminFacet", false); addresses.stateTransition.mailboxFacet = deploySimpleContract("MailboxFacet", false); @@ -125,12 +122,12 @@ contract EcosystemUpgrade_v29_2 is Script, DefaultEcosystemUpgrade { calls = new Call[](2); calls[0] = _buildCallProxyUpgrade( - addresses.bridgehub.messageRootProxy, - addresses.bridgehub.messageRootImplementation + discoveredBridgehub.messageRoot, + bridgehubAddresses.messageRootImplementation ); calls[1] = _buildCallProxyUpgrade( - addresses.bridgehub.chainAssetHandlerProxy, - addresses.bridgehub.chainAssetHandlerImplementation + discoveredBridgehub.chainAssetHandler, + bridgehubAddresses.chainAssetHandlerImplementation ); } diff --git a/l1-contracts/deploy-scripts/upgrade/EcosystemUpgrade_v30.s.sol b/l1-contracts/deploy-scripts/upgrade/EcosystemUpgrade_v30.s.sol new file mode 100644 index 0000000000..243c8732e2 --- /dev/null +++ b/l1-contracts/deploy-scripts/upgrade/EcosystemUpgrade_v30.s.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +// solhint-disable no-console, gas-custom-errors + +import {Script, console2 as console} from "forge-std/Script.sol"; +import {stdToml} from "forge-std/StdToml.sol"; + +import {IBridgehub} from "contracts/bridgehub/IBridgehub.sol"; + +import {Governance} from "contracts/governance/Governance.sol"; + +import {Bridgehub} from "contracts/bridgehub/Bridgehub.sol"; + +import {InitializeDataNewChain as DiamondInitializeDataNewChain} from "contracts/state-transition/chain-interfaces/IDiamondInit.sol"; + +import {L1AssetRouter} from "contracts/bridge/asset-router/L1AssetRouter.sol"; + +import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; +import {INativeTokenVault} from "contracts/bridge/ntv/INativeTokenVault.sol"; + +import {IL2ContractDeployer} from "contracts/common/interfaces/IL2ContractDeployer.sol"; + +import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol"; + +import {Call} from "contracts/governance/Common.sol"; + +import {L2_COMPLEX_UPGRADER_ADDR, L2_VERSION_SPECIFIC_UPGRADER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {IComplexUpgrader} from "contracts/state-transition/l2-deps/IComplexUpgrader.sol"; + +import {DefaultEcosystemUpgrade} from "../upgrade/DefaultEcosystemUpgrade.s.sol"; + +import {IL2V29Upgrade} from "contracts/upgrades/IL2V29Upgrade.sol"; +import {L1V29Upgrade} from "contracts/upgrades/L1V29Upgrade.sol"; + +/// @notice Script used for v30 upgrade flow +contract EcosystemUpgrade_v30 is Script, DefaultEcosystemUpgrade { + using stdToml for string; + + /// @notice E2e upgrade generation + function run() public virtual override { + initialize(vm.envString("UPGRADE_ECOSYSTEM_INPUT"), vm.envString("UPGRADE_ECOSYSTEM_OUTPUT")); + prepareEcosystemUpgrade(); + + /// kl todo check that no chain is on GW. We can write a contract to check it and call it in V30 stage 0 calls. + + prepareDefaultGovernanceCalls(); + } + + // function saveAllBridgedTokens(address _bridgehub) public { + // //// We need to save all bridged tokens + //// i.e. add them to the bridged tokens list in the L1 NTV + // } + + function registerBridgedTokensInNTV(address _bridgehub) public { + INativeTokenVault ntv = INativeTokenVaultBase(IBridgehubBase(_bridgehub).assetRouter().nativeTokenVault()); + address[] memory savedBridgedTokens; + /// todo get save bridged tokens. + /// for tokens in the bridged token list + for (uint256 i = 0; i < savedBridgedTokens.length; ++i) { + address token = ntv.bridgedTokens(i); + ntv.addLegacyTokenToBridgedTokensList(token); + } + } + + /*////////////////////////////////////////////////////////////// + Internal functions + //////////////////////////////////////////////////////////////*/ + + function _getL2UpgradeTargetAndData( + IL2ContractDeployer.ForceDeployment[] memory _forceDeployments + ) internal override returns (address, bytes memory) { + bytes32 ethAssetId = IL1AssetRouter(addresses.bridges.l1AssetRouterProxy).ETH_TOKEN_ASSET_ID(); + bytes memory v29UpgradeCalldata = abi.encodeCall( + IL2V29Upgrade.upgrade, + (AddressAliasHelper.applyL1ToL2Alias(config.ownerAddress), ethAssetId) + ); + return ( + address(L2_COMPLEX_UPGRADER_ADDR), + abi.encodeCall( + IComplexUpgrader.forceDeployAndUpgrade, + (_forceDeployments, L2_VERSION_SPECIFIC_UPGRADER_ADDR, v29UpgradeCalldata) + ) + ); + } + + function getForceDeploymentNames() internal override returns (string[] memory forceDeploymentNames) { + forceDeploymentNames = new string[](1); + forceDeploymentNames[0] = "L2V29Upgrade"; + } + + function getExpectedL2Address(string memory contractName) public override returns (address) { + if (compareStrings(contractName, "L2V29Upgrade")) { + return address(L2_VERSION_SPECIFIC_UPGRADER_ADDR); + } + + return super.getExpectedL2Address(contractName); + } + + function getCreationCode( + string memory contractName, + bool isZKBytecode + ) internal view virtual override returns (bytes memory) { + if (!isZKBytecode && compareStrings(contractName, "L1V29Upgrade")) { + return type(L1V29Upgrade).creationCode; + } + return super.getCreationCode(contractName, isZKBytecode); + } + + function getCreationCalldata( + string memory contractName, + bool isZKBytecode + ) internal view override returns (bytes memory) { + if (compareStrings(contractName, "L1V29Upgrade")) { + return abi.encode(); + } + return super.getCreationCalldata(contractName, isZKBytecode); + } + + function deployUsedUpgradeContract() internal override returns (address) { + return deploySimpleContract("L1V29Upgrade", false); + } + + function getInitializeCalldata(string memory contractName) internal virtual override returns (bytes memory) { + if (compareStrings(contractName, "MessageRoot")) { + return abi.encodeCall(MessageRoot.initializeL1V30Upgrade, ()); + } + return super.getInitializeCalldata(contractName); + } +} diff --git a/l1-contracts/deploy-scripts/upgrade/FinalizeUpgrade.s.sol b/l1-contracts/deploy-scripts/upgrade/FinalizeUpgrade.s.sol index 140345d9c6..8f79c15a4e 100644 --- a/l1-contracts/deploy-scripts/upgrade/FinalizeUpgrade.s.sol +++ b/l1-contracts/deploy-scripts/upgrade/FinalizeUpgrade.s.sol @@ -25,7 +25,7 @@ contract FinalizeUpgrade is Script { if (bh.baseTokenAssetId(chains[i]) == bytes32(0)) { vm.broadcast(); - L1Bridgehub(bridgehub).registerLegacyChain(chains[i]); + // L1Bridgehub(bridgehub).registerLegacyChain(chains[i]); } } } @@ -151,19 +151,17 @@ contract FinalizeUpgrade is Script { console.log("Processing chain: ", params.chains[i]); if (bh.baseTokenAssetId(params.chains[i]) == bytes32(0)) { // Register legacy chain if needed - bytes memory data = abi.encodeWithSelector( - L1Bridgehub.registerLegacyChain.selector, - params.chains[i] - ); - + // bytes memory data = abi.encodeWithSelector( + // L1Bridgehub.registerLegacyChain.selector, + // params.chains[i] + // ); // Add call to aggregator calls array - callIndex = addCall(calls, callIndex, params.bridgehub, data); - + // callIndex = addCall(calls, callIndex, params.bridgehub, data); // If we've hit max calls, flush - if (callIndex == MAX_CALLS_PER_BATCH) { - flushBatch(params.aggregator, calls, callIndex); - callIndex = 0; - } + // if (callIndex == MAX_CALLS_PER_BATCH) { + // flushBatch(params.aggregator, calls, callIndex); + // callIndex = 0; + // } } } diff --git a/l1-contracts/deploy-scripts/upgrade/SystemContractsProcessing.s.sol b/l1-contracts/deploy-scripts/upgrade/SystemContractsProcessing.s.sol index df954f8ba9..bfc1951db1 100644 --- a/l1-contracts/deploy-scripts/upgrade/SystemContractsProcessing.s.sol +++ b/l1-contracts/deploy-scripts/upgrade/SystemContractsProcessing.s.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.28; import {console2 as console} from "forge-std/Script.sol"; import {Utils} from "../Utils.sol"; -import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR, L2_MESSAGE_ROOT_ADDR, L2_MESSAGE_VERIFICATION, L2_NATIVE_TOKEN_VAULT_ADDR, L2_WETH_IMPL_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR, L2_MESSAGE_ROOT_ADDR, L2_MESSAGE_VERIFICATION, L2_NATIVE_TOKEN_VAULT_ADDR, L2_WRAPPED_BASE_TOKEN_IMPL_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {L2ContractHelper} from "contracts/common/l2-helpers/L2ContractHelper.sol"; import {ContractsBytecodesLib} from "../ContractsBytecodesLib.sol"; import {IL2ContractDeployer} from "contracts/common/interfaces/IL2ContractDeployer.sol"; @@ -398,7 +398,7 @@ library SystemContractsProcessing { }); forceDeployments[4] = IL2ContractDeployer.ForceDeployment({ bytecodeHash: L2ContractHelper.hashL2Bytecode(bytecodes[4]), - newAddress: L2_WETH_IMPL_ADDR, + newAddress: L2_WRAPPED_BASE_TOKEN_IMPL_ADDR, callConstructor: false, value: 0, input: "" diff --git a/l1-contracts/foundry.toml b/l1-contracts/foundry.toml index d7e6fe7e41..968286f7e4 100644 --- a/l1-contracts/foundry.toml +++ b/l1-contracts/foundry.toml @@ -1,5 +1,5 @@ [profile.default] -allow_paths = ["../l2-contracts/contracts"] +allow_paths = ["../l2-contracts/contracts", "../lib"] src = "contracts" out = "out" libs = ["./lib"] @@ -18,6 +18,7 @@ fs_permissions = [ { access = "read", path = "../l2-contracts/zkout/" }, { access = "read", path = "../l1-contracts/artifacts-zk/" }, { access = "read", path = "../l1-contracts/script-out/" }, + { access = "read", path = "../l1-contracts/broadcast/" }, { access = "read", path = "../da-contracts/" }, { access = "read", path = "../system-contracts/zkout/" }, { access = "read", path = "./script-config" }, @@ -48,6 +49,7 @@ optimizer_runs = 9999999 # on such reverts allow_internal_expect_revert = true + [profile.default.zksync] enable_eravm_extensions = true zksolc = "1.5.11" diff --git a/l1-contracts/package.json b/l1-contracts/package.json index 7309bae9e8..bc3a455590 100644 --- a/l1-contracts/package.json +++ b/l1-contracts/package.json @@ -68,7 +68,8 @@ "test:fork": "TEST_CONTRACTS_FORK=1 yarn run hardhat test test/unit_tests/*.fork.ts --network hardhat", "test:invariant:l1-context": "WHERE=L1 scripts/run-invariant-tests", "test:invariant:l2-context": "WHERE=L2 scripts/run-invariant-tests", - "coverage:foundry": "forge coverage --ffi --match-path 'test/foundry/l1/*' --no-match-coverage 'contracts/(bridge/.*L2.*\\.sol|governance/L2AdminFactory\\.sol|state-transition/verifiers/.*\\.sol)' --no-match-test 'test_StageProofsForkScriptBased|test_StageProofsForkFileBased|test_MainnetFork'", + "coverage:foundry": "forge coverage --ffi --match-path 'test/foundry/l1/*' --no-match-coverage 'contracts/(bridge/.*L2.*\\.sol|governance/L2AdminFactory\\.sol|state-transition/L2TestnetVerifier\\.sol|state-transition/L2Verifier\\.sol|state-transition/verifiers/.*\\.sol)' --no-match-test 'test_StageProofsForkScriptBased|test_StageProofsForkFileBased|test_MainnetFork'", + "coverage-report": "forge coverage --report lcov --ffi --match-path 'test/foundry/l1/*' --no-match-coverage 'contracts/(bridge/.*L2.*\\.sol|governance/L2AdminFactory\\.sol|state-transition/L2TestnetVerifier\\.sol|state-transition/L2Verifier\\.sol|state-transition/verifiers/.*\\.sol)' --no-match-test 'test_StageProofsForkScriptBased|test_StageProofsForkFileBased|test_MainnetFork' && genhtml -o report lcov.info --branch-coverage --ignore-errors category lcov.info --ignore-errors inconsistent", "deploy-no-build": "ts-node scripts/deploy.ts", "register-zk-chain": "ts-node scripts/register-zk-chain.ts", "deploy-weth-bridges": "ts-node scripts/deploy-weth-bridges.ts", diff --git a/l1-contracts/scripts/deploy-erc20.ts b/l1-contracts/scripts/deploy-erc20.ts index 67ddf3a04d..11a1e282b2 100644 --- a/l1-contracts/scripts/deploy-erc20.ts +++ b/l1-contracts/scripts/deploy-erc20.ts @@ -10,7 +10,7 @@ import { web3Provider } from "./utils"; import type { TokenDescription } from "../src.ts/deploy-token"; import { deployTokens, deployContracts, mintTokens } from "../src.ts/deploy-token"; -import { ethTestConfig } from "../src.ts/utils"; +import { ethTestConfig } from "../src.ts/constants"; const provider = web3Provider(); diff --git a/l1-contracts/scripts/deploy-testkit.ts b/l1-contracts/scripts/deploy-testkit.ts index 8b40f18c60..6e059d2b38 100644 --- a/l1-contracts/scripts/deploy-testkit.ts +++ b/l1-contracts/scripts/deploy-testkit.ts @@ -9,7 +9,7 @@ import { Deployer } from "../src.ts/deploy"; import { web3Provider } from "./utils"; -import { ethTestConfig } from "../src.ts/utils"; +import { ethTestConfig } from "../src.ts/constants"; async function main() { const program = new Command(); diff --git a/l1-contracts/scripts/deploy.ts b/l1-contracts/scripts/deploy.ts index 6f487df52c..bc2e756829 100644 --- a/l1-contracts/scripts/deploy.ts +++ b/l1-contracts/scripts/deploy.ts @@ -8,7 +8,7 @@ import { formatUnits, parseUnits } from "ethers/lib/utils"; import { web3Provider, GAS_MULTIPLIER, web3Url } from "./utils"; import { deployedAddressesFromEnv } from "../src.ts/deploy-utils"; import { initialBridgehubDeployment } from "../src.ts/deploy-process"; -import { ethTestConfig } from "../src.ts/utils"; +import { ethTestConfig } from "../src.ts/constants"; import { Wallet as ZkWallet, Provider as ZkProvider } from "zksync-ethers"; const provider = web3Provider(); diff --git a/l1-contracts/scripts/errors-lint.ts b/l1-contracts/scripts/errors-lint.ts index 9bc4010130..f17ba24521 100644 --- a/l1-contracts/scripts/errors-lint.ts +++ b/l1-contracts/scripts/errors-lint.ts @@ -5,11 +5,13 @@ import { ethers } from "ethers"; import * as https from "https"; // Constant arrays -const CONTRACTS_DIRECTORIES = { +const CONTRACTS_DIRECTORIES: Record = { contracts: [ "common/L1ContractErrors.sol", "bridge/L1BridgeContractErrors.sol", "bridgehub/L1BridgehubErrors.sol", + "interop/InteropErrors.sol", + "bridge/asset-tracker/AssetTrackerErrors.sol", "state-transition/L1StateTransitionErrors.sol", "upgrades/ZkSyncUpgradeErrors.sol", ], @@ -19,11 +21,12 @@ const CONTRACTS_DIRECTORIES = { "../da-contracts/contracts": ["DAContractsErrors.sol"], }; -// Helper function to query the signature database +// ---------- Helpers: signature DB ---------- + async function querySignatureDatabase(signature: string): Promise { const url = `https://api.openchain.xyz/signature-database/v1/search?query=${encodeURIComponent( signature - )}&_=${Date.now()}`; // add a timestamp to avoid caching + )}&_=${Date.now()}`; return new Promise((resolve, reject) => { https .get(url, (res) => { @@ -37,11 +40,10 @@ async function querySignatureDatabase(signature: string): Promise { if (!parsedData.ok || !parsedData.result) { return reject(new Error(`Invalid response from signature database. Response: ${data}`)); } - const { event, function: func } = parsedData.result; const signatureFound = Object.keys(event || {}).length > 0 || Object.keys(func || {}).length > 0; resolve(signatureFound); - } catch (e) { + } catch { reject(new Error(`Failed to parse response from signature database: ${data}`)); } }); @@ -52,7 +54,6 @@ async function querySignatureDatabase(signature: string): Promise { }); } -// Helper function to submit a signature to the database async function submitSignatureToDatabase(signature: string): Promise { const postData = JSON.stringify({ function: [signature], @@ -75,7 +76,7 @@ async function submitSignatureToDatabase(signature: string): Promise { res.on("data", (chunk) => (responseBody += chunk)); res.on("end", () => { - if (res.statusCode >= 200 && res.statusCode < 300) { + if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) { console.log(`Signature "${signature}" submitted successfully.`); resolve(); } else if (res.statusCode === 400 && responseBody.includes("already exists")) { @@ -100,25 +101,34 @@ async function submitSignatureToDatabase(signature: string): Promise { }); } -// Helper: sort error blocks (selector + multi-line error) alphabetically by error name +// ---------- Helpers: parsing/sorting ---------- + +// ethers v5 uses ethers.utils.id; v6 uses ethers.id +function keccakId(text: string): string { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const anyEthers: any = ethers as any; + const fn = anyEthers.id ?? anyEthers.utils?.id; + if (!fn) throw new Error("Unable to find ethers.id / ethers.utils.id"); + return fn(text); +} + +// Sort error blocks (selector + multi-line error) alphabetically by error name function sortErrorBlocks(lines: string[]): string[] { const before: string[] = []; const blocks: string[][] = []; const after: string[] = []; let i = 0; - let inBlock = false; + let startedBlocks = false; while (i < lines.length) { const line = lines[i]; const next = lines[i + 1]; - // If a selector comment followed by an error declaration - if (/^\s*\/\/\s*0x[0-9a-fA-F]{8}/.test(line) && next && /^\s*error\s+/.test(next)) { - inBlock = true; + if (/^\s*\/\/\s*0x[0-9a-fA-F]{8}\s*$/.test(line) && next && /^\s*error\s+/.test(next)) { + startedBlocks = true; const block: string[] = []; block.push(line); i++; - // Capture error and its multi-line body while (i < lines.length) { block.push(lines[i]); if (lines[i].trim().endsWith(");")) { @@ -128,10 +138,8 @@ function sortErrorBlocks(lines: string[]): string[] { i++; } blocks.push(block); - } - // If an error declaration without preceding selector comment - else if (/^\s*error\s+/.test(line)) { - inBlock = true; + } else if (/^\s*error\s+/.test(line)) { + startedBlocks = true; const block: string[] = []; while (i < lines.length) { block.push(lines[i]); @@ -142,37 +150,33 @@ function sortErrorBlocks(lines: string[]): string[] { i++; } blocks.push(block); - } - // Regular lines - else { - if (!inBlock) before.push(line); + } else { + if (!startedBlocks) before.push(line); else after.push(line); i++; } } - // Sort blocks by the first 'error Name' blocks.sort((a, b) => { const nameA = a.find((l) => /^\s*error\s+/.test(l))!.match(/error\s+(\w+)/)![1]; const nameB = b.find((l) => /^\s*error\s+/.test(l))!.match(/error\s+(\w+)/)![1]; return nameA.localeCompare(nameB); }); - // Reassemble file - const sorted: string[] = [...before]; - blocks.forEach((block) => sorted.push(...block)); - return sorted.concat(after); + return [...before, ...blocks.flat(), ...after]; } -// Process a file: handle selector insertion, multiline parsing, and sorting +// ---------- Core: process files & collect usage ---------- + async function processFile( filePath: string, fix: boolean, + database: boolean, collectedErrors: Map ): Promise { const content = fs.readFileSync(filePath, "utf8"); - // Find all enum definitions in the file + // Collect enum names to map to uint8 in error signatures const enums = new Set(); const enumRegex = /enum\s+(\w+)\s*\{/g; let enumMatch; @@ -189,7 +193,6 @@ async function processFile( const line = lines[i]; if (/^\s*error\s+/.test(line)) { - // Capture block lines const blockLines: string[] = []; const start = i; while (i < lines.length) { @@ -197,11 +200,12 @@ async function processFile( if (lines[i].trim().endsWith(");")) break; i++; } - // Regex parse + const blockText = blockLines.join("\n"); const sigRe = /^\s*error\s+(\w+)\s*\(([\s\S]*?)\)\s*;\s*$/m; const match = blockText.match(sigRe); if (!match) throw new Error(`Cannot parse error at ${filePath}:${start + 1}`); + const [, errName, params] = match; const types = params .split(",") @@ -216,8 +220,8 @@ async function processFile( } collectedErrors.set(sig, [errName, filePath]); - // Selector comment - const selector = ethers.utils.id(sig).slice(0, 10); + // Insert/update selector comment + const selector = keccakId(sig).slice(0, 10); const comment = `// ${selector}`; const prev = output[output.length - 1]; if (!prev || (prev.trim() !== comment && !prev.trim().startsWith("// skip-errors-lint"))) { @@ -227,8 +231,8 @@ async function processFile( modified = true; } - // Submit signature to https://openchain.xyz/ if --fix is provided - if (fix) { + // Submit selectors to signature DB + if (database) { const exists = await querySignatureDatabase(sig); if (!exists) { await submitSignatureToDatabase(sig); @@ -237,7 +241,6 @@ async function processFile( } } - // Push block blockLines.forEach((l) => output.push(l)); i++; } else { @@ -247,7 +250,6 @@ async function processFile( } if (fix && modified) { - // Sort all error blocks const sorted = sortErrorBlocks(output); fs.writeFileSync(filePath, sorted.join("\n"), "utf8"); return true; @@ -255,17 +257,103 @@ async function processFile( return modified; } +// Escape for building a safe regex alternation +function escapeRegex(s: string): string { + return s.replace(/[$()*+.?[\\\]^{|}-]/g, "\\$&"); +} + // Recursively collects all custom error usages from the given contract directories. -function collectErrorUsages(directories: string[], usedErrors: Set) { +// This recognizes: +// - revert ErrorName(...) +// - require(..., ErrorName(...)) +// - naked calls: ErrorName(...) +// - qualified calls: Namespace.ErrorName(...) +// - selector usage: ErrorName.selector +// - abi.encodeWithSelector(ErrorName.selector, ...) +function collectErrorUsages(directories: string[], usedErrors: Set, declaredNames?: Set) { + const nameAlternation = + declaredNames && declaredNames.size > 0 + ? Array.from(declaredNames) + .sort((a, b) => a.length - b.length) + .map(escapeRegex) + .join("|") + : "[A-Za-z0-9_]+"; + + const pattern = + "\\b(?:" + + // 1) revert ErrorName(...) + "revert\\s+(" + + nameAlternation + + ")\\s*\\(" + + "|" + + // 2) require(..., ErrorName(...)) + "require\\s*\\([^;]*?\\b(" + + nameAlternation + + ")\\s*\\(" + + "|" + + // 3) naked constructor call ErrorName(...) + "(" + + nameAlternation + + ")\\s*\\(" + + "|" + + // 4) Namespace.ErrorName(...) + "[A-Za-z0-9_]+\\s*\\.\\s*(" + + nameAlternation + + ")\\s*\\(" + + "|" + + // 5) ErrorName.selector + "(" + + nameAlternation + + ")\\.selector\\b" + + "|" + + // 6) abi.encodeWithSelector(ErrorName.selector, ...) + "abi\\s*\\.\\s*encodeWithSelector\\s*\\(\\s*(" + + nameAlternation + + ")\\.selector" + + ")"; + + const usageRe = new RegExp(pattern, "gm"); + for (const dir of directories) { const absoluteDir = path.resolve(dir); - if (fs.existsSync(absoluteDir) && fs.lstatSync(absoluteDir).isDirectory()) { + if (!fs.existsSync(absoluteDir)) continue; + + const stat = fs.statSync(absoluteDir); + if (stat.isDirectory()) { const files = fs.readdirSync(absoluteDir); for (const file of files) { const fullPath = path.join(absoluteDir, file); - if (fs.lstatSync(fullPath).isDirectory()) { - collectErrorUsages([fullPath], usedErrors); + const st = fs.statSync(fullPath); + if (st.isDirectory()) { + collectErrorUsages([fullPath], usedErrors, declaredNames); } else if (file.endsWith(".sol")) { + let src = fs.readFileSync(fullPath, "utf8"); + + // Strip comments + src = src.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, ""); + + // Drop import lines and error declarations to avoid counting definitions/imports as "usage" + src = src.replace(/^\s*import\s+[^;]+;.*$/gm, ""); + src = src.replace(/^\s*error\s+[A-Za-z0-9_]+\s*\([^;]*\)\s*;.*$/gm, ""); + + // Normalize whitespace + src = src.replace(/\s+/g, " "); + + let m: RegExpExecArray | null; + while ((m = usageRe.exec(src)) !== null) { + // Find which capturing group hit and add that name + for (let i = 1; i < m.length; i++) { + const name = m[i]; + if (name) { + if (!declaredNames || declaredNames.has(name)) { + usedErrors.add(name); + } + break; + } + } + } + + // Check for errors used in revert statements like revert ErrorName(...) const fileContent = fs.readFileSync(fullPath, "utf8"); const revertRegex = /revert\s+([A-Za-z0-9_]+)/g; let match; @@ -280,52 +368,77 @@ function collectErrorUsages(directories: string[], usedErrors: Set) { while ((match = requireRegex.exec(fileContent)) !== null) usedErrors.add(match[1]); } } + } else if (stat.isFile() && absoluteDir.endsWith(".sol")) { + // If a single file slipped in, scan its directory + collectErrorUsages([path.dirname(absoluteDir)], usedErrors, declaredNames); } } } +// ---------- CLI ---------- + async function main() { const program = new Command(); program .option("--fix", "Fix the errors by inserting selectors and sorting") .option("--check", "Check if the selectors are present without modifying files") + .option("--database", "Upload error selectors to the signature DB (https://openchain.xyz/signatures).") .parse(process.argv); - const options = program.opts(); + const options = program.opts<{ fix?: boolean; check?: boolean; database?: boolean }>(); if ((!options.fix && !options.check) || (options.fix && options.check)) { console.error("Error: You must provide either --fix or --check, but not both."); process.exit(1); } + if (!options.fix && options.database) { + console.error("You can only upload the signatures to the database when using --fix flag."); + process.exit(1); + } + let hasErrors = false; + for (const [contractsPath, errorsPaths] of Object.entries(CONTRACTS_DIRECTORIES)) { - const declaredErrors = new Map(); + const declaredErrors = new Map(); // sig -> [errName, filePath] const usedErrors = new Set(); + + // Process/validate each error definition file, collecting declared errors for (const customErrorFile of errorsPaths) { const absolutePath = path.resolve(contractsPath + "/" + customErrorFile); - const result = await processFile(absolutePath, options.fix, declaredErrors); + const result = await processFile(absolutePath, !!options.fix, !!options.database, declaredErrors); if (result && options.check) hasErrors = true; } + if (options.check && hasErrors) { console.error("Some errors were found."); process.exit(1); } + if (options.check) { + // Restrict usage scan to only declared error names from this package path + const declaredNames = new Set(Array.from(declaredErrors.values()).map(([name]) => name)); + // Check for error usage in contracts, test files, and deploy scripts const searchPaths = [contractsPath]; if (contractsPath === "contracts") { searchPaths.push("test"); // Also search test directory for contracts } - collectErrorUsages(searchPaths, usedErrors); + collectErrorUsages(searchPaths, usedErrors, declaredNames); + const unusedErrors = [...declaredErrors].filter(([, [errorName]]) => !usedErrors.has(errorName)); if (unusedErrors.length > 0) { - for (const [errorSig, errorFile] of unusedErrors) - console.error(`Error "${errorSig}" from ${errorFile} is declared but never used.`); + for (const [errorSig, [, filePath]] of unusedErrors) { + console.error(`Error "${errorSig}" from ${filePath} is declared but never used.`); + } process.exit(1); } } } + if (options.check && !hasErrors) console.log("All files are correct."); if (options.fix) console.log("All files have been processed and fixed."); } -main(); +main().catch((e) => { + console.error(e?.message ?? String(e)); + process.exit(1); +}); diff --git a/l1-contracts/scripts/initialize-governance.ts b/l1-contracts/scripts/initialize-governance.ts index 800e2d1175..290cc51bb1 100644 --- a/l1-contracts/scripts/initialize-governance.ts +++ b/l1-contracts/scripts/initialize-governance.ts @@ -7,7 +7,7 @@ import { formatUnits, parseUnits } from "ethers/lib/utils"; import { Deployer } from "../src.ts/deploy"; import { GAS_MULTIPLIER, web3Provider } from "./utils"; import { deployedAddressesFromEnv } from "../src.ts/deploy-utils"; -import { ethTestConfig } from "../src.ts/utils"; +import { ethTestConfig } from "../src.ts/constants"; const provider = web3Provider(); diff --git a/l1-contracts/scripts/initialize-validator.ts b/l1-contracts/scripts/initialize-validator.ts index 30d917eca9..afa846c491 100644 --- a/l1-contracts/scripts/initialize-validator.ts +++ b/l1-contracts/scripts/initialize-validator.ts @@ -6,7 +6,7 @@ import { Wallet } from "ethers"; import { Deployer } from "../src.ts/deploy"; import { formatUnits, parseUnits } from "ethers/lib/utils"; import { GAS_MULTIPLIER, web3Provider } from "./utils"; -import { ethTestConfig } from "../src.ts/utils"; +import { ethTestConfig } from "../src.ts/constants"; const provider = web3Provider(); diff --git a/l1-contracts/scripts/register-zk-chain.ts b/l1-contracts/scripts/register-zk-chain.ts index 49d90c1621..49c2f1c8c2 100644 --- a/l1-contracts/scripts/register-zk-chain.ts +++ b/l1-contracts/scripts/register-zk-chain.ts @@ -8,11 +8,10 @@ import * as fs from "fs"; import * as path from "path"; import { Deployer } from "../src.ts/deploy"; import { GAS_MULTIPLIER, web3Provider } from "./utils"; -import { ADDRESS_ONE, encodeNTVAssetId, isCurrentNetworkLocal } from "../src.ts/utils"; +import { encodeNTVAssetId, isCurrentNetworkLocal } from "../src.ts/utils"; +import { ETH_ADDRESS_IN_CONTRACTS } from "../src.ts/constants"; import { getTokens } from "../src.ts/deploy-token"; -const ETH_TOKEN_ADDRESS = ADDRESS_ONE; - const provider = web3Provider(); const testConfigPath = path.join(process.env.ZKSYNC_HOME as string, "etc/test_config/constant"); const ethTestConfig = JSON.parse(fs.readFileSync(`${testConfigPath}/eth.json`, { encoding: "utf-8" })); @@ -31,7 +30,7 @@ const getTokenAddress = async (name: string) => { // If base token is eth, we are ok, otherwise we need to check if token is deployed const checkTokenAddress = async (address: string) => { - if (address == ETH_TOKEN_ADDRESS) { + if (address == ETH_ADDRESS_IN_CONTRACTS) { return; } else if ((await provider.getCode(address)) == "0x") { throw new Error(`Token ${address} is not deployed`); @@ -48,7 +47,7 @@ const chooseBaseTokenAddress = async (name?: string, address?: string) => { } else if (address) { return address; } else { - return ETH_TOKEN_ADDRESS; + return ETH_ADDRESS_IN_CONTRACTS; } }; @@ -104,7 +103,7 @@ async function main() { if (!(await deployer.bridgehubContract(deployWallet).assetIdIsRegistered(baseTokenAssetId))) { await deployer.registerTokenBridgehub(baseTokenAddress, cmd.useGovernance); } - if (baseTokenAddress != ETH_TOKEN_ADDRESS) { + if (baseTokenAddress != ETH_ADDRESS_IN_CONTRACTS) { await deployer.registerTokenInNativeTokenVault(baseTokenAddress); } await deployer.registerZKChain( diff --git a/l1-contracts/scripts/setup-legacy-bridge-era.ts b/l1-contracts/scripts/setup-legacy-bridge-era.ts index 37eeef9cca..e6d8ff54a2 100644 --- a/l1-contracts/scripts/setup-legacy-bridge-era.ts +++ b/l1-contracts/scripts/setup-legacy-bridge-era.ts @@ -13,7 +13,8 @@ import { Deployer } from "../src.ts/deploy"; import { formatUnits, parseUnits, Interface } from "ethers/lib/utils"; import { web3Provider, GAS_MULTIPLIER } from "./utils"; import { deployedAddressesFromEnv } from "../src.ts/deploy-utils"; -import { ethTestConfig, getAddressFromEnv } from "../src.ts/utils"; +import { ethTestConfig } from "../src.ts/constants"; +import { getAddressFromEnv } from "../src.ts/utils"; import { hashL2Bytecode } from "../../l2-contracts/src/utils"; import { Provider } from "zksync-ethers"; import beaconProxy = require("../../l2-contracts/artifacts-zk/@openzeppelin/contracts-v4/proxy/beacon/BeaconProxy.sol/BeaconProxy.json"); diff --git a/l1-contracts/scripts/upgrade-consistency-checker.ts b/l1-contracts/scripts/upgrade-consistency-checker.ts index 57e6e23098..1d2e311940 100644 --- a/l1-contracts/scripts/upgrade-consistency-checker.ts +++ b/l1-contracts/scripts/upgrade-consistency-checker.ts @@ -337,7 +337,7 @@ async function checkBridgehub() { throw new Error("Bridgehub zkChain is not correct"); } - const sharedBridge = await contract.sharedBridge(); + const sharedBridge = await contract.assetRouter(); if (sharedBridge.toLowerCase() != sharedBridgeProxy.toLowerCase()) { throw new Error("Bridgehub sharedBridge is not correct"); } diff --git a/l1-contracts/selectors b/l1-contracts/selectors index 088e2865e3..c427fc0329 100644 --- a/l1-contracts/selectors +++ b/l1-contracts/selectors @@ -147,9 +147,9 @@ AdminFacet |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurn(address,address,bytes) | 0x64b554ad | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(bytes,bool) | 0x3f42d5dd | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8,bytes32,address,bytes) | 0x75ceffdf | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256,bytes32,address,bytes) | 0xb7846107 | +| Function | forwardedBridgeMint(bytes,bool) | 0x3f42d5dd | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | freezeDiamond() | 0x27ae4c16 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -161,6 +161,8 @@ AdminFacet |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | makePermanentRollup() | 0x6e762e98 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pauseDepositsBeforeInitiatingMigration() | 0x42249f9f | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | prepareChainCommitment() | 0x41cf49bb | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | setDAValidatorPair(address,uint8) | 0x2765d079 | @@ -181,10 +183,16 @@ AdminFacet |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | unfreezeDiamond() | 0x17338945 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unpauseDeposits() | 0x63d8882a | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | upgradeChainFromVersion(uint256,((address,uint8,bool,bytes4[])[],address,bytes)) | 0xfc57565f | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | BridgeMint(address,uint256) | 0x397b33b307fc137878ebfc75b295289ec0ee25a31bb5bf034f33256fe8ea2aa6 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | DepositsPaused(uint256,uint256) | 0xced2f00d0cbddf7694c83a78aae4ecbcfd67ab549e62ef2c307a1502c318228b | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | DepositsUnpaused(uint256) | 0xc60a09282147c879caecd0e606e1282d6c85bb33f3296a45ac82d43cd49c6e24 | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | DiamondCut((address,uint8,bool,bytes4[])[],address,bytes) | 0x87b829356b3403d36217eff1f66ee48eacd0a69015153aba4f0de29fe5340c30 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | EnableEvmEmulator() | 0xe75b499a089224d21f8dd168675c516238b2a0022cf371bdd60e00fcf6980288 | @@ -231,6 +239,10 @@ AdminFacet |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | DenominatorIsZero() | 0x0a8ed92c | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepositsAlreadyPaused() | 0xacf542ab | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepositsNotPaused() | 0xa4d3098c | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | DiamondAlreadyFrozen() | 0x0e7ee319 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | DiamondNotFrozen() | 0xa7151b9a | @@ -259,6 +271,8 @@ AdminFacet |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | L1DAValidatorAddressIsZero() | 0x2e89f517 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MigrationInProgress() | 0xf148c8da | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NoFunctionsForDiamondCut() | 0xa6fef710 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NonEmptyCalldata() | 0xc21b1ab7 | @@ -281,6 +295,8 @@ AdminFacet |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | OutdatedProtocolVersion(uint256,uint256) | 0x681150be | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | PriorityQueueNotFullyProcessed() | 0xfe26193e | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | PriorityTxPubdataExceedsMaxPubDataPerBatch() | 0x1a4d284a | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | ProtocolIdMismatch(uint256,uint256) | 0xa461f651 | @@ -321,9 +337,9 @@ AdminFacetTest |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurn(address,address,bytes) | 0x64b554ad | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(bytes,bool) | 0x3f42d5dd | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8,bytes32,address,bytes) | 0x75ceffdf | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256,bytes32,address,bytes) | 0xb7846107 | +| Function | forwardedBridgeMint(bytes,bool) | 0x3f42d5dd | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | freezeDiamond() | 0x27ae4c16 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -345,6 +361,8 @@ AdminFacetTest |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | makePermanentRollup() | 0x6e762e98 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pauseDepositsBeforeInitiatingMigration() | 0x42249f9f | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | prepareChainCommitment() | 0x41cf49bb | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | setDAValidatorPair(address,uint8) | 0x2765d079 | @@ -365,10 +383,16 @@ AdminFacetTest |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | unfreezeDiamond() | 0x17338945 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unpauseDeposits() | 0x63d8882a | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | upgradeChainFromVersion(uint256,((address,uint8,bool,bytes4[])[],address,bytes)) | 0xfc57565f | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | BridgeMint(address,uint256) | 0x397b33b307fc137878ebfc75b295289ec0ee25a31bb5bf034f33256fe8ea2aa6 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | DepositsPaused(uint256,uint256) | 0xced2f00d0cbddf7694c83a78aae4ecbcfd67ab549e62ef2c307a1502c318228b | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | DepositsUnpaused(uint256) | 0xc60a09282147c879caecd0e606e1282d6c85bb33f3296a45ac82d43cd49c6e24 | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | DiamondCut((address,uint8,bool,bytes4[])[],address,bytes) | 0x87b829356b3403d36217eff1f66ee48eacd0a69015153aba4f0de29fe5340c30 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | EnableEvmEmulator() | 0xe75b499a089224d21f8dd168675c516238b2a0022cf371bdd60e00fcf6980288 | @@ -415,6 +439,10 @@ AdminFacetTest |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | DenominatorIsZero() | 0x0a8ed92c | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepositsAlreadyPaused() | 0xacf542ab | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepositsNotPaused() | 0xa4d3098c | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | DiamondAlreadyFrozen() | 0x0e7ee319 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | DiamondNotFrozen() | 0xa7151b9a | @@ -443,6 +471,8 @@ AdminFacetTest |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | L1DAValidatorAddressIsZero() | 0x2e89f517 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MigrationInProgress() | 0xf148c8da | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NoFunctionsForDiamondCut() | 0xa6fef710 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NonEmptyCalldata() | 0xc21b1ab7 | @@ -465,6 +495,8 @@ AdminFacetTest |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | OutdatedProtocolVersion(uint256,uint256) | 0x681150be | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | PriorityQueueNotFullyProcessed() | 0xfe26193e | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | PriorityTxPubdataExceedsMaxPubDataPerBatch() | 0x1a4d284a | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | ProtocolIdMismatch(uint256,uint256) | 0xa461f651 | @@ -508,8 +540,12 @@ AssetRouterBase |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | assetHandlerAddress(bytes32) | 0x53b9e632 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgehubDepositBaseToken(uint256,bytes32,address,uint256) | 0xc4879440 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | finalizeDeposit(uint256,bytes32,bytes) | 0x9c884fd1 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getDepositCalldata(address,bytes32,bytes) | 0x2ff0b2ea | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | owner() | 0x8da5cb5b | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | pause() | 0x8456cb59 | @@ -549,6 +585,45 @@ AssetRouterBase | Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | ╰----------+---------------------------------------------------------------------+--------------------------------------------------------------------╯ +AssetTrackerBase + +╭----------+-------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++===========================================================================================================================+ +| Function | acceptOwnership() | 0x79ba5097 | +|----------+-------------------------------------------+--------------------------------------------------------------------| +| Function | assetMigrationNumber(uint256,bytes32) | 0x28a31683 | +|----------+-------------------------------------------+--------------------------------------------------------------------| +| Function | chainBalance(uint256,bytes32) | 0x3345359b | +|----------+-------------------------------------------+--------------------------------------------------------------------| +| Function | owner() | 0x8da5cb5b | +|----------+-------------------------------------------+--------------------------------------------------------------------| +| Function | pendingOwner() | 0xe30c3978 | +|----------+-------------------------------------------+--------------------------------------------------------------------| +| Function | registerNewToken(bytes32,uint256) | 0xaa8facf7 | +|----------+-------------------------------------------+--------------------------------------------------------------------| +| Function | renounceOwnership() | 0x715018a6 | +|----------+-------------------------------------------+--------------------------------------------------------------------| +| Function | tokenMigrated(uint256,bytes32) | 0x7c4ed2b6 | +|----------+-------------------------------------------+--------------------------------------------------------------------| +| Function | tokenMigratedThisChain(bytes32) | 0xfc33c15f | +|----------+-------------------------------------------+--------------------------------------------------------------------| +| Function | transferOwnership(address) | 0xf2fde38b | +|----------+-------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+-------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | +|----------+-------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | +╰----------+-------------------------------------------+--------------------------------------------------------------------╯ + +AttributesDecoder + +╭------+-----------+----------╮ +| Type | Signature | Selector | ++=============================+ +╰------+-----------+----------╯ + BaseZkSyncUpgrade ╭----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ @@ -600,6 +675,8 @@ BaseZkSyncUpgrade |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | PubdataGreaterThanLimit(uint256,uint256) | 0x959f26fb | |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SettlementLayerUpgradeMustPrecedeChainUpgrade() | 0x364b6f8b | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | TimeNotReached(uint256,uint256) | 0x08753982 | |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | TooManyFactoryDeps() | 0x76da24b9 | @@ -664,6 +741,8 @@ BaseZkSyncUpgradeGenesis |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | PubdataGreaterThanLimit(uint256,uint256) | 0x959f26fb | |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SettlementLayerUpgradeMustPrecedeChainUpgrade() | 0x364b6f8b | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | TimeNotReached(uint256,uint256) | 0x08753982 | |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | TooManyFactoryDeps() | 0x76da24b9 | @@ -691,6 +770,14 @@ BridgeHelper +=============================+ ╰------+-----------+----------╯ +BridgeHelperTest + +╭----------+------------------------------+------------╮ +| Type | Signature | Selector | ++======================================================+ +| Function | callGetters(address,uint256) | 0x01e0eff7 | +╰----------+------------------------------+------------╯ + BridgedStandardERC20 ╭----------+---------------------------------------------------------------+--------------------------------------------------------------------╮ @@ -804,6 +891,8 @@ BridgehubBase |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainAssetHandler() | 0x70d8af87 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainRegistrationSender() | 0x669e1e46 | +|----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManager(uint256) | 0x9d5bd3da | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManagerIsRegistered(address) | 0xb93c9366 | @@ -816,9 +905,9 @@ BridgehubBase |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurnSetSettlementLayer(uint256,uint256) | 0x0641e4f7 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8) | 0x22409213 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256) | 0x9f115e38 | +| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | getAllZKChainChainIDs() | 0x68b8d331 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -854,7 +943,9 @@ BridgehubBase |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | renounceOwnership() | 0x715018a6 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setAddresses(address,address,address,address) | 0x4a945f8d | +| Function | setAddresses(address,address,address,address,address) | 0x5dd68acd | +|----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setAddressesV30(address) | 0x5cca46f2 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | setCTMAssetAddress(bytes32,address) | 0x2dbcf55f | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -914,7 +1005,7 @@ BridgehubBase |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotChainAssetHandler(address,address) | 0x8beee3a3 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NotCurrentSL(uint256,uint256) | 0xc0ca9182 | +| Error | NotCurrentSettlementLayer() | 0x5e67e793 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | SLNotWhitelisted() | 0x90c7cbf1 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -947,6 +1038,13 @@ BytecodesSupplier | Error | MalformedBytecode(uint8) | 0x43e266b0 | ╰----------+-----------------------------------+--------------------------------------------------------------------╯ +Bytes + +╭------+-----------+----------╮ +| Type | Signature | Selector | ++=============================+ +╰------+-----------+----------╯ + CTMDeploymentTracker ╭----------+----------------------------------------------------------------+--------------------------------------------------------------------╮ @@ -1001,6 +1099,13 @@ CTMDeploymentTracker | Error | WrongCounterPart(address,address) | 0x92626457 | ╰----------+----------------------------------------------------------------+--------------------------------------------------------------------╯ +Calldata + +╭------+-----------+----------╮ +| Type | Signature | Selector | ++=============================+ +╰------+-----------+----------╯ + CalldataDA ╭------+-----------+----------╮ @@ -1126,6 +1231,8 @@ ChainAssetHandlerBase |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | bridgeMint(uint256,bytes32,bytes) | 0x36ba0355 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Function | migrationNumber(uint256) | 0xb2157716 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | migrationPaused() | 0x2a641114 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | owner() | 0x8da5cb5b | @@ -1140,6 +1247,10 @@ ChainAssetHandlerBase |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | renounceOwnership() | 0x715018a6 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Function | setMigrationNumberForV30(uint256) | 0x60c74fc5 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Function | setSettlementLayerChainId(uint256,uint256) | 0x5004dafd | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | transferOwnership(address) | 0xf2fde38b | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | unpause() | 0x3f4ba83a | @@ -1166,19 +1277,31 @@ ChainAssetHandlerBase |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | ChainIdNotRegistered(uint256) | 0x23f3c357 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| -| Error | HyperchainNotRegistered() | 0xeab895aa | -|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | IncorrectChainAssetId(bytes32,bytes32) | 0x48857c1d | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | IncorrectSender(address,address) | 0xf5e39c1f | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | IteratedMigrationsNotSupported() | 0x47d42b1b | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | MigrationNotToL1() | 0x4010a88d | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | MigrationNumberAlreadySet() | 0x12b08c62 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | MigrationNumberMismatch(uint256,uint256) | 0xde1362a2 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | MigrationPaused() | 0x3312a450 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | NonEmptyMsgValue() | 0x536ec84b | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | NotAssetRouter(address,address) | 0xf306a770 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | NotSystemContext(address) | 0xb35a7373 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyChain(address,address) | 0x73fe6c1b | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | SLHasDifferentCTM() | 0x36917565 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | ZKChainNotRegistered() | 0x7b968d06 | ╰----------+-----------------------------------------------------+--------------------------------------------------------------------╯ ChainRegistrar @@ -1229,6 +1352,52 @@ ChainRegistrar | Error | ChainIsNotYetDeployed() | 0x613f7af3 | ╰----------+-------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ +ChainRegistrationSender + +╭----------+--------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++========================================================================================================================================+ +| Function | BRIDGE_HUB() | 0x5d4edca7 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Function | acceptOwnership() | 0x79ba5097 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgehubConfirmL2Transaction(uint256,bytes32,bytes32) | 0x8eb7db57 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgehubDeposit(uint256,address,uint256,bytes) | 0xca408c23 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainRegisteredOnChain(uint256,uint256) | 0x350e5664 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Function | initialize(address) | 0xc4d66de8 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Function | owner() | 0x8da5cb5b | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Function | pendingOwner() | 0xe30c3978 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Function | registerChain(uint256,uint256) | 0x9e14f295 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Function | renounceOwnership() | 0x715018a6 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferOwnership(address) | 0xf2fde38b | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Error | ChainAlreadyRegistered() | 0xb0b5006f | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Error | NoEthAllowed() | 0x7f4316f3 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Error | SlotOccupied() | 0xdf3a8fdd | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Error | Unauthorized(address) | 0x8e4a23d6 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedEncodingVersion() | 0x084a1449 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Error | ZKChainNotRegistered() | 0x7b968d06 | +╰----------+--------------------------------------------------------+--------------------------------------------------------------------╯ + ChainTypeManagerBase ╭----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ @@ -1236,6 +1405,8 @@ ChainTypeManagerBase +================================================================================================================================================================================================================================================+ | Function | BRIDGE_HUB() | 0x5d4edca7 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | INTEROP_CENTER() | 0x5ecd0e3a | +|----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | acceptAdmin() | 0x0e18b681 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | acceptOwnership() | 0x79ba5097 | @@ -1250,9 +1421,9 @@ ChainTypeManagerBase |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurn(uint256,bytes) | 0xf85894c5 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(uint256,bytes) | 0xe8a71ca9 | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8,bytes32,address,bytes) | 0x75ceffdf | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256,bytes32,address,bytes) | 0xb7846107 | +| Function | forwardedBridgeMint(uint256,bytes) | 0xe8a71ca9 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | freezeChain(uint256) | 0xaccdd16c | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -1506,6 +1677,8 @@ DefaultUpgrade |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | PubdataGreaterThanLimit(uint256,uint256) | 0x959f26fb | |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SettlementLayerUpgradeMustPrecedeChainUpgrade() | 0x364b6f8b | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | TimeNotReached(uint256,uint256) | 0x08753982 | |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | TooManyFactoryDeps() | 0x76da24b9 | @@ -1657,23 +1830,23 @@ DiamondCutTestContract DiamondInit -╭----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╮ -| Type | Signature | Selector | -+====================================================================================================================================================================================================================+ -| Function | IS_ZKSYNC_OS() | 0x5556381d | -|----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------| -| Function | initialize((uint256,address,address,uint256,address,address,bytes32,bytes32,address,(bytes32,bytes32,bytes32),bytes32,bytes32,bytes32,uint256,(uint8,uint32,uint32,uint32,uint32,uint64))) | 0x36750357 | -|----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------| -| Error | EmptyAssetId() | 0x2d4d012f | -|----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------| -| Error | EmptyBytes32() | 0x1c25715b | -|----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------| -| Error | SlotOccupied() | 0xdf3a8fdd | -|----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------| -| Error | TooMuchGas() | 0xf0b4e88f | -|----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------| -| Error | ZeroAddress() | 0xd92e233d | -╰----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╯ +╭----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╮ +| Type | Signature | Selector | ++============================================================================================================================================================================================================================+ +| Function | IS_ZKSYNC_OS() | 0x5556381d | +|----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------| +| Function | initialize((uint256,address,address,address,uint256,address,address,bytes32,bytes32,address,(bytes32,bytes32,bytes32),bytes32,bytes32,bytes32,uint256,(uint8,uint32,uint32,uint32,uint32,uint64))) | 0x0f954b0d | +|----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------| +| Error | EmptyAssetId() | 0x2d4d012f | +|----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------| +| Error | EmptyBytes32() | 0x1c25715b | +|----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------| +| Error | SlotOccupied() | 0xdf3a8fdd | +|----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------| +| Error | TooMuchGas() | 0xf0b4e88f | +|----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------| +| Error | ZeroAddress() | 0xd92e233d | +╰----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╯ DiamondProxy @@ -1757,27 +1930,35 @@ DummyAdminFacetNoOverlap DummyBridgehub -╭----------+-----------------------------+------------╮ -| Type | Signature | Selector | -+=====================================================+ -| Function | assetRouter() | 0xbc0aac10 | -|----------+-----------------------------+------------| -| Function | baseTokenAssetId(uint256) | 0xe52db4ca | -|----------+-----------------------------+------------| -| Function | getZKChain(uint256) | 0xe680c4c1 | -|----------+-----------------------------+------------| -| Function | messageRoot() | 0xd4b9f4fa | -|----------+-----------------------------+------------| -| Function | setMessageRoot(address) | 0x70f5c679 | -|----------+-----------------------------+------------| -| Function | setSharedBridge(address) | 0xd0bf6fd4 | -|----------+-----------------------------+------------| -| Function | setZKChain(uint256,address) | 0xce214549 | -|----------+-----------------------------+------------| -| Function | sharedBridge() | 0x38720778 | -|----------+-----------------------------+------------| -| Function | zkChain() | 0x2b3558a6 | -╰----------+-----------------------------+------------╯ +╭----------+-------------------------------+------------╮ +| Type | Signature | Selector | ++=======================================================+ +| Function | assetRouter() | 0xbc0aac10 | +|----------+-------------------------------+------------| +| Function | baseTokenAssetId(uint256) | 0xe52db4ca | +|----------+-------------------------------+------------| +| Function | chainAssetHandler() | 0x70d8af87 | +|----------+-------------------------------+------------| +| Function | getAllZKChainChainIDs() | 0x68b8d331 | +|----------+-------------------------------+------------| +| Function | getZKChain(uint256) | 0xe680c4c1 | +|----------+-------------------------------+------------| +| Function | messageRoot() | 0xd4b9f4fa | +|----------+-------------------------------+------------| +| Function | setChainAssetHandler(address) | 0x22f3a9ba | +|----------+-------------------------------+------------| +| Function | setMessageRoot(address) | 0x70f5c679 | +|----------+-------------------------------+------------| +| Function | setSharedBridge(address) | 0xd0bf6fd4 | +|----------+-------------------------------+------------| +| Function | setZKChain(uint256,address) | 0xce214549 | +|----------+-------------------------------+------------| +| Function | settlementLayer(uint256) | 0x671a7131 | +|----------+-------------------------------+------------| +| Function | sharedBridge() | 0x38720778 | +|----------+-------------------------------+------------| +| Function | zkChain() | 0x2b3558a6 | +╰----------+-------------------------------+------------╯ DummyBridgehubSetter @@ -1810,6 +1991,8 @@ DummyBridgehubSetter |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainAssetHandler() | 0x70d8af87 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainRegistrationSender() | 0x669e1e46 | +|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManager(uint256) | 0x9d5bd3da | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManagerIsRegistered(address) | 0xb93c9366 | @@ -1824,9 +2007,9 @@ DummyBridgehubSetter |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurnSetSettlementLayer(uint256,uint256) | 0x0641e4f7 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8) | 0x22409213 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256) | 0x9f115e38 | +| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | getAllZKChainChainIDs() | 0x68b8d331 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -1862,8 +2045,6 @@ DummyBridgehubSetter |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | registerAlreadyDeployedZKChain(uint256,address) | 0xb5662c5d | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | registerLegacyChain(uint256) | 0x3885a750 | -|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | registerNewZKChain(uint256,address,bool) | 0x7011be85 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | registerSettlementLayer(uint256,bool) | 0xdc8e4b26 | @@ -1876,7 +2057,9 @@ DummyBridgehubSetter |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | requestL2TransactionTwoBridges((uint256,uint256,uint256,uint256,uint256,address,address,uint256,bytes)) | 0x24fd57fb | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setAddresses(address,address,address,address) | 0x4a945f8d | +| Function | setAddresses(address,address,address,address,address) | 0x5dd68acd | +|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setAddressesV30(address) | 0x5cca46f2 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | setCTM(uint256,address) | 0xa52c6753 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -1940,8 +2123,6 @@ DummyBridgehubSetter |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | ChainIdAlreadyExists() | 0x24591d89 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ChainIdAlreadyPresent() | 0xff514c10 | -|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | ChainIdCantBeCurrentChain() | 0x717a1656 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | ChainIdMismatch() | 0xa179f8c9 | @@ -1950,10 +2131,6 @@ DummyBridgehubSetter |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | ChainIdTooBig() | 0x8f620a06 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ChainNotLegacy() | 0x5de72107 | -|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ChainNotPresentInCTM() | 0x4bd4ae07 | -|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | EmptyAssetId() | 0x2d4d012f | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | IncorrectBridgeHubAddress(address) | 0xdd381a4c | @@ -1964,7 +2141,7 @@ DummyBridgehubSetter |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotChainAssetHandler(address,address) | 0x8beee3a3 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NotCurrentSL(uint256,uint256) | 0xc0ca9182 | +| Error | NotCurrentSettlementLayer() | 0x5e67e793 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotInitializedReentrancyGuard() | 0xdd7e3621 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -1998,6 +2175,8 @@ DummyChainTypeManager +================================================================================================================================================================================================================================================+ | Function | BRIDGE_HUB() | 0x5d4edca7 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | INTEROP_CENTER() | 0x5ecd0e3a | +|----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | acceptAdmin() | 0x0e18b681 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | acceptOwnership() | 0x79ba5097 | @@ -2012,9 +2191,9 @@ DummyChainTypeManager |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurn(uint256,bytes) | 0xf85894c5 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(uint256,bytes) | 0xe8a71ca9 | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8,bytes32,address,bytes) | 0x75ceffdf | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256,bytes32,address,bytes) | 0xb7846107 | +| Function | forwardedBridgeMint(uint256,bytes) | 0xe8a71ca9 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | freezeChain(uint256) | 0xaccdd16c | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -2186,6 +2365,8 @@ DummyChainTypeManagerWBH +================================================================================================================================================================================================================================================+ | Function | BRIDGE_HUB() | 0x5d4edca7 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | INTEROP_CENTER() | 0x5ecd0e3a | +|----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | acceptAdmin() | 0x0e18b681 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | acceptOwnership() | 0x79ba5097 | @@ -2200,9 +2381,9 @@ DummyChainTypeManagerWBH |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurn(uint256,bytes) | 0xf85894c5 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(uint256,bytes) | 0xe8a71ca9 | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8,bytes32,address,bytes) | 0x75ceffdf | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256,bytes32,address,bytes) | 0xb7846107 | +| Function | forwardedBridgeMint(uint256,bytes) | 0xe8a71ca9 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | freezeChain(uint256) | 0xaccdd16c | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -2423,6 +2604,24 @@ DummyL1ERC20Bridge | Error | WithdrawalAlreadyFinalized() | 0xae899454 | ╰----------+------------------------------------------------------------------------------+--------------------------------------------------------------------╯ +DummyL2BaseTokenSystemContract + +╭----------+----------------+------------╮ +| Type | Signature | Selector | ++========================================+ +| Function | burnMsgValue() | 0x23c2ec09 | +╰----------+----------------+------------╯ + +DummyL2InteropAccount + +╭----------+--------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++======================================================================================================================+ +| Function | forwardFromIC(address,uint256,bytes) | 0xbf7615c2 | +|----------+--------------------------------------+--------------------------------------------------------------------| +| Event | ReturnMessage(bytes) | 0x231ee08db809f586ce6c6dc556a1f101994079be233540df10e124d2f8411343 | +╰----------+--------------------------------------+--------------------------------------------------------------------╯ + DummyL2InteropRootStorage ╭----------+---------------------------------------------+--------------------------------------------------------------------╮ @@ -2444,9 +2643,47 @@ DummyL2InteropRootStorage |----------+---------------------------------------------+--------------------------------------------------------------------| | Function | pendingMessageRootIdsLength() | 0x04cbb0a7 | |----------+---------------------------------------------+--------------------------------------------------------------------| +| Function | addMessageRoot(uint256,uint256,bytes32[]) | 0x5a81e76e | +|----------+---------------------------------------------+--------------------------------------------------------------------| +| Function | addThisChainMessageRoot(uint256,bytes32[]) | 0xb9a2576b | +|----------+---------------------------------------------+--------------------------------------------------------------------| +| Function | batchNumberFromMsgRoot(bytes32) | 0xa7da44b3 | +|----------+---------------------------------------------+--------------------------------------------------------------------| +| Function | chainIdFromMsgRoot(bytes32) | 0xd8b8c897 | +|----------+---------------------------------------------+--------------------------------------------------------------------| +| Function | msgRootSides(uint256,uint256,uint256) | 0x597c5626 | +|----------+---------------------------------------------+--------------------------------------------------------------------| +| Function | msgRoots(uint256,uint256) | 0x62ad91a8 | +|----------+---------------------------------------------+--------------------------------------------------------------------| +| Function | pendingMessageRootIds(uint256) | 0x6104c3bb | +|----------+---------------------------------------------+--------------------------------------------------------------------| +| Function | pendingMessageRootIdsLength() | 0x04cbb0a7 | +|----------+---------------------------------------------+--------------------------------------------------------------------| | Event | InteropRootAdded(uint256,uint256,bytes32[]) | 0x6b451b8422636e45b93bf7f594fa2c1769d039766c4254a6e7f9c0ee1715cdb0 | +|----------+---------------------------------------------+--------------------------------------------------------------------| +| Event | MessageRootAdded(uint256,uint256,bytes32[]) | 0x7babf8ac53365c6e5c00050edbc6746e49e5731da91313394b21a72a6e4b7733 | ╰----------+---------------------------------------------+--------------------------------------------------------------------╯ +DummyL2L1Messenger + +╭----------+--------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++======================================================================================================================+ +| Function | sendToL1(bytes) | 0x62f84b24 | +|----------+--------------------------------------+--------------------------------------------------------------------| +| Event | L1MessageSent(address,bytes32,bytes) | 0x3a36e47291f4201faf137fab081d92295bce2d53be2c6ca68ba82c7faa9ce241 | +╰----------+--------------------------------------+--------------------------------------------------------------------╯ + +DummyL2StandardTriggerAccount + +╭----------+-----------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=========================================================================================================================================================================================================================+ +| Function | process((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,bytes32[],bytes,bytes)) | 0xe60e94f2 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | MessageNotIncluded2() | 0x52b6aafbfde9b9b6e6f36e68746b093bf095b62bc8c486be65c85a421c14a19d | +╰----------+-----------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ + DummyPlonkVerifier ╭----------+-----------------------------+------------╮ @@ -2528,6 +2765,8 @@ DummyZKChain |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | bridgehubRequestL2TransactionOnGateway(bytes32,uint64) | 0xddcc9eec | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | depositsPaused() | 0x60da3e83 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | finalizeEthWithdrawal(uint256,uint256,uint16,bytes,bytes32[]) | 0x6c0960f9 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | genesisUpgrade(address,bytes,bytes[]) | 0xa3bd0112 | @@ -2540,12 +2779,20 @@ DummyZKChain |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | l2TransactionBaseCost(uint256,uint256,uint256) | 0xb473318e | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pauseDepositsOnGateway(uint256) | 0x3b064e40 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1DepositParamsInclusion((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x685143b9 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL1ToL2TransactionStatus(bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0x042901c7 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1ToL2TransactionStatusShared(uint256,bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0xda24b3ee | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LeafInclusion(uint256,uint256,bytes32,bytes32[]) | 0x7efda2ae | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LeafInclusionShared(uint256,uint256,uint256,bytes32,bytes32[]) | 0x79cf6165 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LeafInclusionSharedRecursive(uint256,uint256,uint256,bytes32,bytes32[],uint256) | 0x353d7128 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LogInclusion(uint256,uint256,(uint8,bool,uint16,address,bytes32,bytes32),bytes32[]) | 0x263b7f8e | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LogInclusionShared(uint256,uint256,uint256,(uint8,bool,uint16,address,bytes32,bytes32),bytes32[]) | 0xe896760d | @@ -2558,7 +2805,7 @@ DummyZKChain |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | requestL2Transaction(address,uint256,bytes,uint256,uint256,bytes[],address) | 0xeb672419 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | requestL2TransactionToGatewayMailbox(uint256,bytes32,uint64) | 0xd0772551 | +| Function | requestL2TransactionToGatewayMailboxWithBalanceChange(uint256,bytes32,uint64,uint256,bool) | 0x07f10660 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | setBaseTokenGasMultiplierPrice(uint128,uint128) | 0x328ef4fe | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -2566,6 +2813,8 @@ DummyZKChain |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | setFeeParams() | 0x47fcedb8 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | DepositsPaused(uint256,uint256) | 0xced2f00d0cbddf7694c83a78aae4ecbcfd67ab549e62ef2c307a1502c318228b | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | NewPriorityRequest(uint256,bytes32,uint64,(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes[]) | 0x4531cd5795773d7101c17bdeb9f5ab7f47d7056017506f937083be5d6e77a382 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | NewPriorityRequestId(uint256,bytes32) | 0x779f441679936c5441b671969f37400b8c3ed0071cb47444431bf985754560df | @@ -2578,6 +2827,10 @@ DummyZKChain |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | BatchNotExecuted(uint256) | 0x2078a6a0 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepositsPaused() | 0xdeeb6943 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepthMoreThanOneForRecursiveMerkleProof() | 0x68d91b49 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | GasPerPubdataMismatch() | 0xc91cf3b1 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | HashedLogIsDefault() | 0xd356e6ba | @@ -2602,6 +2855,8 @@ DummyZKChain |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | MsgValueTooLow(uint256,uint256) | 0xb385a3da | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotAssetRouter(address,address) | 0xf306a770 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotHyperchain() | 0x32ddf9a2 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotInitializedReentrancyGuard() | 0xdd7e3621 | @@ -2612,6 +2867,8 @@ DummyZKChain |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | OnlyEraSupported() | 0xf3ed9dfa | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyGateway() | 0xec76af13 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | PubdataGreaterThanLimit(uint256,uint256) | 0x959f26fb | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | Reentrancy() | 0xab143c06 | @@ -2642,6 +2899,13 @@ DynamicIncrementalMerkle +=============================+ ╰------+-----------+----------╯ +DynamicIncrementalMerkleMemory + +╭------+-----------+----------╮ +| Type | Signature | Selector | ++=============================+ +╰------+-----------+----------╯ + EraChainTypeManager ╭----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ @@ -2649,6 +2913,8 @@ EraChainTypeManager +================================================================================================================================================================================================================================================+ | Function | BRIDGE_HUB() | 0x5d4edca7 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | INTEROP_CENTER() | 0x5ecd0e3a | +|----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | acceptAdmin() | 0x0e18b681 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | acceptOwnership() | 0x79ba5097 | @@ -2663,9 +2929,9 @@ EraChainTypeManager |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurn(uint256,bytes) | 0xf85894c5 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(uint256,bytes) | 0xe8a71ca9 | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8,bytes32,address,bytes) | 0x75ceffdf | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256,bytes32,address,bytes) | 0xb7846107 | +| Function | forwardedBridgeMint(uint256,bytes) | 0xe8a71ca9 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | freezeChain(uint256) | 0xaccdd16c | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -2827,6 +3093,8 @@ EraTestnetVerifier +=====================================================+ | Function | dualVerifier() | 0x1589624d | |----------+-----------------------------+------------| +| Function | isTestnetVerifier() | 0x2f3aa86b | +|----------+-----------------------------+------------| | Function | verificationKeyHash() | 0x9e8945d2 | |----------+-----------------------------+------------| | Function | verify(uint256[],uint256[]) | 0xb864f5a9 | @@ -2971,6 +3239,8 @@ ExecutorFacet |----------+-----------------------------------------------------------+--------------------------------------------------------------------| | Error | RevertedBatchNotAfterNewLastBatch() | 0x9a67c1cb | |----------+-----------------------------------------------------------+--------------------------------------------------------------------| +| Error | SettlementLayerChainIdMismatch() | 0x89935a14 | +|----------+-----------------------------------------------------------+--------------------------------------------------------------------| | Error | SystemLogsSizeTooBig() | 0xae43b424 | |----------+-----------------------------------------------------------+--------------------------------------------------------------------| | Error | TimeNotReached(uint256,uint256) | 0x08753982 | @@ -3115,6 +3385,8 @@ ExecutorProvingTest |----------+-------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | RevertedBatchNotAfterNewLastBatch() | 0x9a67c1cb | |----------+-------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SettlementLayerChainIdMismatch() | 0x89935a14 | +|----------+-------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | SystemLogsSizeTooBig() | 0xae43b424 | |----------+-------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | TimeNotReached(uint256,uint256) | 0x08753982 | @@ -3189,6 +3461,14 @@ FullMerkle +=============================+ ╰------+-----------+----------╯ +FullMerkleMemory + +╭-------+-------------------------------+------------╮ +| Type | Signature | Selector | ++====================================================+ +| Error | InvalidMaxLeafNumber(uint256) | 0x039248e8 | +╰-------+-------------------------------+------------╯ + FullMerkleTest ╭----------+-------------------------------------------+------------╮ @@ -3219,6 +3499,108 @@ FullMerkleTest | Error | MerkleWrongLength(uint256,uint256) | 0x485cfcaa | ╰----------+-------------------------------------------+------------╯ +GWAssetTracker + +╭----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=================================================================================================================================================================================================+ +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | acceptOwnership() | 0x79ba5097 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | assetMigrationNumber(uint256,bytes32) | 0x28a31683 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainBalance(uint256,bytes32) | 0x3345359b | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | confirmMigrationOnGateway((bytes1,bool,uint256,bytes32,uint256,uint256)) | 0xd4d7152a | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | handleChainBalanceIncreaseOnGateway(uint256,bytes32,(bytes1,address,bytes32,uint256,bytes32,uint256,uint256)) | 0x6340bd1e | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initiateGatewayToL1MigrationOnGateway(uint256,bytes32) | 0x043d0488 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | owner() | 0x8da5cb5b | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | parseInteropCall(bytes) | 0xe8eedb62 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | parseTokenData(bytes) | 0x65ed9912 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pendingOwner() | 0xe30c3978 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | processLogsAndMessages(((uint8,bool,uint16,address,bytes32,bytes32)[],bytes[],uint256,uint256,bytes32,bytes32)) | 0xe7ca8589 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | registerNewToken(bytes32,uint256) | 0xaa8facf7 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | renounceOwnership() | 0x715018a6 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | requestPauseDepositsForChain(uint256,uint256) | 0x43f49e6c | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setAddresses(uint256) | 0x6e7f096e | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setLegacySharedBridgeAddress() | 0x7073c96d | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setLegacySharedBridgeAddress(uint256,address) | 0x78691dce | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setLegacySharedBridgeAddressForLocalTesting(uint256,address) | 0xc25b5c7c | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenMigrated(uint256,bytes32) | 0x7c4ed2b6 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenMigratedThisChain(bytes32) | 0xfc33c15f | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferOwnership(address) | 0xf2fde38b | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdMismatch(bytes32,bytes32) | 0x1294e9e1 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ChainIdNotRegistered(uint256) | 0x23f3c357 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InsufficientChainBalance(uint256,bytes32,uint256) | 0x07859b3b | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidAssetId(bytes32) | 0x2e19b556 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidBuiltInContractMessage(uint256,uint256,bytes32) | 0xd24c490f | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidCanonicalTxHash(bytes32) | 0x7ad8c2c9 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidEmptyMessageRoot(bytes32,bytes32) | 0x24ef4f8a | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidFunctionSignature(bytes4) | 0x532a43fc | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidInteropBalanceChange(bytes32) | 0xfbf8ed35 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidInteropCalldata(bytes4) | 0x075aaa80 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidInteropChainId(uint256,uint256) | 0x203d8be5 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidL1AssetRouter(address) | 0xeaa867a8 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidL2ShardId() | 0xe1fe041e | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidMaxLeafNumber(uint256) | 0x039248e8 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidMessage() | 0x6eca2e4b | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidServiceLog() | 0xaca75b50 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | L2WithdrawalMessageWrongLength(uint256) | 0x97e1359e | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerkleWrongIndex(uint256,uint256) | 0x1b582fcf | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ReconstructionMismatch(bytes32,bytes32) | 0x0a6c1a5c | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | RegisterNewTokenNotAllowed() | 0x174996d5 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Unauthorized(address) | 0x8e4a23d6 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedEncodingVersion() | 0x084a1449 | +|----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | WrongMsgLength(uint256,uint256) | 0x61cdb17e | +╰----------+-----------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ + GatewayCTMDeployer ╭----------+------------------------+------------╮ @@ -3275,77 +3657,7 @@ GatewayTransactionFilterer | Error | ZeroAddress() | 0xd92e233d | ╰----------+---------------------------------------------------------------------+--------------------------------------------------------------------╯ -GatewayUpgrade - -╭----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ -| Type | Signature | Selector | -+=========================================================================================================================================================================================================================================================================================================================================+ -| Function | THIS_ADDRESS() | 0x315fff4e | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | upgrade(((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes32,bytes32,bytes32,address,(bytes32,bytes32,bytes32),bytes,bytes,uint256,uint256)) | 0x16ef1303 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | upgradeExternal(((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes32,bytes32,bytes32,address,(bytes32,bytes32,bytes32),bytes,bytes,uint256,uint256)) | 0x0f25577d | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | NewL2BootloaderBytecodeHash(bytes32,bytes32) | 0x271b33af94e3f065ecd8659833e6b1daf851f063700c36ddefefab35d4ce4746 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | NewL2DefaultAccountBytecodeHash(bytes32,bytes32) | 0x36df93a47cc02081d9d8208022ab736fdf98fac566e5fc6f5762bf7666e521f3 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | NewL2EvmEmulatorBytecodeHash(bytes32,bytes32) | 0x23ee925b859027449030409cb326f0931c0aafa5a72a1306ca1ec354e839e639 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | NewProtocolVersion(uint256,uint256) | 0x4235104f56661fe2e9d2f2a460b42766581bc45ce366c6a30a9f86c8a2b371a7 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | NewVerifier(address,address) | 0x2ff4895c300d6993c27f2bb507b4b59d29464dc640af727383451365631ba8b2 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | NewVerifierParams((bytes32,bytes32,bytes32),(bytes32,bytes32,bytes32)) | 0x4c055dbc5f14dcb6e081c9421d9657d950dcd6372f6db0a714b9135171cbc15d | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | UpgradeComplete(uint256,bytes32,((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes32,bytes32,bytes32,address,(bytes32,bytes32,bytes32),bytes,bytes,uint256,uint256)) | 0x6bd09c836cb5c068d0e56c5463173036c9e0664c3c89a09c4b2ea71106abfc37 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | GatewayUpgradeFailed() | 0x388b6f68 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidTxType(uint256) | 0x5cb29523 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidUpgradeTxn(uint8) | 0x5f1aa154 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | L2UpgradeNonceNotEqualToNewProtocolVersion(uint256,uint256) | 0xd2c011d6 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | MalformedBytecode(uint8) | 0x43e266b0 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NewProtocolMajorVersionNotZero() | 0x72ea85ad | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | PatchCantSetUpgradeTxn() | 0xd7f50a9d | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | PatchUpgradeCantSetBootloader() | 0x962fd7d0 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | PatchUpgradeCantSetDefaultAccount() | 0x559cc34e | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | PatchUpgradeCantSetEvmEmulator() | 0xc231eccd | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | PreviousProtocolMajorVersionNotZero() | 0x5c598b60 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | PreviousUpgradeNotCleaned() | 0xa0f47245 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | PreviousUpgradeNotFinalized(bytes32) | 0x101ba748 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ProtocolVersionMinorDeltaTooBig(uint256,uint256) | 0xd328c12a | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ProtocolVersionTooSmall() | 0x88d7b498 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | PubdataGreaterThanLimit(uint256,uint256) | 0x959f26fb | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TimeNotReached(uint256,uint256) | 0x08753982 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TooManyFactoryDeps() | 0x76da24b9 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TooMuchGas() | 0xf0b4e88f | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TxnBodyGasLimitNotEnoughGas() | 0x2e311df8 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ValidateTxnNotEnoughGas() | 0x47b3b145 | -|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ZeroGasPriceL1TxZKsyncOS() | 0xdb60e600 | -╰----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ - -GettersFacet +GettersFacet ╭----------+-------------------------------------------+------------╮ | Type | Signature | Selector | @@ -3604,9 +3916,9 @@ IAdmin |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurn(address,address,bytes) | 0x64b554ad | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(bytes,bool) | 0x3f42d5dd | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8,bytes32,address,bytes) | 0x75ceffdf | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256,bytes32,address,bytes) | 0xb7846107 | +| Function | forwardedBridgeMint(bytes,bool) | 0x3f42d5dd | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | freezeDiamond() | 0x27ae4c16 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -3618,6 +3930,8 @@ IAdmin |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | makePermanentRollup() | 0x6e762e98 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pauseDepositsBeforeInitiatingMigration() | 0x42249f9f | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | prepareChainCommitment() | 0x41cf49bb | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | setDAValidatorPair(address,uint8) | 0x2765d079 | @@ -3638,10 +3952,16 @@ IAdmin |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | unfreezeDiamond() | 0x17338945 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unpauseDeposits() | 0x63d8882a | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | upgradeChainFromVersion(uint256,((address,uint8,bool,bytes4[])[],address,bytes)) | 0xfc57565f | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | BridgeMint(address,uint256) | 0x397b33b307fc137878ebfc75b295289ec0ee25a31bb5bf034f33256fe8ea2aa6 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | DepositsPaused(uint256,uint256) | 0xced2f00d0cbddf7694c83a78aae4ecbcfd67ab549e62ef2c307a1502c318228b | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | DepositsUnpaused(uint256) | 0xc60a09282147c879caecd0e606e1282d6c85bb33f3296a45ac82d43cd49c6e24 | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | EnableEvmEmulator() | 0xe75b499a089224d21f8dd168675c516238b2a0022cf371bdd60e00fcf6980288 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | ExecuteUpgrade(((address,uint8,bool,bytes4[])[],address,bytes)) | 0x1dabfc3f4f6a4e74e19be10cc9d1d8e23db03e415d5d3547a1a7d5eb766513ba | @@ -3675,6 +3995,70 @@ IAdmin | Event | ValidatorStatusUpdate(address,bool) | 0x065b77b53864e46fda3d8986acb51696223d6dde7ced42441eb150bae6d48136 | ╰----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ +IAdminFunction + +╭----------+------------------------------------------------------------------------------------------------------------+------------╮ +| Type | Signature | Selector | ++====================================================================================================================================+ +| Function | addL2WethToStore(address,address,uint256,address) | 0x502af062 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | adminEncodeMulticall(bytes) | 0x928a93ef | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | adminExecuteUpgrade(bytes,address,address,address) | 0xf499bcce | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | adminL1L2Tx(address,uint256,uint256,address,uint256,bytes,address,bool) | 0x2cbfa322 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | adminScheduleUpgrade(address,address,uint256,uint256) | 0x223a26fb | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | chainAdminAcceptAdmin(address,address) | 0x7475e9ea | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | chainSetTokenMultiplierSetter(address,address,address,address) | 0x3839ef4d | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | ecosystemAdminExecuteCalls(bytes,address) | 0x02ddb1b8 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | enableValidator(address,uint256,address,address,bool) | 0xb3bd136c | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | enableValidatorViaGateway(address,uint256,uint256,uint256,address,address,address,bool) | 0x89133991 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | governanceAcceptAdmin(address,address) | 0xa0ed82fa | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | governanceAcceptOwner(address,address) | 0x83eddd19 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | governanceExecuteCalls(bytes,address) | 0x1e2cf987 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | grantGatewayWhitelist(address,uint256,address[],bool) | 0x4133df71 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | initConfig() | 0x620b78f7 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | makePermanentRollup(address,address) | 0xe11a9bd2 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | migrateChainToGateway(address,uint256,uint256,uint256,bytes,address,bool) | 0xa30c9725 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | notifyServerMigrationFromGateway(address,uint256,bool) | 0xfb8718da | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | notifyServerMigrationToGateway(address,uint256,bool) | 0x4a2067f4 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | pauseDepositsBeforeInitiatingMigration(address,uint256,bool) | 0x8e465dc9 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | prepareUpgradeZKChainOnGateway(uint256,uint256,bytes,address,uint256,uint256,address,address,address,bool) | 0x96b98c9e | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | revokeGatewayWhitelist(address,uint256,address,bool) | 0xa3e54db6 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | setDAValidatorPair(address,uint256,address,uint8,bool) | 0xc8fb3685 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | setDAValidatorPairWithGateway(address,uint256,uint256,uint256,address,uint8,address,address,bool) | 0x4836c6be | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | setPubdataPricingMode(address,address,uint8) | 0xb8df6282 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | setTransactionFilterer(address,uint256,address,bool) | 0x3a4000a2 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | startMigrateChainFromGateway(address,uint256,uint256,uint256,bytes,address,bool) | 0x214fbd6f | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | unpauseDeposits(address,uint256,bool) | 0x5202d261 | +|----------+------------------------------------------------------------------------------------------------------------+------------| +| Function | updateValidator(address,address,address,uint256,address,bool) | 0xc4e12219 | +╰----------+------------------------------------------------------------------------------------------------------------+------------╯ + IAssetHandler ╭----------+-----------------------------------------------------+--------------------------------------------------------------------╮ @@ -3696,6 +4080,10 @@ IAssetRouterBase +=====================================================================================================================================================+ | Function | assetHandlerAddress(bytes32) | 0x53b9e632 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgehubDepositBaseToken(uint256,bytes32,address,uint256) | 0xc4879440 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getDepositCalldata(address,bytes32,bytes) | 0x2ff0b2ea | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Event | AssetDeploymentTrackerRegistered(bytes32,bytes32,address) | 0x78d918cd43d6ef25bef97471990c81ebfaa55cc35e696326f6fd05b4c976d5d8 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Event | AssetHandlerRegistered(bytes32,address) | 0x2632cc0d58b0cb1017b99cc0b6cc66ad86440cc0dd923bfdaa294f95ba1b0201 | @@ -3709,6 +4097,62 @@ IAssetRouterBase | Event | DepositFinalizedAssetRouter(uint256,bytes32,bytes) | 0x44eb9a840094a49b3cd0a5205042598a1c08c4e87bafb5760bc2d8efa170c541 | ╰----------+---------------------------------------------------------------------+--------------------------------------------------------------------╯ +IAssetTrackerBase + +╭----------+-----------------------------------+------------╮ +| Type | Signature | Selector | ++===========================================================+ +| Function | chainBalance(uint256,bytes32) | 0x3345359b | +|----------+-----------------------------------+------------| +| Function | registerNewToken(bytes32,uint256) | 0xaa8facf7 | +|----------+-----------------------------------+------------| +| Function | tokenMigrated(uint256,bytes32) | 0x7c4ed2b6 | +|----------+-----------------------------------+------------| +| Function | tokenMigratedThisChain(bytes32) | 0xfc33c15f | +╰----------+-----------------------------------+------------╯ + +IAssetTrackerDataEncoding + +╭----------+---------------------------------------------------------------------------------------------+------------╮ +| Type | Signature | Selector | ++=====================================================================================================================+ +| Function | receiveMigrationOnL1((bytes1,bool,address,uint256,bytes32,uint256,uint256,uint256,uint256)) | 0x8e29043a | +╰----------+---------------------------------------------------------------------------------------------+------------╯ + +IBaseToken + +╭----------+------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++======================================================================================================================================+ +| Function | balanceOf(uint256) | 0x9cc7f708 | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Function | burnMsgValue() | 0x23c2ec09 | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Function | decimals() | 0x313ce567 | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Function | mint(address,uint256) | 0x40c10f19 | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Function | name() | 0x06fdde03 | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Function | symbol() | 0x95d89b41 | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Function | totalSupply() | 0x18160ddd | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferFromTo(address,address,uint256) | 0x579952fc | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Function | withdraw(address) | 0x51cff8d9 | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Function | withdrawWithMessage(address,bytes) | 0x84bc3eb0 | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Event | Mint(address,uint256) | 0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885 | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Event | Transfer(address,address,uint256) | 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Event | Withdrawal(address,address,uint256) | 0x2717ead6b9200dd235aad468c9809ea400fe33ac69b5bfaa6d3e90fc922b6398 | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Event | WithdrawalWithMessage(address,address,uint256,bytes) | 0xc405fe8958410bbaf0c73b7a0c3e20859e86ca168a4c9b0def9c54d2555a306b | +╰----------+------------------------------------------------------+--------------------------------------------------------------------╯ + IBridgedStandardToken ╭----------+-----------------------------------------------+--------------------------------------------------------------------╮ @@ -3758,6 +4202,8 @@ IBridgehubBase |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainAssetHandler() | 0x70d8af87 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainRegistrationSender() | 0x669e1e46 | +|----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManager(uint256) | 0x9d5bd3da | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManagerIsRegistered(address) | 0xb93c9366 | @@ -3770,9 +4216,9 @@ IBridgehubBase |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurnSetSettlementLayer(uint256,uint256) | 0x0641e4f7 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8) | 0x22409213 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256) | 0x9f115e38 | +| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | getAllZKChainChainIDs() | 0x68b8d331 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -3834,8 +4280,6 @@ ICTMDeploymentTracker |----------+----------------------------------------------------------------+------------| | Function | bridgeCheckCounterpartAddress(uint256,bytes32,address,address) | 0x9cc395d0 | |----------+----------------------------------------------------------------+------------| -| Function | bridgehubDeposit(uint256,address,uint256,bytes) | 0xca408c23 | -|----------+----------------------------------------------------------------+------------| | Function | calculateAssetId(address) | 0xb68c104a | |----------+----------------------------------------------------------------+------------| | Function | registerCTMAssetOnL1(address) | 0x2f9db630 | @@ -3896,10 +4340,14 @@ IChainAssetHandler |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | bridgeMint(uint256,bytes32,bytes) | 0x36ba0355 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Function | migrationNumber(uint256) | 0xb2157716 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | migrationPaused() | 0x2a641114 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | pauseMigration() | 0xac700e63 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Function | setMigrationNumberForV30(uint256) | 0x60c74fc5 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | unpauseMigration() | 0xf7c7eb92 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Event | BridgeBurn(uint256,bytes32,address,address,uint256) | 0x1cd02155ad1064c60598a8bd0e4e795d7e7d0a0f3c38aad04d261f1297fb2545 | @@ -3911,6 +4359,16 @@ IChainAssetHandler | Event | MigrationStarted(uint256,bytes32,uint256) | 0xc60eb6d595da5361c68f60aa7c8286b8f73c3a99e9db1818e146c522f512496f | ╰----------+-----------------------------------------------------+--------------------------------------------------------------------╯ +IChainRegistrationSender + +╭----------+--------------------------------+------------╮ +| Type | Signature | Selector | ++========================================================+ +| Function | initialize(address) | 0xc4d66de8 | +|----------+--------------------------------+------------| +| Function | registerChain(uint256,uint256) | 0x9e14f295 | +╰----------+--------------------------------+------------╯ + IChainTypeManager ╭----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ @@ -3928,9 +4386,9 @@ IChainTypeManager |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurn(uint256,bytes) | 0xf85894c5 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(uint256,bytes) | 0xe8a71ca9 | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8,bytes32,address,bytes) | 0x75ceffdf | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256,bytes32,address,bytes) | 0xb7846107 | +| Function | forwardedBridgeMint(uint256,bytes) | 0xe8a71ca9 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | freezeChain(uint256) | 0xaccdd16c | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -4037,19 +4495,21 @@ IContractDeployer IDefaultUpgrade -╭----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╮ -| Type | Signature | Selector | -+=========================================================================================================================================================================================================================================================+ -| Function | upgrade(((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes32,bytes32,bytes32,address,(bytes32,bytes32,bytes32),bytes,bytes,uint256,uint256)) | 0x16ef1303 | -╰----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╯ +╭----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╮ +| Type | Signature | Selector | ++==============================================================================================================================================================================================================================================================+ +| Function | upgrade(((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes32,bytes32,bytes32,address,(bytes32,bytes32,bytes32),bytes,bytes,uint256,uint256)) | 0x16ef1303 | +|----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------| +| Function | upgradeInner(((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes32,bytes32,bytes32,address,(bytes32,bytes32,bytes32),bytes,bytes,uint256,uint256)) | 0xdf084ccb | +╰----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╯ IDiamondInit -╭----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╮ -| Type | Signature | Selector | -+====================================================================================================================================================================================================================+ -| Function | initialize((uint256,address,address,uint256,address,address,bytes32,bytes32,address,(bytes32,bytes32,bytes32),bytes32,bytes32,bytes32,uint256,(uint8,uint32,uint32,uint32,uint32,uint64))) | 0x36750357 | -╰----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╯ +╭----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╮ +| Type | Signature | Selector | ++============================================================================================================================================================================================================================+ +| Function | initialize((uint256,address,address,address,uint256,address,address,bytes32,bytes32,address,(bytes32,bytes32,bytes32),bytes32,bytes32,bytes32,uint256,(uint8,uint32,uint32,uint32,uint32,uint64))) | 0x0f954b0d | +╰----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╯ IEIP7702Checker @@ -4059,6 +4519,42 @@ IEIP7702Checker | Function | isEIP7702Account(address) | 0xad91a89d | ╰----------+---------------------------+------------╯ +IERC7786Attributes + +╭----------+---------------------------+------------╮ +| Type | Signature | Selector | ++===================================================+ +| Function | executionAddress(bytes) | 0x054c031b | +|----------+---------------------------+------------| +| Function | indirectCall(uint256) | 0xc8496ea7 | +|----------+---------------------------+------------| +| Function | interopCallValue(uint256) | 0x54b16529 | +|----------+---------------------------+------------| +| Function | unbundlerAddress(bytes) | 0xb9c86698 | +╰----------+---------------------------+------------╯ + +IERC7786GatewaySource + +╭----------+--------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++========================================================================================================================================+ +| Function | sendMessage(bytes,bytes,bytes[]) | 0xcdfe7f5c | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Function | supportsAttribute(bytes4) | 0xdc680a0f | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Event | MessageSent(bytes32,bytes,bytes,bytes,uint256,bytes[]) | 0x7446eaa0a0dda80670b3bfe972bfbefab659bcfb67abad4e0b64dc4630a70481 | +|----------+--------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedAttribute(bytes4) | 0xe1c9e479 | +╰----------+--------------------------------------------------------+--------------------------------------------------------------------╯ + +IERC7786Recipient + +╭----------+-------------------------------------+------------╮ +| Type | Signature | Selector | ++=============================================================+ +| Function | receiveMessage(bytes32,bytes,bytes) | 0x2432ef26 | +╰----------+-------------------------------------+------------╯ + IExecutor ╭----------+-----------------------------------------------------------+--------------------------------------------------------------------╮ @@ -4087,13 +4583,25 @@ IExecutor | Event | BlocksVerification(uint256,uint256) | 0x22c9005dd88c18b552a1cd7e8b3b937fcde9ca69213c1f658f54d572e4877a81 | ╰----------+-----------------------------------------------------------+--------------------------------------------------------------------╯ -IGatewayUpgrade - -╭----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╮ -| Type | Signature | Selector | -+=================================================================================================================================================================================================================================================================+ -| Function | upgradeExternal(((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes32,bytes32,bytes32,address,(bytes32,bytes32,bytes32),bytes,bytes,uint256,uint256)) | 0x0f25577d | -╰----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------╯ +IGWAssetTracker + +╭----------+-----------------------------------------------------------------------------------------------------------------+------------╮ +| Type | Signature | Selector | ++=========================================================================================================================================+ +| Function | confirmMigrationOnGateway((bytes1,bool,uint256,bytes32,uint256,uint256)) | 0xd4d7152a | +|----------+-----------------------------------------------------------------------------------------------------------------+------------| +| Function | handleChainBalanceIncreaseOnGateway(uint256,bytes32,(bytes1,address,bytes32,uint256,bytes32,uint256,uint256)) | 0x6340bd1e | +|----------+-----------------------------------------------------------------------------------------------------------------+------------| +| Function | initiateGatewayToL1MigrationOnGateway(uint256,bytes32) | 0x043d0488 | +|----------+-----------------------------------------------------------------------------------------------------------------+------------| +| Function | processLogsAndMessages(((uint8,bool,uint16,address,bytes32,bytes32)[],bytes[],uint256,uint256,bytes32,bytes32)) | 0xe7ca8589 | +|----------+-----------------------------------------------------------------------------------------------------------------+------------| +| Function | requestPauseDepositsForChain(uint256,uint256) | 0x43f49e6c | +|----------+-----------------------------------------------------------------------------------------------------------------+------------| +| Function | setAddresses(uint256) | 0x6e7f096e | +|----------+-----------------------------------------------------------------------------------------------------------------+------------| +| Function | setLegacySharedBridgeAddress(uint256,address) | 0x78691dce | +╰----------+-----------------------------------------------------------------------------------------------------------------+------------╯ IGetters @@ -4233,6 +4741,44 @@ IGovernance | Event | TransparentOperationScheduled(bytes32,uint256,((address,uint256,bytes)[],bytes32,bytes32)) | 0x23bc9f5dc037eb49c162fd08c2a4d43dfe70063149e140d502273168da0a0625 | ╰----------+--------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ +IInteropCenter + +╭----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=================================================================================================================================================================================================================+ +| Function | forwardTransactionOnGatewayWithBalanceChange(uint256,bytes32,uint64,(bytes1,address,bytes32,uint256,bytes32,uint256,uint256)) | 0x2d795b0a | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initL2(uint256,address) | 0xa81a1197 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | sendBundle(bytes,(bytes,bytes,bytes[])[],bytes[]) | 0x5ef7e104 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | InteropBundleSent(bytes32,bytes32,(bytes1,uint256,uint256,bytes32,(bytes1,bool,address,address,uint256,bytes)[],(bytes,bytes))) | 0xd5e1642d9c6ff371d1f102384c70a9a38530493e4747a53919f128685013cb6e | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewAssetRouter(address,address) | 0x1a63409548d2d73de3e36cb4138d7a708351257aa35c008250f3d3fe25bdb479 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewAssetTracker(address,address) | 0xaf37ef53531769f84726b9421039fd50511f7d2672288012370502b6b1f34b39 | +╰----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ + +IInteropHandler + +╭----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=================================================================================================================================================================+ +| Function | executeBundle(bytes,(uint256,uint256,uint256,(uint16,address,bytes),bytes32[])) | 0x2949e7b7 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unbundleBundle(uint256,bytes,uint8[]) | 0x98483918 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | verifyBundle(bytes,(uint256,uint256,uint256,(uint16,address,bytes),bytes32[])) | 0x743565a6 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BundleExecuted(bytes32) | 0xdd0fe78c1153f6af3f72afd04381692d6ee5747db36a59c9fec395ad369d3625 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BundleUnbundled(bytes32) | 0xcbcf7285f516f8a98b3ff4620dc76c656cce11fe9902ee012f43814dceb0e0c4 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BundleVerified(bytes32) | 0x2f34edd4f9447fc2e17c3670ad4e71dc46b3bcc01346abdd20d82801d2118c54 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | CallProcessed(bytes32,uint256,uint8) | 0x3cd077a28cf869e00954d27389bcc31fe5b102eab4ebdae82fb94fbdcc375f4a | +╰----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------╯ + IL1AssetDeploymentTracker ╭----------+----------------------------------------------------------------+------------╮ @@ -4243,11 +4789,11 @@ IL1AssetDeploymentTracker IL1AssetHandler -╭----------+------------------------------------------------------------+------------╮ -| Type | Signature | Selector | -+====================================================================================+ -| Function | bridgeRecoverFailedTransfer(uint256,bytes32,address,bytes) | 0xc2e90293 | -╰----------+------------------------------------------------------------+------------╯ +╭----------+------------------------------------------------------------------+------------╮ +| Type | Signature | Selector | ++==========================================================================================+ +| Function | bridgeConfirmTransferResult(uint256,uint8,bytes32,address,bytes) | 0xeead84cd | +╰----------+------------------------------------------------------------------+------------╯ IL1AssetRouter @@ -4262,7 +4808,7 @@ IL1AssetRouter |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | assetHandlerAddress(bytes32) | 0x53b9e632 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeRecoverFailedTransfer(uint256,address,bytes32,bytes) | 0x1346ca3b | +| Function | bridgeConfirmTransferResult(uint256,uint8,address,bytes32,bytes) | 0xdfa1b278 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | bridgeRecoverFailedTransfer(uint256,address,bytes32,bytes,bytes32,uint256,uint256,uint16,bytes32[]) | 0x3601e63e | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -4315,6 +4861,28 @@ IL1AssetRouter | Event | LegacyDepositInitiated(uint256,bytes32,address,address,address,uint256) | 0xa1846a4248529db592da99da276f761d9f37a84d0f3d4e83819b869759000700 | ╰----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ +IL1AssetTracker + +╭----------+--------------------------------------------------------------------------------+------------╮ +| Type | Signature | Selector | ++========================================================================================================+ +| Function | BRIDGE_HUB() | 0x5d4edca7 | +|----------+--------------------------------------------------------------------------------+------------| +| Function | consumeBalanceChange(uint256,uint256) | 0xc359c312 | +|----------+--------------------------------------------------------------------------------+------------| +| Function | handleChainBalanceDecreaseOnL1(uint256,bytes32,uint256,uint256) | 0xbecea300 | +|----------+--------------------------------------------------------------------------------+------------| +| Function | handleChainBalanceIncreaseOnL1(uint256,bytes32,uint256,uint256) | 0xba536c18 | +|----------+--------------------------------------------------------------------------------+------------| +| Function | migrateTokenBalanceFromNTVV30(uint256,bytes32) | 0x8e954d08 | +|----------+--------------------------------------------------------------------------------+------------| +| Function | receiveMigrationOnL1((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x807ac6cf | +|----------+--------------------------------------------------------------------------------+------------| +| Function | requestPauseDepositsForChainOnGateway(uint256,uint256) | 0x53deac5f | +|----------+--------------------------------------------------------------------------------+------------| +| Function | setAddresses() | 0xbc3a429b | +╰----------+--------------------------------------------------------------------------------+------------╯ + IL1BaseTokenAssetHandler ╭----------+-----------------------+------------╮ @@ -4328,6 +4896,8 @@ IL1Bridgehub ╭----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ | Type | Signature | Selector | +=========================================================================================================================================================================================+ +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | acceptAdmin() | 0x0e18b681 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | addChainTypeManager(address) | 0xff5a62a1 | @@ -4346,6 +4916,8 @@ IL1Bridgehub |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainAssetHandler() | 0x70d8af87 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainRegistrationSender() | 0x669e1e46 | +|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManager(uint256) | 0x9d5bd3da | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManagerIsRegistered(address) | 0xb93c9366 | @@ -4360,9 +4932,9 @@ IL1Bridgehub |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurnSetSettlementLayer(uint256,uint256) | 0x0641e4f7 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8) | 0x22409213 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256) | 0x9f115e38 | +| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | getAllZKChainChainIDs() | 0x68b8d331 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -4384,8 +4956,6 @@ IL1Bridgehub |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | registerAlreadyDeployedZKChain(uint256,address) | 0xb5662c5d | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | registerLegacyChain(uint256) | 0x3885a750 | -|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | registerNewZKChain(uint256,address,bool) | 0x7011be85 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | registerSettlementLayer(uint256,bool) | 0xdc8e4b26 | @@ -4423,6 +4993,24 @@ IL1Bridgehub | Event | SettlementLayerRegistered(uint256,bool) | 0x02629feb109d94b16a367231d248ba81c462f51ce5b984835f150f1c9f49ed25 | ╰----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ +IL1ChainAssetHandler + +╭----------+--------------------------------+------------╮ +| Type | Signature | Selector | ++========================================================+ +| Function | isMigrationInProgress(uint256) | 0xd9d1bdee | +╰----------+--------------------------------+------------╯ + +IL1CrossChainSender + +╭----------+--------------------------------------------------------+------------╮ +| Type | Signature | Selector | ++================================================================================+ +| Function | bridgehubConfirmL2Transaction(uint256,bytes32,bytes32) | 0x8eb7db57 | +|----------+--------------------------------------------------------+------------| +| Function | bridgehubDeposit(uint256,address,uint256,bytes) | 0xca408c23 | +╰----------+--------------------------------------------------------+------------╯ + IL1DAValidator ╭----------+------------------------------------------------+------------╮ @@ -4488,14 +5076,24 @@ IL1NativeTokenVault |----------+----------------------------------------------------------------+--------------------------------------------------------------------| | Function | bridgeCheckCounterpartAddress(uint256,bytes32,address,address) | 0x9cc395d0 | |----------+----------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokens(uint256) | 0xc409b8f9 | +|----------+----------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokensCount() | 0x88c6e7d8 | +|----------+----------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainBalance(uint256,bytes32) | 0x3345359b | |----------+----------------------------------------------------------------+--------------------------------------------------------------------| | Function | ensureTokenIsRegistered(address) | 0x19a2a285 | |----------+----------------------------------------------------------------+--------------------------------------------------------------------| | Function | getERC20Getters(address,uint256) | 0xa7236d16 | |----------+----------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l1AssetTracker() | 0x2c1c870c | +|----------+----------------------------------------------------------------+--------------------------------------------------------------------| +| Function | migrateTokenBalanceToAssetTracker(uint256,bytes32) | 0x7d783865 | +|----------+----------------------------------------------------------------+--------------------------------------------------------------------| | Function | originChainId(bytes32) | 0x5f3455b5 | |----------+----------------------------------------------------------------+--------------------------------------------------------------------| +| Function | originToken(bytes32) | 0xb4541499 | +|----------+----------------------------------------------------------------+--------------------------------------------------------------------| | Function | registerEthToken() | 0xcb6da609 | |----------+----------------------------------------------------------------+--------------------------------------------------------------------| | Function | registerToken(address) | 0x09824a80 | @@ -4511,45 +5109,53 @@ IL1NativeTokenVault IL1Nullifier -╭----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ -| Type | Signature | Selector | -+=======================================================================================================================================================================================+ -| Function | BRIDGE_HUB() | 0x5d4edca7 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeRecoverFailedTransfer(uint256,address,bytes32,bytes,bytes32,uint256,uint256,uint16,bytes32[]) | 0x3601e63e | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgehubConfirmL2TransactionForwarded(uint256,bytes32,bytes32) | 0x4bc2c8c0 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainBalance(uint256,address) | 0x9cd45184 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | claimFailedDeposit(uint256,address,address,uint256,bytes32,uint256,uint256,uint16,bytes32[]) | 0xc0991525 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | claimFailedDepositLegacyErc20Bridge(address,address,uint256,bytes32,uint256,uint256,uint16,bytes32[]) | 0x8fbb3711 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | depositHappened(uint256,bytes32) | 0x9fa8826b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | finalizeDeposit((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x74beea82 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | finalizeWithdrawal(uint256,uint256,uint256,uint16,bytes,bytes32[]) | 0xc87325f1 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | isWithdrawalFinalized(uint256,uint256,uint256) | 0x8f31f052 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | l1NativeTokenVault() | 0x6f513211 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | l2BridgeAddress(uint256) | 0x07ee9355 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | legacyBridge() | 0x6e9d7899 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | nullifyChainBalanceByNTV(uint256,address) | 0x5de097b1 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setL1AssetRouter(address) | 0x780ce114 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setL1NativeTokenVault(address) | 0xb7cc6f46 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | transferTokenToNTV(address) | 0x40a434d5 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgehubDepositFinalized(uint256,bytes32,bytes32) | 0xe4def01b981193a97a9e81230d7b9f31812ceaf23f864a828a82c687911cb2df | -╰----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ +╭----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=============================================================================================================================================================================================+ +| Function | BRIDGE_HUB() | 0x5d4edca7 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeConfirmTransferResult((uint256,address,uint16,uint8,bytes32,bytes,bytes32,uint256,uint256,bytes32[])) | 0xc6c7af56 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeRecoverFailedTransfer(uint256,address,bytes32,bytes,bytes32,uint256,uint256,uint16,bytes32[]) | 0x3601e63e | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgehubConfirmL2TransactionForwarded(uint256,bytes32,bytes32) | 0x4bc2c8c0 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainBalance(uint256,address) | 0x9cd45184 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | claimFailedDeposit(uint256,address,address,uint256,bytes32,uint256,uint256,uint16,bytes32[]) | 0xc0991525 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | claimFailedDepositLegacyErc20Bridge(address,address,uint256,bytes32,uint256,uint256,uint16,bytes32[]) | 0x8fbb3711 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | depositHappened(uint256,bytes32) | 0x9fa8826b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | finalizeDeposit((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x74beea82 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | finalizeWithdrawal(uint256,uint256,uint256,uint16,bytes,bytes32[]) | 0xc87325f1 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getTransientSettlementLayer() | 0xf8d6c677 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | isWithdrawalFinalized(uint256,uint256,uint256) | 0x8f31f052 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l1AssetRouter() | 0x6d9860e1 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l1NativeTokenVault() | 0x6f513211 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l2BridgeAddress(uint256) | 0x07ee9355 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | legacyBridge() | 0x6e9d7899 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | nullifyChainBalanceByNTV(uint256,address) | 0x5de097b1 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setL1AssetRouter(address) | 0x780ce114 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setL1NativeTokenVault(address) | 0xb7cc6f46 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferTokenToNTV(address) | 0x40a434d5 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgehubDepositFinalized(uint256,bytes32,bytes32) | 0xe4def01b981193a97a9e81230d7b9f31812ceaf23f864a828a82c687911cb2df | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | TransientSettlementLayerSet(uint256) | 0x9dbae9e6e0031ad5f2814bd78f1347f33a63db5cec1013f279da03ca632a1e1e | +╰----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ IL1SharedBridgeLegacy @@ -4564,12 +5170,20 @@ IL2AssetRouter ╭----------+---------------------------------------------------------------------+--------------------------------------------------------------------╮ | Type | Signature | Selector | +=====================================================================================================================================================+ +| Function | BASE_TOKEN_ASSET_ID() | 0xcb944dec | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | L1_ASSET_ROUTER() | 0xcdf25430 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | assetHandlerAddress(bytes32) | 0x53b9e632 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgehubDepositBaseToken(uint256,bytes32,address,uint256) | 0xc4879440 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | finalizeDepositLegacyBridge(address,address,address,uint256,bytes) | 0x54b2e69c | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getDepositCalldata(address,bytes32,bytes) | 0x2ff0b2ea | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initiateIndirectCall(uint256,address,uint256,bytes) | 0x4d7e3d62 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | setAssetHandlerAddress(uint256,bytes32,address) | 0xda556bdc | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | setLegacyTokenAssetHandler(bytes32) | 0x2ed342aa | @@ -4593,6 +5207,28 @@ IL2AssetRouter | Event | WithdrawalInitiatedAssetRouter(uint256,address,bytes32,bytes) | 0x55362fc62473cb1255e770af5d5e02ba6ee5bc7ed6969c30eb11ca31b92384dc | ╰----------+---------------------------------------------------------------------+--------------------------------------------------------------------╯ +IL2AssetTracker + +╭----------+---------------------------------------------------------------------+------------╮ +| Type | Signature | Selector | ++=============================================================================================+ +| Function | confirmMigrationOnL2((bytes1,bool,uint256,bytes32,uint256,uint256)) | 0x3a5c8caa | +|----------+---------------------------------------------------------------------+------------| +| Function | handleFinalizeBaseTokenBridgingOnL2(uint256) | 0xc7bb6041 | +|----------+---------------------------------------------------------------------+------------| +| Function | handleFinalizeBridgingOnL2(bytes32,uint256,uint256,address) | 0x16e247bf | +|----------+---------------------------------------------------------------------+------------| +| Function | handleInitiateBaseTokenBridgingOnL2(uint256) | 0xd0201254 | +|----------+---------------------------------------------------------------------+------------| +| Function | handleInitiateBridgingOnL2(bytes32,uint256,uint256) | 0xb0e6f1b0 | +|----------+---------------------------------------------------------------------+------------| +| Function | initiateL1ToGatewayMigrationOnL2(bytes32) | 0x42410ced | +|----------+---------------------------------------------------------------------+------------| +| Function | registerLegacyTokenOnChain(bytes32) | 0x9f46bad9 | +|----------+---------------------------------------------------------------------+------------| +| Function | setAddresses(uint256,bytes32) | 0x1bafc42e | +╰----------+---------------------------------------------------------------------+------------╯ + IL2Bridgehub ╭----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ @@ -4616,6 +5252,8 @@ IL2Bridgehub |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainAssetHandler() | 0x70d8af87 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainRegistrationSender() | 0x669e1e46 | +|----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManager(uint256) | 0x9d5bd3da | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManagerIsRegistered(address) | 0xb93c9366 | @@ -4628,9 +5266,9 @@ IL2Bridgehub |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurnSetSettlementLayer(uint256,uint256) | 0x0641e4f7 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8) | 0x22409213 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256) | 0x9f115e38 | +| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | getAllZKChainChainIDs() | 0x68b8d331 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -4650,6 +5288,8 @@ IL2Bridgehub |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2MessageInclusion(uint256,uint256,uint256,(uint16,address,bytes),bytes32[]) | 0x99c16d1a | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | registerChainForInterop(uint256,bytes32) | 0xc4aebf2f | +|----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | registerNewZKChain(uint256,address,bool) | 0x7011be85 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | removeChainTypeManager(address) | 0x332b96dc | @@ -4695,13 +5335,13 @@ IL2ContractDeployer | Function | setAllowedBytecodeTypesToDeploy(uint8) | 0xfe06380c | ╰----------+----------------------------------------------------------------+------------╯ -IL2GatewayUpgrade +IL2CrossChainSender -╭----------+---------------------------------------------------------------------+------------╮ -| Type | Signature | Selector | -+=============================================================================================+ -| Function | upgrade((bytes32,address,bool,uint256,bytes)[],address,bytes,bytes) | 0xff87ffa5 | -╰----------+---------------------------------------------------------------------+------------╯ +╭----------+-----------------------------------------------------+------------╮ +| Type | Signature | Selector | ++=============================================================================+ +| Function | initiateIndirectCall(uint256,address,uint256,bytes) | 0x4d7e3d62 | +╰----------+-----------------------------------------------------+------------╯ IL2GenesisUpgrade @@ -4728,6 +5368,10 @@ IL2NativeTokenVault +======================================================================================================================================+ | Function | assetId(address) | 0xfd3f60df | |----------+------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokens(uint256) | 0xc409b8f9 | +|----------+------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokensCount() | 0x88c6e7d8 | +|----------+------------------------------------------------------+--------------------------------------------------------------------| | Function | ensureTokenIsRegistered(address) | 0x19a2a285 | |----------+------------------------------------------------------+--------------------------------------------------------------------| | Function | getERC20Getters(address,uint256) | 0xa7236d16 | @@ -4736,6 +5380,8 @@ IL2NativeTokenVault |----------+------------------------------------------------------+--------------------------------------------------------------------| | Function | originChainId(bytes32) | 0x5f3455b5 | |----------+------------------------------------------------------+--------------------------------------------------------------------| +| Function | originToken(bytes32) | 0xb4541499 | +|----------+------------------------------------------------------+--------------------------------------------------------------------| | Function | registerToken(address) | 0x09824a80 | |----------+------------------------------------------------------+--------------------------------------------------------------------| | Function | setLegacyTokenAssetId(address) | 0x4cd40a02 | @@ -4831,6 +5477,14 @@ IL2V29Upgrade | Function | upgrade(address,bytes32) | 0xa2367305 | ╰----------+--------------------------+------------╯ +IL2V30Upgrade + +╭----------+--------------------------+------------╮ +| Type | Signature | Selector | ++==================================================+ +| Function | upgrade(uint256,address) | 0x028f4e47 | +╰----------+--------------------------+------------╯ + IL2WETH ╭----------+---------------------------------+--------------------------------------------------------------------╮ @@ -4892,14 +5546,22 @@ IMailbox |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | bridgehubRequestL2TransactionOnGateway(bytes32,uint64) | 0xddcc9eec | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | depositsPaused() | 0x60da3e83 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | finalizeEthWithdrawal(uint256,uint256,uint16,bytes,bytes32[]) | 0x6c0960f9 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | getName() | 0x17d7de7c | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | l2TransactionBaseCost(uint256,uint256,uint256) | 0xb473318e | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pauseDepositsOnGateway(uint256) | 0x3b064e40 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1DepositParamsInclusion((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x685143b9 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL1ToL2TransactionStatus(bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0x042901c7 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1ToL2TransactionStatusShared(uint256,bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0xda24b3ee | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LeafInclusion(uint256,uint256,bytes32,bytes32[]) | 0x7efda2ae | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LeafInclusionShared(uint256,uint256,uint256,bytes32,bytes32[]) | 0x79cf6165 | @@ -4916,7 +5578,7 @@ IMailbox |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | requestL2Transaction(address,uint256,bytes,uint256,uint256,bytes[],address) | 0xeb672419 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | requestL2TransactionToGatewayMailbox(uint256,bytes32,uint64) | 0xd0772551 | +| Function | requestL2TransactionToGatewayMailboxWithBalanceChange(uint256,bytes32,uint64,uint256,bool) | 0x07f10660 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | NewPriorityRequest(uint256,bytes32,uint64,(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes[]) | 0x4531cd5795773d7101c17bdeb9f5ab7f47d7056017506f937083be5d6e77a382 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -4934,12 +5596,16 @@ IMailboxImpl |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | bridgehubRequestL2TransactionOnGateway(bytes32,uint64) | 0xddcc9eec | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | depositsPaused() | 0x60da3e83 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | finalizeEthWithdrawal(uint256,uint256,uint16,bytes,bytes32[]) | 0x6c0960f9 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | getName() | 0x17d7de7c | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | l2TransactionBaseCost(uint256,uint256,uint256) | 0xb473318e | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pauseDepositsOnGateway(uint256) | 0x3b064e40 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL1ToL2TransactionStatus(bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0x042901c7 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LeafInclusion(uint256,uint256,bytes32,bytes32[]) | 0x7efda2ae | @@ -4952,7 +5618,7 @@ IMailboxImpl |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | requestL2Transaction(address,uint256,bytes,uint256,uint256,bytes[],address) | 0xeb672419 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | requestL2TransactionToGatewayMailbox(uint256,bytes32,uint64) | 0xd0772551 | +| Function | requestL2TransactionToGatewayMailboxWithBalanceChange(uint256,bytes32,uint64,uint256,bool) | 0x07f10660 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | NewPriorityRequest(uint256,bytes32,uint64,(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes[]) | 0x4531cd5795773d7101c17bdeb9f5ab7f47d7056017506f937083be5d6e77a382 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -4963,21 +5629,59 @@ IMailboxImpl IMessageRoot -╭----------+-------------------------+------------╮ -| Type | Signature | Selector | -+=================================================+ -| Function | BRIDGE_HUB() | 0x5d4edca7 | -|----------+-------------------------+------------| -| Function | addNewChain(uint256) | 0xd4ce08c2 | -|----------+-------------------------+------------| -| Function | historicalRoot(uint256) | 0x2e9b5cbb | -╰----------+-------------------------+------------╯ +╭----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++==========================================================================================================================================================================================+ +| Function | BRIDGE_HUB() | 0x5d4edca7 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | ERA_GATEWAY_CHAIN_ID() | 0x2b12011d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | addChainBatchRoot(uint256,uint256,bytes32) | 0xfb644fc5 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | addNewChain(uint256,uint256) | 0x66e8a86b | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainBatchRoots(uint256,uint256) | 0x1496c5ce | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | currentChainBatchNumber(uint256) | 0xf688e003 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getProofData(uint256,uint256,uint256,bytes32,bytes32[]) | 0x2f67101d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | historicalRoot(uint256) | 0x2e9b5cbb | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1DepositParamsInclusion((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x685143b9 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1ToL2TransactionStatusShared(uint256,bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0xda24b3ee | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LeafInclusionShared(uint256,uint256,uint256,bytes32,bytes32[]) | 0x79cf6165 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LogInclusionShared(uint256,uint256,uint256,(uint8,bool,uint16,address,bytes32,bytes32),bytes32[]) | 0xe896760d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2MessageInclusionShared(uint256,uint256,uint256,(uint16,address,bytes),bytes32[]) | 0x18b7fc22 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | saveV30UpgradeChainBatchNumber(uint256) | 0xccb740c4 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setMigratingChainBatchRoot(uint256,uint256,uint256) | 0xaa1253a5 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | v30UpgradeChainBatchNumber(uint256) | 0xc44da6ef | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | AddedChain(uint256,uint256) | 0x5d96eda109bfd71cf9f4f70c83de31c4150760e8828979a95d9e5f9f15455af7 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | AppendedChainBatchRoot(uint256,uint256,bytes32) | 0x4f7fd9ed016150a623d5a2cf43053fe313a56293a77e060a05db49ed22579520 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewChainRoot(uint256,bytes32,bytes32) | 0x55f052ace108bbb0a540b328ff35be177a5c1d1f6e1e1adb46c1fa4bdaa69c10 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewInteropRoot(uint256,uint256,uint256,bytes32[]) | 0x94a4617be5e5655b97e5cf28ad2038cdc6ae3325b7940f0da8418aac8516a11f | +╰----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ IMessageVerification ╭----------+----------------------------------------------------------------------------------------------------------+------------╮ | Type | Signature | Selector | +==================================================================================================================================+ +| Function | proveL1DepositParamsInclusion((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x685143b9 | +|----------+----------------------------------------------------------------------------------------------------------+------------| +| Function | proveL1ToL2TransactionStatusShared(uint256,bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0xda24b3ee | +|----------+----------------------------------------------------------------------------------------------------------+------------| | Function | proveL2LeafInclusionShared(uint256,uint256,uint256,bytes32,bytes32[]) | 0x79cf6165 | |----------+----------------------------------------------------------------------------------------------------------+------------| | Function | proveL2LogInclusionShared(uint256,uint256,uint256,(uint8,bool,uint16,address,bytes32,bytes32),bytes32[]) | 0xe896760d | @@ -4992,12 +5696,18 @@ INativeTokenVaultBase +=============================================================================================================================+ | Function | assetId(address) | 0xfd3f60df | |----------+---------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokens(uint256) | 0xc409b8f9 | +|----------+---------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokensCount() | 0x88c6e7d8 | +|----------+---------------------------------------------+--------------------------------------------------------------------| | Function | ensureTokenIsRegistered(address) | 0x19a2a285 | |----------+---------------------------------------------+--------------------------------------------------------------------| | Function | getERC20Getters(address,uint256) | 0xa7236d16 | |----------+---------------------------------------------+--------------------------------------------------------------------| | Function | originChainId(bytes32) | 0x5f3455b5 | |----------+---------------------------------------------+--------------------------------------------------------------------| +| Function | originToken(bytes32) | 0xb4541499 | +|----------+---------------------------------------------+--------------------------------------------------------------------| | Function | registerToken(address) | 0x09824a80 | |----------+---------------------------------------------+--------------------------------------------------------------------| | Function | tokenAddress(bytes32) | 0x97bb3ce9 | @@ -5047,45 +5757,45 @@ IRestriction ISystemContext -╭----------+--------------------------------+------------╮ -| Type | Signature | Selector | -+========================================================+ -| Function | baseFee() | 0x6ef25c3a | -|----------+--------------------------------+------------| -| Function | blockGasLimit() | 0x7877a797 | -|----------+--------------------------------+------------| -| Function | chainId() | 0x9a8a0592 | -|----------+--------------------------------+------------| -| Function | coinbase() | 0xa6ae0aac | -|----------+--------------------------------+------------| -| Function | difficulty() | 0x19cae462 | -|----------+--------------------------------+------------| -| Function | gasPerPubdataByte() | 0x7cb9357e | -|----------+--------------------------------+------------| -| Function | gasPrice() | 0xfe173b97 | -|----------+--------------------------------+------------| -| Function | getBatchHash(uint256) | 0xddeaa8e6 | -|----------+--------------------------------+------------| -| Function | getBatchNumberAndTimestamp() | 0xd0f2c663 | -|----------+--------------------------------+------------| -| Function | getBlockHashEVM(uint256) | 0x80b41246 | -|----------+--------------------------------+------------| -| Function | getBlockNumber() | 0x42cbb15c | -|----------+--------------------------------+------------| -| Function | getBlockTimestamp() | 0x796b89b9 | -|----------+--------------------------------+------------| -| Function | getCurrentPubdataSpent() | 0xc0d5b949 | -|----------+--------------------------------+------------| -| Function | getL2BlockNumberAndTimestamp() | 0x8e8acf87 | -|----------+--------------------------------+------------| -| Function | origin() | 0x938b5f32 | -|----------+--------------------------------+------------| -| Function | setChainId(uint256) | 0xef0e2ff4 | -|----------+--------------------------------+------------| -| Function | txNumberInBlock() | 0x8ac84c0e | -|----------+--------------------------------+------------| -| Function | setChainId(uint256) | 0xef0e2ff4 | -╰----------+--------------------------------+------------╯ +╭----------+---------------------------------+------------╮ +| Type | Signature | Selector | ++=========================================================+ +| Function | baseFee() | 0x6ef25c3a | +|----------+---------------------------------+------------| +| Function | blockGasLimit() | 0x7877a797 | +|----------+---------------------------------+------------| +| Function | chainId() | 0x9a8a0592 | +|----------+---------------------------------+------------| +| Function | coinbase() | 0xa6ae0aac | +|----------+---------------------------------+------------| +| Function | currentSettlementLayerChainId() | 0x9413cd32 | +|----------+---------------------------------+------------| +| Function | difficulty() | 0x19cae462 | +|----------+---------------------------------+------------| +| Function | gasPerPubdataByte() | 0x7cb9357e | +|----------+---------------------------------+------------| +| Function | gasPrice() | 0xfe173b97 | +|----------+---------------------------------+------------| +| Function | getBatchHash(uint256) | 0xddeaa8e6 | +|----------+---------------------------------+------------| +| Function | getBatchNumberAndTimestamp() | 0xd0f2c663 | +|----------+---------------------------------+------------| +| Function | getBlockHashEVM(uint256) | 0x80b41246 | +|----------+---------------------------------+------------| +| Function | getBlockNumber() | 0x42cbb15c | +|----------+---------------------------------+------------| +| Function | getBlockTimestamp() | 0x796b89b9 | +|----------+---------------------------------+------------| +| Function | getCurrentPubdataSpent() | 0xc0d5b949 | +|----------+---------------------------------+------------| +| Function | getL2BlockNumberAndTimestamp() | 0x8e8acf87 | +|----------+---------------------------------+------------| +| Function | origin() | 0x938b5f32 | +|----------+---------------------------------+------------| +| Function | setChainId(uint256) | 0xef0e2ff4 | +|----------+---------------------------------+------------| +| Function | txNumberInBlock() | 0x8ac84c0e | +╰----------+---------------------------------+------------╯ ISystemContractProxy @@ -5238,6 +5948,8 @@ IZKChain |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | commitBatchesSharedBridge(address,uint256,uint256,bytes) | 0x0db9eb87 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | depositsPaused() | 0x60da3e83 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | executeBatchesSharedBridge(address,uint256,uint256,bytes) | 0xa085344d | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | executeUpgrade(((address,uint8,bool,bytes4[])[],address,bytes)) | 0xa9f6d941 | @@ -5254,9 +5966,9 @@ IZKChain |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurn(address,address,bytes) | 0x64b554ad | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(bytes,bool) | 0x3f42d5dd | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8,bytes32,address,bytes) | 0x75ceffdf | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256,bytes32,address,bytes) | 0xb7846107 | +| Function | forwardedBridgeMint(bytes,bool) | 0x3f42d5dd | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | freezeDiamond() | 0x27ae4c16 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -5342,14 +6054,22 @@ IZKChain |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | makePermanentRollup() | 0x6e762e98 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pauseDepositsBeforeInitiatingMigration() | 0x42249f9f | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pauseDepositsOnGateway(uint256) | 0x3b064e40 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | precommitSharedBridge(address,uint256,bytes) | 0x0b6db820 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | prepareChainCommitment() | 0x41cf49bb | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveBatchesSharedBridge(address,uint256,uint256,bytes) | 0x9271e450 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1DepositParamsInclusion((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x685143b9 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL1ToL2TransactionStatus(bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0x042901c7 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1ToL2TransactionStatusShared(uint256,bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0xda24b3ee | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LeafInclusion(uint256,uint256,bytes32,bytes32[]) | 0x7efda2ae | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LeafInclusionShared(uint256,uint256,uint256,bytes32,bytes32[]) | 0x79cf6165 | @@ -5366,7 +6086,7 @@ IZKChain |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | requestL2Transaction(address,uint256,bytes,uint256,uint256,bytes[],address) | 0xeb672419 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | requestL2TransactionToGatewayMailbox(uint256,bytes32,uint64) | 0xd0772551 | +| Function | requestL2TransactionToGatewayMailboxWithBalanceChange(uint256,bytes32,uint64,uint256,bool) | 0x07f10660 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | revertBatchesSharedBridge(address,uint256) | 0x7ca4eff7 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -5390,6 +6110,8 @@ IZKChain |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | unfreezeDiamond() | 0x17338945 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unpauseDeposits() | 0x63d8882a | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | upgradeChainFromVersion(uint256,((address,uint8,bool,bytes4[])[],address,bytes)) | 0xfc57565f | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | BatchPrecommitmentSet(uint256,uint256,bytes32) | 0xfea115cea8c7414dc6c05dfb20821e4ea72c37b91e666a90ab4ddb5eabade850 | @@ -5404,6 +6126,10 @@ IZKChain |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | BridgeMint(address,uint256) | 0x397b33b307fc137878ebfc75b295289ec0ee25a31bb5bf034f33256fe8ea2aa6 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | DepositsPaused(uint256,uint256) | 0xced2f00d0cbddf7694c83a78aae4ecbcfd67ab549e62ef2c307a1502c318228b | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | DepositsUnpaused(uint256) | 0xc60a09282147c879caecd0e606e1282d6c85bb33f3296a45ac82d43cd49c6e24 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | EnableEvmEmulator() | 0xe75b499a089224d21f8dd168675c516238b2a0022cf371bdd60e00fcf6980288 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | ExecuteUpgrade(((address,uint8,bool,bytes4[])[],address,bytes)) | 0x1dabfc3f4f6a4e74e19be10cc9d1d8e23db03e415d5d3547a1a7d5eb766513ba | @@ -5463,21 +6189,196 @@ IZKOSContractDeployer IncrementalMerkleTest -╭----------+----------------+------------╮ -| Type | Signature | Selector | -+========================================+ -| Function | height() | 0x0ef26743 | -|----------+----------------+------------| -| Function | index() | 0x2986c0e5 | -|----------+----------------+------------| -| Function | push(bytes32) | 0xb298e36b | -|----------+----------------+------------| -| Function | root() | 0xebf0c717 | -|----------+----------------+------------| -| Function | side(uint256) | 0x7890e5da | -|----------+----------------+------------| -| Function | zeros(uint256) | 0xe8295588 | -╰----------+----------------+------------╯ +╭----------+-------------------------+------------╮ +| Type | Signature | Selector | ++=================================================+ +| Function | clear() | 0x52efea6e | +|----------+-------------------------+------------| +| Function | extendUntilEnd(uint256) | 0x8f1764de | +|----------+-------------------------+------------| +| Function | height() | 0x0ef26743 | +|----------+-------------------------+------------| +| Function | index() | 0x2986c0e5 | +|----------+-------------------------+------------| +| Function | push(bytes32) | 0xb298e36b | +|----------+-------------------------+------------| +| Function | reset(bytes32) | 0xed3c7d40 | +|----------+-------------------------+------------| +| Function | root() | 0xebf0c717 | +|----------+-------------------------+------------| +| Function | side(uint256) | 0x7890e5da | +|----------+-------------------------+------------| +| Function | sidesLength() | 0xfec7727d | +|----------+-------------------------+------------| +| Function | zeros(uint256) | 0xe8295588 | +|----------+-------------------------+------------| +| Function | zerosLength() | 0xc8ffb6d2 | +╰----------+-------------------------+------------╯ + +InteropCenter + +╭----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=================================================================================================================================================================================================================+ +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | acceptOwnership() | 0x79ba5097 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | forwardTransactionOnGatewayWithBalanceChange(uint256,bytes32,uint64,(bytes1,address,bytes32,uint256,bytes32,uint256,uint256)) | 0x2d795b0a | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initL2(uint256,address) | 0xa81a1197 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | interopBundleNonce(address) | 0x5e4217e1 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | owner() | 0x8da5cb5b | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | parseAttributes(bytes[],uint8) | 0x7df96ccd | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pause() | 0x8456cb59 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | paused() | 0x5c975abb | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pendingOwner() | 0xe30c3978 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | renounceOwnership() | 0x715018a6 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | sendBundle(bytes,(bytes,bytes,bytes[])[],bytes[]) | 0x5ef7e104 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | sendMessage(bytes,bytes,bytes[]) | 0xcdfe7f5c | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | supportsAttribute(bytes4) | 0xdc680a0f | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferOwnership(address) | 0xf2fde38b | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unpause() | 0x3f4ba83a | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | InteropBundleSent(bytes32,bytes32,(bytes1,uint256,uint256,bytes32,(bytes1,bool,address,address,uint256,bytes)[],(bytes,bytes))) | 0xd5e1642d9c6ff371d1f102384c70a9a38530493e4747a53919f128685013cb6e | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | MessageSent(bytes32,bytes,bytes,bytes,uint256,bytes[]) | 0x7446eaa0a0dda80670b3bfe972bfbefab659bcfb67abad4e0b64dc4630a70481 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewAssetRouter(address,address) | 0x1a63409548d2d73de3e36cb4138d7a708351257aa35c008250f3d3fe25bdb479 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewAssetTracker(address,address) | 0xaf37ef53531769f84726b9421039fd50511f7d2672288012370502b6b1f34b39 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AttributeAlreadySet(bytes4) | 0x9031f751 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AttributeViolatesRestriction(bytes4,uint256) | 0xbcb41ec7 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | IndirectCallValueMismatch(uint256,uint256) | 0x62d214aa | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InteroperableAddressChainReferenceNotEmpty(bytes) | 0xfe8b1b16 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InteroperableAddressNotEmpty(bytes) | 0x884f49ba | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InteroperableAddressParsingError(bytes) | 0xe7c8d4cf | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MsgValueMismatch(uint256,uint256) | 0x4a094431 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotInGatewayMode() | 0x472477e2 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotL2ToL2(uint256,uint256) | 0xc5441a63 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SlotOccupied() | 0xdf3a8fdd | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Unauthorized(address) | 0x8e4a23d6 | +|----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedAttribute(bytes4) | 0xe1c9e479 | +╰----------+---------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ + +InteropDataEncoding + +╭------+-----------+----------╮ +| Type | Signature | Selector | ++=============================+ +╰------+-----------+----------╯ + +InteropHandler + +╭----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=================================================================================================================================================================+ +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bundleStatus(bytes32) | 0x7e4fbbde | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | callStatus(bytes32,uint256) | 0xaac0ac46 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | executeBundle(bytes,(uint256,uint256,uint256,(uint16,address,bytes),bytes32[])) | 0x2949e7b7 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initL2(uint256) | 0xfdf736a3 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | receiveMessage(bytes32,bytes,bytes) | 0x2432ef26 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unbundleBundle(uint256,bytes,uint8[]) | 0x98483918 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | verifyBundle(bytes,(uint256,uint256,uint256,(uint16,address,bytes),bytes32[])) | 0x743565a6 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BundleExecuted(bytes32) | 0xdd0fe78c1153f6af3f72afd04381692d6ee5747db36a59c9fec395ad369d3625 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BundleUnbundled(bytes32) | 0xcbcf7285f516f8a98b3ff4620dc76c656cce11fe9902ee012f43814dceb0e0c4 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BundleVerified(bytes32) | 0x2f34edd4f9447fc2e17c3670ad4e71dc46b3bcc01346abdd20d82801d2118c54 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | CallProcessed(bytes32,uint256,uint8) | 0x3cd077a28cf869e00954d27389bcc31fe5b102eab4ebdae82fb94fbdcc375f4a | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | BundleAlreadyProcessed(bytes32) | 0x5bba5111 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | BundleVerifiedAlready(bytes32) | 0xa43d2953 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | CallAlreadyExecuted(bytes32,uint256) | 0xd5c7a376 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | CallNotExecutable(bytes32,uint256) | 0xc087b727 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | CanNotUnbundle(bytes32) | 0xf729f26d | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ExecutingNotAllowed(bytes32,bytes,bytes) | 0xe845be4c | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InteroperableAddressParsingError(bytes) | 0xe7c8d4cf | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidSelector(bytes4) | 0x12ba286f | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MessageNotIncluded() | 0x32c2e156 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotInGatewayMode() | 0x472477e2 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotInitializedReentrancyGuard() | 0xdd7e3621 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Reentrancy() | 0xab143c06 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SlotOccupied() | 0xdf3a8fdd | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Unauthorized(address) | 0x8e4a23d6 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnauthorizedMessageSender(address,address) | 0x89fd2c76 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnbundlingNotAllowed(bytes32,bytes,bytes) | 0x0345c281 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | WrongCallStatusLength(uint256,uint256) | 0x801534e9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | WrongDestinationChainId(bytes32,uint256,uint256) | 0x4534e972 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | WrongSourceChainId(bytes32,uint256,uint256) | 0x534ab1b2 | +╰----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------╯ + +InteroperableAddress + +╭-------+------------------------------------------------+------------╮ +| Type | Signature | Selector | ++=====================================================================+ +| Error | InteroperableAddressEmptyReferenceAndAddress() | 0x703474a1 | +|-------+------------------------------------------------+------------| +| Error | InteroperableAddressParsingError(bytes) | 0xe7c8d4cf | +╰-------+------------------------------------------------+------------╯ L1AssetRouter @@ -5502,7 +6403,7 @@ L1AssetRouter |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | assetHandlerAddress(bytes32) | 0x53b9e632 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeRecoverFailedTransfer(uint256,address,bytes32,bytes) | 0x1346ca3b | +| Function | bridgeConfirmTransferResult(uint256,uint8,address,bytes32,bytes) | 0xdfa1b278 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | bridgeRecoverFailedTransfer(uint256,address,bytes32,bytes,bytes32,uint256,uint256,uint16,bytes32[]) | 0x3601e63e | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -5594,6 +6495,8 @@ L1AssetRouter |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | AssetIdNotSupported(bytes32) | 0x04a0b7e9 | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | BadTransferDataLength() | 0x9b821ed7 | +|----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | IncorrectTokenAddressFromNTV(bytes32,address) | 0x1929b7de | |----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | InvalidNTVBurnData() | 0xde4c0b96 | @@ -5623,6 +6526,106 @@ L1AssetRouter | Error | ZeroAddress() | 0xd92e233d | ╰----------+-----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ +L1AssetTracker + +╭----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++================================================================================================================================================================+ +| Function | BRIDGE_HUB() | 0x5d4edca7 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L1_NULLIFIER() | 0xe60ccaba | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | MESSAGE_ROOT() | 0x26ce0686 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | NATIVE_TOKEN_VAULT() | 0x5aa6fa1f | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | acceptOwnership() | 0x79ba5097 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | assetMigrationNumber(uint256,bytes32) | 0x28a31683 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainAssetHandler() | 0x70d8af87 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainBalance(uint256,bytes32) | 0x3345359b | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | consumeBalanceChange(uint256,uint256) | 0xc359c312 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | handleChainBalanceDecreaseOnL1(uint256,bytes32,uint256,uint256) | 0xbecea300 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | handleChainBalanceIncreaseOnL1(uint256,bytes32,uint256,uint256) | 0xba536c18 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initialize(address) | 0xc4d66de8 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | migrateTokenBalanceFromNTVV30(uint256,bytes32) | 0x8e954d08 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | owner() | 0x8da5cb5b | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pendingOwner() | 0xe30c3978 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | receiveMigrationOnL1((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x807ac6cf | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | registerNewToken(bytes32,uint256) | 0xaa8facf7 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | renounceOwnership() | 0x715018a6 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | requestPauseDepositsForChainOnGateway(uint256,uint256) | 0x53deac5f | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setAddresses() | 0xbc3a429b | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenMigrated(uint256,bytes32) | 0x7c4ed2b6 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenMigratedThisChain(bytes32) | 0xfc33c15f | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferOwnership(address) | 0xf2fde38b | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdMismatch(bytes32,bytes32) | 0x1294e9e1 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InsufficientChainBalance(uint256,bytes32,uint256) | 0x07859b3b | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidAssetMigrationNumber() | 0x95bddd6c | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidChainId() | 0x7a47c9a2 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidChainMigrationNumber(uint256,uint256) | 0x05208b6d | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidFunctionSignature(bytes4) | 0x532a43fc | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidMigrationNumber(uint256,uint256) | 0x9530c5e1 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidProof() | 0x09bde339 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidSender() | 0xddb5de5e | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidSettlementLayer() | 0xd0f0bff7 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidVersion() | 0xa9146eeb | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidWithdrawalChainId() | 0xf76b228a | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | L1TotalSupplyAlreadyMigrated() | 0xa16d8a80 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotMigratedChain() | 0x8dfed13a | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyWhitelistedSettlementLayer(address,address) | 0x0fd3385e | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SlotOccupied() | 0xdf3a8fdd | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TransientBalanceChangeAlreadySet(uint256,uint256) | 0x03a5ba47 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Unauthorized(address) | 0x8e4a23d6 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | V30UpgradeChainBatchNumberNotSet() | 0x862f0039 | +|----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ZeroAddress() | 0xd92e233d | +╰----------+--------------------------------------------------------------------------------+--------------------------------------------------------------------╯ + L1Bridgehub ╭----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ @@ -5654,6 +6657,8 @@ L1Bridgehub |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainAssetHandler() | 0x70d8af87 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainRegistrationSender() | 0x669e1e46 | +|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManager(uint256) | 0x9d5bd3da | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManagerIsRegistered(address) | 0xb93c9366 | @@ -5668,9 +6673,9 @@ L1Bridgehub |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurnSetSettlementLayer(uint256,uint256) | 0x0641e4f7 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8) | 0x22409213 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256) | 0x9f115e38 | +| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | getAllZKChainChainIDs() | 0x68b8d331 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -5706,8 +6711,6 @@ L1Bridgehub |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | registerAlreadyDeployedZKChain(uint256,address) | 0xb5662c5d | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | registerLegacyChain(uint256) | 0x3885a750 | -|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | registerNewZKChain(uint256,address,bool) | 0x7011be85 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | registerSettlementLayer(uint256,bool) | 0xdc8e4b26 | @@ -5720,7 +6723,9 @@ L1Bridgehub |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | requestL2TransactionTwoBridges((uint256,uint256,uint256,uint256,uint256,address,address,uint256,bytes)) | 0x24fd57fb | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setAddresses(address,address,address,address) | 0x4a945f8d | +| Function | setAddresses(address,address,address,address,address) | 0x5dd68acd | +|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setAddressesV30(address) | 0x5cca46f2 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | setCTMAssetAddress(bytes32,address) | 0x2dbcf55f | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -5780,8 +6785,6 @@ L1Bridgehub |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | ChainIdAlreadyExists() | 0x24591d89 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ChainIdAlreadyPresent() | 0xff514c10 | -|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | ChainIdCantBeCurrentChain() | 0x717a1656 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | ChainIdMismatch() | 0xa179f8c9 | @@ -5790,10 +6793,6 @@ L1Bridgehub |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | ChainIdTooBig() | 0x8f620a06 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ChainNotLegacy() | 0x5de72107 | -|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ChainNotPresentInCTM() | 0x4bd4ae07 | -|----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | EmptyAssetId() | 0x2d4d012f | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | IncorrectBridgeHubAddress(address) | 0xdd381a4c | @@ -5804,7 +6803,7 @@ L1Bridgehub |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotChainAssetHandler(address,address) | 0x8beee3a3 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NotCurrentSL(uint256,uint256) | 0xc0ca9182 | +| Error | NotCurrentSettlementLayer() | 0x5e67e793 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotInitializedReentrancyGuard() | 0xdd7e3621 | |----------+---------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -5833,85 +6832,105 @@ L1Bridgehub L1ChainAssetHandler -╭----------+------------------------------------------------------------+--------------------------------------------------------------------╮ -| Type | Signature | Selector | -+============================================================================================================================================+ -| Function | ASSET_ROUTER() | 0xc6a70bbb | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | BRIDGEHUB() | 0x1657ec18 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | ETH_TOKEN_ASSET_ID() | 0x81eccdd4 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | L1_CHAIN_ID() | 0x2f90b184 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | MESSAGE_ROOT() | 0x26ce0686 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | acceptOwnership() | 0x79ba5097 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeBurn(uint256,uint256,bytes32,address,bytes) | 0x699b0fb9 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeMint(uint256,bytes32,bytes) | 0x36ba0355 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeRecoverFailedTransfer(uint256,bytes32,address,bytes) | 0xc2e90293 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | initialize(address) | 0xc4d66de8 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | migrationPaused() | 0x2a641114 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | owner() | 0x8da5cb5b | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pause() | 0x8456cb59 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pauseMigration() | 0xac700e63 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | paused() | 0x5c975abb | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pendingOwner() | 0xe30c3978 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | renounceOwnership() | 0x715018a6 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | transferOwnership(address) | 0xf2fde38b | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | unpause() | 0x3f4ba83a | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Function | unpauseMigration() | 0xf7c7eb92 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgeBurn(uint256,bytes32,address,address,uint256) | 0x1cd02155ad1064c60598a8bd0e4e795d7e7d0a0f3c38aad04d261f1297fb2545 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgeMint(uint256,bytes32,address,uint256) | 0xbc0f4055a7869d8ecad34b33382a0bc181c5811565fec42f335505be5fd661d2 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Event | MigrationFinalized(uint256,bytes32,address) | 0xb0cc16029b506b2a262b52711e71db4fcd1cb078bd4bb86c7ba82cd3be2eadd3 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Event | MigrationStarted(uint256,bytes32,uint256) | 0xc60eb6d595da5361c68f60aa7c8286b8f73c3a99e9db1818e146c522f512496f | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ChainIdNotRegistered(uint256) | 0x23f3c357 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Error | HyperchainNotRegistered() | 0xeab895aa | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Error | IncorrectChainAssetId(bytes32,bytes32) | 0x48857c1d | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Error | IncorrectSender(address,address) | 0xf5e39c1f | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Error | MigrationPaused() | 0x3312a450 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NonEmptyMsgValue() | 0x536ec84b | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NotAssetRouter(address,address) | 0xf306a770 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Error | SLHasDifferentCTM() | 0x36917565 | -|----------+------------------------------------------------------------+--------------------------------------------------------------------| -| Error | SlotOccupied() | 0xdf3a8fdd | -╰----------+------------------------------------------------------------+--------------------------------------------------------------------╯ +╭----------+------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++==================================================================================================================================================+ +| Function | ASSET_ROUTER() | 0xc6a70bbb | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | BRIDGEHUB() | 0x1657ec18 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | ETH_TOKEN_ASSET_ID() | 0x81eccdd4 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | MESSAGE_ROOT() | 0x26ce0686 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | acceptOwnership() | 0x79ba5097 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeBurn(uint256,uint256,bytes32,address,bytes) | 0x699b0fb9 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeConfirmTransferResult(uint256,uint8,bytes32,address,bytes) | 0xeead84cd | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeMint(uint256,bytes32,bytes) | 0x36ba0355 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initialize(address) | 0xc4d66de8 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | isMigrationInProgress(uint256) | 0xd9d1bdee | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | migrationNumber(uint256) | 0xb2157716 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | migrationPaused() | 0x2a641114 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | owner() | 0x8da5cb5b | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pause() | 0x8456cb59 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pauseMigration() | 0xac700e63 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | paused() | 0x5c975abb | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pendingOwner() | 0xe30c3978 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | renounceOwnership() | 0x715018a6 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setMigrationNumberForV30(uint256) | 0x60c74fc5 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setSettlementLayerChainId(uint256,uint256) | 0x5004dafd | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferOwnership(address) | 0xf2fde38b | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unpause() | 0x3f4ba83a | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unpauseMigration() | 0xf7c7eb92 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgeBurn(uint256,bytes32,address,address,uint256) | 0x1cd02155ad1064c60598a8bd0e4e795d7e7d0a0f3c38aad04d261f1297fb2545 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgeMint(uint256,bytes32,address,uint256) | 0xbc0f4055a7869d8ecad34b33382a0bc181c5811565fec42f335505be5fd661d2 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | MigrationFinalized(uint256,bytes32,address) | 0xb0cc16029b506b2a262b52711e71db4fcd1cb078bd4bb86c7ba82cd3be2eadd3 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | MigrationStarted(uint256,bytes32,uint256) | 0xc60eb6d595da5361c68f60aa7c8286b8f73c3a99e9db1818e146c522f512496f | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ChainIdNotRegistered(uint256) | 0x23f3c357 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | IncorrectChainAssetId(bytes32,bytes32) | 0x48857c1d | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | IncorrectSender(address,address) | 0xf5e39c1f | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | IteratedMigrationsNotSupported() | 0x47d42b1b | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MigrationNotToL1() | 0x4010a88d | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MigrationNumberAlreadySet() | 0x12b08c62 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MigrationNumberMismatch(uint256,uint256) | 0xde1362a2 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MigrationPaused() | 0x3312a450 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NonEmptyMsgValue() | 0x536ec84b | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotAssetRouter(address,address) | 0xf306a770 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotSystemContext(address) | 0xb35a7373 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyChain(address,address) | 0x73fe6c1b | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SLHasDifferentCTM() | 0x36917565 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SlotOccupied() | 0xdf3a8fdd | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ZKChainNotRegistered() | 0x7b968d06 | +╰----------+------------------------------------------------------------------+--------------------------------------------------------------------╯ L1ERC20Bridge @@ -6111,6 +7130,8 @@ L1GenesisUpgrade |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | SelectorsMustAllHaveSameFreezability() | 0xd3b6535b | |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SettlementLayerUpgradeMustPrecedeChainUpgrade() | 0x364b6f8b | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | TimeNotReached(uint256,uint256) | 0x08753982 | |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | TooManyFactoryDeps() | 0x76da24b9 | @@ -6128,453 +7149,565 @@ L1GenesisUpgrade L1MessageRoot -╭----------+-----------------------------------------------------------+--------------------------------------------------------------------╮ -| Type | Signature | Selector | -+===========================================================================================================================================+ -| Function | BRIDGE_HUB() | 0x5d4edca7 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | L1_CHAIN_ID() | 0x2f90b184 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | addNewChain(uint256) | 0xd4ce08c2 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainCount() | 0xe02e1bfd | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainIndex(uint256) | 0x48ceb85e | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainIndexToId(uint256) | 0xed1d7d97 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainRegistered(uint256) | 0xb8776d4d | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | getAggregatedRoot() | 0x3977d71c | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | getChainRoot(uint256) | 0x1e4fba05 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | historicalRoot(uint256) | 0x2e9b5cbb | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | initialize() | 0x8129fc1c | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | sharedTree() | 0xb1fde1a8 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | updateFullTree() | 0xbcd1b23d | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | AddedChain(uint256,uint256) | 0x5d96eda109bfd71cf9f4f70c83de31c4150760e8828979a95d9e5f9f15455af7 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | AppendedChainBatchRoot(uint256,uint256,bytes32) | 0x4f7fd9ed016150a623d5a2cf43053fe313a56293a77e060a05db49ed22579520 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | NewChainRoot(uint256,bytes32,bytes32) | 0x55f052ace108bbb0a540b328ff35be177a5c1d1f6e1e1adb46c1fa4bdaa69c10 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | NewInteropRoot(uint256,uint256,uint256,bytes32[]) | 0x94a4617be5e5655b97e5cf28ad2038cdc6ae3325b7940f0da8418aac8516a11f | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | ChainExists() | 0x65e8a019 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | MerkleWrongIndex(uint256,uint256) | 0x1b582fcf | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | MerkleWrongLength(uint256,uint256) | 0x485cfcaa | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | MessageRootNotRegistered() | 0x913183d8 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | OnlyBridgehubOrChainAssetHandler(address,address,address) | 0x2d396674 | -╰----------+-----------------------------------------------------------+--------------------------------------------------------------------╯ +╭----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++==========================================================================================================================================================================================+ +| Function | BRIDGE_HUB() | 0x5d4edca7 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | ERA_GATEWAY_CHAIN_ID() | 0x2b12011d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | addChainBatchRoot(uint256,uint256,bytes32) | 0xfb644fc5 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | addNewChain(uint256,uint256) | 0x66e8a86b | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainBatchRoots(uint256,uint256) | 0x1496c5ce | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainCount() | 0xe02e1bfd | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainIndex(uint256) | 0x48ceb85e | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainIndexToId(uint256) | 0xed1d7d97 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainRegistered(uint256) | 0xb8776d4d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | currentChainBatchNumber(uint256) | 0xf688e003 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getAggregatedRoot() | 0x3977d71c | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getChainRoot(uint256) | 0x1e4fba05 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getProofData(uint256,uint256,uint256,bytes32,bytes32[]) | 0x2f67101d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | historicalRoot(uint256) | 0x2e9b5cbb | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initialize() | 0x8129fc1c | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initializeL1V30Upgrade() | 0x719a3a9b | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1DepositParamsInclusion((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x685143b9 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1ToL2TransactionStatusShared(uint256,bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0xda24b3ee | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LeafInclusionShared(uint256,uint256,uint256,bytes32,bytes32[]) | 0x79cf6165 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LeafInclusionSharedRecursive(uint256,uint256,uint256,bytes32,bytes32[],uint256) | 0x353d7128 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LogInclusionShared(uint256,uint256,uint256,(uint8,bool,uint16,address,bytes32,bytes32),bytes32[]) | 0xe896760d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2MessageInclusionShared(uint256,uint256,uint256,(uint16,address,bytes),bytes32[]) | 0x18b7fc22 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | saveV30UpgradeChainBatchNumber(uint256) | 0xccb740c4 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | saveV30UpgradeChainBatchNumberOnL1((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x5cffbddf | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setMigratingChainBatchRoot(uint256,uint256,uint256) | 0xaa1253a5 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | sharedTree() | 0xb1fde1a8 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | updateFullTree() | 0xbcd1b23d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | v30UpgradeChainBatchNumber(uint256) | 0xc44da6ef | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | AddedChain(uint256,uint256) | 0x5d96eda109bfd71cf9f4f70c83de31c4150760e8828979a95d9e5f9f15455af7 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | AppendedChainBatchRoot(uint256,uint256,bytes32) | 0x4f7fd9ed016150a623d5a2cf43053fe313a56293a77e060a05db49ed22579520 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewChainRoot(uint256,bytes32,bytes32) | 0x55f052ace108bbb0a540b328ff35be177a5c1d1f6e1e1adb46c1fa4bdaa69c10 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewInteropRoot(uint256,uint256,uint256,bytes32[]) | 0x94a4617be5e5655b97e5cf28ad2038cdc6ae3325b7940f0da8418aac8516a11f | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | BatchZeroNotAllowed() | 0xa695b1ef | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ChainBatchRootAlreadyExists(uint256,uint256) | 0xbe263463 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ChainBatchRootZero() | 0x655c373c | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ChainExists() | 0x65e8a019 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | CurrentBatchNumberAlreadySet() | 0x5d03f19d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepthMoreThanOneForRecursiveMerkleProof() | 0x68d91b49 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | HashedLogIsDefault() | 0xd356e6ba | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | IncorrectFunctionSignature() | 0xdb495273 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidProof() | 0x09bde339 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidProofLengthForFinalNode() | 0x48c5fa28 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | LocallyNoChainsAtGenesis() | 0xc3bd3c65 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerkleIndexOutOfBounds() | 0x9bb54c35 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerklePathEmpty() | 0x8e23ac1a | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerklePathOutOfBounds() | 0x1c500385 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerkleWrongIndex(uint256,uint256) | 0x1b582fcf | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerkleWrongLength(uint256,uint256) | 0x485cfcaa | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MessageRootNotRegistered() | 0x913183d8 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NonConsecutiveBatchNumber(uint256,uint256) | 0x366c42f8 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotWhitelistedSettlementLayer(uint256) | 0xb30ebfd8 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyAssetTracker(address,address) | 0x3db511f4 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyBridgehubOrChainAssetHandler(address,address,address) | 0x2d396674 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyChain(address,address) | 0x73fe6c1b | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyGateway() | 0xec76af13 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyL1() | 0x8d14ca84 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyL2MessageRoot() | 0x605d6b86 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyOnSettlementLayer() | 0x6b75db8c | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyPreV30Chain(uint256) | 0x26d10385 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TotalBatchesExecutedLessThanV30UpgradeChainBatchNumber() | 0x8732442d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TotalBatchesExecutedZero() | 0x70a472bd | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedProofMetadataVersion(uint256) | 0x79274f04 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | V30UpgradeChainBatchNumberAlreadySet() | 0x246de5b7 | +╰----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ L1NativeTokenVault -╭----------+----------------------------------------------------------------+--------------------------------------------------------------------╮ -| Type | Signature | Selector | -+================================================================================================================================================+ -| Function | ASSET_ROUTER() | 0xc6a70bbb | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | BASE_TOKEN_ASSET_ID() | 0xcb944dec | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | L1_CHAIN_ID() | 0x2f90b184 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | L1_NULLIFIER() | 0xe60ccaba | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | WETH_TOKEN() | 0x37d277d4 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | acceptOwnership() | 0x79ba5097 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | assetId(address) | 0xfd3f60df | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeBurn(uint256,uint256,bytes32,address,bytes) | 0x699b0fb9 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeCheckCounterpartAddress(uint256,bytes32,address,address) | 0x9cc395d0 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeMint(uint256,bytes32,bytes) | 0x36ba0355 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeRecoverFailedTransfer(uint256,bytes32,address,bytes) | 0xc2e90293 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgedTokenBeacon() | 0xf2d44246 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | calculateCreate2TokenAddress(uint256,address) | 0xc487412c | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainBalance(uint256,bytes32) | 0x3345359b | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | ensureTokenIsRegistered(address) | 0x19a2a285 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | getERC20Getters(address,uint256) | 0xa7236d16 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | initialize(address,address) | 0x485cc955 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | originChainId(bytes32) | 0x5f3455b5 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | owner() | 0x8da5cb5b | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pause() | 0x8456cb59 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | paused() | 0x5c975abb | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pendingOwner() | 0xe30c3978 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | registerEthToken() | 0xcb6da609 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | registerToken(address) | 0x09824a80 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | renounceOwnership() | 0x715018a6 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | tokenAddress(bytes32) | 0x97bb3ce9 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | tokenDataOriginChainId(bytes) | 0x07a6d4bc | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | transferFundsFromSharedBridge(address) | 0x8310f2c6 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | transferOwnership(address) | 0xf2fde38b | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | tryRegisterTokenFromBurnData(bytes,bytes32) | 0x49b40853 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | unpause() | 0x3f4ba83a | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | updateChainBalancesFromSharedBridge(address,uint256) | 0x1c9f0149 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgeBurn(uint256,bytes32,address,address,uint256) | 0x1cd02155ad1064c60598a8bd0e4e795d7e7d0a0f3c38aad04d261f1297fb2545 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgeMint(uint256,bytes32,address,uint256) | 0xbc0f4055a7869d8ecad34b33382a0bc181c5811565fec42f335505be5fd661d2 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgedTokenBeaconUpdated(address,bytes32) | 0xc3f14dba68f86c42f518e5c0e8a5cbc9514da6f388e2f52c5b1a6263d8588bfb | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | TokenBeaconUpdated(address) | 0x5ed5e4f58bf9a324a38beaa1177fb96fcb7bf3a5f4c4585ebb78c4a8c0249d0f | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AddressMismatch(address,address) | 0x1f73225f | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AmountMustBeGreaterThanZero() | 0x5e85ae73 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AssetIdAlreadyRegistered() | 0xfe919e28 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AssetIdMismatch(bytes32,bytes32) | 0x1294e9e1 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | BurningNativeWETHNotSupported() | 0xaa5f6180 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ClaimFailedDepositFailed() | 0x0fef9068 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | DeployingBridgedTokenForNativeToken() | 0x138ee1a3 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyDeposit() | 0x95b66fe9 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyToken() | 0x066f53b1 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InsufficientChainBalance() | 0x826fb11e | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidNTVBurnData() | 0xde4c0b96 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NoFundsTransferred() | 0xcab098d8 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NonEmptyMsgValue() | 0x536ec84b | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | OriginChainIdNotFound() | 0xb926450e | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokenNotSupported(address) | 0x06439c6b | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokensWithFeesNotSupported() | 0x23830e28 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | Unauthorized(address) | 0x8e4a23d6 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | UnsupportedEncodingVersion() | 0x084a1449 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ValueMismatch(uint256,uint256) | 0x626ade30 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | WithdrawFailed() | 0x750b219c | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | WrongAmountTransferred(uint256,uint256) | 0xfeda3bf8 | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | WrongCounterpart() | 0xb4aeddbc | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ZeroAddress() | 0xd92e233d | -|----------+----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ZeroAmountToTransfer() | 0xe4742c42 | -╰----------+----------------------------------------------------------------+--------------------------------------------------------------------╯ +╭----------+------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++==================================================================================================================================================+ +| Function | ASSET_ROUTER() | 0xc6a70bbb | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | BASE_TOKEN_ASSET_ID() | 0xcb944dec | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L1_NULLIFIER() | 0xe60ccaba | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | WETH_TOKEN() | 0x37d277d4 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | acceptOwnership() | 0x79ba5097 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | addLegacyTokenToBridgedTokensList(address) | 0x2e270c4c | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | assetId(address) | 0xfd3f60df | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeBurn(uint256,uint256,bytes32,address,bytes) | 0x699b0fb9 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeCheckCounterpartAddress(uint256,bytes32,address,address) | 0x9cc395d0 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeConfirmTransferResult(uint256,uint8,bytes32,address,bytes) | 0xeead84cd | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeMint(uint256,bytes32,bytes) | 0x36ba0355 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokenBeacon() | 0xf2d44246 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokens(uint256) | 0xc409b8f9 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokensCount() | 0x88c6e7d8 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | calculateCreate2TokenAddress(uint256,address) | 0xc487412c | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainBalance(uint256,bytes32) | 0x3345359b | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | ensureTokenIsRegistered(address) | 0x19a2a285 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getERC20Getters(address,uint256) | 0xa7236d16 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initialize(address,address) | 0x485cc955 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l1AssetTracker() | 0x2c1c870c | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | migrateTokenBalanceToAssetTracker(uint256,bytes32) | 0x7d783865 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | originChainId(bytes32) | 0x5f3455b5 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | originToken(bytes32) | 0xb4541499 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | owner() | 0x8da5cb5b | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pause() | 0x8456cb59 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | paused() | 0x5c975abb | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pendingOwner() | 0xe30c3978 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | registerEthToken() | 0xcb6da609 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | registerToken(address) | 0x09824a80 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | renounceOwnership() | 0x715018a6 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setAssetTracker(address) | 0xe26daa7e | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenAddress(bytes32) | 0x97bb3ce9 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenDataOriginChainId(bytes) | 0x07a6d4bc | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenIndex(bytes32) | 0x31b60086 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferOwnership(address) | 0xf2fde38b | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tryRegisterTokenFromBurnData(bytes,bytes32) | 0x49b40853 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unpause() | 0x3f4ba83a | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgeBurn(uint256,bytes32,address,address,uint256) | 0x1cd02155ad1064c60598a8bd0e4e795d7e7d0a0f3c38aad04d261f1297fb2545 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgeMint(uint256,bytes32,address,uint256) | 0xbc0f4055a7869d8ecad34b33382a0bc181c5811565fec42f335505be5fd661d2 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgedTokenBeaconUpdated(address,bytes32) | 0xc3f14dba68f86c42f518e5c0e8a5cbc9514da6f388e2f52c5b1a6263d8588bfb | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | TokenBeaconUpdated(address) | 0x5ed5e4f58bf9a324a38beaa1177fb96fcb7bf3a5f4c4585ebb78c4a8c0249d0f | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AddressMismatch(address,address) | 0x1f73225f | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AmountMustBeGreaterThanZero() | 0x5e85ae73 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdAlreadyRegistered() | 0xfe919e28 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdMismatch(bytes32,bytes32) | 0x1294e9e1 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | BurningNativeWETHNotSupported() | 0xaa5f6180 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ClaimFailedDepositFailed() | 0x0fef9068 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DeployingBridgedTokenForNativeToken() | 0x138ee1a3 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyDeposit() | 0x95b66fe9 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyToken() | 0x066f53b1 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidNTVBurnData() | 0xde4c0b96 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NoFundsTransferred() | 0xcab098d8 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NonEmptyMsgValue() | 0x536ec84b | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyFailureStatusAllowed() | 0x7ec6d3a1 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OriginChainIdNotFound() | 0xb926450e | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenAlreadyInBridgedTokensList() | 0x84204265 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenNotLegacy() | 0x1850b46b | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenNotSupported(address) | 0x06439c6b | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokensWithFeesNotSupported() | 0x23830e28 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Unauthorized(address) | 0x8e4a23d6 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedEncodingVersion() | 0x084a1449 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ValueMismatch(uint256,uint256) | 0x626ade30 | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | WithdrawFailed() | 0x750b219c | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | WrongCounterpart() | 0xb4aeddbc | +|----------+------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ZeroAddress() | 0xd92e233d | +╰----------+------------------------------------------------------------------+--------------------------------------------------------------------╯ L1Nullifier -╭----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ -| Type | Signature | Selector | -+=======================================================================================================================================================================================+ -| Function | BRIDGE_HUB() | 0x5d4edca7 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | __DEPRECATED_admin() | 0xf7a5cec0 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | __DEPRECATED_chainBalance(uint256,address) | 0x6182877b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | __DEPRECATED_l2BridgeAddress(uint256) | 0xfdbb0301 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | __DEPRECATED_pendingAdmin() | 0x6cdecb2b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | acceptOwnership() | 0x79ba5097 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeRecoverFailedTransfer(uint256,address,bytes32,bytes,bytes32,uint256,uint256,uint16,bytes32[]) | 0x3601e63e | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgehubConfirmL2TransactionForwarded(uint256,bytes32,bytes32) | 0x4bc2c8c0 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainBalance(uint256,address) | 0x9cd45184 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | claimFailedDeposit(uint256,address,address,uint256,bytes32,uint256,uint256,uint16,bytes32[]) | 0xc0991525 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | claimFailedDepositLegacyErc20Bridge(address,address,uint256,bytes32,uint256,uint256,uint16,bytes32[]) | 0x8fbb3711 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | depositHappened(uint256,bytes32) | 0x9fa8826b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | encodeTxDataHash(bytes1,address,bytes32,bytes) | 0xf120e6c4 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | finalizeDeposit((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x74beea82 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | finalizeWithdrawal(uint256,uint256,uint256,uint16,bytes,bytes32[]) | 0xc87325f1 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | initialize(address,uint256,uint256,uint256,uint256) | 0xf92ad219 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | isWithdrawalFinalized(uint256,uint256,uint256) | 0x8f31f052 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | l1AssetRouter() | 0x6d9860e1 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | l1NativeTokenVault() | 0x6f513211 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | l2BridgeAddress(uint256) | 0x07ee9355 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | legacyBridge() | 0x6e9d7899 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | nullifyChainBalanceByNTV(uint256,address) | 0x5de097b1 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | owner() | 0x8da5cb5b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pause() | 0x8456cb59 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | paused() | 0x5c975abb | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pendingOwner() | 0xe30c3978 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | renounceOwnership() | 0x715018a6 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setL1AssetRouter(address) | 0x780ce114 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setL1Erc20Bridge(address) | 0x30bda03e | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setL1NativeTokenVault(address) | 0xb7cc6f46 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | transferOwnership(address) | 0xf2fde38b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | transferTokenToNTV(address) | 0x40a434d5 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | unpause() | 0x3f4ba83a | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgehubDepositFinalized(uint256,bytes32,bytes32) | 0xe4def01b981193a97a9e81230d7b9f31812ceaf23f864a828a82c687911cb2df | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AddressAlreadySet(address) | 0x0dfb42bf | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | DepositDoesNotExist() | 0xc7c9660f | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | DepositExists() | 0xad2fa98e | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EthTransferFailed() | 0x6d963f88 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | IncorrectTokenAddressFromNTV(bytes32,address) | 0x1929b7de | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidNTVBurnData() | 0xde4c0b96 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidProof() | 0x09bde339 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidSelector(bytes4) | 0x12ba286f | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | L2WithdrawalMessageWrongLength(uint256) | 0x97e1359e | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | LegacyBridgeNotSet() | 0x8efef97a | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | LegacyMethodForNonL1Token() | 0x767eed08 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NativeTokenVaultAlreadySet() | 0x1c55230b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NotInitializedReentrancyGuard() | 0xdd7e3621 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | Reentrancy() | 0xab143c06 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | SharedBridgeValueNotSet(uint8) | 0x7774d2f9 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | SlotOccupied() | 0xdf3a8fdd | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokenNotLegacy() | 0x1850b46b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | Unauthorized(address) | 0x8e4a23d6 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | UnsupportedEncodingVersion() | 0x084a1449 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | WithdrawalAlreadyFinalized() | 0xae899454 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | WrongL2Sender(address) | 0x636c90db | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | WrongMsgLength(uint256,uint256) | 0x61cdb17e | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ZeroAddress() | 0xd92e233d | -╰----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ +╭----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=============================================================================================================================================================================================+ +| Function | BRIDGE_HUB() | 0x5d4edca7 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | MESSAGE_ROOT() | 0x26ce0686 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | __DEPRECATED_admin() | 0xf7a5cec0 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | __DEPRECATED_chainBalance(uint256,address) | 0x6182877b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | __DEPRECATED_l2BridgeAddress(uint256) | 0xfdbb0301 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | __DEPRECATED_pendingAdmin() | 0x6cdecb2b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | acceptOwnership() | 0x79ba5097 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeConfirmTransferResult((uint256,address,uint16,uint8,bytes32,bytes,bytes32,uint256,uint256,bytes32[])) | 0xc6c7af56 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeRecoverFailedTransfer(uint256,address,bytes32,bytes,bytes32,uint256,uint256,uint16,bytes32[]) | 0x3601e63e | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgehubConfirmL2TransactionForwarded(uint256,bytes32,bytes32) | 0x4bc2c8c0 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainBalance(uint256,address) | 0x9cd45184 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | claimFailedDeposit(uint256,address,address,uint256,bytes32,uint256,uint256,uint16,bytes32[]) | 0xc0991525 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | claimFailedDepositLegacyErc20Bridge(address,address,uint256,bytes32,uint256,uint256,uint16,bytes32[]) | 0x8fbb3711 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | depositHappened(uint256,bytes32) | 0x9fa8826b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | encodeTxDataHash(bytes1,address,bytes32,bytes) | 0xf120e6c4 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | finalizeDeposit((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x74beea82 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | finalizeWithdrawal(uint256,uint256,uint256,uint16,bytes,bytes32[]) | 0xc87325f1 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getTransientSettlementLayer() | 0xf8d6c677 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initialize(address,uint256,uint256,uint256,uint256) | 0xf92ad219 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | isWithdrawalFinalized(uint256,uint256,uint256) | 0x8f31f052 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l1AssetRouter() | 0x6d9860e1 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l1NativeTokenVault() | 0x6f513211 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l2BridgeAddress(uint256) | 0x07ee9355 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | legacyBridge() | 0x6e9d7899 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | nullifyChainBalanceByNTV(uint256,address) | 0x5de097b1 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | owner() | 0x8da5cb5b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pause() | 0x8456cb59 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | paused() | 0x5c975abb | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pendingOwner() | 0xe30c3978 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | renounceOwnership() | 0x715018a6 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setL1AssetRouter(address) | 0x780ce114 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setL1Erc20Bridge(address) | 0x30bda03e | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setL1NativeTokenVault(address) | 0xb7cc6f46 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferOwnership(address) | 0xf2fde38b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferTokenToNTV(address) | 0x40a434d5 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unpause() | 0x3f4ba83a | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgehubDepositFinalized(uint256,bytes32,bytes32) | 0xe4def01b981193a97a9e81230d7b9f31812ceaf23f864a828a82c687911cb2df | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | TransientSettlementLayerSet(uint256) | 0x9dbae9e6e0031ad5f2814bd78f1347f33a63db5cec1013f279da03ca632a1e1e | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AddressAlreadySet(address) | 0x0dfb42bf | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepositDoesNotExist(bytes32,bytes32) | 0x42bce528 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepositExists() | 0xad2fa98e | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EthAlreadyMigratedToL1NTV() | 0x82b0de47 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | IncorrectTokenAddressFromNTV(bytes32,address) | 0x1929b7de | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidNTVBurnData() | 0xde4c0b96 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidProof() | 0x09bde339 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidSelector(bytes4) | 0x12ba286f | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | L2WithdrawalMessageWrongLength(uint256) | 0x97e1359e | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | LegacyBridgeNotSet() | 0x8efef97a | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | LegacyMethodForNonL1Token() | 0x767eed08 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NativeTokenVaultAlreadySet() | 0x1c55230b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotInitializedReentrancyGuard() | 0xdd7e3621 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Reentrancy() | 0xab143c06 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SharedBridgeValueNotSet(uint8) | 0x7774d2f9 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SlotOccupied() | 0xdf3a8fdd | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenNotLegacy() | 0x1850b46b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Unauthorized(address) | 0x8e4a23d6 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedEncodingVersion() | 0x084a1449 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | WithdrawalAlreadyFinalized() | 0xae899454 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | WrongL2Sender(address) | 0x636c90db | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | WrongMsgLength(uint256,uint256) | 0x61cdb17e | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ZeroAddress() | 0xd92e233d | +╰----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ L1NullifierDev -╭----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ -| Type | Signature | Selector | -+=======================================================================================================================================================================================+ -| Function | BRIDGE_HUB() | 0x5d4edca7 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | __DEPRECATED_admin() | 0xf7a5cec0 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | __DEPRECATED_chainBalance(uint256,address) | 0x6182877b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | __DEPRECATED_l2BridgeAddress(uint256) | 0xfdbb0301 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | __DEPRECATED_pendingAdmin() | 0x6cdecb2b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | acceptOwnership() | 0x79ba5097 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeRecoverFailedTransfer(uint256,address,bytes32,bytes,bytes32,uint256,uint256,uint16,bytes32[]) | 0x3601e63e | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgehubConfirmL2TransactionForwarded(uint256,bytes32,bytes32) | 0x4bc2c8c0 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainBalance(uint256,address) | 0x9cd45184 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | claimFailedDeposit(uint256,address,address,uint256,bytes32,uint256,uint256,uint16,bytes32[]) | 0xc0991525 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | claimFailedDepositLegacyErc20Bridge(address,address,uint256,bytes32,uint256,uint256,uint16,bytes32[]) | 0x8fbb3711 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | depositHappened(uint256,bytes32) | 0x9fa8826b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | encodeTxDataHash(bytes1,address,bytes32,bytes) | 0xf120e6c4 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | finalizeDeposit((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x74beea82 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | finalizeWithdrawal(uint256,uint256,uint256,uint16,bytes,bytes32[]) | 0xc87325f1 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | initialize(address,uint256,uint256,uint256,uint256) | 0xf92ad219 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | isWithdrawalFinalized(uint256,uint256,uint256) | 0x8f31f052 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | l1AssetRouter() | 0x6d9860e1 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | l1NativeTokenVault() | 0x6f513211 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | l2BridgeAddress(uint256) | 0x07ee9355 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | legacyBridge() | 0x6e9d7899 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | nullifyChainBalanceByNTV(uint256,address) | 0x5de097b1 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | owner() | 0x8da5cb5b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pause() | 0x8456cb59 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | paused() | 0x5c975abb | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pendingOwner() | 0xe30c3978 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | renounceOwnership() | 0x715018a6 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setL1AssetRouter(address) | 0x780ce114 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setL1Erc20Bridge(address) | 0x30bda03e | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setL1NativeTokenVault(address) | 0xb7cc6f46 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setL2LegacySharedBridge(uint256,address) | 0x4771ebad | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | transferOwnership(address) | 0xf2fde38b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | transferTokenToNTV(address) | 0x40a434d5 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | unpause() | 0x3f4ba83a | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgehubDepositFinalized(uint256,bytes32,bytes32) | 0xe4def01b981193a97a9e81230d7b9f31812ceaf23f864a828a82c687911cb2df | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AddressAlreadySet(address) | 0x0dfb42bf | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | DepositDoesNotExist() | 0xc7c9660f | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | DepositExists() | 0xad2fa98e | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EthTransferFailed() | 0x6d963f88 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | IncorrectTokenAddressFromNTV(bytes32,address) | 0x1929b7de | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidNTVBurnData() | 0xde4c0b96 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidProof() | 0x09bde339 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidSelector(bytes4) | 0x12ba286f | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | L2WithdrawalMessageWrongLength(uint256) | 0x97e1359e | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | LegacyBridgeNotSet() | 0x8efef97a | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | LegacyMethodForNonL1Token() | 0x767eed08 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NativeTokenVaultAlreadySet() | 0x1c55230b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NotInitializedReentrancyGuard() | 0xdd7e3621 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | Reentrancy() | 0xab143c06 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | SharedBridgeValueNotSet(uint8) | 0x7774d2f9 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | SlotOccupied() | 0xdf3a8fdd | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokenNotLegacy() | 0x1850b46b | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | Unauthorized(address) | 0x8e4a23d6 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | UnsupportedEncodingVersion() | 0x084a1449 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | WithdrawalAlreadyFinalized() | 0xae899454 | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | WrongL2Sender(address) | 0x636c90db | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | WrongMsgLength(uint256,uint256) | 0x61cdb17e | -|----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ZeroAddress() | 0xd92e233d | -╰----------+-------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ +╭----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=============================================================================================================================================================================================+ +| Function | BRIDGE_HUB() | 0x5d4edca7 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | MESSAGE_ROOT() | 0x26ce0686 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | __DEPRECATED_admin() | 0xf7a5cec0 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | __DEPRECATED_chainBalance(uint256,address) | 0x6182877b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | __DEPRECATED_l2BridgeAddress(uint256) | 0xfdbb0301 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | __DEPRECATED_pendingAdmin() | 0x6cdecb2b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | acceptOwnership() | 0x79ba5097 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeConfirmTransferResult((uint256,address,uint16,uint8,bytes32,bytes,bytes32,uint256,uint256,bytes32[])) | 0xc6c7af56 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeRecoverFailedTransfer(uint256,address,bytes32,bytes,bytes32,uint256,uint256,uint16,bytes32[]) | 0x3601e63e | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgehubConfirmL2TransactionForwarded(uint256,bytes32,bytes32) | 0x4bc2c8c0 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainBalance(uint256,address) | 0x9cd45184 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | claimFailedDeposit(uint256,address,address,uint256,bytes32,uint256,uint256,uint16,bytes32[]) | 0xc0991525 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | claimFailedDepositLegacyErc20Bridge(address,address,uint256,bytes32,uint256,uint256,uint16,bytes32[]) | 0x8fbb3711 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | depositHappened(uint256,bytes32) | 0x9fa8826b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | encodeTxDataHash(bytes1,address,bytes32,bytes) | 0xf120e6c4 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | finalizeDeposit((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x74beea82 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | finalizeWithdrawal(uint256,uint256,uint256,uint16,bytes,bytes32[]) | 0xc87325f1 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getTransientSettlementLayer() | 0xf8d6c677 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initialize(address,uint256,uint256,uint256,uint256) | 0xf92ad219 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | isWithdrawalFinalized(uint256,uint256,uint256) | 0x8f31f052 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l1AssetRouter() | 0x6d9860e1 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l1NativeTokenVault() | 0x6f513211 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l2BridgeAddress(uint256) | 0x07ee9355 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | legacyBridge() | 0x6e9d7899 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | nullifyChainBalanceByNTV(uint256,address) | 0x5de097b1 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | owner() | 0x8da5cb5b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pause() | 0x8456cb59 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | paused() | 0x5c975abb | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pendingOwner() | 0xe30c3978 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | renounceOwnership() | 0x715018a6 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setL1AssetRouter(address) | 0x780ce114 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setL1Erc20Bridge(address) | 0x30bda03e | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setL1NativeTokenVault(address) | 0xb7cc6f46 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setL2LegacySharedBridge(uint256,address) | 0x4771ebad | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferOwnership(address) | 0xf2fde38b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferTokenToNTV(address) | 0x40a434d5 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unpause() | 0x3f4ba83a | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgehubDepositFinalized(uint256,bytes32,bytes32) | 0xe4def01b981193a97a9e81230d7b9f31812ceaf23f864a828a82c687911cb2df | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | TransientSettlementLayerSet(uint256) | 0x9dbae9e6e0031ad5f2814bd78f1347f33a63db5cec1013f279da03ca632a1e1e | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AddressAlreadySet(address) | 0x0dfb42bf | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepositDoesNotExist(bytes32,bytes32) | 0x42bce528 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepositExists() | 0xad2fa98e | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EthAlreadyMigratedToL1NTV() | 0x82b0de47 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | IncorrectTokenAddressFromNTV(bytes32,address) | 0x1929b7de | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidNTVBurnData() | 0xde4c0b96 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidProof() | 0x09bde339 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidSelector(bytes4) | 0x12ba286f | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | L2WithdrawalMessageWrongLength(uint256) | 0x97e1359e | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | LegacyBridgeNotSet() | 0x8efef97a | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | LegacyMethodForNonL1Token() | 0x767eed08 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NativeTokenVaultAlreadySet() | 0x1c55230b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotInitializedReentrancyGuard() | 0xdd7e3621 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Reentrancy() | 0xab143c06 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SharedBridgeValueNotSet(uint8) | 0x7774d2f9 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SlotOccupied() | 0xdf3a8fdd | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenNotLegacy() | 0x1850b46b | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Unauthorized(address) | 0x8e4a23d6 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedEncodingVersion() | 0x084a1449 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | WithdrawalAlreadyFinalized() | 0xae899454 | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | WrongL2Sender(address) | 0x636c90db | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | WrongMsgLength(uint256,uint256) | 0x61cdb17e | +|----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ZeroAddress() | 0xd92e233d | +╰----------+-------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ L1V29Upgrade @@ -6631,6 +7764,8 @@ L1V29Upgrade |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | PubdataGreaterThanLimit(uint256,uint256) | 0x959f26fb | |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SettlementLayerUpgradeMustPrecedeChainUpgrade() | 0x364b6f8b | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | TimeNotReached(uint256,uint256) | 0x08753982 | |----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | TooManyFactoryDeps() | 0x76da24b9 | @@ -6681,14 +7816,20 @@ L2AssetRouter |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | assetHandlerAddress(bytes32) | 0x53b9e632 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgehubDepositBaseToken(uint256,bytes32,address,uint256) | 0xc4879440 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | finalizeDeposit(uint256,bytes32,bytes) | 0x9c884fd1 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | finalizeDeposit(address,address,address,uint256,bytes) | 0xcfe7af7c | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | finalizeDepositLegacyBridge(address,address,address,uint256,bytes) | 0x54b2e69c | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getDepositCalldata(address,bytes32,bytes) | 0x2ff0b2ea | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | initL2(uint256,uint256,address,address,bytes32,address) | 0xcc06b5ca | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initiateIndirectCall(uint256,address,uint256,bytes) | 0x4d7e3d62 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | l1Bridge() | 0x969b53da | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | l1TokenAddress(address) | 0xf54266a2 | @@ -6703,6 +7844,8 @@ L2AssetRouter |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | pendingOwner() | 0xe30c3978 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | receiveMessage(bytes32,bytes,bytes) | 0x2432ef26 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | renounceOwnership() | 0x715018a6 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Function | setAssetHandlerAddress(uint256,bytes32,address) | 0xda556bdc | @@ -6749,16 +7892,28 @@ L2AssetRouter |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Error | AmountMustBeGreaterThanZero() | 0x5e85ae73 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetHandlerDoesNotExist(bytes32) | 0xfde974f4 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Error | AssetIdNotSupported(bytes32) | 0x04a0b7e9 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | BadTransferDataLength() | 0x9b821ed7 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Error | EmptyAddress() | 0x7138356f | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidCaller(address) | 0xcbd9d2e0 | +| Error | ExecuteMessageFailed() | 0xf4072616 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | IncorrectTokenAddressFromNTV(bytes32,address) | 0x1929b7de | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InteroperableAddressParsingError(bytes) | 0xe7c8d4cf | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Error | InvalidNTVBurnData() | 0xde4c0b96 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidSelector(bytes4) | 0x12ba286f | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotInitializedReentrancyGuard() | 0xdd7e3621 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | PayloadTooShort() | 0x97da9c1c | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Error | Reentrancy() | 0xab143c06 | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Error | SlotOccupied() | 0xdf3a8fdd | @@ -6766,6 +7921,78 @@ L2AssetRouter | Error | TokenNotLegacy() | 0x1850b46b | |----------+---------------------------------------------------------------------+--------------------------------------------------------------------| | Error | Unauthorized(address) | 0x8e4a23d6 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedEncodingVersion() | 0x084a1449 | +╰----------+---------------------------------------------------------------------+--------------------------------------------------------------------╯ + +L2AssetTracker + +╭----------+---------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=====================================================================================================================================================+ +| Function | BASE_TOKEN_ASSET_ID() | 0xcb944dec | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | acceptOwnership() | 0x79ba5097 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | assetMigrationNumber(uint256,bytes32) | 0x28a31683 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainBalance(uint256,bytes32) | 0x3345359b | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | confirmMigrationOnL2((bytes1,bool,uint256,bytes32,uint256,uint256)) | 0x3a5c8caa | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | handleFinalizeBaseTokenBridgingOnL2(uint256) | 0xc7bb6041 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | handleFinalizeBridgingOnL2(bytes32,uint256,uint256,address) | 0x16e247bf | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | handleInitiateBaseTokenBridgingOnL2(uint256) | 0xd0201254 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | handleInitiateBridgingOnL2(bytes32,uint256,uint256) | 0xb0e6f1b0 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initiateL1ToGatewayMigrationOnL2(bytes32) | 0x42410ced | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | migrateTokenBalanceFromNTVV30(bytes32) | 0x6f864c3e | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | owner() | 0x8da5cb5b | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pendingOwner() | 0xe30c3978 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | registerLegacyTokenOnChain(bytes32) | 0x9f46bad9 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | registerNewToken(bytes32,uint256) | 0xaa8facf7 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | renounceOwnership() | 0x715018a6 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setAddresses(uint256,bytes32) | 0x1bafc42e | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenMigrated(uint256,bytes32) | 0x7c4ed2b6 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenMigratedThisChain(bytes32) | 0xfc33c15f | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferOwnership(address) | 0xf2fde38b | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdNotRegistered(bytes32) | 0xda72d995 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InsufficientChainBalance(uint256,bytes32,uint256) | 0x07859b3b | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidChainId() | 0x7a47c9a2 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MaxChainBalanceAlreadyAssigned(bytes32) | 0xda4352c4 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MissingBaseTokenAssetId() | 0x7e472272 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyGatewaySettlementLayer() | 0x4a22c4b8 | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenBalanceNotMigratedToGateway(bytes32,uint256,uint256) | 0x90ed63bb | +|----------+---------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Unauthorized(address) | 0x8e4a23d6 | ╰----------+---------------------------------------------------------------------+--------------------------------------------------------------------╯ L2Bridgehub @@ -6801,6 +8028,8 @@ L2Bridgehub |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainAssetHandler() | 0x70d8af87 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainRegistrationSender() | 0x669e1e46 | +|----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManager(uint256) | 0x9d5bd3da | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | chainTypeManagerIsRegistered(address) | 0xb93c9366 | @@ -6815,9 +8044,9 @@ L2Bridgehub |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurnSetSettlementLayer(uint256,uint256) | 0x0641e4f7 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8) | 0x22409213 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256) | 0x9f115e38 | +| Function | forwardedBridgeMint(bytes32,uint256,bytes32) | 0x17fa3751 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | getAllZKChainChainIDs() | 0x68b8d331 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -6849,13 +8078,17 @@ L2Bridgehub |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2MessageInclusion(uint256,uint256,uint256,(uint16,address,bytes),bytes32[]) | 0x99c16d1a | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | registerChainForInterop(uint256,bytes32) | 0xc4aebf2f | +|----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | registerNewZKChain(uint256,address,bool) | 0x7011be85 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | removeChainTypeManager(address) | 0x332b96dc | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | renounceOwnership() | 0x715018a6 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setAddresses(address,address,address,address) | 0x4a945f8d | +| Function | setAddresses(address,address,address,address,address) | 0x5dd68acd | +|----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setAddressesV30(address) | 0x5cca46f2 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | setCTMAssetAddress(bytes32,address) | 0x2dbcf55f | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -6917,7 +8150,7 @@ L2Bridgehub |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotChainAssetHandler(address,address) | 0x8beee3a3 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NotCurrentSL(uint256,uint256) | 0xc0ca9182 | +| Error | NotCurrentSettlementLayer() | 0x5e67e793 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotInGatewayMode() | 0x472477e2 | |----------+----------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -6959,6 +8192,8 @@ L2ChainAssetHandler |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | initL2(uint256,address,address,address,address) | 0x619a038c | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Function | migrationNumber(uint256) | 0xb2157716 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | migrationPaused() | 0x2a641114 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | owner() | 0x8da5cb5b | @@ -6973,6 +8208,10 @@ L2ChainAssetHandler |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | renounceOwnership() | 0x715018a6 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Function | setMigrationNumberForV30(uint256) | 0x60c74fc5 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Function | setSettlementLayerChainId(uint256,uint256) | 0x5004dafd | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | transferOwnership(address) | 0xf2fde38b | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | unpause() | 0x3f4ba83a | @@ -7001,23 +8240,35 @@ L2ChainAssetHandler |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | ChainIdNotRegistered(uint256) | 0x23f3c357 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| -| Error | HyperchainNotRegistered() | 0xeab895aa | -|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | IncorrectChainAssetId(bytes32,bytes32) | 0x48857c1d | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | IncorrectSender(address,address) | 0xf5e39c1f | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | InvalidCaller(address) | 0xcbd9d2e0 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | IteratedMigrationsNotSupported() | 0x47d42b1b | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | MigrationNotToL1() | 0x4010a88d | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | MigrationNumberAlreadySet() | 0x12b08c62 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | MigrationNumberMismatch(uint256,uint256) | 0xde1362a2 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | MigrationPaused() | 0x3312a450 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | NonEmptyMsgValue() | 0x536ec84b | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | NotAssetRouter(address,address) | 0xf306a770 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | NotSystemContext(address) | 0xb35a7373 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyChain(address,address) | 0x73fe6c1b | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | SLHasDifferentCTM() | 0x36917565 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | SlotOccupied() | 0xdf3a8fdd | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | ZKChainNotRegistered() | 0x7b968d06 | ╰----------+-----------------------------------------------------+--------------------------------------------------------------------╯ L2ComplexUpgrader @@ -7076,73 +8327,155 @@ L2GenesisUpgrade L2MessageRoot -╭----------+-----------------------------------------------------------+--------------------------------------------------------------------╮ -| Type | Signature | Selector | -+===========================================================================================================================================+ -| Function | BRIDGE_HUB() | 0x5d4edca7 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | L1_CHAIN_ID() | 0x2f90b184 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | addChainBatchRoot(uint256,uint256,bytes32) | 0xfb644fc5 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | addNewChain(uint256) | 0xd4ce08c2 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainCount() | 0xe02e1bfd | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainIndex(uint256) | 0x48ceb85e | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainIndexToId(uint256) | 0xed1d7d97 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainRegistered(uint256) | 0xb8776d4d | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | getAggregatedRoot() | 0x3977d71c | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | getChainRoot(uint256) | 0x1e4fba05 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | historicalRoot(uint256) | 0x2e9b5cbb | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | initL2(uint256) | 0xfdf736a3 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | sharedTree() | 0xb1fde1a8 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | updateFullTree() | 0xbcd1b23d | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | AddedChain(uint256,uint256) | 0x5d96eda109bfd71cf9f4f70c83de31c4150760e8828979a95d9e5f9f15455af7 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | AppendedChainBatchRoot(uint256,uint256,bytes32) | 0x4f7fd9ed016150a623d5a2cf43053fe313a56293a77e060a05db49ed22579520 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | NewChainRoot(uint256,bytes32,bytes32) | 0x55f052ace108bbb0a540b328ff35be177a5c1d1f6e1e1adb46c1fa4bdaa69c10 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | NewInteropRoot(uint256,uint256,uint256,bytes32[]) | 0x94a4617be5e5655b97e5cf28ad2038cdc6ae3325b7940f0da8418aac8516a11f | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | ChainExists() | 0x65e8a019 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidCaller(address) | 0xcbd9d2e0 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | MerkleWrongIndex(uint256,uint256) | 0x1b582fcf | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | MerkleWrongLength(uint256,uint256) | 0x485cfcaa | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | MessageRootNotRegistered() | 0x913183d8 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | OnlyBridgehubOrChainAssetHandler(address,address,address) | 0x2d396674 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | OnlyChain(address,address) | 0x73fe6c1b | -╰----------+-----------------------------------------------------------+--------------------------------------------------------------------╯ +╭----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++==========================================================================================================================================================================================+ +| Function | BRIDGE_HUB() | 0x5d4edca7 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | ERA_GATEWAY_CHAIN_ID() | 0x2b12011d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | addChainBatchRoot(uint256,uint256,bytes32) | 0xfb644fc5 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | addNewChain(uint256,uint256) | 0x66e8a86b | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainBatchRoots(uint256,uint256) | 0x1496c5ce | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainCount() | 0xe02e1bfd | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainIndex(uint256) | 0x48ceb85e | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainIndexToId(uint256) | 0xed1d7d97 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainRegistered(uint256) | 0xb8776d4d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | currentChainBatchNumber(uint256) | 0xf688e003 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getAggregatedRoot() | 0x3977d71c | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getChainRoot(uint256) | 0x1e4fba05 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getProofData(uint256,uint256,uint256,bytes32,bytes32[]) | 0x2f67101d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | historicalRoot(uint256) | 0x2e9b5cbb | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initL2(uint256,uint256) | 0x47b78c1d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initializeL2V30Upgrade() | 0xaafe6833 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1DepositParamsInclusion((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x685143b9 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1ToL2TransactionStatusShared(uint256,bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0xda24b3ee | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LeafInclusionShared(uint256,uint256,uint256,bytes32,bytes32[]) | 0x79cf6165 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LeafInclusionSharedRecursive(uint256,uint256,uint256,bytes32,bytes32[],uint256) | 0x353d7128 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LogInclusionShared(uint256,uint256,uint256,(uint8,bool,uint16,address,bytes32,bytes32),bytes32[]) | 0xe896760d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2MessageInclusionShared(uint256,uint256,uint256,(uint16,address,bytes),bytes32[]) | 0x18b7fc22 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | saveV30UpgradeChainBatchNumber(uint256) | 0xccb740c4 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | sendV30UpgradeBlockNumberFromGateway(uint256,uint256) | 0x3802d6fb | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setMigratingChainBatchRoot(uint256,uint256,uint256) | 0xaa1253a5 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | sharedTree() | 0xb1fde1a8 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | updateFullTree() | 0xbcd1b23d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | v30UpgradeChainBatchNumber(uint256) | 0xc44da6ef | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | AddedChain(uint256,uint256) | 0x5d96eda109bfd71cf9f4f70c83de31c4150760e8828979a95d9e5f9f15455af7 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | AppendedChainBatchRoot(uint256,uint256,bytes32) | 0x4f7fd9ed016150a623d5a2cf43053fe313a56293a77e060a05db49ed22579520 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewChainRoot(uint256,bytes32,bytes32) | 0x55f052ace108bbb0a540b328ff35be177a5c1d1f6e1e1adb46c1fa4bdaa69c10 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewInteropRoot(uint256,uint256,uint256,bytes32[]) | 0x94a4617be5e5655b97e5cf28ad2038cdc6ae3325b7940f0da8418aac8516a11f | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | BatchZeroNotAllowed() | 0xa695b1ef | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ChainBatchRootAlreadyExists(uint256,uint256) | 0xbe263463 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ChainBatchRootZero() | 0x655c373c | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ChainExists() | 0x65e8a019 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | CurrentBatchNumberAlreadySet() | 0x5d03f19d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepthMoreThanOneForRecursiveMerkleProof() | 0x68d91b49 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | HashedLogIsDefault() | 0xd356e6ba | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidCaller(address) | 0xcbd9d2e0 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidProofLengthForFinalNode() | 0x48c5fa28 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerkleIndexOutOfBounds() | 0x9bb54c35 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerklePathEmpty() | 0x8e23ac1a | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerklePathOutOfBounds() | 0x1c500385 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerkleWrongIndex(uint256,uint256) | 0x1b582fcf | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerkleWrongLength(uint256,uint256) | 0x485cfcaa | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MessageRootNotRegistered() | 0x913183d8 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NonConsecutiveBatchNumber(uint256,uint256) | 0x366c42f8 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotL2() | 0x8eb4fc01 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotWhitelistedSettlementLayer(uint256) | 0xb30ebfd8 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyAssetTracker(address,address) | 0x3db511f4 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyBridgehubOrChainAssetHandler(address,address,address) | 0x2d396674 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyChain(address,address) | 0x73fe6c1b | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyGateway() | 0xec76af13 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyOnSettlementLayer() | 0x6b75db8c | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyPreV30Chain(uint256) | 0x26d10385 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TotalBatchesExecutedLessThanV30UpgradeChainBatchNumber() | 0x8732442d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TotalBatchesExecutedZero() | 0x70a472bd | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedProofMetadataVersion(uint256) | 0x79274f04 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | V30UpgradeChainBatchNumberAlreadySet() | 0x246de5b7 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | V30UpgradeChainBatchNumberNotSet() | 0x862f0039 | +╰----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ L2MessageVerification ╭----------+----------------------------------------------------------------------------------------------------------+------------╮ | Type | Signature | Selector | +==================================================================================================================================+ +| Function | proveL1DepositParamsInclusion((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x685143b9 | +|----------+----------------------------------------------------------------------------------------------------------+------------| +| Function | proveL1ToL2TransactionStatusShared(uint256,bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0xda24b3ee | +|----------+----------------------------------------------------------------------------------------------------------+------------| | Function | proveL2LeafInclusionShared(uint256,uint256,uint256,bytes32,bytes32[]) | 0x79cf6165 | |----------+----------------------------------------------------------------------------------------------------------+------------| +| Function | proveL2LeafInclusionSharedRecursive(uint256,uint256,uint256,bytes32,bytes32[],uint256) | 0x353d7128 | +|----------+----------------------------------------------------------------------------------------------------------+------------| | Function | proveL2LogInclusionShared(uint256,uint256,uint256,(uint8,bool,uint16,address,bytes32,bytes32),bytes32[]) | 0xe896760d | |----------+----------------------------------------------------------------------------------------------------------+------------| | Function | proveL2MessageInclusionShared(uint256,uint256,uint256,(uint16,address,bytes),bytes32[]) | 0x18b7fc22 | |----------+----------------------------------------------------------------------------------------------------------+------------| +| Error | DepthMoreThanOneForRecursiveMerkleProof() | 0x68d91b49 | +|----------+----------------------------------------------------------------------------------------------------------+------------| | Error | HashedLogIsDefault() | 0xd356e6ba | |----------+----------------------------------------------------------------------------------------------------------+------------| | Error | InvalidProofLengthForFinalNode() | 0x48c5fa28 | @@ -7158,407 +8491,461 @@ L2MessageVerification L2NativeTokenVault -╭----------+-----------------------------------------------------------------+--------------------------------------------------------------------╮ -| Type | Signature | Selector | -+=================================================================================================================================================+ -| Function | BASE_TOKEN_ASSET_ID() | 0xcb944dec | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | L1_CHAIN_ID() | 0x2f90b184 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | L2_LEGACY_SHARED_BRIDGE() | 0xc438a9f2 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | L2_TOKEN_PROXY_BYTECODE_HASH() | 0x2149ed74 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | WETH_TOKEN() | 0x37d277d4 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | acceptOwnership() | 0x79ba5097 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | assetId(address) | 0xfd3f60df | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeBurn(uint256,uint256,bytes32,address,bytes) | 0x699b0fb9 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeMint(uint256,bytes32,bytes) | 0x36ba0355 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgedTokenBeacon() | 0xf2d44246 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | calculateCreate2TokenAddress(uint256,address) | 0xc487412c | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | ensureTokenIsRegistered(address) | 0x19a2a285 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | getERC20Getters(address,uint256) | 0xa7236d16 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | initL2(uint256,address,bytes32,address,address,address,bytes32) | 0x1576078c | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | l2TokenAddress(address) | 0xf5f15168 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | originChainId(bytes32) | 0x5f3455b5 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | owner() | 0x8da5cb5b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pause() | 0x8456cb59 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | paused() | 0x5c975abb | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pendingOwner() | 0xe30c3978 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | registerToken(address) | 0x09824a80 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | renounceOwnership() | 0x715018a6 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setLegacyTokenAssetId(address) | 0x4cd40a02 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | tokenAddress(bytes32) | 0x97bb3ce9 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | tokenDataOriginChainId(bytes) | 0x07a6d4bc | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | transferOwnership(address) | 0xf2fde38b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | tryRegisterTokenFromBurnData(bytes,bytes32) | 0x49b40853 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | unpause() | 0x3f4ba83a | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | updateL2(uint256,bytes32,address,address,bytes32) | 0xb2a399eb | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgeBurn(uint256,bytes32,address,address,uint256) | 0x1cd02155ad1064c60598a8bd0e4e795d7e7d0a0f3c38aad04d261f1297fb2545 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgeMint(uint256,bytes32,address,uint256) | 0xbc0f4055a7869d8ecad34b33382a0bc181c5811565fec42f335505be5fd661d2 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgedTokenBeaconUpdated(address,bytes32) | 0xc3f14dba68f86c42f518e5c0e8a5cbc9514da6f388e2f52c5b1a6263d8588bfb | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | FinalizeDeposit(address,address,address,uint256) | 0xb84fba9af218da60d299dc177abd5805e7ac541d2673cbee7808c10017874f63 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | L2TokenBeaconUpdated(address,bytes32) | 0x01fd5911e6d04aec6b21f19752502ad7f3e9876279643c8fa7a4d30c88a29fb2 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | WithdrawalInitiated(address,address,address,uint256) | 0x2fc3848834aac8e883a2d2a17a7514dc4f2d3dd268089df9b9f5d918259ef3b0 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AddressMismatch(address,address) | 0x1f73225f | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AmountMustBeGreaterThanZero() | 0x5e85ae73 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AssetIdAlreadyRegistered() | 0xfe919e28 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AssetIdMismatch(bytes32,bytes32) | 0x1294e9e1 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AssetIdNotSupported(bytes32) | 0x04a0b7e9 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | BurningNativeWETHNotSupported() | 0xaa5f6180 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | DeployFailed() | 0xb4f54111 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | DeployingBridgedTokenForNativeToken() | 0x138ee1a3 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyAddress() | 0x7138356f | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyBytes32() | 0x1c25715b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyDeposit() | 0x95b66fe9 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyToken() | 0x066f53b1 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidCaller(address) | 0xcbd9d2e0 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidNTVBurnData() | 0xde4c0b96 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NoLegacySharedBridge() | 0xb20b58ce | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NonEmptyMsgValue() | 0x536ec84b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokenIsLegacy() | 0xa51fa558 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokenNotLegacy() | 0x1850b46b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokenNotSupported(address) | 0x06439c6b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokensWithFeesNotSupported() | 0x23830e28 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | U32CastOverflow() | 0xfe3c3c45 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | Unauthorized(address) | 0x8e4a23d6 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | UnsupportedEncodingVersion() | 0x084a1449 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ValueMismatch(uint256,uint256) | 0x626ade30 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ZeroAddress() | 0xd92e233d | -╰----------+-----------------------------------------------------------------+--------------------------------------------------------------------╯ +╭----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=================================================================================================================================================================+ +| Function | ASSET_ROUTER() | 0xc6a70bbb | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | BASE_TOKEN_ASSET_ID() | 0xcb944dec | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | BASE_TOKEN_ORIGIN_TOKEN() | 0x98c35c0b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L2_LEGACY_SHARED_BRIDGE() | 0xc438a9f2 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L2_TOKEN_PROXY_BYTECODE_HASH() | 0x2149ed74 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | WETH_TOKEN() | 0x37d277d4 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | acceptOwnership() | 0x79ba5097 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | addLegacyTokenToBridgedTokensList(address) | 0x2e270c4c | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | assetId(address) | 0xfd3f60df | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeBurn(uint256,uint256,bytes32,address,bytes) | 0x699b0fb9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeMint(uint256,bytes32,bytes) | 0x36ba0355 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokenBeacon() | 0xf2d44246 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokens(uint256) | 0xc409b8f9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokensCount() | 0x88c6e7d8 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | calculateCreate2TokenAddress(uint256,address) | 0xc487412c | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | ensureTokenIsRegistered(address) | 0x19a2a285 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getERC20Getters(address,uint256) | 0xa7236d16 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initL2(uint256,address,bytes32,address,address,address,bytes32,address,uint256) | 0x96d84370 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l2TokenAddress(address) | 0xf5f15168 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | originChainId(bytes32) | 0x5f3455b5 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | originToken(bytes32) | 0xb4541499 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | owner() | 0x8da5cb5b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pause() | 0x8456cb59 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | paused() | 0x5c975abb | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pendingOwner() | 0xe30c3978 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | registerToken(address) | 0x09824a80 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | renounceOwnership() | 0x715018a6 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setAddresses(uint256) | 0x6e7f096e | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setLegacyTokenAssetId(address) | 0x4cd40a02 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenAddress(bytes32) | 0x97bb3ce9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenDataOriginChainId(bytes) | 0x07a6d4bc | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenIndex(bytes32) | 0x31b60086 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferOwnership(address) | 0xf2fde38b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tryRegisterTokenFromBurnData(bytes,bytes32) | 0x49b40853 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unpause() | 0x3f4ba83a | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | updateL2(uint256,bytes32,address,address,bytes32,address,uint256) | 0x72e8f434 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgeBurn(uint256,bytes32,address,address,uint256) | 0x1cd02155ad1064c60598a8bd0e4e795d7e7d0a0f3c38aad04d261f1297fb2545 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgeMint(uint256,bytes32,address,uint256) | 0xbc0f4055a7869d8ecad34b33382a0bc181c5811565fec42f335505be5fd661d2 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgedTokenBeaconUpdated(address,bytes32) | 0xc3f14dba68f86c42f518e5c0e8a5cbc9514da6f388e2f52c5b1a6263d8588bfb | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | FinalizeDeposit(address,address,address,uint256) | 0xb84fba9af218da60d299dc177abd5805e7ac541d2673cbee7808c10017874f63 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | L2TokenBeaconUpdated(address,bytes32) | 0x01fd5911e6d04aec6b21f19752502ad7f3e9876279643c8fa7a4d30c88a29fb2 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | WithdrawalInitiated(address,address,address,uint256) | 0x2fc3848834aac8e883a2d2a17a7514dc4f2d3dd268089df9b9f5d918259ef3b0 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AddressMismatch(address,address) | 0x1f73225f | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AmountMustBeGreaterThanZero() | 0x5e85ae73 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdAlreadyRegistered() | 0xfe919e28 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdMismatch(bytes32,bytes32) | 0x1294e9e1 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdNotSupported(bytes32) | 0x04a0b7e9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | BurningNativeWETHNotSupported() | 0xaa5f6180 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DeployFailed() | 0xb4f54111 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DeployingBridgedTokenForNativeToken() | 0x138ee1a3 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyAddress() | 0x7138356f | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyBytes32() | 0x1c25715b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyDeposit() | 0x95b66fe9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyToken() | 0x066f53b1 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidCaller(address) | 0xcbd9d2e0 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidNTVBurnData() | 0xde4c0b96 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NoLegacySharedBridge() | 0xb20b58ce | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NonEmptyMsgValue() | 0x536ec84b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenAlreadyInBridgedTokensList() | 0x84204265 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenIsLegacy() | 0xa51fa558 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenNotLegacy() | 0x1850b46b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenNotSupported(address) | 0x06439c6b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokensWithFeesNotSupported() | 0x23830e28 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | U32CastOverflow() | 0xfe3c3c45 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Unauthorized(address) | 0x8e4a23d6 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedEncodingVersion() | 0x084a1449 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ValueMismatch(uint256,uint256) | 0x626ade30 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ZeroAddress() | 0xd92e233d | +╰----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------╯ L2NativeTokenVaultDev -╭----------+-----------------------------------------------------------------+--------------------------------------------------------------------╮ -| Type | Signature | Selector | -+=================================================================================================================================================+ -| Function | BASE_TOKEN_ASSET_ID() | 0xcb944dec | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | L1_CHAIN_ID() | 0x2f90b184 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | L2_LEGACY_SHARED_BRIDGE() | 0xc438a9f2 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | L2_TOKEN_PROXY_BYTECODE_HASH() | 0x2149ed74 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | WETH_TOKEN() | 0x37d277d4 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | acceptOwnership() | 0x79ba5097 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | assetId(address) | 0xfd3f60df | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeBurn(uint256,uint256,bytes32,address,bytes) | 0x699b0fb9 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeMint(uint256,bytes32,bytes) | 0x36ba0355 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgedTokenBeacon() | 0xf2d44246 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | calculateCreate2TokenAddress(uint256,address) | 0xc487412c | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | deployBridgedStandardERC20(address) | 0xbfff27c2 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | ensureTokenIsRegistered(address) | 0x19a2a285 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | getERC20Getters(address,uint256) | 0xa7236d16 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | initL2(uint256,address,bytes32,address,address,address,bytes32) | 0x1576078c | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | l2TokenAddress(address) | 0xf5f15168 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | originChainId(bytes32) | 0x5f3455b5 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | owner() | 0x8da5cb5b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pause() | 0x8456cb59 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | paused() | 0x5c975abb | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pendingOwner() | 0xe30c3978 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | registerToken(address) | 0x09824a80 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | renounceOwnership() | 0x715018a6 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setLegacyTokenAssetId(address) | 0x4cd40a02 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | test() | 0xf8a8fd6d | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | tokenAddress(bytes32) | 0x97bb3ce9 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | tokenDataOriginChainId(bytes) | 0x07a6d4bc | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | transferOwnership(address) | 0xf2fde38b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | tryRegisterTokenFromBurnData(bytes,bytes32) | 0x49b40853 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | unpause() | 0x3f4ba83a | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | updateL2(uint256,bytes32,address,address,bytes32) | 0xb2a399eb | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgeBurn(uint256,bytes32,address,address,uint256) | 0x1cd02155ad1064c60598a8bd0e4e795d7e7d0a0f3c38aad04d261f1297fb2545 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgeMint(uint256,bytes32,address,uint256) | 0xbc0f4055a7869d8ecad34b33382a0bc181c5811565fec42f335505be5fd661d2 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgedTokenBeaconUpdated(address,bytes32) | 0xc3f14dba68f86c42f518e5c0e8a5cbc9514da6f388e2f52c5b1a6263d8588bfb | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | FinalizeDeposit(address,address,address,uint256) | 0xb84fba9af218da60d299dc177abd5805e7ac541d2673cbee7808c10017874f63 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | L2TokenBeaconUpdated(address,bytes32) | 0x01fd5911e6d04aec6b21f19752502ad7f3e9876279643c8fa7a4d30c88a29fb2 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | WithdrawalInitiated(address,address,address,uint256) | 0x2fc3848834aac8e883a2d2a17a7514dc4f2d3dd268089df9b9f5d918259ef3b0 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AddressMismatch(address,address) | 0x1f73225f | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AmountMustBeGreaterThanZero() | 0x5e85ae73 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AssetIdAlreadyRegistered() | 0xfe919e28 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AssetIdMismatch(bytes32,bytes32) | 0x1294e9e1 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AssetIdNotSupported(bytes32) | 0x04a0b7e9 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | BurningNativeWETHNotSupported() | 0xaa5f6180 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | DeployingBridgedTokenForNativeToken() | 0x138ee1a3 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyAddress() | 0x7138356f | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyBytes32() | 0x1c25715b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyDeposit() | 0x95b66fe9 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyToken() | 0x066f53b1 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidCaller(address) | 0xcbd9d2e0 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidNTVBurnData() | 0xde4c0b96 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NoLegacySharedBridge() | 0xb20b58ce | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NonEmptyMsgValue() | 0x536ec84b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokenIsLegacy() | 0xa51fa558 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokenNotLegacy() | 0x1850b46b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokenNotSupported(address) | 0x06439c6b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokensWithFeesNotSupported() | 0x23830e28 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | Unauthorized(address) | 0x8e4a23d6 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | UnsupportedEncodingVersion() | 0x084a1449 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ValueMismatch(uint256,uint256) | 0x626ade30 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ZeroAddress() | 0xd92e233d | -╰----------+-----------------------------------------------------------------+--------------------------------------------------------------------╯ +╭----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=================================================================================================================================================================+ +| Function | ASSET_ROUTER() | 0xc6a70bbb | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | BASE_TOKEN_ASSET_ID() | 0xcb944dec | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | BASE_TOKEN_ORIGIN_TOKEN() | 0x98c35c0b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L2_LEGACY_SHARED_BRIDGE() | 0xc438a9f2 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L2_TOKEN_PROXY_BYTECODE_HASH() | 0x2149ed74 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | WETH_TOKEN() | 0x37d277d4 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | acceptOwnership() | 0x79ba5097 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | addLegacyTokenToBridgedTokensList(address) | 0x2e270c4c | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | assetId(address) | 0xfd3f60df | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeBurn(uint256,uint256,bytes32,address,bytes) | 0x699b0fb9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeMint(uint256,bytes32,bytes) | 0x36ba0355 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokenBeacon() | 0xf2d44246 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokens(uint256) | 0xc409b8f9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokensCount() | 0x88c6e7d8 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | calculateCreate2TokenAddress(uint256,address) | 0xc487412c | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | deployBridgedStandardERC20(address) | 0xbfff27c2 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | ensureTokenIsRegistered(address) | 0x19a2a285 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getERC20Getters(address,uint256) | 0xa7236d16 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initL2(uint256,address,bytes32,address,address,address,bytes32,address,uint256) | 0x96d84370 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l2TokenAddress(address) | 0xf5f15168 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | originChainId(bytes32) | 0x5f3455b5 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | originToken(bytes32) | 0xb4541499 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | owner() | 0x8da5cb5b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pause() | 0x8456cb59 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | paused() | 0x5c975abb | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pendingOwner() | 0xe30c3978 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | registerToken(address) | 0x09824a80 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | renounceOwnership() | 0x715018a6 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setAddresses(uint256) | 0x6e7f096e | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setLegacyTokenAssetId(address) | 0x4cd40a02 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | test() | 0xf8a8fd6d | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenAddress(bytes32) | 0x97bb3ce9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenDataOriginChainId(bytes) | 0x07a6d4bc | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenIndex(bytes32) | 0x31b60086 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferOwnership(address) | 0xf2fde38b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tryRegisterTokenFromBurnData(bytes,bytes32) | 0x49b40853 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unpause() | 0x3f4ba83a | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | updateL2(uint256,bytes32,address,address,bytes32,address,uint256) | 0x72e8f434 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgeBurn(uint256,bytes32,address,address,uint256) | 0x1cd02155ad1064c60598a8bd0e4e795d7e7d0a0f3c38aad04d261f1297fb2545 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgeMint(uint256,bytes32,address,uint256) | 0xbc0f4055a7869d8ecad34b33382a0bc181c5811565fec42f335505be5fd661d2 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgedTokenBeaconUpdated(address,bytes32) | 0xc3f14dba68f86c42f518e5c0e8a5cbc9514da6f388e2f52c5b1a6263d8588bfb | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | FinalizeDeposit(address,address,address,uint256) | 0xb84fba9af218da60d299dc177abd5805e7ac541d2673cbee7808c10017874f63 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | L2TokenBeaconUpdated(address,bytes32) | 0x01fd5911e6d04aec6b21f19752502ad7f3e9876279643c8fa7a4d30c88a29fb2 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | WithdrawalInitiated(address,address,address,uint256) | 0x2fc3848834aac8e883a2d2a17a7514dc4f2d3dd268089df9b9f5d918259ef3b0 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AddressMismatch(address,address) | 0x1f73225f | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AmountMustBeGreaterThanZero() | 0x5e85ae73 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdAlreadyRegistered() | 0xfe919e28 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdMismatch(bytes32,bytes32) | 0x1294e9e1 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdNotSupported(bytes32) | 0x04a0b7e9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | BurningNativeWETHNotSupported() | 0xaa5f6180 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DeployingBridgedTokenForNativeToken() | 0x138ee1a3 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyAddress() | 0x7138356f | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyBytes32() | 0x1c25715b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyDeposit() | 0x95b66fe9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyToken() | 0x066f53b1 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidCaller(address) | 0xcbd9d2e0 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidNTVBurnData() | 0xde4c0b96 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NoLegacySharedBridge() | 0xb20b58ce | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NonEmptyMsgValue() | 0x536ec84b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenAlreadyInBridgedTokensList() | 0x84204265 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenIsLegacy() | 0xa51fa558 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenNotLegacy() | 0x1850b46b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenNotSupported(address) | 0x06439c6b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokensWithFeesNotSupported() | 0x23830e28 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Unauthorized(address) | 0x8e4a23d6 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedEncodingVersion() | 0x084a1449 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ValueMismatch(uint256,uint256) | 0x626ade30 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ZeroAddress() | 0xd92e233d | +╰----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------╯ L2NativeTokenVaultZKOS -╭----------+-----------------------------------------------------------------+--------------------------------------------------------------------╮ -| Type | Signature | Selector | -+=================================================================================================================================================+ -| Function | BASE_TOKEN_ASSET_ID() | 0xcb944dec | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | L1_CHAIN_ID() | 0x2f90b184 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | L2_LEGACY_SHARED_BRIDGE() | 0xc438a9f2 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | L2_TOKEN_PROXY_BYTECODE_HASH() | 0x2149ed74 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | WETH_TOKEN() | 0x37d277d4 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | acceptOwnership() | 0x79ba5097 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | assetId(address) | 0xfd3f60df | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeBurn(uint256,uint256,bytes32,address,bytes) | 0x699b0fb9 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgeMint(uint256,bytes32,bytes) | 0x36ba0355 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | bridgedTokenBeacon() | 0xf2d44246 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | calculateCreate2TokenAddress(uint256,address) | 0xc487412c | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | ensureTokenIsRegistered(address) | 0x19a2a285 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | getERC20Getters(address,uint256) | 0xa7236d16 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | initL2(uint256,address,bytes32,address,address,address,bytes32) | 0x1576078c | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | l2TokenAddress(address) | 0xf5f15168 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | originChainId(bytes32) | 0x5f3455b5 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | owner() | 0x8da5cb5b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pause() | 0x8456cb59 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | paused() | 0x5c975abb | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | pendingOwner() | 0xe30c3978 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | registerToken(address) | 0x09824a80 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | renounceOwnership() | 0x715018a6 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | setLegacyTokenAssetId(address) | 0x4cd40a02 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | tokenAddress(bytes32) | 0x97bb3ce9 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | tokenDataOriginChainId(bytes) | 0x07a6d4bc | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | transferOwnership(address) | 0xf2fde38b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | tryRegisterTokenFromBurnData(bytes,bytes32) | 0x49b40853 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | unpause() | 0x3f4ba83a | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Function | updateL2(uint256,bytes32,address,address,bytes32) | 0xb2a399eb | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgeBurn(uint256,bytes32,address,address,uint256) | 0x1cd02155ad1064c60598a8bd0e4e795d7e7d0a0f3c38aad04d261f1297fb2545 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgeMint(uint256,bytes32,address,uint256) | 0xbc0f4055a7869d8ecad34b33382a0bc181c5811565fec42f335505be5fd661d2 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | BridgedTokenBeaconUpdated(address,bytes32) | 0xc3f14dba68f86c42f518e5c0e8a5cbc9514da6f388e2f52c5b1a6263d8588bfb | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | FinalizeDeposit(address,address,address,uint256) | 0xb84fba9af218da60d299dc177abd5805e7ac541d2673cbee7808c10017874f63 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | L2TokenBeaconUpdated(address,bytes32) | 0x01fd5911e6d04aec6b21f19752502ad7f3e9876279643c8fa7a4d30c88a29fb2 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Event | WithdrawalInitiated(address,address,address,uint256) | 0x2fc3848834aac8e883a2d2a17a7514dc4f2d3dd268089df9b9f5d918259ef3b0 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AddressMismatch(address,address) | 0x1f73225f | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AmountMustBeGreaterThanZero() | 0x5e85ae73 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AssetIdAlreadyRegistered() | 0xfe919e28 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AssetIdMismatch(bytes32,bytes32) | 0x1294e9e1 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | AssetIdNotSupported(bytes32) | 0x04a0b7e9 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | BurningNativeWETHNotSupported() | 0xaa5f6180 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | DeployingBridgedTokenForNativeToken() | 0x138ee1a3 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyAddress() | 0x7138356f | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyBytes32() | 0x1c25715b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyDeposit() | 0x95b66fe9 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | EmptyToken() | 0x066f53b1 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidCaller(address) | 0xcbd9d2e0 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidNTVBurnData() | 0xde4c0b96 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NoLegacySharedBridge() | 0xb20b58ce | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | NonEmptyMsgValue() | 0x536ec84b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokenIsLegacy() | 0xa51fa558 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokenNotLegacy() | 0x1850b46b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokenNotSupported(address) | 0x06439c6b | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | TokensWithFeesNotSupported() | 0x23830e28 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | Unauthorized(address) | 0x8e4a23d6 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | UnsupportedEncodingVersion() | 0x084a1449 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ValueMismatch(uint256,uint256) | 0x626ade30 | -|----------+-----------------------------------------------------------------+--------------------------------------------------------------------| -| Error | ZeroAddress() | 0xd92e233d | -╰----------+-----------------------------------------------------------------+--------------------------------------------------------------------╯ +╭----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=================================================================================================================================================================+ +| Function | ASSET_ROUTER() | 0xc6a70bbb | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | BASE_TOKEN_ASSET_ID() | 0xcb944dec | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | BASE_TOKEN_ORIGIN_TOKEN() | 0x98c35c0b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L2_LEGACY_SHARED_BRIDGE() | 0xc438a9f2 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L2_TOKEN_PROXY_BYTECODE_HASH() | 0x2149ed74 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | WETH_TOKEN() | 0x37d277d4 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | acceptOwnership() | 0x79ba5097 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | addLegacyTokenToBridgedTokensList(address) | 0x2e270c4c | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | assetId(address) | 0xfd3f60df | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeBurn(uint256,uint256,bytes32,address,bytes) | 0x699b0fb9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgeMint(uint256,bytes32,bytes) | 0x36ba0355 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokenBeacon() | 0xf2d44246 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokens(uint256) | 0xc409b8f9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokensCount() | 0x88c6e7d8 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | calculateCreate2TokenAddress(uint256,address) | 0xc487412c | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | ensureTokenIsRegistered(address) | 0x19a2a285 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getERC20Getters(address,uint256) | 0xa7236d16 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | initL2(uint256,address,bytes32,address,address,address,bytes32,address,uint256) | 0x96d84370 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | l2TokenAddress(address) | 0xf5f15168 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | originChainId(bytes32) | 0x5f3455b5 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | originToken(bytes32) | 0xb4541499 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | owner() | 0x8da5cb5b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pause() | 0x8456cb59 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | paused() | 0x5c975abb | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pendingOwner() | 0xe30c3978 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | registerToken(address) | 0x09824a80 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | renounceOwnership() | 0x715018a6 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setAddresses(uint256) | 0x6e7f096e | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setLegacyTokenAssetId(address) | 0x4cd40a02 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenAddress(bytes32) | 0x97bb3ce9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenDataOriginChainId(bytes) | 0x07a6d4bc | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenIndex(bytes32) | 0x31b60086 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | transferOwnership(address) | 0xf2fde38b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | tryRegisterTokenFromBurnData(bytes,bytes32) | 0x49b40853 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | unpause() | 0x3f4ba83a | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | updateL2(uint256,bytes32,address,address,bytes32,address,uint256) | 0x72e8f434 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgeBurn(uint256,bytes32,address,address,uint256) | 0x1cd02155ad1064c60598a8bd0e4e795d7e7d0a0f3c38aad04d261f1297fb2545 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgeMint(uint256,bytes32,address,uint256) | 0xbc0f4055a7869d8ecad34b33382a0bc181c5811565fec42f335505be5fd661d2 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | BridgedTokenBeaconUpdated(address,bytes32) | 0xc3f14dba68f86c42f518e5c0e8a5cbc9514da6f388e2f52c5b1a6263d8588bfb | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | FinalizeDeposit(address,address,address,uint256) | 0xb84fba9af218da60d299dc177abd5805e7ac541d2673cbee7808c10017874f63 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | L2TokenBeaconUpdated(address,bytes32) | 0x01fd5911e6d04aec6b21f19752502ad7f3e9876279643c8fa7a4d30c88a29fb2 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferStarted(address,address) | 0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | OwnershipTransferred(address,address) | 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Paused(address) | 0x62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Unpaused(address) | 0x5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | WithdrawalInitiated(address,address,address,uint256) | 0x2fc3848834aac8e883a2d2a17a7514dc4f2d3dd268089df9b9f5d918259ef3b0 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AddressMismatch(address,address) | 0x1f73225f | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AmountMustBeGreaterThanZero() | 0x5e85ae73 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdAlreadyRegistered() | 0xfe919e28 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdMismatch(bytes32,bytes32) | 0x1294e9e1 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | AssetIdNotSupported(bytes32) | 0x04a0b7e9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | BurningNativeWETHNotSupported() | 0xaa5f6180 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DeployingBridgedTokenForNativeToken() | 0x138ee1a3 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyAddress() | 0x7138356f | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyBytes32() | 0x1c25715b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyDeposit() | 0x95b66fe9 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | EmptyToken() | 0x066f53b1 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidCaller(address) | 0xcbd9d2e0 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidNTVBurnData() | 0xde4c0b96 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NoLegacySharedBridge() | 0xb20b58ce | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NonEmptyMsgValue() | 0x536ec84b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenAlreadyInBridgedTokensList() | 0x84204265 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenIsLegacy() | 0xa51fa558 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenNotLegacy() | 0x1850b46b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenNotSupported(address) | 0x06439c6b | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TokensWithFeesNotSupported() | 0x23830e28 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | Unauthorized(address) | 0x8e4a23d6 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedEncodingVersion() | 0x084a1449 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ValueMismatch(uint256,uint256) | 0x626ade30 | +|----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ZeroAddress() | 0xd92e233d | +╰----------+---------------------------------------------------------------------------------+--------------------------------------------------------------------╯ L2ProxyAdminDeployer @@ -7603,8 +8990,6 @@ L2SharedBridgeLegacy |----------+--------------------------------------------------------+--------------------------------------------------------------------| | Error | EmptyBytes32() | 0x1c25715b | |----------+--------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidCaller(address) | 0xcbd9d2e0 | -|----------+--------------------------------------------------------+--------------------------------------------------------------------| | Error | U32CastOverflow() | 0xfe3c3c45 | |----------+--------------------------------------------------------+--------------------------------------------------------------------| | Error | Unauthorized(address) | 0x8e4a23d6 | @@ -7649,8 +9034,6 @@ L2SharedBridgeLegacyDev |----------+--------------------------------------------------------+--------------------------------------------------------------------| | Error | EmptyBytes32() | 0x1c25715b | |----------+--------------------------------------------------------+--------------------------------------------------------------------| -| Error | InvalidCaller(address) | 0xcbd9d2e0 | -|----------+--------------------------------------------------------+--------------------------------------------------------------------| | Error | U32CastOverflow() | 0xfe3c3c45 | |----------+--------------------------------------------------------+--------------------------------------------------------------------| | Error | Unauthorized(address) | 0x8e4a23d6 | @@ -7658,6 +9041,14 @@ L2SharedBridgeLegacyDev | Error | ZeroAddress() | 0xd92e233d | ╰----------+--------------------------------------------------------+--------------------------------------------------------------------╯ +L2V30Upgrade + +╭----------+--------------------------+------------╮ +| Type | Signature | Selector | ++==================================================+ +| Function | upgrade(uint256,address) | 0x028f4e47 | +╰----------+--------------------------+------------╯ + L2WETH ╭----------+---------------------------------------------------------------+--------------------------------------------------------------------╮ @@ -7862,6 +9253,13 @@ L2WrappedBaseTokenStore | Error | ZeroAddress() | 0xd92e233d | ╰----------+-------------------------------------------+--------------------------------------------------------------------╯ +LegacySharedBridgeAddresses + +╭------+-----------+----------╮ +| Type | Signature | Selector | ++=============================+ +╰------+-----------+----------╯ + LibMap ╭------+-----------+----------╮ @@ -7878,18 +9276,28 @@ MailboxFacet |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | bridgehubRequestL2TransactionOnGateway(bytes32,uint64) | 0xddcc9eec | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | depositsPaused() | 0x60da3e83 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | finalizeEthWithdrawal(uint256,uint256,uint16,bytes,bytes32[]) | 0x6c0960f9 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | getName() | 0x17d7de7c | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | l2TransactionBaseCost(uint256,uint256,uint256) | 0xb473318e | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pauseDepositsOnGateway(uint256) | 0x3b064e40 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1DepositParamsInclusion((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x685143b9 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL1ToL2TransactionStatus(bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0x042901c7 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1ToL2TransactionStatusShared(uint256,bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0xda24b3ee | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LeafInclusion(uint256,uint256,bytes32,bytes32[]) | 0x7efda2ae | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LeafInclusionShared(uint256,uint256,uint256,bytes32,bytes32[]) | 0x79cf6165 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LeafInclusionSharedRecursive(uint256,uint256,uint256,bytes32,bytes32[],uint256) | 0x353d7128 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LogInclusion(uint256,uint256,(uint8,bool,uint16,address,bytes32,bytes32),bytes32[]) | 0x263b7f8e | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LogInclusionShared(uint256,uint256,uint256,(uint8,bool,uint16,address,bytes32,bytes32),bytes32[]) | 0xe896760d | @@ -7902,7 +9310,9 @@ MailboxFacet |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | requestL2Transaction(address,uint256,bytes,uint256,uint256,bytes[],address) | 0xeb672419 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | requestL2TransactionToGatewayMailbox(uint256,bytes32,uint64) | 0xd0772551 | +| Function | requestL2TransactionToGatewayMailboxWithBalanceChange(uint256,bytes32,uint64,uint256,bool) | 0x07f10660 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | DepositsPaused(uint256,uint256) | 0xced2f00d0cbddf7694c83a78aae4ecbcfd67ab549e62ef2c307a1502c318228b | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | NewPriorityRequest(uint256,bytes32,uint64,(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes[]) | 0x4531cd5795773d7101c17bdeb9f5ab7f47d7056017506f937083be5d6e77a382 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| @@ -7916,6 +9326,10 @@ MailboxFacet |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | BatchNotExecuted(uint256) | 0x2078a6a0 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepositsPaused() | 0xdeeb6943 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepthMoreThanOneForRecursiveMerkleProof() | 0x68d91b49 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | GasPerPubdataMismatch() | 0xc91cf3b1 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | HashedLogIsDefault() | 0xd356e6ba | @@ -7940,6 +9354,8 @@ MailboxFacet |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | MsgValueTooLow(uint256,uint256) | 0xb385a3da | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotAssetRouter(address,address) | 0xf306a770 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotHyperchain() | 0x32ddf9a2 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotInitializedReentrancyGuard() | 0xdd7e3621 | @@ -7950,6 +9366,8 @@ MailboxFacet |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | OnlyEraSupported() | 0xf3ed9dfa | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyGateway() | 0xec76af13 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | PubdataGreaterThanLimit(uint256,uint256) | 0x959f26fb | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | Reentrancy() | 0xab143c06 | @@ -7982,6 +9400,8 @@ MailboxFacetTest |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | bridgehubRequestL2TransactionOnGateway(bytes32,uint64) | 0xddcc9eec | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | depositsPaused() | 0x60da3e83 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | finalizeEthWithdrawal(uint256,uint256,uint16,bytes,bytes32[]) | 0x6c0960f9 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | getL2GasPrice(uint256) | 0xab07b2e9 | @@ -7990,12 +9410,20 @@ MailboxFacetTest |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | l2TransactionBaseCost(uint256,uint256,uint256) | 0xb473318e | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | pauseDepositsOnGateway(uint256) | 0x3b064e40 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1DepositParamsInclusion((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x685143b9 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL1ToL2TransactionStatus(bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0x042901c7 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1ToL2TransactionStatusShared(uint256,bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0xda24b3ee | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LeafInclusion(uint256,uint256,bytes32,bytes32[]) | 0x7efda2ae | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LeafInclusionShared(uint256,uint256,uint256,bytes32,bytes32[]) | 0x79cf6165 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LeafInclusionSharedRecursive(uint256,uint256,uint256,bytes32,bytes32[],uint256) | 0x353d7128 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LogInclusion(uint256,uint256,(uint8,bool,uint16,address,bytes32,bytes32),bytes32[]) | 0x263b7f8e | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | proveL2LogInclusionShared(uint256,uint256,uint256,(uint8,bool,uint16,address,bytes32,bytes32),bytes32[]) | 0xe896760d | @@ -8008,10 +9436,12 @@ MailboxFacetTest |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | requestL2Transaction(address,uint256,bytes,uint256,uint256,bytes[],address) | 0xeb672419 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | requestL2TransactionToGatewayMailbox(uint256,bytes32,uint64) | 0xd0772551 | +| Function | requestL2TransactionToGatewayMailboxWithBalanceChange(uint256,bytes32,uint64,uint256,bool) | 0x07f10660 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | setFeeParams((uint8,uint32,uint32,uint32,uint32,uint64)) | 0xb4866c43 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | DepositsPaused(uint256,uint256) | 0xced2f00d0cbddf7694c83a78aae4ecbcfd67ab549e62ef2c307a1502c318228b | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | NewPriorityRequest(uint256,bytes32,uint64,(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes[]) | 0x4531cd5795773d7101c17bdeb9f5ab7f47d7056017506f937083be5d6e77a382 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Event | NewPriorityRequestId(uint256,bytes32) | 0x779f441679936c5441b671969f37400b8c3ed0071cb47444431bf985754560df | @@ -8024,6 +9454,10 @@ MailboxFacetTest |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | BatchNotExecuted(uint256) | 0x2078a6a0 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepositsPaused() | 0xdeeb6943 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepthMoreThanOneForRecursiveMerkleProof() | 0x68d91b49 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | GasPerPubdataMismatch() | 0xc91cf3b1 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | HashedLogIsDefault() | 0xd356e6ba | @@ -8048,6 +9482,8 @@ MailboxFacetTest |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | MsgValueTooLow(uint256,uint256) | 0xb385a3da | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotAssetRouter(address,address) | 0xf306a770 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotHyperchain() | 0x32ddf9a2 | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | NotInitializedReentrancyGuard() | 0xdd7e3621 | @@ -8058,6 +9494,8 @@ MailboxFacetTest |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | OnlyEraSupported() | 0xf3ed9dfa | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyGateway() | 0xec76af13 | +|----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | PubdataGreaterThanLimit(uint256,uint256) | 0x959f26fb | |----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Error | Reentrancy() | 0xab143c06 | @@ -8119,61 +9557,135 @@ MessageHashing MessageRootBase -╭----------+-----------------------------------------------------------+--------------------------------------------------------------------╮ -| Type | Signature | Selector | -+===========================================================================================================================================+ -| Function | BRIDGE_HUB() | 0x5d4edca7 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | L1_CHAIN_ID() | 0x2f90b184 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | addNewChain(uint256) | 0xd4ce08c2 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainCount() | 0xe02e1bfd | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainIndex(uint256) | 0x48ceb85e | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainIndexToId(uint256) | 0xed1d7d97 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | chainRegistered(uint256) | 0xb8776d4d | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | getAggregatedRoot() | 0x3977d71c | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | getChainRoot(uint256) | 0x1e4fba05 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | historicalRoot(uint256) | 0x2e9b5cbb | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | sharedTree() | 0xb1fde1a8 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Function | updateFullTree() | 0xbcd1b23d | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | AddedChain(uint256,uint256) | 0x5d96eda109bfd71cf9f4f70c83de31c4150760e8828979a95d9e5f9f15455af7 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | AppendedChainBatchRoot(uint256,uint256,bytes32) | 0x4f7fd9ed016150a623d5a2cf43053fe313a56293a77e060a05db49ed22579520 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | NewChainRoot(uint256,bytes32,bytes32) | 0x55f052ace108bbb0a540b328ff35be177a5c1d1f6e1e1adb46c1fa4bdaa69c10 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Event | NewInteropRoot(uint256,uint256,uint256,bytes32[]) | 0x94a4617be5e5655b97e5cf28ad2038cdc6ae3325b7940f0da8418aac8516a11f | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | ChainExists() | 0x65e8a019 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | MerkleWrongIndex(uint256,uint256) | 0x1b582fcf | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | MerkleWrongLength(uint256,uint256) | 0x485cfcaa | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | MessageRootNotRegistered() | 0x913183d8 | -|----------+-----------------------------------------------------------+--------------------------------------------------------------------| -| Error | OnlyBridgehubOrChainAssetHandler(address,address,address) | 0x2d396674 | -╰----------+-----------------------------------------------------------+--------------------------------------------------------------------╯ +╭----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++==========================================================================================================================================================================================+ +| Function | BRIDGE_HUB() | 0x5d4edca7 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | ERA_GATEWAY_CHAIN_ID() | 0x2b12011d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | L1_CHAIN_ID() | 0x2f90b184 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | addChainBatchRoot(uint256,uint256,bytes32) | 0xfb644fc5 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | addNewChain(uint256,uint256) | 0x66e8a86b | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainBatchRoots(uint256,uint256) | 0x1496c5ce | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainCount() | 0xe02e1bfd | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainIndex(uint256) | 0x48ceb85e | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainIndexToId(uint256) | 0xed1d7d97 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | chainRegistered(uint256) | 0xb8776d4d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | currentChainBatchNumber(uint256) | 0xf688e003 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getAggregatedRoot() | 0x3977d71c | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getChainRoot(uint256) | 0x1e4fba05 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | getProofData(uint256,uint256,uint256,bytes32,bytes32[]) | 0x2f67101d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | historicalRoot(uint256) | 0x2e9b5cbb | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1DepositParamsInclusion((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x685143b9 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL1ToL2TransactionStatusShared(uint256,bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0xda24b3ee | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LeafInclusionShared(uint256,uint256,uint256,bytes32,bytes32[]) | 0x79cf6165 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LeafInclusionSharedRecursive(uint256,uint256,uint256,bytes32,bytes32[],uint256) | 0x353d7128 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2LogInclusionShared(uint256,uint256,uint256,(uint8,bool,uint16,address,bytes32,bytes32),bytes32[]) | 0xe896760d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | proveL2MessageInclusionShared(uint256,uint256,uint256,(uint16,address,bytes),bytes32[]) | 0x18b7fc22 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | saveV30UpgradeChainBatchNumber(uint256) | 0xccb740c4 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | setMigratingChainBatchRoot(uint256,uint256,uint256) | 0xaa1253a5 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | sharedTree() | 0xb1fde1a8 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | updateFullTree() | 0xbcd1b23d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | v30UpgradeChainBatchNumber(uint256) | 0xc44da6ef | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | AddedChain(uint256,uint256) | 0x5d96eda109bfd71cf9f4f70c83de31c4150760e8828979a95d9e5f9f15455af7 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | AppendedChainBatchRoot(uint256,uint256,bytes32) | 0x4f7fd9ed016150a623d5a2cf43053fe313a56293a77e060a05db49ed22579520 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | Initialized(uint8) | 0x7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewChainRoot(uint256,bytes32,bytes32) | 0x55f052ace108bbb0a540b328ff35be177a5c1d1f6e1e1adb46c1fa4bdaa69c10 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewInteropRoot(uint256,uint256,uint256,bytes32[]) | 0x94a4617be5e5655b97e5cf28ad2038cdc6ae3325b7940f0da8418aac8516a11f | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | BatchZeroNotAllowed() | 0xa695b1ef | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ChainBatchRootAlreadyExists(uint256,uint256) | 0xbe263463 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ChainBatchRootZero() | 0x655c373c | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ChainExists() | 0x65e8a019 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | CurrentBatchNumberAlreadySet() | 0x5d03f19d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | DepthMoreThanOneForRecursiveMerkleProof() | 0x68d91b49 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | HashedLogIsDefault() | 0xd356e6ba | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidProofLengthForFinalNode() | 0x48c5fa28 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerkleIndexOutOfBounds() | 0x9bb54c35 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerklePathEmpty() | 0x8e23ac1a | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerklePathOutOfBounds() | 0x1c500385 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerkleWrongIndex(uint256,uint256) | 0x1b582fcf | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MerkleWrongLength(uint256,uint256) | 0x485cfcaa | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MessageRootNotRegistered() | 0x913183d8 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NonConsecutiveBatchNumber(uint256,uint256) | 0x366c42f8 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotWhitelistedSettlementLayer(uint256) | 0xb30ebfd8 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyAssetTracker(address,address) | 0x3db511f4 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyBridgehubOrChainAssetHandler(address,address,address) | 0x2d396674 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyChain(address,address) | 0x73fe6c1b | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyOnSettlementLayer() | 0x6b75db8c | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | OnlyPreV30Chain(uint256) | 0x26d10385 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TotalBatchesExecutedLessThanV30UpgradeChainBatchNumber() | 0x8732442d | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TotalBatchesExecutedZero() | 0x70a472bd | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | UnsupportedProofMetadataVersion(uint256) | 0x79274f04 | +|----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | V30UpgradeChainBatchNumberAlreadySet() | 0x246de5b7 | +╰----------+----------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ MessageVerification ╭----------+----------------------------------------------------------------------------------------------------------+------------╮ | Type | Signature | Selector | +==================================================================================================================================+ +| Function | proveL1DepositParamsInclusion((uint256,uint256,uint256,address,uint16,bytes,bytes32[])) | 0x685143b9 | +|----------+----------------------------------------------------------------------------------------------------------+------------| +| Function | proveL1ToL2TransactionStatusShared(uint256,bytes32,uint256,uint256,uint16,bytes32[],uint8) | 0xda24b3ee | +|----------+----------------------------------------------------------------------------------------------------------+------------| | Function | proveL2LeafInclusionShared(uint256,uint256,uint256,bytes32,bytes32[]) | 0x79cf6165 | |----------+----------------------------------------------------------------------------------------------------------+------------| +| Function | proveL2LeafInclusionSharedRecursive(uint256,uint256,uint256,bytes32,bytes32[],uint256) | 0x353d7128 | +|----------+----------------------------------------------------------------------------------------------------------+------------| | Function | proveL2LogInclusionShared(uint256,uint256,uint256,(uint8,bool,uint16,address,bytes32,bytes32),bytes32[]) | 0xe896760d | |----------+----------------------------------------------------------------------------------------------------------+------------| | Function | proveL2MessageInclusionShared(uint256,uint256,uint256,(uint16,address,bytes),bytes32[]) | 0x18b7fc22 | @@ -8274,6 +9786,8 @@ NativeTokenVaultBase +=====================================================================================================================================+ | Function | acceptOwnership() | 0x79ba5097 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Function | addLegacyTokenToBridgedTokensList(address) | 0x2e270c4c | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | assetId(address) | 0xfd3f60df | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | bridgeBurn(uint256,uint256,bytes32,address,bytes) | 0x699b0fb9 | @@ -8282,6 +9796,10 @@ NativeTokenVaultBase |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | bridgedTokenBeacon() | 0xf2d44246 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokens(uint256) | 0xc409b8f9 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Function | bridgedTokensCount() | 0x88c6e7d8 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | calculateCreate2TokenAddress(uint256,address) | 0xc487412c | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | ensureTokenIsRegistered(address) | 0x19a2a285 | @@ -8290,6 +9808,8 @@ NativeTokenVaultBase |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | originChainId(bytes32) | 0x5f3455b5 | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Function | originToken(bytes32) | 0xb4541499 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | owner() | 0x8da5cb5b | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | pause() | 0x8456cb59 | @@ -8306,6 +9826,8 @@ NativeTokenVaultBase |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | tokenDataOriginChainId(bytes) | 0x07a6d4bc | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Function | tokenIndex(bytes32) | 0x31b60086 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | transferOwnership(address) | 0xf2fde38b | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Function | tryRegisterTokenFromBurnData(bytes,bytes32) | 0x49b40853 | @@ -8348,6 +9870,10 @@ NativeTokenVaultBase |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | NonEmptyMsgValue() | 0x536ec84b | |----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenAlreadyInBridgedTokensList() | 0x84204265 | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| +| Error | TokenNotLegacy() | 0x1850b46b | +|----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | TokenNotSupported(address) | 0x06439c6b | |----------+-----------------------------------------------------+--------------------------------------------------------------------| | Error | TokensWithFeesNotSupported() | 0x23830e28 | @@ -8748,6 +10274,78 @@ ServerNotifier | Error | ZeroAddress() | 0xd92e233d | ╰----------+----------------------------------------------------+--------------------------------------------------------------------╯ +SettlementLayerV30Upgrade + +╭----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╮ +| Type | Signature | Selector | ++=========================================================================================================================================================================================================================================================================================================================================+ +| Function | upgrade(((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes32,bytes32,bytes32,address,(bytes32,bytes32,bytes32),bytes,bytes,uint256,uint256)) | 0x16ef1303 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewL2BootloaderBytecodeHash(bytes32,bytes32) | 0x271b33af94e3f065ecd8659833e6b1daf851f063700c36ddefefab35d4ce4746 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewL2DefaultAccountBytecodeHash(bytes32,bytes32) | 0x36df93a47cc02081d9d8208022ab736fdf98fac566e5fc6f5762bf7666e521f3 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewL2EvmEmulatorBytecodeHash(bytes32,bytes32) | 0x23ee925b859027449030409cb326f0931c0aafa5a72a1306ca1ec354e839e639 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewProtocolVersion(uint256,uint256) | 0x4235104f56661fe2e9d2f2a460b42766581bc45ce366c6a30a9f86c8a2b371a7 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewVerifier(address,address) | 0x2ff4895c300d6993c27f2bb507b4b59d29464dc640af727383451365631ba8b2 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | NewVerifierParams((bytes32,bytes32,bytes32),(bytes32,bytes32,bytes32)) | 0x4c055dbc5f14dcb6e081c9421d9657d950dcd6372f6db0a714b9135171cbc15d | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Event | UpgradeComplete(uint256,bytes32,((uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes32,bytes32,bytes32,address,(bytes32,bytes32,bytes32),bytes,bytes,uint256,uint256)) | 0x6bd09c836cb5c068d0e56c5463173036c9e0664c3c89a09c4b2ea71106abfc37 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | GWNotV30(uint256) | 0x8da071ba | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidTxType(uint256) | 0x5cb29523 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | InvalidUpgradeTxn(uint8) | 0x5f1aa154 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | L2UpgradeNonceNotEqualToNewProtocolVersion(uint256,uint256) | 0xd2c011d6 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | MalformedBytecode(uint8) | 0x43e266b0 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NewProtocolMajorVersionNotZero() | 0x72ea85ad | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | NotAllBatchesExecuted() | 0xf9ba09d6 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | PatchCantSetUpgradeTxn() | 0xd7f50a9d | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | PatchUpgradeCantSetBootloader() | 0x962fd7d0 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | PatchUpgradeCantSetDefaultAccount() | 0x559cc34e | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | PatchUpgradeCantSetEvmEmulator() | 0xc231eccd | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | PreviousProtocolMajorVersionNotZero() | 0x5c598b60 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | PreviousUpgradeNotCleaned() | 0xa0f47245 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | PreviousUpgradeNotFinalized(bytes32) | 0x101ba748 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | PriorityQueueNotReady() | 0xa840274f | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ProtocolVersionMinorDeltaTooBig(uint256,uint256) | 0xd328c12a | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ProtocolVersionTooSmall() | 0x88d7b498 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | PubdataGreaterThanLimit(uint256,uint256) | 0x959f26fb | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | SettlementLayerUpgradeMustPrecedeChainUpgrade() | 0x364b6f8b | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TimeNotReached(uint256,uint256) | 0x08753982 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TooManyFactoryDeps() | 0x76da24b9 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TooMuchGas() | 0xf0b4e88f | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | TxnBodyGasLimitNotEnoughGas() | 0x2e311df8 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ValidateTxnNotEnoughGas() | 0x47b3b145 | +|----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Error | ZeroGasPriceL1TxZKsyncOS() | 0xdb60e600 | +╰----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------╯ + SimpleExecutor ╭----------+--------------------------------+------------╮ @@ -8958,6 +10556,8 @@ TestExecutor |----------+-----------------------------------------------------------+--------------------------------------------------------------------| | Error | RevertedBatchNotAfterNewLastBatch() | 0x9a67c1cb | |----------+-----------------------------------------------------------+--------------------------------------------------------------------| +| Error | SettlementLayerChainIdMismatch() | 0x89935a14 | +|----------+-----------------------------------------------------------+--------------------------------------------------------------------| | Error | SystemLogsSizeTooBig() | 0xae43b424 | |----------+-----------------------------------------------------------+--------------------------------------------------------------------| | Error | TimeNotReached(uint256,uint256) | 0x08753982 | @@ -9040,6 +10640,13 @@ TransactionValidator +=============================+ ╰------+-----------+----------╯ +TransientPrimitivesLib + +╭------+-----------+----------╮ +| Type | Signature | Selector | ++=============================+ +╰------+-----------+----------╯ + TransitionaryOwner ╭----------+--------------------------------------------+------------╮ @@ -9321,6 +10928,8 @@ ZKsyncOSChainTypeManager +================================================================================================================================================================================================================================================+ | Function | BRIDGE_HUB() | 0x5d4edca7 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| +| Function | INTEROP_CENTER() | 0x5ecd0e3a | +|----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | acceptAdmin() | 0x0e18b681 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | acceptOwnership() | 0x79ba5097 | @@ -9335,9 +10944,9 @@ ZKsyncOSChainTypeManager |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | forwardedBridgeBurn(uint256,bytes) | 0xf85894c5 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeMint(uint256,bytes) | 0xe8a71ca9 | +| Function | forwardedBridgeConfirmTransferResult(uint256,uint8,bytes32,address,bytes) | 0x75ceffdf | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| -| Function | forwardedBridgeRecoverFailedTransfer(uint256,bytes32,address,bytes) | 0xb7846107 | +| Function | forwardedBridgeMint(uint256,bytes) | 0xe8a71ca9 | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| | Function | freezeChain(uint256) | 0xaccdd16c | |----------+----------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------| diff --git a/l1-contracts/src.ts/constants.ts b/l1-contracts/src.ts/constants.ts new file mode 100644 index 0000000000..adceb890e7 --- /dev/null +++ b/l1-contracts/src.ts/constants.ts @@ -0,0 +1,42 @@ +// hardhat import should be the first import in the file +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import * as hardhat from "hardhat"; + +import * as fs from "fs"; +import * as path from "path"; + +export const testConfigPath = process.env.ZKSYNC_ENV + ? path.join(process.env.ZKSYNC_HOME as string, "etc/test_config/constant") + : "./test/test_config/constant"; +export const ethTestConfig = JSON.parse(fs.readFileSync(`${testConfigPath}/eth.json`, { encoding: "utf-8" })); + +// eslint-disable-next-line @typescript-eslint/no-var-requires +export const REQUIRED_L2_GAS_PRICE_PER_PUBDATA = require("../../SystemConfig.json").REQUIRED_L2_GAS_PRICE_PER_PUBDATA; + +export const SYSTEM_UPGRADE_L2_TX_TYPE = 254; +export const ADDRESS_ONE = "0x0000000000000000000000000000000000000001"; +export const ETH_ADDRESS_IN_CONTRACTS = ADDRESS_ONE; +export const L1_TO_L2_ALIAS_OFFSET = "0x1111000000000000000000000000000000001111"; +export const L2_BRIDGEHUB_ADDRESS = "0x0000000000000000000000000000000000010002"; +export const L2_ASSET_ROUTER_ADDRESS = "0x0000000000000000000000000000000000010003"; +export const L2_NATIVE_TOKEN_VAULT_ADDRESS = "0x0000000000000000000000000000000000010004"; +export const L2_MESSAGE_ROOT_ADDRESS = "0x0000000000000000000000000000000000010005"; +export const DEPLOYER_SYSTEM_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000008006"; +export const EMPTY_STRING_KECCAK = "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; + +export const HYPERCHAIN_COMMITMENT_ABI_STRING = + "tuple(uint256 totalBatchesExecuted, uint256 totalBatchesVerified, uint256 totalBatchesCommitted, bytes32 l2SystemContractsUpgradeTxHash, uint256 l2SystemContractsUpgradeBatchNumber, bytes32[] batchHashes, tuple(uint256 nextLeafIndex, uint256 startIndex, uint256 unprocessedIndex, bytes32[] sides) priorityTree)"; +export const STORED_BATCH_INFO_ABI_STRING = + "tuple(uint64 batchNumber, bytes32 batchHash, uint64 indexRepeatedStorageChanges, uint256 numberOfLayer1Txs, bytes32 priorityOperationsHash, bytes32 l2LogsTreeRoot, uint256 timestamp, bytes32 commitment)"; +export const COMMIT_BATCH_INFO_ABI_STRING = + "tuple(uint64 batchNumber, uint64 timestamp, uint64 indexRepeatedStorageChanges, bytes32 newStateRoot, uint256 numberOfLayer1Txs, bytes32 priorityOperationsHash, bytes32 bootloaderHeapInitialContentsHash, bytes32 eventsQueueStateHash, bytes systemLogs, bytes operatorDAInput)"; +export const PRIORITY_OPS_BATCH_INFO_ABI_STRING = + "tuple(bytes32[] leftPath, bytes32[] rightPath, bytes32[] itemHashes)"; +export const DIAMOND_CUT_DATA_ABI_STRING = + "tuple(tuple(address facet, uint8 action, bool isFreezable, bytes4[] selectors)[] facetCuts, address initAddress, bytes initCalldata)"; +export const FORCE_DEPLOYMENT_ABI_STRING = + "tuple(bytes32 bytecodeHash, address newAddress, bool callConstructor, uint256 value, bytes input)[]"; +export const BRIDGEHUB_CTM_ASSET_DATA_ABI_STRING = "tuple(uint256 chainId, bytes ctmData, bytes chainData)"; +export const FIXED_FORCE_DEPLOYMENTS_DATA_ABI_STRING = + "tuple(uint256 l1ChainId, uint256 eraChainId, address l1AssetRouter, bytes32 l2TokenProxyBytecodeHash, address aliasedL1Governance, uint256 maxNumberOfZKChains, bytes32 bridgehubBytecodeHash, bytes32 l2AssetRouterBytecodeHash, bytes32 l2NtvBytecodeHash, bytes32 messageRootBytecodeHash)"; +export const ADDITIONAL_FORCE_DEPLOYMENTS_DATA_ABI_STRING = "tuple(bytes32 baseTokenAssetId, address l2Weth)"; diff --git a/l1-contracts/src.ts/deploy-process.ts b/l1-contracts/src.ts/deploy-process.ts index ba5e64c848..3d9116e4a6 100644 --- a/l1-contracts/src.ts/deploy-process.ts +++ b/l1-contracts/src.ts/deploy-process.ts @@ -12,13 +12,8 @@ import type { FacetCut } from "./diamondCut"; import type { Deployer } from "./deploy"; import { getTokens } from "./deploy-token"; -import { - ADDRESS_ONE, - L2_BRIDGEHUB_ADDRESS, - L2_MESSAGE_ROOT_ADDRESS, - isCurrentNetworkLocal, - encodeNTVAssetId, -} from "../src.ts/utils"; +import { ADDRESS_ONE, L2_BRIDGEHUB_ADDRESS, L2_MESSAGE_ROOT_ADDRESS } from "../src.ts/constants"; +import { isCurrentNetworkLocal, encodeNTVAssetId } from "../src.ts/utils"; export const L2_BOOTLOADER_BYTECODE_HASH = "0x1000100000000000000000000000000000000000000000000000000000000000"; export const L2_DEFAULT_ACCOUNT_BYTECODE_HASH = "0x1001000000000000000000000000000000000000000000000000000000000000"; diff --git a/l1-contracts/src.ts/deploy-test-process.ts b/l1-contracts/src.ts/deploy-test-process.ts index c3ddc84304..f56db09725 100644 --- a/l1-contracts/src.ts/deploy-test-process.ts +++ b/l1-contracts/src.ts/deploy-test-process.ts @@ -21,17 +21,9 @@ import { import { deployTokens, getTokens } from "./deploy-token"; import { SYSTEM_CONFIG } from "../scripts/utils"; -import { - testConfigPath, - getNumberFromEnv, - getHashFromEnv, - PubdataPricingMode, - ADDRESS_ONE, - EMPTY_STRING_KECCAK, - isCurrentNetworkLocal, - ETH_ADDRESS_IN_CONTRACTS, - encodeNTVAssetId, -} from "./utils"; +import { getNumberFromEnv, getHashFromEnv, PubdataPricingMode, isCurrentNetworkLocal, encodeNTVAssetId } from "./utils"; +import { testConfigPath, ADDRESS_ONE, EMPTY_STRING_KECCAK, ETH_ADDRESS_IN_CONTRACTS } from "../src.ts/constants"; + import { diamondCut, getCurrentFacetCutsForAdd, facetCut, Action } from "./diamondCut"; import { CONTRACTS_GENESIS_PROTOCOL_VERSION } from "../test/unit_tests/utils"; @@ -60,6 +52,7 @@ export async function loadDefaultEnvVarsForTests(deployWallet: Wallet) { process.env.CONTRACTS_L2_ERC20_BRIDGE_ADDR = ADDRESS_ONE; process.env.CONTRACTS_BRIDGEHUB_PROXY_ADDR = ADDRESS_ONE; process.env.CONTRACTS_L2_DA_VALIDATOR_ADDR = ADDRESS_ONE; + process.env.CONTRACTS_CHAIN_ASSET_HANDLER_ADDR = ADDRESS_ONE; } export async function defaultDeployerForTests(deployWallet: Wallet, ownerAddress: string): Promise { @@ -333,6 +326,7 @@ export class EraDeployer extends Deployer { { chainId: this.chainId, // era chain Id bridgehub: this.addresses.Bridgehub.BridgehubProxy, + interopCenter: this.addresses.Bridgehub.InteropCenterProxy, chainTypeManager: this.addresses.StateTransition.StateTransitionProxy, protocolVersion: CONTRACTS_GENESIS_PROTOCOL_VERSION, admin: this.ownerAddress, diff --git a/l1-contracts/src.ts/deploy-utils.ts b/l1-contracts/src.ts/deploy-utils.ts index 91b82efd28..d462cbf1a1 100644 --- a/l1-contracts/src.ts/deploy-utils.ts +++ b/l1-contracts/src.ts/deploy-utils.ts @@ -4,14 +4,8 @@ import { ethers } from "ethers"; import { Interface } from "ethers/lib/utils"; import { SingletonFactoryFactory } from "../typechain"; -import { - encodeNTVAssetId, - getAddressFromEnv, - getNumberFromEnv, - REQUIRED_L2_GAS_PRICE_PER_PUBDATA, - DEPLOYER_SYSTEM_CONTRACT_ADDRESS, - ADDRESS_ONE, -} from "./utils"; +import { encodeNTVAssetId, getAddressFromEnv, getNumberFromEnv } from "./utils"; +import { REQUIRED_L2_GAS_PRICE_PER_PUBDATA, DEPLOYER_SYSTEM_CONTRACT_ADDRESS, ADDRESS_ONE } from "./constants"; import { IBridgehubFactory } from "../typechain/IBridgehubFactory"; import { IERC20Factory } from "../typechain/IERC20Factory"; @@ -203,6 +197,8 @@ export interface DeployedAddresses { CTMDeploymentTrackerProxy: string; MessageRootImplementation: string; MessageRootProxy: string; + InteropCenterImplementation: string; + InteropCenterProxy: string; }; StateTransition: { StateTransitionProxy: string; diff --git a/l1-contracts/src.ts/deploy.ts b/l1-contracts/src.ts/deploy.ts index 7f2a170242..5fd42de8e2 100644 --- a/l1-contracts/src.ts/deploy.ts +++ b/l1-contracts/src.ts/deploy.ts @@ -37,24 +37,28 @@ import { } from "../scripts/utils"; import { getTokens } from "./deploy-token"; import { - ADDRESS_ONE, getAddressFromEnv, getHashFromEnv, getNumberFromEnv, PubdataPricingMode, hashL2Bytecode, - DIAMOND_CUT_DATA_ABI_STRING, - FIXED_FORCE_DEPLOYMENTS_DATA_ABI_STRING, - REQUIRED_L2_GAS_PRICE_PER_PUBDATA, compileInitialCutHash, readBytecode, applyL1ToL2Alias, - BRIDGEHUB_CTM_ASSET_DATA_ABI_STRING, encodeNTVAssetId, computeL2Create2Address, priorityTxMaxGasLimit, isCurrentNetworkLocal, } from "./utils"; +import { + DIAMOND_CUT_DATA_ABI_STRING, + BRIDGEHUB_CTM_ASSET_DATA_ABI_STRING, + REQUIRED_L2_GAS_PRICE_PER_PUBDATA, + FIXED_FORCE_DEPLOYMENTS_DATA_ABI_STRING, + ADDRESS_ONE, + // L2_MESSAGE_ROOT_ADDRESS, +} from "../src.ts/constants"; + import type { ChainAdminCall } from "./utils"; import { IGovernanceFactory } from "../typechain/IGovernanceFactory"; import { ITransparentUpgradeableProxyFactory } from "../typechain/ITransparentUpgradeableProxyFactory"; @@ -70,7 +74,13 @@ import { ValidatorTimelockFactory } from "../typechain/ValidatorTimelockFactory" import type { FacetCut } from "./diamondCut"; import { getCurrentFacetCutsForAdd } from "./diamondCut"; -import { BridgehubFactory, ChainAdminFactory, ERC20Factory, ChainTypeManagerFactory } from "../typechain"; +import { + BridgehubFactory, + ChainAdminFactory, + ERC20Factory, + ChainTypeManagerFactory, + InteropCenterFactory, +} from "../typechain"; import { IL1AssetRouterFactory } from "../typechain/IL1AssetRouterFactory"; import { IL1NativeTokenVaultFactory } from "../typechain/IL1NativeTokenVaultFactory"; @@ -464,6 +474,43 @@ export class Deployer { this.addresses.Bridgehub.BridgehubProxy = contractAddress; } + public async deployInteropCenterImplementation( + create2Salt: string, + ethTxOptions: ethers.providers.TransactionRequest + ) { + const contractAddress = await this.deployViaCreate2( + "InteropCenter", + [this.addresses.Bridgehub.BridgehubProxy, await this.getL1ChainId(), this.addresses.Governance], + create2Salt, + ethTxOptions + ); + + if (this.verbose) { + console.log(`CONTRACTS_INTEROP_CENTER_IMPL_ADDR=${contractAddress}`); + } + + this.addresses.Bridgehub.InteropCenterImplementation = contractAddress; + } + + public async deployInteropCenterProxy(create2Salt: string, ethTxOptions: ethers.providers.TransactionRequest) { + const bridgehub = new Interface(hardhat.artifacts.readArtifactSync("InteropCenter").abi); + + const initCalldata = bridgehub.encodeFunctionData("initialize", [this.addresses.Governance]); + + const contractAddress = await this.deployViaCreate2( + "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy", + [this.addresses.Bridgehub.InteropCenterImplementation, this.addresses.TransparentProxyAdmin, initCalldata], + create2Salt, + ethTxOptions + ); + + if (this.verbose) { + console.log(`CONTRACTS_INTEROP_CENTER_PROXY_ADDR=${contractAddress}`); + } + + this.addresses.Bridgehub.InteropCenterProxy = contractAddress; + } + public async deployMessageRootImplementation(create2Salt: string, ethTxOptions: ethers.providers.TransactionRequest) { const contractAddress = await this.deployViaCreate2( "MessageRoot", @@ -504,7 +551,7 @@ export class Deployer { ) { const contractAddress = await this.deployViaCreate2( "ChainTypeManager", - [this.addresses.Bridgehub.BridgehubProxy], + [this.addresses.Bridgehub.BridgehubProxy, this.addresses.Bridgehub.InteropCenterProxy], create2Salt, { ...ethTxOptions, @@ -586,9 +633,10 @@ export class Deployer { public async deployMailboxFacet(create2Salt: string, ethTxOptions: ethers.providers.TransactionRequest) { const eraChainId = getNumberFromEnv("CONTRACTS_ERA_CHAIN_ID"); + const chainAssetHandler = getAddressFromEnv("CONTRACTS_CHAIN_ASSET_HANDLER_ADDR"); const contractAddress = await this.deployViaCreate2( "MailboxFacet", - [eraChainId, await this.getL1ChainId()], + [eraChainId, await this.getL1ChainId(), chainAssetHandler], create2Salt, ethTxOptions ); @@ -824,7 +872,7 @@ export class Deployer { const contractName = isCurrentNetworkLocal() ? "L1NullifierDev" : "L1Nullifier"; const contractAddress = await this.deployViaCreate2( contractName, - [this.addresses.Bridgehub.BridgehubProxy, eraChainId, eraDiamondProxy], + [this.addresses.Bridgehub.BridgehubProxy, this.addresses.Bridgehub.BridgehubProxy, eraChainId, eraDiamondProxy], create2Salt, ethTxOptions ); @@ -868,6 +916,7 @@ export class Deployer { [ l1WethToken, this.addresses.Bridgehub.BridgehubProxy, + this.addresses.Bridgehub.InteropCenterProxy, this.addresses.Bridges.L1NullifierProxy, eraChainId, eraDiamondProxy, @@ -1019,7 +1068,11 @@ export class Deployer { ) { const contractAddress = await this.deployViaCreate2( "CTMDeploymentTracker", - [this.addresses.Bridgehub.BridgehubProxy, this.addresses.Bridges.SharedBridgeProxy], + [ + this.addresses.Bridgehub.BridgehubProxy, + this.addresses.Bridgehub.InteropCenterProxy, + this.addresses.Bridges.SharedBridgeProxy, + ], create2Salt, ethTxOptions ); @@ -1070,13 +1123,19 @@ export class Deployer { public async registerAddresses() { const bridgehub = this.bridgehubContract(this.deployWallet); + const interopCenter = this.interopCenter(this.deployWallet); const upgradeData1 = await bridgehub.interface.encodeFunctionData("setAddresses", [ this.addresses.Bridges.SharedBridgeProxy, this.addresses.Bridgehub.CTMDeploymentTrackerProxy, this.addresses.Bridgehub.MessageRootProxy, + this.addresses.Bridgehub.InteropCenterProxy, + ]); + const upgradeData2 = await interopCenter.interface.encodeFunctionData("setAddresses", [ + this.addresses.Bridges.SharedBridgeProxy, ]); await this.executeUpgrade(this.addresses.Bridgehub.BridgehubProxy, 0, upgradeData1); + await this.executeUpgrade(this.addresses.Bridgehub.InteropCenterProxy, 0, upgradeData2); if (this.verbose) { console.log("Shared bridge was registered in Bridgehub"); } @@ -1158,6 +1217,8 @@ export class Deployer { await this.deployBridgehubProxy(create2Salt, { gasPrice }); await this.deployMessageRootImplementation(create2Salt, { gasPrice }); await this.deployMessageRootProxy(create2Salt, { gasPrice }); + await this.deployInteropCenterImplementation(create2Salt, { gasPrice }); + await this.deployInteropCenterProxy(create2Salt, { gasPrice }); } public async deployChainTypeManagerContract( @@ -1209,7 +1270,7 @@ export class Deployer { if (this.verbose) { console.log("CTM deployment tracker whitelisted in L1 Shared Bridge", receipt2.gasUsed.toString()); console.log( - `CONTRACTS_CTM_ASSET_INFO=${await bridgehub.ctmAssetId(this.addresses.StateTransition.StateTransitionProxy)}` + `CONTRACTS_CTM_ASSET_INFO=${await bridgehub.ctmAssetIdFromAddress(this.addresses.StateTransition.StateTransitionProxy)}` ); } @@ -1223,7 +1284,7 @@ export class Deployer { receipt3.gasUsed.toString() ); console.log( - `CONTRACTS_CTM_ASSET_INFO=${await bridgehub.ctmAssetId(this.addresses.StateTransition.StateTransitionProxy)}` + `CONTRACTS_CTM_ASSET_INFO=${await bridgehub.ctmAssetIdFromAddress(this.addresses.StateTransition.StateTransitionProxy)}` ); } } else { @@ -1420,7 +1481,7 @@ export class Deployer { console.log(`CHAIN_ETH_ZKSYNC_NETWORK_ID=${parseInt(chainId, 16)}`); console.log( - `CONTRACTS_CTM_ASSET_INFO=${await bridgehub.ctmAssetId(this.addresses.StateTransition.StateTransitionProxy)}` + `CONTRACTS_CTM_ASSET_INFO=${await bridgehub.ctmAssetIdFromAddress(this.addresses.StateTransition.StateTransitionProxy)}` ); console.log(`CONTRACTS_BASE_TOKEN_ADDR=${baseTokenAddress}`); } @@ -1811,6 +1872,10 @@ export class Deployer { return BridgehubFactory.connect(this.addresses.Bridgehub.BridgehubProxy, signerOrProvider); } + public interopCenter(signerOrProvider: Signer | providers.Provider) { + return InteropCenterFactory.connect(this.addresses.Bridgehub.InteropCenterProxy, signerOrProvider); + } + public chainTypeManagerContract(signerOrProvider: Signer | providers.Provider) { return ChainTypeManagerFactory.connect(this.addresses.StateTransition.StateTransitionProxy, signerOrProvider); } diff --git a/l1-contracts/src.ts/utils.ts b/l1-contracts/src.ts/utils.ts index ffb7d1bfac..c301cd7070 100644 --- a/l1-contracts/src.ts/utils.ts +++ b/l1-contracts/src.ts/utils.ts @@ -5,31 +5,13 @@ import * as hardhat from "hardhat"; import type { BytesLike, BigNumberish } from "ethers"; import { ethers } from "ethers"; import * as fs from "fs"; -import * as path from "path"; import { DiamondInitFactory } from "../typechain"; import type { DiamondCut, FacetCut } from "./diamondCut"; import { diamondCut } from "./diamondCut"; import { SYSTEM_CONFIG, web3Url } from "../scripts/utils"; import { Wallet as ZkWallet, Provider } from "zksync-ethers"; +import { L2_NATIVE_TOKEN_VAULT_ADDRESS, L1_TO_L2_ALIAS_OFFSET } from "./constants"; -export const testConfigPath = process.env.ZKSYNC_ENV - ? path.join(process.env.ZKSYNC_HOME as string, "etc/test_config/constant") - : "./test/test_config/constant"; -export const ethTestConfig = JSON.parse(fs.readFileSync(`${testConfigPath}/eth.json`, { encoding: "utf-8" })); - -// eslint-disable-next-line @typescript-eslint/no-var-requires -export const REQUIRED_L2_GAS_PRICE_PER_PUBDATA = require("../../SystemConfig.json").REQUIRED_L2_GAS_PRICE_PER_PUBDATA; - -export const SYSTEM_UPGRADE_L2_TX_TYPE = 254; -export const ADDRESS_ONE = "0x0000000000000000000000000000000000000001"; -export const ETH_ADDRESS_IN_CONTRACTS = ADDRESS_ONE; -export const L1_TO_L2_ALIAS_OFFSET = "0x1111000000000000000000000000000000001111"; -export const L2_BRIDGEHUB_ADDRESS = "0x0000000000000000000000000000000000010002"; -export const L2_ASSET_ROUTER_ADDRESS = "0x0000000000000000000000000000000000010003"; -export const L2_NATIVE_TOKEN_VAULT_ADDRESS = "0x0000000000000000000000000000000000010004"; -export const L2_MESSAGE_ROOT_ADDRESS = "0x0000000000000000000000000000000000010005"; -export const DEPLOYER_SYSTEM_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000008006"; -export const EMPTY_STRING_KECCAK = "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; const CREATE2_PREFIX = ethers.utils.solidityKeccak256(["string"], ["zksyncCreate2"]); export const priorityTxMaxGasLimit = getNumberFromEnv("CONTRACTS_PRIORITY_TX_MAX_GAS_LIMIT"); @@ -316,6 +298,7 @@ export function compileInitialCutHash( { chainId: "0x0000000000000000000000000000000000000000000000000000000000000001", bridgehub: "0x0000000000000000000000000000000000001234", + interopCenter: "0x0000000000000000000000000000000000001235", chainTypeManager: "0x0000000000000000000000000000000000002234", protocolVersion: "0x0000000000000000000000000000000000002234", admin: "0x0000000000000000000000000000000000003234", @@ -332,7 +315,7 @@ export function compileInitialCutHash( }, ]); - return diamondCut(facetCuts, diamondInit, "0x" + diamondInitCalldata.slice(2 + (4 + 8 * 32) * 2)); + return diamondCut(facetCuts, diamondInit, "0x" + diamondInitCalldata.slice(2 + (4 + 9 * 32) * 2)); } export enum PubdataSource { diff --git a/l1-contracts/test/foundry/l1/integration/AssetRouterTest.t.sol b/l1-contracts/test/foundry/l1/integration/AssetRouterTest.t.sol index c9c11a057f..b853b20d81 100644 --- a/l1-contracts/test/foundry/l1/integration/AssetRouterTest.t.sol +++ b/l1-contracts/test/foundry/l1/integration/AssetRouterTest.t.sol @@ -1,37 +1,45 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; -import {Test} from "forge-std/Test.sol"; +import {StdStorage, stdStorage} from "forge-std/Test.sol"; +import {IBridgehubBase, L2TransactionRequestDirect, L2TransactionRequestTwoBridgesOuter} from "contracts/bridgehub/IBridgehubBase.sol"; import {Vm} from "forge-std/Vm.sol"; -import {console2 as console} from "forge-std/console2.sol"; -import {IBridgehubBase, L2TransactionRequestTwoBridgesOuter} from "contracts/bridgehub/IBridgehubBase.sol"; import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; - import {TestnetERC20Token} from "contracts/dev-contracts/TestnetERC20Token.sol"; import {SimpleExecutor} from "contracts/dev-contracts/SimpleExecutor.sol"; +import {IMessageRoot, IMessageVerification} from "contracts/bridgehub/IMessageRoot.sol"; + import {L1ContractDeployer} from "./_SharedL1ContractDeployer.t.sol"; import {TokenDeployer} from "./_SharedTokenDeployer.t.sol"; import {ZKChainDeployer} from "./_SharedZKChainDeployer.t.sol"; import {L2TxMocker} from "./_SharedL2TxMocker.t.sol"; import {ETH_TOKEN_ADDRESS, REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol"; import {L2Message} from "contracts/common/Messaging.sol"; + import {L2_ASSET_ROUTER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {IChainAssetHandler} from "contracts/bridgehub/IChainAssetHandler.sol"; import {NativeTokenVaultBase} from "contracts/bridge/ntv/NativeTokenVaultBase.sol"; import {L2NativeTokenVault} from "contracts/bridge/ntv/L2NativeTokenVault.sol"; import {FinalizeL1DepositParams} from "contracts/bridge/interfaces/IL1Nullifier.sol"; import {NEW_ENCODING_VERSION} from "contracts/bridge/asset-router/IAssetRouterBase.sol"; import {AssetRouterBase} from "contracts/bridge/asset-router/AssetRouterBase.sol"; import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; +import {ProofData} from "contracts/common/libraries/MessageHashing.sol"; import {L2CanonicalTransaction} from "contracts/common/Messaging.sol"; import {BridgeHelper} from "contracts/bridge/BridgeHelper.sol"; import {BridgedStandardERC20, NonSequentialVersion} from "contracts/bridge/BridgedStandardERC20.sol"; import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; +import {IAssetTrackerBase} from "contracts/bridge/asset-tracker/IAssetTrackerBase.sol"; + import {ConfigSemaphore} from "./utils/_ConfigSemaphore.sol"; contract AssetRouterIntegrationTest is L1ContractDeployer, ZKChainDeployer, TokenDeployer, L2TxMocker, ConfigSemaphore { + using stdStorage for StdStorage; + bytes32 constant NEW_PRIORITY_REQUEST_HASH = keccak256( "NewPriorityRequest(uint256,bytes32,uint64,(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256[4],bytes,bytes,uint256[],bytes,bytes),bytes[])" @@ -72,14 +80,14 @@ contract AssetRouterIntegrationTest is L1ContractDeployer, ZKChainDeployer, Toke _registerNewTokens(tokens); _deployEra(); + _deployZKChain(ETH_TOKEN_ADDRESS); + _deployZKChain(ETH_TOKEN_ADDRESS); + _deployZKChain(tokens[0]); + _deployZKChain(tokens[0]); + _deployZKChain(tokens[1]); + _deployZKChain(tokens[1]); simpleExecutor = new SimpleExecutor(); - // _deployHyperchain(ETH_TOKEN_ADDRESS); - // _deployHyperchain(ETH_TOKEN_ADDRESS); - // _deployHyperchain(tokens[0]); - // _deployHyperchain(tokens[0]); - // _deployHyperchain(tokens[1]); - // _deployHyperchain(tokens[1]); releaseConfigLock(); @@ -91,16 +99,78 @@ contract AssetRouterIntegrationTest is L1ContractDeployer, ZKChainDeployer, Toke } } + function _setAssetTrackerChainBalance(uint256 _chainId, address _token, uint256 _value) internal { + bytes32 assetId = DataEncoding.encodeNTVAssetId(eraZKChainId, _token); + if (address(addresses.l1AssetTracker) != address(0)) { + stdstore + .target(address(addresses.l1AssetTracker)) + .sig(IAssetTrackerBase.chainBalance.selector) + .with_key(_chainId) + .with_key(assetId) + .checked_write(_value); + } + } + function setUp() public { prepare(); + bytes32 ETH_TOKEN_ASSET_ID = DataEncoding.encodeNTVAssetId(eraZKChainId, ETH_TOKEN_ADDRESS); + + vm.mockCall( + address(ecosystemAddresses.bridgehub.chainAssetHandlerProxy), + abi.encodeWithSelector(IChainAssetHandler.migrationNumber.selector), + abi.encode(0) + ); + vm.mockCall( + address(ecosystemAddresses.bridgehub.messageRootProxy), + abi.encodeWithSelector(IMessageRoot.v30UpgradeChainBatchNumber.selector), + abi.encode(10) + ); + + _setAssetTrackerChainBalance(eraZKChainId, ETH_TOKEN_ADDRESS, 1e30); + _setAssetTrackerChainBalance(506, ETH_TOKEN_ADDRESS, 1e30); + bytes32 ethAssetId = 0x8df3463b1850eb1d8d1847743ea155aef6b16074db8ba81d897dc30554fb2085; + stdstore + .target(address(ecosystemAddresses.bridgehub.assetTrackerProxy)) + .sig(IAssetTrackerBase.chainBalance.selector) + .with_key(eraZKChainId) + .with_key(ETH_TOKEN_ASSET_ID) + .checked_write(100); + vm.prank(Ownable2StepUpgradeable(addresses.l1NativeTokenVault).pendingOwner()); + Ownable2StepUpgradeable(addresses.l1NativeTokenVault).acceptOwnership(); } function depositToL1(address _tokenAddress) public { vm.mockCall( - address(addresses.bridgehub), - abi.encodeWithSelector(IBridgehubBase.proveL2MessageInclusion.selector), + address(ecosystemAddresses.bridgehub.messageRootProxy), + abi.encodeWithSelector(IMessageVerification.proveL2MessageInclusionShared.selector), abi.encode(true) ); + vm.mockCall( + address(addresses.bridgehub), + abi.encodeWithSelector(IBridgehubBase.settlementLayer.selector), + abi.encode(506) + ); + vm.mockCall( + address(ecosystemAddresses.bridgehub.messageRootProxy), + abi.encodeWithSelector(IMessageRoot.getProofData.selector), + abi.encode( + ProofData({ + settlementLayerChainId: 506, + settlementLayerBatchNumber: 0, + settlementLayerBatchRootMask: 0, + batchLeafProofLen: 0, + batchSettlementRoot: 0, + chainIdLeaf: 0, + ptr: 0, + finalProofNode: false + }) + ) + ); + vm.mockCall( + address(ecosystemAddresses.bridgehub.messageRootProxy), + abi.encodeWithSelector(IMessageRoot.v30UpgradeChainBatchNumber.selector), + abi.encode(10) + ); uint256 chainId = eraZKChainId; l2TokenAssetId = DataEncoding.encodeNTVAssetId(chainId, _tokenAddress); bytes memory transferData = DataEncoding.encodeBridgeMintData({ @@ -211,6 +281,28 @@ contract AssetRouterIntegrationTest is L1ContractDeployer, ZKChainDeployer, Toke ); } + function test_DepositDirect() public { + depositToL1(ETH_TOKEN_ADDRESS); + bytes memory secondBridgeCalldata = bytes.concat( + NEW_ENCODING_VERSION, + abi.encode(l2TokenAssetId, abi.encode(uint256(100), address(this))) + ); + IERC20(tokenL1Address).approve(address(addresses.l1NativeTokenVault), 100); + addresses.bridgehub.requestL2TransactionDirect{value: 250000000000100}( + L2TransactionRequestDirect({ + chainId: eraZKChainId, + mintValue: 250000000000100, + l2Contract: address(addresses.sharedBridge), + l2Value: 0, + l2Calldata: secondBridgeCalldata, + l2GasLimit: 1000000, + l2GasPerPubdataByteLimit: REQUIRED_L2_GAS_PRICE_PER_PUBDATA, + factoryDeps: new bytes[](0), + refundRecipient: address(0) + }) + ); + } + function test_DepositToL1AndWithdraw7702() public { uint256 randomCallerPk = uint256(keccak256("RANDOM_CALLER")); address payable randomCaller = payable(vm.addr(randomCallerPk)); diff --git a/l1-contracts/test/foundry/l1/integration/AssetTrackerTest.t.sol b/l1-contracts/test/foundry/l1/integration/AssetTrackerTest.t.sol new file mode 100644 index 0000000000..9418d16f15 --- /dev/null +++ b/l1-contracts/test/foundry/l1/integration/AssetTrackerTest.t.sol @@ -0,0 +1,383 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {console} from "forge-std/console.sol"; + +import {StdStorage, Test, stdStorage} from "forge-std/Test.sol"; + +import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; + +import {IMailbox} from "contracts/state-transition/chain-interfaces/IMailbox.sol"; +import {IMailboxImpl} from "contracts/state-transition/chain-interfaces/IMailboxImpl.sol"; + +import {L1ContractDeployer} from "./_SharedL1ContractDeployer.t.sol"; +import {TokenDeployer} from "./_SharedTokenDeployer.t.sol"; +import {ZKChainDeployer} from "./_SharedZKChainDeployer.t.sol"; +import {L2TxMocker} from "./_SharedL2TxMocker.t.sol"; +import {ETH_TOKEN_ADDRESS, SERVICE_TRANSACTION_SENDER} from "contracts/common/Config.sol"; +import {ConfirmBalanceMigrationData, L2Message, TokenBalanceMigrationData} from "contracts/common/Messaging.sol"; +import {GW_ASSET_TRACKER, GW_ASSET_TRACKER_ADDR, L2_ASSET_ROUTER_ADDR, L2_ASSET_ROUTER, L2_ASSET_TRACKER_ADDR, L2_BRIDGEHUB, L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR, L2_COMPLEX_UPGRADER_ADDR, L2_NATIVE_TOKEN_VAULT, L2_NATIVE_TOKEN_VAULT_ADDR, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; + +import {AddressesAlreadyGenerated} from "test/foundry/L1TestsErrors.sol"; +import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; + +import {TOKEN_BALANCE_MIGRATION_DATA_VERSION} from "contracts/bridge/asset-tracker/IAssetTrackerBase.sol"; +import {FinalizeL1DepositParams} from "contracts/bridge/interfaces/IL1Nullifier.sol"; +import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol"; +import {IChainAssetHandler} from "contracts/bridgehub/IChainAssetHandler.sol"; +import {IL2AssetTracker, L2AssetTracker} from "contracts/bridge/asset-tracker/L2AssetTracker.sol"; +import {IL1AssetTracker, L1AssetTracker} from "contracts/bridge/asset-tracker/L1AssetTracker.sol"; +import {GWAssetTracker, IGWAssetTracker} from "contracts/bridge/asset-tracker/GWAssetTracker.sol"; +import {IMessageVerification} from "contracts/bridgehub/IMessageRoot.sol"; + +import {IAssetTrackerDataEncoding} from "contracts/bridge/asset-tracker/IAssetTrackerDataEncoding.sol"; +import {IL1NativeTokenVault} from "contracts/bridge/ntv/IL1NativeTokenVault.sol"; + +contract AssetTrackerTests is L1ContractDeployer, ZKChainDeployer, TokenDeployer, L2TxMocker { + using stdStorage for StdStorage; + + uint256 constant TEST_USERS_COUNT = 10; + address[] public users; + address[] public l2ContractAddresses; + + IBridgehubBase l2Bridgehub; + IL1AssetTracker assetTracker; + IL2AssetTracker l2AssetTracker; + IGWAssetTracker gwAssetTracker; + address l1AssetTracker = address(0); + + address tokenAddress; + bytes32 assetId; + uint256 originalChainId; + uint256 gwChainId; + bytes32 assetMigrationNumberLocation; + bytes32 totalSupplyAcrossAllChainsLocation; + uint256 migrationNumber = 20; + bytes32 chainBalanceLocation; + uint256 amount = 1000000000000000000; + + // generate MAX_USERS addresses and append it to users array + function _generateUserAddresses() internal { + if (users.length != 0) { + revert AddressesAlreadyGenerated(); + } + + for (uint256 i = 0; i < TEST_USERS_COUNT; i++) { + address newAddress = makeAddr(string(abi.encode("account", i))); + users.push(newAddress); + } + } + + function prepare() public { + _generateUserAddresses(); + + _deployL1Contracts(); + _deployTokens(); + _registerNewTokens(tokens); + + _deployEra(); + // _deployZKChain(ETH_TOKEN_ADDRESS); + // _deployZKChain(ETH_TOKEN_ADDRESS); + // _deployZKChain(tokens[0]); + // _deployZKChain(tokens[0]); + // _deployZKChain(tokens[1]); + // _deployZKChain(tokens[1]); + + for (uint256 i = 0; i < zkChainIds.length; i++) { + address contractAddress = makeAddr(string(abi.encode("contract", i))); + l2ContractAddresses.push(contractAddress); + + _addL2ChainContract(zkChainIds[i], contractAddress); + } + + assetTracker = IL1AssetTracker( + address(IL1NativeTokenVault(ecosystemAddresses.vaults.l1NativeTokenVaultProxy).l1AssetTracker()) + ); + address l2AssetTrackerAddress = address(new L2AssetTracker()); + vm.etch(L2_ASSET_TRACKER_ADDR, l2AssetTrackerAddress.code); + l2AssetTracker = IL2AssetTracker(L2_ASSET_TRACKER_ADDR); + address gwAssetTrackerAddress = address(new GWAssetTracker()); + vm.etch(GW_ASSET_TRACKER_ADDR, gwAssetTrackerAddress.code); + gwAssetTracker = IGWAssetTracker(GW_ASSET_TRACKER_ADDR); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + l2AssetTracker.setAddresses(block.chainid, bytes32(0)); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + gwAssetTracker.setAddresses(block.chainid); + + vm.mockCall( + L2_BRIDGEHUB_ADDR, + abi.encodeWithSelector(IBridgehubBase.settlementLayer.selector), + abi.encode(block.chainid) + ); + } + + function setUp() public { + originalChainId = block.chainid; + gwChainId = 1; + prepare(); + tokenAddress = tokens[1]; + assetId = DataEncoding.encodeNTVAssetId(block.chainid, tokenAddress); + + // 0x13b704bded2382d6e555a218f4d57330c8d624337c03a7aa1779d78f557b4126; + // the below does not work for some reason: + } + + function getChainBalanceLocation(bytes32 _assetId, uint256 _chainId) internal pure returns (bytes32) { + return computeNestedMappingSlot(uint256(_assetId), _chainId, 0 + 151); + } + + function getAssetMigrationNumberLocation(bytes32 _assetId, uint256 _chainId) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(_assetId, keccak256(abi.encodePacked(_chainId, uint256(1 + 151))))); + } + + function getTotalSupplyAcrossAllChainsLocation(bytes32 _assetId) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(_assetId, uint256(2 + 151))); + } + + function computeNestedMappingSlot( + uint256 outerKey, + uint256 innerKey, + uint256 baseSlot + ) internal pure returns (bytes32) { + // Computes keccak256(abi.encode(outerKey, keccak256(abi.encode(innerKey, baseSlot)))) + bytes32 innerHash = keccak256(abi.encodePacked(innerKey, baseSlot)); + return keccak256(abi.encode(outerKey, innerHash)); + } + + function test_migrationL1ToGateway() public { + // vm.chainId(eraZKChainId); + // vm.mockCall( + // L2_NATIVE_TOKEN_VAULT_ADDR, + // abi.encodeWithSelector(L2_NATIVE_TOKEN_VAULT.tokenAddress.selector), + // abi.encode(tokenAddress) + // ); + // vm.mockCall( + // L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + // abi.encodeWithSelector(L2_TO_L1_MESSENGER_SYSTEM_CONTRACT.sendToL1.selector), + // abi.encode(bytes32(0)) + // ); + // assetTracker.initiateL1ToGatewayMigrationOnL2(assetId); + TokenBalanceMigrationData memory data = TokenBalanceMigrationData({ + version: TOKEN_BALANCE_MIGRATION_DATA_VERSION, + chainId: eraZKChainId, + assetId: assetId, + tokenOriginChainId: originalChainId, + amount: amount, + chainMigrationNumber: migrationNumber, + assetMigrationNumber: migrationNumber - 1, + originToken: tokenAddress, + isL1ToGateway: true + }); + ConfirmBalanceMigrationData memory confirmData = ConfirmBalanceMigrationData({ + version: TOKEN_BALANCE_MIGRATION_DATA_VERSION, + isL1ToGateway: true, + chainId: eraZKChainId, + assetId: assetId, + migrationNumber: migrationNumber, + amount: amount + }); + bytes memory encodedData = abi.encodeCall(IAssetTrackerDataEncoding.receiveMigrationOnL1, data); + + FinalizeL1DepositParams memory finalizeWithdrawalParamsL1ToGateway = FinalizeL1DepositParams({ + chainId: eraZKChainId, + l2BatchNumber: 0, + l2MessageIndex: 0, + l2Sender: L2_ASSET_TRACKER_ADDR, + l2TxNumberInBatch: 0, + message: encodedData, + merkleProof: new bytes32[](0) + }); + vm.chainId(originalChainId); + vm.mockCall( + address(ecosystemAddresses.bridgehub.messageRootProxy), + abi.encodeWithSelector(IMessageVerification.proveL2MessageInclusionShared.selector), + abi.encode(true) + ); + vm.mockCall( + address(addresses.bridgehub), + abi.encodeWithSelector(IBridgehubBase.settlementLayer.selector), + abi.encode(gwChainId) + ); + bytes[] memory mocks1 = new bytes[](2); + bytes32 randomHash = keccak256(abi.encode(assetId)); + mocks1[0] = abi.encode(randomHash); + mocks1[1] = abi.encode(randomHash); + vm.mockCalls( + address(0x0000000000000000000000000000000000000011), + abi.encodeWithSelector(IMailboxImpl.requestL2ServiceTransaction.selector), + mocks1 + ); + bytes[] memory mocks2 = new bytes[](2); + mocks2[0] = abi.encode(0x0000000000000000000000000000000000000011); + mocks2[1] = abi.encode(0x0000000000000000000000000000000000000011); + + vm.mockCalls(address(addresses.bridgehub), abi.encodeWithSelector(IBridgehubBase.getZKChain.selector), mocks2); + + vm.store( + address(assetTracker), + getAssetMigrationNumberLocation(assetId, eraZKChainId), + bytes32(migrationNumber - 2) + ); + vm.store( + address(l2AssetTracker), + getAssetMigrationNumberLocation(assetId, eraZKChainId), + bytes32(migrationNumber - 2) + ); + vm.store(address(assetTracker), getChainBalanceLocation(assetId, eraZKChainId), bytes32(amount)); + vm.store(address(assetTracker), getTotalSupplyAcrossAllChainsLocation(assetId), bytes32(amount)); + + vm.mockCall( + address(ecosystemAddresses.bridgehub.chainAssetHandlerProxy), + abi.encodeWithSelector(IChainAssetHandler.migrationNumber.selector), + abi.encode(migrationNumber) + ); + vm.mockCall( + address(L2_CHAIN_ASSET_HANDLER_ADDR), + abi.encodeWithSelector(IChainAssetHandler.migrationNumber.selector), + abi.encode(migrationNumber) + ); + console.log("chainAssetHandler", address(ecosystemAddresses.bridgehub.chainAssetHandlerProxy)); + vm.mockCall( + address(ecosystemAddresses.bridgehub.chainAssetHandlerProxy), + abi.encodeWithSelector(IChainAssetHandler.migrationNumber.selector), + abi.encode(migrationNumber) + ); + IL1AssetTracker(assetTracker).receiveMigrationOnL1(finalizeWithdrawalParamsL1ToGateway); + + vm.prank(SERVICE_TRANSACTION_SENDER); + l2AssetTracker.confirmMigrationOnL2(confirmData); + vm.prank(SERVICE_TRANSACTION_SENDER); + gwAssetTracker.confirmMigrationOnGateway(confirmData); + } + + function test_migrationGatewayToL1() public { + vm.chainId(gwChainId); + { + vm.mockCall( + address(L2_BRIDGEHUB), + abi.encodeWithSelector(L2_BRIDGEHUB.getZKChain.selector), + abi.encode(tokenAddress) + ); + vm.mockCall( + address(L2_BRIDGEHUB), + abi.encodeWithSelector(L2_BRIDGEHUB.settlementLayer.selector), + abi.encode(originalChainId) + ); + vm.mockCall( + L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + abi.encodeWithSelector(L2_TO_L1_MESSENGER_SYSTEM_CONTRACT.sendToL1.selector), + abi.encode(bytes32(0)) + ); + vm.mockCall( + address(ecosystemAddresses.bridgehub.chainAssetHandlerProxy), + abi.encodeWithSelector(IChainAssetHandler.migrationNumber.selector), + abi.encode(migrationNumber) + ); + vm.mockCall( + address(L2_CHAIN_ASSET_HANDLER_ADDR), + abi.encodeWithSelector(IChainAssetHandler.migrationNumber.selector), + abi.encode(migrationNumber) + ); + } + + gwAssetTracker.initiateGatewayToL1MigrationOnGateway(eraZKChainId, assetId); + + TokenBalanceMigrationData memory data = TokenBalanceMigrationData({ + version: TOKEN_BALANCE_MIGRATION_DATA_VERSION, + chainId: eraZKChainId, + assetId: assetId, + tokenOriginChainId: originalChainId, + amount: amount, + chainMigrationNumber: migrationNumber, + assetMigrationNumber: migrationNumber - 1, + originToken: tokenAddress, + isL1ToGateway: false + }); + ConfirmBalanceMigrationData memory confirmData = ConfirmBalanceMigrationData({ + version: TOKEN_BALANCE_MIGRATION_DATA_VERSION, + isL1ToGateway: false, + chainId: eraZKChainId, + assetId: assetId, + migrationNumber: migrationNumber, + amount: amount + }); + bytes memory encodedData = abi.encodeCall(IAssetTrackerDataEncoding.receiveMigrationOnL1, data); + + FinalizeL1DepositParams memory finalizeWithdrawalParamsGatewayToL1 = FinalizeL1DepositParams({ + chainId: gwChainId, + l2BatchNumber: 0, + l2MessageIndex: 0, + l2Sender: L2_ASSET_TRACKER_ADDR, + l2TxNumberInBatch: 0, + message: encodedData, + merkleProof: new bytes32[](0) + }); + + vm.chainId(originalChainId); + vm.mockCall( + address(ecosystemAddresses.bridgehub.messageRootProxy), + abi.encodeWithSelector(IMessageVerification.proveL2MessageInclusionShared.selector), + abi.encode(true) + ); + // vm.mockCall( + // address(addresses.bridgehub), + // abi.encodeWithSelector(IBridgehubBase.settlementLayer.selector), + // abi.encode(originalChainId) + // ); + vm.mockCall( + address(addresses.bridgehub), + abi.encodeWithSelector(IBridgehubBase.whitelistedSettlementLayers.selector), + abi.encode(true) + ); + + bytes32 randomHash = keccak256(abi.encode(assetId)); + + vm.mockCall( + address(0x0000000000000000000000000000000000000011), + abi.encodeWithSelector(IMailboxImpl.requestL2ServiceTransaction.selector), + abi.encode(randomHash) + ); + + vm.mockCall( + address(addresses.bridgehub), + abi.encodeWithSelector(IBridgehubBase.getZKChain.selector), + abi.encode(0x0000000000000000000000000000000000000011) + ); + vm.store(address(assetTracker), getChainBalanceLocation(assetId, gwChainId), bytes32(amount)); + vm.store(address(gwAssetTracker), getChainBalanceLocation(assetId, gwChainId), bytes32(amount)); + vm.store(address(gwAssetTracker), getTotalSupplyAcrossAllChainsLocation(assetId), bytes32(amount)); + + vm.store( + address(assetTracker), + getAssetMigrationNumberLocation(assetId, eraZKChainId), + bytes32(migrationNumber - 1) + ); + vm.store( + address(gwAssetTracker), + getAssetMigrationNumberLocation(assetId, eraZKChainId), + bytes32(migrationNumber - 1) + ); + vm.mockCall( + address(ecosystemAddresses.bridgehub.chainAssetHandlerProxy), + abi.encodeWithSelector(IChainAssetHandler.migrationNumber.selector), + abi.encode(migrationNumber) + ); + console.log("chainAssetHandler", address(ecosystemAddresses.bridgehub.chainAssetHandlerProxy)); + + assetTracker.receiveMigrationOnL1(finalizeWithdrawalParamsGatewayToL1); + + // vm.prank(AddressAliasHelper.applyL1ToL2Alias(l1AssetTracker)); + vm.store(address(assetTracker), chainBalanceLocation, bytes32(amount)); + vm.store(address(l2AssetTracker), chainBalanceLocation, bytes32(amount)); + vm.store(address(l2AssetTracker), getChainBalanceLocation(assetId, eraZKChainId), bytes32(amount)); + vm.store(address(gwAssetTracker), chainBalanceLocation, bytes32(amount)); + vm.store(address(gwAssetTracker), getChainBalanceLocation(assetId, eraZKChainId), bytes32(amount)); + + vm.prank(SERVICE_TRANSACTION_SENDER); + gwAssetTracker.confirmMigrationOnGateway(confirmData); + } + + // add this to be excluded from coverage report + function test() internal override {} +} diff --git a/l1-contracts/test/foundry/l1/integration/BridgeHubInvariantTests.t.sol b/l1-contracts/test/foundry/l1/integration/BridgeHubInvariantTests.t.sol index 3aa4a0ca96..f162cc4f30 100644 --- a/l1-contracts/test/foundry/l1/integration/BridgeHubInvariantTests.t.sol +++ b/l1-contracts/test/foundry/l1/integration/BridgeHubInvariantTests.t.sol @@ -16,6 +16,7 @@ import {ZKChainDeployer} from "./_SharedZKChainDeployer.t.sol"; import {L2TxMocker} from "./_SharedL2TxMocker.t.sol"; import {DEFAULT_L2_LOGS_TREE_ROOT_HASH, EMPTY_STRING_KECCAK, ETH_TOKEN_ADDRESS, REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol"; import {L2CanonicalTransaction, L2Message} from "contracts/common/Messaging.sol"; + import {L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {IL1ERC20Bridge} from "contracts/bridge/interfaces/IL1ERC20Bridge.sol"; diff --git a/l1-contracts/test/foundry/l1/integration/BridgehubTests.t.sol b/l1-contracts/test/foundry/l1/integration/BridgehubTests.t.sol index 1e103b37bd..2c1547cd42 100644 --- a/l1-contracts/test/foundry/l1/integration/BridgehubTests.t.sol +++ b/l1-contracts/test/foundry/l1/integration/BridgehubTests.t.sol @@ -19,6 +19,7 @@ import {ZKChainDeployer} from "./_SharedZKChainDeployer.t.sol"; import {L2TxMocker} from "./_SharedL2TxMocker.t.sol"; import {DEFAULT_L2_LOGS_TREE_ROOT_HASH, EMPTY_STRING_KECCAK, ETH_TOKEN_ADDRESS, REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol"; import {L2CanonicalTransaction, L2Message} from "contracts/common/Messaging.sol"; + import {L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {IL1ERC20Bridge} from "contracts/bridge/interfaces/IL1ERC20Bridge.sol"; diff --git a/l1-contracts/test/foundry/l1/integration/ChainRegistrationSender.t.sol b/l1-contracts/test/foundry/l1/integration/ChainRegistrationSender.t.sol new file mode 100644 index 0000000000..cea84aa192 --- /dev/null +++ b/l1-contracts/test/foundry/l1/integration/ChainRegistrationSender.t.sol @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {StdStorage, Test, stdStorage} from "forge-std/Test.sol"; +import {Vm} from "forge-std/Vm.sol"; + +import {Ownable} from "@openzeppelin/contracts-v4/access/Ownable.sol"; + +import {L2TransactionRequestTwoBridgesOuter} from "contracts/bridgehub/IBridgehubBase.sol"; +import {CHAIN_REGISTRATION_SENDER_ENCODING_VERSION, ChainRegistrationSender} from "contracts/bridgehub/ChainRegistrationSender.sol"; +import {TestnetERC20Token} from "contracts/dev-contracts/TestnetERC20Token.sol"; +import {MailboxFacet} from "contracts/state-transition/chain-deps/facets/Mailbox.sol"; + +import {L1ContractDeployer} from "./_SharedL1ContractDeployer.t.sol"; +import {TokenDeployer} from "./_SharedTokenDeployer.t.sol"; +import {ZKChainDeployer} from "./_SharedZKChainDeployer.t.sol"; +import {L2TxMocker} from "./_SharedL2TxMocker.t.sol"; +import {ETH_TOKEN_ADDRESS, REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol"; + +import {AddressesAlreadyGenerated} from "test/foundry/L1TestsErrors.sol"; + +import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; +import {ConfigSemaphore} from "./utils/_ConfigSemaphore.sol"; + +contract ChainRegistrationSenderTests is + L1ContractDeployer, + ZKChainDeployer, + TokenDeployer, + L2TxMocker, + ConfigSemaphore +{ + using stdStorage for StdStorage; + uint256 constant TEST_USERS_COUNT = 10; + address[] public users; + address[] public l2ContractAddresses; + + // generate MAX_USERS addresses and append it to users array + function _generateUserAddresses() internal { + if (users.length != 0) { + revert AddressesAlreadyGenerated(); + } + + for (uint256 i = 0; i < TEST_USERS_COUNT; i++) { + address newAddress = makeAddr(string(abi.encode("account", i))); + users.push(newAddress); + } + } + + function prepare() public { + takeConfigLock(); // Prevents race condition with configs + _generateUserAddresses(); + + _deployL1Contracts(); + _deployTokens(); + _registerNewTokens(tokens); + + _deployEra(); + _deployZKChain(ETH_TOKEN_ADDRESS); + _deployZKChain(ETH_TOKEN_ADDRESS); + + releaseConfigLock(); + + for (uint256 i = 0; i < zkChainIds.length; i++) { + address contractAddress = makeAddr(string(abi.encode("contract", i))); + l2ContractAddresses.push(contractAddress); + + _addL2ChainContract(zkChainIds[i], contractAddress); + } + } + + function setUp() public { + prepare(); + + vm.mockCall( + address(ecosystemAddresses.bridgehub.messageRootProxy), + abi.encodeWithSelector(IMessageRoot.v30UpgradeChainBatchNumber.selector), + abi.encode(10) + ); + } + + function test_chainRegistrationSender() public { + address owner = Ownable(address(addresses.bridgehub)).owner(); + stdstore + .target(address(addresses.chainRegistrationSender)) + .sig(addresses.chainRegistrationSender.chainRegisteredOnChain.selector) + .with_key(zkChainIds[0]) + .with_key(zkChainIds[1]) + .checked_write(false); + + vm.startBroadcast(owner); + addresses.chainRegistrationSender.registerChain(zkChainIds[0], zkChainIds[1]); + vm.stopBroadcast(); + } + + // deposits ERC20 token to the ZK chain where base token is ETH + // this function use requestL2TransactionTwoBridges function from shared bridge. + // tokenAddress should be any ERC20 token, excluding ETH + function chainRegistrationSenderDeposit(uint256 l2Value, address tokenAddress) private { + TestnetERC20Token currentToken = TestnetERC20Token(tokenAddress); + uint256 currentChainId = zkChainIds[0]; + address currentUser = users[0]; + + uint256 gasPrice = 10000000; + vm.txGasPrice(gasPrice); + + uint256 l2GasLimit = 1000000; + MailboxFacet chainMailBox = MailboxFacet(getZKChainAddress(currentChainId)); + + uint256 minRequiredGas = chainMailBox.l2TransactionBaseCost( + gasPrice, + l2GasLimit, + REQUIRED_L2_GAS_PRICE_PER_PUBDATA + ); + + uint256 mintValue = minRequiredGas; + vm.deal(currentUser, mintValue); + + // currentToken.mint(currentUser, l2Value); + // currentToken.approve(address(addresses.sharedBridge), l2Value); + + bytes memory secondBridgeCallData = bytes.concat( + CHAIN_REGISTRATION_SENDER_ENCODING_VERSION, + abi.encode(currentChainId) + ); + L2TransactionRequestTwoBridgesOuter memory requestTx = _createL2TransactionRequestTwoBridges({ + _chainId: currentChainId, + _mintValue: mintValue, + _secondBridgeValue: 0, + _secondBridgeAddress: address(addresses.chainRegistrationSender), + _l2Value: 0, + _l2GasLimit: l2GasLimit, + _l2GasPerPubdataByteLimit: REQUIRED_L2_GAS_PRICE_PER_PUBDATA, + _secondBridgeCalldata: secondBridgeCallData + }); + + vm.recordLogs(); + bytes32 resultantHash = addresses.bridgehub.requestL2TransactionTwoBridges{value: mintValue}(requestTx); + Vm.Log[] memory logs = vm.getRecordedLogs(); + // NewPriorityRequest memory request = _getNewPriorityQueueFromLogs(logs); + + // assertNotEq(resultantHash, bytes32(0)); + // assertNotEq(request.txHash, bytes32(0)); + // _handleRequestByMockL2Contract(request, RequestType.TWO_BRIDGES); + + // depositsUsers[currentUser][ETH_TOKEN_ADDRESS] += mintValue; + // depositsBridge[currentChainAddress][ETH_TOKEN_ADDRESS] += mintValue; + // tokenSumDeposit[ETH_TOKEN_ADDRESS] += mintValue; + + // depositsUsers[currentUser][currentTokenAddress] += l2Value; + // depositsBridge[currentChainAddress][currentTokenAddress] += l2Value; + // tokenSumDeposit[currentTokenAddress] += l2Value; + // l2ValuesSum[currentTokenAddress] += l2Value; + } + + function test_chainRegistrationSenderDeposit() public { + stdstore + .target(address(addresses.chainRegistrationSender)) + .sig(addresses.chainRegistrationSender.chainRegisteredOnChain.selector) + .with_key(zkChainIds[0]) + .with_key(zkChainIds[1]) + .checked_write(false); + chainRegistrationSenderDeposit(1000000, ETH_TOKEN_ADDRESS); + } + + // add this to be excluded from coverage report + function test() internal override {} +} diff --git a/l1-contracts/test/foundry/l1/integration/DeploymentTest.t.sol b/l1-contracts/test/foundry/l1/integration/DeploymentTest.t.sol index bacf1b4d37..cd43c109d5 100644 --- a/l1-contracts/test/foundry/l1/integration/DeploymentTest.t.sol +++ b/l1-contracts/test/foundry/l1/integration/DeploymentTest.t.sol @@ -17,11 +17,10 @@ import {L2TxMocker} from "./_SharedL2TxMocker.t.sol"; import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol"; -import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; + import {AddressesAlreadyGenerated} from "test/foundry/L1TestsErrors.sol"; import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; -import {IncorrectBridgeHubAddress} from "contracts/common/L1ContractErrors.sol"; -import {L1MessageRoot} from "contracts/bridgehub/L1MessageRoot.sol"; + import {ConfigSemaphore} from "./utils/_ConfigSemaphore.sol"; contract DeploymentTests is L1ContractDeployer, ZKChainDeployer, TokenDeployer, L2TxMocker, ConfigSemaphore { @@ -50,12 +49,12 @@ contract DeploymentTests is L1ContractDeployer, ZKChainDeployer, TokenDeployer, _registerNewTokens(tokens); _deployEra(); - // _deployZKChain(ETH_TOKEN_ADDRESS); - // _deployZKChain(ETH_TOKEN_ADDRESS); - // _deployZKChain(tokens[0]); - // _deployZKChain(tokens[0]); - // _deployZKChain(tokens[1]); - // _deployZKChain(tokens[1]); + _deployZKChain(ETH_TOKEN_ADDRESS); + _deployZKChain(ETH_TOKEN_ADDRESS); + _deployZKChain(tokens[0]); + _deployZKChain(tokens[0]); + _deployZKChain(tokens[1]); + _deployZKChain(tokens[1]); releaseConfigLock(); @@ -82,40 +81,17 @@ contract DeploymentTests is L1ContractDeployer, ZKChainDeployer, TokenDeployer, assertNotEq(newChainAddress, address(0)); address[] memory chainAddresses = addresses.bridgehub.getAllZKChains(); - assertEq(chainAddresses.length, 1); + assertEq(chainAddresses.length, 7); assertEq(chainAddresses[0], newChainAddress); uint256[] memory chainIds = addresses.bridgehub.getAllZKChainChainIDs(); - assertEq(chainIds.length, 1); + assertEq(chainIds.length, 7); assertEq(chainIds[0], chainId); uint256 protocolVersion = addresses.chainTypeManager.getProtocolVersion(chainId); assertEq(protocolVersion, 120259084288); } - function test_bridgehubSetter() public { - uint256 chainId = zkChainIds[0]; - uint256 randomChainId = 123456; - - vm.mockCall( - address(addresses.chainTypeManager), - abi.encodeWithSelector(IChainTypeManager.getZKChainLegacy.selector, randomChainId), - abi.encode(address(0x01)) - ); - vm.store(address(addresses.bridgehub), keccak256(abi.encode(randomChainId, 205)), bytes32(uint256(uint160(1)))); - vm.store( - address(addresses.bridgehub), - keccak256(abi.encode(randomChainId, 204)), - bytes32(uint256(uint160(address(addresses.chainTypeManager)))) - ); - addresses.bridgehub.registerLegacyChain(randomChainId); - - assertEq(addresses.bridgehub.settlementLayer(randomChainId), block.chainid); - - address messageRoot = address(addresses.bridgehub.messageRoot()); - assertTrue(L1MessageRoot(messageRoot).chainIndex(randomChainId) != 0); - } - function test_registerAlreadyDeployedZKChain() public { address owner = Ownable(address(addresses.bridgehub)).owner(); @@ -129,7 +105,8 @@ contract DeploymentTests is L1ContractDeployer, ZKChainDeployer, TokenDeployer, owner, addresses.chainTypeManager.protocolVersion(), addresses.chainTypeManager.storedBatchZero(), - address(addresses.bridgehub) + address(addresses.bridgehub), + address(addresses.interopCenter) ); address stmAddr = IZKChain(chain).getChainTypeManager(); @@ -160,16 +137,14 @@ contract DeploymentTests is L1ContractDeployer, ZKChainDeployer, TokenDeployer, owner, addresses.chainTypeManager.protocolVersion(), addresses.chainTypeManager.storedBatchZero(), - address(addresses.bridgehub.assetRouter()) + address(addresses.bridgehub), + address(addresses.interopCenter) ); address stmAddr = IZKChain(chain).getChainTypeManager(); vm.startBroadcast(owner); addresses.bridgehub.addTokenAssetId(baseTokenAssetId); - vm.expectRevert( - abi.encodeWithSelector(IncorrectBridgeHubAddress.selector, address(addresses.bridgehub.assetRouter())) - ); addresses.bridgehub.registerAlreadyDeployedZKChain(chainId, chain); vm.stopBroadcast(); } diff --git a/l1-contracts/test/foundry/l1/integration/L1GatewayTests.t.sol b/l1-contracts/test/foundry/l1/integration/L1GatewayTests.t.sol index 92f30a0a92..89a028c1ff 100644 --- a/l1-contracts/test/foundry/l1/integration/L1GatewayTests.t.sol +++ b/l1-contracts/test/foundry/l1/integration/L1GatewayTests.t.sol @@ -10,25 +10,28 @@ import {Ownable} from "@openzeppelin/contracts-v4/access/Ownable.sol"; import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; import {L2Bridgehub} from "contracts/bridgehub/L2Bridgehub.sol"; import {IBridgehubBase, BridgehubBurnCTMAssetData, BridgehubMintCTMAssetData, L2TransactionRequestDirect} from "contracts/bridgehub/IBridgehubBase.sol"; - import {L1ContractDeployer} from "./_SharedL1ContractDeployer.t.sol"; import {TokenDeployer} from "./_SharedTokenDeployer.t.sol"; import {ZKChainDeployer} from "./_SharedZKChainDeployer.t.sol"; import {GatewayDeployer} from "./_SharedGatewayDeployer.t.sol"; import {L2TxMocker} from "./_SharedL2TxMocker.t.sol"; import {ETH_TOKEN_ADDRESS, SETTLEMENT_LAYER_RELAY_SENDER} from "contracts/common/Config.sol"; -import {L2CanonicalTransaction, L2Message, TxStatus} from "contracts/common/Messaging.sol"; +import {L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {L2CanonicalTransaction, L2Message, TxStatus, ConfirmTransferResultData} from "contracts/common/Messaging.sol"; +import {IL1Nullifier} from "contracts/bridge/interfaces/IL1Nullifier.sol"; import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; import {IAssetRouterBase} from "contracts/bridge/asset-router/IAssetRouterBase.sol"; import {AssetRouterBase} from "contracts/bridge/asset-router/AssetRouterBase.sol"; -import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol"; +import {IGetters, IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol"; import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; import {AddressesAlreadyGenerated} from "test/foundry/L1TestsErrors.sol"; import {NotInGatewayMode} from "contracts/bridgehub/L1BridgehubErrors.sol"; +import {InvalidProof, DepositDoesNotExist} from "contracts/common/L1ContractErrors.sol"; +import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol"; import {ChainAdmin} from "contracts/governance/ChainAdmin.sol"; import {IAdmin} from "contracts/state-transition/chain-interfaces/IAdmin.sol"; import {ConfigSemaphore} from "./utils/_ConfigSemaphore.sol"; @@ -39,6 +42,12 @@ import {DefaultUpgrade} from "contracts/upgrades/DefaultUpgrade.sol"; import {ProposedUpgrade} from "contracts/upgrades/BaseZkSyncUpgrade.sol"; import {VerifierParams} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; import {SemVer} from "contracts/common/libraries/SemVer.sol"; +import {ProofData} from "contracts/common/libraries/MessageHashing.sol"; +import {IChainAssetHandler} from "contracts/bridgehub/IChainAssetHandler.sol"; +import {IL1ChainAssetHandler} from "contracts/bridgehub/IL1ChainAssetHandler.sol"; +import {IMessageRoot, IMessageVerification} from "contracts/bridgehub/IMessageRoot.sol"; +import {OnlyFailureStatusAllowed} from "contracts/bridge/L1BridgeContractErrors.sol"; +import {NotMigrated} from "contracts/state-transition/L1StateTransitionErrors.sol"; contract L1GatewayTests is L1ContractDeployer, @@ -52,14 +61,17 @@ contract L1GatewayTests is address[] public users; address[] public l2ContractAddresses; - uint256 migratingChainId = 10; + uint256 migratingChainId = 271; IZKChain migratingChain; - uint256 gatewayChainId = 11; + uint256 gatewayChainId = 506; IZKChain gatewayChain; uint256 mintChainId = 12; + // The `pausedDepositsTimestamp` sits at slot 62 of ZKChainStorage + bytes32 pausedDepositsTimestampSlot = bytes32(uint256(62)); + // generate MAX_USERS addresses and append it to users array function _generateUserAddresses() internal { if (users.length != 0) { @@ -81,12 +93,12 @@ contract L1GatewayTests is _registerNewTokens(tokens); _deployEra(); - _deployZKChain(ETH_TOKEN_ADDRESS); - acceptPendingAdmin(); - _deployZKChain(ETH_TOKEN_ADDRESS); - acceptPendingAdmin(); - // _deployZKChain(tokens[0]); - // _deployZKChain(tokens[0]); + _deployZKChainWithPausedDeposits(ETH_TOKEN_ADDRESS, migratingChainId); + acceptPendingAdmin(migratingChainId); + _deployZKChain(ETH_TOKEN_ADDRESS, gatewayChainId); + acceptPendingAdmin(gatewayChainId); + vm.warp(block.timestamp + 1); + // _deployZKChain(tokens[1]); // _deployZKChain(tokens[1]); @@ -108,6 +120,23 @@ contract L1GatewayTests is vm.deal(migratingChain.getAdmin(), 100000000000000000000000000000000000); vm.deal(gatewayChain.getAdmin(), 100000000000000000000000000000000000); + vm.mockCall( + address(ecosystemAddresses.bridgehub.messageRootProxy), + abi.encodeWithSelector(IMessageRoot.getProofData.selector), + abi.encode( + ProofData({ + settlementLayerChainId: 0, + settlementLayerBatchNumber: 0, + settlementLayerBatchRootMask: 0, + batchLeafProofLen: 0, + batchSettlementRoot: 0, + chainIdLeaf: 0, + ptr: 0, + finalProofNode: false + }) + ) + ); + // vm.deal(msg.sender, 100000000000000000000000000000000000); // vm.deal(bridgehub, 100000000000000000000000000000000000); } @@ -146,12 +175,13 @@ contract L1GatewayTests is gatewayScript.fullGatewayRegistration(); } - function test_startMessageToL2() public { + function test_requestL2TransactionDirect() public { _setUpGatewayWithFilterer(); gatewayScript.migrateChainToGateway(migratingChainId); - IL1Bridgehub bridgehub = IL1Bridgehub(addresses.bridgehub); - uint256 expectedValue = 1000000000000000000000; + _confirmMigration(TxStatus.Success); + IBridgehubBase bridgehub = IBridgehubBase(addresses.bridgehub); + uint256 expectedValue = 1000000000000000000000; L2TransactionRequestDirect memory request = _createL2TransactionRequestDirect( migratingChainId, expectedValue, @@ -167,75 +197,7 @@ contract L1GatewayTests is _setUpGatewayWithFilterer(); gatewayScript.migrateChainToGateway(migratingChainId); - // Setup - IL1Bridgehub bridgehub = IL1Bridgehub(addresses.bridgehub); - bytes32 assetId = addresses.bridgehub.ctmAssetIdFromChainId(migratingChainId); - bytes memory transferData; - - { - IZKChain chain = IZKChain(addresses.bridgehub.getZKChain(migratingChainId)); - bytes memory chainData = abi.encode(chain.getProtocolVersion()); - bytes memory ctmData = abi.encode( - address(1), - msg.sender, - addresses.chainTypeManager.protocolVersion(), - ecosystemConfig.contracts.diamondCutData - ); - BridgehubBurnCTMAssetData memory data = BridgehubBurnCTMAssetData({ - chainId: migratingChainId, - ctmData: ctmData, - chainData: chainData - }); - transferData = abi.encode(data); - } - - address chainAdmin = IZKChain(addresses.bridgehub.getZKChain(migratingChainId)).getAdmin(); - IL1AssetRouter assetRouter = IL1AssetRouter(address(addresses.bridgehub.assetRouter())); - bytes32 l2TxHash = keccak256("l2TxHash"); - uint256 l2BatchNumber = 5; - uint256 l2MessageIndex = 0; - uint16 l2TxNumberInBatch = 0; - bytes32[] memory merkleProof = new bytes32[](1); - bytes32 txDataHash = keccak256(bytes.concat(bytes1(0x01), abi.encode(chainAdmin, assetId, transferData))); - - // Mock Call for Msg Inclusion - vm.mockCall( - address(addresses.bridgehub), - abi.encodeWithSelector( - IBridgehubBase.proveL1ToL2TransactionStatus.selector, - migratingChainId, - l2TxHash, - l2BatchNumber, - l2MessageIndex, - l2TxNumberInBatch, - merkleProof, - TxStatus.Failure - ), - abi.encode(true) - ); - - // Set Deposit Happened - vm.startBroadcast(address(addresses.bridgehub)); - assetRouter.bridgehubConfirmL2Transaction({ - _chainId: migratingChainId, - _txDataHash: txDataHash, - _txHash: l2TxHash - }); - vm.stopBroadcast(); - - vm.startBroadcast(); - addresses.l1Nullifier.bridgeRecoverFailedTransfer({ - _chainId: migratingChainId, - _depositSender: chainAdmin, - _assetId: assetId, - _assetData: transferData, - _l2TxHash: l2TxHash, - _l2BatchNumber: l2BatchNumber, - _l2MessageIndex: l2MessageIndex, - _l2TxNumberInBatch: l2TxNumberInBatch, - _merkleProof: merkleProof - }); - vm.stopBroadcast(); + _confirmMigration(TxStatus.Failure); } function test_finishMigrateBackChain() public { @@ -245,7 +207,7 @@ contract L1GatewayTests is } function migrateBackChain() public { - IL1Bridgehub bridgehub = IL1Bridgehub(addresses.bridgehub); + IBridgehubBase bridgehub = IBridgehubBase(addresses.bridgehub); IZKChain migratingChain = IZKChain(addresses.bridgehub.getZKChain(migratingChainId)); bytes32 assetId = addresses.bridgehub.ctmAssetIdFromChainId(migratingChainId); @@ -259,8 +221,8 @@ contract L1GatewayTests is // we are already on L1, so we have to set another chain id, it cannot be GW or mintChainId. vm.chainId(migratingChainId); vm.mockCall( - address(addresses.bridgehub), - abi.encodeWithSelector(IBridgehubBase.proveL2MessageInclusion.selector), + address(ecosystemAddresses.bridgehub.messageRootProxy), + abi.encodeWithSelector(IMessageVerification.proveL2MessageInclusionShared.selector), abi.encode(true) ); vm.mockCall( @@ -286,8 +248,12 @@ contract L1GatewayTests is BridgehubMintCTMAssetData memory data = BridgehubMintCTMAssetData({ chainId: migratingChainId, baseTokenAssetId: baseTokenAssetId, + batchNumber: 0, ctmData: ctmData, - chainData: chainData + chainData: chainData, + migrationNumber: IChainAssetHandler(address(ecosystemAddresses.bridgehub.chainAssetHandlerProxy)) + .migrationNumber(migratingChainId), + v30UpgradeChainBatchNumber: 0 }); bytes memory bridgehubMintData = abi.encode(data); bytes memory message = abi.encodePacked( @@ -325,6 +291,7 @@ contract L1GatewayTests is DefaultUpgrade upgradeImpl = new DefaultUpgrade(); uint256 currentProtocolVersion = migratingChain.getProtocolVersion(); (uint32 major, uint32 minor, uint32 patch) = SemVer.unpackSemVer(uint96(currentProtocolVersion)); + uint256 newProtocolVersion = SemVer.packSemVer(major, minor + 1, patch); ProposedUpgrade memory upgrade = ProposedUpgrade({ l2ProtocolUpgradeTx: Utils.makeEmptyL2CanonicalTransaction(), @@ -340,7 +307,7 @@ contract L1GatewayTests is l1ContractsUpgradeCalldata: hex"", postUpgradeCalldata: hex"", upgradeTimestamp: 0, - newProtocolVersion: SemVer.packSemVer(major, minor + 1, patch) + newProtocolVersion: newProtocolVersion }); Diamond.DiamondCutData memory diamondCut = Diamond.DiamondCutData({ facetCuts: new Diamond.FacetCut[](0), @@ -354,12 +321,249 @@ contract L1GatewayTests is abi.encodeCall(IChainTypeManager.upgradeCutHash, (currentProtocolVersion)), abi.encode(keccak256(abi.encode(diamondCut))) ); + vm.mockCall( + address(gatewayChain), + abi.encodeCall(IGetters.getProtocolVersion, ()), + abi.encode(newProtocolVersion) + ); vm.startBroadcast(migratingChain.getAdmin()); migratingChain.upgradeChainFromVersion(currentProtocolVersion, diamondCut); vm.stopBroadcast(); } + function test_proveL2LogsInclusionFromData() public { + _setUpGatewayWithFilterer(); + gatewayScript.migrateChainToGateway(migratingChainId); + IBridgehubBase bridgehub = IBridgehubBase(addresses.bridgehub); + + bytes + memory data = hex"74beea820000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010f000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002e49c884fd1000000000000000000000000000000000000000000000000000000000000010f93d0008af83c021d815bd4e76d7297c69d7f4cc4cf0b8892f7f74f6e33e11829000000000000000000000000c71d126d294a5d2e4002a62d0017b7109f18ade9000000000000000000000000c71d126d294a5d2e4002a62d0017b7109f18ade900000000000000000000000058dc094d71c4c3740bc1ef43d46b58717fa3595a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c101000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000457425443000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045742544300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0101030000000000000000000000000000000000000000000000000000000000e4ed1ec13a28c40715db6399f6f99ce04e5f19d60ad3ff6831f098cb6cf7594400000000000000000000000000000000000000000000000000000000000000079ba301ae10c10e68bffcc2b466aac46d7c7cd6f87eb055e4d43897f303c7a03a21b22cb4099a976636357d5d1f46deeb36f60ec6557eef0da85abaa8222c8c018dba9883941a824d6545029e626b54bd10404b2b8fff432a39ad36d9a36fe3d6000000000000000000000000000000110000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000001fa0103000100000000000000000000000000000000000000000000000000000000f84927dc03d95cc652990ba75874891ccc5a4d79a0e10a2ffdd238a34a39f82823d18b4879c426cf1cb583e1102d9d7f4a5a3a2d01e3f7cc6d042de25409fef1178cf3cbada927540027845a799eab8cf1d788869a9cc11c0f3ebfec198ff347"; + address eraAddress = bridgehub.getZKChain(migratingChainId); + vm.expectRevert(); + address(addresses.l1Nullifier).call(data); + } + + function test_revertWhen_migrationNeverHappened() public { + _setUpGatewayWithFilterer(); + MerkleProofData memory merkleProofData = _getMerkleProofData(); + + IBridgehubBase bridgehub = IBridgehubBase(addresses.bridgehub); + address chainAssetHandler = address(ecosystemAddresses.bridgehub.chainAssetHandlerProxy); + bytes32 assetId = bridgehub.ctmAssetIdFromChainId(migratingChainId); + address zkChain = addresses.bridgehub.getZKChain(migratingChainId); + address chainAdmin = IZKChain(zkChain).getAdmin(); + + bytes memory transferData = _getTransferData(); + ConfirmTransferResultData memory transferResultData = _getConfirmTransferResultData( + gatewayChainId, + merkleProofData, + chainAdmin, + assetId, + transferData, + TxStatus.Success + ); + + // Reverts if message is not found + vm.expectRevert(abi.encodeWithSelector(InvalidProof.selector)); + addresses.l1Nullifier.bridgeConfirmTransferResult(transferResultData); + + _mockMessageInclusion(gatewayChainId, merkleProofData, TxStatus.Success); + + // Reverts if deposit was faked + bytes32 txDataHash = keccak256(bytes.concat(bytes1(0x01), abi.encode(chainAdmin, assetId, transferData))); + vm.expectRevert(abi.encodeWithSelector(DepositDoesNotExist.selector, bytes32(0), txDataHash)); + addresses.l1Nullifier.bridgeConfirmTransferResult(transferResultData); + } + + function test_revertWhen_bridgeConfirmTransferResult_validTransfer() public { + bytes32 ETH_TOKEN_ASSET_ID = keccak256( + abi.encode(block.chainid, L2_NATIVE_TOKEN_VAULT_ADDR, ETH_TOKEN_ADDRESS) + ); + MerkleProofData memory merkleProofData = _getMerkleProofData(); + + address alice = makeAddr("alice"); + uint256 amount = 1 ether; + bytes memory transferData = abi.encode(amount, alice, ETH_TOKEN_ADDRESS); + //bytes32 txDataHash = keccak256(abi.encode(alice, ETH_TOKEN_ADDRESS, amount)); + bytes32 txDataHash = keccak256(bytes.concat(bytes1(0x01), abi.encode(alice, ETH_TOKEN_ASSET_ID, transferData))); + _setDepositHappened(migratingChainId, merkleProofData.l2TxHash, txDataHash); + require( + addresses.l1Nullifier.depositHappened(migratingChainId, merkleProofData.l2TxHash) == txDataHash, + "Deposit not set" + ); + + _mockMessageInclusion(migratingChainId, merkleProofData, TxStatus.Success); + + ConfirmTransferResultData memory transferResultData = _getConfirmTransferResultData( + migratingChainId, + merkleProofData, + alice, + ETH_TOKEN_ASSET_ID, + transferData, + TxStatus.Success + ); + + vm.expectRevert(abi.encodeWithSelector(OnlyFailureStatusAllowed.selector)); + addresses.l1Nullifier.bridgeConfirmTransferResult(transferResultData); + } + + function _setDepositHappened(uint256 _chainId, bytes32 _txHash, bytes32 _txDataHash) internal { + vm.startBroadcast(address(addresses.bridgehub)); + IL1AssetRouter(address(addresses.bridgehub.assetRouter())).bridgehubConfirmL2Transaction({ + _chainId: _chainId, + _txDataHash: _txDataHash, + _txHash: _txHash + }); + vm.stopBroadcast(); + } + + struct MerkleProofData { + bytes32 l2TxHash; + uint256 l2BatchNumber; + uint256 l2MessageIndex; + uint16 l2TxNumberInBatch; + bytes32[] merkleProof; + } + + function _getMerkleProofData() internal returns (MerkleProofData memory) { + bytes32[] memory merkleProof = new bytes32[](1); + merkleProof[0] = bytes32(uint256(1)); + return + MerkleProofData({ + l2TxHash: keccak256("l2TxHash"), + l2BatchNumber: 5, + l2MessageIndex: 0, + l2TxNumberInBatch: 0, + merkleProof: merkleProof + }); + } + + function _mockMessageInclusion( + uint256 chainId, + MerkleProofData memory merkleProofData, + TxStatus txStatus + ) internal { + vm.mockCall( + address(ecosystemAddresses.bridgehub.messageRootProxy), + abi.encodeWithSelector( + IMessageVerification.proveL1ToL2TransactionStatusShared.selector, + chainId, + merkleProofData.l2TxHash, + merkleProofData.l2BatchNumber, + merkleProofData.l2MessageIndex, + merkleProofData.l2TxNumberInBatch, + merkleProofData.merkleProof, + txStatus + ), + abi.encode(true) + ); + } + + function _getTransferData() internal returns (bytes memory) { + return + abi.encode( + BridgehubBurnCTMAssetData({ + chainId: migratingChainId, + ctmData: abi.encode( + AddressAliasHelper.applyL1ToL2Alias(msg.sender), + ecosystemConfig.contracts.diamondCutData + ), + chainData: abi.encode( + IZKChain(addresses.bridgehub.getZKChain(migratingChainId)).getProtocolVersion() + ) + }) + ); + } + + function _getConfirmTransferResultData( + uint256 chainId, + MerkleProofData memory merkleProofData, + address sender, + bytes32 assetId, + bytes memory assetData, + TxStatus txStatus + ) internal returns (ConfirmTransferResultData memory) { + return + ConfirmTransferResultData({ + _chainId: chainId, + _depositSender: sender, + _assetId: assetId, + _assetData: assetData, + _l2TxHash: merkleProofData.l2TxHash, + _l2BatchNumber: merkleProofData.l2BatchNumber, + _l2MessageIndex: merkleProofData.l2MessageIndex, + _l2TxNumberInBatch: merkleProofData.l2TxNumberInBatch, + _merkleProof: merkleProofData.merkleProof, + _txStatus: txStatus + }); + } + + // Used for both successful and failed migrations. + function _confirmMigration(TxStatus txStatus) internal { + MerkleProofData memory merkleProofData = _getMerkleProofData(); + _mockMessageInclusion(gatewayChainId, merkleProofData, txStatus); + + IBridgehubBase bridgehub = IBridgehubBase(addresses.bridgehub); + address chainAssetHandler = address(ecosystemAddresses.bridgehub.chainAssetHandlerProxy); + bytes32 assetId = bridgehub.ctmAssetIdFromChainId(migratingChainId); + address zkChain = addresses.bridgehub.getZKChain(migratingChainId); + address chainAdmin = IZKChain(zkChain).getAdmin(); + + bytes memory transferData = _getTransferData(); + + // Set Deposit Happened + bytes32 txDataHash = keccak256(bytes.concat(bytes1(0x01), abi.encode(chainAdmin, assetId, transferData))); + _setDepositHappened(gatewayChainId, merkleProofData.l2TxHash, txDataHash); + + ConfirmTransferResultData memory transferResultData = _getConfirmTransferResultData( + gatewayChainId, + merkleProofData, + chainAdmin, + assetId, + transferData, + txStatus + ); + + // Sanity check before + assertNotEq(addresses.l1Nullifier.depositHappened(gatewayChainId, merkleProofData.l2TxHash), 0x00); + assertEq(IChainAssetHandler(chainAssetHandler).migrationNumber(migratingChainId), 1); + + if (txStatus == TxStatus.Success) { + vm.expectEmit(); + emit IAdmin.DepositsUnpaused(migratingChainId); + } else { + vm.expectEmit(); + emit IL1AssetRouter.ClaimedFailedDepositAssetRouter(gatewayChainId, assetId, transferData); + } + addresses.l1Nullifier.bridgeConfirmTransferResult(transferResultData); + + { + // Avoid stack-too-deep + // Check that value in `depositHappened` mapping was cleared + assertEq(addresses.l1Nullifier.depositHappened(gatewayChainId, merkleProofData.l2TxHash), 0x00); + // Read storage to check that the recorded timestamp is reset to 0, ie, deposits were unpaused + uint256 pausedDepositsTimestamp = uint256(vm.load(address(zkChain), pausedDepositsTimestampSlot)); + assertEq(pausedDepositsTimestamp, 0); + // Migration is no longer in progress + bool isMigrationInProgress = IL1ChainAssetHandler(chainAssetHandler).isMigrationInProgress( + migratingChainId + ); + assertEq(isMigrationInProgress, false); + } + + uint256 migrationNumber = IChainAssetHandler(chainAssetHandler).migrationNumber(migratingChainId); + uint256 settlementLayer = bridgehub.settlementLayer(migratingChainId); + if (txStatus == TxStatus.Success) { + assertEq(migrationNumber, 1); + assertEq(settlementLayer, gatewayChainId); + } else { + assertEq(migrationNumber, 0); + assertEq(settlementLayer, block.chainid); + assertEq(IGetters(address(zkChain)).getSettlementLayer(), address(0)); + } + } + // add this to be excluded from coverage report function test() internal override {} } diff --git a/l1-contracts/test/foundry/l1/integration/UpgradeTestv29.t.sol b/l1-contracts/test/foundry/l1/integration/UpgradeTestv29.t.sol index f127ce1a41..612da5f718 100644 --- a/l1-contracts/test/foundry/l1/integration/UpgradeTestv29.t.sol +++ b/l1-contracts/test/foundry/l1/integration/UpgradeTestv29.t.sol @@ -11,10 +11,10 @@ import {Call} from "contracts/governance/Common.sol"; import {Test} from "forge-std/Test.sol"; // For now, this test is testing "stage" - as mainnet wasn't updated yet. -string constant ECOSYSTEM_INPUT = "/upgrade-envs/v0.28.0-precompiles/stage.toml"; -string constant ECOSYSTEM_OUTPUT = "/test/foundry/l1/integration/upgrade-envs/script-out/stage.toml"; -string constant CHAIN_INPUT = "/upgrade-envs/v0.28.0-precompiles/stage-gateway.toml"; -string constant CHAIN_OUTPUT = "/test/foundry/l1/integration/upgrade-envs/script-out/stage-gateway.toml"; +string constant ECOSYSTEM_INPUT = "/upgrade-envs/v0.29.2-interopA-ff/mainnet.toml"; +string constant ECOSYSTEM_OUTPUT = "/test/foundry/l1/integration/upgrade-envs/script-out/mainnet.toml"; +string constant CHAIN_INPUT = "/upgrade-envs/v0.29.2-interopA-ff/mainnet-gateway.toml"; +string constant CHAIN_OUTPUT = "/test/foundry/l1/integration/upgrade-envs/script-out/mainnet-gateway.toml"; contract UpgradeIntegrationTest is Test { EcosystemUpgrade_v29 ecosystemUpgrade; @@ -23,7 +23,7 @@ contract UpgradeIntegrationTest is Test { function setUp() public { ecosystemUpgrade = new EcosystemUpgrade_v29(); ecosystemUpgrade.initialize(ECOSYSTEM_INPUT, ECOSYSTEM_OUTPUT); - + ecosystemUpgrade.deployNewEcosystemContractsL1(); chainUpgrade = new ChainUpgrade(); } diff --git a/l1-contracts/test/foundry/l1/integration/_GatewayPreparationForTests.sol b/l1-contracts/test/foundry/l1/integration/_GatewayPreparationForTests.sol index 0467ce1147..ce65a4997e 100644 --- a/l1-contracts/test/foundry/l1/integration/_GatewayPreparationForTests.sol +++ b/l1-contracts/test/foundry/l1/integration/_GatewayPreparationForTests.sol @@ -1,6 +1,9 @@ import {stdToml} from "forge-std/StdToml.sol"; import {Script, console2 as console} from "forge-std/Script.sol"; +// import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol"; +// import {IBridgehub} from "contracts/bridgehub/IBridgehub.sol"; +// import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; import {GatewayGovernanceUtils} from "deploy-scripts/gateway/GatewayGovernanceUtils.s.sol"; import {L1Bridgehub} from "contracts/bridgehub/L1Bridgehub.sol"; @@ -21,11 +24,33 @@ contract GatewayPreparationForTests is Script, GatewayGovernanceUtils { string memory toml = vm.readFile(path); uint256 gatewayChainId = toml.readUint("$.chain.chain_chain_id"); + gatewayChainId = 506; //toml.readUint("$.chain.chain_chain_id"); + // // currently there is a single gateway test file. + // console.log("Gateway chain id skipped value = %s", toml.readUint("$.chain.chain_chain_id")); // Grab config from output of l1 deployment - path = string.concat(root, vm.envString("L1_OUTPUT")); + path = string.concat(root, vm.envString("CTM_OUTPUT")); toml = vm.readFile(path); + // config.gatewayChainId = 506; //toml.readUint("$.chain.chain_chain_id"); + // currently there is a single gateway test file. + // console.log("Gateway chain id skipped value = %s", toml.readUint("$.chain.chain_chain_id")); + + // path = string.concat(root, vm.envString("GATEWAY_AS_CHAIN_OUTPUT")); + // toml = vm.readFile(path); + + // config.gatewayChainAdmin = IZKChain(IBridgehubBase(config.bridgehub).getZKChain(config.gatewayChainId)).getAdmin(); + // // toml.readAddress("$.chain_admin_addr"); + // config.gatewayChainProxyAdmin = toml.readAddress("$.chain_proxy_admin_addr"); + // config.gatewayAccessControlRestriction = toml.readAddress( + // "$.deployed_addresses.access_control_restriction_addr" + // ); + // config.l1NullifierProxy = address(IL1AssetRouter(IBridgehubBase(config.bridgehub).assetRouter()).L1_NULLIFIER()); + + // console.log("chain chain id = ", config.gatewayChainId); + + // // This value is never checked in the integration tests + // config.gatewayDiamondCutData = hex""; _initializeGatewayGovernanceConfig( GatewayGovernanceConfig({ bridgehubProxy: toml.readAddress("$.deployed_addresses.bridgehub.bridgehub_proxy_addr"), diff --git a/l1-contracts/test/foundry/l1/integration/_SharedGatewayDeployer.t.sol b/l1-contracts/test/foundry/l1/integration/_SharedGatewayDeployer.t.sol index 2ec3fc680e..abf06b415f 100644 --- a/l1-contracts/test/foundry/l1/integration/_SharedGatewayDeployer.t.sol +++ b/l1-contracts/test/foundry/l1/integration/_SharedGatewayDeployer.t.sol @@ -10,6 +10,8 @@ contract GatewayDeployer is L1ContractDeployer { GatewayPreparationForTests gatewayScript; function _initializeGatewayScript() internal { + vm.setEnv("CTM_CONFIG", "/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-ctm.toml"); + vm.setEnv("CTM_OUTPUT", "/test/foundry/l1/integration/deploy-scripts/script-out/output-deploy-ctm.toml"); vm.setEnv("L1_CONFIG", "/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-l1.toml"); vm.setEnv("L1_OUTPUT", "/test/foundry/l1/integration/deploy-scripts/script-out/output-deploy-l1.toml"); vm.setEnv( diff --git a/l1-contracts/test/foundry/l1/integration/_SharedL1ContractDeployer.t.sol b/l1-contracts/test/foundry/l1/integration/_SharedL1ContractDeployer.t.sol index 4df736f1ae..5ac7c12282 100644 --- a/l1-contracts/test/foundry/l1/integration/_SharedL1ContractDeployer.t.sol +++ b/l1-contracts/test/foundry/l1/integration/_SharedL1ContractDeployer.t.sol @@ -2,45 +2,54 @@ pragma solidity 0.8.28; import {StdStorage, Test, stdStorage} from "forge-std/Test.sol"; - import {DeployL1CoreContractsIntegrationScript} from "./deploy-scripts/DeployL1CoreContractsIntegration.s.sol"; import {L1Bridgehub} from "contracts/bridgehub/L1Bridgehub.sol"; import {DeployCTMIntegrationScript} from "./deploy-scripts/DeployCTMIntegration.s.sol"; import {RegisterCTM} from "deploy-scripts/RegisterCTM.s.sol"; +import {ChainRegistrationSender} from "contracts/bridgehub/ChainRegistrationSender.sol"; +import {IInteropCenter} from "contracts/interop/IInteropCenter.sol"; import {L1AssetRouter} from "contracts/bridge/asset-router/L1AssetRouter.sol"; +import {L1AssetTracker} from "contracts/bridge/asset-tracker/L1AssetTracker.sol"; import {L1Nullifier} from "contracts/bridge/L1Nullifier.sol"; import {L1NativeTokenVault} from "contracts/bridge/ntv/L1NativeTokenVault.sol"; import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; import {CTMDeploymentTracker} from "contracts/bridgehub/CTMDeploymentTracker.sol"; import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; -import {Config, DeployedAddresses} from "deploy-scripts/DeployUtils.s.sol"; +import {DeployedAddresses as CoreDeployedAddresses} from "deploy-scripts/DeployL1CoreUtils.s.sol"; +import {UtilsTest} from "foundry-test/l1/unit/concrete/Utils/Utils.t.sol"; +import {Config, DeployedAddresses as CTMDeployedAddresses} from "deploy-scripts/DeployCTMUtils.s.sol"; -contract L1ContractDeployer is Test { +contract L1ContractDeployer is UtilsTest { using stdStorage for StdStorage; DeployL1CoreContractsIntegrationScript l1CoreContractsScript; DeployCTMIntegrationScript ctmScript; RegisterCTM registerCTMScript; + struct AllAddresses { - DeployedAddresses ecosystemAddresses; address bridgehubProxyAddress; address bridgehubOwnerAddress; L1Bridgehub bridgehub; + IInteropCenter interopCenter; CTMDeploymentTracker ctmDeploymentTracker; L1AssetRouter sharedBridge; + L1AssetTracker l1AssetTracker; L1Nullifier l1Nullifier; L1NativeTokenVault l1NativeTokenVault; IChainTypeManager chainTypeManager; + ChainRegistrationSender chainRegistrationSender; } Config public ecosystemConfig; AllAddresses public addresses; + CoreDeployedAddresses ecosystemAddresses; + CTMDeployedAddresses ctmAddresses; - function deployEcosystem() public returns (DeployedAddresses memory addresses) { + function deployEcosystem() public returns (CoreDeployedAddresses memory ecosystemAddresses) { l1CoreContractsScript = new DeployL1CoreContractsIntegrationScript(); l1CoreContractsScript.runForTest(); - addresses = l1CoreContractsScript.getAddresses(); + ecosystemAddresses = l1CoreContractsScript.getAddresses(); } function registerCTM(address bridgehub, address ctm) public { @@ -51,6 +60,8 @@ contract L1ContractDeployer is Test { function _deployL1Contracts() internal { vm.setEnv("L1_CONFIG", "/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-l1.toml"); vm.setEnv("L1_OUTPUT", "/test/foundry/l1/integration/deploy-scripts/script-out/output-deploy-l1.toml"); + vm.setEnv("CTM_CONFIG", "/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-ctm.toml"); + vm.setEnv("CTM_OUTPUT", "/test/foundry/l1/integration/deploy-scripts/script-out/output-deploy-ctm.toml"); vm.setEnv( "ZK_CHAIN_CONFIG", "/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-zk-chain-era.toml" @@ -63,32 +74,26 @@ contract L1ContractDeployer is Test { "GATEWAY_PREPARATION_L1_CONFIG", "/test/foundry/l1/integration/deploy-scripts/script-config/gateway-preparation-l1.toml" ); - - DeployedAddresses memory coreContractsAddresses = deployEcosystem(); + ecosystemAddresses = deployEcosystem(); ctmScript = new DeployCTMIntegrationScript(); - ctmScript.runForTest(coreContractsAddresses.bridgehub.bridgehubProxy); - addresses.ecosystemAddresses = ctmScript.getAddresses(); - registerCTM( - addresses.ecosystemAddresses.bridgehub.bridgehubProxy, - addresses.ecosystemAddresses.stateTransition.chainTypeManagerProxy - ); + ctmScript.runForTest(ecosystemAddresses.bridgehub.bridgehubProxy, false); + ctmAddresses = ctmScript.getAddresses(); + registerCTM(ecosystemAddresses.bridgehub.bridgehubProxy, ctmAddresses.stateTransition.chainTypeManagerProxy); ecosystemConfig = ctmScript.getConfig(); - addresses.bridgehub = L1Bridgehub(addresses.ecosystemAddresses.bridgehub.bridgehubProxy); - addresses.chainTypeManager = IChainTypeManager( - addresses.ecosystemAddresses.stateTransition.chainTypeManagerProxy - ); - addresses.ctmDeploymentTracker = CTMDeploymentTracker( - addresses.ecosystemAddresses.bridgehub.ctmDeploymentTrackerProxy - ); + // Get bridgehub from the CTM script's discovered addresses + addresses.bridgehub = L1Bridgehub(ecosystemAddresses.bridgehub.bridgehubProxy); + addresses.chainTypeManager = IChainTypeManager(ctmAddresses.stateTransition.chainTypeManagerProxy); + addresses.ctmDeploymentTracker = CTMDeploymentTracker(address(addresses.bridgehub.l1CtmDeployer())); - addresses.sharedBridge = L1AssetRouter(addresses.ecosystemAddresses.bridges.l1AssetRouterProxy); - addresses.l1Nullifier = L1Nullifier(addresses.ecosystemAddresses.bridges.l1NullifierProxy); - addresses.l1NativeTokenVault = L1NativeTokenVault( - payable(addresses.ecosystemAddresses.vaults.l1NativeTokenVaultProxy) - ); + addresses.sharedBridge = L1AssetRouter(ecosystemAddresses.bridges.l1AssetRouterProxy); + addresses.l1Nullifier = L1Nullifier(ecosystemAddresses.bridges.l1NullifierProxy); + addresses.l1NativeTokenVault = L1NativeTokenVault(payable(address(addresses.l1Nullifier.l1NativeTokenVault()))); + addresses.chainRegistrationSender = ChainRegistrationSender( + ecosystemAddresses.bridgehub.chainRegistrationSenderProxy + ); _acceptOwnership(); _setEraBatch(); @@ -149,5 +154,5 @@ contract L1ContractDeployer is Test { } // add this to be excluded from coverage report - function test() internal virtual {} + function test() internal virtual override {} } diff --git a/l1-contracts/test/foundry/l1/integration/_SharedZKChainDeployer.t.sol b/l1-contracts/test/foundry/l1/integration/_SharedZKChainDeployer.t.sol index 55d44678cd..b1694440ab 100644 --- a/l1-contracts/test/foundry/l1/integration/_SharedZKChainDeployer.t.sol +++ b/l1-contracts/test/foundry/l1/integration/_SharedZKChainDeployer.t.sol @@ -12,6 +12,7 @@ import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {DiamondProxy} from "contracts/state-transition/chain-deps/DiamondProxy.sol"; import {IDiamondInit} from "contracts/state-transition/chain-interfaces/IDiamondInit.sol"; +import {IAdmin} from "contracts/state-transition/chain-interfaces/IAdmin.sol"; contract ZKChainDeployer is L1ContractDeployer { using stdStorage for StdStorage; @@ -53,14 +54,33 @@ contract ZKChainDeployer is L1ContractDeployer { deployScript.runForTest(); zkChainIds.push(eraZKChainId); eraConfig = deployScript.getConfig(); + + address chainAddress = getZKChainAddress(eraZKChainId); + IAdmin(chainAddress).unpauseDeposits(); } function _deployZKChain(address _baseToken) internal { + _deployZKChain(_baseToken, 0); + } + + function _deployZKChain(address _baseToken, uint256 _chainId) internal { + uint256 chainId = _deployZKChainInner(_baseToken, _chainId); + + address chainAddress = getZKChainAddress(chainId); + IAdmin(chainAddress).unpauseDeposits(); + } + + function _deployZKChainWithPausedDeposits(address _baseToken, uint256 _chainId) internal { + _deployZKChainInner(_baseToken, _chainId); + } + + function _deployZKChainInner(address _baseToken, uint256 _chainId) internal returns (uint256 chainId) { + chainId = _chainId == 0 ? currentZKChainId : _chainId; vm.setEnv( "ZK_CHAIN_CONFIG", string.concat( "/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-zk-chain-", - Strings.toString(currentZKChainId), + Strings.toString(chainId), ".toml" ) ); @@ -68,13 +88,15 @@ contract ZKChainDeployer is L1ContractDeployer { "ZK_CHAIN_OUT", string.concat( "/test/foundry/l1/integration/deploy-scripts/script-out/output-deploy-zk-chain-", - Strings.toString(currentZKChainId), + Strings.toString(chainId), ".toml" ) ); - zkChainIds.push(currentZKChainId); - saveZKChainConfig(_getDefaultDescription(currentZKChainId, _baseToken, currentZKChainId)); - currentZKChainId++; + zkChainIds.push(chainId); + saveZKChainConfig(_getDefaultDescription(chainId, _baseToken, chainId)); + if (chainId == currentZKChainId) { + currentZKChainId++; + } deployScript.runForTest(); } @@ -151,7 +173,12 @@ contract ZKChainDeployer is L1ContractDeployer { } function acceptPendingAdmin() public { - IZKChain chain = IZKChain(addresses.bridgehub.getZKChain(currentZKChainId - 1)); + acceptPendingAdmin(0); + } + + function acceptPendingAdmin(uint256 _chainId) public { + uint256 chainId = _chainId == 0 ? currentZKChainId - 1 : _chainId; + IZKChain chain = IZKChain(addresses.bridgehub.getZKChain(chainId)); address admin = chain.getPendingAdmin(); vm.startBroadcast(admin); chain.acceptAdmin(); @@ -168,20 +195,28 @@ contract ZKChainDeployer is L1ContractDeployer { address _admin, uint256 _protocolVersion, bytes32 _storedBatchZero, - address _bridgehub + address _bridgehub, + address _interopCenter ) internal returns (address) { Diamond.DiamondCutData memory diamondCut = abi.decode( ecosystemConfig.contracts.diamondCutData, (Diamond.DiamondCutData) ); - bytes memory initData; + bytes memory initData1; + bytes memory initData2; { - initData = bytes.concat( + // stack too deep + initData1 = bytes.concat( IDiamondInit.initialize.selector, bytes32(_chainId), bytes32(uint256(uint160(address(_bridgehub)))), - bytes32(uint256(uint160(address(this)))), + bytes32(uint256(uint160(address(_interopCenter)))), + bytes32(uint256(uint160(address(this)))) + ); + } + { + initData2 = bytes.concat( bytes32(_protocolVersion), bytes32(uint256(uint160(_admin))), bytes32(uint256(uint160(address(0x1337)))), @@ -190,6 +225,11 @@ contract ZKChainDeployer is L1ContractDeployer { diamondCut.initCalldata ); } + bytes memory initData; + { + initData = bytes.concat(initData1, initData2); + } + diamondCut.initCalldata = initData; DiamondProxy hyperchainContract = new DiamondProxy{salt: bytes32(0)}(block.chainid, diamondCut); return address(hyperchainContract); diff --git a/l1-contracts/test/foundry/l1/integration/deploy-scripts/DeployCTMIntegration.s.sol b/l1-contracts/test/foundry/l1/integration/deploy-scripts/DeployCTMIntegration.s.sol index f4a9117ca0..e1a8bc8040 100644 --- a/l1-contracts/test/foundry/l1/integration/deploy-scripts/DeployCTMIntegration.s.sol +++ b/l1-contracts/test/foundry/l1/integration/deploy-scripts/DeployCTMIntegration.s.sol @@ -7,7 +7,7 @@ import {Script} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; import {DeployCTMScript} from "deploy-scripts/DeployCTM.s.sol"; -import {StateTransitionDeployedAddresses} from "deploy-scripts/Utils.sol"; +import {StateTransitionDeployedAddresses} from "deploy-scripts/Types.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; contract DeployCTMIntegrationScript is Script, DeployCTMScript { @@ -63,7 +63,7 @@ contract DeployCTMIntegrationScript is Script, DeployCTMScript { function getUpgradeAddedFacetCuts( StateTransitionDeployedAddresses memory stateTransition - ) internal virtual override returns (Diamond.FacetCut[] memory facetCuts) { + ) internal virtual returns (Diamond.FacetCut[] memory facetCuts) { return getChainCreationFacetCuts(stateTransition); } } diff --git a/l1-contracts/test/foundry/l1/integration/deploy-scripts/DeployIntegrationUtils.s.sol b/l1-contracts/test/foundry/l1/integration/deploy-scripts/DeployIntegrationUtils.s.sol index 530bfc99b5..160b7472c2 100644 --- a/l1-contracts/test/foundry/l1/integration/deploy-scripts/DeployIntegrationUtils.s.sol +++ b/l1-contracts/test/foundry/l1/integration/deploy-scripts/DeployIntegrationUtils.s.sol @@ -6,11 +6,17 @@ pragma solidity ^0.8.24; import {Script} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; -import {DeployUtils} from "deploy-scripts/DeployUtils.s.sol"; -import {StateTransitionDeployedAddresses} from "deploy-scripts/Utils.sol"; +import {DeployCTMUtils} from "deploy-scripts/DeployCTMUtils.s.sol"; +import {StateTransitionDeployedAddresses} from "deploy-scripts/Types.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; -abstract contract DeployIntegrationUtils is Script, DeployUtils { +import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol"; +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; +import {IMailboxImpl} from "contracts/state-transition/chain-interfaces/IMailboxImpl.sol"; +import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; +import {GW_ASSET_TRACKER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; + +abstract contract DeployIntegrationUtils is Script, DeployCTMUtils { using stdToml for string; function test() internal virtual override {} @@ -18,7 +24,9 @@ abstract contract DeployIntegrationUtils is Script, DeployUtils { function getInitializeCalldata( string memory contractName, bool isZKBytecode - ) internal virtual override returns (bytes memory); + ) internal virtual override returns (bytes memory) { + return super.getInitializeCalldata(contractName, isZKBytecode); + } function getChainCreationFacetCuts( StateTransitionDeployedAddresses memory stateTransition @@ -68,7 +76,26 @@ abstract contract DeployIntegrationUtils is Script, DeployUtils { function getUpgradeAddedFacetCuts( StateTransitionDeployedAddresses memory stateTransition - ) internal virtual override returns (Diamond.FacetCut[] memory facetCuts) { + ) internal virtual returns (Diamond.FacetCut[] memory facetCuts) { return getChainCreationFacetCuts(stateTransition); } + + function clearPriorityQueue(address _bridgehub, uint256 _chainId) public { + IZKChain chain = IZKChain(IBridgehubBase(_bridgehub).getZKChain(_chainId)); + uint256 treeSize = chain.getPriorityQueueSize(); + // The priorityTree sits at slot 51 of ZKChainStorage + // unprocessedIndex is the second field (51 + 1 = 52) in PriorityTree.Tree + bytes32 slot = bytes32(uint256(52)); + uint256 value = uint256(vm.load(address(chain), slot)); + // We modify the unprocessedIndex so that the tree size is zero + vm.store(address(chain), slot, bytes32(value + treeSize)); + } + + function pauseDepositsBeforeInitiatingMigration(address _bridgehub, uint256 _chainId) public { + IZKChain chain = IZKChain(IBridgehubBase(_bridgehub).getZKChain(_chainId)); + uint256 l1ChainId = IL1Bridgehub(_bridgehub).L1_CHAIN_ID(); + vm.prank(GW_ASSET_TRACKER_ADDR); + IMailboxImpl(address(chain)).pauseDepositsOnGateway(block.timestamp); + vm.warp(block.timestamp + 1); + } } diff --git a/l1-contracts/test/foundry/l1/integration/deploy-scripts/DeployL1CoreContractsIntegration.s.sol b/l1-contracts/test/foundry/l1/integration/deploy-scripts/DeployL1CoreContractsIntegration.s.sol index e11a5420cc..b64fc3a4b1 100644 --- a/l1-contracts/test/foundry/l1/integration/deploy-scripts/DeployL1CoreContractsIntegration.s.sol +++ b/l1-contracts/test/foundry/l1/integration/deploy-scripts/DeployL1CoreContractsIntegration.s.sol @@ -7,7 +7,6 @@ import {Script} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; import {DeployL1CoreContractsScript} from "deploy-scripts/DeployL1CoreContracts.s.sol"; -import {StateTransitionDeployedAddresses} from "deploy-scripts/Utils.sol"; contract DeployL1CoreContractsIntegrationScript is Script, DeployL1CoreContractsScript { using stdToml for string; diff --git a/l1-contracts/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-ctm.toml b/l1-contracts/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-ctm.toml new file mode 100644 index 0000000000..2fb9bb14b2 --- /dev/null +++ b/l1-contracts/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-ctm.toml @@ -0,0 +1,38 @@ +era_chain_id = 9 +owner_address = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" +testnet_verifier = true +support_l2_legacy_shared_bridge_test = false +is_zk_sync_os = false + +[gateway] +chain_id = 123 + +[contracts] +governance_security_council_address = "0x0000000000000000000000000000000000000000" +governance_min_delay = 0 +max_number_of_chains = 100 +create2_factory_salt = "0x00000000000000000000000000000000000000000000000000000000000000ff" +create2_factory_addr = "0x0000000000000000000000000000000000000000" +validator_timelock_execution_delay = 0 +genesis_root = "0x1000000000000000000000000000000000000000000000000000000000000000" +genesis_rollup_leaf_index = 1 +genesis_batch_commitment = "0x1000000000000000000000000000000000000000000000000000000000000000" +latest_protocol_version = 120259084288 +recursion_node_level_vk_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +recursion_leaf_level_vk_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +recursion_circuits_set_vks_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +priority_tx_max_gas_limit = 80000000 +diamond_init_pubdata_pricing_mode = 0 +diamond_init_batch_overhead_l1_gas = 1000000 +diamond_init_max_pubdata_per_batch = 120000 +diamond_init_max_l2_gas_per_batch = 80000000 +diamond_init_priority_tx_max_pubdata = 99000 +diamond_init_minimal_l2_gas_price = 250000000 +bootloader_hash = "0x0100000000000000000000000000000000000000000000000000000000000000" +default_aa_hash = "0x0100000000000000000000000000000000000000000000000000000000000000" +evm_emulator_hash = "0x0100000000000000000000000000000000000000000000000000000000000000" +force_deployments_data = "0x00" +diamond_cut_data = "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000103aa417efc38582cbb322d23b86342cb3bca4a40000000000000000000000000000000000000000000000000000000000000de00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000009c00000000000000000000000000000000000000000000000000000000000000bc00000000000000000000000005d8d8112ce7c189c3df7e80fce3cd96863acbbb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000014a37dc1d400000000000000000000000000000000000000000000000000000000a3bd011200000000000000000000000000000000000000000000000000000000a9f6d94100000000000000000000000000000000000000000000000000000000be6f11cf00000000000000000000000000000000000000000000000000000000e76db86500000000000000000000000000000000000000000000000000000000fc57565f000000000000000000000000000000000000000000000000000000006223258e0000000000000000000000000000000000000000000000000000000064b554ad0000000000000000000000000000000000000000000000000000000064bf8d660000000000000000000000000000000000000000000000000000000082b57749000000000000000000000000000000000000000000000000000000008c564cc100000000000000000000000000000000000000000000000000000000235d9eb50000000000000000000000000000000000000000000000000000000027ae4c160000000000000000000000000000000000000000000000000000000043dc2951000000000000000000000000000000000000000000000000000000004623c91d000000000000000000000000000000000000000000000000000000004dd18bf5000000000000000000000000000000000000000000000000000000000e18b68100000000000000000000000000000000000000000000000000000000173389450000000000000000000000000000000000000000000000000000000021f603d7000000000000000000000000000000000000000000000000000000001cc5d103000000000000000000000000000000000000000000000000000000000000000000000000000000007684a3fd9f61c7c4d396177cc92384b076c6164a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000002c98acd7a6000000000000000000000000000000000000000000000000000000009cd939e4000000000000000000000000000000000000000000000000000000009d1b5a8100000000000000000000000000000000000000000000000000000000a1954fc500000000000000000000000000000000000000000000000000000000a7358efb00000000000000000000000000000000000000000000000000000000adfca15e00000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000b22dd78e00000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000cdffacc600000000000000000000000000000000000000000000000000000000d046815600000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000e5355c7500000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000ea6c029c00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000f5c1182c00000000000000000000000000000000000000000000000000000000facd743b00000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000fe26699e00000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000006e9960c30000000000000000000000000000000000000000000000000000000074f4d30d0000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000007a0ed627000000000000000000000000000000000000000000000000000000007b30c8da0000000000000000000000000000000000000000000000000000000039d7d4aa0000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000052ef6b2c000000000000000000000000000000000000000000000000000000005518c73b0000000000000000000000000000000000000000000000000000000056142d7a000000000000000000000000000000000000000000000000000000001de72e340000000000000000000000000000000000000000000000000000000029b98c670000000000000000000000000000000000000000000000000000000033ce93fe000000000000000000000000000000000000000000000000000000003408e470000000000000000000000000000000000000000000000000000000003591c1a000000000000000000000000000000000000000000000000000000000396073820000000000000000000000000000000000000000000000000000000006d49e5b00000000000000000000000000000000000000000000000000000000086a56f8000000000000000000000000000000000000000000000000000000000ec6b0b70000000000000000000000000000000000000000000000000000000018e3a94100000000000000000000000000000000000000000000000000000000000000000000000000000000a36f72a317fa180d945efb5fe4383c9fbfe8c8be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000b7efda2ae00000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000d06b26e200000000000000000000000000000000000000000000000000000000dcabb98200000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000042901c70000000000000000000000000000000000000000000000000000000008522c300000000000000000000000000000000000000000000000000000000012f43dab000000000000000000000000000000000000000000000000000000006c0960f900000000000000000000000000000000000000000000000000000000263b7f8e00000000000000000000000000000000000000000000000000000000000000000000000000000000340e73f0092fd6faec522a3b8a6b4b0d7242dbff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008701f58c5000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000bd6db49900000000000000000000000000000000000000000000000000000000c37533bb0000000000000000000000000000000000000000000000000000000000a22e22000000000000000000000000000000000000000000000000000000000f23da43000000000000000000000000000000000000000000000000000000006edd4f120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000ec2597d47a5416270d475b67e2b6cc20f35f4f50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c4b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000001d4c00000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000182b8000000000000000000000000000000000000000000000000000000000ee6b280000000000000000000000000a4cb26d6933d2c3e76718d30de8547bcdf8dd241" + +[tokens] +token_weth_address = "0x0000000000000000000000000000000000000000" diff --git a/l1-contracts/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-zk-chain-11.toml b/l1-contracts/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-zk-chain-11.toml new file mode 100644 index 0000000000..6ee582e673 --- /dev/null +++ b/l1-contracts/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-zk-chain-11.toml @@ -0,0 +1,16 @@ +owner_address = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" + +[chain] +allow_evm_emulator = false +base_token_addr = "0x0000000000000000000000000000000000000001" +base_token_gas_price_multiplier_denominator = 1 +base_token_gas_price_multiplier_nominator = 1 +bridgehub_create_new_chain_salt = 11 +chain_chain_id = 11 +governance_min_delay = 0 +governance_security_council_address = "0x0000000000000000000000000000000000000000" +validator_sender_operator_blobs_eth = "0x0000000000000000000000000000000000000001" +validator_sender_operator_eth = "0x0000000000000000000000000000000000000000" +validator_sender_operator_execute = "0x0000000000000000000000000000000000000003" +validator_sender_operator_prove = "0x0000000000000000000000000000000000000002" +validium_mode = 0 diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2AssetTracker.t.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2AssetTracker.t.sol new file mode 100644 index 0000000000..1f3d1bcf7e --- /dev/null +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2AssetTracker.t.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; +// solhint-disable gas-custom-errors + +import {StdStorage, Test, stdStorage} from "forge-std/Test.sol"; + +import {SharedL2ContractDeployer} from "./_SharedL2ContractDeployer.sol"; +import {GW_ASSET_TRACKER, GW_ASSET_TRACKER_ADDR, L2_BRIDGEHUB, L2_MESSAGE_ROOT, L2_MESSAGE_ROOT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; + +abstract contract L2AssetTrackerTest is Test, SharedL2ContractDeployer { + using stdStorage for StdStorage; + + function test_processLogsAndMessages() public { + finalizeDepositWithChainId(271); + + vm.chainId(GATEWAY_CHAIN_ID); + + bytes + memory data = hex"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000010f0000000000000000000000000000000000000000000000000000000000000007cc02c444ed97a398f98ce0846b2caeb14e9645874c530fc4443be56e97ac8ebee4ed1ec13a28c40715db6399f6f99ce04e5f19d60ad3ff6831f098cb6cf7594400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008008000000000000000000000000000000000000000000000000000000000001000ddfdf66b94c8f7281bac1dacc6204e33587e468aa0c680028c352df613ce9a26700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010439efa3f00100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000026e45cb3eb3303a363310dba9552e16500027f51000000000000000000000000000000000000000000000000000000000000010feaf44f2baeaf1396b40964237242564e6742f685bdef518ddbcd34039ae3d29f00000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000"; + // ProcessLogsInput memory input = abi.decode(data,(ProcessLogsInput)); + // Note: get this from real local txs + + // Initialize v30UpgradeChainBatchNumber for chain 271 with the correct placeholder value + uint256 placeholderValue = uint256( + keccak256(abi.encodePacked("V30_UPGRADE_CHAIN_BATCH_NUMBER_PLACEHOLDER_VALUE_FOR_GATEWAY")) + ); + stdstore + .target(address(L2_MESSAGE_ROOT_ADDR)) + .sig("v30UpgradeChainBatchNumber(uint256)") + .with_key(271) + .checked_write(placeholderValue); + + // Add the required previous batch roots for batches 1-4 + // The test is trying to add batch 5, so we need batches 1-4 to exist first + bytes32 dummyBatchRoot = keccak256("dummy_batch_root"); + for (uint256 i = 1; i <= 4; i++) { + stdstore + .target(address(L2_MESSAGE_ROOT_ADDR)) + .sig("chainBatchRoots(uint256,uint256)") + .with_key(271) + .with_key(i) + .checked_write(bytes32(uint256(dummyBatchRoot) + i)); + } + + // Set the current batch number to 4 so that batch 5 can be added next + stdstore + .target(address(L2_MESSAGE_ROOT_ADDR)) + .sig("currentChainBatchNumber(uint256)") + .with_key(271) + .checked_write(4); + + vm.prank(L2_BRIDGEHUB.getZKChain(271)); + + // TODO fix data + + // (bool success, ) = GW_ASSET_TRACKER_ADDR.call(bytes.concat(hex"e7ca8589", data)); + + // require(success, "Failed to call GWAssetTracker"); + } +} diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2Erc20TestAbstract.t.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2Erc20TestAbstract.t.sol index bc3714044b..0a8e69ed6f 100644 --- a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2Erc20TestAbstract.t.sol +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2Erc20TestAbstract.t.sol @@ -3,26 +3,38 @@ pragma solidity ^0.8.20; // solhint-disable gas-custom-errors -import {Test} from "forge-std/Test.sol"; +import {StdStorage, Test, stdStorage} from "forge-std/Test.sol"; import "forge-std/console.sol"; import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol"; import {L2AssetRouter} from "contracts/bridge/asset-router/L2AssetRouter.sol"; import {IL2NativeTokenVault} from "contracts/bridge/ntv/IL2NativeTokenVault.sol"; - import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; +import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; -import {L2_ASSET_ROUTER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {L2_ASSET_ROUTER_ADDR, L2_BASE_TOKEN_SYSTEM_CONTRACT, L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR, L2_BRIDGEHUB_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol"; import {IAdmin} from "contracts/state-transition/chain-interfaces/IAdmin.sol"; import {IL2AssetRouter} from "contracts/bridge/asset-router/IL2AssetRouter.sol"; -import {SharedL2ContractDeployer} from "./_SharedL2ContractDeployer.sol"; +import {NEW_ENCODING_VERSION} from "contracts/bridge/asset-router/IAssetRouterBase.sol"; import {TestnetERC20Token} from "contracts/dev-contracts/TestnetERC20Token.sol"; +import {IERC7786Attributes} from "contracts/interop/IERC7786Attributes.sol"; +import {IERC7786GatewaySource} from "contracts/interop/IERC7786GatewaySource.sol"; +import {InteroperableAddress} from "contracts/vendor/draft-InteroperableAddress.sol"; + +import {SharedL2ContractDeployer} from "./_SharedL2ContractDeployer.sol"; +import {InteropCall, InteropCallStarter} from "contracts/common/Messaging.sol"; abstract contract L2Erc20TestAbstract is Test, SharedL2ContractDeployer { + using stdStorage for StdStorage; + + address constant UNBUNDLER_ADDRESS = address(0x1); + address constant EXECUTION_ADDRESS = address(0x2); + function performDeposit(address depositor, address receiver, uint256 amount) internal { vm.prank(aliasedL1AssetRouter); L2AssetRouter(L2_ASSET_ROUTER_ADDR).finalizeDeposit({ @@ -35,12 +47,14 @@ abstract contract L2Erc20TestAbstract is Test, SharedL2ContractDeployer { } function initializeTokenByDeposit() internal returns (address l2TokenAddress) { - performDeposit(makeAddr("someDepositor"), makeAddr("someReeiver"), 1); + performDeposit(makeAddr("someDepositor"), makeAddr("someReceiver"), 1); l2TokenAddress = IL2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR).l2TokenAddress(L1_TOKEN_ADDRESS); if (l2TokenAddress == address(0)) { revert("Token not initialized"); } + vm.prank(L2_NATIVE_TOKEN_VAULT_ADDR); + BridgedStandardERC20(l2TokenAddress).bridgeMint(address(this), 100000); } function test_shouldFinalizeERC20Deposit() public { @@ -75,7 +89,7 @@ abstract contract L2Erc20TestAbstract is Test, SharedL2ContractDeployer { assertEq(BridgedStandardERC20(l2TokenAddress).decimals(), 18); } - function test_governanceShouldlNotBeAbleToSkipInitializerVersions() public { + function test_governanceShouldNotBeAbleToSkipInitializerVersions() public { address l2TokenAddress = initializeTokenByDeposit(); BridgedStandardERC20.ERC20Getters memory getters = BridgedStandardERC20.ERC20Getters({ @@ -109,4 +123,114 @@ abstract contract L2Erc20TestAbstract is Test, SharedL2ContractDeployer { DataEncoding.encodeBridgeBurnData(100, address(1), address(l2NativeToken)) ); } + + function test_requestTokenTransferInterop() public { + address l2TokenAddress = initializeTokenByDeposit(); + bytes32 l2TokenAssetId = l2NativeTokenVault.assetId(l2TokenAddress); + vm.deal(address(this), 1000 ether); + + bytes memory secondBridgeCalldata = bytes.concat( + NEW_ENCODING_VERSION, + abi.encode(l2TokenAssetId, abi.encode(uint256(100), address(this), 0)) + ); + + InteropCallStarter[] memory calls = new InteropCallStarter[](1); + bytes[] memory callAttributes = new bytes[](1); + callAttributes[0] = abi.encodeCall(IERC7786Attributes.indirectCall, (0)); + + calls[0] = InteropCallStarter({ + to: InteroperableAddress.formatEvmV1(L2_ASSET_ROUTER_ADDR), + data: secondBridgeCalldata, + callAttributes: callAttributes + }); + + uint256 destinationChainId = 271; + vm.mockCall( + L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + abi.encodeWithSelector(L2_TO_L1_MESSENGER_SYSTEM_CONTRACT.sendToL1.selector), + abi.encode(bytes("")) + ); + vm.mockCall( + L2_BRIDGEHUB_ADDR, + abi.encodeWithSelector(IBridgehubBase.baseTokenAssetId.selector), + abi.encode(baseTokenAssetId) + ); + + vm.mockCall( + L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR, + abi.encodeWithSelector(L2_BASE_TOKEN_SYSTEM_CONTRACT.burnMsgValue.selector), + abi.encode(bytes("")) + ); + + bytes[] memory bundleAttributes = new bytes[](1); + bundleAttributes[0] = abi.encodeCall( + IERC7786Attributes.unbundlerAddress, + (InteroperableAddress.formatEvmV1(UNBUNDLER_ADDRESS)) + ); + l2InteropCenter.sendBundle(InteroperableAddress.formatEvmV1(271), calls, bundleAttributes); + } + + function test_requestSendCall() public { + address l2TokenAddress = initializeTokenByDeposit(); + bytes32 l2TokenAssetId = l2NativeTokenVault.assetId(l2TokenAddress); + vm.deal(address(this), 1000 ether); + + bytes memory secondBridgeCalldata = bytes.concat( + NEW_ENCODING_VERSION, + abi.encode(l2TokenAssetId, abi.encode(uint256(100), address(this), 0)) + ); + + InteropCallStarter[] memory calls = new InteropCallStarter[](1); + bytes[] memory attributes = new bytes[](3); + attributes[0] = abi.encodeCall(IERC7786Attributes.indirectCall, (0)); + attributes[1] = abi.encodeCall( + IERC7786Attributes.executionAddress, + (InteroperableAddress.formatEvmV1(EXECUTION_ADDRESS)) + ); + attributes[2] = abi.encodeCall( + IERC7786Attributes.unbundlerAddress, + (InteroperableAddress.formatEvmV1(UNBUNDLER_ADDRESS)) + ); + calls[0] = InteropCallStarter({ + to: InteroperableAddress.formatEvmV1(L2_ASSET_ROUTER_ADDR), + data: secondBridgeCalldata, + callAttributes: attributes + }); + + uint256 destinationChainId = 271; + vm.mockCall( + L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + abi.encodeWithSelector(L2_TO_L1_MESSENGER_SYSTEM_CONTRACT.sendToL1.selector), + abi.encode(bytes("")) + ); + vm.mockCall( + L2_BRIDGEHUB_ADDR, + abi.encodeWithSelector(IBridgehubBase.baseTokenAssetId.selector), + abi.encode(baseTokenAssetId) + ); + + vm.mockCall( + L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR, + abi.encodeWithSelector(L2_BASE_TOKEN_SYSTEM_CONTRACT.burnMsgValue.selector), + abi.encode(bytes("")) + ); + IERC7786GatewaySource(address(l2InteropCenter)).sendMessage( + calls[0].to, + calls[0].data, + calls[0].callAttributes + ); + } + + function test_supportsAttributes() public { + assertEq( + IERC7786GatewaySource(address(l2InteropCenter)).supportsAttribute(IERC7786Attributes.indirectCall.selector), + true + ); + assertEq( + IERC7786GatewaySource(address(l2InteropCenter)).supportsAttribute( + IERC7786GatewaySource.supportsAttribute.selector + ), + false + ); + } } diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2GatewayTestAbstract.t.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2GatewayTestAbstract.t.sol index 4e05148d82..3e0f62adb9 100644 --- a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2GatewayTestAbstract.t.sol +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2GatewayTestAbstract.t.sol @@ -7,8 +7,9 @@ pragma solidity ^0.8.20; import {StdStorage, Test, console2 as console, stdStorage} from "forge-std/Test.sol"; import "forge-std/console.sol"; -import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; -import {SETTLEMENT_LAYER_RELAY_SENDER, ZKChainCommitment} from "contracts/common/Config.sol"; +import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; + +import {SETTLEMENT_LAYER_RELAY_SENDER, ZKChainCommitment, PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET} from "contracts/common/Config.sol"; import {BridgehubBurnCTMAssetData, BridgehubMintCTMAssetData, IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; import {BridgehubBase} from "contracts/bridgehub/BridgehubBase.sol"; @@ -17,13 +18,23 @@ import {L2Bridgehub} from "contracts/bridgehub/L2Bridgehub.sol"; import {IAssetRouterBase} from "contracts/bridge/asset-router/IAssetRouterBase.sol"; import {AssetRouterBase} from "contracts/bridge/asset-router/AssetRouterBase.sol"; +import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; + import {SharedL2ContractDeployer} from "./_SharedL2ContractDeployer.sol"; -import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; +import {BALANCE_CHANGE_VERSION} from "contracts/bridge/asset-tracker/IAssetTrackerBase.sol"; +import {BalanceChange} from "contracts/common/Messaging.sol"; +import {IChainAssetHandler} from "contracts/bridgehub/IChainAssetHandler.sol"; abstract contract L2GatewayTestAbstract is Test, SharedL2ContractDeployer { using stdStorage for StdStorage; + function _pauseDeposits(uint256 _chainId) public { + pauseDepositsBeforeInitiatingMigration(L2_BRIDGEHUB_ADDR, _chainId); + // As the priority queue was not empty before migration, we wait until the paused deposits window starts + vm.warp(block.timestamp + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET); + } + function test_gatewayShouldFinalizeDeposit() public { finalizeDeposit(); require(l2Bridgehub.ctmAssetIdFromAddress(address(chainTypeManager)) == ctmAssetId, "ctmAssetId mismatch"); @@ -47,16 +58,31 @@ abstract contract L2GatewayTestAbstract is Test, SharedL2ContractDeployer { require(!GettersFacet(diamondProxy).isPriorityQueueActive(), "Priority queue must not be active"); } - function test_forwardToL2OnGateway() public { + function test_forwardToL2OnGateway_L2() public { // todo fix this test finalizeDeposit(); vm.prank(SETTLEMENT_LAYER_RELAY_SENDER); - L2Bridgehub(address(l2Bridgehub)).forwardTransactionOnGateway(mintChainId, bytes32(0), 0); + vm.mockCall( + L2_CHAIN_ASSET_HANDLER_ADDR, + abi.encodeWithSelector(IChainAssetHandler.migrationNumber.selector), + abi.encode(1) + ); + BalanceChange memory balanceChange = BalanceChange({ + version: BALANCE_CHANGE_VERSION, + baseTokenAssetId: bytes32(0), + baseTokenAmount: 0, + assetId: bytes32(0), + amount: 0, + tokenOriginChainId: 0, + originToken: address(0) + }); + l2InteropCenter.forwardTransactionOnGatewayWithBalanceChange(mintChainId, bytes32(0), 0, balanceChange); } function test_withdrawFromGateway() public { - // todo fix this test finalizeDeposit(); + clearPriorityQueue(address(discoveredBridgehub.bridgehubProxy), mintChainId); + _pauseDeposits(mintChainId); address newAdmin = makeAddr("newAdmin"); bytes memory newDiamondCut = abi.encode(); BridgehubBurnCTMAssetData memory data = BridgehubBurnCTMAssetData({ @@ -66,42 +92,20 @@ abstract contract L2GatewayTestAbstract is Test, SharedL2ContractDeployer { }); vm.prank(ownerWallet); vm.mockCall( - address(L2_TO_L1_MESSENGER_SYSTEM_CONTRACT), + address(L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR), abi.encodeWithSelector(L2_TO_L1_MESSENGER_SYSTEM_CONTRACT.sendToL1.selector), abi.encode(bytes("")) ); l2AssetRouter.withdraw(ctmAssetId, abi.encode(data)); } - function finalizeDeposit() public { - finalizeDepositWithCustomCommitment(exampleChainCommitment); - } - - function finalizeDepositWithCustomCommitment(bytes memory chainCommitment) public { - bytes memory chainData = chainCommitment; - bytes memory ctmData = abi.encode( - baseTokenAssetId, - ownerWallet, - chainTypeManager.protocolVersion(), - config.contracts.diamondCutData - ); - BridgehubMintCTMAssetData memory data = BridgehubMintCTMAssetData({ - chainId: mintChainId, - baseTokenAssetId: baseTokenAssetId, - ctmData: ctmData, - chainData: chainData - }); - vm.prank(aliasedL1AssetRouter); - AssetRouterBase(address(l2AssetRouter)).finalizeDeposit(L1_CHAIN_ID, ctmAssetId, abi.encode(data)); - } - function test_finalizeDepositWithRealChainData() public { // Note: get this from real local txs // Note: if the contracts were changed, this test might fail. Just comment it out. bytes - memory data = hex"9c884fd1000000000000000000000000000000000000000000000000000000000000000917531d49af8763b6b62da9916d00fa378c1b4b7786eab4bdb643daaddd9d6426000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000014800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010f52f431aa35dd80982e3c66614112503ca2c6e344745f4a2bcfc9bd7e09c75584000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000011c0000000000000000000000000000000000000000000000000000000000000112052f431aa35dd80982e3c66614112503ca2c6e344745f4a2bcfc9bd7e09c755840000000000000000000000002f9a6cbadd1b37615ce9cc71842c3b0748e9e4570000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000108000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c288eb67124c094529a0ae3270f56ec5e64c2b730000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000a600000000000000000000000000000000000000000000000000000000000000cc00000000000000000000000005a0c575ae5582d250979443d277008f7e32d99a100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000150e18b681000000000000000000000000000000000000000000000000000000001733894500000000000000000000000000000000000000000000000000000000fc57565f000000000000000000000000000000000000000000000000000000001cc5d1030000000000000000000000000000000000000000000000000000000021f603d700000000000000000000000000000000000000000000000000000000235d9eb50000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000002878fe74000000000000000000000000000000000000000000000000000000003f42d5dd0000000000000000000000000000000000000000000000000000000041cf49bb000000000000000000000000000000000000000000000000000000004623c91d000000000000000000000000000000000000000000000000000000004dd18bf5000000000000000000000000000000000000000000000000000000005b898748000000000000000000000000000000000000000000000000000000006223258e0000000000000000000000000000000000000000000000000000000064b554ad0000000000000000000000000000000000000000000000000000000064bf8d66000000000000000000000000000000000000000000000000000000006e762e9800000000000000000000000000000000000000000000000000000000a9f6d94100000000000000000000000000000000000000000000000000000000b784610700000000000000000000000000000000000000000000000000000000be6f11cf00000000000000000000000000000000000000000000000000000000e76db86500000000000000000000000000000000000000000000000000000000000000000000000000000000379b31e7f4b22a023da84ad20b898c8038fb0492000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000003006d49e5b000000000000000000000000000000000000000000000000000000000ec6b0b700000000000000000000000000000000000000000000000000000000fe26699e0000000000000000000000000000000000000000000000000000000018e3a941000000000000000000000000000000000000000000000000000000001de72e340000000000000000000000000000000000000000000000000000000022c5cf230000000000000000000000000000000000000000000000000000000029b98c670000000000000000000000000000000000000000000000000000000033ce93fe000000000000000000000000000000000000000000000000000000003408e470000000000000000000000000000000000000000000000000000000003591c1a000000000000000000000000000000000000000000000000000000000396073820000000000000000000000000000000000000000000000000000000039d7d4aa0000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000052ef6b2c000000000000000000000000000000000000000000000000000000005a59033500000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000006a27e8b5000000000000000000000000000000000000000000000000000000006e9960c30000000000000000000000000000000000000000000000000000000074f4d30d0000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000007a0ed627000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008708474e00000000000000000000000000000000000000000000000000000000946ebad100000000000000000000000000000000000000000000000000000000960dcf240000000000000000000000000000000000000000000000000000000098acd7a6000000000000000000000000000000000000000000000000000000009cd939e4000000000000000000000000000000000000000000000000000000009d1b5a8100000000000000000000000000000000000000000000000000000000a1954fc500000000000000000000000000000000000000000000000000000000adfca15e00000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000b22dd78e00000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000cdffacc600000000000000000000000000000000000000000000000000000000d046815600000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000dd655bb000000000000000000000000000000000000000000000000000000000e5355c7500000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000ea6c029c00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000f4ff5e2e00000000000000000000000000000000000000000000000000000000f5c1182c00000000000000000000000000000000000000000000000000000000facd743b00000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000000000000000000000000000dea3b08fd1b185a78fb83f923576e597750f1b80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000e042901c70000000000000000000000000000000000000000000000000000000012f43dab00000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000018b7fc2200000000000000000000000000000000000000000000000000000000263b7f8e000000000000000000000000000000000000000000000000000000006c0960f90000000000000000000000000000000000000000000000000000000079cf6165000000000000000000000000000000000000000000000000000000007efda2ae00000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000d077255100000000000000000000000000000000000000000000000000000000d07b90d100000000000000000000000000000000000000000000000000000000ddcc9eec00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000e896760d0000000000000000000000000000000000000000000000000000000000000000000000000000000023be442ccb5b2d6d3960691888719bc76093a31200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000040f23da4300000000000000000000000000000000000000000000000000000000e12a61370000000000000000000000000000000000000000000000000000000098f8196200000000000000000000000000000000000000000000000000000000cf02827d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000a9edb426784d7e4a8a02571d9a4481010bc0eb98000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010008cffa528a3e3ba642ba72c25ab4ce5663f9e8622d8fd883ebc113f49b7c010005f75d0c14b6da8400e091a9f5a895b693fc44d028c6d2f29e57d8b137d301000d417fc3c32f3bb837e09637cfa15303d685e44d1a5f1a04a3a3ea298fe400000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000001d4c00000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000182b8000000000000000000000000000000000000000000000000000000000ee6b28000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000087ef4adf518e6986b85e2fa3bf7047b353d8a8422a5af274abefd1c30a7a8b9800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001fcd1aeeb5e3711b1d1ee7567c82ccc35ec73911e95efccbba41086a656a04c4000000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004ae848202ab08b6303b34fe671aa187102485987c81a5623eea86bc531dc8ad7306a23e438ce807cd551f5d126dd9c48273c07ad26e9fa988329d10901626c68062f784161a84f8977c3f8fa83ced9efae70bc7eef93d29d06940084f00c73b952da0da7438a146b6c88e382df7fcc113f627e19966eef7676277106832574405"; + memory data = hex"9c884fd1000000000000000000000000000000000000000000000000000000000000000959aa8734729403717df39fdf9638d16e2c3d339457191b4f6bb608dbae81c160000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010f52f431aa35dd80982e3c66614112503ca2c6e344745f4a2bcfc9bd7e09c755840000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000114000000000000000000000000000000000000000000000000000000000000010a052f431aa35dd80982e3c66614112503ca2c6e344745f4a2bcfc9bd7e09c755840000000000000000000000007677c9b069b7de5bb947d8c99a0bcaf394703ecd0000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000005a0dc1bd07644266f19e89c9648b2da2e57e35fd0000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000a200000000000000000000000000000000000000000000000000000000000000c600000000000000000000000006322eb095e77f76685de717c99c7eab89eb8c91800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000140e18b681000000000000000000000000000000000000000000000000000000001733894500000000000000000000000000000000000000000000000000000000fc57565f000000000000000000000000000000000000000000000000000000001cc5d1030000000000000000000000000000000000000000000000000000000021f603d700000000000000000000000000000000000000000000000000000000235d9eb50000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000002878fe74000000000000000000000000000000000000000000000000000000003f42d5dd0000000000000000000000000000000000000000000000000000000041cf49bb000000000000000000000000000000000000000000000000000000004623c91d000000000000000000000000000000000000000000000000000000004dd18bf5000000000000000000000000000000000000000000000000000000006223258e0000000000000000000000000000000000000000000000000000000064b554ad0000000000000000000000000000000000000000000000000000000064bf8d66000000000000000000000000000000000000000000000000000000006e762e9800000000000000000000000000000000000000000000000000000000a9f6d94100000000000000000000000000000000000000000000000000000000b784610700000000000000000000000000000000000000000000000000000000be6f11cf00000000000000000000000000000000000000000000000000000000e76db86500000000000000000000000000000000000000000000000000000000000000000000000000000000076544525dc218ef52a52e013e7d9e02342645ce000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000002f06d49e5b000000000000000000000000000000000000000000000000000000000ec6b0b700000000000000000000000000000000000000000000000000000000fe26699e0000000000000000000000000000000000000000000000000000000018e3a941000000000000000000000000000000000000000000000000000000001de72e340000000000000000000000000000000000000000000000000000000022c5cf230000000000000000000000000000000000000000000000000000000029b98c670000000000000000000000000000000000000000000000000000000033ce93fe000000000000000000000000000000000000000000000000000000003408e470000000000000000000000000000000000000000000000000000000003591c1a000000000000000000000000000000000000000000000000000000000396073820000000000000000000000000000000000000000000000000000000039d7d4aa0000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000052ef6b2c000000000000000000000000000000000000000000000000000000005a59033500000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000006a27e8b5000000000000000000000000000000000000000000000000000000006e9960c30000000000000000000000000000000000000000000000000000000074f4d30d0000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000007a0ed627000000000000000000000000000000000000000000000000000000007b30c8da000000000000000000000000000000000000000000000000000000008708474e00000000000000000000000000000000000000000000000000000000946ebad100000000000000000000000000000000000000000000000000000000960dcf240000000000000000000000000000000000000000000000000000000098acd7a6000000000000000000000000000000000000000000000000000000009cd939e4000000000000000000000000000000000000000000000000000000009d1b5a8100000000000000000000000000000000000000000000000000000000a1954fc500000000000000000000000000000000000000000000000000000000adfca15e00000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000b22dd78e00000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000cdffacc600000000000000000000000000000000000000000000000000000000d046815600000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000e5355c7500000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000ea6c029c00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000f4ff5e2e00000000000000000000000000000000000000000000000000000000f5c1182c00000000000000000000000000000000000000000000000000000000facd743b00000000000000000000000000000000000000000000000000000000fd791f3c00000000000000000000000000000000000000000000000000000000000000000000000000000000838193685dc563b00f38f2d0b5de695ce34e852f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d042901c70000000000000000000000000000000000000000000000000000000012f43dab00000000000000000000000000000000000000000000000000000000eb6724190000000000000000000000000000000000000000000000000000000018b7fc2200000000000000000000000000000000000000000000000000000000263b7f8e000000000000000000000000000000000000000000000000000000006c0960f90000000000000000000000000000000000000000000000000000000079cf6165000000000000000000000000000000000000000000000000000000007efda2ae00000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000d077255100000000000000000000000000000000000000000000000000000000ddcc9eec00000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000e896760d00000000000000000000000000000000000000000000000000000000000000000000000000000000775bd7a034fd606b716113978d58aa8fdf1a953700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000040f23da4300000000000000000000000000000000000000000000000000000000e12a61370000000000000000000000000000000000000000000000000000000098f8196200000000000000000000000000000000000000000000000000000000cf02827d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000fa043dfb4ab56f5d6d5232b4075ca2fd6f6bb1d4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010008b99787eebe6c393d5df031f54c5f92c03b22249fee2e1ceca4a20ed8ae01000615dd0d89d8f012254048f022f09eeb77e293780d4884fe864e9dbb78de00000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000001d4c00000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000182b8000000000000000000000000000000000000000000000000000000000ee6b2800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009d3e224f424aa0c33685a951d8a7f3d905f602ed0ddbab27978529198133bab60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000113683622e80dc275333cff0625d5698e2e393eb130fd26c1fad005f340a308d600000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004ff616c6c09c5f9827f42fa2e38b14154243e4150cc2f0cd29d4632f1a6fa88493608ece7b04503cfbd16ba5dcfcc9a946c7564e207f8d0f8befbb44e723f6e501298f18a823119265b57a36cfd6c8638f1fda179f247131a1d0ca4a88a75bb82878663a1e190807881f1803c1d9dff191224fba96ede3a460594f6212d086667"; address recipient = L2_ASSET_ROUTER_ADDR; - bytes32 assetId = 0x17531d49af8763b6b62da9916d00fa378c1b4b7786eab4bdb643daaddd9d6426; + bytes32 assetId = 0x59aa8734729403717df39fdf9638d16e2c3d339457191b4f6bb608dbae81c160; stdstore .target(L2_ASSET_ROUTER_ADDR) .sig(IAssetRouterBase.assetHandlerAddress.selector) diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2InteropTestAbstract.t.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2InteropTestAbstract.t.sol new file mode 100644 index 0000000000..9ba5be877d --- /dev/null +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2InteropTestAbstract.t.sol @@ -0,0 +1,478 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; +// solhint-disable gas-custom-errors + +import {Test} from "forge-std/Test.sol"; +import "forge-std/console.sol"; + +import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; + +import {L2_ASSET_ROUTER_ADDR, L2_BASE_TOKEN_SYSTEM_CONTRACT, L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR, L2_BRIDGEHUB_ADDR, L2_INTEROP_CENTER_ADDR, L2_INTEROP_HANDLER_ADDR, L2_MESSAGE_VERIFICATION, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {Transaction} from "contracts/common/l2-helpers/L2ContractHelper.sol"; +import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; + +import {IBaseToken} from "contracts/common/l2-helpers/IBaseToken.sol"; +import {IAssetRouterBase, AssetRouterBase} from "contracts/bridge/asset-router/AssetRouterBase.sol"; + +import {InteropCenter} from "contracts/interop/InteropCenter.sol"; +import {CallStatus, IInteropHandler} from "contracts/interop/IInteropHandler.sol"; +import {IERC7786Attributes} from "contracts/interop/IERC7786Attributes.sol"; +import {UnauthorizedMessageSender, WrongDestinationChainId} from "contracts/interop/InteropErrors.sol"; +import {InteroperableAddress} from "contracts/vendor/draft-InteroperableAddress.sol"; + +import {SharedL2ContractDeployer} from "./_SharedL2ContractDeployer.sol"; +import {BundleAttributes, INTEROP_BUNDLE_VERSION, INTEROP_CALL_VERSION, InteropBundle, InteropCall, InteropCallStarter, L2Message, MessageInclusionProof} from "contracts/common/Messaging.sol"; + +import {IMessageVerification} from "contracts/common/interfaces/IMessageVerification.sol"; + +import {InteropDataEncoding} from "contracts/interop/InteropDataEncoding.sol"; +import {InteropHandler} from "contracts/interop/InteropHandler.sol"; + +abstract contract L2InteropTestAbstract is Test, SharedL2ContractDeployer { + address constant UNBUNDLER_ADDRESS = address(0x1); + address constant EXECUTION_ADDRESS = address(0x2); + + function test_requestL2TransactionDirectWithCalldata() public { + // Note: get this from real local txs + bytes + memory data = hex"d52471c1000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001f9000000000000000000000000000000000000000000000001158e460913d000000000000000000000000000009ca26d77cde9cff9145d06725b400b2ec4bbc6160000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000023c34600000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000001400000000000000000000000009ca26d77cde9cff9145d06725b400b2ec4bbc61600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + + vm.mockCall( + L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + abi.encodeWithSelector(L2_TO_L1_MESSENGER_SYSTEM_CONTRACT.sendToL1.selector), + abi.encode(bytes32(0)) + ); + address recipient = L2_BRIDGEHUB_ADDR; + // (bool success, ) = recipient.call(data); + // assertTrue(success); + } + + function test_sendBundle_simple() public { + vm.mockCall( + L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR, + abi.encodeWithSelector(IBaseToken.burnMsgValue.selector), + abi.encode() + ); + vm.mockCall( + L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + abi.encodeWithSelector(L2_TO_L1_MESSENGER_SYSTEM_CONTRACT.sendToL1.selector), + abi.encode(bytes32(0)) + ); + + bytes memory destinationChainId = InteroperableAddress.formatEvmV1(260); + + address targetContract = makeAddr("targetContract"); + InteropCallStarter[] memory callStarters = new InteropCallStarter[](1); + + callStarters[0] = InteropCallStarter({ + to: InteroperableAddress.formatEvmV1(targetContract), + data: abi.encodeWithSignature("simpleCall()"), + callAttributes: new bytes[](0) + }); + + address executionAddress = makeAddr("executionAddress"); + address unbundlerAddress = makeAddr("unbundlerAddress"); + + bytes[] memory bundleAttributes = new bytes[](2); + bundleAttributes[0] = abi.encodePacked( + IERC7786Attributes.executionAddress.selector, + InteroperableAddress.formatEvmV1(260, executionAddress) + ); + bundleAttributes[1] = abi.encodePacked( + IERC7786Attributes.unbundlerAddress.selector, + InteroperableAddress.formatEvmV1(260, unbundlerAddress) + ); + + (bool success, bytes memory returnData) = L2_INTEROP_CENTER_ADDR.call( + abi.encodeWithSelector( + InteropCenter.sendBundle.selector, + destinationChainId, + callStarters, + bundleAttributes + ) + ); + + assertTrue(success, "sendBundle should succeed"); + + // Decode the returned bundle hash + bytes32 bundleHash = abi.decode(returnData, (bytes32)); + assertNotEq(bundleHash, bytes32(0), "Bundle hash should not be zero"); + } + + function getInclusionProof(address messageSender) public view returns (MessageInclusionProof memory) { + bytes32[] memory proof = new bytes32[](27); + proof[0] = bytes32(0x010f050000000000000000000000000000000000000000000000000000000000); + proof[1] = bytes32(0x72abee45b59e344af8a6e520241c4744aff26ed411f4c4b00f8af09adada43ba); + proof[2] = bytes32(0xc3d03eebfd83049991ea3d3e358b6712e7aa2e2e63dc2d4b438987cec28ac8d0); + proof[3] = bytes32(0xe3697c7f33c31a9b0f0aeb8542287d0d21e8c4cf82163d0c44c7a98aa11aa111); + proof[4] = bytes32(0x199cc5812543ddceeddd0fc82807646a4899444240db2c0d2f20c3cceb5f51fa); + proof[5] = bytes32(0xe4733f281f18ba3ea8775dd62d2fcd84011c8c938f16ea5790fd29a03bf8db89); + proof[6] = bytes32(0x1798a1fd9c8fbb818c98cff190daa7cc10b6e5ac9716b4a2649f7c2ebcef2272); + proof[7] = bytes32(0x66d7c5983afe44cf15ea8cf565b34c6c31ff0cb4dd744524f7842b942d08770d); + proof[8] = bytes32(0xb04e5ee349086985f74b73971ce9dfe76bbed95c84906c5dffd96504e1e5396c); + proof[9] = bytes32(0xac506ecb5465659b3a927143f6d724f91d8d9c4bdb2463aee111d9aa869874db); + proof[10] = bytes32(0x124b05ec272cecd7538fdafe53b6628d31188ffb6f345139aac3c3c1fd2e470f); + proof[11] = bytes32(0xc3be9cbd19304d84cca3d045e06b8db3acd68c304fc9cd4cbffe6d18036cb13f); + proof[12] = bytes32(0xfef7bd9f889811e59e4076a0174087135f080177302763019adaf531257e3a87); + proof[13] = bytes32(0xa707d1c62d8be699d34cb74804fdd7b4c568b6c1a821066f126c680d4b83e00b); + proof[14] = bytes32(0xf6e093070e0389d2e529d60fadb855fdded54976ec50ac709e3a36ceaa64c291); + proof[15] = bytes32(0xe4ed1ec13a28c40715db6399f6f99ce04e5f19d60ad3ff6831f098cb6cf75944); + proof[16] = bytes32(0x000000000000000000000000000000000000000000000000000000000000001e); + proof[17] = bytes32(0x46700b4d40ac5c35af2c22dda2787a91eb567b06c924a8fb8ae9a05b20c08c21); + proof[18] = bytes32(0x72bb6e886e3de761d93578a590bfe0e44fb544481eb63186f6a6d184aec321a8); + proof[19] = bytes32(0x3cc519adb13de86ec011fa462394c5db945103c4d35919c9433d7b990de49c87); + proof[20] = bytes32(0xcc52bf2ee1507ce0b5dbf31a95ce4b02043c142aab2466fc24db520852cddf5f); + proof[21] = bytes32(0x40ad48c159fc740c32e9b540f79561a4760501ef80e32c61e477ac3505d3dabd); + proof[22] = bytes32(0x0000000000000000000000000000009f00000000000000000000000000000001); + proof[23] = bytes32(0x00000000000000000000000000000000000000000000000000000000000001fa); + proof[24] = bytes32(0x0102000100000000000000000000000000000000000000000000000000000000); + proof[25] = bytes32(0xf84927dc03d95cc652990ba75874891ccc5a4d79a0e10a2ffdd238a34a39f828); + proof[26] = bytes32(0xe25714e53790167f58b1da56145a1c025a461008fe358f583f53d764000ca847); + + return + MessageInclusionProof({ + chainId: ERA_CHAIN_ID, + l1BatchNumber: 31, + l2MessageIndex: 0, + message: L2Message( + 0, + address(messageSender), + hex"9c884fd1000000000000000000000000000000000000000000000000000000000000010f76b59944c0e577e988c1b823ef4ad168478ddfe6044cca433996ade7637ec70d00000000000000000000000083aeb38092d5f5a5cf7fb8ccf94c981c1d37d81300000000000000000000000083aeb38092d5f5a5cf7fb8ccf94c981c1d37d813000000000000000000000000ee0dcf9b8c3048530fd6b2211ae3ba32e8590905000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c1010000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004574254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000457425443000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000" + ), + proof: proof + }); + } + + function test_l2MessageVerification() public { + MessageInclusionProof memory proof = getInclusionProof(L2_INTEROP_CENTER_ADDR); + L2_MESSAGE_VERIFICATION.proveL2MessageInclusionShared( + proof.chainId, + proof.l1BatchNumber, + proof.l2MessageIndex, + proof.message, + proof.proof + ); + } + + function test_l2MessageInclusion() public { + bytes + memory data = hex"000000000000000000000000000000000000000000000000000000000000010f000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000010003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002e49c884fd1000000000000000000000000000000000000000000000000000000000000010f76b59944c0e577e988c1b823ef4ad168478ddfe6044cca433996ade7637ec70d0000000000000000000000007bf0d042d77d77762db0da0198241e1ed52fcfec0000000000000000000000007bf0d042d77d77762db0da0198241e1ed52fcfec000000000000000000000000ee0dcf9b8c3048530fd6b2211ae3ba32e8590905000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c101000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000457425443000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045742544300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b010f05000000000000000000000000000000000000000000000000000000000072abee45b59e344af8a6e520241c4744aff26ed411f4c4b00f8af09adada43bac3d03eebfd83049991ea3d3e358b6712e7aa2e2e63dc2d4b438987cec28ac8d0e3697c7f33c31a9b0f0aeb8542287d0d21e8c4cf82163d0c44c7a98aa11aa111199cc5812543ddceeddd0fc82807646a4899444240db2c0d2f20c3cceb5f51fae4733f281f18ba3ea8775dd62d2fcd84011c8c938f16ea5790fd29a03bf8db891798a1fd9c8fbb818c98cff190daa7cc10b6e5ac9716b4a2649f7c2ebcef227266d7c5983afe44cf15ea8cf565b34c6c31ff0cb4dd744524f7842b942d08770db04e5ee349086985f74b73971ce9dfe76bbed95c84906c5dffd96504e1e5396cac506ecb5465659b3a927143f6d724f91d8d9c4bdb2463aee111d9aa869874db124b05ec272cecd7538fdafe53b6628d31188ffb6f345139aac3c3c1fd2e470fc3be9cbd19304d84cca3d045e06b8db3acd68c304fc9cd4cbffe6d18036cb13ffef7bd9f889811e59e4076a0174087135f080177302763019adaf531257e3a87a707d1c62d8be699d34cb74804fdd7b4c568b6c1a821066f126c680d4b83e00bf6e093070e0389d2e529d60fadb855fdded54976ec50ac709e3a36ceaa64c291e4ed1ec13a28c40715db6399f6f99ce04e5f19d60ad3ff6831f098cb6cf759440000000000000000000000000000000000000000000000000000000000000019964bc0ec60b4ef3961a574f9600449173bd53b1b5c849d16f62f0f6c0abb507ecc4c41edb0c2031348b292b768e9bac1ee8c92c09ef8a3277c2ece409c12d86a266f52b16165e9e2253be106c3774931e09bc1aff98955a74814788fbaba6b7f7fb5ed988285f34b64f87805c7c4aea5d4304769ebc0646fec775c4b2f442704d65feac380aaaf873c998d9341e47ee14561dd24e0bce7845c372183d94e98a3000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001fa0102000100000000000000000000000000000000000000000000000000000000f84927dc03d95cc652990ba75874891ccc5a4d79a0e10a2ffdd238a34a39f82803916fcde2bef5aa3b302f7eb413ecc65bb744d4ba66e1b4c6757107025f40c7"; + (bool success, ) = address(L2_MESSAGE_VERIFICATION).call( + abi.encodePacked(IMessageVerification.proveL2MessageInclusionShared.selector, data) + ); + require(success); + } + + function test_executeBundle() public { + InteropBundle memory interopBundle = getInteropBundle(1); + bytes memory bundle = abi.encode(interopBundle); + MessageInclusionProof memory proof = getInclusionProof(L2_INTEROP_CENTER_ADDR); + vm.mockCall( + address(L2_MESSAGE_VERIFICATION), + abi.encodeWithSelector(L2_MESSAGE_VERIFICATION.proveL2MessageInclusionShared.selector), + abi.encode(true) + ); + vm.mockCall( + L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR, + abi.encodeWithSelector(L2_BASE_TOKEN_SYSTEM_CONTRACT.mint.selector), + abi.encode(bytes("")) + ); + vm.mockCall( + L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + abi.encodeWithSelector(L2_TO_L1_MESSENGER_SYSTEM_CONTRACT.sendToL1.selector), + abi.encode(bytes32(0)) + ); + bytes32 bundleHash = InteropDataEncoding.encodeInteropBundleHash(proof.chainId, bundle); + // Expect event + vm.expectEmit(true, false, false, false); + emit IInteropHandler.BundleExecuted(bundleHash); + vm.prank(EXECUTION_ADDRESS); + IInteropHandler(L2_INTEROP_HANDLER_ADDR).executeBundle(bundle, proof); + // Check storage changes + assertEq( + uint256(InteropHandler(L2_INTEROP_HANDLER_ADDR).bundleStatus(bundleHash)), + 2, + "BundleStatus should be FullyExecuted" + ); + for (uint256 i = 0; i < interopBundle.calls.length; ++i) { + assertEq( + uint256(InteropHandler(L2_INTEROP_HANDLER_ADDR).callStatus(bundleHash, i)), + 1, + "CallStatus should be Executed" + ); + } + } + + function test_unbundleBundle() public { + InteropBundle memory interopBundle = getInteropBundle(3); + bytes memory bundle = abi.encode(interopBundle); + MessageInclusionProof memory proof = getInclusionProof(L2_INTEROP_CENTER_ADDR); + vm.mockCall( + address(L2_MESSAGE_VERIFICATION), + abi.encodeWithSelector(L2_MESSAGE_VERIFICATION.proveL2MessageInclusionShared.selector), + abi.encode(true) + ); + vm.mockCall( + L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR, + abi.encodeWithSelector(L2_BASE_TOKEN_SYSTEM_CONTRACT.mint.selector), + abi.encode(bytes("")) + ); + vm.mockCall( + L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + abi.encodeWithSelector(L2_TO_L1_MESSENGER_SYSTEM_CONTRACT.sendToL1.selector), + abi.encode(bytes32(0)) + ); + bytes32 bundleHash = InteropDataEncoding.encodeInteropBundleHash(proof.chainId, bundle); + IInteropHandler(L2_INTEROP_HANDLER_ADDR).verifyBundle(bundle, proof); + CallStatus[] memory callStatuses1 = new CallStatus[](3); + callStatuses1[0] = CallStatus.Unprocessed; + callStatuses1[1] = CallStatus.Cancelled; + callStatuses1[2] = CallStatus.Executed; + CallStatus[] memory callStatuses2 = new CallStatus[](3); + callStatuses2[0] = CallStatus.Executed; + callStatuses2[1] = CallStatus.Cancelled; + callStatuses2[2] = CallStatus.Unprocessed; + // Expect events for first unbundle + vm.expectEmit(true, false, false, false); + emit IInteropHandler.CallProcessed(bundleHash, 1, CallStatus.Cancelled); + vm.expectEmit(true, false, false, false); + emit IInteropHandler.CallProcessed(bundleHash, 2, CallStatus.Executed); + vm.expectEmit(true, false, false, false); + emit IInteropHandler.BundleUnbundled(bundleHash); + vm.prank(UNBUNDLER_ADDRESS); + IInteropHandler(L2_INTEROP_HANDLER_ADDR).unbundleBundle(proof.chainId, bundle, callStatuses1); + // Check storage changes after first unbundle + assertEq( + uint256(InteropHandler(L2_INTEROP_HANDLER_ADDR).callStatus(bundleHash, 0)), + 0, + "Call 0 should be Unprocessed" + ); + assertEq( + uint256(InteropHandler(L2_INTEROP_HANDLER_ADDR).callStatus(bundleHash, 1)), + 2, + "Call 1 should be Cancelled" + ); + assertEq( + uint256(InteropHandler(L2_INTEROP_HANDLER_ADDR).callStatus(bundleHash, 2)), + 1, + "Call 2 should be Executed" + ); + assertEq( + uint256(InteropHandler(L2_INTEROP_HANDLER_ADDR).bundleStatus(bundleHash)), + 3, + "BundleStatus should be Unbundled" + ); + // Expect events for second unbundle + vm.expectEmit(true, false, false, false); + emit IInteropHandler.CallProcessed(bundleHash, 0, CallStatus.Executed); + vm.expectEmit(true, false, false, false); + emit IInteropHandler.BundleUnbundled(bundleHash); + vm.prank(UNBUNDLER_ADDRESS); + IInteropHandler(L2_INTEROP_HANDLER_ADDR).unbundleBundle(proof.chainId, bundle, callStatuses2); + // Check storage changes after second unbundle + assertEq( + uint256(InteropHandler(L2_INTEROP_HANDLER_ADDR).callStatus(bundleHash, 0)), + 1, + "Call 0 should be Executed" + ); + assertEq( + uint256(InteropHandler(L2_INTEROP_HANDLER_ADDR).callStatus(bundleHash, 1)), + 2, + "Call 1 should be Cancelled" + ); + assertEq( + uint256(InteropHandler(L2_INTEROP_HANDLER_ADDR).callStatus(bundleHash, 2)), + 1, + "Call 2 should be Executed" + ); + assertEq( + uint256(InteropHandler(L2_INTEROP_HANDLER_ADDR).bundleStatus(bundleHash)), + 3, + "BundleStatus should be Unbundled" + ); + } + + function getInteropBundle(uint256 amount) public returns (InteropBundle memory) { + address depositor = makeAddr("someDepositor"); + address receiver = makeAddr("someReceiver"); + address token = makeAddr("someToken"); + InteropCall[] memory calls = new InteropCall[](3); + bytes32 assetId = DataEncoding.encodeNTVAssetId(L1_CHAIN_ID, token); + calls[0] = InteropCall({ + version: INTEROP_CALL_VERSION, + shadowAccount: false, + to: L2_ASSET_ROUTER_ADDR, + from: L2_ASSET_ROUTER_ADDR, + value: 0, + data: abi.encodeCall( + AssetRouterBase.finalizeDeposit, + ( + L1_CHAIN_ID, + assetId, + DataEncoding.encodeBridgeMintData( + depositor, + receiver, + token, + amount, + encodeTokenData(TOKEN_DEFAULT_NAME, TOKEN_DEFAULT_SYMBOL, TOKEN_DEFAULT_DECIMALS) + ) + ) + ) + }); + calls[1] = InteropCall({ + version: INTEROP_CALL_VERSION, + shadowAccount: false, + to: L2_ASSET_ROUTER_ADDR, + from: L2_ASSET_ROUTER_ADDR, + value: 0, + data: abi.encodeCall( + AssetRouterBase.finalizeDeposit, + ( + L1_CHAIN_ID, + assetId, + DataEncoding.encodeBridgeMintData( + depositor, + receiver, + token, + amount, + encodeTokenData(TOKEN_DEFAULT_NAME, TOKEN_DEFAULT_SYMBOL, TOKEN_DEFAULT_DECIMALS) + ) + ) + ) + }); + calls[2] = InteropCall({ + version: INTEROP_CALL_VERSION, + shadowAccount: false, + to: L2_ASSET_ROUTER_ADDR, + from: L2_ASSET_ROUTER_ADDR, + value: 0, + data: abi.encodeCall( + AssetRouterBase.finalizeDeposit, + ( + L1_CHAIN_ID, + assetId, + DataEncoding.encodeBridgeMintData( + depositor, + receiver, + token, + amount, + encodeTokenData(TOKEN_DEFAULT_NAME, TOKEN_DEFAULT_SYMBOL, TOKEN_DEFAULT_DECIMALS) + ) + ) + ) + }); + InteropBundle memory interopBundle = InteropBundle({ + version: INTEROP_BUNDLE_VERSION, + sourceChainId: ERA_CHAIN_ID, + destinationChainId: 31337, + interopBundleSalt: keccak256(abi.encodePacked(depositor, bytes32(0))), + calls: calls, + bundleAttributes: BundleAttributes({ + executionAddress: InteroperableAddress.formatEvmV1(EXECUTION_ADDRESS), + unbundlerAddress: InteroperableAddress.formatEvmV1(UNBUNDLER_ADDRESS) + }) + }); + return interopBundle; + } + + /// @notice Regression test to ensure bundles can only be verified from InteropCenter + /// @dev This test verifies that the fix for unauthorized bundle verification is working + function test_verifyBundle_revertWhen_messageNotFromInteropCenter() public { + address nonInteropCenter = makeAddr("nonInteropCenter"); + + InteropBundle memory interopBundle = getInteropBundle(1); + bytes memory bundle = abi.encode(interopBundle); + + MessageInclusionProof memory proof = getInclusionProof(nonInteropCenter); + + vm.mockCall( + address(L2_MESSAGE_VERIFICATION), + abi.encodeWithSelector(L2_MESSAGE_VERIFICATION.proveL2MessageInclusionShared.selector), + abi.encode(true) + ); + + vm.expectRevert( + abi.encodeWithSelector(UnauthorizedMessageSender.selector, L2_INTEROP_CENTER_ADDR, nonInteropCenter) + ); + + IInteropHandler(L2_INTEROP_HANDLER_ADDR).verifyBundle(bundle, proof); + } + + /// @notice Regression test to ensure bundles can only be executed on the correct destination chain + /// @dev This test verifies that the fix for destination chain ID validation is working + function test_verifyBundle_revertWhen_wrongDestinationChainId() public { + InteropBundle memory interopBundle = getInteropBundle(1); + uint256 wrongChainId = 12345; + interopBundle.destinationChainId = wrongChainId; + + bytes memory bundle = abi.encode(interopBundle); + MessageInclusionProof memory proof = getInclusionProof(L2_INTEROP_CENTER_ADDR); + + vm.mockCall( + address(L2_MESSAGE_VERIFICATION), + abi.encodeWithSelector(L2_MESSAGE_VERIFICATION.proveL2MessageInclusionShared.selector), + abi.encode(true) + ); + + bytes32 bundleHash = InteropDataEncoding.encodeInteropBundleHash(proof.chainId, bundle); + + vm.expectRevert( + abi.encodeWithSelector(WrongDestinationChainId.selector, bundleHash, wrongChainId, block.chainid) + ); + + IInteropHandler(L2_INTEROP_HANDLER_ADDR).verifyBundle(bundle, proof); + } + + /// @notice Test pause functionality in InteropCenter + function test_interopCenter_pause() public { + address interopCenterOwner = InteropCenter(L2_INTEROP_CENTER_ADDR).owner(); + + vm.prank(interopCenterOwner); + InteropCenter(L2_INTEROP_CENTER_ADDR).pause(); + + assertTrue(InteropCenter(L2_INTEROP_CENTER_ADDR).paused(), "InteropCenter should be paused"); + + bytes memory recipient = abi.encodePacked(uint256(271), address(0x123)); + bytes memory payload = abi.encode("test"); + bytes[] memory attributes = new bytes[](0); + + vm.expectRevert("Pausable: paused"); + InteropCenter(L2_INTEROP_CENTER_ADDR).sendMessage(recipient, payload, attributes); + } + + /// @notice Test unpause functionality in InteropCenter + function test_interopCenter_unpause() public { + address interopCenterOwner = InteropCenter(L2_INTEROP_CENTER_ADDR).owner(); + + vm.prank(interopCenterOwner); + InteropCenter(L2_INTEROP_CENTER_ADDR).pause(); + assertTrue(InteropCenter(L2_INTEROP_CENTER_ADDR).paused(), "InteropCenter should be paused"); + + vm.prank(interopCenterOwner); + InteropCenter(L2_INTEROP_CENTER_ADDR).unpause(); + + assertFalse(InteropCenter(L2_INTEROP_CENTER_ADDR).paused(), "InteropCenter should be unpaused"); + } + + /// @notice Test that only owner can pause InteropCenter + function test_interopCenter_pause_onlyOwner() public { + address nonOwner = makeAddr("nonOwner"); + + vm.prank(nonOwner); + vm.expectRevert("Ownable: caller is not the owner"); + InteropCenter(L2_INTEROP_CENTER_ADDR).pause(); + } + + /// @notice Test that only owner can unpause InteropCenter + function test_interopCenter_unpause_onlyOwner() public { + address interopCenterOwner = InteropCenter(L2_INTEROP_CENTER_ADDR).owner(); + vm.prank(interopCenterOwner); + InteropCenter(L2_INTEROP_CENTER_ADDR).pause(); + + address nonOwner = makeAddr("nonOwner"); + vm.prank(nonOwner); + vm.expectRevert("Ownable: caller is not the owner"); + InteropCenter(L2_INTEROP_CENTER_ADDR).unpause(); + } +} diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2NativeTokenVaultTestAbstract.t.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2NativeTokenVaultTestAbstract.t.sol index dbd2b3b12c..6503ae1a8d 100644 --- a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2NativeTokenVaultTestAbstract.t.sol +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2NativeTokenVaultTestAbstract.t.sol @@ -7,8 +7,11 @@ pragma solidity ^0.8.20; import {StdStorage, Test, stdStorage} from "forge-std/Test.sol"; import "forge-std/console.sol"; +import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; + // import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol"; // import {L2AssetRouter} from "contracts/bridge/asset-router/L2AssetRouter.sol"; +import {L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {L2NativeTokenVault} from "contracts/bridge/ntv/L2NativeTokenVault.sol"; import {INativeTokenVaultBase} from "contracts/bridge/ntv/INativeTokenVaultBase.sol"; import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; @@ -27,13 +30,11 @@ import {IL1Nullifier} from "contracts/bridge/interfaces/IL1Nullifier.sol"; import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; import {SharedL2ContractDeployer} from "./_SharedL2ContractDeployer.sol"; -import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; -import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol"; - import {BridgeMintNotImplemented, TokenIsLegacy, TokenNotLegacy, Unauthorized} from "contracts/common/L1ContractErrors.sol"; import {IL2SharedBridgeLegacy} from "contracts/bridge/interfaces/IL2SharedBridgeLegacy.sol"; import {IAssetHandler} from "contracts/bridge/interfaces/IAssetHandler.sol"; +import {L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; abstract contract L2NativeTokenVaultTestAbstract is Test, SharedL2ContractDeployer { using stdStorage for StdStorage; @@ -46,13 +47,13 @@ abstract contract L2NativeTokenVaultTestAbstract is Test, SharedL2ContractDeploy abi.encodeCall(IL2SharedBridgeLegacy.l1TokenAddress, (l2Token)), abi.encode(l1Token) ); - L2NativeTokenVault(addresses.vaults.l1NativeTokenVaultProxy).setLegacyTokenAssetId(l2Token); + L2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR).setLegacyTokenAssetId(l2Token); } function test_registerLegacyToken_IncorrectConfiguration() external { address l2Token = makeAddr("l2Token"); address l1Token = makeAddr("l1Token"); - L2NativeTokenVault l2NativeTokenVault = L2NativeTokenVault(addresses.vaults.l1NativeTokenVaultProxy); + L2NativeTokenVault l2NativeTokenVault = L2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR); bytes32 assetId = DataEncoding.encodeNTVAssetId(L1_CHAIN_ID, l1Token); @@ -61,13 +62,13 @@ abstract contract L2NativeTokenVaultTestAbstract is Test, SharedL2ContractDeploy assertEq(l2NativeTokenVault.assetId(l2Token), bytes32(0)); stdstore - .target(address(addresses.vaults.l1NativeTokenVaultProxy)) + .target(address(L2_NATIVE_TOKEN_VAULT_ADDR)) .sig(INativeTokenVaultBase.tokenAddress.selector) .with_key(assetId) .checked_write(l2Token); stdstore - .target(address(addresses.vaults.l1NativeTokenVaultProxy)) + .target(address(L2_NATIVE_TOKEN_VAULT_ADDR)) .sig(INativeTokenVaultBase.assetId.selector) .with_key(l2Token) .checked_write(assetId); @@ -80,7 +81,7 @@ abstract contract L2NativeTokenVaultTestAbstract is Test, SharedL2ContractDeploy abi.encodeCall(IL2SharedBridgeLegacy.l1TokenAddress, (l2Token)), abi.encode(l1Token) ); - L2NativeTokenVault(addresses.vaults.l1NativeTokenVaultProxy).setLegacyTokenAssetId(l2Token); + L2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR).setLegacyTokenAssetId(l2Token); assertNotEq(l2NativeTokenVault.originChainId(assetId), 0); assertNotEq(l2NativeTokenVault.tokenAddress(assetId), address(0)); @@ -90,7 +91,7 @@ abstract contract L2NativeTokenVaultTestAbstract is Test, SharedL2ContractDeploy function test_registerLegacyTokenRevertNotLegacy() external { address l2Token = makeAddr("l2Token"); vm.expectRevert(TokenNotLegacy.selector); - L2NativeTokenVault(addresses.vaults.l1NativeTokenVaultProxy).setLegacyTokenAssetId(l2Token); + L2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR).setLegacyTokenAssetId(l2Token); } function test_registerTokenRevertIsLegacy() external { @@ -103,11 +104,11 @@ abstract contract L2NativeTokenVaultTestAbstract is Test, SharedL2ContractDeploy ); vm.expectRevert(TokenIsLegacy.selector); - INativeTokenVaultBase(addresses.vaults.l1NativeTokenVaultProxy).registerToken(l2Token); + INativeTokenVaultBase(L2_NATIVE_TOKEN_VAULT_ADDR).registerToken(l2Token); } function test_bridgeMint_CorrectlyConfiguresL2LegacyToken() external { - L2NativeTokenVault l2NativeTokenVault = L2NativeTokenVault(addresses.vaults.l1NativeTokenVaultProxy); + L2NativeTokenVault l2NativeTokenVault = L2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR); uint256 originChainId = L1_CHAIN_ID; address originToken = makeAddr("l1Token"); @@ -141,6 +142,7 @@ abstract contract L2NativeTokenVaultTestAbstract is Test, SharedL2ContractDeploy // fails on the following line without this `mockCall` // https://github.com/matter-labs/era-contracts/blob/cebfe26a41f3b83039a7d36558bf4e0401b154fc/l1-contracts/contracts/bridge/ntv/NativeTokenVault.sol#L163 vm.mockCall(expectedL2TokenAddress, abi.encodeCall(IBridgedStandardToken.bridgeMint, (receiver, amount)), ""); + vm.mockCall(expectedL2TokenAddress, abi.encodeCall(IERC20.totalSupply, ()), abi.encode(amount)); vm.prank(L2_ASSET_ROUTER_ADDR); IAssetHandler(address(l2NativeTokenVault)).bridgeMint(originChainId, assetId, data); diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2WethTestAbstract.t.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2WethTestAbstract.t.sol index 914ca658bd..8b9ea698df 100644 --- a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2WethTestAbstract.t.sol +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/L2WethTestAbstract.t.sol @@ -18,6 +18,9 @@ import {IL1Nullifier} from "contracts/bridge/interfaces/IL1Nullifier.sol"; import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; import {SharedL2ContractDeployer} from "./_SharedL2ContractDeployer.sol"; +import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; +import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol"; +import {SystemContractsArgs} from "./Utils.sol"; abstract contract L2WethTestAbstract is Test, SharedL2ContractDeployer { function test_shouldDepositWethByCallingDeposit() public { diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/Utils.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/Utils.sol index 77e5f51ab4..ed44a8239a 100644 --- a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/Utils.sol +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/Utils.sol @@ -4,8 +4,13 @@ pragma solidity ^0.8.24; // solhint-disable gas-custom-errors +address constant L2_INTEROP_ACCOUNT_ADDR = address(0x0000000000000000000000000000000000010010); +address constant L2_STANDARD_TRIGGER_ACCOUNT_ADDR = address(0x0000000000000000000000000000000000010011); + struct SystemContractsArgs { + bool broadcast; uint256 l1ChainId; + uint256 gatewayChainId; uint256 eraChainId; address l1AssetRouter; address legacySharedBridge; diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/_SharedL2ContractDeployer.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/_SharedL2ContractDeployer.sol index 0af25de522..71b799ce4e 100644 --- a/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/_SharedL2ContractDeployer.sol +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-abstract/_SharedL2ContractDeployer.sol @@ -14,30 +14,37 @@ import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol"; import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol"; import {BeaconProxy} from "@openzeppelin/contracts-v4/proxy/beacon/BeaconProxy.sol"; -import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {IL2NativeTokenVault} from "../../../../../contracts/bridge/ntv/IL2NativeTokenVault.sol"; +import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR, L2_INTEROP_CENTER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "contracts/common/Config.sol"; import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol"; import {IL2Bridgehub} from "contracts/bridgehub/IL2Bridgehub.sol"; -import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; - -import {IL2AssetRouter} from "contracts/bridge/asset-router/IL2AssetRouter.sol"; -import {IL1Nullifier} from "contracts/bridge/interfaces/IL1Nullifier.sol"; -import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; -import {L2WrappedBaseToken} from "contracts/bridge/L2WrappedBaseToken.sol"; -import {L2SharedBridgeLegacy} from "contracts/bridge/L2SharedBridgeLegacy.sol"; -import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; -import {MailboxFacet} from "contracts/state-transition/chain-deps/facets/Mailbox.sol"; -import {AdminFacet} from "contracts/state-transition/chain-deps/facets/Admin.sol"; -import {BridgehubL2TransactionRequest} from "contracts/common/Messaging.sol"; +import {BridgehubMintCTMAssetData, IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; + +import {IL2AssetRouter} from "../../../../../contracts/bridge/asset-router/IL2AssetRouter.sol"; +import {IL1Nullifier} from "../../../../../contracts/bridge/interfaces/IL1Nullifier.sol"; +import {IL1AssetRouter} from "../../../../../contracts/bridge/asset-router/IL1AssetRouter.sol"; + +import {BridgehubL2TransactionRequest} from "../../../../../contracts/common/Messaging.sol"; +import {IInteropCenter, InteropCenter} from "../../../../../contracts/interop/InteropCenter.sol"; +import {L2WrappedBaseToken} from "../../../../../contracts/bridge/L2WrappedBaseToken.sol"; +import {L2SharedBridgeLegacy} from "../../../../../contracts/bridge/L2SharedBridgeLegacy.sol"; +import {MailboxFacet} from "../../../../../contracts/state-transition/chain-deps/facets/Mailbox.sol"; +import {AdminFacet} from "../../../../../contracts/state-transition/chain-deps/facets/Admin.sol"; +import {DataEncoding} from "../../../../../contracts/common/libraries/DataEncoding.sol"; import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol"; +import {ZKChainBase} from "contracts/state-transition/chain-deps/facets/ZKChainBase.sol"; import {SystemContractsArgs} from "./Utils.sol"; import {DeployIntegrationUtils} from "../deploy-scripts/DeployIntegrationUtils.s.sol"; +import {UtilsCallMockerTest} from "foundry-test/l1/unit/concrete/Utils/Utils.t.sol"; +import {AssetRouterBase} from "contracts/bridge/asset-router/AssetRouterBase.sol"; -abstract contract SharedL2ContractDeployer is Test, DeployIntegrationUtils { +abstract contract SharedL2ContractDeployer is UtilsCallMockerTest, DeployIntegrationUtils { L2WrappedBaseToken internal weth; address internal l1WethAddress = address(4); @@ -51,9 +58,12 @@ abstract contract SharedL2ContractDeployer is Test, DeployIntegrationUtils { IL2AssetRouter l2AssetRouter = IL2AssetRouter(L2_ASSET_ROUTER_ADDR); IL2Bridgehub l2Bridgehub = IL2Bridgehub(L2_BRIDGEHUB_ADDR); + IInteropCenter l2InteropCenter = IInteropCenter(L2_INTEROP_CENTER_ADDR); + IL2NativeTokenVault l2NativeTokenVault = IL2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR); uint256 internal constant L1_CHAIN_ID = 10; // it cannot be 9, the default block.chainid uint256 internal ERA_CHAIN_ID = 270; + uint256 internal GATEWAY_CHAIN_ID = 506; uint256 internal mintChainId = 300; address internal l1AssetRouter = makeAddr("l1AssetRouter"); address internal aliasedL1AssetRouter = AddressAliasHelper.applyL1ToL2Alias(l1AssetRouter); @@ -68,8 +78,7 @@ abstract contract SharedL2ContractDeployer is Test, DeployIntegrationUtils { address internal l1CTM = makeAddr("l1CTM"); bytes32 internal ctmAssetId = keccak256(abi.encode(L1_CHAIN_ID, l1CTMDeployer, bytes32(uint256(uint160(l1CTM))))); - bytes32 internal baseTokenAssetId = - keccak256(abi.encode(L1_CHAIN_ID, L2_NATIVE_TOKEN_VAULT_ADDR, abi.encode(ETH_TOKEN_ADDRESS))); + bytes32 internal baseTokenAssetId = DataEncoding.encodeNTVAssetId(L1_CHAIN_ID, ETH_TOKEN_ADDRESS); bytes internal exampleChainCommitment; @@ -78,9 +87,19 @@ abstract contract SharedL2ContractDeployer is Test, DeployIntegrationUtils { IChainTypeManager internal chainTypeManager; function setUp() public virtual { + setUpInner(false); + } + + function setUpInner(bool _skip) public virtual { + // Timestamp needs to be big enough for `pauseDepositsBeforeInitiatingMigration` time checks + vm.warp(PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + 1); + + if (_skip) { + vm.startBroadcast(); + } standardErc20Impl = new BridgedStandardERC20(); beacon = new UpgradeableBeacon(address(standardErc20Impl)); - beacon.transferOwnership(ownerWallet); + // beacon.transferOwnership(ownerWallet); // One of the purposes of deploying it here is to publish its bytecode BeaconProxy beaconProxy = new BeaconProxy(address(beacon), new bytes(0)); @@ -90,6 +109,7 @@ abstract contract SharedL2ContractDeployer is Test, DeployIntegrationUtils { beaconProxyBytecodeHash := extcodehash(beaconProxy) } + discoveredBridgehub.bridgehubProxy = L2_BRIDGEHUB_ADDR; sharedBridgeLegacy = deployL2SharedBridgeLegacy( L1_CHAIN_ID, ERA_CHAIN_ID, @@ -99,11 +119,15 @@ abstract contract SharedL2ContractDeployer is Test, DeployIntegrationUtils { ); L2WrappedBaseToken weth = deployL2Weth(); - + if (_skip) { + vm.stopBroadcast(); + } initSystemContracts( SystemContractsArgs({ + broadcast: _skip, l1ChainId: L1_CHAIN_ID, eraChainId: ERA_CHAIN_ID, + gatewayChainId: GATEWAY_CHAIN_ID, l1AssetRouter: l1AssetRouter, legacySharedBridge: sharedBridgeLegacy, l2TokenBeacon: address(beacon), @@ -114,19 +138,21 @@ abstract contract SharedL2ContractDeployer is Test, DeployIntegrationUtils { maxNumberOfZKChains: 100 }) ); - deployL2Contracts(L1_CHAIN_ID); - - vm.prank(aliasedL1AssetRouter); - l2AssetRouter.setAssetHandlerAddress(L1_CHAIN_ID, ctmAssetId, L2_CHAIN_ASSET_HANDLER_ADDR); - vm.prank(ownerWallet); - l2Bridgehub.addChainTypeManager(address(addresses.stateTransition.chainTypeManagerProxy)); - vm.prank(AddressAliasHelper.applyL1ToL2Alias(l1CTMDeployer)); - l2Bridgehub.setCTMAssetAddress( - bytes32(uint256(uint160(l1CTM))), - address(addresses.stateTransition.chainTypeManagerProxy) - ); - chainTypeManager = IChainTypeManager(address(addresses.stateTransition.chainTypeManagerProxy)); - getExampleChainCommitment(); + if (!_skip) { + deployL2Contracts(L1_CHAIN_ID); + + vm.prank(aliasedL1AssetRouter); + l2AssetRouter.setAssetHandlerAddress(L1_CHAIN_ID, ctmAssetId, L2_CHAIN_ASSET_HANDLER_ADDR); + vm.prank(ownerWallet); + l2Bridgehub.addChainTypeManager(address(addresses.stateTransition.chainTypeManagerProxy)); + vm.prank(AddressAliasHelper.applyL1ToL2Alias(l1CTMDeployer)); + l2Bridgehub.setCTMAssetAddress( + bytes32(uint256(uint160(l1CTM))), + address(addresses.stateTransition.chainTypeManagerProxy) + ); + chainTypeManager = IChainTypeManager(address(addresses.stateTransition.chainTypeManagerProxy)); + getExampleChainCommitment(); + } } function getExampleChainCommitment() internal returns (bytes memory) { @@ -147,8 +173,15 @@ abstract contract SharedL2ContractDeployer is Test, DeployIntegrationUtils { abi.encodeWithSelector(IBridgehubBase.baseToken.selector, ERA_CHAIN_ID + 1), abi.encode(address(uint160(1))) ); - + vm.mockCall( + address(L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT), + abi.encodeWithSelector(L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT.currentSettlementLayerChainId.selector), + abi.encode(block.chainid) + ); vm.prank(L2_BRIDGEHUB_ADDR); + mockDiamondInitInteropCenterCallsWithAddress(L2_BRIDGEHUB_ADDR, L2_ASSET_ROUTER_ADDR, baseTokenAssetId); + uint256 currentChainId = block.chainid; + vm.chainId(L1_CHAIN_ID); address chainAddress = chainTypeManager.createNewChain( ERA_CHAIN_ID + 1, baseTokenAssetId, @@ -156,8 +189,7 @@ abstract contract SharedL2ContractDeployer is Test, DeployIntegrationUtils { abi.encode(config.contracts.diamondCutData, generatedData.forceDeploymentsData), new bytes[](0) ); - - uint256 currentChainId = block.chainid; + vm.chainId(currentChainId); // This function is available only on L1 (and it is correct), // but inside testing we need to call this function to recreate commitment @@ -239,8 +271,41 @@ abstract contract SharedL2ContractDeployer is Test, DeployIntegrationUtils { return weth; } + function finalizeDeposit() public { + finalizeDepositWithCustomCommitment(exampleChainCommitment); + } + + function finalizeDepositWithChainId(uint256 _chainId) public { + finalizeDepositWithCustomCommitmentAndChainId(_chainId, exampleChainCommitment); + } + + function finalizeDepositWithCustomCommitment(bytes memory chainCommitment) public { + finalizeDepositWithCustomCommitmentAndChainId(mintChainId, chainCommitment); + } + + function finalizeDepositWithCustomCommitmentAndChainId(uint256 _chainId, bytes memory chainCommitment) public { + bytes memory chainData = chainCommitment; + bytes memory ctmData = abi.encode( + baseTokenAssetId, + ownerWallet, + chainTypeManager.protocolVersion(), + config.contracts.diamondCutData + ); + BridgehubMintCTMAssetData memory data = BridgehubMintCTMAssetData({ + chainId: _chainId, + baseTokenAssetId: baseTokenAssetId, + batchNumber: 0, + ctmData: ctmData, + chainData: chainData, + migrationNumber: 0, + v30UpgradeChainBatchNumber: 0 + }); + vm.prank(aliasedL1AssetRouter); + AssetRouterBase(address(l2AssetRouter)).finalizeDeposit(L1_CHAIN_ID, ctmAssetId, abi.encode(data)); + } + function initSystemContracts(SystemContractsArgs memory _args) internal virtual; function deployL2Contracts(uint256 _l1ChainId) public virtual; - function test() internal virtual override {} + function test() internal virtual override(DeployIntegrationUtils, UtilsCallMockerTest) {} } diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2AssetTrackerL1Test.t.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2AssetTrackerL1Test.t.sol new file mode 100644 index 0000000000..6ed3a0cbbd --- /dev/null +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2AssetTrackerL1Test.t.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +// solhint-disable gas-custom-errors + +import {Test} from "forge-std/Test.sol"; +import "forge-std/console.sol"; + +import {SharedL2ContractDeployer} from "../l2-tests-abstract/_SharedL2ContractDeployer.sol"; + +import {SharedL2ContractL1Deployer, SystemContractsArgs} from "./_SharedL2ContractL1Deployer.sol"; +import {L2AssetTrackerTest} from "../l2-tests-abstract/L2AssetTracker.t.sol"; + +import {StateTransitionDeployedAddresses} from "deploy-scripts/Types.sol"; +import {DeployIntegrationUtils} from "../deploy-scripts/DeployIntegrationUtils.s.sol"; +import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; + +contract L2AssetTrackerL1Test is Test, SharedL2ContractL1Deployer, L2AssetTrackerTest { + function test() internal virtual override(SharedL2ContractDeployer, SharedL2ContractL1Deployer) {} + + function initSystemContracts( + SystemContractsArgs memory _args + ) internal virtual override(SharedL2ContractDeployer, SharedL2ContractL1Deployer) { + super.initSystemContracts(_args); + } + + function deployL2Contracts( + uint256 _l1ChainId + ) public virtual override(SharedL2ContractDeployer, SharedL2ContractL1Deployer) { + super.deployL2Contracts(_l1ChainId); + } + + function getChainCreationFacetCuts( + StateTransitionDeployedAddresses memory stateTransition + ) internal override(DeployIntegrationUtils, SharedL2ContractL1Deployer) returns (Diamond.FacetCut[] memory) { + return super.getChainCreationFacetCuts(stateTransition); + } + + function getUpgradeAddedFacetCuts( + StateTransitionDeployedAddresses memory stateTransition + ) internal override(DeployIntegrationUtils, SharedL2ContractL1Deployer) returns (Diamond.FacetCut[] memory) { + return super.getUpgradeAddedFacetCuts(stateTransition); + } + function getInitializeCalldata( + string memory contractName, + bool isZKBytecode + ) internal virtual override(DeployIntegrationUtils, SharedL2ContractL1Deployer) returns (bytes memory) { + return super.getInitializeCalldata(contractName, isZKBytecode); + } +} diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2Erc20L1Test.t.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2Erc20L1Test.t.sol index 7b4ddacdd1..1223b0d83c 100644 --- a/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2Erc20L1Test.t.sol +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2Erc20L1Test.t.sol @@ -27,10 +27,9 @@ import {SharedL2ContractDeployer} from "../l2-tests-abstract/_SharedL2ContractDe import {SharedL2ContractL1Deployer, SystemContractsArgs} from "./_SharedL2ContractL1Deployer.sol"; -import {DeployUtils} from "deploy-scripts/DeployUtils.s.sol"; import {L2Erc20TestAbstract} from "../l2-tests-abstract/L2Erc20TestAbstract.t.sol"; -import {StateTransitionDeployedAddresses} from "deploy-scripts/Utils.sol"; +import {StateTransitionDeployedAddresses} from "deploy-scripts/Types.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {DeployIntegrationUtils} from "../deploy-scripts/DeployIntegrationUtils.s.sol"; @@ -64,8 +63,8 @@ contract L2Erc20L1Test is Test, SharedL2ContractL1Deployer, L2Erc20TestAbstract function getCreationCode( string memory contractName, bool isZKBytecode - ) internal view virtual override(DeployUtils, SharedL2ContractL1Deployer) returns (bytes memory) { - return super.getCreationCode(contractName, false); + ) internal view virtual override returns (bytes memory) { + return super.getCreationCode(contractName, isZKBytecode); } function getInitializeCalldata( diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2GatewayL1Test.t.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2GatewayL1Test.t.sol index 5f47370383..8cd3e8c5b5 100644 --- a/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2GatewayL1Test.t.sol +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2GatewayL1Test.t.sol @@ -25,12 +25,12 @@ import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; import {SharedL2ContractDeployer} from "../l2-tests-abstract/_SharedL2ContractDeployer.sol"; +import {L2GatewayTestAbstract} from "../l2-tests-abstract/L2GatewayTestAbstract.t.sol"; import {SharedL2ContractL1Deployer, SystemContractsArgs} from "./_SharedL2ContractL1Deployer.sol"; -import {DeployUtils} from "deploy-scripts/DeployUtils.s.sol"; import {L2GatewayTestAbstract} from "../l2-tests-abstract/L2GatewayTestAbstract.t.sol"; -import {StateTransitionDeployedAddresses} from "deploy-scripts/Utils.sol"; +import {StateTransitionDeployedAddresses} from "deploy-scripts/Types.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {DeployIntegrationUtils} from "../deploy-scripts/DeployIntegrationUtils.s.sol"; @@ -60,14 +60,6 @@ contract L2GatewayL1Test is Test, SharedL2ContractL1Deployer, L2GatewayTestAbstr ) internal override(DeployIntegrationUtils, SharedL2ContractL1Deployer) returns (Diamond.FacetCut[] memory) { return super.getUpgradeAddedFacetCuts(stateTransition); } - - function getCreationCode( - string memory contractName, - bool isZKBytecode - ) internal view virtual override(DeployUtils, SharedL2ContractL1Deployer) returns (bytes memory) { - return super.getCreationCode(contractName, false); - } - function getInitializeCalldata( string memory contractName, bool isZKBytecode diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2InteropL1Test.t.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2InteropL1Test.t.sol new file mode 100644 index 0000000000..4798166f62 --- /dev/null +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2InteropL1Test.t.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +// solhint-disable gas-custom-errors + +import {Test} from "forge-std/Test.sol"; +import "forge-std/console.sol"; + +import {SharedL2ContractDeployer} from "../l2-tests-abstract/_SharedL2ContractDeployer.sol"; +import {L2InteropTestAbstract} from "../l2-tests-abstract/L2InteropTestAbstract.t.sol"; + +import {SharedL2ContractL1Deployer, SystemContractsArgs} from "./_SharedL2ContractL1Deployer.sol"; +import {StateTransitionDeployedAddresses} from "deploy-scripts/Types.sol"; +import {DeployIntegrationUtils} from "../deploy-scripts/DeployIntegrationUtils.s.sol"; +import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; + +contract L2InteropL1Test is Test, SharedL2ContractL1Deployer, L2InteropTestAbstract { + function test() internal virtual override(SharedL2ContractDeployer, SharedL2ContractL1Deployer) {} + + function initSystemContracts( + SystemContractsArgs memory _args + ) internal virtual override(SharedL2ContractDeployer, SharedL2ContractL1Deployer) { + super.initSystemContracts(_args); + } + + function deployL2Contracts( + uint256 _l1ChainId + ) public virtual override(SharedL2ContractDeployer, SharedL2ContractL1Deployer) { + super.deployL2Contracts(_l1ChainId); + } + + function getChainCreationFacetCuts( + StateTransitionDeployedAddresses memory stateTransition + ) internal override(DeployIntegrationUtils, SharedL2ContractL1Deployer) returns (Diamond.FacetCut[] memory) { + return super.getChainCreationFacetCuts(stateTransition); + } + + function getUpgradeAddedFacetCuts( + StateTransitionDeployedAddresses memory stateTransition + ) internal override(DeployIntegrationUtils, SharedL2ContractL1Deployer) returns (Diamond.FacetCut[] memory) { + return super.getUpgradeAddedFacetCuts(stateTransition); + } + + function getInitializeCalldata( + string memory contractName, + bool isZKBytecode + ) internal virtual override(DeployIntegrationUtils, SharedL2ContractL1Deployer) returns (bytes memory) { + return super.getInitializeCalldata(contractName, isZKBytecode); + } +} diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2NativeTokenVaultL1Test.t.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2NativeTokenVaultL1Test.t.sol index d31ddc9b3a..2624e8aced 100644 --- a/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2NativeTokenVaultL1Test.t.sol +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2NativeTokenVaultL1Test.t.sol @@ -27,12 +27,12 @@ import {SharedL2ContractDeployer} from "../l2-tests-abstract/_SharedL2ContractDe import {SharedL2ContractL1Deployer, SystemContractsArgs} from "./_SharedL2ContractL1Deployer.sol"; -import {DeployUtils} from "deploy-scripts/DeployUtils.s.sol"; import {L2NativeTokenVaultTestAbstract} from "../l2-tests-abstract/L2NativeTokenVaultTestAbstract.t.sol"; -import {StateTransitionDeployedAddresses} from "deploy-scripts/Utils.sol"; +import {StateTransitionDeployedAddresses} from "deploy-scripts/Types.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {DeployIntegrationUtils} from "../deploy-scripts/DeployIntegrationUtils.s.sol"; +import {DeployCTMUtils} from "deploy-scripts/DeployCTMUtils.s.sol"; contract L2NativeTokenVaultL1Test is Test, SharedL2ContractL1Deployer, L2NativeTokenVaultTestAbstract { function test() internal virtual override(SharedL2ContractDeployer, SharedL2ContractL1Deployer) {} @@ -61,13 +61,6 @@ contract L2NativeTokenVaultL1Test is Test, SharedL2ContractL1Deployer, L2NativeT return super.getUpgradeAddedFacetCuts(stateTransition); } - function getCreationCode( - string memory contractName, - bool isZKBytecode - ) internal view virtual override(DeployUtils, SharedL2ContractL1Deployer) returns (bytes memory) { - return super.getCreationCode(contractName, isZKBytecode); - } - function getInitializeCalldata( string memory contractName, bool isZKBytecode diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2UtilsBase.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2UtilsBase.sol index db1a3b4f71..ed30c5192a 100644 --- a/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2UtilsBase.sol +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/L2UtilsBase.sol @@ -1,17 +1,21 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.28; +pragma solidity ^0.8.20; import {Vm} from "forge-std/Vm.sol"; import {StdStorage, stdStorage, stdToml} from "forge-std/Test.sol"; import {console2 as console} from "forge-std/Script.sol"; +import {L2AssetTracker} from "contracts/bridge/asset-tracker/L2AssetTracker.sol"; +import {GWAssetTracker} from "contracts/bridge/asset-tracker/GWAssetTracker.sol"; import {L2Bridgehub} from "contracts/bridgehub/L2Bridgehub.sol"; import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; import {CTMDeploymentTracker} from "contracts/bridgehub/CTMDeploymentTracker.sol"; +import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; -import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR, L2_INTEROP_ROOT_STORAGE, L2_MESSAGE_ROOT_ADDR, L2_MESSAGE_VERIFICATION, L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {GW_ASSET_TRACKER_ADDR, L2_ASSET_ROUTER_ADDR, L2_ASSET_TRACKER_ADDR, L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR, L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR, L2_COMPLEX_UPGRADER_ADDR, L2_INTEROP_CENTER_ADDR, L2_INTEROP_HANDLER_ADDR, L2_INTEROP_ROOT_STORAGE, L2_MESSAGE_ROOT_ADDR, L2_MESSAGE_VERIFICATION, L2_NATIVE_TOKEN_VAULT_ADDR, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {L2_INTEROP_ACCOUNT_ADDR, L2_STANDARD_TRIGGER_ACCOUNT_ADDR} from "../l2-tests-abstract/Utils.sol"; import {L2MessageRoot} from "contracts/bridgehub/L2MessageRoot.sol"; import {L2AssetRouter} from "contracts/bridge/asset-router/L2AssetRouter.sol"; @@ -23,14 +27,18 @@ import {L2NativeTokenVaultDev} from "contracts/dev-contracts/test/L2NativeTokenV import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; import {ICTMDeploymentTracker} from "contracts/bridgehub/ICTMDeploymentTracker.sol"; -import {L2MessageVerification} from "../../../../../contracts/bridgehub/L2MessageVerification.sol"; +import {L2MessageVerification} from "../../../../../contracts/interop/L2MessageVerification.sol"; import {DummyL2InteropRootStorage} from "../../../../../contracts/dev-contracts/test/DummyL2InteropRootStorage.sol"; -import {DeployCTMIntegrationScript} from "../deploy-scripts/DeployCTMIntegration.s.sol"; +import {InteropCenter} from "../../../../../contracts/interop/InteropCenter.sol"; +import {InteropHandler} from "../../../../../contracts/interop/InteropHandler.sol"; +import {DummyL2L1Messenger} from "../../../../../contracts/dev-contracts/test/DummyL2L1Messenger.sol"; -import {SharedL2ContractDeployer, SystemContractsArgs} from "../l2-tests-abstract/_SharedL2ContractDeployer.sol"; +import {DummyL2StandardTriggerAccount} from "../../../../../contracts/dev-contracts/test/DummyL2StandardTriggerAccount.sol"; +import {DummyL2BaseTokenSystemContract} from "../../../../../contracts/dev-contracts/test/DummyBaseTokenSystemContract.sol"; +import {DummyL2InteropAccount} from "../../../../../contracts/dev-contracts/test/DummyL2InteropAccount.sol"; -import {DeployIntegrationUtils} from "../deploy-scripts/DeployIntegrationUtils.s.sol"; +import {SystemContractsArgs} from "../l2-tests-abstract/_SharedL2ContractDeployer.sol"; import {L2_COMPLEX_UPGRADER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; library L2UtilsBase { @@ -43,32 +51,50 @@ library L2UtilsBase { /// @dev We provide a fast form of debugging the L2 contracts using L1 foundry. We also test using zk foundry. function initSystemContracts(SystemContractsArgs memory _args) internal { - bytes32 baseTokenAssetId = DataEncoding.encodeNTVAssetId(_args.l1ChainId, ETH_TOKEN_ADDRESS); - address wethToken = address(0x1); - // we deploy the code to get the contract code with immutables which we then vm.etch - address messageRoot = address(new L2MessageRoot()); - address bridgehub = address(new L2Bridgehub()); - address assetRouter = address(new L2AssetRouter()); - address ntv = address(new L2NativeTokenVaultDev()); - - vm.etch(L2_MESSAGE_ROOT_ADDR, messageRoot.code); - vm.prank(L2_COMPLEX_UPGRADER_ADDR); - L2MessageRoot(L2_MESSAGE_ROOT_ADDR).initL2(_args.l1ChainId); - - vm.etch(L2_BRIDGEHUB_ADDR, bridgehub.code); - uint256 prevChainId = block.chainid; - vm.chainId(_args.l1ChainId); - - vm.prank(L2_COMPLEX_UPGRADER_ADDR); - L2Bridgehub(L2_BRIDGEHUB_ADDR).initL2(_args.l1ChainId, _args.aliasedOwner, _args.maxNumberOfZKChains); - vm.chainId(prevChainId); - vm.prank(_args.aliasedOwner); - L2Bridgehub(L2_BRIDGEHUB_ADDR).setAddresses( - L2_ASSET_ROUTER_ADDR, - ICTMDeploymentTracker(_args.l1CtmDeployer), - IMessageRoot(L2_MESSAGE_ROOT_ADDR), - L2_CHAIN_ASSET_HANDLER_ADDR - ); + // Variables that will be used across multiple scopes + bytes32 baseTokenAssetId; + address wethToken; + + // Initialize variables in a scoped block to avoid stack too deep + { + baseTokenAssetId = DataEncoding.encodeNTVAssetId(_args.l1ChainId, ETH_TOKEN_ADDRESS); + wethToken = address(0x1); + } + + { + address bridgehub = address(new L2Bridgehub()); + vm.etch(L2_BRIDGEHUB_ADDR, bridgehub.code); + address interopCenter = address(new InteropCenter()); + vm.etch(L2_INTEROP_CENTER_ADDR, interopCenter.code); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + InteropCenter(L2_INTEROP_CENTER_ADDR).initL2(_args.l1ChainId, _args.aliasedOwner); + } + + { + address messageRoot = address(new L2MessageRoot()); + vm.etch(L2_MESSAGE_ROOT_ADDR, messageRoot.code); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + L2MessageRoot(L2_MESSAGE_ROOT_ADDR).initL2(_args.l1ChainId, _args.gatewayChainId); + } + + { + uint256 prevChainId = block.chainid; + vm.chainId(_args.l1ChainId); + + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + L2Bridgehub(L2_BRIDGEHUB_ADDR).initL2(_args.l1ChainId, _args.aliasedOwner, _args.maxNumberOfZKChains); + vm.chainId(prevChainId); + + vm.prank(_args.aliasedOwner); + address aliasedL1ChainRegistrationSender = address(0x000000000000000000000000000000000002000a); + L2Bridgehub(L2_BRIDGEHUB_ADDR).setAddresses( + L2_ASSET_ROUTER_ADDR, + ICTMDeploymentTracker(_args.l1CtmDeployer), + IMessageRoot(L2_MESSAGE_ROOT_ADDR), + L2_CHAIN_ASSET_HANDLER_ADDR, + aliasedL1ChainRegistrationSender + ); + } { address l2messageVerification = address(new L2MessageVerification()); @@ -87,38 +113,86 @@ library L2UtilsBase { L2_MESSAGE_ROOT_ADDR ); } + { + address interopHandler = address(new InteropHandler()); + vm.etch(L2_INTEROP_HANDLER_ADDR, interopHandler.code); + /// storing the reentrancy guard as the constructor is not called. + vm.store( + L2_INTEROP_HANDLER_ADDR, + bytes32(0x8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4), + bytes32(uint256(1)) + ); + address l2AssetTrackerAddress = address(new L2AssetTracker()); + vm.etch(L2_ASSET_TRACKER_ADDR, l2AssetTrackerAddress.code); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + L2AssetTracker(L2_ASSET_TRACKER_ADDR).setAddresses(_args.l1ChainId, bytes32(0)); + + address gwAssetTrackerAddress = address(new GWAssetTracker()); + vm.etch(GW_ASSET_TRACKER_ADDR, gwAssetTrackerAddress.code); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + GWAssetTracker(GW_ASSET_TRACKER_ADDR).setAddresses(_args.l1ChainId); + } + { + address l2StandardTriggerAccount = address(new DummyL2StandardTriggerAccount()); + vm.etch(L2_STANDARD_TRIGGER_ACCOUNT_ADDR, l2StandardTriggerAccount.code); + address l2InteropAccount = address(new DummyL2InteropAccount()); + vm.etch(L2_INTEROP_ACCOUNT_ADDR, l2InteropAccount.code); + } + + { + address l2DummyBaseTokenSystemContract = address(new DummyL2BaseTokenSystemContract()); + vm.etch(L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR, l2DummyBaseTokenSystemContract.code); + } + + // DummyL2L1Messenger dummyL2L1Messenger = new DummyL2L1Messenger(); + // vm.etch(L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, address(dummyL2L1Messenger).code); + { + address assetRouter = address(new L2AssetRouter()); + vm.etch(L2_ASSET_ROUTER_ADDR, assetRouter.code); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + L2AssetRouter(L2_ASSET_ROUTER_ADDR).initL2( + _args.l1ChainId, + _args.eraChainId, + IL1AssetRouter(_args.l1AssetRouter), + IL2SharedBridgeLegacy(_args.legacySharedBridge), + baseTokenAssetId, + _args.aliasedOwner + ); + } - vm.etch(L2_ASSET_ROUTER_ADDR, assetRouter.code); - vm.prank(L2_COMPLEX_UPGRADER_ADDR); - L2AssetRouter(L2_ASSET_ROUTER_ADDR).initL2( - _args.l1ChainId, - _args.eraChainId, - IL1AssetRouter(_args.l1AssetRouter), - IL2SharedBridgeLegacy(_args.legacySharedBridge), - baseTokenAssetId, - _args.aliasedOwner - ); - // Initializing reentrancy guard - vm.store( - L2_ASSET_ROUTER_ADDR, - bytes32(0x8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4), - bytes32(uint256(1)) - ); - - vm.etch(L2_NATIVE_TOKEN_VAULT_ADDR, ntv.code); - - vm.prank(L2_COMPLEX_UPGRADER_ADDR); - L2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR).initL2( - _args.l1ChainId, - _args.aliasedOwner, - _args.l2TokenProxyBytecodeHash, - _args.legacySharedBridge, - _args.l2TokenBeacon, - wethToken, - baseTokenAssetId - ); - - vm.store(L2_NATIVE_TOKEN_VAULT_ADDR, bytes32(uint256(251)), bytes32(uint256(_args.l2TokenProxyBytecodeHash))); - L2NativeTokenVaultDev(L2_NATIVE_TOKEN_VAULT_ADDR).deployBridgedStandardERC20(_args.aliasedOwner); + { + // Initializing reentrancy guard + // stdstore.target(address(L2_ASSET_ROUTER_ADDR)).sig("l1AssetRouter()").checked_write(_args.l1AssetRouter); + vm.store( + L2_ASSET_ROUTER_ADDR, + bytes32(0x8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4), + bytes32(uint256(1)) + ); + } + + { + address ntv = address(new L2NativeTokenVaultDev()); + vm.etch(L2_NATIVE_TOKEN_VAULT_ADDR, ntv.code); + + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + L2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR).initL2( + _args.l1ChainId, + _args.aliasedOwner, + _args.l2TokenProxyBytecodeHash, + _args.legacySharedBridge, + _args.l2TokenBeacon, + wethToken, + baseTokenAssetId, + ETH_TOKEN_ADDRESS, + _args.l1ChainId + ); + + vm.store( + L2_NATIVE_TOKEN_VAULT_ADDR, + bytes32(uint256(251)), + bytes32(uint256(_args.l2TokenProxyBytecodeHash)) + ); + L2NativeTokenVaultDev(L2_NATIVE_TOKEN_VAULT_ADDR).deployBridgedStandardERC20(_args.aliasedOwner); + } } } diff --git a/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/_SharedL2ContractL1Deployer.sol b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/_SharedL2ContractL1Deployer.sol index b819f73d88..cb23b594dd 100644 --- a/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/_SharedL2ContractL1Deployer.sol +++ b/l1-contracts/test/foundry/l1/integration/l2-tests-in-l1-context/_SharedL2ContractL1Deployer.sol @@ -4,31 +4,19 @@ pragma solidity 0.8.28; import {StdStorage, stdStorage, stdToml} from "forge-std/Test.sol"; import {Script, console2 as console} from "forge-std/Script.sol"; -import {Config, DeployUtils, DeployedAddresses} from "deploy-scripts/DeployUtils.s.sol"; - -import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; - -import {L2MessageRoot} from "contracts/bridgehub/L2MessageRoot.sol"; -import {L2AssetRouter} from "contracts/bridge/asset-router/L2AssetRouter.sol"; -import {L2NativeTokenVault} from "contracts/bridge/ntv/L2NativeTokenVault.sol"; -import {L2ChainAssetHandler} from "contracts/bridgehub/L2ChainAssetHandler.sol"; -import {L2NativeTokenVaultDev} from "contracts/dev-contracts/test/L2NativeTokenVaultDev.sol"; -import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; -import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; -import {ICTMDeploymentTracker} from "contracts/bridgehub/ICTMDeploymentTracker.sol"; -import {L2MessageVerification} from "../../../../../contracts/bridgehub/L2MessageVerification.sol"; -import {DummyL2InteropRootStorage} from "../../../../../contracts/dev-contracts/test/DummyL2InteropRootStorage.sol"; - -import {StateTransitionDeployedAddresses} from "deploy-scripts/Utils.sol"; +import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_INTEROP_CENTER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {ISystemContext} from "contracts/common/interfaces/ISystemContext.sol"; + +import {StateTransitionDeployedAddresses} from "deploy-scripts/Types.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {DeployCTMIntegrationScript} from "../deploy-scripts/DeployCTMIntegration.s.sol"; import {SharedL2ContractDeployer, SystemContractsArgs} from "../l2-tests-abstract/_SharedL2ContractDeployer.sol"; +import {L2UtilsBase} from "./L2UtilsBase.sol"; +import {DeployCTMUtils} from "deploy-scripts/DeployCTMUtils.s.sol"; import {DeployIntegrationUtils} from "../deploy-scripts/DeployIntegrationUtils.s.sol"; - -import {DeployL1HelperScript} from "deploy-scripts/DeployL1HelperScript.s.sol"; import {L2UtilsBase} from "./L2UtilsBase.sol"; contract SharedL2ContractL1Deployer is SharedL2ContractDeployer, DeployCTMIntegrationScript { @@ -39,26 +27,46 @@ contract SharedL2ContractL1Deployer is SharedL2ContractDeployer, DeployCTMIntegr function initSystemContracts(SystemContractsArgs memory _args) internal virtual override { L2UtilsBase.initSystemContracts(_args); + vm.mockCall( + L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, + abi.encodeWithSelector(ISystemContext.currentSettlementLayerChainId.selector), + abi.encode(9) + ); } function deployL2Contracts(uint256 _l1ChainId) public virtual override { + deployL2ContractsInner(_l1ChainId, false); + } + + function deployL2ContractsInner(uint256 _l1ChainId, bool _skip) public { string memory root = vm.projectRoot(); + string memory CONTRACTS_PATH = vm.envString("CONTRACTS_PATH"); string memory inputPath = string.concat( root, + "/", + CONTRACTS_PATH, + "/l1-contracts", "/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-l1.toml" ); initializeConfig(inputPath); - addresses.transparentProxyAdmin = makeAddr("transparentProxyAdmin"); - addresses.bridgehub.bridgehubProxy = L2_BRIDGEHUB_ADDR; - addresses.bridges.l1AssetRouterProxy = L2_ASSET_ROUTER_ADDR; - addresses.vaults.l1NativeTokenVaultProxy = L2_NATIVE_TOKEN_VAULT_ADDR; + discoveredBridgehub.bridgehubProxy = L2_BRIDGEHUB_ADDR; + discoveredBridgehub.assetRouter = L2_ASSET_ROUTER_ADDR; + discoveredBridgehub.assetRouterAddresses.nativeTokenVault = L2_NATIVE_TOKEN_VAULT_ADDR; + discoveredBridgehub.interopCenterProxy = L2_INTEROP_CENTER_ADDR; config.l1ChainId = _l1ChainId; console.log("Deploying L2 contracts"); - instantiateCreate2Factory(); + if (!_skip) { + instantiateCreate2Factory(); + } + + // TODO refactor + addresses.transparentProxyAdmin = makeAddr("transparentProxyAdmin"); + addresses.governance = makeAddr("governance"); addresses.stateTransition.genesisUpgrade = deploySimpleContract("L1GenesisUpgrade", true); addresses.stateTransition.verifier = deploySimpleContract("Verifier", true); addresses.stateTransition.validatorTimelock = deploySimpleContract("ValidatorTimelock", true); addresses.eip7702Checker = address(0); + initializeGeneratedData(); deployStateTransitionDiamondFacets(); string memory ctmContractName = config.isZKsyncOS ? "ZKsyncOSChainTypeManager" : "EraChainTypeManager"; ( @@ -70,20 +78,6 @@ contract SharedL2ContractL1Deployer is SharedL2ContractDeployer, DeployCTMIntegr // add this to be excluded from coverage report function test() internal virtual override(DeployCTMIntegrationScript, SharedL2ContractDeployer) {} - function getCreationCode( - string memory contractName, - bool isZKBytecode - ) internal view virtual override(DeployUtils, DeployL1HelperScript) returns (bytes memory) { - return super.getCreationCode(contractName, false); - } - - function getInitializeCalldata( - string memory contractName, - bool isZKBytecode - ) internal virtual override(DeployIntegrationUtils, DeployL1HelperScript) returns (bytes memory) { - return super.getInitializeCalldata(contractName, isZKBytecode); - } - function getChainCreationFacetCuts( StateTransitionDeployedAddresses memory stateTransition ) @@ -105,4 +99,11 @@ contract SharedL2ContractL1Deployer is SharedL2ContractDeployer, DeployCTMIntegr { return super.getUpgradeAddedFacetCuts(stateTransition); } + + function getInitializeCalldata( + string memory contractName, + bool isZKBytecode + ) internal virtual override(DeployIntegrationUtils, DeployCTMUtils) returns (bytes memory) { + return super.getInitializeCalldata(contractName, isZKBytecode); + } } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridge/AssetTracker/GWAssetTracker.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridge/AssetTracker/GWAssetTracker.t.sol new file mode 100644 index 0000000000..d31ba955c3 --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridge/AssetTracker/GWAssetTracker.t.sol @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {console2 as console} from "forge-std/console2.sol"; +import {GWAssetTracker} from "contracts/bridge/asset-tracker/GWAssetTracker.sol"; + +import {BalanceChange, ConfirmBalanceMigrationData} from "contracts/common/Messaging.sol"; +import {L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR, L2_COMPLEX_UPGRADER_ADDR, L2_INTEROP_CENTER_ADDR, L2_MESSAGE_ROOT_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; + +import {AssetRouterBase} from "contracts/bridge/asset-router/AssetRouterBase.sol"; + +import {BALANCE_CHANGE_VERSION, TOKEN_BALANCE_MIGRATION_DATA_VERSION} from "contracts/bridge/asset-tracker/IAssetTrackerBase.sol"; +import {SERVICE_TRANSACTION_SENDER} from "contracts/common/Config.sol"; + +import {InvalidCanonicalTxHash} from "contracts/bridge/asset-tracker/AssetTrackerErrors.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; +import {IChainAssetHandler} from "contracts/bridgehub/IChainAssetHandler.sol"; + +import {L2MessageRoot} from "contracts/bridgehub/L2MessageRoot.sol"; + +contract GWAssetTrackerTestHelper is GWAssetTracker { + function getEmptyMessageRoot(uint256 _chainId) external returns (bytes32) { + return _getEmptyMessageRoot(_chainId); + } +} + +contract GWAssetTrackerTest is Test { + GWAssetTrackerTestHelper public gwAssetTracker; + address public mockBridgehub; + address public mockMessageRoot; + address public mockNativeTokenVault; + address public mockChainAssetHandler; + address public mockZKChain; + + uint256 public constant L1_CHAIN_ID = 1; + uint256 public constant CHAIN_ID = 2; + uint256 public constant MIGRATION_NUMBER = 10; + bytes32 public constant ASSET_ID = keccak256("assetId"); + bytes32 public constant CANONICAL_TX_HASH = keccak256("canonicalTxHash"); + address public constant ORIGIN_TOKEN = address(0x123); + uint256 public constant ORIGIN_CHAIN_ID = 3; + uint256 public constant AMOUNT = 1000; + bytes32 public constant BASE_TOKEN_ASSET_ID = keccak256("baseTokenAssetId"); + uint256 public constant BASE_TOKEN_AMOUNT = 500; + + function setUp() public { + // Deploy GWAssetTrackerTestHelper + gwAssetTracker = new GWAssetTrackerTestHelper(); + + // Create mock addresses + mockBridgehub = makeAddr("mockBridgehub"); + mockMessageRoot = makeAddr("mockMessageRoot"); + mockNativeTokenVault = makeAddr("mockNativeTokenVault"); + mockChainAssetHandler = makeAddr("mockChainAssetHandler"); + mockZKChain = makeAddr("mockZKChain"); + + // Mock the L2 contract addresses + vm.etch(L2_BRIDGEHUB_ADDR, address(mockBridgehub).code); + vm.etch(L2_MESSAGE_ROOT_ADDR, address(mockMessageRoot).code); + vm.etch(L2_NATIVE_TOKEN_VAULT_ADDR, address(mockNativeTokenVault).code); + vm.etch(L2_CHAIN_ASSET_HANDLER_ADDR, address(mockChainAssetHandler).code); + + // Set up the contract + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + gwAssetTracker.setAddresses(L1_CHAIN_ID); + + vm.mockCall( + L2_CHAIN_ASSET_HANDLER_ADDR, + abi.encodeWithSelector(IChainAssetHandler.migrationNumber.selector), + abi.encode(1) + ); + } + + function test_SetAddresses() public { + uint256 newL1ChainId = 999; + + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + gwAssetTracker.setAddresses(newL1ChainId); + + assertEq(gwAssetTracker.L1_CHAIN_ID(), newL1ChainId); + } + + function test_SetAddresses_Unauthorized() public { + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, address(this))); + gwAssetTracker.setAddresses(999); + } + + function test_HandleChainBalanceIncreaseOnGateway() public { + BalanceChange memory balanceChange = BalanceChange({ + version: BALANCE_CHANGE_VERSION, + assetId: ASSET_ID, + baseTokenAssetId: BASE_TOKEN_ASSET_ID, + amount: AMOUNT, + baseTokenAmount: BASE_TOKEN_AMOUNT, + originToken: ORIGIN_TOKEN, + tokenOriginChainId: ORIGIN_CHAIN_ID + }); + vm.prank(L2_INTEROP_CENTER_ADDR); + gwAssetTracker.handleChainBalanceIncreaseOnGateway(CHAIN_ID, CANONICAL_TX_HASH, balanceChange); + + // Check that chain balance was increased + assertEq(gwAssetTracker.chainBalance(CHAIN_ID, ASSET_ID), AMOUNT); + assertEq(gwAssetTracker.chainBalance(CHAIN_ID, BASE_TOKEN_ASSET_ID), BASE_TOKEN_AMOUNT); + + // Check that token was registered (these are internal mappings, so we can't test them directly) + // The token registration happens in the _registerToken function + } + + function test_HandleChainBalanceIncreaseOnGateway_Unauthorized() public { + BalanceChange memory balanceChange = BalanceChange({ + version: BALANCE_CHANGE_VERSION, + assetId: ASSET_ID, + baseTokenAssetId: BASE_TOKEN_ASSET_ID, + amount: AMOUNT, + baseTokenAmount: BASE_TOKEN_AMOUNT, + originToken: ORIGIN_TOKEN, + tokenOriginChainId: ORIGIN_CHAIN_ID + }); + + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, address(this))); + gwAssetTracker.handleChainBalanceIncreaseOnGateway(CHAIN_ID, CANONICAL_TX_HASH, balanceChange); + } + + function test_HandleChainBalanceIncreaseOnGateway_InvalidCanonicalTxHash() public { + BalanceChange memory balanceChange = BalanceChange({ + version: BALANCE_CHANGE_VERSION, + assetId: ASSET_ID, + baseTokenAssetId: BASE_TOKEN_ASSET_ID, + amount: AMOUNT, + baseTokenAmount: BASE_TOKEN_AMOUNT, + originToken: ORIGIN_TOKEN, + tokenOriginChainId: ORIGIN_CHAIN_ID + }); + + // First call succeeds + vm.prank(L2_INTEROP_CENTER_ADDR); + gwAssetTracker.handleChainBalanceIncreaseOnGateway(CHAIN_ID, CANONICAL_TX_HASH, balanceChange); + + // Second call with same canonical tx hash should fail + vm.expectRevert(abi.encodeWithSelector(InvalidCanonicalTxHash.selector, CANONICAL_TX_HASH)); + vm.prank(L2_INTEROP_CENTER_ADDR); + gwAssetTracker.handleChainBalanceIncreaseOnGateway(CHAIN_ID, CANONICAL_TX_HASH, balanceChange); + } + + function test_SetLegacySharedBridgeAddress() public { + address legacyBridge = makeAddr("legacyBridge"); + + vm.prank(SERVICE_TRANSACTION_SENDER); + gwAssetTracker.setLegacySharedBridgeAddress(CHAIN_ID, legacyBridge); + } + + function test_SetLegacySharedBridgeAddress_Unauthorized() public { + address legacyBridge = makeAddr("legacyBridge"); + + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, address(this))); + gwAssetTracker.setLegacySharedBridgeAddress(CHAIN_ID, legacyBridge); + } + + function test_ConfirmMigrationOnGateway_Unauthorized() public { + ConfirmBalanceMigrationData memory data = ConfirmBalanceMigrationData({ + version: TOKEN_BALANCE_MIGRATION_DATA_VERSION, + chainId: CHAIN_ID, + assetId: ASSET_ID, + amount: AMOUNT, + migrationNumber: MIGRATION_NUMBER, + isL1ToGateway: false + }); + + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, address(this))); + gwAssetTracker.confirmMigrationOnGateway(data); + } + + function test_ParseInteropCall() public { + bytes memory callData = abi.encodePacked( + AssetRouterBase.finalizeDeposit.selector, + abi.encode(CHAIN_ID, ASSET_ID, abi.encode("transferData")) + ); + + (uint256 fromChainId, bytes32 assetId, bytes memory transferData) = gwAssetTracker.parseInteropCall(callData); + + assertEq(fromChainId, CHAIN_ID); + assertEq(assetId, ASSET_ID); + assertEq(transferData, abi.encode("transferData")); + } + + function test_emptyRootEquivalence() public { + bytes32 emptyRoot = gwAssetTracker.getEmptyMessageRoot(CHAIN_ID); + + vm.chainId(CHAIN_ID); + L2MessageRoot dummyL2MessageRoot = new L2MessageRoot(); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + dummyL2MessageRoot.initL2(L1_CHAIN_ID, block.chainid); + + assertEq(dummyL2MessageRoot.getAggregatedRoot(), emptyRoot); + } +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/L2MessageVerification.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/L2MessageVerification.t.sol index b131ca9072..c77e5df88f 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/L2MessageVerification.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/L2MessageVerification.t.sol @@ -3,13 +3,11 @@ pragma solidity ^0.8.24; import {Test} from "forge-std/Test.sol"; -import {L2MessageRoot} from "contracts/bridgehub/L2MessageRoot.sol"; -import {MessageRootNotRegistered, OnlyBridgehub} from "contracts/bridgehub/L1BridgehubErrors.sol"; import {Merkle} from "contracts/common/libraries/Merkle.sol"; -import {L2MessageVerification} from "contracts/bridgehub/L2MessageVerification.sol"; +import {L2MessageVerification} from "contracts/interop/L2MessageVerification.sol"; import {L2Log, L2Message} from "contracts/common/Messaging.sol"; -// import {IL2MessageRootStorage} from "contracts/common/interfaces/IL2MessageRootStorage.sol"; +// import {IL2InteropRootStorage} from "contracts/common/interfaces/IL2InteropRootStorage.sol"; import {L2_INTEROP_ROOT_STORAGE} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; // Chain tree consists of batch commitments as their leaves. We use hash of "new bytes(96)" as the hash of an empty leaf. diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/MessageRoot.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/MessageRoot.t.sol index f88a71389f..fdf9f80f2d 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/MessageRoot.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/MessageRoot.t.sol @@ -3,12 +3,17 @@ pragma solidity 0.8.28; import {Test} from "forge-std/Test.sol"; +import {Ownable} from "@openzeppelin/contracts-v4/access/Ownable.sol"; import {L1MessageRoot} from "contracts/bridgehub/L1MessageRoot.sol"; -import {MessageRootBase} from "contracts/bridgehub/MessageRootBase.sol"; +import {L2MessageRoot} from "contracts/bridgehub/L2MessageRoot.sol"; +import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; +import {IChainAssetHandler} from "contracts/bridgehub/IChainAssetHandler.sol"; + import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; import {MessageRootNotRegistered, OnlyBridgehubOrChainAssetHandler} from "contracts/bridgehub/L1BridgehubErrors.sol"; import {MessageHashing} from "contracts/common/libraries/MessageHashing.sol"; +import {GW_ASSET_TRACKER_ADDR, L2_COMPLEX_UPGRADER_ADDR, L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; // Chain tree consists of batch commitments as their leaves. We use hash of "new bytes(96)" as the hash of an empty leaf. bytes32 constant CHAIN_TREE_EMPTY_ENTRY_HASH = bytes32( @@ -23,12 +28,36 @@ bytes32 constant SHARED_ROOT_TREE_EMPTY_HASH = bytes32( contract MessageRootTest is Test { address bridgeHub; L1MessageRoot messageRoot; + L2MessageRoot l2MessageRoot; uint256 L1_CHAIN_ID; + uint256 gatewayChainId; + address assetTracker; function setUp() public { + bridgeHub = makeAddr("bridgeHub"); + uint256[] memory allZKChainChainIDs = new uint256[](1); + allZKChainChainIDs[0] = 271; + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.getAllZKChainChainIDs.selector), + abi.encode(allZKChainChainIDs) + ); + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.chainTypeManager.selector), + abi.encode(makeAddr("chainTypeManager")) + ); + vm.mockCall(bridgeHub, abi.encodeWithSelector(IBridgehubBase.settlementLayer.selector), abi.encode(0)); + + assetTracker = makeAddr("assetTracker"); bridgeHub = makeAddr("bridgeHub"); L1_CHAIN_ID = 5; - messageRoot = new L1MessageRoot(bridgeHub); + gatewayChainId = 506; + messageRoot = new L1MessageRoot(bridgeHub, 1); + l2MessageRoot = new L2MessageRoot(); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + l2MessageRoot.initL2(L1_CHAIN_ID, gatewayChainId); + vm.mockCall(address(bridgeHub), abi.encodeWithSelector(Ownable.owner.selector), abi.encode(assetTracker)); } function test_init() public { @@ -55,12 +84,13 @@ contract MessageRootTest is Test { abi.encodeWithSelector(IBridgehubBase.chainAssetHandler.selector), abi.encode(chainAssetHandler) ); - messageRoot.addNewChain(alphaChainId); + messageRoot.addNewChain(alphaChainId, 0); assertFalse(messageRoot.chainRegistered(alphaChainId), "alpha chain 2"); } function test_addNewChain() public { + // kl todo: enable these tests if commented out. uint256 alphaChainId = uint256(uint160(makeAddr("alphaChainId"))); uint256 betaChainId = uint256(uint160(makeAddr("betaChainId"))); @@ -69,8 +99,8 @@ contract MessageRootTest is Test { vm.prank(bridgeHub); vm.expectEmit(true, false, false, false); - emit MessageRootBase.AddedChain(alphaChainId, 0); - messageRoot.addNewChain(alphaChainId); + emit IMessageRoot.AddedChain(alphaChainId, 0); + messageRoot.addNewChain(alphaChainId, 0); assertTrue(messageRoot.chainRegistered(alphaChainId), "alpha chain 2"); assertFalse(messageRoot.chainRegistered(betaChainId), "beta chain 2"); @@ -78,58 +108,123 @@ contract MessageRootTest is Test { assertEq(messageRoot.getChainRoot(alphaChainId), bytes32(0)); } - // FIXME: amend the tests as appending chain batch roots is not allowed on L1. - // function test_RevertWhen_ChainNotRegistered() public { - // address alphaChainSender = makeAddr("alphaChainSender"); - // uint256 alphaChainId = uint256(uint160(makeAddr("alphaChainId"))); - // vm.mockCall( - // bridgeHub, - // abi.encodeWithSelector(IBridgehub.getZKChain.selector, alphaChainId), - // abi.encode(alphaChainSender) - // ); - - // vm.prank(alphaChainSender); - // vm.expectRevert(MessageRootNotRegistered.selector); - // messageRoot.addChainBatchRoot(alphaChainId, 1, bytes32(alphaChainId)); - // } - - // function test_addChainBatchRoot() public { - // address alphaChainSender = makeAddr("alphaChainSender"); - // uint256 alphaChainId = uint256(uint160(makeAddr("alphaChainId"))); - // vm.mockCall( - // bridgeHub, - // abi.encodeWithSelector(IBridgehub.getZKChain.selector, alphaChainId), - // abi.encode(alphaChainSender) - // ); - - // vm.prank(bridgeHub); - // messageRoot.addNewChain(alphaChainId); - - // vm.prank(alphaChainSender); - // vm.expectEmit(true, false, false, false); - // emit MessageRootBase.AppendedChainBatchRoot(alphaChainId, 1, bytes32(alphaChainId)); - // vm.expectEmit(true, false, false, false); - // emit MessageRootBase.NewChainRoot(alphaChainId, bytes32(0), bytes32(0)); - // messageRoot.addChainBatchRoot(alphaChainId, 1, bytes32(alphaChainId)); - // } - - // function test_updateFullTree() public { - // address alphaChainSender = makeAddr("alphaChainSender"); - // uint256 alphaChainId = uint256(uint160(makeAddr("alphaChainId"))); - // vm.mockCall( - // bridgeHub, - // abi.encodeWithSelector(IBridgehub.getZKChain.selector, alphaChainId), - // abi.encode(alphaChainSender) - // ); - - // vm.prank(bridgeHub); - // messageRoot.addNewChain(alphaChainId); - - // vm.prank(alphaChainSender); - // messageRoot.addChainBatchRoot(alphaChainId, 1, bytes32(alphaChainId)); - - // messageRoot.updateFullTree(); - - // assertEq(messageRoot.getAggregatedRoot(), 0x0ef1ac67d77f177a33449c47a8f05f0283300a81adca6f063c92c774beed140c); - // } + function test_RevertWhen_ChainNotRegistered() public { + address alphaChainSender = makeAddr("alphaChainSender"); + uint256 alphaChainId = uint256(uint160(makeAddr("alphaChainId"))); + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.getZKChain.selector, alphaChainId), + abi.encode(alphaChainSender) + ); + + vm.prank(alphaChainSender); + vm.expectRevert(MessageRootNotRegistered.selector); + messageRoot.addChainBatchRoot(alphaChainId, 1, bytes32(alphaChainId)); + } + + function test_addChainBatchRoot_1() public { + address alphaChainSender = makeAddr("alphaChainSender"); + uint256 alphaChainId = uint256(uint160(makeAddr("alphaChainId"))); + vm.mockCall( + L2_BRIDGEHUB_ADDR, + abi.encodeWithSelector(IBridgehubBase.getZKChain.selector, alphaChainId), + abi.encode(alphaChainSender) + ); + vm.mockCall( + L2_BRIDGEHUB_ADDR, + abi.encodeWithSelector(IBridgehubBase.chainAssetHandler.selector), + abi.encode(L2_CHAIN_ASSET_HANDLER_ADDR) + ); + + vm.prank(L2_BRIDGEHUB_ADDR); + l2MessageRoot.addNewChain(L1_CHAIN_ID, 0); + + vm.chainId(L1_CHAIN_ID); + vm.prank(alphaChainSender); + vm.expectRevert(); + l2MessageRoot.addChainBatchRoot(L1_CHAIN_ID, 1, bytes32(L1_CHAIN_ID)); + + vm.prank(L2_BRIDGEHUB_ADDR); + l2MessageRoot.addNewChain(alphaChainId, 0); + + vm.prank(alphaChainSender); + vm.expectEmit(true, false, false, false); + emit IMessageRoot.AppendedChainBatchRoot(alphaChainId, 1, bytes32(alphaChainId)); + vm.expectEmit(true, false, false, false); + emit IMessageRoot.NewChainRoot(alphaChainId, bytes32(0), bytes32(0)); + l2MessageRoot.addChainBatchRoot(alphaChainId, 1, bytes32(alphaChainId)); + } + + function test_updateFullTree() public { + address alphaChainSender = makeAddr("alphaChainSender"); + uint256 alphaChainId = uint256(uint160(makeAddr("alphaChainId"))); + vm.mockCall( + address(bridgeHub), + abi.encodeWithSelector(IBridgehubBase.getZKChain.selector, alphaChainId), + abi.encode(alphaChainSender) + ); + vm.mockCall( + L2_BRIDGEHUB_ADDR, + abi.encodeWithSelector(IBridgehubBase.getZKChain.selector, alphaChainId), + abi.encode(alphaChainSender) + ); + vm.mockCall( + address(bridgeHub), + abi.encodeWithSelector(IBridgehubBase.chainAssetHandler.selector), + abi.encode(L2_CHAIN_ASSET_HANDLER_ADDR) + ); + vm.mockCall( + L2_BRIDGEHUB_ADDR, + abi.encodeWithSelector(IBridgehubBase.chainAssetHandler.selector), + abi.encode(L2_CHAIN_ASSET_HANDLER_ADDR) + ); + vm.prank(bridgeHub); + messageRoot.addNewChain(alphaChainId, 0); + vm.prank(alphaChainSender); + messageRoot.addChainBatchRoot(alphaChainId, 1, bytes32(alphaChainId)); + vm.prank(L2_BRIDGEHUB_ADDR); + l2MessageRoot.addNewChain(alphaChainId, 0); + vm.chainId(gatewayChainId); + vm.prank(GW_ASSET_TRACKER_ADDR); + l2MessageRoot.addChainBatchRoot(alphaChainId, 1, bytes32(alphaChainId)); + l2MessageRoot.updateFullTree(); + assertEq(l2MessageRoot.getAggregatedRoot(), 0x0ef1ac67d77f177a33449c47a8f05f0283300a81adca6f063c92c774beed140c); + } + + function test_addChainBatchRootWithRealData() public { + address alphaChainSender = makeAddr("alphaChainSender"); + uint256 alphaChainId = 271; //uint256(uint160(makeAddr("alphaChainId"))); + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.getZKChain.selector, alphaChainId), + abi.encode(alphaChainSender) + ); + + vm.prank(bridgeHub); + messageRoot.addNewChain(alphaChainId, 0); + + vm.prank(alphaChainSender); + // vm.expectEmit(true, false, false, false); + // emit MessageRoot.Preimage(bytes32(0), bytes32(0)); + // vm.expectEmit(true, false, false, false); + // emit MessageRoot.AppendedChainBatchRoot(alphaChainId, 1, bytes32(alphaChainId)); + messageRoot.addChainBatchRoot( + alphaChainId, + 1, + bytes32(hex"63c4d39ce8f2410a1e65b0ad1209fe8b368928a7124bfa6e10e0d4f0786129dd") + ); + vm.prank(alphaChainSender); + messageRoot.addChainBatchRoot( + alphaChainId, + 2, + bytes32(hex"bcc3a5584fe0f85e968c0bae082172061e3f3a8a47ff9915adae4a3e6174fc12") + ); + vm.prank(alphaChainSender); + messageRoot.addChainBatchRoot( + alphaChainId, + 3, + bytes32(hex"8d1ced168691d5e8a2dc778350a2c40a2714cc7d64bff5b8da40a96c47dc5f3e") + ); + messageRoot.getChainRoot(alphaChainId); + } } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/MessageRoot_Extended.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/MessageRoot_Extended.t.sol new file mode 100644 index 0000000000..cd22cf9477 --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/MessageRoot_Extended.t.sol @@ -0,0 +1,417 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {Test} from "forge-std/Test.sol"; +import {Ownable} from "@openzeppelin/contracts-v4/access/Ownable.sol"; +import {L1MessageRoot} from "contracts/bridgehub/L1MessageRoot.sol"; +import {L2MessageRoot} from "contracts/bridgehub/L2MessageRoot.sol"; +import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; +import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; +import {ChainExists, MessageRootNotRegistered, NotL2, OnlyChain, OnlyGateway, OnlyL2MessageRoot, OnlyOnSettlementLayer, TotalBatchesExecutedZero, V30UpgradeChainBatchNumberNotSet} from "contracts/bridgehub/L1BridgehubErrors.sol"; +import {Unauthorized, InvalidCaller} from "contracts/common/L1ContractErrors.sol"; +import {GW_ASSET_TRACKER_ADDR, L2_BRIDGEHUB_ADDR, L2_COMPLEX_UPGRADER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; + +import {ProofData} from "contracts/common/Messaging.sol"; + +import {FinalizeL1DepositParams} from "contracts/bridge/interfaces/IL1Nullifier.sol"; +import {IGetters} from "contracts/state-transition/chain-interfaces/IGetters.sol"; + +contract MessageRoot_Extended_Test is Test { + address bridgeHub; + uint256 L1_CHAIN_ID; + uint256 gatewayChainId; + L1MessageRoot messageRoot; + L2MessageRoot l2MessageRoot; + address assetTracker; + address chainAssetHandler; + + function setUp() public { + bridgeHub = makeAddr("bridgeHub"); + chainAssetHandler = makeAddr("chainAssetHandler"); + assetTracker = makeAddr("assetTracker"); + L1_CHAIN_ID = 1; + gatewayChainId = 506; + + vm.mockCall(bridgeHub, abi.encodeWithSelector(IL1Bridgehub.L1_CHAIN_ID.selector), abi.encode(L1_CHAIN_ID)); + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.chainAssetHandler.selector), + abi.encode(chainAssetHandler) + ); + vm.mockCall(address(bridgeHub), abi.encodeWithSelector(Ownable.owner.selector), abi.encode(assetTracker)); + + uint256[] memory allZKChainChainIDs = new uint256[](1); + allZKChainChainIDs[0] = 271; + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.getAllZKChainChainIDs.selector), + abi.encode(allZKChainChainIDs) + ); + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.chainTypeManager.selector), + abi.encode(makeAddr("chainTypeManager")) + ); + vm.mockCall(bridgeHub, abi.encodeWithSelector(IBridgehubBase.settlementLayer.selector), abi.encode(0)); + + messageRoot = new L1MessageRoot(bridgeHub, gatewayChainId); + l2MessageRoot = new L2MessageRoot(); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + l2MessageRoot.initL2(L1_CHAIN_ID, gatewayChainId); + } + + function test_ChainRegistered_CurrentChain() public { + // Test that current chain is always registered + assertTrue(messageRoot.chainRegistered(block.chainid)); + } + + function test_ChainRegistered_UnregisteredChain() public { + uint256 unregisteredChainId = 999; + assertFalse(messageRoot.chainRegistered(unregisteredChainId)); + } + + function test_AddNewChain_ChainExists() public { + uint256 chainId = 271; + + // Add chain first time + vm.prank(bridgeHub); + messageRoot.addNewChain(chainId, 0); + + // Try to add same chain again + vm.prank(bridgeHub); + vm.expectRevert(ChainExists.selector); + messageRoot.addNewChain(chainId, 0); + } + + function test_AddNewChain_FromChainAssetHandler() public { + uint256 chainId = 271; + + vm.prank(chainAssetHandler); + vm.expectEmit(true, false, false, false); + emit IMessageRoot.AddedChain(chainId, 0); + messageRoot.addNewChain(chainId, 0); + + assertTrue(messageRoot.chainRegistered(chainId)); + } + + function test_GetChainRoot_ChainNotRegistered() public { + uint256 unregisteredChainId = 999; + vm.expectRevert(MessageRootNotRegistered.selector); + messageRoot.getChainRoot(unregisteredChainId); + } + + function test_GetAggregatedRoot_WithChains() public { + uint256 chainId = 271; + + vm.prank(bridgeHub); + messageRoot.addNewChain(chainId, 0); + + // Should return the shared tree root + bytes32 root = messageRoot.getAggregatedRoot(); + assertTrue(root != bytes32(0)); + } + + function test_InitializeL2V30Upgrade_NotL2() public { + vm.expectRevert(abi.encodeWithSelector(InvalidCaller.selector, address(this))); + l2MessageRoot.initializeL2V30Upgrade(); + } + + function test_InitializeL2V30Upgrade_NotUpgrader() public { + vm.chainId(2); // Set to non-L1 chain + vm.expectRevert(abi.encodeWithSelector(InvalidCaller.selector, address(this))); + l2MessageRoot.initializeL2V30Upgrade(); + } + + function test_InitializeL1V30Upgrade_NotL1() public { + vm.chainId(2); // Set to non-L1 chain + + vm.expectRevert("Initializable: contract is already initialized"); + messageRoot.initializeL1V30Upgrade(); + } + + function test_SendV30UpgradeBlockNumberFromGateway_NotGateway() public { + vm.chainId(2); // Set to non-gateway chain + vm.expectRevert(OnlyGateway.selector); + l2MessageRoot.sendV30UpgradeBlockNumberFromGateway(271, 100); + } + + function test_SendV30UpgradeBlockNumberFromGateway_NotSet() public { + vm.chainId(gatewayChainId); // Set to gateway chain + vm.expectRevert(V30UpgradeChainBatchNumberNotSet.selector); + l2MessageRoot.sendV30UpgradeBlockNumberFromGateway(271, 100); + } + + function test_SaveV30UpgradeChainBatchNumberOnL1_NotL2MessageRoot() public { + FinalizeL1DepositParams memory params = FinalizeL1DepositParams({ + l2Sender: makeAddr("wrongSender"), + chainId: 1, + message: abi.encodeWithSelector(L2MessageRoot.sendV30UpgradeBlockNumberFromGateway.selector, 271, 100), + l2TxNumberInBatch: 1, + l2BatchNumber: 1, + l2MessageIndex: 1, + merkleProof: new bytes32[](0) + }); + vm.expectRevert(OnlyL2MessageRoot.selector); + messageRoot.saveV30UpgradeChainBatchNumberOnL1(params); + } + + function test_SaveV30UpgradeChainBatchNumber_NotChain() public { + uint256 chainId = 271; + address wrongSender = makeAddr("wrongSender"); + + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.getZKChain.selector, chainId), + abi.encode(makeAddr("correctChain")) + ); + + vm.expectRevert(abi.encodeWithSelector(OnlyChain.selector, wrongSender, makeAddr("correctChain"))); + vm.prank(wrongSender); + messageRoot.saveV30UpgradeChainBatchNumber(chainId); + } + + function test_SaveV30UpgradeChainBatchNumber_NotOnSettlementLayer() public { + uint256 chainId = 271; + address chainSender = makeAddr("chainSender"); + + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.getZKChain.selector, chainId), + abi.encode(chainSender) + ); + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.settlementLayer.selector, chainId), + abi.encode(2) // Different settlement layer + ); + + vm.expectRevert(OnlyOnSettlementLayer.selector); + vm.prank(chainSender); + messageRoot.saveV30UpgradeChainBatchNumber(chainId); + } + + function test_SaveV30UpgradeChainBatchNumber_TotalBatchesExecutedZero() public { + uint256 chainId = 271; + address chainSender = makeAddr("chainSender"); + + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.getZKChain.selector, chainId), + abi.encode(chainSender) + ); + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.settlementLayer.selector, chainId), + abi.encode(block.chainid) + ); + + // Mock getTotalBatchesExecuted to return 0 + vm.mockCall(chainSender, abi.encodeWithSelector(IGetters.getTotalBatchesExecuted.selector), abi.encode(0)); + + vm.expectRevert(TotalBatchesExecutedZero.selector); + vm.prank(chainSender); + messageRoot.saveV30UpgradeChainBatchNumber(chainId); + } + + function test_SetMigratingChainBatchRoot_Success() public { + uint256 chainId = 271; + uint256 batchNumber = 1; + uint256 v30UpgradeChainBatchNumber = 100; + + vm.prank(bridgeHub); + messageRoot.setMigratingChainBatchRoot(chainId, batchNumber, v30UpgradeChainBatchNumber); + + assertEq(messageRoot.currentChainBatchNumber(chainId), batchNumber); + assertEq(messageRoot.v30UpgradeChainBatchNumber(chainId), v30UpgradeChainBatchNumber); + } + + function test_GetProofData() public { + uint256 chainId = 271; + uint256 batchNumber = 1; + uint256 leafProofMask = 1; + bytes32 leaf = keccak256("leaf"); + bytes32[] memory proof = new bytes32[](1); + proof[0] = keccak256("proof"); + + ProofData memory result = messageRoot.getProofData(chainId, batchNumber, leafProofMask, leaf, proof); + + // Verify the result is not empty + assertTrue(result.settlementLayerChainId != 0 || result.batchSettlementRoot != bytes32(0)); + } + + function test_ChainCount() public { + uint256 initialCount = messageRoot.chainCount(); + assertEq(initialCount, 1); // Current chain is always registered + + uint256 chainId = 271; + vm.prank(bridgeHub); + messageRoot.addNewChain(chainId, 0); + + uint256 newCount = messageRoot.chainCount(); + assertEq(newCount, 2); + } + + function test_ChainIndex() public { + uint256 chainId = 271; + + vm.prank(bridgeHub); + messageRoot.addNewChain(chainId, 0); + + uint256 index = messageRoot.chainIndex(chainId); + assertEq(index, 1); + + uint256 chainIdFromIndex = messageRoot.chainIndexToId(1); + assertEq(chainIdFromIndex, chainId); + } + + function test_CurrentChainBatchNumber() public { + uint256 chainId = 271; + uint256 startingBatchNumber = 5; + + vm.prank(bridgeHub); + messageRoot.addNewChain(chainId, startingBatchNumber); + + uint256 currentBatch = messageRoot.currentChainBatchNumber(chainId); + assertEq(currentBatch, startingBatchNumber); + } + + function test_V30UpgradeChainBatchNumber() public { + uint256 chainId = 271; + uint256 v30UpgradeBatchNumber = 100; + + vm.prank(bridgeHub); + messageRoot.setMigratingChainBatchRoot(chainId, 1, v30UpgradeBatchNumber); + + uint256 v30Batch = messageRoot.v30UpgradeChainBatchNumber(chainId); + assertEq(v30Batch, v30UpgradeBatchNumber); + } + + function test_AddChainBatchRoot_Success() public { + uint256 chainId = 271; + address chainSender = makeAddr("chainSender"); + bytes32 batchRoot = keccak256("batchRoot"); + + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.getZKChain.selector, chainId), + abi.encode(chainSender) + ); + + // Mock the getSemverProtocolVersion call + vm.mockCall( + chainSender, + abi.encodeWithSelector(IGetters.getSemverProtocolVersion.selector), + abi.encode(0, 29, 0) // major, minor, patch + ); + + vm.prank(bridgeHub); + messageRoot.addNewChain(chainId, 0); + + // Successfully add batch root + vm.prank(chainSender); + messageRoot.addChainBatchRoot(chainId, 1, batchRoot); + + // Verify batch root is stored + assertEq(messageRoot.chainBatchRoots(chainId, 1), batchRoot); + assertEq(messageRoot.currentChainBatchNumber(chainId), 1); + } + + function test_AddChainBatchRoot_ConsecutiveBatchNumber() public { + uint256 chainId = 271; + address chainSender = makeAddr("chainSender"); + bytes32 batchRoot1 = keccak256("batchRoot1"); + bytes32 batchRoot2 = keccak256("batchRoot2"); + + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.getZKChain.selector, chainId), + abi.encode(chainSender) + ); + + // Mock the getSemverProtocolVersion call + vm.mockCall( + chainSender, + abi.encodeWithSelector(IGetters.getSemverProtocolVersion.selector), + abi.encode(0, 29, 0) // major, minor, patch + ); + + vm.prank(bridgeHub); + messageRoot.addNewChain(chainId, 0); + + // Add first batch root + vm.prank(chainSender); + messageRoot.addChainBatchRoot(chainId, 1, batchRoot1); + + // Add second batch root + vm.prank(chainSender); + messageRoot.addChainBatchRoot(chainId, 2, batchRoot2); + + // Verify both batch roots are stored + assertEq(messageRoot.chainBatchRoots(chainId, 1), batchRoot1); + assertEq(messageRoot.chainBatchRoots(chainId, 2), batchRoot2); + assertEq(messageRoot.currentChainBatchNumber(chainId), 2); + } + + function test_UpdateFullTree() public { + uint256 chainId = 271; + address chainSender = makeAddr("chainSender"); + + vm.mockCall( + bridgeHub, + abi.encodeWithSelector(IBridgehubBase.getZKChain.selector, chainId), + abi.encode(chainSender) + ); + + // Mock the getSemverProtocolVersion call + vm.mockCall( + chainSender, + abi.encodeWithSelector(IGetters.getSemverProtocolVersion.selector), + abi.encode(0, 29, 0) // major, minor, patch + ); + + vm.prank(bridgeHub); + messageRoot.addNewChain(chainId, 0); + + // Add a batch root + vm.prank(chainSender); + messageRoot.addChainBatchRoot(chainId, 1, keccak256("batchRoot")); + + // Update the full tree + messageRoot.updateFullTree(); + + // Verify the aggregated root is updated + bytes32 root = messageRoot.getAggregatedRoot(); + assertTrue(root != bytes32(0)); + } + + function test_HistoricalRoot() public { + uint256 chainId = 271; + address chainSender = makeAddr("chainSender"); + + vm.mockCall( + L2_BRIDGEHUB_ADDR, + abi.encodeWithSelector(IBridgehubBase.getZKChain.selector, chainId), + abi.encode(chainSender) + ); + + // Mock the getSemverProtocolVersion call + vm.mockCall( + chainSender, + abi.encodeWithSelector(IGetters.getSemverProtocolVersion.selector), + abi.encode(0, 29, 0) // major, minor, patch + ); + + vm.prank(L2_BRIDGEHUB_ADDR); + l2MessageRoot.addNewChain(chainId, 0); + + // Add a batch root + vm.prank(GW_ASSET_TRACKER_ADDR); + l2MessageRoot.addChainBatchRoot(chainId, 1, keccak256("batchRoot")); + + // Check that historical root is set + bytes32 historicalRoot = l2MessageRoot.historicalRoot(block.number); + assertTrue(historicalRoot != bytes32(0)); + } +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/experimental_bridge.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/experimental_bridge.t.sol index 05936ead50..87da03f2bb 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/experimental_bridge.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridgehub/experimental_bridge.t.sol @@ -2,13 +2,15 @@ pragma solidity 0.8.28; -import {Vm} from "forge-std/Vm.sol"; +import {console2 as console} from "forge-std/Script.sol"; + import {StdStorage, Test, stdStorage} from "forge-std/Test.sol"; import "forge-std/console.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {TestnetERC20Token} from "contracts/dev-contracts/TestnetERC20Token.sol"; import {L1Bridgehub} from "contracts/bridgehub/L1Bridgehub.sol"; +import {IInteropCenter, InteropCenter} from "contracts/interop/InteropCenter.sol"; import {ChainCreationParams} from "contracts/state-transition/IChainTypeManager.sol"; import {L2TransactionRequestDirect, L2TransactionRequestTwoBridgesInner, L2TransactionRequestTwoBridgesOuter} from "contracts/bridgehub/IBridgehubBase.sol"; import {DummyChainTypeManagerWBH} from "contracts/dev-contracts/test/DummyChainTypeManagerWithBridgeHubAddress.sol"; @@ -22,7 +24,7 @@ import {L1NativeTokenVault} from "contracts/bridge/ntv/L1NativeTokenVault.sol"; import {L1Nullifier} from "contracts/bridge/L1Nullifier.sol"; import {BridgehubL2TransactionRequest, L2Log, L2Message, TxStatus} from "contracts/common/Messaging.sol"; -import {L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {L2_COMPLEX_UPGRADER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; import {Utils} from "../Utils/Utils.sol"; @@ -36,11 +38,16 @@ import {SecondBridgeAddressTooLow} from "contracts/bridgehub/L1BridgehubErrors.s import {AssetIdAlreadyRegistered, AssetIdNotSupported, BridgeHubAlreadyRegistered, CTMAlreadyRegistered, CTMNotRegistered, ChainIdTooBig, MsgValueMismatch, SharedBridgeNotSet, SlotOccupied, Unauthorized, WrongMagicValue, ZeroChainId} from "contracts/common/L1ContractErrors.sol"; import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {IL1AssetTracker, L1AssetTracker} from "contracts/bridge/asset-tracker/L1AssetTracker.sol"; + +import {IMessageVerification} from "contracts/common/MessageVerification.sol"; + contract ExperimentalBridgeTest is Test { using stdStorage for StdStorage; address weth; - L1Bridgehub bridgeHub; + L1Bridgehub bridgehub; + IInteropCenter interopCenter; DummyBridgehubSetter dummyBridgehub; address public bridgeOwner; address public testTokenAddress; @@ -57,6 +64,7 @@ contract ExperimentalBridgeTest is Test { L1NativeTokenVault ntv; IMessageRoot messageRoot; L1Nullifier l1Nullifier; + L1AssetTracker assetTracker; SimpleExecutor simpleExecutor; bytes32 tokenAssetId; @@ -74,6 +82,7 @@ contract ExperimentalBridgeTest is Test { uint256 l1ChainId; uint256 eraChainId; + uint256 gatewayChainId; address deployerAddress; @@ -102,27 +111,44 @@ contract ExperimentalBridgeTest is Test { function setUp() public { l1ChainId = 1; eraChainId = 320; + gatewayChainId = 506; deployerAddress = makeAddr("DEPLOYER_ADDRESS"); bridgeOwner = makeAddr("BRIDGE_OWNER"); dummyBridgehub = new DummyBridgehubSetter(bridgeOwner, type(uint256).max); - bridgeHub = L1Bridgehub(address(dummyBridgehub)); + bridgehub = L1Bridgehub(address(dummyBridgehub)); + interopCenter = new InteropCenter(); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + interopCenter.initL2(l1ChainId, bridgeOwner); + messageRoot = new L1MessageRoot(address(bridgehub), 1); weth = makeAddr("WETH"); - mockCTM = new DummyChainTypeManagerWBH(address(bridgeHub)); + mockCTM = new DummyChainTypeManagerWBH(address(bridgehub)); IEIP7702Checker eip7702Checker = IEIP7702Checker(Utils.deployEIP7702Checker()); - mockChainContract = new DummyZKChain(address(bridgeHub), eraChainId, block.chainid, eip7702Checker); + mockChainContract = new DummyZKChain(address(bridgehub), eraChainId, block.chainid, address(0), eip7702Checker); mockL2Contract = makeAddr("mockL2Contract"); // mocks to use in bridges instead of using a dummy one address mockL1WethAddress = makeAddr("Weth"); address eraDiamondProxy = makeAddr("eraDiamondProxy"); - l1Nullifier = new L1Nullifier(bridgeHub, eraChainId, eraDiamondProxy); + l1Nullifier = new L1Nullifier(bridgehub, messageRoot, eraChainId, eraDiamondProxy); l1NullifierAddress = address(l1Nullifier); mockSharedBridge = new DummySharedBridge(keccak256("0xabc")); mockSecondSharedBridge = new DummySharedBridge(keccak256("0xdef")); - ntv = _deployNTV(address(mockSharedBridge)); + // kl todo: clean this up. NTV id deployed below in deployNTV. its was a mess before this upgrade. + ntv = _deployNTVWithoutEthToken(address(mockSharedBridge)); + assetTracker = new L1AssetTracker( + block.chainid, + address(bridgehub), + address(mockSharedBridge), + address(ntv), + address(0) + ); + + vm.prank(bridgeOwner); + ntv.setAssetTracker(address(assetTracker)); + ntv.registerEthToken(); mockSecondSharedBridge.setNativeTokenVault(ntv); @@ -131,11 +157,11 @@ contract ExperimentalBridgeTest is Test { ntv.registerToken(address(testToken)); tokenAssetId = DataEncoding.encodeNTVAssetId(block.chainid, address(testToken)); - messageRoot = new L1MessageRoot(address(bridgeHub)); + messageRoot = new L1MessageRoot(address(bridgehub), gatewayChainId); sharedBridge = new L1AssetRouter( mockL1WethAddress, - address(bridgeHub), + address(bridgehub), l1NullifierAddress, eraChainId, eraDiamondProxy @@ -148,7 +174,7 @@ contract ExperimentalBridgeTest is Test { secondBridge = new L1AssetRouter( mockL1WethAddress, - address(bridgeHub), + address(bridgehub), l1NullifierAddress, eraChainId, eraDiamondProxy @@ -165,47 +191,70 @@ contract ExperimentalBridgeTest is Test { testToken6 = new TestnetERC20Token("USDC", "USD Coin", 6); testToken8 = new TestnetERC20Token("WBTC", "Wrapped Bitcoin", 8); - // test if the ownership of the bridgeHub is set correctly or not - defaultOwner = bridgeHub.owner(); + // test if the ownership of the bridgehub is set correctly or not + defaultOwner = bridgehub.owner(); // Now, the `reentrancyGuardInitializer` should prevent anyone from calling `initialize` since we have called the constructor of the contract vm.expectRevert(SlotOccupied.selector); - bridgeHub.initialize(bridgeOwner); + bridgehub.initialize(bridgeOwner); vm.store(address(mockChainContract), LOCK_FLAG_ADDRESS, bytes32(uint256(1))); bytes32 bridgehubLocation = bytes32(uint256(36)); - vm.store(address(mockChainContract), bridgehubLocation, bytes32(uint256(uint160(address(bridgeHub))))); + vm.store(address(mockChainContract), bridgehubLocation, bytes32(uint256(uint160(address(bridgehub))))); bytes32 baseTokenGasPriceNominatorLocation = bytes32(uint256(40)); vm.store(address(mockChainContract), baseTokenGasPriceNominatorLocation, bytes32(uint256(1))); bytes32 baseTokenGasPriceDenominatorLocation = bytes32(uint256(41)); vm.store(address(mockChainContract), baseTokenGasPriceDenominatorLocation, bytes32(uint256(1))); // The ownership can only be transferred by the current owner to a new owner via the two-step approach + vm.mockCall( + address(assetTracker), + abi.encodeWithSelector(IL1AssetTracker.handleChainBalanceIncreaseOnL1.selector), + abi.encode() + ); + // Default owner calls transferOwnership vm.prank(defaultOwner); - bridgeHub.transferOwnership(bridgeOwner); + bridgehub.transferOwnership(bridgeOwner); // bridgeOwner calls acceptOwnership vm.prank(bridgeOwner); - bridgeHub.acceptOwnership(); + bridgehub.acceptOwnership(); // Ownership should have changed - assertEq(bridgeHub.owner(), bridgeOwner); + assertEq(bridgehub.owner(), bridgeOwner); simpleExecutor = new SimpleExecutor(); } - function _deployNTV(address _sharedBridgeAddr) internal returns (L1NativeTokenVault addr) { + function _deployNTVWithoutEthToken(address _sharedBridgeAddr) internal returns (L1NativeTokenVault addr) { L1NativeTokenVault ntvImpl = new L1NativeTokenVault(weth, _sharedBridgeAddr, l1Nullifier); TransparentUpgradeableProxy ntvProxy = new TransparentUpgradeableProxy( address(ntvImpl), - address(bridgeOwner), + address(deployerAddress), abi.encodeCall(ntvImpl.initialize, (bridgeOwner, address(0))) ); addr = L1NativeTokenVault(payable(ntvProxy)); vm.prank(bridgeOwner); L1AssetRouter(_sharedBridgeAddr).setNativeTokenVault(addr); + } + + function _deployNTV(address _sharedBridgeAddr) internal returns (L1NativeTokenVault addr) { + addr = _deployNTVWithoutEthToken(_sharedBridgeAddr); + vm.prank(bridgeOwner); + addr.setAssetTracker(address(assetTracker)); + + L1AssetTracker assetTracker2 = new L1AssetTracker( + block.chainid, + address(bridgehub), + address(mockSharedBridge), + address(addr), + address(0) + ); + + vm.etch(address(assetTracker), address(assetTracker2).code); + console.log(address(ntv)); addr.registerEthToken(); } @@ -222,14 +271,21 @@ contract ExperimentalBridgeTest is Test { function _initializeBridgehub() internal { vm.prank(bridgeOwner); - bridgeHub.setPendingAdmin(deployerAddress); + bridgehub.setPendingAdmin(deployerAddress); vm.prank(deployerAddress); - bridgeHub.acceptAdmin(); + bridgehub.acceptAdmin(); vm.startPrank(bridgeOwner); - bridgeHub.addChainTypeManager(address(mockCTM)); - bridgeHub.addTokenAssetId(tokenAssetId); - bridgeHub.setAddresses(sharedBridgeAddress, ICTMDeploymentTracker(address(0)), messageRoot, address(0)); + bridgehub.addChainTypeManager(address(mockCTM)); + bridgehub.addTokenAssetId(tokenAssetId); + bridgehub.setAddresses( + sharedBridgeAddress, + ICTMDeploymentTracker(address(0)), + messageRoot, + address(0), + address(0) + ); + // interopCenter.setAddresses(sharedBridgeAddress, address(assetTracker)); vm.stopPrank(); vm.prank(l1Nullifier.owner()); @@ -241,77 +297,77 @@ contract ExperimentalBridgeTest is Test { function test_newPendingAdminReplacesPrevious(address randomDeployer, address otherRandomDeployer) public { vm.assume(randomDeployer != address(0)); vm.assume(otherRandomDeployer != address(0)); - assertEq(address(0), bridgeHub.admin()); + assertEq(address(0), bridgehub.admin()); vm.assume(randomDeployer != otherRandomDeployer); - vm.prank(bridgeHub.owner()); - bridgeHub.setPendingAdmin(randomDeployer); + vm.prank(bridgehub.owner()); + bridgehub.setPendingAdmin(randomDeployer); - vm.prank(bridgeHub.owner()); - bridgeHub.setPendingAdmin(otherRandomDeployer); + vm.prank(bridgehub.owner()); + bridgehub.setPendingAdmin(otherRandomDeployer); vm.prank(otherRandomDeployer); - bridgeHub.acceptAdmin(); + bridgehub.acceptAdmin(); - assertEq(otherRandomDeployer, bridgeHub.admin()); + assertEq(otherRandomDeployer, bridgehub.admin()); } function test_onlyPendingAdminCanAccept(address randomDeployer, address otherRandomDeployer) public { vm.assume(randomDeployer != address(0)); vm.assume(otherRandomDeployer != address(0)); - assertEq(address(0), bridgeHub.admin()); + assertEq(address(0), bridgehub.admin()); vm.assume(randomDeployer != otherRandomDeployer); - vm.prank(bridgeHub.owner()); - bridgeHub.setPendingAdmin(randomDeployer); + vm.prank(bridgehub.owner()); + bridgehub.setPendingAdmin(randomDeployer); vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, otherRandomDeployer)); vm.prank(otherRandomDeployer); - bridgeHub.acceptAdmin(); + bridgehub.acceptAdmin(); - assertEq(address(0), bridgeHub.admin()); + assertEq(address(0), bridgehub.admin()); } function test_onlyOwnerCanSetDeployer(address randomDeployer) public { vm.assume(randomDeployer != address(0)); - assertEq(address(0), bridgeHub.admin()); + assertEq(address(0), bridgehub.admin()); - vm.prank(bridgeHub.owner()); - bridgeHub.setPendingAdmin(randomDeployer); + vm.prank(bridgehub.owner()); + bridgehub.setPendingAdmin(randomDeployer); vm.prank(randomDeployer); - bridgeHub.acceptAdmin(); + bridgehub.acceptAdmin(); - assertEq(randomDeployer, bridgeHub.admin()); + assertEq(randomDeployer, bridgehub.admin()); } function test_randomCallerCannotSetDeployer(address randomCaller, address randomDeployer) public { - if (randomCaller != bridgeHub.owner() && randomCaller != bridgeHub.admin()) { + if (randomCaller != bridgehub.owner() && randomCaller != bridgehub.admin()) { vm.prank(randomCaller); vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomCaller)); - bridgeHub.setPendingAdmin(randomDeployer); + bridgehub.setPendingAdmin(randomDeployer); // The deployer shouldn't have changed. - assertEq(address(0), bridgeHub.admin()); + assertEq(address(0), bridgehub.admin()); } } function test_addChainTypeManager(address randomAddressWithoutTheCorrectInterface) public { vm.assume(randomAddressWithoutTheCorrectInterface != address(0)); - bool isCTMRegistered = bridgeHub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); + bool isCTMRegistered = bridgehub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); assertTrue(!isCTMRegistered); vm.prank(bridgeOwner); - bridgeHub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); + bridgehub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); - isCTMRegistered = bridgeHub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); + isCTMRegistered = bridgehub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); assertTrue(isCTMRegistered); // An address that has already been registered, cannot be registered again (at least not before calling `removeChainTypeManager`). vm.prank(bridgeOwner); vm.expectRevert(CTMAlreadyRegistered.selector); - bridgeHub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); + bridgehub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); - isCTMRegistered = bridgeHub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); + isCTMRegistered = bridgehub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); assertTrue(isCTMRegistered); } @@ -320,149 +376,150 @@ contract ExperimentalBridgeTest is Test { address randomAddressWithoutTheCorrectInterface ) public { vm.assume(randomAddressWithoutTheCorrectInterface != address(0)); - bool isCTMRegistered = bridgeHub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); + bool isCTMRegistered = bridgehub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); assertTrue(!isCTMRegistered); if (randomCaller != bridgeOwner) { vm.prank(randomCaller); vm.expectRevert(bytes("Ownable: caller is not the owner")); - bridgeHub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); + bridgehub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); } vm.prank(bridgeOwner); - bridgeHub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); + bridgehub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); - isCTMRegistered = bridgeHub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); + isCTMRegistered = bridgehub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); assertTrue(isCTMRegistered); // An address that has already been registered, cannot be registered again (at least not before calling `removeChainTypeManager`). vm.prank(bridgeOwner); vm.expectRevert(CTMAlreadyRegistered.selector); - bridgeHub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); + bridgehub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); // Definitely not by a random caller if (randomCaller != bridgeOwner) { vm.prank(randomCaller); vm.expectRevert("Ownable: caller is not the owner"); - bridgeHub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); + bridgehub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); } - isCTMRegistered = bridgeHub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); + isCTMRegistered = bridgehub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); assertTrue(isCTMRegistered); } - function test_removeChainTypeManager(address randomAddressWithoutTheCorrectInterface) public { - vm.assume(randomAddressWithoutTheCorrectInterface != address(0)); - bool isCTMRegistered = bridgeHub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); - assertTrue(!isCTMRegistered); - - // A non-existent CTM cannot be removed - vm.prank(bridgeOwner); - vm.expectRevert(CTMNotRegistered.selector); - bridgeHub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); - - // Let's first register our particular chainTypeManager - vm.prank(bridgeOwner); - bridgeHub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); - - isCTMRegistered = bridgeHub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); - assertTrue(isCTMRegistered); - - // Only an address that has already been registered, can be removed. - vm.prank(bridgeOwner); - bridgeHub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); - - isCTMRegistered = bridgeHub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); - assertTrue(!isCTMRegistered); - - // An already removed CTM cannot be removed again - vm.prank(bridgeOwner); - vm.expectRevert(CTMNotRegistered.selector); - bridgeHub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); - } - - function test_removeChainTypeManager_cannotBeCalledByRandomAddress( - address randomAddressWithoutTheCorrectInterface, - address randomCaller - ) public { - vm.assume(randomAddressWithoutTheCorrectInterface != address(0)); - bool isCTMRegistered = bridgeHub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); - assertTrue(!isCTMRegistered); - - if (randomCaller != bridgeOwner) { - vm.prank(randomCaller); - vm.expectRevert(bytes("Ownable: caller is not the owner")); - - bridgeHub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); - } - - // A non-existent CTM cannot be removed - vm.prank(bridgeOwner); - vm.expectRevert(CTMNotRegistered.selector); - bridgeHub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); - - // Let's first register our particular chainTypeManager - vm.prank(bridgeOwner); - bridgeHub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); - - isCTMRegistered = bridgeHub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); - assertTrue(isCTMRegistered); - - // Only an address that has already been registered, can be removed. - vm.prank(bridgeOwner); - bridgeHub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); - - isCTMRegistered = bridgeHub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); - assertTrue(!isCTMRegistered); - - // An already removed CTM cannot be removed again - vm.prank(bridgeOwner); - vm.expectRevert(CTMNotRegistered.selector); - bridgeHub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); - - // Not possible by a randomcaller as well - if (randomCaller != bridgeOwner) { - vm.prank(randomCaller); - vm.expectRevert(bytes("Ownable: caller is not the owner")); - bridgeHub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); - } - } + // function test_removeChainTypeManager(address randomAddressWithoutTheCorrectInterface) public { + // vm.assume(randomAddressWithoutTheCorrectInterface != address(0)); + // bool isCTMRegistered = bridgehub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); + // assertTrue(!isCTMRegistered); + + // // A non-existent CTM cannot be removed + // vm.prank(bridgeOwner); + // vm.expectRevert(CTMNotRegistered.selector); + // bridgehub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); + + // // Let's first register our particular chainTypeManager + // vm.prank(bridgeOwner); + // bridgehub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); + + // isCTMRegistered = bridgehub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); + // assertTrue(isCTMRegistered); + + // // Only an address that has already been registered, can be removed. + // vm.prank(bridgeOwner); + // bridgehub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); + + // isCTMRegistered = bridgehub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); + // assertTrue(!isCTMRegistered); + + // // An already removed CTM cannot be removed again + // vm.prank(bridgeOwner); + // vm.expectRevert(CTMNotRegistered.selector); + // bridgehub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); + // } + + // function test_removeChainTypeManager_cannotBeCalledByRandomAddress( + // address randomAddressWithoutTheCorrectInterface, + // address randomCaller + // ) public { + // vm.assume(randomAddressWithoutTheCorrectInterface != address(0)); + // bool isCTMRegistered = bridgehub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); + // assertTrue(!isCTMRegistered); + + // if (randomCaller != bridgeOwner) { + // vm.prank(randomCaller); + // vm.expectRevert(bytes("Ownable: caller is not the owner")); + + // bridgehub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); + // } + + // // A non-existent CTM cannot be removed + // vm.prank(bridgeOwner); + // vm.expectRevert(CTMNotRegistered.selector); + // bridgehub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); + + // // Let's first register our particular chainTypeManager + // vm.prank(bridgeOwner); + // bridgehub.addChainTypeManager(randomAddressWithoutTheCorrectInterface); + + // isCTMRegistered = bridgehub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); + // assertTrue(isCTMRegistered); + + // // Only an address that has already been registered, can be removed. + // vm.prank(bridgeOwner); + // bridgehub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); + + // isCTMRegistered = bridgehub.chainTypeManagerIsRegistered(randomAddressWithoutTheCorrectInterface); + // assertTrue(!isCTMRegistered); + + // // An already removed CTM cannot be removed again + // vm.prank(bridgeOwner); + // vm.expectRevert(CTMNotRegistered.selector); + // bridgehub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); + + // // Not possible by a randomcaller as well + // if (randomCaller != bridgeOwner) { + // vm.prank(randomCaller); + // vm.expectRevert(bytes("Ownable: caller is not the owner")); + // bridgehub.removeChainTypeManager(randomAddressWithoutTheCorrectInterface); + // } + // } function test_addAssetId(address randomAddress) public { vm.startPrank(bridgeOwner); - bridgeHub.setAddresses( + bridgehub.setAddresses( address(mockSharedBridge), ICTMDeploymentTracker(address(0)), IMessageRoot(address(0)), + address(0), address(0) ); vm.stopPrank(); bytes32 assetId = DataEncoding.encodeNTVAssetId(block.chainid, testTokenAddress); - assertTrue(!bridgeHub.assetIdIsRegistered(assetId), "This random address is not registered as a token"); + assertTrue(!bridgehub.assetIdIsRegistered(assetId), "This random address is not registered as a token"); vm.prank(bridgeOwner); - bridgeHub.addTokenAssetId(assetId); + bridgehub.addTokenAssetId(assetId); assertTrue( - bridgeHub.assetIdIsRegistered(assetId), + bridgehub.assetIdIsRegistered(assetId), "after call from the bridgeowner, this randomAddress should be a registered token" ); if (randomAddress != address(testTokenAddress)) { assetId = DataEncoding.encodeNTVAssetId(block.chainid, address(randomAddress)); - vm.assume(!bridgeHub.assetIdIsRegistered(assetId)); + vm.assume(!bridgehub.assetIdIsRegistered(assetId)); // Testing to see if a random address can also be added or not vm.prank(bridgeOwner); - bridgeHub.addTokenAssetId(assetId); - assertTrue(bridgeHub.assetIdIsRegistered(assetId)); + bridgehub.addTokenAssetId(assetId); + assertTrue(bridgehub.assetIdIsRegistered(assetId)); } // An already registered token cannot be registered again vm.prank(bridgeOwner); vm.expectRevert(AssetIdAlreadyRegistered.selector); - bridgeHub.addTokenAssetId(assetId); + bridgehub.addTokenAssetId(assetId); } function test_addAssetId_cannotBeCalledByRandomAddress( @@ -470,10 +527,11 @@ contract ExperimentalBridgeTest is Test { uint256 randomValue ) public useRandomToken(randomValue) { vm.startPrank(bridgeOwner); - bridgeHub.setAddresses( + bridgehub.setAddresses( address(mockSharedBridge), ICTMDeploymentTracker(address(0)), IMessageRoot(address(0)), + address(0), address(0) ); vm.stopPrank(); @@ -481,18 +539,18 @@ contract ExperimentalBridgeTest is Test { bytes32 assetId = DataEncoding.encodeNTVAssetId(block.chainid, testTokenAddress); vm.assume(randomCaller != bridgeOwner); - vm.assume(randomCaller != bridgeHub.admin()); + vm.assume(randomCaller != bridgehub.admin()); vm.prank(randomCaller); vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomCaller)); - bridgeHub.addTokenAssetId(assetId); + bridgehub.addTokenAssetId(assetId); - assertTrue(!bridgeHub.assetIdIsRegistered(assetId), "This random address is not registered as a token"); + assertTrue(!bridgehub.assetIdIsRegistered(assetId), "This random address is not registered as a token"); vm.prank(bridgeOwner); - bridgeHub.addTokenAssetId(assetId); + bridgehub.addTokenAssetId(assetId); assertTrue( - bridgeHub.assetIdIsRegistered(assetId), + bridgehub.assetIdIsRegistered(assetId), "after call from the bridgeowner, this testTokenAddress should be a registered token" ); @@ -500,29 +558,30 @@ contract ExperimentalBridgeTest is Test { if (randomCaller != bridgeOwner) { vm.prank(bridgeOwner); vm.expectRevert(AssetIdAlreadyRegistered.selector); - bridgeHub.addTokenAssetId(assetId); + bridgehub.addTokenAssetId(assetId); } } function test_setAddresses(address randomAssetRouter, address randomCTMDeployer, address randomMessageRoot) public { - assertTrue(address(bridgeHub.assetRouter()) == address(0), "Shared bridge is already there"); - assertTrue(bridgeHub.l1CtmDeployer() == ICTMDeploymentTracker(address(0)), "L1 CTM deployer is already there"); - assertTrue(bridgeHub.messageRoot() == IMessageRoot(address(0)), "Message root is already there"); + assertTrue(address(bridgehub.assetRouter()) == address(0), "Shared bridge is already there"); + assertTrue(bridgehub.l1CtmDeployer() == ICTMDeploymentTracker(address(0)), "L1 CTM deployer is already there"); + assertTrue(bridgehub.messageRoot() == IMessageRoot(address(0)), "Message root is already there"); vm.prank(bridgeOwner); - bridgeHub.setAddresses( + bridgehub.setAddresses( randomAssetRouter, ICTMDeploymentTracker(randomCTMDeployer), IMessageRoot(randomMessageRoot), + address(0), address(0) ); - assertTrue(address(bridgeHub.assetRouter()) == randomAssetRouter, "Shared bridge is already there"); + assertTrue(address(bridgehub.assetRouter()) == randomAssetRouter, "Shared bridge is already there"); assertTrue( - bridgeHub.l1CtmDeployer() == ICTMDeploymentTracker(randomCTMDeployer), + bridgehub.l1CtmDeployer() == ICTMDeploymentTracker(randomCTMDeployer), "L1 CTM deployer is already there" ); - assertTrue(bridgeHub.messageRoot() == IMessageRoot(randomMessageRoot), "Message root is already there"); + assertTrue(bridgehub.messageRoot() == IMessageRoot(randomMessageRoot), "Message root is already there"); } function test_setAddresses_cannotBeCalledByRandomAddress( @@ -531,20 +590,21 @@ contract ExperimentalBridgeTest is Test { address randomCTMDeployer, address randomMessageRoot ) public { - vm.assume(randomCaller != bridgeOwner); + vm.assume(randomCaller != bridgeOwner && randomCaller != L2_COMPLEX_UPGRADER_ADDR); vm.prank(randomCaller); vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomCaller)); - bridgeHub.setAddresses( + bridgehub.setAddresses( randomAssetRouter, ICTMDeploymentTracker(randomCTMDeployer), IMessageRoot(randomMessageRoot), + address(0), address(0) ); - assertTrue(address(bridgeHub.assetRouter()) == address(0), "Shared bridge is already there"); - assertTrue(bridgeHub.l1CtmDeployer() == ICTMDeploymentTracker(address(0)), "L1 CTM deployer is already there"); - assertTrue(bridgeHub.messageRoot() == IMessageRoot(address(0)), "Message root is already there"); + assertTrue(address(bridgehub.assetRouter()) == address(0), "Shared bridge is already there"); + assertTrue(bridgehub.l1CtmDeployer() == ICTMDeploymentTracker(address(0)), "L1 CTM deployer is already there"); + assertTrue(bridgehub.messageRoot() == IMessageRoot(address(0)), "Message root is already there"); } uint256 newChainId; @@ -561,11 +621,11 @@ contract ExperimentalBridgeTest is Test { admin = makeAddr("NEW_CHAIN_ADMIN"); vm.prank(bridgeOwner); - bridgeHub.pause(); + bridgehub.pause(); vm.prank(bridgeOwner); - bridgeHub.setPendingAdmin(deployerAddress); + bridgehub.setPendingAdmin(deployerAddress); vm.prank(deployerAddress); - bridgeHub.acceptAdmin(); + bridgehub.acceptAdmin(); // ntv.registerToken(address(testToken)); @@ -576,7 +636,7 @@ contract ExperimentalBridgeTest is Test { vm.expectRevert("Pausable: paused"); vm.prank(deployerAddress); - bridgeHub.createNewChain({ + bridgehub.createNewChain({ _chainId: chainId, _chainTypeManager: address(mockCTM), _baseTokenAssetId: tokenAssetId, @@ -587,11 +647,11 @@ contract ExperimentalBridgeTest is Test { }); vm.prank(bridgeOwner); - bridgeHub.unpause(); + bridgehub.unpause(); vm.expectRevert(CTMNotRegistered.selector); vm.prank(deployerAddress); - bridgeHub.createNewChain({ + bridgehub.createNewChain({ _chainId: chainId, _chainTypeManager: address(mockCTM), _baseTokenAssetId: tokenAssetId, @@ -613,14 +673,14 @@ contract ExperimentalBridgeTest is Test { admin = makeAddr("NEW_CHAIN_ADMIN"); vm.prank(bridgeOwner); - bridgeHub.setPendingAdmin(deployerAddress); + bridgehub.setPendingAdmin(deployerAddress); vm.prank(deployerAddress); - bridgeHub.acceptAdmin(); + bridgehub.acceptAdmin(); chainId = bound(chainId, 1, type(uint48).max); vm.expectRevert(CTMNotRegistered.selector); vm.prank(deployerAddress); - bridgeHub.createNewChain({ + bridgehub.createNewChain({ _chainId: chainId, _chainTypeManager: address(mockCTM), _baseTokenAssetId: tokenAssetId, @@ -642,14 +702,14 @@ contract ExperimentalBridgeTest is Test { admin = makeAddr("NEW_CHAIN_ADMIN"); vm.prank(bridgeOwner); - bridgeHub.setPendingAdmin(deployerAddress); + bridgehub.setPendingAdmin(deployerAddress); vm.prank(deployerAddress); - bridgeHub.acceptAdmin(); + bridgehub.acceptAdmin(); chainId = bound(chainId, type(uint48).max + uint256(1), type(uint256).max); vm.expectRevert(ChainIdTooBig.selector); vm.prank(deployerAddress); - bridgeHub.createNewChain({ + bridgehub.createNewChain({ _chainId: chainId, _chainTypeManager: address(mockCTM), _baseTokenAssetId: tokenAssetId, @@ -662,7 +722,7 @@ contract ExperimentalBridgeTest is Test { chainId = 0; vm.expectRevert(ZeroChainId.selector); vm.prank(deployerAddress); - bridgeHub.createNewChain({ + bridgehub.createNewChain({ _chainId: chainId, _chainTypeManager: address(mockCTM), _baseTokenAssetId: tokenAssetId, @@ -684,17 +744,17 @@ contract ExperimentalBridgeTest is Test { admin = makeAddr("NEW_CHAIN_ADMIN"); vm.prank(bridgeOwner); - bridgeHub.setPendingAdmin(deployerAddress); + bridgehub.setPendingAdmin(deployerAddress); vm.prank(deployerAddress); - bridgeHub.acceptAdmin(); + bridgehub.acceptAdmin(); vm.startPrank(bridgeOwner); - bridgeHub.addChainTypeManager(address(mockCTM)); + bridgehub.addChainTypeManager(address(mockCTM)); vm.stopPrank(); vm.expectRevert(abi.encodeWithSelector(AssetIdNotSupported.selector, tokenAssetId)); vm.prank(deployerAddress); - bridgeHub.createNewChain({ + bridgehub.createNewChain({ _chainId: chainId, _chainTypeManager: address(mockCTM), _baseTokenAssetId: tokenAssetId, @@ -715,18 +775,18 @@ contract ExperimentalBridgeTest is Test { admin = makeAddr("NEW_CHAIN_ADMIN"); vm.prank(bridgeOwner); - bridgeHub.setPendingAdmin(deployerAddress); + bridgehub.setPendingAdmin(deployerAddress); vm.prank(deployerAddress); - bridgeHub.acceptAdmin(); + bridgehub.acceptAdmin(); vm.startPrank(bridgeOwner); - bridgeHub.addChainTypeManager(address(mockCTM)); - bridgeHub.addTokenAssetId(tokenAssetId); + bridgehub.addChainTypeManager(address(mockCTM)); + bridgehub.addTokenAssetId(tokenAssetId); vm.stopPrank(); vm.expectRevert(SharedBridgeNotSet.selector); vm.prank(deployerAddress); - bridgeHub.createNewChain({ + bridgehub.createNewChain({ _chainId: chainId, _chainTypeManager: address(mockCTM), _baseTokenAssetId: tokenAssetId, @@ -748,13 +808,13 @@ contract ExperimentalBridgeTest is Test { chainId = bound(chainId, 1, type(uint48).max); vm.assume(chainId != block.chainid); - stdstore.target(address(bridgeHub)).sig("chainTypeManager(uint256)").with_key(chainId).checked_write( + stdstore.target(address(bridgehub)).sig("chainTypeManager(uint256)").with_key(chainId).checked_write( address(mockCTM) ); vm.expectRevert(BridgeHubAlreadyRegistered.selector); vm.prank(deployerAddress); - bridgeHub.createNewChain({ + bridgehub.createNewChain({ _chainId: chainId, _chainTypeManager: address(mockCTM), _baseTokenAssetId: tokenAssetId, @@ -783,7 +843,7 @@ contract ExperimentalBridgeTest is Test { vm.prank(randomCaller); vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomCaller)); - bridgeHub.createNewChain({ + bridgehub.createNewChain({ _chainId: chainId, _chainTypeManager: address(mockCTM), _baseTokenAssetId: tokenAssetId, @@ -795,7 +855,7 @@ contract ExperimentalBridgeTest is Test { vm.prank(mockCTM.owner()); - // bridgeHub.createNewChain => chainTypeManager.createNewChain => this function sets the stateTransition mapping + // bridgehub.createNewChain => chainTypeManager.createNewChain => this function sets the stateTransition mapping // of `chainId`, let's emulate that using foundry cheatcodes or let's just use the extra function we introduced in our mockCTM mockCTM.setZKChain(chainId, address(mockChainContract)); @@ -814,10 +874,10 @@ contract ExperimentalBridgeTest is Test { abi.encode(newChainAddress) ); - vm.expectEmit(true, true, true, true, address(bridgeHub)); + vm.expectEmit(true, true, true, true, address(bridgehub)); emit NewChain(chainId, address(mockCTM), admin); - bridgeHub.createNewChain({ + bridgehub.createNewChain({ _chainId: chainId, _chainTypeManager: address(mockCTM), _baseTokenAssetId: tokenAssetId, @@ -830,12 +890,12 @@ contract ExperimentalBridgeTest is Test { vm.stopPrank(); vm.clearMockedCalls(); - assertTrue(bridgeHub.chainTypeManager(chainId) == address(mockCTM)); - assertTrue(bridgeHub.baseTokenAssetId(chainId) == tokenAssetId); - assertTrue(bridgeHub.getZKChain(chainId) == newChainAddress); + assertTrue(bridgehub.chainTypeManager(chainId) == address(mockCTM)); + assertTrue(bridgehub.baseTokenAssetId(chainId) == tokenAssetId); + assertTrue(bridgehub.getZKChain(chainId) == newChainAddress); } - function test_proveL2MessageInclusion( + function test_proveL2MessageInclusion_new( uint256 mockChainId, uint256 mockBatchNumber, uint256 mockIndex, @@ -844,32 +904,27 @@ contract ExperimentalBridgeTest is Test { address randomSender, bytes memory randomData ) public { + _initializeBridgehub(); mockChainId = _setUpZKChainForChainId(mockChainId); // Now the following statements should be true as well: - assertTrue(bridgeHub.chainTypeManager(mockChainId) == address(mockCTM)); - assertTrue(bridgeHub.getZKChain(mockChainId) == address(mockChainContract)); + assertTrue(bridgehub.chainTypeManager(mockChainId) == address(mockCTM)); + assertTrue(bridgehub.getZKChain(mockChainId) == address(mockChainContract)); // Creating a random L2Message::l2Message so that we pass the correct parameters to `proveL2MessageInclusion` L2Message memory l2Message = _createMockL2Message(randomTxNumInBatch, randomSender, randomData); - // Since we have used random data for the `bridgeHub.proveL2MessageInclusion` function which basically forwards the call + // Since we have used random data for the `InteropCenter.proveL2MessageInclusion` function which basically forwards the call // to the same function in the mailbox, we will mock the call to the mailbox to return true and see if it works. vm.mockCall( - address(mockChainContract), + address(messageRoot), // solhint-disable-next-line func-named-parameters - abi.encodeWithSelector( - mockChainContract.proveL2MessageInclusion.selector, - mockBatchNumber, - mockIndex, - l2Message, - mockProof - ), + abi.encodeWithSelector(IMessageVerification.proveL2MessageInclusionShared.selector), abi.encode(true) ); assertTrue( - bridgeHub.proveL2MessageInclusion({ + bridgehub.proveL2MessageInclusion({ _chainId: mockChainId, _batchNumber: mockBatchNumber, _index: mockIndex, @@ -880,7 +935,7 @@ contract ExperimentalBridgeTest is Test { vm.clearMockedCalls(); } - function test_proveL2LogInclusion( + function test_proveL2LogInclusion_new( uint256 mockChainId, uint256 mockBatchNumber, uint256 mockIndex, @@ -892,11 +947,12 @@ contract ExperimentalBridgeTest is Test { bytes32 randomKey, bytes32 randomValue ) public { + _initializeBridgehub(); mockChainId = _setUpZKChainForChainId(mockChainId); // Now the following statements should be true as well: - assertTrue(bridgeHub.chainTypeManager(mockChainId) == address(mockCTM)); - assertTrue(bridgeHub.getZKChain(mockChainId) == address(mockChainContract)); + assertTrue(bridgehub.chainTypeManager(mockChainId) == address(mockCTM)); + assertTrue(bridgehub.getZKChain(mockChainId) == address(mockChainContract)); // Creating a random L2Log::l2Log so that we pass the correct parameters to `proveL2LogInclusion` L2Log memory l2Log = _createMockL2Log({ @@ -908,23 +964,17 @@ contract ExperimentalBridgeTest is Test { randomValue: randomValue }); - // Since we have used random data for the `bridgeHub.proveL2LogInclusion` function which basically forwards the call + // Since we have used random data for the `interopCenter.proveL2LogInclusion` function which basically forwards the call // to the same function in the mailbox, we will mock the call to the mailbox to return true and see if it works. vm.mockCall( - address(mockChainContract), + address(messageRoot), // solhint-disable-next-line func-named-parameters - abi.encodeWithSelector( - mockChainContract.proveL2LogInclusion.selector, - mockBatchNumber, - mockIndex, - l2Log, - mockProof - ), + abi.encodeWithSelector(IMessageVerification.proveL2LogInclusionShared.selector), abi.encode(true) ); assertTrue( - bridgeHub.proveL2LogInclusion({ + bridgehub.proveL2LogInclusion({ _chainId: mockChainId, _batchNumber: mockBatchNumber, _index: mockIndex, @@ -935,7 +985,7 @@ contract ExperimentalBridgeTest is Test { vm.clearMockedCalls(); } - function test_proveL1ToL2TransactionStatus( + function test_proveL1ToL2TransactionStatus_new( uint256 randomChainId, bytes32 randomL2TxHash, uint256 randomL2BatchNumber, @@ -945,6 +995,7 @@ contract ExperimentalBridgeTest is Test { bool randomResultantBool, bool txStatusBool ) public { + _initializeBridgehub(); randomChainId = _setUpZKChainForChainId(randomChainId); TxStatus txStatus; @@ -956,22 +1007,14 @@ contract ExperimentalBridgeTest is Test { } vm.mockCall( - address(mockChainContract), + address(messageRoot), // solhint-disable-next-line func-named-parameters - abi.encodeWithSelector( - mockChainContract.proveL1ToL2TransactionStatus.selector, - randomL2TxHash, - randomL2BatchNumber, - randomL2MessageIndex, - randomL2TxNumberInBatch, - randomMerkleProof, - txStatus - ), + abi.encodeWithSelector(IMessageVerification.proveL1ToL2TransactionStatusShared.selector), abi.encode(randomResultantBool) ); assertTrue( - bridgeHub.proveL1ToL2TransactionStatus({ + bridgehub.proveL1ToL2TransactionStatus({ _chainId: randomChainId, _l2TxHash: randomL2TxHash, _l2BatchNumber: randomL2BatchNumber, @@ -1005,7 +1048,7 @@ contract ExperimentalBridgeTest is Test { ); assertTrue( - bridgeHub.l2TransactionBaseCost(mockChainId, mockGasPrice, mockL2GasLimit, mockL2GasPerPubdataByteLimit) == + bridgehub.l2TransactionBaseCost(mockChainId, mockGasPrice, mockL2GasLimit, mockL2GasPerPubdataByteLimit) == mockL2TxnCost ); vm.clearMockedCalls(); @@ -1038,14 +1081,14 @@ contract ExperimentalBridgeTest is Test { l2TxnReqDirect.chainId = _setUpZKChainForChainId(l2TxnReqDirect.chainId); - assertTrue(bridgeHub.baseTokenAssetId(l2TxnReqDirect.chainId) != ETH_TOKEN_ASSET_ID); + assertTrue(bridgehub.baseTokenAssetId(l2TxnReqDirect.chainId) != ETH_TOKEN_ASSET_ID); _setUpBaseTokenForChainId(l2TxnReqDirect.chainId, true, address(0)); - assertTrue(bridgeHub.baseTokenAssetId(l2TxnReqDirect.chainId) == ETH_TOKEN_ASSET_ID); - console.log(IL1AssetRouter(address(bridgeHub.assetRouter())).assetHandlerAddress(ETH_TOKEN_ASSET_ID)); - assertTrue(bridgeHub.baseToken(l2TxnReqDirect.chainId) == ETH_TOKEN_ADDRESS); + assertTrue(bridgehub.baseTokenAssetId(l2TxnReqDirect.chainId) == ETH_TOKEN_ASSET_ID); + console.log(bridgehub.assetRouter().assetHandlerAddress(ETH_TOKEN_ASSET_ID)); + assertTrue(bridgehub.baseToken(l2TxnReqDirect.chainId) == ETH_TOKEN_ADDRESS); - assertTrue(bridgeHub.getZKChain(l2TxnReqDirect.chainId) == address(mockChainContract)); + assertTrue(bridgehub.getZKChain(l2TxnReqDirect.chainId) == address(mockChainContract)); canonicalHash = keccak256(abi.encode("CANONICAL_TX_HASH")); vm.mockCall( @@ -1056,8 +1099,8 @@ contract ExperimentalBridgeTest is Test { mockChainContract.setFeeParams(); mockChainContract.setBaseTokenGasMultiplierPrice(uint128(1), uint128(1)); - mockChainContract.setBridgeHubAddress(address(bridgeHub)); - assertTrue(mockChainContract.getBridgeHubAddress() == address(bridgeHub)); + mockChainContract.setBridgeHubAddress(address(bridgehub)); + assertTrue(mockChainContract.getBridgeHubAddress() == address(bridgehub)); } function test_requestL2TransactionDirect_RevertWhen_incorrectETHParams( @@ -1092,7 +1135,7 @@ contract ExperimentalBridgeTest is Test { vm.deal(randomCaller, msgValue); vm.expectRevert(abi.encodeWithSelector(MsgValueMismatch.selector, mockMintValue, msgValue)); vm.prank(randomCaller); - bridgeHub.requestL2TransactionDirect{value: msgValue}(l2TxnReqDirect); + bridgehub.requestL2TransactionDirect{value: msgValue}(l2TxnReqDirect); } function test_requestL2TransactionDirect_ETHCase( @@ -1128,7 +1171,7 @@ contract ExperimentalBridgeTest is Test { gasPrice = bound(gasPrice, 1_000, 50_000_000); vm.txGasPrice(gasPrice * 1 gwei); vm.prank(randomCaller); - bytes32 resultantHash = bridgeHub.requestL2TransactionDirect{value: randomCaller.balance}(l2TxnReqDirect); + bytes32 resultantHash = bridgehub.requestL2TransactionDirect{value: randomCaller.balance}(l2TxnReqDirect); assertTrue(resultantHash == hash); } @@ -1170,7 +1213,7 @@ contract ExperimentalBridgeTest is Test { _setUpBaseTokenForChainId(l2TxnReqDirect.chainId, false, address(testToken)); - assertTrue(bridgeHub.getZKChain(l2TxnReqDirect.chainId) == address(mockChainContract)); + assertTrue(bridgehub.getZKChain(l2TxnReqDirect.chainId) == address(mockChainContract)); bytes32 canonicalHash = keccak256(abi.encode("CANONICAL_TX_HASH")); vm.mockCall( @@ -1181,8 +1224,8 @@ contract ExperimentalBridgeTest is Test { mockChainContract.setFeeParams(); mockChainContract.setBaseTokenGasMultiplierPrice(uint128(1), uint128(1)); - mockChainContract.setBridgeHubAddress(address(bridgeHub)); - assertTrue(mockChainContract.getBridgeHubAddress() == address(bridgeHub)); + mockChainContract.setBridgeHubAddress(address(bridgehub)); + assertTrue(mockChainContract.getBridgeHubAddress() == address(bridgehub)); gasPrice = bound(gasPrice, 1_000, 50_000_000); vm.txGasPrice(gasPrice * 1 gwei); @@ -1190,7 +1233,7 @@ contract ExperimentalBridgeTest is Test { vm.deal(randomCaller, 1 ether); vm.prank(randomCaller); vm.expectRevert(abi.encodeWithSelector(MsgValueMismatch.selector, 0, randomCaller.balance)); - bytes32 resultantHash = bridgeHub.requestL2TransactionDirect{value: randomCaller.balance}(l2TxnReqDirect); + bytes32 resultantHash = bridgehub.requestL2TransactionDirect{value: randomCaller.balance}(l2TxnReqDirect); // Now, let's call the same function with zero msg.value testToken.mint(randomCaller, l2TxnReqDirect.mintValue); @@ -1201,7 +1244,7 @@ contract ExperimentalBridgeTest is Test { assertEq(testToken.balanceOf(address(this)), l2TxnReqDirect.mintValue); testToken.approve(sharedBridgeAddress, l2TxnReqDirect.mintValue); - resultantHash = bridgeHub.requestL2TransactionDirect(l2TxnReqDirect); + resultantHash = bridgehub.requestL2TransactionDirect(l2TxnReqDirect); assertEq(canonicalHash, resultantHash); } @@ -1245,7 +1288,7 @@ contract ExperimentalBridgeTest is Test { _setUpBaseTokenForChainId(l2TxnReqDirect.chainId, false, address(testToken)); - assertTrue(bridgeHub.getZKChain(l2TxnReqDirect.chainId) == address(mockChainContract)); + assertTrue(bridgehub.getZKChain(l2TxnReqDirect.chainId) == address(mockChainContract)); bytes32 canonicalHash = keccak256(abi.encode("CANONICAL_TX_HASH")); vm.mockCall( @@ -1256,8 +1299,8 @@ contract ExperimentalBridgeTest is Test { mockChainContract.setFeeParams(); mockChainContract.setBaseTokenGasMultiplierPrice(uint128(1), uint128(1)); - mockChainContract.setBridgeHubAddress(address(bridgeHub)); - assertTrue(mockChainContract.getBridgeHubAddress() == address(bridgeHub)); + mockChainContract.setBridgeHubAddress(address(bridgehub)); + assertTrue(mockChainContract.getBridgeHubAddress() == address(bridgehub)); gasPrice = bound(gasPrice, 1_000, 50_000_000); vm.txGasPrice(gasPrice * 1 gwei); @@ -1269,7 +1312,7 @@ contract ExperimentalBridgeTest is Test { assertEq(testToken.balanceOf(randomCaller), l2TxnReqDirect.mintValue); bytes memory calldataForExecutor = abi.encodeWithSelector( - bridgeHub.requestL2TransactionDirect.selector, + bridgehub.requestL2TransactionDirect.selector, l2TxnReqDirect ); @@ -1279,7 +1322,7 @@ contract ExperimentalBridgeTest is Test { testToken.approve(sharedBridgeAddress, l2TxnReqDirect.mintValue); assertEq(testToken.allowance(randomCaller, sharedBridgeAddress), l2TxnReqDirect.mintValue); vm.signAndAttachDelegation(address(simpleExecutor), randomCallerPk); - SimpleExecutor(randomCaller).execute(address(bridgeHub), 0, calldataForExecutor); + SimpleExecutor(randomCaller).execute(address(bridgehub), 0, calldataForExecutor); } function test_requestTransactionTwoBridgesChecksMagicValue( @@ -1314,9 +1357,9 @@ contract ExperimentalBridgeTest is Test { l2TxnReq2BridgeOut.chainId = _setUpZKChainForChainId(l2TxnReq2BridgeOut.chainId); _setUpBaseTokenForChainId(l2TxnReq2BridgeOut.chainId, true, address(0)); - assertTrue(bridgeHub.baseToken(l2TxnReq2BridgeOut.chainId) == ETH_TOKEN_ADDRESS); + assertTrue(bridgehub.baseToken(l2TxnReq2BridgeOut.chainId) == ETH_TOKEN_ADDRESS); - assertTrue(bridgeHub.getZKChain(l2TxnReq2BridgeOut.chainId) == address(mockChainContract)); + assertTrue(bridgehub.getZKChain(l2TxnReq2BridgeOut.chainId) == address(mockChainContract)); uint256 callerMsgValue = l2TxnReq2BridgeOut.mintValue + l2TxnReq2BridgeOut.secondBridgeValue; address randomCaller = makeAddr("RANDOM_CALLER"); @@ -1338,7 +1381,7 @@ contract ExperimentalBridgeTest is Test { vm.expectRevert(abi.encodeWithSelector(WrongMagicValue.selector, TWO_BRIDGES_MAGIC_VALUE, magicValue)); vm.prank(randomCaller); - bridgeHub.requestL2TransactionTwoBridges{value: randomCaller.balance}(l2TxnReq2BridgeOut); + bridgehub.requestL2TransactionTwoBridges{value: randomCaller.balance}(l2TxnReq2BridgeOut); } function test_requestL2TransactionTwoBridgesWrongBridgeAddress( @@ -1372,15 +1415,15 @@ contract ExperimentalBridgeTest is Test { l2TxnReq2BridgeOut.chainId = _setUpZKChainForChainId(l2TxnReq2BridgeOut.chainId); _setUpBaseTokenForChainId(l2TxnReq2BridgeOut.chainId, true, address(0)); - assertTrue(bridgeHub.baseToken(l2TxnReq2BridgeOut.chainId) == ETH_TOKEN_ADDRESS); + assertTrue(bridgehub.baseToken(l2TxnReq2BridgeOut.chainId) == ETH_TOKEN_ADDRESS); - assertTrue(bridgeHub.getZKChain(l2TxnReq2BridgeOut.chainId) == address(mockChainContract)); + assertTrue(bridgehub.getZKChain(l2TxnReq2BridgeOut.chainId) == address(mockChainContract)); uint256 callerMsgValue = l2TxnReq2BridgeOut.mintValue + l2TxnReq2BridgeOut.secondBridgeValue; address randomCaller = makeAddr("RANDOM_CALLER"); vm.deal(randomCaller, callerMsgValue); - mockChainContract.setBridgeHubAddress(address(bridgeHub)); + mockChainContract.setBridgeHubAddress(address(bridgehub)); bytes32 canonicalHash = keccak256(abi.encode("CANONICAL_TX_HASH")); @@ -1422,7 +1465,7 @@ contract ExperimentalBridgeTest is Test { ) ); vm.prank(randomCaller); - bridgeHub.requestL2TransactionTwoBridges{value: randomCaller.balance}(l2TxnReq2BridgeOut); + bridgehub.requestL2TransactionTwoBridges{value: randomCaller.balance}(l2TxnReq2BridgeOut); } function test_requestL2TransactionTwoBridges_ERC20ToNonBase( @@ -1461,9 +1504,9 @@ contract ExperimentalBridgeTest is Test { bytes32 canonicalHash = keccak256(abi.encode("CANONICAL_TX_HASH")); _setUpBaseTokenForChainId(l2TxnReq2BridgeOut.chainId, false, address(testToken)); - assertTrue(bridgeHub.baseToken(l2TxnReq2BridgeOut.chainId) == address(testToken)); - assertTrue(bridgeHub.getZKChain(l2TxnReq2BridgeOut.chainId) == address(mockChainContract)); - mockChainContract.setBridgeHubAddress(address(bridgeHub)); + assertTrue(bridgehub.baseToken(l2TxnReq2BridgeOut.chainId) == address(testToken)); + assertTrue(bridgehub.getZKChain(l2TxnReq2BridgeOut.chainId) == address(mockChainContract)); + mockChainContract.setBridgeHubAddress(address(bridgehub)); vm.mockCall( address(mockChainContract), @@ -1482,7 +1525,7 @@ contract ExperimentalBridgeTest is Test { erc20Token.approve(secondBridgeAddress, l2Value); vm.stopPrank(); vm.prank(randomCaller); - bytes32 resultHash = bridgeHub.requestL2TransactionTwoBridges(l2TxnReq2BridgeOut); + bytes32 resultHash = bridgehub.requestL2TransactionTwoBridges(l2TxnReq2BridgeOut); assertEq(resultHash, canonicalHash); assertEq(erc20Token.balanceOf(randomCaller), 0); @@ -1495,7 +1538,7 @@ contract ExperimentalBridgeTest is Test { vm.startPrank(randomCaller); testToken.approve(sharedBridgeAddress, l2TxnReq2BridgeOut.mintValue); vm.expectRevert(abi.encodeWithSelector(MsgValueMismatch.selector, l2TxnReq2BridgeOut.secondBridgeValue, 0)); - bridgeHub.requestL2TransactionTwoBridges(l2TxnReq2BridgeOut); + bridgehub.requestL2TransactionTwoBridges(l2TxnReq2BridgeOut); vm.stopPrank(); } @@ -1531,12 +1574,12 @@ contract ExperimentalBridgeTest is Test { }); _setUpBaseTokenForChainId(l2TxnReq2BridgeOut.chainId, false, address(testToken)); - assertTrue(bridgeHub.baseToken(l2TxnReq2BridgeOut.chainId) == address(testToken)); - assertTrue(bridgeHub.getZKChain(l2TxnReq2BridgeOut.chainId) == address(mockChainContract)); + assertTrue(bridgehub.baseToken(l2TxnReq2BridgeOut.chainId) == address(testToken)); + assertTrue(bridgehub.getZKChain(l2TxnReq2BridgeOut.chainId) == address(mockChainContract)); address randomCaller = makeAddr("RANDOM_CALLER"); - mockChainContract.setBridgeHubAddress(address(bridgeHub)); + mockChainContract.setBridgeHubAddress(address(bridgehub)); { bytes32 canonicalHash = keccak256(abi.encode("CANONICAL_TX_HASH")); @@ -1548,23 +1591,24 @@ contract ExperimentalBridgeTest is Test { ); } + // kl todo this was copied up. + testToken.mint(randomCaller, l2TxnReq2BridgeOut.mintValue); + assertEq(testToken.balanceOf(randomCaller), l2TxnReq2BridgeOut.mintValue); + vm.prank(randomCaller); + testToken.approve(sharedBridgeAddress, l2TxnReq2BridgeOut.mintValue); + if (msgValue != secondBridgeValue) { vm.deal(randomCaller, msgValue); vm.expectRevert( abi.encodeWithSelector(MsgValueMismatch.selector, l2TxnReq2BridgeOut.secondBridgeValue, msgValue) ); vm.prank(randomCaller); - bridgeHub.requestL2TransactionTwoBridges{value: msgValue}(l2TxnReq2BridgeOut); + bridgehub.requestL2TransactionTwoBridges{value: msgValue}(l2TxnReq2BridgeOut); } - testToken.mint(randomCaller, l2TxnReq2BridgeOut.mintValue); - assertEq(testToken.balanceOf(randomCaller), l2TxnReq2BridgeOut.mintValue); - vm.prank(randomCaller); - testToken.approve(sharedBridgeAddress, l2TxnReq2BridgeOut.mintValue); - vm.deal(randomCaller, l2TxnReq2BridgeOut.secondBridgeValue); vm.prank(randomCaller); - bridgeHub.requestL2TransactionTwoBridges{value: randomCaller.balance}(l2TxnReq2BridgeOut); + bridgehub.requestL2TransactionTwoBridges{value: randomCaller.balance}(l2TxnReq2BridgeOut); } ///////////////////////////////////////////////////////// @@ -1681,15 +1725,15 @@ contract ExperimentalBridgeTest is Test { mockChainId = bound(mockChainId, 1, type(uint48).max); mockChainIdInRange = mockChainId; - if (!bridgeHub.chainTypeManagerIsRegistered(address(mockCTM))) { + if (!bridgehub.chainTypeManagerIsRegistered(address(mockCTM))) { vm.prank(bridgeOwner); - bridgeHub.addChainTypeManager(address(mockCTM)); + bridgehub.addChainTypeManager(address(mockCTM)); } // We need to set the chainTypeManager of the mockChainId to mockCTM - // There is no function to do that in the bridgeHub + // There is no function to do that in the bridgehub // So, perhaps we will have to manually set the values in the chainTypeManager mapping via a foundry cheatcode - assertTrue(!(bridgeHub.chainTypeManager(mockChainId) == address(mockCTM))); + assertTrue(!(bridgehub.chainTypeManager(mockChainId) == address(mockCTM))); dummyBridgehub.setCTM(mockChainId, address(mockCTM)); dummyBridgehub.setZKChain(mockChainId, address(mockChainContract)); @@ -1704,7 +1748,7 @@ contract ExperimentalBridgeTest is Test { bytes32 baseTokenAssetId = DataEncoding.encodeNTVAssetId(block.chainid, token); - stdstore.target(address(bridgeHub)).sig("baseTokenAssetId(uint256)").with_key(mockChainId).checked_write( + stdstore.target(address(bridgehub)).sig("baseTokenAssetId(uint256)").with_key(mockChainId).checked_write( baseTokenAssetId ); } @@ -1778,16 +1822,16 @@ contract ExperimentalBridgeTest is Test { bytes memory randomData ) public { vm.startPrank(bridgeOwner); - bridgeHub.addChainTypeManager(address(mockCTM)); + bridgehub.addChainTypeManager(address(mockCTM)); vm.stopPrank(); L2Message memory l2Message = _createMockL2Message(randomTxNumInBatch, randomSender, randomData); vm.mockCall( - address(bridgeHub), + address(bridgehub), // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - bridgeHub.proveL2MessageInclusion.selector, + bridgehub.proveL2MessageInclusion.selector, mockChainId, mockBatchNumber, mockIndex, @@ -1798,7 +1842,7 @@ contract ExperimentalBridgeTest is Test { ); assertTrue( - bridgeHub.proveL2MessageInclusion({ + bridgehub.proveL2MessageInclusion({ _chainId: mockChainId, _batchNumber: mockBatchNumber, _index: mockIndex, @@ -1821,7 +1865,7 @@ contract ExperimentalBridgeTest is Test { bytes32 randomValue ) public { vm.startPrank(bridgeOwner); - bridgeHub.addChainTypeManager(address(mockCTM)); + bridgehub.addChainTypeManager(address(mockCTM)); vm.stopPrank(); L2Log memory l2Log = _createMockL2Log({ @@ -1834,10 +1878,10 @@ contract ExperimentalBridgeTest is Test { }); vm.mockCall( - address(bridgeHub), + address(bridgehub), // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - bridgeHub.proveL2LogInclusion.selector, + bridgehub.proveL2LogInclusion.selector, mockChainId, mockBatchNumber, mockIndex, @@ -1848,7 +1892,7 @@ contract ExperimentalBridgeTest is Test { ); assertTrue( - bridgeHub.proveL2LogInclusion({ + bridgehub.proveL2LogInclusion({ _chainId: mockChainId, _batchNumber: mockBatchNumber, _index: mockIndex, @@ -1868,7 +1912,7 @@ contract ExperimentalBridgeTest is Test { bool randomResultantBool ) public { vm.startPrank(bridgeOwner); - bridgeHub.addChainTypeManager(address(mockCTM)); + bridgehub.addChainTypeManager(address(mockCTM)); vm.stopPrank(); TxStatus txStatus; @@ -1880,10 +1924,10 @@ contract ExperimentalBridgeTest is Test { } vm.mockCall( - address(bridgeHub), + address(bridgehub), // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - bridgeHub.proveL1ToL2TransactionStatus.selector, + bridgehub.proveL1ToL2TransactionStatus.selector, randomChainId, randomL2TxHash, randomL2BatchNumber, @@ -1896,7 +1940,7 @@ contract ExperimentalBridgeTest is Test { ); assertTrue( - bridgeHub.proveL1ToL2TransactionStatus({ + bridgehub.proveL1ToL2TransactionStatus({ _chainId: randomChainId, _l2TxHash: randomL2TxHash, _l2BatchNumber: randomL2BatchNumber, diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/AssetRouterBase/FinalizeDepositBranches.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/AssetRouterBase/FinalizeDepositBranches.t.sol new file mode 100644 index 0000000000..d4ed63d49e --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/AssetRouterBase/FinalizeDepositBranches.t.sol @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {Test} from "forge-std/Test.sol"; + +import {AssetRouterBase} from "contracts/bridge/asset-router/AssetRouterBase.sol"; +import {IAssetHandler} from "contracts/bridge/interfaces/IAssetHandler.sol"; +import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; + +contract MockAssetHandler is IAssetHandler { + bool public called; + uint256 public lastChainId; + bytes32 public lastAssetId; + bytes public lastTransferData; + + function bridgeMint(uint256 _chainId, bytes32 _assetId, bytes calldata _transferData) external payable override { + called = true; + lastChainId = _chainId; + lastAssetId = _assetId; + lastTransferData = _transferData; + } + + function bridgeBurn( + uint256 _chainId, + uint256 _msgValue, + bytes32 _assetId, + address _originalCaller, + bytes calldata _data + ) external payable override returns (bytes memory) { + return abi.encode("mock"); + } +} + +contract TestAssetRouterBase is AssetRouterBase { + address public nativeTokenVault; + + // constructor() AssetRouterBase(1, 1, IBridgehubBase(address(1))) {} + + function setAssetHandlerAddressThisChain(bytes32, address) external override {} + + function bridgehubDepositBaseToken(uint256, bytes32, address, uint256) external payable override {} + + function finalizeDeposit(uint256 _chainId, bytes32 _assetId, bytes calldata _transferData) public payable override { + _finalizeDeposit(_chainId, _assetId, _transferData, nativeTokenVault); + } + + function _ensureTokenRegisteredWithNTV(address) internal pure override returns (bytes32) { + return keccak256("test"); + } + + function setNTV(address _ntv) external { + nativeTokenVault = _ntv; + } + + function setAssetHandler(bytes32 _assetId, address _handler) external { + assetHandlerAddress[_assetId] = _handler; + } + + function BRIDGE_HUB() external view returns (IBridgehubBase) { + return IBridgehubBase(address(1)); + } + + function L1_CHAIN_ID() external view returns (uint256) { + return 1; + } + + function _bridgehub() internal view override returns (IBridgehubBase) { + return IBridgehubBase(address(1)); + } + + function _l1ChainId() internal view returns (uint256) { + return 1; + } + + function _eraChainId() internal view returns (uint256) { + return 1; + } +} + +contract AssetRouterBase_FinalizeDepositBranches_Test is Test { + TestAssetRouterBase router; + MockAssetHandler existingHandler; + MockAssetHandler ntvHandler; + + function setUp() public { + router = new TestAssetRouterBase(); + existingHandler = new MockAssetHandler(); + ntvHandler = new MockAssetHandler(); + router.setNTV(address(ntvHandler)); + } + + function test_ExistingAssetHandler_CallsHandler() public { + bytes32 assetId = keccak256("testAsset"); + bytes memory transferData = abi.encode("testData"); + + // Set existing handler + router.setAssetHandler(assetId, address(existingHandler)); + + router.finalizeDeposit{value: 1 ether}(1, assetId, transferData); + + assertTrue(existingHandler.called()); + assertEq(existingHandler.lastChainId(), 1); + assertEq(existingHandler.lastAssetId(), assetId); + assertEq(keccak256(existingHandler.lastTransferData()), keccak256(transferData)); + + // NTV should not be called + assertFalse(ntvHandler.called()); + } + + function test_NoAssetHandler_AutoRegistersNTV() public { + bytes32 assetId = keccak256("newAsset"); + bytes memory transferData = abi.encode("testData"); + + // No handler set for this assetId + assertEq(router.assetHandlerAddress(assetId), address(0)); + + router.finalizeDeposit{value: 1 ether}(1, assetId, transferData); + + // NTV should be called + assertTrue(ntvHandler.called()); + assertEq(ntvHandler.lastChainId(), 1); + assertEq(ntvHandler.lastAssetId(), assetId); + assertEq(keccak256(ntvHandler.lastTransferData()), keccak256(transferData)); + + // Asset handler should be registered + assertEq(router.assetHandlerAddress(assetId), address(ntvHandler)); + } +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/AssetRouterBase/GetTransferDataErrors.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/AssetRouterBase/GetTransferDataErrors.t.sol new file mode 100644 index 0000000000..f757492295 --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/AssetRouterBase/GetTransferDataErrors.t.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {Test} from "forge-std/Test.sol"; + +import {AssetRouterBase} from "contracts/bridge/asset-router/AssetRouterBase.sol"; +import {BadTransferDataLength, UnsupportedEncodingVersion} from "contracts/common/L1ContractErrors.sol"; +import {NEW_ENCODING_VERSION} from "contracts/bridge/asset-router/IAssetRouterBase.sol"; +import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; + +contract TestAssetRouterBase is AssetRouterBase { + // constructor() AssetRouterBase(1, 1, IBridgehubBase(address(1))) {} + + function setAssetHandlerAddressThisChain(bytes32, address) external override {} + + function bridgehubDepositBaseToken(uint256, bytes32, address, uint256) external payable override {} + + function finalizeDeposit(uint256, bytes32, bytes calldata) public payable override {} + + function _ensureTokenRegisteredWithNTV(address) internal pure override returns (bytes32) { + return keccak256("test"); + } + + // Use a specific name that won't trigger fuzz testing + function callGetTransferData(bytes1 encodingVersion, bytes calldata data) external returns (bytes32, bytes memory) { + return _getTransferData(encodingVersion, address(0), data); + } + + function BRIDGE_HUB() external view returns (IBridgehubBase) { + return IBridgehubBase(address(1)); + } + + function L1_CHAIN_ID() external view returns (uint256) { + return 1; + } + + function _bridgehub() internal view override returns (IBridgehubBase) { + return IBridgehubBase(address(1)); + } + + function _l1ChainId() internal view returns (uint256) { + return 1; + } + + function _eraChainId() internal view returns (uint256) { + return 1; + } +} + +contract AssetRouterBase_GetTransferDataErrors_Test is Test { + TestAssetRouterBase router; + + function setUp() public { + router = new TestAssetRouterBase(); + } + + function test_BadTransferDataLength_WhenDataTooShort() public { + bytes memory shortData = hex"01"; // NEW_ENCODING_VERSION but only 1 byte + vm.expectRevert(BadTransferDataLength.selector); + router.callGetTransferData(NEW_ENCODING_VERSION, shortData); + } + + function test_UnsupportedEncodingVersion_WhenNotNew() public { + bytes memory data = hex"02"; // invalid encoding version + vm.expectRevert(UnsupportedEncodingVersion.selector); + router.callGetTransferData(bytes1(0x02), data); + } +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/BridgeHelper/GetERC20Getters.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/BridgeHelper/GetERC20Getters.t.sol new file mode 100644 index 0000000000..abf1433df3 --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/BridgeHelper/GetERC20Getters.t.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {Test} from "forge-std/Test.sol"; + +import {BridgeHelperTest} from "contracts/dev-contracts/test/BridgeHelperTest.sol"; +import {RevertFallback} from "contracts/dev-contracts/RevertFallback.sol"; + +contract GetERC20GettersTest is Test { + BridgeHelperTest helper; + RevertFallback bad; + + function setUp() public { + helper = new BridgeHelperTest(); + bad = new RevertFallback(); + } + + function _decode( + bytes memory data + ) + internal + pure + returns (uint256 chainId, bytes memory nameBytes, bytes memory symbolBytes, bytes memory decimalsBytes) + { + // Skip the first byte (encoding version) + bytes memory tail = new bytes(data.length - 1); + for (uint256 i = 1; i < data.length; i++) { + tail[i - 1] = data[i]; + } + (chainId, nameBytes, symbolBytes, decimalsBytes) = abi.decode(tail, (uint256, bytes, bytes, bytes)); + } + + function test_ETH_ReturnsEtherEth18() public view { + bytes memory data = helper.callGetters(address(1), 1337); + (uint256 chainId, bytes memory nameBytes, bytes memory symbolBytes, bytes memory decimalsBytes) = _decode(data); + + assertEq(chainId, 1337, "chainId"); + assertEq(keccak256(nameBytes), keccak256(abi.encode("Ether")), "name"); + assertEq(keccak256(symbolBytes), keccak256(abi.encode("ETH")), "symbol"); + assertEq(keccak256(decimalsBytes), keccak256(abi.encode(uint8(18))), "decimals"); + } + + function test_FailedStaticcalls_ReturnsEmptyBytes() public view { + bytes memory data = helper.callGetters(address(bad), 1); + (uint256 chainId, bytes memory nameBytes, bytes memory symbolBytes, bytes memory decimalsBytes) = _decode(data); + + assertEq(chainId, 1, "chainId"); + assertEq(nameBytes.length, 0, "name empty"); + assertEq(symbolBytes.length, 0, "symbol empty"); + assertEq(decimalsBytes.length, 0, "decimals empty"); + } +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/BridgedStandardERC20/InitializeFallbacks.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/BridgedStandardERC20/InitializeFallbacks.t.sol new file mode 100644 index 0000000000..d56adb8598 --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/BridgedStandardERC20/InitializeFallbacks.t.sol @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {Test} from "forge-std/Test.sol"; + +import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol"; +import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts-v4/proxy/ERC1967/ERC1967Proxy.sol"; + +contract BridgedStandardERC20_InitializeFallbacks_Test is Test { + BridgedStandardERC20 implementation; + address originToken = address(0xBEEF); + bytes32 assetId = keccak256(abi.encode("assetId")); + + function setUp() public { + implementation = new BridgedStandardERC20(); + } + + function _encodeTokenData( + bytes memory nameBytes, + bytes memory symbolBytes, + bytes memory decimalsBytes + ) internal pure returns (bytes memory) { + return + DataEncoding.encodeTokenData({ + _chainId: 1, + _name: nameBytes, + _symbol: symbolBytes, + _decimals: decimalsBytes + }); + } + + function _deployProxy() internal returns (BridgedStandardERC20 token) { + ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), bytes("")); + token = BridgedStandardERC20(address(proxy)); + } + + function _deployAndInit(bytes memory tokenData) internal returns (BridgedStandardERC20 token) { + token = _deployProxy(); + token.bridgeInitialize(assetId, originToken, tokenData); + } + + function test_IgnoreName_FallbacksAndGetters() public { + bytes memory invalid = hex"1234"; // not ABI-encoded string/uint8 + bytes memory data = _encodeTokenData({ + nameBytes: invalid, + symbolBytes: abi.encode("SYM"), + decimalsBytes: abi.encode(uint8(6)) + }); + + BridgedStandardERC20 token = _deployAndInit(data); + + // name() should revert when ignoreName = true + vm.expectRevert(); + token.name(); + + // others return provided values + assertEq(keccak256(bytes(token.symbol())), keccak256(bytes("SYM"))); + assertEq(token.decimals(), 6); + } + + function test_IgnoreSymbol_FallbacksAndGetters() public { + bytes memory invalid = hex"1234"; + bytes memory data = _encodeTokenData({ + nameBytes: abi.encode("NiceName"), + symbolBytes: invalid, + decimalsBytes: abi.encode(uint8(18)) + }); + + BridgedStandardERC20 token = _deployAndInit(data); + + assertEq(keccak256(bytes(token.name())), keccak256(bytes("NiceName"))); + vm.expectRevert(); + token.symbol(); + assertEq(token.decimals(), 18); + } + + function test_IgnoreDecimals_FallbacksAndGetters() public { + bytes memory invalid = hex"1234"; + bytes memory data = _encodeTokenData({ + nameBytes: abi.encode("N"), + symbolBytes: abi.encode("S"), + decimalsBytes: invalid + }); + + BridgedStandardERC20 token = _deployAndInit(data); + + assertEq(keccak256(bytes(token.name())), keccak256(bytes("N"))); + assertEq(keccak256(bytes(token.symbol())), keccak256(bytes("S"))); + vm.expectRevert(); + token.decimals(); + } + + function test_AllInvalid_AllGettersRevert() public { + bytes memory invalid = hex"1234"; + bytes memory data = _encodeTokenData(invalid, invalid, invalid); + BridgedStandardERC20 token = _deployAndInit(data); + + vm.expectRevert(); + token.name(); + vm.expectRevert(); + token.symbol(); + vm.expectRevert(); + token.decimals(); + } +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/BridgedStandardERC20/OnlyNTV.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/BridgedStandardERC20/OnlyNTV.t.sol new file mode 100644 index 0000000000..e9de93bcde --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/BridgedStandardERC20/OnlyNTV.t.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {StdStorage, Test, stdStorage} from "forge-std/Test.sol"; + +import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol"; +import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts-v4/proxy/ERC1967/ERC1967Proxy.sol"; +import {L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; + +contract MockNTV { + function L1_CHAIN_ID() external view returns (uint256) { + return block.chainid; + } +} + +contract BridgedStandardERC20_OnlyNTV_Test is Test { + using stdStorage for StdStorage; + + BridgedStandardERC20 implementation; + address originToken = address(0xBEEF); + bytes32 assetId = keccak256(abi.encode("assetId")); + + function setUp() public { + implementation = new BridgedStandardERC20(); + } + + function _deployProxy() internal returns (BridgedStandardERC20 token) { + ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), bytes("")); + token = BridgedStandardERC20(address(proxy)); + } + + function _init(BridgedStandardERC20 token) internal { + bytes memory data = DataEncoding.encodeTokenData({ + _chainId: 1, + _name: abi.encode("N"), + _symbol: abi.encode("S"), + _decimals: abi.encode(uint8(18)) + }); + token.bridgeInitialize(assetId, originToken, data); + } + + function _installMockNTV() internal { + MockNTV mock = new MockNTV(); + bytes memory code = address(mock).code; + vm.etch(L2_NATIVE_TOKEN_VAULT_ADDR, code); + } + + function _zeroOutNTVAndAssetId(BridgedStandardERC20 token) internal { + // discover slots by getter selectors and zero them + uint256 ntvSlot = stdstore.target(address(token)).sig("nativeTokenVault()").find(); + vm.store(address(token), bytes32(ntvSlot), bytes32(uint256(0))); + uint256 assetSlot = stdstore.target(address(token)).sig("assetId()").find(); + vm.store(address(token), bytes32(assetSlot), bytes32(0)); + } + + function test_LazyInitSetsDefaultNTVAndAssetId_OnFirstMint() public { + BridgedStandardERC20 token = _deployProxy(); + _init(token); + _installMockNTV(); + + // Force the lazy-init path + _zeroOutNTVAndAssetId(token); + assertEq(token.nativeTokenVault(), address(0)); + assertEq(token.assetId(), bytes32(0)); + + vm.prank(L2_NATIVE_TOKEN_VAULT_ADDR); + token.bridgeMint(address(0xCAFE), 123); + + assertEq(token.nativeTokenVault(), L2_NATIVE_TOKEN_VAULT_ADDR); + bytes32 expected = DataEncoding.encodeNTVAssetId(block.chainid, originToken); + assertEq(token.assetId(), expected); + } + + function test_UnauthorizedSenderReverts_OnMint() public { + BridgedStandardERC20 token = _deployProxy(); + _init(token); + _installMockNTV(); + + _zeroOutNTVAndAssetId(token); + + // correct sender sets NTV + vm.prank(L2_NATIVE_TOKEN_VAULT_ADDR); + token.bridgeMint(address(this), 1); + + // now unauthorized sender + vm.expectRevert(); + token.bridgeMint(address(this), 1); + } +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/BridgedStandardERC20/ReinitializeGuard.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/BridgedStandardERC20/ReinitializeGuard.t.sol new file mode 100644 index 0000000000..3478e1b977 --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/BridgedStandardERC20/ReinitializeGuard.t.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {Test} from "forge-std/Test.sol"; + +import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol"; +import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts-v4/proxy/ERC1967/ERC1967Proxy.sol"; +import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol"; + +contract BridgedStandardERC20_ReinitializeGuard_Test is Test { + BridgedStandardERC20 implementation; + address originToken = address(0xBEEF); + bytes32 assetId = keccak256(abi.encode("assetId")); + + function setUp() public { + implementation = new BridgedStandardERC20(); + } + + function _encodeTokenData( + bytes memory nameBytes, + bytes memory symbolBytes, + bytes memory decimalsBytes + ) internal pure returns (bytes memory) { + return + DataEncoding.encodeTokenData({ + _chainId: 1, + _name: nameBytes, + _symbol: symbolBytes, + _decimals: decimalsBytes + }); + } + + function _deployProxy() internal returns (BridgedStandardERC20 token) { + ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), bytes("")); + token = BridgedStandardERC20(address(proxy)); + } + + function _init(BridgedStandardERC20 token) internal { + bytes memory data = _encodeTokenData(abi.encode("N"), abi.encode("S"), abi.encode(uint8(18))); + token.bridgeInitialize(assetId, originToken, data); + } + + function test_Reinitialize_OnlyBeaconOwner_And_VersionPlusOne() public { + BridgedStandardERC20 token = _deployProxy(); + _init(token); + + UpgradeableBeacon beacon = new UpgradeableBeacon(address(new BridgedStandardERC20())); + address owner = address(0xABCD); + beacon.transferOwnership(owner); + + bytes32 BEACON_SLOT = bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1); + vm.store(address(token), BEACON_SLOT, bytes32(uint256(uint160(address(beacon))))); + + // Non-owner should revert Unauthorized + vm.expectRevert(); + token.reinitializeToken({ + _availableGetters: BridgedStandardERC20.ERC20Getters(false, false, false), + _newName: "NewName", + _newSymbol: "NS", + _version: 2 + }); + + // Owner, wrong version (not +1) should revert + vm.prank(owner); + vm.expectRevert(); + token.reinitializeToken({ + _availableGetters: BridgedStandardERC20.ERC20Getters(false, false, false), + _newName: "NewName", + _newSymbol: "NS", + _version: 3 + }); + + // Owner, correct version +1 should succeed + vm.prank(owner); + token.reinitializeToken({ + _availableGetters: BridgedStandardERC20.ERC20Getters(false, false, false), + _newName: "NewName", + _newSymbol: "NS", + _version: 2 + }); + + // Values updated + assertEq(keccak256(bytes(token.name())), keccak256(bytes("NewName"))); + assertEq(keccak256(bytes(token.symbol())), keccak256(bytes("NS"))); + } +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeBase.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeBase.t.sol index 4da88b6042..91d888236a 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeBase.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeBase.t.sol @@ -19,6 +19,7 @@ import {L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2 import {StdStorage, stdStorage} from "forge-std/Test.sol"; import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; +import {IMessageVerification} from "contracts/common/interfaces/IMessageVerification.sol"; contract L1AssetRouterTestBase is L1AssetRouterTest { using stdStorage for StdStorage; @@ -129,10 +130,10 @@ contract L1AssetRouterTestBase is L1AssetRouterTest { require(l1Nullifier.depositHappened(chainId, txHash) == txDataHash, "Deposit not set"); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL1ToL2TransactionStatus.selector, + IMessageVerification.proveL1ToL2TransactionStatusShared.selector, chainId, txHash, l2BatchNumber, @@ -170,10 +171,10 @@ contract L1AssetRouterTestBase is L1AssetRouterTest { require(l1Nullifier.depositHappened(chainId, txHash) == txDataHash, "Deposit not set"); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL1ToL2TransactionStatus.selector, + IMessageVerification.proveL1ToL2TransactionStatusShared.selector, chainId, txHash, l2BatchNumber, @@ -212,10 +213,10 @@ contract L1AssetRouterTestBase is L1AssetRouterTest { require(l1Nullifier.depositHappened(chainId, txHash) == txDataHash, "Deposit not set"); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL1ToL2TransactionStatus.selector, + IMessageVerification.proveL1ToL2TransactionStatusShared.selector, chainId, txHash, l2BatchNumber, @@ -256,10 +257,10 @@ contract L1AssetRouterTestBase is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, chainId, l2BatchNumber, l2MessageIndex, @@ -283,7 +284,7 @@ contract L1AssetRouterTestBase is L1AssetRouterTest { } function test_finalizeWithdrawal_ErcOnEth() public { - _setNativeTokenVaultChainBalance(chainId, address(token), amount); + _setAssetTrackerChainBalance(chainId, address(token), amount); bytes memory message = abi.encodePacked( AssetRouterBase.finalizeDeposit.selector, chainId, @@ -297,10 +298,10 @@ contract L1AssetRouterTestBase is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeCall( - IBridgehubBase.proveL2MessageInclusion, + IMessageVerification.proveL2MessageInclusionShared, (chainId, l2BatchNumber, l2MessageIndex, l2ToL1Message, merkleProof) ), abi.encode(true) @@ -322,9 +323,9 @@ contract L1AssetRouterTestBase is L1AssetRouterTest { function test_finalizeWithdrawal_EthOnErc() public { // vm.deal(address(sharedBridge), amount); - // _setNativeTokenVaultChainBalance(chainId, ETH_TOKEN_ADDRESS, amount); + // _setAssetTrackerChainBalance(chainId, ETH_TOKEN_ADDRESS, amount); _setBaseTokenAssetId(tokenAssetId); - vm.prank(bridgehubAddress); + // vm.prank(bridgehubAddress); bytes memory message = abi.encodePacked( AssetRouterBase.finalizeDeposit.selector, @@ -339,10 +340,10 @@ contract L1AssetRouterTestBase is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, chainId, l2BatchNumber, l2MessageIndex, @@ -367,7 +368,7 @@ contract L1AssetRouterTestBase is L1AssetRouterTest { function test_finalizeWithdrawal_BaseErcOnErc() public { _setBaseTokenAssetId(tokenAssetId); - vm.prank(bridgehubAddress); + // vm.prank(bridgehubAddress); bytes memory message = abi.encodePacked( AssetRouterBase.finalizeDeposit.selector, @@ -382,10 +383,10 @@ contract L1AssetRouterTestBase is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, chainId // l2BatchNumber, // l2MessageIndex, @@ -428,10 +429,10 @@ contract L1AssetRouterTestBase is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, chainId, l2BatchNumber, l2MessageIndex, @@ -454,28 +455,28 @@ contract L1AssetRouterTestBase is L1AssetRouterTest { }); } - function test_safeTransferFundsFromSharedBridge_Erc() public { - bytes32 assetId = DataEncoding.encodeNTVAssetId(block.chainid, address(token)); - uint256 startBalanceNtv = nativeTokenVault.chainBalance(chainId, assetId); - // solhint-disable-next-line func-named-parameters - vm.expectEmit(true, true, false, true, address(token)); - emit IERC20.Transfer(address(l1Nullifier), address(nativeTokenVault), amount); - nativeTokenVault.transferFundsFromSharedBridge(address(token)); - nativeTokenVault.updateChainBalancesFromSharedBridge(address(token), chainId); - uint256 endBalanceNtv = nativeTokenVault.chainBalance(chainId, assetId); - assertEq(endBalanceNtv - startBalanceNtv, amount); - } - - function test_safeTransferFundsFromSharedBridge_Eth() public { - uint256 startEthBalanceNtv = address(nativeTokenVault).balance; - uint256 startBalanceNtv = nativeTokenVault.chainBalance(chainId, ETH_TOKEN_ASSET_ID); - nativeTokenVault.transferFundsFromSharedBridge(ETH_TOKEN_ADDRESS); - nativeTokenVault.updateChainBalancesFromSharedBridge(ETH_TOKEN_ADDRESS, chainId); - uint256 endBalanceNtv = nativeTokenVault.chainBalance(chainId, ETH_TOKEN_ASSET_ID); - uint256 endEthBalanceNtv = address(nativeTokenVault).balance; - assertEq(endBalanceNtv - startBalanceNtv, amount); - assertEq(endEthBalanceNtv - startEthBalanceNtv, amount); - } + // function test_safeTransferFundsFromSharedBridge_Erc() public { + // bytes32 assetId = DataEncoding.encodeNTVAssetId(block.chainid, address(token)); + // uint256 startBalanceNtv = nativeTokenVault.chainBalance(chainId, assetId); + // // solhint-disable-next-line func-named-parameters + // vm.expectEmit(true, true, false, true, address(token)); + // emit IERC20.Transfer(address(l1Nullifier), address(nativeTokenVault), amount); + // nativeTokenVault.transferFundsFromSharedBridge(address(token)); + // nativeTokenVault.updateChainBalancesFromSharedBridge(address(token), chainId); + // uint256 endBalanceNtv = nativeTokenVault.chainBalance(chainId, assetId); + // assertEq(endBalanceNtv - startBalanceNtv, amount); + // } + + // function test_safeTransferFundsFromSharedBridge_Eth() public { + // uint256 startEthBalanceNtv = address(nativeTokenVault).balance; + // uint256 startBalanceNtv = nativeTokenVault.chainBalance(chainId, ETH_TOKEN_ASSET_ID); + // nativeTokenVault.transferFundsFromSharedBridge(ETH_TOKEN_ADDRESS); + // nativeTokenVault.updateChainBalancesFromSharedBridge(ETH_TOKEN_ADDRESS, chainId); + // uint256 endBalanceNtv = nativeTokenVault.chainBalance(chainId, ETH_TOKEN_ASSET_ID); + // uint256 endEthBalanceNtv = address(nativeTokenVault).balance; + // assertEq(endBalanceNtv - startBalanceNtv, amount); + // assertEq(endEthBalanceNtv - startEthBalanceNtv, amount); + // } function test_bridgehubDeposit_Eth_storesCorrectTxHash() public { _setBaseTokenAssetId(tokenAssetId); diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeFails.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeFails.t.sol index edeacc2732..73c5f1b17d 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeFails.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeFails.t.sol @@ -8,7 +8,7 @@ import {L1AssetRouterTest} from "./_L1SharedBridge_Shared.t.sol"; import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; -import {SET_ASSET_HANDLER_COUNTERPART_ENCODING_VERSION} from "contracts/bridge/asset-router/IAssetRouterBase.sol"; +import {NEW_ENCODING_VERSION, SET_ASSET_HANDLER_COUNTERPART_ENCODING_VERSION} from "contracts/bridge/asset-router/IAssetRouterBase.sol"; import {L1AssetRouter} from "contracts/bridge/asset-router/L1AssetRouter.sol"; import {L1NativeTokenVault} from "contracts/bridge/ntv/L1NativeTokenVault.sol"; import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; @@ -21,10 +21,15 @@ import {IL1ERC20Bridge} from "contracts/bridge/interfaces/IL1ERC20Bridge.sol"; import {INativeTokenVaultBase} from "contracts/bridge/ntv/INativeTokenVaultBase.sol"; import {L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; -import {AddressAlreadySet, AssetIdNotSupported, BurningNativeWETHNotSupported, DepositDoesNotExist, DepositExists, EmptyDeposit, InsufficientChainBalance, InvalidProof, InvalidSelector, L2WithdrawalMessageWrongLength, NoFundsTransferred, NonEmptyMsgValue, SharedBridgeKey, SharedBridgeValueNotSet, TokenNotSupported, TokensWithFeesNotSupported, Unauthorized, ValueMismatch, WithdrawFailed, WithdrawalAlreadyFinalized, ZeroAddress} from "contracts/common/L1ContractErrors.sol"; +import {AddressAlreadySet, AssetIdNotSupported, BurningNativeWETHNotSupported, DepositDoesNotExist, DepositExists, EmptyDeposit, InvalidProof, InvalidSelector, L2WithdrawalMessageWrongLength, NoFundsTransferred, NonEmptyMsgValue, SharedBridgeKey, SharedBridgeValueNotSet, TokenNotSupported, TokensWithFeesNotSupported, Unauthorized, ValueMismatch, WithdrawFailed, WithdrawalAlreadyFinalized, ZeroAddress} from "contracts/common/L1ContractErrors.sol"; +import {InsufficientChainBalance} from "contracts/bridge/asset-tracker/AssetTrackerErrors.sol"; import {StdStorage, stdStorage} from "forge-std/Test.sol"; -import {ClaimFailedDepositFailed, EmptyToken, EthTransferFailed, NativeTokenVaultAlreadySet, WrongAmountTransferred, WrongCounterpart, ZeroAmountToTransfer} from "contracts/bridge/L1BridgeContractErrors.sol"; +import {ClaimFailedDepositFailed, EmptyToken, NativeTokenVaultAlreadySet, WrongCounterpart} from "contracts/bridge/L1BridgeContractErrors.sol"; +import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; + +import {IMessageVerification} from "contracts/common/interfaces/IMessageVerification.sol"; +import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; /// We are testing all the specified revert and require cases. contract L1AssetRouterFailTest is L1AssetRouterTest { @@ -69,7 +74,7 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { function test_registerToken_noCode() public { vm.expectRevert(abi.encodeWithSelector(EmptyToken.selector)); - nativeTokenVault.registerToken(address(0)); + nativeTokenVault.registerToken(address(0x1111)); } function test_setL1Erc20Bridge_alreadySet() public { @@ -110,34 +115,36 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { sharedBridge.bridgehubDeposit(eraChainId, owner, 0, data); } + error EthAlreadyMigratedToL1NTV(); function test_transferFundsToSharedBridge_Eth_CallFailed() public { - vm.mockCallRevert(address(nativeTokenVault), abi.encode(), "eth transfer failed"); + bytes memory emptyData = ""; + vm.mockCallRevert(address(nativeTokenVault), emptyData, "eth transfer failed"); vm.prank(address(nativeTokenVault)); - vm.expectRevert(abi.encodeWithSelector(EthTransferFailed.selector)); + vm.expectRevert(abi.encodeWithSelector(EthAlreadyMigratedToL1NTV.selector)); l1Nullifier.transferTokenToNTV(ETH_TOKEN_ADDRESS); } - function test_transferFundsToSharedBridge_Eth_0_AmountTransferred() public { - vm.deal(address(l1Nullifier), 0); - vm.prank(address(nativeTokenVault)); - vm.expectRevert(abi.encodeWithSelector(NoFundsTransferred.selector)); - nativeTokenVault.transferFundsFromSharedBridge(ETH_TOKEN_ADDRESS); - } - - function test_transferFundsToSharedBridge_Erc_0_AmountTransferred() public { - vm.prank(address(l1Nullifier)); - token.transfer(address(1), amount); - vm.prank(address(nativeTokenVault)); - vm.expectRevert(ZeroAmountToTransfer.selector); - nativeTokenVault.transferFundsFromSharedBridge(address(token)); - } - - function test_transferFundsToSharedBridge_Erc_WrongAmountTransferred() public { - vm.mockCall(address(token), abi.encodeWithSelector(IERC20.balanceOf.selector), abi.encode(10)); - vm.prank(address(nativeTokenVault)); - vm.expectRevert(abi.encodeWithSelector(WrongAmountTransferred.selector, 0, 10)); - nativeTokenVault.transferFundsFromSharedBridge(address(token)); - } + // function test_transferFundsToSharedBridge_Eth_0_AmountTransferred() public { + // vm.deal(address(l1Nullifier), 0); + // vm.prank(address(nativeTokenVault)); + // vm.expectRevert(abi.encodeWithSelector(NoFundsTransferred.selector)); + // nativeTokenVault.transferFundsFromSharedBridge(ETH_TOKEN_ADDRESS); + // } + + // function test_transferFundsToSharedBridge_Erc_0_AmountTransferred() public { + // vm.prank(address(l1Nullifier)); + // token.transfer(address(1), amount); + // vm.prank(address(nativeTokenVault)); + // vm.expectRevert(ZeroAmountToTransfer.selector); + // nativeTokenVault.transferFundsFromSharedBridge(address(token)); + // } + + // function test_transferFundsToSharedBridge_Erc_WrongAmountTransferred() public { + // vm.mockCall(address(token), abi.encodeWithSelector(IERC20.balanceOf.selector), abi.encode(10)); + // vm.prank(address(nativeTokenVault)); + // vm.expectRevert(abi.encodeWithSelector(WrongAmountTransferred.selector, 0, 10)); + // nativeTokenVault.transferFundsFromSharedBridge(address(token)); + // } function test_bridgehubDepositBaseToken_Eth_Token_incorrectSender() public { vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, address(this))); @@ -251,11 +258,20 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { data: message }); + _setAssetTrackerChainBalance(chainId, ETH_TOKEN_ADDRESS, amount); + _setAssetTrackerChainBalance(block.chainid, ETH_TOKEN_ADDRESS, amount); + vm.mockCall( - bridgehubAddress, + messageRootAddress, + abi.encodeWithSelector(IMessageRoot.v30UpgradeChainBatchNumber.selector, chainId), + abi.encode(10) + ); + + vm.mockCall( + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, chainId, l2BatchNumber, l2MessageIndex, @@ -283,11 +299,20 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { _setSharedBridgeDepositHappened(chainId, txHash, txDataHash); require(l1Nullifier.depositHappened(chainId, txHash) == txDataHash, "Deposit not set"); + _setAssetTrackerChainBalance(chainId, ETH_TOKEN_ADDRESS, amount); + _setAssetTrackerChainBalance(block.chainid, ETH_TOKEN_ADDRESS, amount); + vm.mockCall( - bridgehubAddress, + messageRootAddress, + abi.encodeWithSelector(IMessageRoot.v30UpgradeChainBatchNumber.selector, chainId), + abi.encode(10) + ); + + vm.mockCall( + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL1ToL2TransactionStatus.selector, + IMessageVerification.proveL1ToL2TransactionStatusShared.selector, chainId, txHash, l2BatchNumber, @@ -322,10 +347,10 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { require(l1Nullifier.depositHappened(chainId, txHash) == txDataHash, "Deposit not set"); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL1ToL2TransactionStatus.selector, + IMessageVerification.proveL1ToL2TransactionStatusShared.selector, eraChainId, txHash, l2BatchNumber, @@ -363,11 +388,14 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { require(l1Nullifier.depositHappened(eraChainId, txHash) == txDataHash, "Deposit not set"); console.log("txDataHash", uint256(txDataHash)); + bytes32 ETH_TOKEN_ASSET_ID = DataEncoding.encodeNTVAssetId(block.chainid, ETH_TOKEN_ADDRESS); + _setAssetTrackerChainBalance(eraChainId, ETH_TOKEN_ADDRESS, 1); + vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL1ToL2TransactionStatus.selector, + IMessageVerification.proveL1ToL2TransactionStatusShared.selector, eraChainId, txHash, l2BatchNumber, @@ -379,10 +407,13 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { abi.encode(true) ); - vm.expectRevert(InsufficientChainBalance.selector); + // asset tracker is a separate contract. + vm.expectRevert( + abi.encodeWithSelector(InsufficientChainBalance.selector, eraChainId, ETH_TOKEN_ASSET_ID, amount) + ); vm.mockCall( - address(bridgehubAddress), - abi.encodeWithSelector(IBridgehubBase.proveL1ToL2TransactionStatus.selector), + messageRootAddress, + abi.encodeWithSelector(IMessageVerification.proveL1ToL2TransactionStatusShared.selector), abi.encode(true) ); l1Nullifier.bridgeRecoverFailedTransfer({ @@ -400,11 +431,11 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { function test_claimFailedDeposit_proofInvalid() public { vm.mockCall( - bridgehubAddress, - abi.encodeWithSelector(IBridgehubBase.proveL1ToL2TransactionStatus.selector), + messageRootAddress, + abi.encodeWithSelector(IMessageVerification.proveL1ToL2TransactionStatusShared.selector), abi.encode(address(0)) ); - vm.prank(bridgehubAddress); + // vm.prank(bridgehubAddress); vm.expectRevert(abi.encodeWithSelector(InvalidProof.selector)); l1Nullifier.claimFailedDeposit({ _chainId: chainId, @@ -421,10 +452,10 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { function test_claimFailedDeposit_amountZero() public { vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL1ToL2TransactionStatus.selector, + IMessageVerification.proveL1ToL2TransactionStatusShared.selector, chainId, txHash, l2BatchNumber, @@ -456,10 +487,10 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { vm.deal(address(sharedBridge), amount); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL1ToL2TransactionStatus.selector, + IMessageVerification.proveL1ToL2TransactionStatusShared.selector, chainId, txHash, l2BatchNumber, @@ -471,7 +502,14 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { abi.encode(true) ); - vm.expectRevert(DepositDoesNotExist.selector); + bytes32 txDataHash = DataEncoding.encodeTxDataHash( + NEW_ENCODING_VERSION, + alice, + ETH_TOKEN_ASSET_ID, + address(l1Nullifier.l1NativeTokenVault()), + DataEncoding.encodeBridgeBurnData(amount, address(0), address(0)) + ); + vm.expectRevert(abi.encodeWithSelector(DepositDoesNotExist.selector, 0, txDataHash)); l1Nullifier.claimFailedDeposit({ _chainId: chainId, _depositSender: alice, @@ -486,17 +524,17 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { } function test_claimFailedDeposit_chainBalanceLow() public { - _setNativeTokenVaultChainBalance(chainId, ETH_TOKEN_ADDRESS, 0); + _setAssetTrackerChainBalance(chainId, ETH_TOKEN_ADDRESS, 0); bytes32 txDataHash = keccak256(abi.encode(alice, ETH_TOKEN_ADDRESS, amount)); _setSharedBridgeDepositHappened(chainId, txHash, txDataHash); require(l1Nullifier.depositHappened(chainId, txHash) == txDataHash, "Deposit not set"); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL1ToL2TransactionStatus.selector, + IMessageVerification.proveL1ToL2TransactionStatusShared.selector, chainId, txHash, l2BatchNumber, @@ -508,7 +546,7 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { abi.encode(true) ); - vm.expectRevert(InsufficientChainBalance.selector); + vm.expectRevert(abi.encodeWithSelector(InsufficientChainBalance.selector, chainId, ETH_TOKEN_ASSET_ID, amount)); l1Nullifier.claimFailedDeposit({ _chainId: chainId, _depositSender: alice, @@ -623,7 +661,11 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { amount ); - vm.mockCall(bridgehubAddress, abi.encode(IBridgehubBase.proveL2MessageInclusion.selector), abi.encode(true)); + vm.mockCall( + messageRootAddress, + abi.encode(IMessageVerification.proveL2MessageInclusionShared.selector), + abi.encode(true) + ); vm.expectRevert( abi.encodeWithSelector(SharedBridgeValueNotSet.selector, SharedBridgeKey.PostUpgradeFirstBatch) @@ -647,10 +689,10 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, chainId, l2BatchNumber, l2MessageIndex, @@ -659,9 +701,9 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { ), abi.encode(true) ); - _setNativeTokenVaultChainBalance(chainId, ETH_TOKEN_ADDRESS, 1); + _setAssetTrackerChainBalance(chainId, ETH_TOKEN_ADDRESS, 1); - vm.expectRevert(InsufficientChainBalance.selector); + vm.expectRevert(abi.encodeWithSelector(InsufficientChainBalance.selector, chainId, ETH_TOKEN_ASSET_ID, 100)); sharedBridge.finalizeWithdrawal({ _chainId: chainId, _l2BatchNumber: l2BatchNumber, @@ -681,10 +723,10 @@ contract L1AssetRouterFailTest is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, chainId, l2BatchNumber, l2MessageIndex, diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeHyperEnabled.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeHyperEnabled.t.sol index 44020e9577..7689d6d3b4 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeHyperEnabled.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeHyperEnabled.t.sol @@ -12,6 +12,8 @@ import {IAssetRouterBase} from "contracts/bridge/asset-router/IAssetRouterBase.s import {AssetRouterBase} from "contracts/bridge/asset-router/AssetRouterBase.sol"; import {L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {IMessageVerification} from "contracts/common/interfaces/IMessageVerification.sol"; + // note, this should be the same as where hyper is disabled contract L1AssetRouterHyperEnabledTest is L1AssetRouterTest { function test_bridgehubDepositBaseToken_Eth() public { @@ -45,7 +47,7 @@ contract L1AssetRouterHyperEnabledTest is L1AssetRouterTest { } function test_bridgehubDeposit_Eth() public { - // vm.prank(bridgehubAddress); + // vm.prank(interopCenterAddress); // solhint-disable-next-line func-named-parameters vm.expectEmit(true, true, true, false, address(sharedBridge)); _setBaseTokenAssetId(tokenAssetId); @@ -100,13 +102,13 @@ contract L1AssetRouterHyperEnabledTest is L1AssetRouterTest { _setSharedBridgeDepositHappened(chainId, txHash, txDataHash); require(l1Nullifier.depositHappened(chainId, txHash) == txDataHash, "Deposit not set"); - _setNativeTokenVaultChainBalance(chainId, address(token), amount); + _setAssetTrackerChainBalance(chainId, address(token), amount); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL1ToL2TransactionStatus.selector, + IMessageVerification.proveL1ToL2TransactionStatusShared.selector, chainId, txHash, l2BatchNumber, @@ -121,7 +123,7 @@ contract L1AssetRouterHyperEnabledTest is L1AssetRouterTest { // solhint-disable-next-line func-named-parameters vm.expectEmit(true, true, true, false, address(sharedBridge)); emit ClaimedFailedDepositAssetRouter(chainId, tokenAssetId, abi.encode(bytes32(0))); - vm.prank(bridgehubAddress); + // vm.prank(bridgehubAddress); l1Nullifier.claimFailedDeposit({ _chainId: chainId, _depositSender: alice, @@ -146,10 +148,10 @@ contract L1AssetRouterHyperEnabledTest is L1AssetRouterTest { // require(address(bridgehub.deployer()) == address(31337), "BH: deployer wrong"); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL1ToL2TransactionStatus.selector, + IMessageVerification.proveL1ToL2TransactionStatusShared.selector, chainId, txHash, l2BatchNumber, @@ -164,7 +166,7 @@ contract L1AssetRouterHyperEnabledTest is L1AssetRouterTest { // solhint-disable-next-line func-named-parameters vm.expectEmit(true, true, true, false, address(sharedBridge)); emit ClaimedFailedDepositAssetRouter(chainId, ETH_TOKEN_ASSET_ID, abi.encode(bytes32(0))); - vm.prank(bridgehubAddress); + // vm.prank(bridgehubAddress); l1Nullifier.claimFailedDeposit({ _chainId: chainId, _depositSender: alice, @@ -189,10 +191,10 @@ contract L1AssetRouterHyperEnabledTest is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, chainId, l2BatchNumber, l2MessageIndex, @@ -231,10 +233,10 @@ contract L1AssetRouterHyperEnabledTest is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, chainId, l2BatchNumber, l2MessageIndex, @@ -273,10 +275,10 @@ contract L1AssetRouterHyperEnabledTest is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, chainId, l2BatchNumber, l2MessageIndex, @@ -315,10 +317,10 @@ contract L1AssetRouterHyperEnabledTest is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, chainId // l2BatchNumber, // l2MessageIndex, @@ -356,10 +358,10 @@ contract L1AssetRouterHyperEnabledTest is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, chainId, l2BatchNumber, l2MessageIndex, diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeLegacy.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeLegacy.t.sol index daeded9ff5..0ee9aa0c32 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeLegacy.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeLegacy.t.sol @@ -13,6 +13,7 @@ import {IMailboxImpl} from "contracts/state-transition/chain-interfaces/IMailbox import {IL1ERC20Bridge} from "contracts/bridge/interfaces/IL1ERC20Bridge.sol"; import {L2_ASSET_ROUTER_ADDR, L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {FinalizeL1DepositParams} from "contracts/bridge/interfaces/IL1Nullifier.sol"; +import {IMessageVerification} from "contracts/common/interfaces/IMessageVerification.sol"; contract L1AssetRouterLegacyTest is L1AssetRouterTest { function test_depositLegacyERC20Bridge() public { @@ -54,7 +55,7 @@ contract L1AssetRouterLegacyTest is L1AssetRouterTest { vm.deal(address(sharedBridge), amount); /// storing chainBalance - _setNativeTokenVaultChainBalance(eraChainId, ETH_TOKEN_ADDRESS, amount); + _setAssetTrackerChainBalance(eraChainId, ETH_TOKEN_ADDRESS, amount); vm.mockCall( bridgehubAddress, abi.encodeWithSelector(IBridgehubBase.baseToken.selector), @@ -69,10 +70,10 @@ contract L1AssetRouterLegacyTest is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, eraChainId, l2BatchNumber, l2MessageIndex, @@ -100,7 +101,7 @@ contract L1AssetRouterLegacyTest is L1AssetRouterTest { function test_finalizeWithdrawalLegacyErc20Bridge_ErcOnEth() public { /// storing chainBalance - _setNativeTokenVaultChainBalance(eraChainId, address(token), amount); + _setAssetTrackerChainBalance(eraChainId, address(token), amount); // solhint-disable-next-line func-named-parameters bytes memory message = abi.encodePacked( @@ -116,10 +117,10 @@ contract L1AssetRouterLegacyTest is L1AssetRouterTest { }); vm.mockCall( - bridgehubAddress, + messageRootAddress, // solhint-disable-next-line func-named-parameters abi.encodeWithSelector( - IBridgehubBase.proveL2MessageInclusion.selector, + IMessageVerification.proveL2MessageInclusionShared.selector, eraChainId, l2BatchNumber, l2MessageIndex, diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/_L1SharedBridge_Shared.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/_L1SharedBridge_Shared.t.sol index ba09aec715..7f06c27f3f 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/_L1SharedBridge_Shared.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/L1SharedBridge/_L1SharedBridge_Shared.t.sol @@ -9,20 +9,26 @@ import {ERC20} from "@openzeppelin/contracts-v4/token/ERC20/ERC20.sol"; import {L1AssetRouter} from "contracts/bridge/asset-router/L1AssetRouter.sol"; +import {IInteropCenter} from "contracts/interop/IInteropCenter.sol"; import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; import {TestnetERC20Token} from "contracts/dev-contracts/TestnetERC20Token.sol"; import {L1NativeTokenVault} from "contracts/bridge/ntv/L1NativeTokenVault.sol"; -import {L1Nullifier} from "contracts/bridge/L1Nullifier.sol"; +import {L1AssetTracker} from "contracts/bridge/asset-tracker/L1AssetTracker.sol"; +import {IL1Nullifier, L1Nullifier} from "contracts/bridge/L1Nullifier.sol"; import {L1NullifierDev} from "contracts/dev-contracts/L1NullifierDev.sol"; import {INativeTokenVaultBase} from "contracts/bridge/ntv/INativeTokenVaultBase.sol"; +import {IAssetTrackerBase} from "contracts/bridge/asset-tracker/IAssetTrackerBase.sol"; import {IL1BaseTokenAssetHandler} from "contracts/bridge/interfaces/IL1BaseTokenAssetHandler.sol"; import {IL1ERC20Bridge} from "contracts/bridge/interfaces/IL1ERC20Bridge.sol"; import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; import {L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; +import {ProofData} from "contracts/common/libraries/MessageHashing.sol"; +import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; +import {IChainAssetHandler} from "contracts/bridgehub/IChainAssetHandler.sol"; contract L1AssetRouterTest is Test { using stdStorage for StdStorage; @@ -68,10 +74,14 @@ contract L1AssetRouterTest is Test { L1Nullifier l1NullifierImpl; L1Nullifier l1Nullifier; address bridgehubAddress; + address interopCenterAddress; + address chainAssetHandler; + address messageRootAddress; address l1ERC20BridgeAddress; address l1WethAddress; address l2SharedBridge; address l1NullifierAddress; + L1AssetTracker l1AssetTracker; TestnetERC20Token token; bytes32 tokenAssetId; uint256 eraPostUpgradeFirstBatch; @@ -109,6 +119,8 @@ contract L1AssetRouterTest is Test { proxyAdmin = makeAddr("proxyAdmin"); // zkSync = makeAddr("zkSync"); bridgehubAddress = makeAddr("bridgehub"); + messageRootAddress = makeAddr("messageRoot"); + interopCenterAddress = makeAddr("interopCenter"); alice = makeAddr("alice"); // bob = makeAddr("bob"); l1WethAddress = address(new ERC20("Wrapped ETH", "WETH")); @@ -120,6 +132,7 @@ contract L1AssetRouterTest is Test { l2MessageIndex = uint256(uint160(makeAddr("l2MessageIndex"))); l2TxNumberInBatch = uint16(uint160(makeAddr("l2TxNumberInBatch"))); l2LegacySharedBridgeAddr = makeAddr("l2LegacySharedBridge"); + merkleProof = new bytes32[](1); eraPostUpgradeFirstBatch = 1; @@ -132,6 +145,8 @@ contract L1AssetRouterTest is Test { token = new TestnetERC20Token("TestnetERC20Token", "TET", 18); l1NullifierImpl = new L1NullifierDev({ _bridgehub: IL1Bridgehub(bridgehubAddress), + _messageRoot: IMessageRoot(messageRootAddress), + _interopCenter: IInteropCenter(interopCenterAddress), _eraChainId: eraChainId, _eraDiamondProxy: eraDiamondProxy }); @@ -169,6 +184,25 @@ contract L1AssetRouterTest is Test { abi.encodeWithSelector(L1NativeTokenVault.initialize.selector, owner, tokenBeacon) ); nativeTokenVault = L1NativeTokenVault(payable(nativeTokenVaultProxy)); + vm.mockCall( + bridgehubAddress, + abi.encodeWithSelector(IBridgehubBase.chainAssetHandler.selector), + abi.encode(address(chainAssetHandler)) + ); + vm.mockCall( + chainAssetHandler, + abi.encodeWithSelector(IChainAssetHandler.migrationNumber.selector), + abi.encode(0) + ); + l1AssetTracker = new L1AssetTracker( + block.chainid, + bridgehubAddress, + address(sharedBridge), + address(nativeTokenVault), + messageRootAddress + ); + vm.prank(owner); + nativeTokenVault.setAssetTracker(address(l1AssetTracker)); vm.prank(owner); l1Nullifier.setL1AssetRouter(address(sharedBridge)); @@ -204,6 +238,11 @@ contract L1AssetRouterTest is Test { abi.encodeWithSelector(IBridgehubBase.baseTokenAssetId.selector), abi.encode(ETH_TOKEN_ASSET_ID) ); + vm.mockCall( + bridgehubAddress, + abi.encodeWithSelector(IBridgehubBase.settlementLayer.selector), + abi.encode(block.chainid) + ); vm.mockCall( bridgehubAddress, abi.encodeWithSelector(IBridgehubBase.baseTokenAssetId.selector, chainId), @@ -214,17 +253,40 @@ contract L1AssetRouterTest is Test { abi.encodeWithSelector(IL1Bridgehub.requestL2TransactionDirect.selector), abi.encode(txHash) ); + bytes32 ETH_TOKEN_ASSET_ID = DataEncoding.encodeNTVAssetId(block.chainid, ETH_TOKEN_ADDRESS); + stdstore + .target(address(l1AssetTracker)) + .sig(IAssetTrackerBase.chainBalance.selector) + .with_key(eraChainId) + .with_key(ETH_TOKEN_ASSET_ID) + .checked_write(100); + stdstore + .target(address(l1AssetTracker)) + .sig(IAssetTrackerBase.chainBalance.selector) + .with_key(chainId) + .with_key(ETH_TOKEN_ASSET_ID) + .checked_write(100); + stdstore + .target(address(l1AssetTracker)) + .sig(IAssetTrackerBase.chainBalance.selector) + .with_key(chainId) + .with_key(tokenAssetId) + .checked_write(100); token.mint(address(nativeTokenVault), amount); /// storing chainBalance - _setNativeTokenVaultChainBalance(chainId, address(token), 1000 * amount); - _setNativeTokenVaultChainBalance(chainId, ETH_TOKEN_ADDRESS, amount); + _setAssetTrackerChainBalance(chainId, address(token), 1000 * amount); + _setAssetTrackerChainBalance(chainId, ETH_TOKEN_ADDRESS, amount); + // Also set balance for block.chainid to handle _getWithdrawalChain scenarios + _setAssetTrackerChainBalance(block.chainid, address(token), 1000 * amount); + _setAssetTrackerChainBalance(block.chainid, ETH_TOKEN_ADDRESS, amount); // console.log("chainBalance %s, %s", address(token), nativeTokenVault.chainBalance(chainId, address(token))); _setSharedBridgeChainBalance(chainId, address(token), amount); _setSharedBridgeChainBalance(chainId, ETH_TOKEN_ADDRESS, amount); vm.deal(bridgehubAddress, amount); + vm.deal(interopCenterAddress, amount); vm.deal(address(sharedBridge), amount); vm.deal(address(l1Nullifier), amount); vm.deal(address(nativeTokenVault), amount); @@ -240,7 +302,7 @@ contract L1AssetRouterTest is Test { token.approve(address(l1Nullifier), amount); _setBaseTokenAssetId(ETH_TOKEN_ASSET_ID); - _setNativeTokenVaultChainBalance(chainId, address(token), amount); + _setAssetTrackerChainBalance(chainId, address(token), amount); vm.mockCall( address(nativeTokenVault), @@ -258,6 +320,33 @@ contract L1AssetRouterTest is Test { abi.encodeWithSelector(IBridgehubBase.baseToken.selector, chainId), abi.encode(ETH_TOKEN_ADDRESS) ); + + vm.mockCall( + l1NullifierAddress, + abi.encodeWithSelector(IL1Nullifier.getTransientSettlementLayer.selector), + abi.encode(0) + ); + vm.mockCall( + messageRootAddress, + abi.encodeWithSelector(IMessageRoot.v30UpgradeChainBatchNumber.selector), + abi.encode(10) + ); + vm.mockCall( + address(messageRootAddress), + abi.encodeWithSelector(IMessageRoot.getProofData.selector), + abi.encode( + ProofData({ + settlementLayerChainId: 0, + settlementLayerBatchNumber: 0, + settlementLayerBatchRootMask: 0, + batchLeafProofLen: 0, + batchSettlementRoot: 0, + chainIdLeaf: 0, + ptr: 0, + finalProofNode: false + }) + ) + ); } function _setSharedBridgeDepositHappened(uint256 _chainId, bytes32 _txHash, bytes32 _txDataHash) internal { @@ -269,11 +358,11 @@ contract L1AssetRouterTest is Test { .checked_write(_txDataHash); } - function _setNativeTokenVaultChainBalance(uint256 _chainId, address _token, uint256 _value) internal { + function _setAssetTrackerChainBalance(uint256 _chainId, address _token, uint256 _value) internal { bytes32 assetId = DataEncoding.encodeNTVAssetId(block.chainid, _token); stdstore - .target(address(nativeTokenVault)) - .sig(nativeTokenVault.chainBalance.selector) + .target(address(l1AssetTracker)) + .sig(IAssetTrackerBase.chainBalance.selector) .with_key(_chainId) .with_key(assetId) .checked_write(_value); diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/NativeTokenVault/L1NativeTokenVault.sol b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/NativeTokenVault/L1NativeTokenVault.sol index 6e7f8018f2..614bf2d319 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Bridges/NativeTokenVault/L1NativeTokenVault.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Bridges/NativeTokenVault/L1NativeTokenVault.sol @@ -2,6 +2,7 @@ import {Test} from "forge-std/Test.sol"; import {L1NativeTokenVault} from "contracts/bridge/ntv/L1NativeTokenVault.sol"; import {L1AssetRouter} from "contracts/bridge/asset-router/L1AssetRouter.sol"; +import {AssetTrackerBase} from "contracts/bridge/asset-tracker/AssetTrackerBase.sol"; import {IL1Nullifier} from "contracts/bridge/interfaces/IL1Nullifier.sol"; import {AssetIdAlreadyRegistered} from "contracts/common/L1ContractErrors.sol"; @@ -19,11 +20,15 @@ contract L1NativeTokenVaultTest is Test { L1NativeTokenVault ntv; SomeToken token; + address assetTracker; function setUp() public { assetRouter = makeAddr("assetRouter"); ntv = new L1NativeTokenVault(makeAddr("wethToken"), assetRouter, IL1Nullifier(address(0))); + assetTracker = makeAddr("assetTracker"); + vm.prank(address(0)); + ntv.setAssetTracker(assetTracker); token = new SomeToken(); } @@ -37,6 +42,10 @@ contract L1NativeTokenVaultTest is Test { ), hex"" ); + bytes[] memory zeros = new bytes[](2); + zeros[0] = abi.encode(0); + zeros[1] = abi.encode(0); + vm.mockCalls(assetTracker, abi.encodeWithSelector(AssetTrackerBase.registerNewToken.selector), zeros); ntv.registerToken(address(token)); vm.expectRevert(AssetIdAlreadyRegistered.selector); diff --git a/l1-contracts/test/foundry/l1/unit/concrete/ChainRegistrar/ChainRegistrar.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/ChainRegistrar/ChainRegistrar.t.sol new file mode 100644 index 0000000000..d6255ed6ee --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/ChainRegistrar/ChainRegistrar.t.sol @@ -0,0 +1,533 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; + +import {ChainRegistrar} from "contracts/chain-registrar/ChainRegistrar.sol"; +import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; +import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; +import {IGetters} from "contracts/state-transition/chain-interfaces/IGetters.sol"; +import {IL1SharedBridgeLegacy} from "contracts/bridge/interfaces/IL1SharedBridgeLegacy.sol"; +import {PubdataPricingMode} from "contracts/state-transition/chain-deps/ZKChainStorage.sol"; +import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; + +import {TestnetERC20Token} from "contracts/dev-contracts/TestnetERC20Token.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts-v4/proxy/ERC1967/ERC1967Proxy.sol"; + +contract ChainRegistrarTest is Test { + ChainRegistrar public chainRegistrar; + ERC1967Proxy public proxy; + address public mockBridgehub; + address public mockChainTypeManager; + address public mockDiamondProxy; + address public mockAssetRouter; + address public l2Deployer; + address public owner; + address public proposer; + + uint256 public constant CHAIN_ID = 123; + uint256 public constant PROPOSER_CHAIN_ID = 456; + address public constant BLOB_OPERATOR = address(0x111); + address public constant OPERATOR = address(0x222); + address public constant GOVERNOR = address(0x333); + address public constant TOKEN_MULTIPLIER_SETTER = address(0x444); + uint128 public constant GAS_PRICE_MULTIPLIER_NOMINATOR = 1000; + uint128 public constant GAS_PRICE_MULTIPLIER_DENOMINATOR = 1000; + + TestnetERC20Token public testToken; + + function setUp() public { + // Create mock addresses + mockBridgehub = makeAddr("mockBridgehub"); + mockChainTypeManager = makeAddr("mockChainTypeManager"); + mockDiamondProxy = makeAddr("mockDiamondProxy"); + mockAssetRouter = makeAddr("mockAssetRouter"); + l2Deployer = makeAddr("l2Deployer"); + owner = makeAddr("owner"); + proposer = makeAddr("proposer"); + + // Deploy test token + testToken = new TestnetERC20Token("Test Token", "TT", 18); + + // Deploy ChainRegistrar implementation + ChainRegistrar implementation = new ChainRegistrar(); + + // Deploy proxy + bytes memory initData = abi.encodeWithSelector( + ChainRegistrar.initialize.selector, + mockBridgehub, + l2Deployer, + owner + ); + proxy = new ERC1967Proxy(address(implementation), initData); + chainRegistrar = ChainRegistrar(address(proxy)); + + // Set up mocks + vm.mockCall( + mockBridgehub, + abi.encodeWithSelector(IBridgehubBase.chainTypeManager.selector, CHAIN_ID), + abi.encode(address(0)) // Not deployed yet + ); + + vm.mockCall( + mockBridgehub, + abi.encodeWithSelector(IBridgehubBase.chainTypeManager.selector, PROPOSER_CHAIN_ID), + abi.encode(mockChainTypeManager) // Already deployed + ); + + vm.mockCall( + mockBridgehub, + abi.encodeWithSelector(IBridgehubBase.assetRouter.selector), + abi.encode(mockAssetRouter) + ); + + vm.mockCall( + mockChainTypeManager, + abi.encodeWithSelector(IChainTypeManager.getZKChain.selector, CHAIN_ID), + abi.encode(mockDiamondProxy) + ); + + vm.mockCall( + mockDiamondProxy, + abi.encodeWithSelector(IGetters.getPendingAdmin.selector), + abi.encode(address(0x555)) + ); + + vm.mockCall(mockDiamondProxy, abi.encodeWithSelector(IGetters.getAdmin.selector), abi.encode(address(0x666))); + + vm.mockCall( + mockAssetRouter, + abi.encodeWithSelector(IL1SharedBridgeLegacy.l2BridgeAddress.selector, CHAIN_ID), + abi.encode(address(0x777)) + ); + + // Give proposer some test tokens + testToken.mint(proposer, 1000 ether); + } + + function test_Initialize() public { + assertEq(address(chainRegistrar.bridgehub()), mockBridgehub); + assertEq(chainRegistrar.l2Deployer(), l2Deployer); + assertEq(chainRegistrar.owner(), owner); + } + + function test_ProposeChainRegistration_ETH() public { + vm.prank(proposer); + chainRegistrar.proposeChainRegistration( + CHAIN_ID, + PubdataPricingMode.Rollup, + BLOB_OPERATOR, + OPERATOR, + GOVERNOR, + ETH_TOKEN_ADDRESS, + TOKEN_MULTIPLIER_SETTER, + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + + // Check that the proposal was stored + ( + uint256 chainId, + ChainRegistrar.BaseToken memory baseToken, + address blobOperator, + address operator, + address governor, + PubdataPricingMode pubdataPricingMode + ) = chainRegistrar.proposedChains(proposer, CHAIN_ID); + assertEq(chainId, CHAIN_ID); + assertEq(blobOperator, BLOB_OPERATOR); + assertEq(operator, OPERATOR); + assertEq(governor, GOVERNOR); + assertEq(uint256(pubdataPricingMode), uint256(PubdataPricingMode.Rollup)); + assertEq(baseToken.tokenAddress, ETH_TOKEN_ADDRESS); + assertEq(baseToken.tokenMultiplierSetter, TOKEN_MULTIPLIER_SETTER); + assertEq(baseToken.gasPriceMultiplierNominator, GAS_PRICE_MULTIPLIER_NOMINATOR); + assertEq(baseToken.gasPriceMultiplierDenominator, GAS_PRICE_MULTIPLIER_DENOMINATOR); + } + + function test_ProposeChainRegistration_ERC20() public { + // Calculate exact amount needed + uint256 amount = (1 ether * GAS_PRICE_MULTIPLIER_NOMINATOR) / GAS_PRICE_MULTIPLIER_DENOMINATOR; + + // Approve tokens for transfer to the ChainRegistrar contract + vm.prank(proposer); + testToken.approve(address(chainRegistrar), amount); + + vm.prank(proposer); + chainRegistrar.proposeChainRegistration( + CHAIN_ID, + PubdataPricingMode.Rollup, + BLOB_OPERATOR, + OPERATOR, + GOVERNOR, + address(testToken), + TOKEN_MULTIPLIER_SETTER, + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + + // Check that the proposal was stored + (uint256 chainId, ChainRegistrar.BaseToken memory baseToken, , , , ) = chainRegistrar.proposedChains( + proposer, + CHAIN_ID + ); + assertEq(chainId, CHAIN_ID); + assertEq(baseToken.tokenAddress, address(testToken)); + } + + function test_ProposeChainRegistration_ERC20_InsufficientBalance() public { + // Don't approve tokens + vm.prank(proposer); + vm.expectRevert(); + chainRegistrar.proposeChainRegistration( + CHAIN_ID, + PubdataPricingMode.Rollup, + BLOB_OPERATOR, + OPERATOR, + GOVERNOR, + address(testToken), + TOKEN_MULTIPLIER_SETTER, + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + } + + function test_ProposeChainRegistration_ChainAlreadyDeployed() public { + vm.expectRevert(abi.encodeWithSelector(ChainRegistrar.ChainIsAlreadyDeployed.selector)); + vm.prank(proposer); + chainRegistrar.proposeChainRegistration( + PROPOSER_CHAIN_ID, // This chain is already deployed + PubdataPricingMode.Rollup, + BLOB_OPERATOR, + OPERATOR, + GOVERNOR, + ETH_TOKEN_ADDRESS, + TOKEN_MULTIPLIER_SETTER, + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + } + + function test_ProposeChainRegistration_ChainAlreadyProposed() public { + // First proposal + vm.prank(proposer); + chainRegistrar.proposeChainRegistration( + CHAIN_ID, + PubdataPricingMode.Rollup, + BLOB_OPERATOR, + OPERATOR, + GOVERNOR, + ETH_TOKEN_ADDRESS, + TOKEN_MULTIPLIER_SETTER, + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + + // Second proposal should fail + vm.expectRevert(abi.encodeWithSelector(ChainRegistrar.ChainIsAlreadyProposed.selector)); + vm.prank(proposer); + chainRegistrar.proposeChainRegistration( + CHAIN_ID, + PubdataPricingMode.Rollup, + BLOB_OPERATOR, + OPERATOR, + GOVERNOR, + ETH_TOKEN_ADDRESS, + TOKEN_MULTIPLIER_SETTER, + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + } + + function test_ProposeChainRegistration_Event() public { + vm.expectEmit(true, false, false, true); + emit ChainRegistrar.NewChainRegistrationProposal(CHAIN_ID, proposer); + + vm.prank(proposer); + chainRegistrar.proposeChainRegistration( + CHAIN_ID, + PubdataPricingMode.Rollup, + BLOB_OPERATOR, + OPERATOR, + GOVERNOR, + ETH_TOKEN_ADDRESS, + TOKEN_MULTIPLIER_SETTER, + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + } + + function test_ChangeDeployer() public { + address newDeployer = makeAddr("newDeployer"); + + vm.expectEmit(true, false, false, true); + emit ChainRegistrar.L2DeployerChanged(newDeployer); + + vm.prank(owner); + chainRegistrar.changeDeployer(newDeployer); + + assertEq(chainRegistrar.l2Deployer(), newDeployer); + } + + function test_ChangeDeployer_Unauthorized() public { + address newDeployer = makeAddr("newDeployer"); + + vm.expectRevert("Ownable: caller is not the owner"); + vm.prank(proposer); + chainRegistrar.changeDeployer(newDeployer); + } + + function test_GetRegisteredChainConfig() public { + // Mock the chain as deployed + vm.mockCall( + mockBridgehub, + abi.encodeWithSelector(IBridgehubBase.chainTypeManager.selector, CHAIN_ID), + abi.encode(mockChainTypeManager) + ); + + ChainRegistrar.RegisteredChainConfig memory config = chainRegistrar.getRegisteredChainConfig(CHAIN_ID); + + assertEq(config.pendingChainAdmin, address(0x555)); + assertEq(config.chainAdmin, address(0x666)); + assertEq(config.diamondProxy, mockDiamondProxy); + assertEq(config.l2BridgeAddress, address(0x777)); + } + + function test_GetRegisteredChainConfig_ChainNotDeployed() public { + uint256 nonExistentChainId = 999; + + vm.mockCall( + mockBridgehub, + abi.encodeWithSelector(IBridgehubBase.chainTypeManager.selector, nonExistentChainId), + abi.encode(address(0)) + ); + + vm.expectRevert(abi.encodeWithSelector(ChainRegistrar.ChainIsNotYetDeployed.selector)); + chainRegistrar.getRegisteredChainConfig(nonExistentChainId); + } + + function test_GetRegisteredChainConfig_BridgeNotRegistered() public { + // Mock the chain as deployed + vm.mockCall( + mockBridgehub, + abi.encodeWithSelector(IBridgehubBase.chainTypeManager.selector, CHAIN_ID), + abi.encode(mockChainTypeManager) + ); + + vm.mockCall( + mockAssetRouter, + abi.encodeWithSelector(IL1SharedBridgeLegacy.l2BridgeAddress.selector, CHAIN_ID), + abi.encode(address(0)) // No bridge registered + ); + + vm.expectRevert(abi.encodeWithSelector(ChainRegistrar.BridgeIsNotRegistered.selector)); + chainRegistrar.getRegisteredChainConfig(CHAIN_ID); + } + + function test_ProposeChainRegistration_ValidiumMode() public { + vm.prank(proposer); + chainRegistrar.proposeChainRegistration( + CHAIN_ID, + PubdataPricingMode.Validium, + BLOB_OPERATOR, + OPERATOR, + GOVERNOR, + ETH_TOKEN_ADDRESS, + TOKEN_MULTIPLIER_SETTER, + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + + (uint256 chainId, , , , , PubdataPricingMode pubdataPricingMode) = chainRegistrar.proposedChains( + proposer, + CHAIN_ID + ); + assertEq(chainId, CHAIN_ID); + assertEq(uint256(pubdataPricingMode), uint256(PubdataPricingMode.Validium)); + } + + function test_ProposeChainRegistration_DifferentGasMultipliers() public { + uint128 nominator = 2000; + uint128 denominator = 1000; + + vm.prank(proposer); + chainRegistrar.proposeChainRegistration( + CHAIN_ID, + PubdataPricingMode.Rollup, + BLOB_OPERATOR, + OPERATOR, + GOVERNOR, + ETH_TOKEN_ADDRESS, + TOKEN_MULTIPLIER_SETTER, + nominator, + denominator + ); + + (uint256 chainId, ChainRegistrar.BaseToken memory baseToken, , , , ) = chainRegistrar.proposedChains( + proposer, + CHAIN_ID + ); + assertEq(chainId, CHAIN_ID); + assertEq(baseToken.gasPriceMultiplierNominator, nominator); + assertEq(baseToken.gasPriceMultiplierDenominator, denominator); + } + + function test_ProposeChainRegistration_ZeroAddresses() public { + vm.prank(proposer); + chainRegistrar.proposeChainRegistration( + CHAIN_ID, + PubdataPricingMode.Rollup, + address(0), // Zero blob operator + address(0), // Zero operator + address(0), // Zero governor + ETH_TOKEN_ADDRESS, + address(0), // Zero token multiplier setter + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + + ( + uint256 chainId, + ChainRegistrar.BaseToken memory baseToken, + address blobOperator, + address operator, + address governor, + + ) = chainRegistrar.proposedChains(proposer, CHAIN_ID); + assertEq(chainId, CHAIN_ID); + assertEq(blobOperator, address(0)); + assertEq(operator, address(0)); + assertEq(governor, address(0)); + assertEq(baseToken.tokenMultiplierSetter, address(0)); + } + + function test_ProposeChainRegistration_ERC20_ExactAmount() public { + // Calculate exact amount needed + uint256 amount = (1 ether * GAS_PRICE_MULTIPLIER_NOMINATOR) / GAS_PRICE_MULTIPLIER_DENOMINATOR; + + // Approve exact amount to the ChainRegistrar contract + vm.prank(proposer); + testToken.approve(address(chainRegistrar), amount); + + vm.prank(proposer); + chainRegistrar.proposeChainRegistration( + CHAIN_ID, + PubdataPricingMode.Rollup, + BLOB_OPERATOR, + OPERATOR, + GOVERNOR, + address(testToken), + TOKEN_MULTIPLIER_SETTER, + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + + // Check that the proposal was stored + (uint256 chainId, , , , , ) = chainRegistrar.proposedChains(proposer, CHAIN_ID); + assertEq(chainId, CHAIN_ID); + } + + function test_ProposeChainRegistration_ERC20_MoreThanNeeded() public { + // Calculate exact amount needed + uint256 amount = (1 ether * GAS_PRICE_MULTIPLIER_NOMINATOR) / GAS_PRICE_MULTIPLIER_DENOMINATOR; + + // Approve more than needed to the ChainRegistrar contract + vm.prank(proposer); + testToken.approve(address(chainRegistrar), amount * 2); + + vm.prank(proposer); + chainRegistrar.proposeChainRegistration( + CHAIN_ID, + PubdataPricingMode.Rollup, + BLOB_OPERATOR, + OPERATOR, + GOVERNOR, + address(testToken), + TOKEN_MULTIPLIER_SETTER, + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + + // Check that the proposal was stored + (uint256 chainId, , , , , ) = chainRegistrar.proposedChains(proposer, CHAIN_ID); + assertEq(chainId, CHAIN_ID); + } + + function test_ProposeChainRegistration_ERC20_AlreadyHasBalance() public { + // Give l2Deployer some tokens + testToken.mint(l2Deployer, 1 ether); + + vm.prank(proposer); + chainRegistrar.proposeChainRegistration( + CHAIN_ID, + PubdataPricingMode.Rollup, + BLOB_OPERATOR, + OPERATOR, + GOVERNOR, + address(testToken), + TOKEN_MULTIPLIER_SETTER, + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + + // Check that the proposal was stored + (uint256 chainId, , , , , ) = chainRegistrar.proposedChains(proposer, CHAIN_ID); + assertEq(chainId, CHAIN_ID); + } + + function test_ProposeChainRegistration_MultipleProposers() public { + address proposer2 = makeAddr("proposer2"); + + // Mock the second chain ID as not deployed + vm.mockCall( + mockBridgehub, + abi.encodeWithSelector(IBridgehubBase.chainTypeManager.selector, CHAIN_ID + 1), + abi.encode(address(0)) + ); + + // First proposer + vm.prank(proposer); + chainRegistrar.proposeChainRegistration( + CHAIN_ID, + PubdataPricingMode.Rollup, + BLOB_OPERATOR, + OPERATOR, + GOVERNOR, + ETH_TOKEN_ADDRESS, + TOKEN_MULTIPLIER_SETTER, + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + + // Second proposer with different chain ID + vm.prank(proposer2); + chainRegistrar.proposeChainRegistration( + CHAIN_ID + 1, + PubdataPricingMode.Validium, + address(0x888), + address(0x999), + address(0xAAA), + ETH_TOKEN_ADDRESS, + address(0xBBB), + GAS_PRICE_MULTIPLIER_NOMINATOR, + GAS_PRICE_MULTIPLIER_DENOMINATOR + ); + + // Check both proposals + (uint256 chainId1, , , , , PubdataPricingMode pubdataPricingMode1) = chainRegistrar.proposedChains( + proposer, + CHAIN_ID + ); + (uint256 chainId2, , , , , PubdataPricingMode pubdataPricingMode2) = chainRegistrar.proposedChains( + proposer2, + CHAIN_ID + 1 + ); + + assertEq(chainId1, CHAIN_ID); + assertEq(chainId2, CHAIN_ID + 1); + assertEq(uint256(pubdataPricingMode1), uint256(PubdataPricingMode.Rollup)); + assertEq(uint256(pubdataPricingMode2), uint256(PubdataPricingMode.Validium)); + } +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/FacetCut.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/FacetCut.t.sol index 4f1d0197fa..0e646b60ae 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/FacetCut.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/FacetCut.t.sol @@ -11,6 +11,7 @@ import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters import {MailboxFacet} from "contracts/state-transition/chain-deps/facets/Mailbox.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {AddressHasNoCode, FacetExists, NoFunctionsForDiamondCut, RemoveFunctionFacetAddressNotZero, RemoveFunctionFacetAddressZero, ReplaceFunctionFacetAddressZero, SelectorsMustAllHaveSameFreezability, ZeroAddress} from "contracts/common/L1ContractErrors.sol"; +import {PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "contracts/common/Config.sol"; contract FacetCutTest is DiamondCutTest { MailboxFacet private mailboxFacet; @@ -33,7 +34,14 @@ contract FacetCutTest is DiamondCutTest { eraChainId = 9; diamondCutTestContract = new DiamondCutTestContract(); IEIP7702Checker eip7702Checker = IEIP7702Checker(Utils.deployEIP7702Checker()); - mailboxFacet = new MailboxFacet(eraChainId, block.chainid, eip7702Checker); + mailboxFacet = new MailboxFacet( + eraChainId, + block.chainid, + address(0), + eip7702Checker, + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ); gettersFacet = new GettersFacet(); executorFacet1 = new ExecutorFacet(block.chainid); executorFacet2 = new ExecutorFacet(block.chainid); diff --git a/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/Initialization.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/Initialization.t.sol index 3d3016f996..c2e9038b96 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/Initialization.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/Initialization.t.sol @@ -39,7 +39,7 @@ contract InitializationTest is DiamondCutTest { DiamondInit diamondInit = new DiamondInit(false); bytes memory diamondInitData = abi.encodeWithSelector( diamondInit.initialize.selector, - Utils.makeInitializeData(address(0)) + Utils.makeInitializeData(address(0), address(0)) ); Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](0); diff --git a/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/UpgradeLogic.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/UpgradeLogic.t.sol index da5fc15024..9bcbd13297 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/UpgradeLogic.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/UpgradeLogic.t.sol @@ -17,6 +17,7 @@ import {DummyBridgehub} from "contracts/dev-contracts/test/DummyBridgehub.sol"; import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; import {DiamondAlreadyFrozen, DiamondNotFrozen, Unauthorized} from "contracts/common/L1ContractErrors.sol"; import {RollupDAManager} from "contracts/state-transition/data-availability/RollupDAManager.sol"; +import {CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "contracts/common/Config.sol"; contract UpgradeLogicTest is DiamondCutTest { DiamondProxy private diamondProxy; @@ -24,9 +25,11 @@ contract UpgradeLogicTest is DiamondCutTest { AdminFacet private adminFacet; AdminFacet private proxyAsAdmin; GettersFacet private proxyAsGetters; + address interopCenter = makeAddr("interopCenter"); address private admin; address private chainTypeManager; address private randomSigner; + bytes32 baseTokenAssetId = DataEncoding.encodeNTVAssetId(1, (makeAddr("baseToken"))); function getAdminSelectors() private view returns (bytes4[] memory) { bytes4[] memory selectors = new bytes4[](11); @@ -53,7 +56,14 @@ contract UpgradeLogicTest is DiamondCutTest { diamondCutTestContract = new DiamondCutTestContract(); diamondInit = new DiamondInit(false); - adminFacet = new AdminFacet(block.chainid, RollupDAManager(address(0))); + adminFacet = new AdminFacet( + block.chainid, + RollupDAManager(address(0)), + CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, + CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ); gettersFacet = new GettersFacet(); Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](2); @@ -81,10 +91,11 @@ contract UpgradeLogicTest is DiamondCutTest { chainId: 1, bridgehub: address(dummyBridgehub), chainTypeManager: chainTypeManager, + interopCenter: interopCenter, protocolVersion: 0, admin: admin, validatorTimelock: makeAddr("validatorTimelock"), - baseTokenAssetId: DataEncoding.encodeNTVAssetId(1, (makeAddr("baseToken"))), + baseTokenAssetId: baseTokenAssetId, storedBatchZero: bytes32(0), // genesisBatchHash: 0x02c775f0a90abf7a0e8043f2fdc38f0580ca9f9996a895d05a501bfeaa3b2e21, // genesisIndexRepeatedStorageChanges: 0, @@ -115,6 +126,7 @@ contract UpgradeLogicTest is DiamondCutTest { initCalldata: diamondInitCalldata }); + mockDiamondInitInteropCenterCallsWithAddress(address(dummyBridgehub), address(0), baseTokenAssetId); diamondProxy = new DiamondProxy(block.chainid, diamondCutData); proxyAsAdmin = AdminFacet(address(diamondProxy)); proxyAsGetters = GettersFacet(address(diamondProxy)); diff --git a/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/_DiamondCut_Shared.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/_DiamondCut_Shared.t.sol index 63e88b2d86..63c3bb83b8 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/_DiamondCut_Shared.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/DiamondCut/_DiamondCut_Shared.t.sol @@ -2,10 +2,11 @@ pragma solidity 0.8.28; import {Test} from "forge-std/Test.sol"; +import {UtilsTest} from "foundry-test/l1/unit/concrete/Utils/Utils.t.sol"; import {DiamondCutTestContract} from "contracts/dev-contracts/test/DiamondCutTestContract.sol"; import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; -contract DiamondCutTest is Test { +contract DiamondCutTest is UtilsTest { DiamondCutTestContract internal diamondCutTestContract; GettersFacet internal gettersFacet; } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Executor/Committing.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Executor/Committing.t.sol index 88196bb592..dac618db6f 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Executor/Committing.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Executor/Committing.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.28; import "forge-std/console.sol"; import {Vm} from "forge-std/Test.sol"; -import {L2_BOOTLOADER_ADDRESS, L2_SYSTEM_CONTEXT_ADDRESS, Utils} from "../Utils/Utils.sol"; +import {EVENT_INDEX, L2_BOOTLOADER_ADDRESS, L2_SYSTEM_CONTEXT_ADDRESS, Utils} from "../Utils/Utils.sol"; import {EMPTY_PREPUBLISHED_COMMITMENT, ExecutorTest, POINT_EVALUATION_PRECOMPILE_RESULT} from "./_Executor_Shared.t.sol"; import {IExecutor, SystemLogKey, TOTAL_BLOBS_IN_COMMITMENT} from "contracts/state-transition/chain-interfaces/IExecutor.sol"; @@ -225,7 +225,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); vm.blobhashes(defaultBlobVersionedHashes); - vm.expectRevert(abi.encodeWithSelector(MissingSystemLogs.selector, 511, 509)); + vm.expectRevert(abi.encodeWithSelector(MissingSystemLogs.selector, 1023, 1021)); (uint256 commitBatchFrom, uint256 commitBatchTo, bytes memory commitData) = Utils.encodeCommitBatchesData( genesisStoredBatchInfo, wrongNewCommitBatchInfoArray @@ -423,7 +423,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - uint256 allLogsProcessed = uint256(511); + uint256 allLogsProcessed = uint256(1023); vm.expectRevert( abi.encodeWithSelector(MissingSystemLogs.selector, allLogsProcessed, allLogsProcessed ^ (1 << i)) ); @@ -504,11 +504,11 @@ contract CommittingTest is ExecutorTest { Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(entries.length, 1); - assertEq(entries[0].topics[0], keccak256("BlockCommit(uint256,bytes32,bytes32)")); - assertEq(entries[0].topics[1], bytes32(uint256(1))); // batchNumber - assertEq(entries[0].topics[2], correctNewCommitBatchInfo.newStateRoot); // batchHash - assertEq(entries[0].topics[3], expectedBatchCommitment); // commitment + assertEq(entries.length, 1 + EVENT_INDEX); + assertEq(entries[EVENT_INDEX].topics[0], keccak256("BlockCommit(uint256,bytes32,bytes32)")); + assertEq(entries[EVENT_INDEX].topics[1], bytes32(uint256(1))); // batchNumber + assertEq(entries[EVENT_INDEX].topics[2], correctNewCommitBatchInfo.newStateRoot); // batchHash + assertEq(entries[EVENT_INDEX].topics[3], expectedBatchCommitment); // commitment uint256 totalBatchesCommitted = getters.getTotalBatchesCommitted(); assertEq(totalBatchesCommitted, 1); @@ -544,9 +544,9 @@ contract CommittingTest is ExecutorTest { Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(entries.length, 1); - assertEq(entries[0].topics[0], keccak256("BlockCommit(uint256,bytes32,bytes32)")); - assertEq(entries[0].topics[1], bytes32(uint256(1))); // batchNumber + assertEq(entries.length, 1 + EVENT_INDEX); + assertEq(entries[EVENT_INDEX].topics[0], keccak256("BlockCommit(uint256,bytes32,bytes32)")); + assertEq(entries[EVENT_INDEX].topics[1], bytes32(uint256(1))); // batchNumber uint256 totalBatchesCommitted = getters.getTotalBatchesCommitted(); assertEq(totalBatchesCommitted, 1); @@ -613,9 +613,9 @@ contract CommittingTest is ExecutorTest { Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(entries.length, 1); - assertEq(entries[0].topics[0], keccak256("BlockCommit(uint256,bytes32,bytes32)")); - assertEq(entries[0].topics[1], bytes32(uint256(1))); // batchNumber + assertEq(entries.length, 1 + EVENT_INDEX); + assertEq(entries[EVENT_INDEX].topics[0], keccak256("BlockCommit(uint256,bytes32,bytes32)")); + assertEq(entries[EVENT_INDEX].topics[1], bytes32(uint256(1))); // batchNumber uint256 totalBatchesCommitted = getters.getTotalBatchesCommitted(); assertEq(totalBatchesCommitted, 1); @@ -1025,25 +1025,25 @@ contract CommittingTest is ExecutorTest { ); } - struct MessageRoot { + struct InteropRoot { uint256 chainId; uint256 blockNumber; // We double overloading this. The sides normally contain the root, as well as the sides. - // Second overloading: if the length is 1, we are importing a chainBatchRoot/messageRoot instead of sides. + // Second overloading: if the length is 1, we are importing a chainBatchRoot/InteropRoot instead of sides. bytes32[] sides; } function test_recalculateinteropRootRollingHash() public { - MessageRoot[] memory interopRoots = new MessageRoot[](2); - MessageRoot memory interopRoot1 = MessageRoot({chainId: 260, blockNumber: 1, sides: new bytes32[](1)}); + InteropRoot[] memory interopRoots = new InteropRoot[](2); + InteropRoot memory interopRoot1 = InteropRoot({chainId: 260, blockNumber: 1, sides: new bytes32[](1)}); interopRoot1.sides[0] = 0xfb2eb93318710c98f501f6ff6b11c373baccd0ffcaefe15f97debe09cb7939e1; interopRoots[0] = interopRoot1; - MessageRoot memory interopRoot2 = MessageRoot({chainId: 506, blockNumber: 17, sides: new bytes32[](1)}); + InteropRoot memory interopRoot2 = InteropRoot({chainId: 506, blockNumber: 17, sides: new bytes32[](1)}); interopRoot2.sides[0] = 0xf83b13aa476ef3253e6acff5779276da7924fabaec9a8c39274cf021efe1255a; interopRoots[1] = interopRoot2; bytes32 rollingHash = 0x0000000000000000000000000000000000000000000000000000000000000000; for (uint256 i = 0; i < interopRoots.length; i++) { - MessageRoot memory interopRoot = interopRoots[i]; + InteropRoot memory interopRoot = interopRoots[i]; console.logBytes( abi.encodePacked( rollingHash, diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Executor/Executing.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Executor/Executing.t.sol index bf5062765c..dc6e54ae56 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Executor/Executing.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Executor/Executing.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; -import {Vm} from "forge-std/Test.sol"; -import {L2_SYSTEM_CONTEXT_ADDRESS, Utils} from "../Utils/Utils.sol"; +import {StdStorage, Test, Vm, stdStorage} from "forge-std/Test.sol"; +import {EVENT_INDEX, L2_SYSTEM_CONTEXT_ADDRESS, Utils} from "../Utils/Utils.sol"; import {EMPTY_PREPUBLISHED_COMMITMENT, ExecutorTest, POINT_EVALUATION_PRECOMPILE_RESULT} from "./_Executor_Shared.t.sol"; @@ -10,8 +10,14 @@ import {POINT_EVALUATION_PRECOMPILE_ADDR, REQUIRED_L2_GAS_PRICE_PER_PUBDATA, TES import {L2_BOOTLOADER_ADDRESS} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {IExecutor, SystemLogKey} from "contracts/state-transition/chain-interfaces/IExecutor.sol"; import {BatchHashMismatch, CantExecuteUnprovenBatches, NonSequentialBatch, PriorityOperationsRollingHashMismatch, QueueIsEmpty} from "contracts/common/L1ContractErrors.sol"; +import {PriorityOpsBatchInfo, PriorityTree} from "contracts/state-transition/libraries/PriorityTree.sol"; +import {BatchDecoder} from "contracts/state-transition/libraries/BatchDecoder.sol"; +import {InteropRoot} from "contracts/common/Messaging.sol"; +import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; contract ExecutingTest is ExecutorTest { + using stdStorage for StdStorage; + bytes32 l2DAValidatorOutputHash; bytes32[] blobVersionedHashes; @@ -40,6 +46,10 @@ contract ExecutingTest is ExecutorTest { priorityOpsHashes = hashes; } + function getV30UpgradeChainBatchNumberLocation(bytes32 _chainId) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(_chainId, uint256(11))); + } + function setUp() public { generatePriorityOps(2); @@ -127,14 +137,14 @@ contract ExecutingTest is ExecutorTest { newStoredBatchInfo = IExecutor.StoredBatchInfo({ batchNumber: 1, - batchHash: entries[0].topics[2], + batchHash: entries[EVENT_INDEX].topics[2], indexRepeatedStorageChanges: 0, numberOfLayer1Txs: priorityOpsHashes.length, priorityOperationsHash: correctRollingHash, dependencyRootsRollingHash: bytes32(0), l2LogsTreeRoot: 0, timestamp: currentTimestamp, - commitment: entries[0].topics[3] + commitment: entries[EVENT_INDEX].topics[3] }); IExecutor.StoredBatchInfo[] memory storedBatchInfoArray = new IExecutor.StoredBatchInfo[](1); @@ -160,10 +170,18 @@ contract ExecutingTest is ExecutorTest { vm.prank(validator); vm.expectRevert(NonSequentialBatch.selector); - (uint256 executeBatchFrom, uint256 executeBatchTo, bytes memory executeData) = Utils.encodeExecuteBatchesData( - storedBatchInfoArray, - Utils.generatePriorityOps(storedBatchInfoArray.length) + (uint256 executeBatchFrom, uint256 executeBatchTo, bytes memory executeData) = Utils + .encodeExecuteBatchesDataZeroLogs( + storedBatchInfoArray, + Utils.generatePriorityOps(storedBatchInfoArray.length) + ); + vm.mockCall( + address(messageRoot), + abi.encodeWithSelector(IMessageRoot.addChainBatchRoot.selector, 9, 10, bytes32(0)), + abi.encode() ); + + vm.store(address(messageRoot), getV30UpgradeChainBatchNumberLocation(bytes32(l2ChainId)), bytes32(uint256(1))); executor.executeBatchesSharedBridge(address(0), executeBatchFrom, executeBatchTo, executeData); } @@ -184,10 +202,11 @@ contract ExecutingTest is ExecutorTest { keccak256(abi.encode(wrongNewStoredBatchInfo)) ) ); - (uint256 executeBatchFrom, uint256 executeBatchTo, bytes memory executeData) = Utils.encodeExecuteBatchesData( - storedBatchInfoArray, - Utils.generatePriorityOps(storedBatchInfoArray.length) - ); + (uint256 executeBatchFrom, uint256 executeBatchTo, bytes memory executeData) = Utils + .encodeExecuteBatchesDataZeroLogs( + storedBatchInfoArray, + Utils.generatePriorityOps(storedBatchInfoArray.length) + ); executor.executeBatchesSharedBridge(address(0), executeBatchFrom, executeBatchTo, executeData); } @@ -202,10 +221,11 @@ contract ExecutingTest is ExecutorTest { vm.prank(validator); vm.expectRevert(CantExecuteUnprovenBatches.selector); - (uint256 executeBatchFrom, uint256 executeBatchTo, bytes memory executeData) = Utils.encodeExecuteBatchesData( - storedBatchInfoArray, - Utils.generatePriorityOps(storedBatchInfoArray.length) - ); + (uint256 executeBatchFrom, uint256 executeBatchTo, bytes memory executeData) = Utils + .encodeExecuteBatchesDataZeroLogs( + storedBatchInfoArray, + Utils.generatePriorityOps(storedBatchInfoArray.length) + ); executor.executeBatchesSharedBridge(address(0), executeBatchFrom, executeBatchTo, executeData); } @@ -253,10 +273,10 @@ contract ExecutingTest is ExecutorTest { Vm.Log[] memory entries = vm.getRecordedLogs(); IExecutor.StoredBatchInfo memory correctNewStoredBatchInfo = newStoredBatchInfo; - correctNewStoredBatchInfo.batchHash = entries[0].topics[2]; + correctNewStoredBatchInfo.batchHash = entries[EVENT_INDEX].topics[2]; correctNewStoredBatchInfo.numberOfLayer1Txs = 1; correctNewStoredBatchInfo.priorityOperationsHash = correctRollingHash; - correctNewStoredBatchInfo.commitment = entries[0].topics[3]; + correctNewStoredBatchInfo.commitment = entries[EVENT_INDEX].topics[3]; IExecutor.StoredBatchInfo[] memory correctNewStoredBatchInfoArray = new IExecutor.StoredBatchInfo[](1); correctNewStoredBatchInfoArray[0] = correctNewStoredBatchInfo; @@ -277,7 +297,7 @@ contract ExecutingTest is ExecutorTest { vm.prank(validator); // vm.expectRevert(QueueIsEmpty.selector); { - (processBatchFrom, processBatchTo, processData) = Utils.encodeExecuteBatchesData( + (processBatchFrom, processBatchTo, processData) = Utils.encodeExecuteBatchesDataZeroLogs( correctNewStoredBatchInfoArray, Utils.generatePriorityOps(correctNewStoredBatchInfoArray.length, 1) ); @@ -334,10 +354,10 @@ contract ExecutingTest is ExecutorTest { Vm.Log[] memory entries = vm.getRecordedLogs(); IExecutor.StoredBatchInfo memory correctNewStoredBatchInfo = newStoredBatchInfo; - correctNewStoredBatchInfo.batchHash = entries[0].topics[2]; + correctNewStoredBatchInfo.batchHash = entries[EVENT_INDEX].topics[2]; correctNewStoredBatchInfo.numberOfLayer1Txs = 2; correctNewStoredBatchInfo.priorityOperationsHash = correctRollingHash; - correctNewStoredBatchInfo.commitment = entries[0].topics[3]; + correctNewStoredBatchInfo.commitment = entries[EVENT_INDEX].topics[3]; IExecutor.StoredBatchInfo[] memory correctNewStoredBatchInfoArray = new IExecutor.StoredBatchInfo[](1); correctNewStoredBatchInfoArray[0] = correctNewStoredBatchInfo; @@ -380,7 +400,7 @@ contract ExecutingTest is ExecutorTest { vm.expectRevert(PriorityOperationsRollingHashMismatch.selector); { - (processBatchFrom, processBatchTo, processData) = Utils.encodeExecuteBatchesData( + (processBatchFrom, processBatchTo, processData) = Utils.encodeExecuteBatchesDataZeroLogs( correctNewStoredBatchInfoArray, Utils.generatePriorityOps(correctNewStoredBatchInfoArray.length, 2) ); @@ -431,10 +451,11 @@ contract ExecutingTest is ExecutorTest { storedBatchInfoArray[0] = newStoredBatchInfo; vm.prank(validator); - (uint256 executeBatchFrom, uint256 executeBatchTo, bytes memory executeData) = Utils.encodeExecuteBatchesData( - storedBatchInfoArray, - Utils.generatePriorityOps(storedBatchInfoArray.length) - ); + (uint256 executeBatchFrom, uint256 executeBatchTo, bytes memory executeData) = Utils + .encodeExecuteBatchesDataZeroLogs( + storedBatchInfoArray, + Utils.generatePriorityOps(storedBatchInfoArray.length) + ); executor.executeBatchesSharedBridge(address(0), executeBatchFrom, executeBatchTo, executeData); uint256 totalBlocksExecuted = getters.getTotalBlocksExecuted(); @@ -456,11 +477,255 @@ contract ExecutingTest is ExecutorTest { storedBatchInfoArray[0] = newStoredBatchInfo; vm.prank(validator); - (uint256 executeBatchFrom, uint256 executeBatchTo, bytes memory executeData) = Utils.encodeExecuteBatchesData( - storedBatchInfoArray, - Utils.generatePriorityOps(storedBatchInfoArray.length) - ); + (uint256 executeBatchFrom, uint256 executeBatchTo, bytes memory executeData) = Utils + .encodeExecuteBatchesDataZeroLogs( + storedBatchInfoArray, + Utils.generatePriorityOps(storedBatchInfoArray.length) + ); validatorTimelock.executeBatchesSharedBridge(address(executor), executeBatchFrom, executeBatchTo, executeData); vm.snapshotGasLastCall("Executor", "execute"); } + + /// This test takes data from real execution and recomputes the dependency roots rolling hash. + function test_logExecuteData() public { + uint256 from = 6798; + bytes + memory data = hex"01000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000062000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000001a8ed62acaf39783208fcddaee684e5ca2b7693fbb5978af4bd7ddd81bcdc9c175f20000000000000000000000000000000000000000000000000000000000001d5d0000000000000000000000000000000000000000000000000000000000000002f6005bf5b16c8b491f81c6cb92f917a8d5c0e10bd5b689b16ac47fcdd1220dba3e877fdd7b3f9fa7adeaca0b88430160762b5587f2758efcd1529ab3f763de823c6edec289e5512922c72dbbd9c3ebed59efea54288623f12ac0afb1e990b2930000000000000000000000000000000000000000000000000000000068a053fa21aad8d32fd5881588f6bd644f621208e8bfc1459c1f791e62059b49630fd780000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000d88ad2594ee8b981d3ef5420ad5250ed9de1436d076721bbcb9a15e7b18ebb31a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e5ed16037fb652be5487cdb073056e0554e1e9c05fdc7da0950f01ced4172c1c0c465544d4708f3b545c61d29cef84640cdac305ffd09c9beaa19aca9fc6b2820000000000000000000000000000000000000000000000000000000000000000a05c8f714cd022cb5ac8d5629b9f95e2455b4ca712b309e72daf16b18f63ead400000000000000000000000000000000000000000000000000000000000000003c5b8adbf4175733f7900bbc6a0ef3563dd7cd559197a2e5db83a2210e8249d50000000000000000000000000000000000000000000000000000000000000000cedbc7e1c8c59d9200d4b8405aab5d8c861bcea996b682067305bba074020e2e49d3823456c36ff9d77facc2e5464b6d674ee4b6cb3cb5dc6c4db2f3f70d41f9000000000000000000000000000000000000000000000000000000000000000da414724b068c2c5667efd7e961bd2dbca337e29bc984b69320b0b11947dfe0a2000000000000000000000000000000000000000000000000000000000000000069b1b11c3655dd725a46f3bcfc4305c3022d8dd6ae6502190571a9b709a2a8e87388b7ae694d650f6347f3c593e33a95a91deeed22c74af1326c4d363823933b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c992ef0bdf73920fea3895cd7509b383e866f9ba569634617668279f44aca7e80000000000000000000000000000000000000000000000000000000000000000c75a4c92cc0306b976ea3d1c389f01eac5d786b3a2778027be39b027baea4ac800000000000000000000000000000000000000000000000000000000000000008460ccfbf1cf677570dc773f4d4b1dc6099a7243d2c296aaed6653800a38c171000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002212064ced811e7dd5b4d3406890595c4670cae0bfde889412a159e39ec5c72ff999ec81b5c8dbe6ea0f391758aac7fc247734dcc8aee54a85375cd48f42e5b080000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003c00000000000000000000000000000000000000000000000000000000000000460000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000006e00000000000000000000000000000000000000000000000000000000000000780000000000000000000000000000000000000000000000000000000000000082000000000000000000000000000000000000000000000000000000000000008c000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000aa00000000000000000000000000000000000000000000000000000000000000b400000000000000000000000000000000000000000000000000000000000000be00000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000d200000000000000000000000000000000000000000000000000000000000000dc00000000000000000000000000000000000000000000000000000000000000e60000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f651000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000014fb886c527b4ab9848965f039693acd91b9c0b3bcbeab58989bb1df2be75da95000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f61c0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000192c801c7e325122d296d07d27c254ad37858a3358423d0401f38077f5a3aae4f000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f60200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001602244f967799d0f74520b98c357d7d554118296c5ed31c6f7a6856df3fad066000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5fe000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000017de74f9b2bfee16d512c059dc07c405fd0bc79bfb13bb3b6dc67e517e93460a5000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5fa0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000114801f399a371ff59d38d7f78918ac277df43389073af074b37aac86cabd2338000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5f900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001eabc2446af29d65ca3dc77afd5389015093298a78dc9d4efc9330e10c2e183ea000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5f700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001ff7d87e25ade5a049177cac0c9a68821483780c005474ffaebc28ef6316cf618000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5ee000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000012c4110442b096562abff4741c2c96e8cae008048cc576daa5d76dc33cbd63dea000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5ed000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000019a53e2626e90094027acc7ecc75633d1abe736d5340deb0645f3ea14822d4cf2000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5ec00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001d7e03f2b5b0feb9dbe71659a71df2cabfeffe3f65eafec8c632b2c17d123a565000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5eb00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001d67c2d0cc8c0f1e1f5be8fda146b0d167397f18d139f38eb9da1b3eaf3414dea000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5ea0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000193f0b0b8c2ccabddc1c07cfaa996433d81223d91730d88fdad54804e305db8f9000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5e8000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000012335ea8e9d4f0485ff8be5691160b03a5addbdfb8e02a3f7f080c3dcc19c9944000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5e700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001a6189e72789f643eec450a3e02b87d6931c7ed4bae9ac8181c79dc9352570274000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5e6000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000015f08e0b445ec32b8bc3024359757af602777a7f1f79d3e2ec2838d5c2e13d704000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5e500000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001f03bc20cf469641ef46dfcd8c0749e81d2dfa678781b0b59308ff1c29fb329d4000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5e400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001b508657ce12647ef390fa5c91834ab66e531fdb8dce356e36bbf717d3d94b696000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5e2000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000013873ec57227b252e1257b289828722dcffa8245d5944102981e2870b5c7c00f8000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5e100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001672bebee9db3cad834b1534e6788e3a2d1fd239531caed5ea8a3ed1a6a1ab45a000000000000000000000000000000000000000000000000000000000000007b000000000000000000000000000000000000000000000000000000000001f5e000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000001c9b13eea0113427a72a055767f015187ef3af07a18a84c2eacae887756f9219a"; + + // ( + // IExecutor.StoredBatchInfo[] memory batchesData, + // PriorityOpsBatchInfo[] memory priorityOpsData, + // InteropRoot[][] memory dependencyRoots + // ) = this.decode(data, from); + // bytes32 dependencyRootsRollingHash = 0; + + // for (uint256 i = 0; i < dependencyRoots[0].length; ++i) { + // InteropRoot memory interopRoot = dependencyRoots[0][i]; + + // dependencyRootsRollingHash = keccak256( + // // solhint-disable-next-line func-named-parameters + // abi.encodePacked( + // dependencyRootsRollingHash, + // interopRoot.chainId, + // interopRoot.blockOrBatchNumber, + // interopRoot.sides + // ) + // ); + // } + + // InteropRoot[] memory dependencyRootsReordered = new InteropRoot[](dependencyRoots[0].length); + // uint256 i = 0; + + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0x602244f967799d0f74520b98c357d7d554118296c5ed31c6f7a6856df3fad066; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128514 /* [1.285e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0x7de74f9b2bfee16d512c059dc07c405fd0bc79bfb13bb3b6dc67e517e93460a5; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128510 /* [1.285e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0x14801f399a371ff59d38d7f78918ac277df43389073af074b37aac86cabd2338; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128506 /* [1.285e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0xeabc2446af29d65ca3dc77afd5389015093298a78dc9d4efc9330e10c2e183ea; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128505 /* [1.285e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0xff7d87e25ade5a049177cac0c9a68821483780c005474ffaebc28ef6316cf618; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128503 /* [1.285e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0x2c4110442b096562abff4741c2c96e8cae008048cc576daa5d76dc33cbd63dea; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128494 /* [1.284e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0x9a53e2626e90094027acc7ecc75633d1abe736d5340deb0645f3ea14822d4cf2; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128493 /* [1.284e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0xd7e03f2b5b0feb9dbe71659a71df2cabfeffe3f65eafec8c632b2c17d123a565; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128492 /* [1.284e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0xd67c2d0cc8c0f1e1f5be8fda146b0d167397f18d139f38eb9da1b3eaf3414dea; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128491 /* [1.284e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0x93f0b0b8c2ccabddc1c07cfaa996433d81223d91730d88fdad54804e305db8f9; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128490 /* [1.284e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0x2335ea8e9d4f0485ff8be5691160b03a5addbdfb8e02a3f7f080c3dcc19c9944; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128488 /* [1.284e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0xa6189e72789f643eec450a3e02b87d6931c7ed4bae9ac8181c79dc9352570274; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128487 /* [1.284e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0x5f08e0b445ec32b8bc3024359757af602777a7f1f79d3e2ec2838d5c2e13d704; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128486 /* [1.284e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0xf03bc20cf469641ef46dfcd8c0749e81d2dfa678781b0b59308ff1c29fb329d4; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128485 /* [1.284e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0xb508657ce12647ef390fa5c91834ab66e531fdb8dce356e36bbf717d3d94b696; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128484 /* [1.284e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0x3873ec57227b252e1257b289828722dcffa8245d5944102981e2870b5c7c00f8; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128482 /* [1.284e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0x672bebee9db3cad834b1534e6788e3a2d1fd239531caed5ea8a3ed1a6a1ab45a; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128481 /* [1.284e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0xc9b13eea0113427a72a055767f015187ef3af07a18a84c2eacae887756f9219a; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128480 /* [1.284e5] */, + // sides: sides + // }); + // } + + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0x92c801c7e325122d296d07d27c254ad37858a3358423d0401f38077f5a3aae4f; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128540 /* [1.285e5] */, + // sides: sides + // }); + // } + // { + // bytes32[] memory sides = new bytes32[](1); + // sides[0] = 0x4fb886c527b4ab9848965f039693acd91b9c0b3bcbeab58989bb1df2be75da95; + // dependencyRootsReordered[i++] = InteropRoot({ + // chainId: 123, + // blockOrBatchNumber: 128593 /* [1.285e5] */, + // sides: sides + // }); + // } + // bytes32 dependencyRootsRollingHash2; + + // for (uint256 i = 0; i < dependencyRootsReordered.length; i++) { + // InteropRoot memory interopRoot = dependencyRootsReordered[i]; + + // dependencyRootsRollingHash2 = keccak256( + // // solhint-disable-next-line func-named-parameters + // abi.encodePacked( + // dependencyRootsRollingHash2, + // interopRoot.chainId, + // interopRoot.blockOrBatchNumber, + // interopRoot.sides + // ) + // ); + // } + } + + function decode( + bytes calldata data, + uint256 from + ) public view returns (IExecutor.StoredBatchInfo[] memory, PriorityOpsBatchInfo[] memory, InteropRoot[][] memory) { + ( + IExecutor.StoredBatchInfo[] memory storedBatchInfos, + PriorityOpsBatchInfo[] memory priorityOpsBatchInfos, + InteropRoot[][] memory dependencyRoots, + , + , + + ) = BatchDecoder.decodeAndCheckExecuteData(data, from, from); + return (storedBatchInfos, priorityOpsBatchInfos, dependencyRoots); + } } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Executor/ExecutorProof.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Executor/ExecutorProof.t.sol index 7d1e037ee4..902b00b4de 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Executor/ExecutorProof.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Executor/ExecutorProof.t.sol @@ -11,6 +11,8 @@ import {ExecutorFacet} from "contracts/state-transition/chain-deps/facets/Execut import {IExecutor, LogProcessingOutput} from "contracts/state-transition/chain-interfaces/IExecutor.sol"; import {IVerifierV2} from "contracts/state-transition/chain-interfaces/IVerifierV2.sol"; import {IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; +import {DummyBridgehub} from "contracts/dev-contracts/test/DummyBridgehub.sol"; +import {UtilsTest} from "foundry-test/l1/unit/concrete/Utils/Utils.t.sol"; import {EraTestnetVerifier} from "contracts/state-transition/verifiers/EraTestnetVerifier.sol"; contract TestExecutorFacet is ExecutorFacet { @@ -44,10 +46,11 @@ contract TestExecutorFacet is ExecutorFacet { function test() internal virtual {} } -contract ExecutorProofTest is Test { +contract ExecutorProofTest is UtilsTest { UtilsFacet internal utilsFacet; TestExecutorFacet internal executor; address internal testnetVerifier = address(new EraTestnetVerifier(IVerifierV2(address(0)), IVerifier(address(0)))); + DummyBridgehub internal dummyBridgehub; function getTestExecutorFacetSelectors() private pure returns (bytes4[] memory) { bytes4[] memory selectors = new bytes4[](3); @@ -71,8 +74,11 @@ contract ExecutorProofTest is Test { isFreezable: true, selectors: Utils.getUtilsFacetSelectors() }); + bytes32 baseTokenAssetId = bytes32(uint256(uint160(makeAddr("baseTokenAssetId")))); + dummyBridgehub = new DummyBridgehub(); + mockDiamondInitInteropCenterCallsWithAddress(address(dummyBridgehub), address(0), baseTokenAssetId); - address diamondProxy = Utils.makeDiamondProxy(facetCuts, testnetVerifier); + address diamondProxy = Utils.makeDiamondProxy(facetCuts, testnetVerifier, address(dummyBridgehub)); executor = TestExecutorFacet(diamondProxy); utilsFacet = UtilsFacet(diamondProxy); } @@ -121,15 +127,15 @@ contract ExecutorProofTest is Test { ); assertEq( nextCommitment, - 0x9fae89899313dc524150960147a32da2521608231cb39e2741b2ca13435d3f12, + 0x34fb9fa208735dbedb259d815c79e77427a5af4b4c3c4898a98a0a6a5f1586ad, "nextCommitment computation failed" ); bytes32 prevCommitment = 0x8199d18dbc01ea80a635f515d6a12312daa1aa32b5404944477dcd41fd7b2bdf; uint256 result = executor.getBatchProofPublicInput(prevCommitment, nextCommitment); - assertEq(result, 0xC09291737B046C329198E1BEE081240EAFC26B675F0124BFB2A12FA6, "getBatchProofPublicInput"); + assertEq(result, 0xB29C9ADF0177455F74D0A0F38065E77A6D425370D418CD37DBF3EAA0, "getBatchProofPublicInput"); } // add this to be excluded from coverage report - function test() internal {} + function test() internal override {} } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Executor/Proving.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Executor/Proving.t.sol index fa1dbcf639..fc6f1d0582 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Executor/Proving.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Executor/Proving.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.28; import {Vm} from "forge-std/Test.sol"; -import {L2_SYSTEM_CONTEXT_ADDRESS, Utils} from "../Utils/Utils.sol"; +import {EVENT_INDEX, L2_SYSTEM_CONTEXT_ADDRESS, Utils} from "../Utils/Utils.sol"; import {EMPTY_PREPUBLISHED_COMMITMENT, ExecutorTest, POINT_EVALUATION_PRECOMPILE_RESULT} from "./_Executor_Shared.t.sol"; @@ -50,14 +50,14 @@ contract ProvingTest is ExecutorTest { newStoredBatchInfo = IExecutor.StoredBatchInfo({ batchNumber: 1, - batchHash: entries[0].topics[2], + batchHash: entries[EVENT_INDEX].topics[2], indexRepeatedStorageChanges: 0, numberOfLayer1Txs: 0, priorityOperationsHash: keccak256(""), l2LogsTreeRoot: 0, dependencyRootsRollingHash: bytes32(0), timestamp: currentTimestamp, - commitment: entries[0].topics[3] + commitment: entries[EVENT_INDEX].topics[3] }); } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Executor/Reverting.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Executor/Reverting.t.sol index 4586e7e5cd..baceb83b3c 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Executor/Reverting.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Executor/Reverting.t.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.28; import {Vm} from "forge-std/Test.sol"; -import {L2_SYSTEM_CONTEXT_ADDRESS, Utils} from "../Utils/Utils.sol"; +import {EVENT_INDEX, L2_SYSTEM_CONTEXT_ADDRESS, Utils} from "../Utils/Utils.sol"; import {EMPTY_PREPUBLISHED_COMMITMENT, ExecutorTest, POINT_EVALUATION_PRECOMPILE_RESULT} from "./_Executor_Shared.t.sol"; @@ -49,14 +49,14 @@ contract RevertingTest is ExecutorTest { newStoredBatchInfo = IExecutor.StoredBatchInfo({ batchNumber: 1, - batchHash: entries[0].topics[2], + batchHash: entries[EVENT_INDEX].topics[2], indexRepeatedStorageChanges: 0, numberOfLayer1Txs: 0, priorityOperationsHash: keccak256(""), dependencyRootsRollingHash: bytes32(0), l2LogsTreeRoot: 0, timestamp: currentTimestamp, - commitment: entries[0].topics[3] + commitment: entries[EVENT_INDEX].topics[3] }); IExecutor.StoredBatchInfo[] memory storedBatchInfoArray = new IExecutor.StoredBatchInfo[](1); diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Executor/_Executor_Shared.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Executor/_Executor_Shared.t.sol index 8b9d0285b8..d8137b0b0e 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Executor/_Executor_Shared.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Executor/_Executor_Shared.t.sol @@ -10,6 +10,7 @@ import {ValidatorTimelock} from "contracts/state-transition/ValidatorTimelock.so import {Utils, DEFAULT_L2_LOGS_TREE_ROOT_HASH, L2_DA_COMMITMENT_SCHEME} from "../Utils/Utils.sol"; import {TESTNET_COMMIT_TIMESTAMP_NOT_OLDER, ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; import {DummyEraBaseTokenBridge} from "contracts/dev-contracts/test/DummyEraBaseTokenBridge.sol"; +import {IAssetRouterBase} from "contracts/bridge/asset-router/IAssetRouterBase.sol"; import {DummyChainTypeManagerForValidatorTimelock as DummyCTM} from "contracts/dev-contracts/test/DummyChainTypeManagerForValidatorTimelock.sol"; import {IChainTypeManager} from "contracts/state-transition/IChainTypeManager.sol"; import {DiamondInit} from "contracts/state-transition/chain-deps/DiamondInit.sol"; @@ -30,19 +31,23 @@ import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {EraTestnetVerifier} from "contracts/state-transition/verifiers/EraTestnetVerifier.sol"; import {DummyBridgehub} from "contracts/dev-contracts/test/DummyBridgehub.sol"; import {L1MessageRoot} from "contracts/bridgehub/L1MessageRoot.sol"; +import {MessageRootBase} from "contracts/bridgehub/MessageRootBase.sol"; +import {L1ChainAssetHandler} from "contracts/bridgehub/L1ChainAssetHandler.sol"; +import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; +import {IL1Nullifier} from "contracts/bridge/interfaces/IL1Nullifier.sol"; import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; import {RollupDAManager} from "contracts/state-transition/data-availability/RollupDAManager.sol"; - -import {MessageRootBase} from "contracts/bridgehub/MessageRootBase.sol"; +import {UtilsTest} from "foundry-test/l1/unit/concrete/Utils/Utils.t.sol"; +import {CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "contracts/common/Config.sol"; bytes32 constant EMPTY_PREPUBLISHED_COMMITMENT = 0x0000000000000000000000000000000000000000000000000000000000000000; bytes constant POINT_EVALUATION_PRECOMPILE_RESULT = hex"000000000000000000000000000000000000000000000000000000000000100073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"; -contract ExecutorTest is Test { +contract ExecutorTest is UtilsTest { address internal owner; address internal validator; address internal randomSigner; @@ -61,6 +66,9 @@ contract ExecutorTest is Test { ValidatorTimelock internal validatorTimelock; address internal rollupL1DAValidator; L1MessageRoot internal messageRoot; + DummyBridgehub dummyBridgehub; + L1ChainAssetHandler internal chainAssetHandler; + bytes32 internal baseTokenAssetId = DataEncoding.encodeNTVAssetId(block.chainid, ETH_TOKEN_ADDRESS); uint256 l2ChainId; @@ -100,7 +108,7 @@ contract ExecutorTest is Test { } function getGettersSelectors() public view returns (bytes4[] memory) { - bytes4[] memory selectors = new bytes4[](32); + bytes4[] memory selectors = new bytes4[](33); uint256 i = 0; selectors[i++] = getters.getVerifier.selector; selectors[i++] = getters.getAdmin.selector; @@ -134,6 +142,7 @@ contract ExecutorTest is Test { selectors[i++] = getters.isPriorityQueueActive.selector; selectors[i++] = getters.getChainTypeManager.selector; selectors[i++] = getters.getChainId.selector; + selectors[i++] = getters.getSemverProtocolVersion.selector; return selectors; } @@ -182,29 +191,66 @@ contract ExecutorTest is Test { owner = makeAddr("owner"); validator = makeAddr("validator"); randomSigner = makeAddr("randomSigner"); - DummyBridgehub dummyBridgehub = new DummyBridgehub(); - messageRoot = new L1MessageRoot(address(dummyBridgehub)); + dummyBridgehub = new DummyBridgehub(); + vm.mockCall(address(dummyBridgehub), abi.encodeWithSelector(IL1Bridgehub.L1_CHAIN_ID.selector), abi.encode(1)); + uint256[] memory allZKChainChainIDs = new uint256[](1); + allZKChainChainIDs[0] = 271; + vm.mockCall( + address(dummyBridgehub), + abi.encodeWithSelector(IBridgehubBase.getAllZKChainChainIDs.selector), + abi.encode(allZKChainChainIDs) + ); + vm.mockCall( + address(dummyBridgehub), + abi.encodeWithSelector(IBridgehubBase.chainTypeManager.selector), + abi.encode(makeAddr("chainTypeManager")) + ); + address interopCenter = makeAddr("interopCenter"); + messageRoot = new L1MessageRoot(address(dummyBridgehub), 1); dummyBridgehub.setMessageRoot(address(messageRoot)); sharedBridge = new DummyEraBaseTokenBridge(); + address assetTracker = makeAddr("assetTracker"); + chainAssetHandler = new L1ChainAssetHandler( + owner, + address(dummyBridgehub), + address(sharedBridge), + address(messageRoot), + address(assetTracker), + IL1Nullifier(address(0)) + ); + dummyBridgehub.setChainAssetHandler(address(chainAssetHandler)); dummyBridgehub.setSharedBridge(address(sharedBridge)); - // FIXME: amend the tests as appending chain batch roots is not allowed on L1. - // vm.mockCall( - // address(messageRoot), - // abi.encodeWithSelector(MessageRootBase.addChainBatchRoot.selector, 9, 1, bytes32(0)), - // abi.encode() - // ); + vm.mockCall( + address(messageRoot), + abi.encodeWithSelector(MessageRootBase.addChainBatchRoot.selector, 9, 1, bytes32(0)), + abi.encode() + ); l2ChainId = 9; rollupL1DAValidator = Utils.deployL1RollupDAValidatorBytecode(); IEIP7702Checker eip7702Checker = IEIP7702Checker(Utils.deployEIP7702Checker()); - admin = new AdminFacet(block.chainid, RollupDAManager(address(0))); + admin = new AdminFacet( + block.chainid, + RollupDAManager(address(0)), + CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, + CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ); getters = new GettersFacet(); executor = new TestExecutor(); - mailbox = new MailboxFacet(l2ChainId, block.chainid, eip7702Checker); + mailbox = new MailboxFacet( + l2ChainId, + block.chainid, + address(chainAssetHandler), + eip7702Checker, + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ); DummyCTM chainTypeManager = new DummyCTM(owner, address(0)); vm.mockCall( @@ -234,11 +280,12 @@ contract ExecutorTest is Test { // TODO REVIEW chainId: l2ChainId, bridgehub: address(dummyBridgehub), + interopCenter: interopCenter, chainTypeManager: address(chainTypeManager), protocolVersion: 0, admin: owner, validatorTimelock: address(validatorTimelock), - baseTokenAssetId: DataEncoding.encodeNTVAssetId(block.chainid, ETH_TOKEN_ADDRESS), + baseTokenAssetId: baseTokenAssetId, storedBatchZero: keccak256(abi.encode(genesisStoredBatchInfo)), verifier: IVerifier(testnetVerifier), // verifier verifierParams: VerifierParams({ @@ -252,6 +299,7 @@ contract ExecutorTest is Test { priorityTxMaxGasLimit: 1000000, feeParams: defaultFeeParams() }); + mockDiamondInitInteropCenterCallsWithAddress(address(dummyBridgehub), address(0), baseTokenAssetId); bytes memory diamondInitData = abi.encodeWithSelector(diamondInit.initialize.selector, params); @@ -346,7 +394,7 @@ contract ExecutorTest is Test { vm.mockCall( address(sharedBridge), - abi.encodeWithSelector(IL1AssetRouter.bridgehubDepositBaseToken.selector), + abi.encodeWithSelector(IAssetRouterBase.bridgehubDepositBaseToken.selector), abi.encode(true) ); } @@ -356,5 +404,5 @@ contract ExecutorTest is Test { } // add this to be excluded from coverage report - function test() internal virtual {} + function test() internal virtual override {} } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Governance/PermanentRestriction.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Governance/PermanentRestriction.t.sol index fc6fbe2b17..35fb1a447c 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Governance/PermanentRestriction.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Governance/PermanentRestriction.t.sol @@ -14,6 +14,8 @@ import {IZKChain} from "contracts/state-transition/chain-interfaces/IZKChain.sol import {IAdmin} from "contracts/state-transition/chain-interfaces/IAdmin.sol"; import {AccessControlRestriction} from "contracts/governance/AccessControlRestriction.sol"; +import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; + import {ChainAdmin} from "contracts/governance/ChainAdmin.sol"; import {ChainTypeManagerTest} from "test/foundry/l1/unit/concrete/state-transition/ChainTypeManager/_ChainTypeManager_Shared.t.sol"; @@ -364,12 +366,14 @@ contract PermanentRestrictionTest is ChainTypeManagerTest { vm.startPrank(governor); bridgehub.addChainTypeManager(address(chainContractAddress)); bridgehub.addTokenAssetId(DataEncoding.encodeNTVAssetId(block.chainid, baseToken)); + L1MessageRoot messageRootNew = new L1MessageRoot(address(bridgehub), 1); bridgehub.setAddresses( sharedBridge, ICTMDeploymentTracker(address(0)), - new L1MessageRoot(address(bridgehub)), + messageRootNew, + address(chainAssetHandler), address(0) - ); + ); // kl todo maybe address(1) vm.stopPrank(); // ctm deployer address is 0 in this test @@ -396,14 +400,26 @@ contract PermanentRestrictionTest is ChainTypeManagerTest { abi.encodeWithSelector(IBridgehubBase.baseToken.selector, chainId), abi.encode(baseToken) ); + vm.mockCall( + address(messageRootNew), + abi.encodeWithSelector(IMessageRoot.v30UpgradeChainBatchNumber.selector), + abi.encode(0) + ); + vm.mockCall( + address(bridgehub), + abi.encodeWithSelector(IBridgehubBase.chainAssetHandler.selector), + abi.encode(chainAssetHandler) + ); vm.mockCall(address(baseToken), abi.encodeWithSelector(IERC20Metadata.name.selector), abi.encode("TestToken")); vm.mockCall(address(baseToken), abi.encodeWithSelector(IERC20Metadata.symbol.selector), abi.encode("TT")); + bytes32 baseTokenAssetId = DataEncoding.encodeNTVAssetId(block.chainid, baseToken); + mockDiamondInitInteropCenterCallsWithAddress(address(bridgehub), sharedBridge, baseTokenAssetId); vm.startPrank(governor); bridgehub.createNewChain({ _chainId: chainId, _chainTypeManager: address(chainContractAddress), - _baseTokenAssetId: DataEncoding.encodeNTVAssetId(block.chainid, baseToken), + _baseTokenAssetId: baseTokenAssetId, _salt: 0, _admin: newChainAdmin, _initData: getCTMInitData(), diff --git a/l1-contracts/test/foundry/l1/unit/concrete/SystemContractsCaller/SystemContractsCaller.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/SystemContractsCaller/SystemContractsCaller.t.sol new file mode 100644 index 0000000000..1c01b7d8eb --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/SystemContractsCaller/SystemContractsCaller.t.sol @@ -0,0 +1,505 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; + +import {CalldataForwardingMode, SystemContractsCaller, U32CastOverflow, Utils} from "contracts/common/l2-helpers/SystemContractsCaller.sol"; + +contract SystemContractsCallerTest is Test { + using SystemContractsCaller for *; + + address public constant TEST_TARGET = address(0x123); + uint32 public constant TEST_GAS_LIMIT = 100000; + uint256 public constant TEST_VALUE = 1 ether; + uint128 public constant TEST_VALUE_128 = 1 ether; + bytes public constant TEST_DATA = "test data"; + + function setUp() public {} + + function test_Utils_SafeCastToU32_Success() public { + uint256 value = 1000; + uint32 result = Utils.safeCastToU32(value); + assertEq(result, 1000); + } + + function test_Utils_SafeCastToU32_MaxValue() public { + uint256 value = type(uint32).max; + uint32 result = Utils.safeCastToU32(value); + assertEq(result, type(uint32).max); + } + + function test_Utils_SafeCastToU32_Overflow() public { + uint256 value = uint256(type(uint32).max) + 1; + vm.expectRevert(U32CastOverflow.selector); + Utils.safeCastToU32(value); + } + + function test_GetFarCallABIWithEmptyFatPointer() public { + uint32 gasPassed = 50000; + uint8 shardId = 1; + CalldataForwardingMode forwardingMode = CalldataForwardingMode.UseHeap; + bool isConstructorCall = false; + bool isSystemCall = true; + + uint256 result = SystemContractsCaller.getFarCallABIWithEmptyFatPointer( + gasPassed, + shardId, + forwardingMode, + isConstructorCall, + isSystemCall + ); + + // Check that the bits are set correctly + assertEq(result & 0xFFFFFFFF, 0); // dataOffset + assertEq((result >> 32) & 0xFFFFFFFF, 0); // memoryPage + assertEq((result >> 64) & 0xFFFFFFFF, 0); // dataStart + assertEq((result >> 96) & 0xFFFFFFFF, 0); // dataLength + assertEq((result >> 192) & 0xFFFFFFFF, gasPassed); // gasPassed + assertEq((result >> 224) & 0xFF, uint256(forwardingMode)); // forwardingMode + assertEq((result >> 232) & 0xFF, shardId); // shardId + assertEq((result >> 240) & 0x1, isConstructorCall ? 1 : 0); // isConstructorCall + assertEq((result >> 248) & 0x1, isSystemCall ? 1 : 0); // isSystemCall + } + + function test_GetFarCallABIWithEmptyFatPointer_ConstructorCall() public { + uint32 gasPassed = 50000; + uint8 shardId = 1; + CalldataForwardingMode forwardingMode = CalldataForwardingMode.UseHeap; + bool isConstructorCall = true; + bool isSystemCall = true; + + uint256 result = SystemContractsCaller.getFarCallABIWithEmptyFatPointer( + gasPassed, + shardId, + forwardingMode, + isConstructorCall, + isSystemCall + ); + + assertEq((result >> 240) & 0x1, 1); // isConstructorCall should be 1 + assertEq((result >> 248) & 0x1, 1); // isSystemCall should be 1 + } + + function test_GetFarCallABIWithEmptyFatPointer_NotSystemCall() public { + uint32 gasPassed = 50000; + uint8 shardId = 1; + CalldataForwardingMode forwardingMode = CalldataForwardingMode.UseHeap; + bool isConstructorCall = false; + bool isSystemCall = false; + + uint256 result = SystemContractsCaller.getFarCallABIWithEmptyFatPointer( + gasPassed, + shardId, + forwardingMode, + isConstructorCall, + isSystemCall + ); + + assertEq((result >> 240) & 0x1, 0); // isConstructorCall should be 0 + assertEq((result >> 248) & 0x1, 0); // isSystemCall should be 0 + } + + function test_GetFarCallABIWithEmptyFatPointer_AllForwardingModes() public { + uint32 gasPassed = 50000; + uint8 shardId = 1; + bool isConstructorCall = false; + bool isSystemCall = true; + + // Test UseHeap + uint256 result1 = SystemContractsCaller.getFarCallABIWithEmptyFatPointer( + gasPassed, + shardId, + CalldataForwardingMode.UseHeap, + isConstructorCall, + isSystemCall + ); + assertEq((result1 >> 224) & 0xFF, uint256(CalldataForwardingMode.UseHeap)); + + // Test ForwardFatPointer + uint256 result2 = SystemContractsCaller.getFarCallABIWithEmptyFatPointer( + gasPassed, + shardId, + CalldataForwardingMode.ForwardFatPointer, + isConstructorCall, + isSystemCall + ); + assertEq((result2 >> 224) & 0xFF, uint256(CalldataForwardingMode.ForwardFatPointer)); + + // Test UseAuxHeap + uint256 result3 = SystemContractsCaller.getFarCallABIWithEmptyFatPointer( + gasPassed, + shardId, + CalldataForwardingMode.UseAuxHeap, + isConstructorCall, + isSystemCall + ); + assertEq((result3 >> 224) & 0xFF, uint256(CalldataForwardingMode.UseAuxHeap)); + } + + function test_GetFarCallABI() public { + uint32 dataOffset = 0; + uint32 memoryPage = 0; + uint32 dataStart = 0x20; + uint32 dataLength = 100; + uint32 gasPassed = 50000; + uint8 shardId = 1; + CalldataForwardingMode forwardingMode = CalldataForwardingMode.UseHeap; + bool isConstructorCall = false; + bool isSystemCall = true; + + uint256 result = SystemContractsCaller.getFarCallABI( + dataOffset, + memoryPage, + dataStart, + dataLength, + gasPassed, + shardId, + forwardingMode, + isConstructorCall, + isSystemCall + ); + + // Check that all fields are set correctly + assertEq(result & 0xFFFFFFFF, dataOffset); // dataOffset + assertEq((result >> 32) & 0xFFFFFFFF, memoryPage); // memoryPage + assertEq((result >> 64) & 0xFFFFFFFF, dataStart); // dataStart + assertEq((result >> 96) & 0xFFFFFFFF, dataLength); // dataLength + assertEq((result >> 192) & 0xFFFFFFFF, gasPassed); // gasPassed + assertEq((result >> 224) & 0xFF, uint256(forwardingMode)); // forwardingMode + assertEq((result >> 232) & 0xFF, shardId); // shardId + assertEq((result >> 240) & 0x1, isConstructorCall ? 1 : 0); // isConstructorCall + assertEq((result >> 248) & 0x1, isSystemCall ? 1 : 0); // isSystemCall + } + + function test_GetFarCallABI_MaxValues() public { + uint32 dataOffset = type(uint32).max; + uint32 memoryPage = type(uint32).max; + uint32 dataStart = type(uint32).max; + uint32 dataLength = type(uint32).max; + uint32 gasPassed = type(uint32).max; + uint8 shardId = type(uint8).max; + CalldataForwardingMode forwardingMode = CalldataForwardingMode.UseAuxHeap; + bool isConstructorCall = true; + bool isSystemCall = true; + + uint256 result = SystemContractsCaller.getFarCallABI( + dataOffset, + memoryPage, + dataStart, + dataLength, + gasPassed, + shardId, + forwardingMode, + isConstructorCall, + isSystemCall + ); + + // Check that all fields are set correctly + assertEq(result & 0xFFFFFFFF, dataOffset); + assertEq((result >> 32) & 0xFFFFFFFF, memoryPage); + assertEq((result >> 64) & 0xFFFFFFFF, dataStart); + assertEq((result >> 96) & 0xFFFFFFFF, dataLength); + assertEq((result >> 192) & 0xFFFFFFFF, gasPassed); + assertEq((result >> 224) & 0xFF, uint256(forwardingMode)); + assertEq((result >> 232) & 0xFF, shardId); + assertEq((result >> 240) & 0x1, 1); + assertEq((result >> 248) & 0x1, 1); + } + + function test_GetFarCallABI_ZeroValues() public { + uint32 dataOffset = 0; + uint32 memoryPage = 0; + uint32 dataStart = 0; + uint32 dataLength = 0; + uint32 gasPassed = 0; + uint8 shardId = 0; + CalldataForwardingMode forwardingMode = CalldataForwardingMode.UseHeap; + bool isConstructorCall = false; + bool isSystemCall = false; + + uint256 result = SystemContractsCaller.getFarCallABI( + dataOffset, + memoryPage, + dataStart, + dataLength, + gasPassed, + shardId, + forwardingMode, + isConstructorCall, + isSystemCall + ); + + // Check that all fields are set correctly + assertEq(result & 0xFFFFFFFF, dataOffset); + assertEq((result >> 32) & 0xFFFFFFFF, memoryPage); + assertEq((result >> 64) & 0xFFFFFFFF, dataStart); + assertEq((result >> 96) & 0xFFFFFFFF, dataLength); + assertEq((result >> 192) & 0xFFFFFFFF, gasPassed); + assertEq((result >> 224) & 0xFF, uint256(forwardingMode)); + assertEq((result >> 232) & 0xFF, shardId); + assertEq((result >> 240) & 0x1, 0); + assertEq((result >> 248) & 0x1, 0); + } + + function test_GetFarCallABI_DifferentShardIds() public { + uint32 dataOffset = 0; + uint32 memoryPage = 0; + uint32 dataStart = 0x20; + uint32 dataLength = 100; + uint32 gasPassed = 50000; + CalldataForwardingMode forwardingMode = CalldataForwardingMode.UseHeap; + bool isConstructorCall = false; + bool isSystemCall = true; + + for (uint8 shardId = 0; shardId < 10; shardId++) { + uint256 result = SystemContractsCaller.getFarCallABI( + dataOffset, + memoryPage, + dataStart, + dataLength, + gasPassed, + shardId, + forwardingMode, + isConstructorCall, + isSystemCall + ); + + assertEq((result >> 232) & 0xFF, shardId); + } + } + + function test_GetFarCallABI_DifferentDataOffsets() public { + uint32 memoryPage = 0; + uint32 dataStart = 0x20; + uint32 dataLength = 100; + uint32 gasPassed = 50000; + uint8 shardId = 1; + CalldataForwardingMode forwardingMode = CalldataForwardingMode.UseHeap; + bool isConstructorCall = false; + bool isSystemCall = true; + + for (uint32 dataOffset = 0; dataOffset < 10; dataOffset++) { + uint256 result = SystemContractsCaller.getFarCallABI( + dataOffset, + memoryPage, + dataStart, + dataLength, + gasPassed, + shardId, + forwardingMode, + isConstructorCall, + isSystemCall + ); + + assertEq(result & 0xFFFFFFFF, dataOffset); + } + } + + function test_GetFarCallABI_DifferentDataLengths() public { + uint32 dataOffset = 0; + uint32 memoryPage = 0; + uint32 dataStart = 0x20; + uint32 gasPassed = 50000; + uint8 shardId = 1; + CalldataForwardingMode forwardingMode = CalldataForwardingMode.UseHeap; + bool isConstructorCall = false; + bool isSystemCall = true; + + for (uint32 dataLength = 0; dataLength < 10; dataLength++) { + uint256 result = SystemContractsCaller.getFarCallABI( + dataOffset, + memoryPage, + dataStart, + dataLength, + gasPassed, + shardId, + forwardingMode, + isConstructorCall, + isSystemCall + ); + + assertEq((result >> 96) & 0xFFFFFFFF, dataLength); + } + } + + function test_GetFarCallABI_DifferentGasPassed() public { + uint32 dataOffset = 0; + uint32 memoryPage = 0; + uint32 dataStart = 0x20; + uint32 dataLength = 100; + uint8 shardId = 1; + CalldataForwardingMode forwardingMode = CalldataForwardingMode.UseHeap; + bool isConstructorCall = false; + bool isSystemCall = true; + + for (uint32 gasPassed = 0; gasPassed < 10; gasPassed++) { + uint256 result = SystemContractsCaller.getFarCallABI( + dataOffset, + memoryPage, + dataStart, + dataLength, + gasPassed, + shardId, + forwardingMode, + isConstructorCall, + isSystemCall + ); + + assertEq((result >> 192) & 0xFFFFFFFF, gasPassed); + } + } + + function test_GetFarCallABI_AllForwardingModes() public { + uint32 dataOffset = 0; + uint32 memoryPage = 0; + uint32 dataStart = 0x20; + uint32 dataLength = 100; + uint32 gasPassed = 50000; + uint8 shardId = 1; + bool isConstructorCall = false; + bool isSystemCall = true; + + // Test UseHeap + uint256 result1 = SystemContractsCaller.getFarCallABI( + dataOffset, + memoryPage, + dataStart, + dataLength, + gasPassed, + shardId, + CalldataForwardingMode.UseHeap, + isConstructorCall, + isSystemCall + ); + assertEq((result1 >> 224) & 0xFF, uint256(CalldataForwardingMode.UseHeap)); + + // Test ForwardFatPointer + uint256 result2 = SystemContractsCaller.getFarCallABI( + dataOffset, + memoryPage, + dataStart, + dataLength, + gasPassed, + shardId, + CalldataForwardingMode.ForwardFatPointer, + isConstructorCall, + isSystemCall + ); + assertEq((result2 >> 224) & 0xFF, uint256(CalldataForwardingMode.ForwardFatPointer)); + + // Test UseAuxHeap + uint256 result3 = SystemContractsCaller.getFarCallABI( + dataOffset, + memoryPage, + dataStart, + dataLength, + gasPassed, + shardId, + CalldataForwardingMode.UseAuxHeap, + isConstructorCall, + isSystemCall + ); + assertEq((result3 >> 224) & 0xFF, uint256(CalldataForwardingMode.UseAuxHeap)); + } + + function test_GetFarCallABI_AllCombinations() public { + uint32 dataOffset = 0; + uint32 memoryPage = 0; + uint32 dataStart = 0x20; + uint32 dataLength = 100; + uint32 gasPassed = 50000; + uint8 shardId = 1; + + // Test all combinations of boolean flags + for (uint i = 0; i < 4; i++) { + bool isConstructorCall = (i & 1) == 1; + bool isSystemCall = (i & 2) == 2; + + uint256 result = SystemContractsCaller.getFarCallABI( + dataOffset, + memoryPage, + dataStart, + dataLength, + gasPassed, + shardId, + CalldataForwardingMode.UseHeap, + isConstructorCall, + isSystemCall + ); + + assertEq((result >> 240) & 0x1, isConstructorCall ? 1 : 0); + assertEq((result >> 248) & 0x1, isSystemCall ? 1 : 0); + } + } + + function test_GetFarCallABI_EdgeCases() public { + uint32 dataOffset = 1; + uint32 memoryPage = 1; + uint32 dataStart = 0x21; + uint32 dataLength = 1; + uint32 gasPassed = 1; + uint8 shardId = 1; + CalldataForwardingMode forwardingMode = CalldataForwardingMode.UseHeap; + bool isConstructorCall = true; + bool isSystemCall = true; + + uint256 result = SystemContractsCaller.getFarCallABI( + dataOffset, + memoryPage, + dataStart, + dataLength, + gasPassed, + shardId, + forwardingMode, + isConstructorCall, + isSystemCall + ); + + // Check that all fields are set correctly + assertEq(result & 0xFFFFFFFF, dataOffset); + assertEq((result >> 32) & 0xFFFFFFFF, memoryPage); + assertEq((result >> 64) & 0xFFFFFFFF, dataStart); + assertEq((result >> 96) & 0xFFFFFFFF, dataLength); + assertEq((result >> 192) & 0xFFFFFFFF, gasPassed); + assertEq((result >> 224) & 0xFF, uint256(forwardingMode)); + assertEq((result >> 232) & 0xFF, shardId); + assertEq((result >> 240) & 0x1, 1); + assertEq((result >> 248) & 0x1, 1); + } + + function test_GetFarCallABI_BitManipulation() public { + uint32 dataOffset = 0x12345678; + uint32 memoryPage = 0x87654321; + uint32 dataStart = 0x11111111; + uint32 dataLength = 0x22222222; + uint32 gasPassed = 0x33333333; + uint8 shardId = 0x44; + CalldataForwardingMode forwardingMode = CalldataForwardingMode.UseAuxHeap; + bool isConstructorCall = true; + bool isSystemCall = true; + + uint256 result = SystemContractsCaller.getFarCallABI( + dataOffset, + memoryPage, + dataStart, + dataLength, + gasPassed, + shardId, + forwardingMode, + isConstructorCall, + isSystemCall + ); + + // Check that all fields are set correctly with bit manipulation + assertEq(result & 0xFFFFFFFF, dataOffset); + assertEq((result >> 32) & 0xFFFFFFFF, memoryPage); + assertEq((result >> 64) & 0xFFFFFFFF, dataStart); + assertEq((result >> 96) & 0xFFFFFFFF, dataLength); + assertEq((result >> 192) & 0xFFFFFFFF, gasPassed); + assertEq((result >> 224) & 0xFF, uint256(forwardingMode)); + assertEq((result >> 232) & 0xFF, shardId); + assertEq((result >> 240) & 0x1, 1); + assertEq((result >> 248) & 0x1, 1); + } +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Utils/Utils.sol b/l1-contracts/test/foundry/l1/unit/concrete/Utils/Utils.sol index e055ba0368..1e8bf65edb 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Utils/Utils.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Utils/Utils.sol @@ -12,12 +12,13 @@ import {AdminFacet} from "contracts/state-transition/chain-deps/facets/Admin.sol import {ExecutorFacet} from "contracts/state-transition/chain-deps/facets/Executor.sol"; import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; import {MailboxFacet} from "contracts/state-transition/chain-deps/facets/Mailbox.sol"; + import {FeeParams, IVerifier, PubdataPricingMode, VerifierParams} from "contracts/state-transition/chain-deps/ZKChainStorage.sol"; import {BatchDecoder} from "contracts/state-transition/libraries/BatchDecoder.sol"; import {InitializeData, InitializeDataNewChain} from "contracts/state-transition/chain-interfaces/IDiamondInit.sol"; import {IExecutor, SystemLogKey} from "contracts/state-transition/chain-interfaces/IExecutor.sol"; -import {InteropRoot, L2CanonicalTransaction} from "contracts/common/Messaging.sol"; -import {DummyBridgehub} from "contracts/dev-contracts/test/DummyBridgehub.sol"; +import {InteropRoot, L2CanonicalTransaction, L2Log} from "contracts/common/Messaging.sol"; + import {PriorityOpsBatchInfo} from "contracts/state-transition/libraries/PriorityTree.sol"; import {InvalidBlobCommitmentsLength, InvalidBlobHashesLength} from "test/foundry/L1TestsErrors.sol"; import {Utils as DeployUtils} from "deploy-scripts/Utils.sol"; @@ -35,6 +36,8 @@ L2DACommitmentScheme constant L2_DA_COMMITMENT_SCHEME = L2DACommitmentScheme.PUB uint256 constant MAX_NUMBER_OF_BLOBS = 6; uint256 constant TOTAL_BLOBS_IN_COMMITMENT = 16; +uint256 constant EVENT_INDEX = 0; + library Utils { function packBatchTimestampAndBlockTimestamp( uint256 batchTimestamp, @@ -64,7 +67,7 @@ library Utils { } function createSystemLogs(bytes32 _outputHash) public returns (bytes[] memory) { - bytes[] memory logs = new bytes[](9); + bytes[] memory logs = new bytes[](10); logs[0] = constructL2Log( true, L2_TO_L1_MESSENGER, @@ -119,6 +122,12 @@ library Utils { uint256(SystemLogKey.L2_TXS_STATUS_ROLLING_HASH_KEY), bytes32("") ); + logs[9] = constructL2Log( + true, + L2_BOOTLOADER_ADDRESS, + uint256(SystemLogKey.SETTLEMENT_LAYER_CHAIN_ID_KEY), + bytes32(uint256(uint160(block.chainid))) + ); return logs; } @@ -263,18 +272,41 @@ library Utils { PriorityOpsBatchInfo[] memory _priorityOpsData ) internal pure returns (uint256, uint256, bytes memory) { InteropRoot[][] memory dependencyRoots = new InteropRoot[][](_batchesData.length); + L2Log[] memory l2Logs = new L2Log[](_batchesData.length); + bytes[] memory messages = new bytes[](_batchesData.length); + bytes32[] memory messageRoots = new bytes32[](_batchesData.length); + + return ( + _batchesData[0].batchNumber, + _batchesData[_batchesData.length - 1].batchNumber, + bytes.concat( + bytes1(BatchDecoder.SUPPORTED_ENCODING_VERSION), + abi.encode(_batchesData, _priorityOpsData, dependencyRoots, l2Logs, messages, messageRoots) + ) + ); + } + + function encodeExecuteBatchesDataZeroLogs( + IExecutor.StoredBatchInfo[] memory _batchesData, + PriorityOpsBatchInfo[] memory _priorityOpsData + ) internal pure returns (uint256, uint256, bytes memory) { + InteropRoot[][] memory dependencyRoots = new InteropRoot[][](_batchesData.length); + L2Log[] memory l2Logs = new L2Log[](0); + bytes[] memory messages = new bytes[](0); + bytes32[] memory messageRoots = new bytes32[](0); + return ( _batchesData[0].batchNumber, _batchesData[_batchesData.length - 1].batchNumber, bytes.concat( bytes1(BatchDecoder.SUPPORTED_ENCODING_VERSION), - abi.encode(_batchesData, _priorityOpsData, dependencyRoots) + abi.encode(_batchesData, _priorityOpsData, dependencyRoots, l2Logs, messages, messageRoots) ) ); } function getAdminSelectors() public pure returns (bytes4[] memory) { - bytes4[] memory selectors = new bytes4[](13); + bytes4[] memory selectors = new bytes4[](14); uint256 i = 0; selectors[i++] = AdminFacet.setPendingAdmin.selector; selectors[i++] = AdminFacet.acceptAdmin.selector; @@ -289,6 +321,7 @@ library Utils { selectors[i++] = AdminFacet.unfreezeDiamond.selector; selectors[i++] = AdminFacet.genesisUpgrade.selector; selectors[i++] = AdminFacet.setDAValidatorPair.selector; + selectors[i++] = AdminFacet.pauseDepositsBeforeInitiatingMigration.selector; return selectors; } @@ -344,7 +377,7 @@ library Utils { } function getMailboxSelectors() public pure returns (bytes4[] memory) { - bytes4[] memory selectors = new bytes4[](8); + bytes4[] memory selectors = new bytes4[](9); uint256 i = 0; selectors[i++] = MailboxFacet.proveL2MessageInclusion.selector; selectors[i++] = MailboxFacet.proveL2LogInclusion.selector; @@ -354,6 +387,7 @@ library Utils { selectors[i++] = MailboxFacet.bridgehubRequestL2Transaction.selector; selectors[i++] = MailboxFacet.l2TransactionBaseCost.selector; selectors[i++] = MailboxFacet.proveL2LeafInclusion.selector; + selectors[i++] = MailboxFacet.requestL2ServiceTransaction.selector; return selectors; } @@ -431,14 +465,13 @@ library Utils { }); } - function makeInitializeData(address testnetVerifier) public returns (InitializeData memory) { - DummyBridgehub dummyBridgehub = new DummyBridgehub(); - + function makeInitializeData(address testnetVerifier, address bridgehub) public returns (InitializeData memory) { return InitializeData({ chainId: 1, - bridgehub: address(dummyBridgehub), + bridgehub: bridgehub, chainTypeManager: address(0x1234567890876543567890), + interopCenter: address(0x1234567890876543567890), protocolVersion: 0, admin: address(0x32149872498357874258787), validatorTimelock: address(0x85430237648403822345345), @@ -469,11 +502,15 @@ library Utils { }); } - function makeDiamondProxy(Diamond.FacetCut[] memory facetCuts, address testnetVerifier) public returns (address) { + function makeDiamondProxy( + Diamond.FacetCut[] memory facetCuts, + address testnetVerifier, + address bridgehub + ) public returns (address) { DiamondInit diamondInit = new DiamondInit(false); bytes memory diamondInitData = abi.encodeWithSelector( diamondInit.initialize.selector, - makeInitializeData(testnetVerifier) + makeInitializeData(testnetVerifier, bridgehub) ); Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Utils/Utils.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Utils/Utils.t.sol index 6051c09cad..c2669859e5 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/Utils/Utils.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/Utils/Utils.t.sol @@ -5,10 +5,12 @@ pragma solidity 0.8.28; import {Test} from "forge-std/Test.sol"; import {L2_BOOTLOADER_ADDRESS, L2_SYSTEM_CONTEXT_ADDRESS, L2_TO_L1_MESSENGER, SystemLogKey, Utils, L2_DA_COMMITMENT_SCHEME} from "./Utils.sol"; +import {UtilsCallMockerTest} from "foundry-test/l1/unit/concrete/Utils/UtilsCallMocker.t.sol"; + // solhint-enable max-line-length -contract UtilsTest is Test { - function test_PackBatchTimestampAndBlockTimestamp() public { +contract UtilsTest is UtilsCallMockerTest { + function test_PackBatchTimestampAndBlockTimestamp() public virtual { uint64 batchTimestamp = 0x12345678; uint64 blockTimestamp = 0x87654321; bytes32 packedBytes = Utils.packBatchTimestampAndBlockTimestamp(batchTimestamp, blockTimestamp); @@ -20,7 +22,7 @@ contract UtilsTest is Test { ); } - function test_ConstructL2Log() public { + function test_ConstructL2Log() public virtual { bytes memory l2Log = Utils.constructL2Log( true, L2_TO_L1_MESSENGER, @@ -41,10 +43,10 @@ contract UtilsTest is Test { ); } - function test_CreateSystemLogs() public { + function test_CreateSystemLogs() public virtual { bytes[] memory logs = Utils.createSystemLogs(bytes32(0)); - assertEq(logs.length, 9, "logs length should be correct"); + assertEq(logs.length, 10, "logs length should be correct"); assertEq( logs[0], @@ -147,5 +149,5 @@ contract UtilsTest is Test { } // add this to be excluded from coverage report - function test() internal virtual {} + function test() internal virtual override {} } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/Utils/UtilsCallMocker.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/Utils/UtilsCallMocker.t.sol new file mode 100644 index 0000000000..fdae5ddce5 --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/Utils/UtilsCallMocker.t.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {Test} from "forge-std/Test.sol"; +import {Utils} from "./Utils.sol"; +import {console} from "forge-std/console.sol"; +import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; +import {L1AssetRouter} from "contracts/bridge/asset-router/L1AssetRouter.sol"; +import {IL1Bridgehub} from "contracts/bridgehub/IL1Bridgehub.sol"; +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; +import {INativeTokenVaultBase} from "contracts/bridge/ntv/INativeTokenVaultBase.sol"; +import {IL1NativeTokenVault} from "contracts/bridge/ntv/IL1NativeTokenVault.sol"; +import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; +import {L2_ASSET_ROUTER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR, L2_ASSET_TRACKER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; + +// solhint-enable max-line-length + +contract UtilsCallMockerTest is Test { + function mockDiamondInitInteropCenterCallsWithAddress( + address bridgehub, + address assetRouter, + bytes32 baseTokenAssetId + ) public { + address assetTracker = makeAddr("assetTracker"); + address nativeTokenVault = makeAddr("nativeTokenVault"); + if (assetRouter == address(0)) { + assetRouter = makeAddr("assetRouter"); + } else if (assetRouter == L2_ASSET_ROUTER_ADDR) { + nativeTokenVault = L2_NATIVE_TOKEN_VAULT_ADDR; + assetTracker = L2_ASSET_TRACKER_ADDR; + } + + vm.mockCall(bridgehub, abi.encodeWithSelector(IBridgehubBase.assetRouter.selector), abi.encode(assetRouter)); + vm.mockCall( + assetRouter, + abi.encodeWithSelector(IL1AssetRouter.nativeTokenVault.selector), + abi.encode(nativeTokenVault) + ); + vm.mockCall( + nativeTokenVault, + abi.encodeWithSelector(IL1NativeTokenVault.l1AssetTracker.selector), + abi.encode(assetTracker) + ); + vm.mockCall( + nativeTokenVault, + abi.encodeWithSelector(INativeTokenVaultBase.originChainId.selector, baseTokenAssetId), + abi.encode(block.chainid) + ); + vm.mockCall( + nativeTokenVault, + abi.encodeWithSelector(INativeTokenVaultBase.originToken.selector, baseTokenAssetId), + abi.encode(ETH_TOKEN_ADDRESS) + ); + } + + function test() internal virtual {} +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/FullMerkleMemoryEdgeCases.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/FullMerkleMemoryEdgeCases.t.sol new file mode 100644 index 0000000000..053a78f10f --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/FullMerkleMemoryEdgeCases.t.sol @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {FullMerkleTest} from "./_FullMerkle_Shared.t.sol"; +import {FullMerkleMemory} from "contracts/common/libraries/FullMerkleMemory.sol"; +import {FullMerkleTest as FullMerkleTestContract} from "contracts/dev-contracts/test/FullMerkleTest.sol"; + +contract FullMerkleMemoryEdgeCasesTest is FullMerkleTest { + using FullMerkleMemory for FullMerkleMemory.FullTree; + + /// @dev Test createTree() with zero max leaf number (should revert) + function test_createTreeZeroMaxLeaf() public { + FullMerkleMemory.FullTree memory memoryTree; + + vm.expectRevert(abi.encodeWithSelector(FullMerkleMemory.InvalidMaxLeafNumber.selector, 0)); + memoryTree.createTree(0); + } + + /// @dev Test tree expansion when reaching power of 2 boundary (pushNewLeaf edge case) + function test_pushNewLeafTreeExpansion() public { + // Create tree with capacity for exactly 4 leaves (height 2) + FullMerkleMemory.FullTree memory memoryTree = _setupMemoryTree(8); + + // Fill to capacity that triggers expansion + memoryTree.pushNewLeaf(bytes32(uint256(1))); + memoryTree.pushNewLeaf(bytes32(uint256(2))); + memoryTree.pushNewLeaf(bytes32(uint256(3))); + memoryTree.pushNewLeaf(bytes32(uint256(4))); + + assertEq(memoryTree._leafNumber, 4); + uint256 heightBefore = memoryTree._height; + + // Push 5th element - this should potentially trigger expansion logic + memoryTree.pushNewLeaf(bytes32(uint256(5))); + + // Verify tree still works correctly + assertEq(memoryTree._leafNumber, 5); + assertTrue(memoryTree._height >= heightBefore); + + // Verify we can get a valid root + bytes32 root = memoryTree.root(); + assertTrue(root != bytes32(0), "Root should be non-zero after expansion"); + } + + /// @dev Test node array initialization on first access (line 114) + function test_nodeArrayInitialization() public { + FullMerkleMemory.FullTree memory memoryTree = _setupMemoryTree(8); + + // Push elements to trigger node creation at different levels + memoryTree.pushNewLeaf(bytes32(uint256(1))); + memoryTree.pushNewLeaf(bytes32(uint256(2))); // This should create level 1 nodes + + // Verify node arrays are properly initialized + assertTrue(memoryTree._nodes[1].length > 0, "Level 1 nodes should be initialized"); + + // Push more to trigger higher level initialization + memoryTree.pushNewLeaf(bytes32(uint256(3))); + memoryTree.pushNewLeaf(bytes32(uint256(4))); // This should create level 2 nodes + + assertTrue(memoryTree._nodes[2].length > 0, "Level 2 nodes should be initialized"); + } + + /// @dev Test updateLeaf() with various edge cases + function test_updateLeafEdgeCases() public { + FullMerkleMemory.FullTree memory memoryTree = _setupMemoryTree(16); + + // Add several leaves + for (uint256 i = 1; i <= 10; i++) { + memoryTree.pushNewLeaf(bytes32(i)); + } + + bytes32 rootBefore = memoryTree.root(); + + // Update first leaf (index 0) + bytes32 newValue = keccak256("updated_first"); + memoryTree.updateLeaf(0, newValue); + + bytes32 rootAfter = memoryTree.root(); + assertTrue(rootBefore != rootAfter, "Root should change after update"); + + // Update last leaf + bytes32 newLastValue = keccak256("updated_last"); + memoryTree.updateLeaf(9, newLastValue); + + // Verify root changed again + bytes32 finalRoot = memoryTree.root(); + assertTrue(rootAfter != finalRoot, "Root should change after last leaf update"); + } + + /// @dev Test updateAllLeaves() functionality + function test_updateAllLeaves() public { + FullMerkleMemory.FullTree memory memoryTree = _setupMemoryTree(8); + + // Add initial leaves + memoryTree.pushNewLeaf(bytes32(uint256(1))); + memoryTree.pushNewLeaf(bytes32(uint256(2))); + memoryTree.pushNewLeaf(bytes32(uint256(3))); + memoryTree.pushNewLeaf(bytes32(uint256(4))); + + bytes32 rootBefore = memoryTree.root(); + + // Create new leaf values + bytes32[] memory newLeaves = new bytes32[](4); + newLeaves[0] = keccak256("new1"); + newLeaves[1] = keccak256("new2"); + newLeaves[2] = keccak256("new3"); + newLeaves[3] = keccak256("new4"); + + // Update all leaves + memoryTree.updateAllLeaves(newLeaves); + + bytes32 rootAfter = memoryTree.root(); + assertTrue(rootBefore != rootAfter, "Root should change after updating all leaves"); + + // Verify leaf count remains the same + assertEq(memoryTree._leafNumber, 4); + } + + /// @dev Test updateAllNodesAtHeight() edge cases + function test_updateAllNodesAtHeight() public { + FullMerkleMemory.FullTree memory memoryTree = _setupMemoryTree(16); + + // Build tree with several leaves + for (uint256 i = 1; i <= 8; i++) { + memoryTree.pushNewLeaf(bytes32(i)); + } + + bytes32 rootBefore = memoryTree.root(); + + // Update nodes at height 1 (leaf level + 1) + bytes32[] memory newNodes = new bytes32[](4); // 8 leaves -> 4 nodes at height 1 + for (uint256 i = 0; i < 4; i++) { + newNodes[i] = keccak256(abi.encodePacked("height1_node", i)); + } + + memoryTree.updateAllNodesAtHeight(1, newNodes); + + bytes32 rootAfter = memoryTree.root(); + assertTrue(rootBefore != rootAfter, "Root should change after updating nodes"); + } + + /// @dev Test tree behavior with single element + function test_singleElementTree() public { + FullMerkleMemory.FullTree memory memoryTree = _setupMemoryTree(1); + + bytes32 leafValue = keccak256("single"); + memoryTree.pushNewLeaf(leafValue); + + // For single element tree, root should equal the leaf value + assertEq(memoryTree.root(), leafValue); + assertEq(memoryTree._leafNumber, 1); + assertEq(memoryTree._height, 0); + } + + /// @dev Test zero value handling in calculations + function test_zeroValueHandling() public { + FullMerkleMemory.FullTree memory memoryTree = _setupMemoryTree(8); + + // Push some zero values + memoryTree.pushNewLeaf(bytes32(0)); + memoryTree.pushNewLeaf(zeroHash); + memoryTree.pushNewLeaf(bytes32(uint256(1))); + + // Should handle zeros properly without errors + bytes32 root1 = memoryTree.root(); + assertTrue(root1 != bytes32(0), "Root should be non-zero even with zero leaves"); + + // Update with zero value + memoryTree.updateLeaf(2, bytes32(0)); + bytes32 root2 = memoryTree.root(); + assertTrue(root1 != root2, "Root should change when updating to zero"); + } + + /// @dev Test memory tree vs storage tree equivalence for edge cases + function test_memoryStorageEquivalenceEdgeCases() public { + // Test with power-of-2 boundaries + uint256[] memory testSizes = new uint256[](5); + testSizes[0] = 1; + testSizes[1] = 2; + testSizes[2] = 4; + testSizes[3] = 8; + testSizes[4] = 15; // Non-power-of-2 + + for (uint256 s = 0; s < testSizes.length; s++) { + // Reset storage tree + merkleTest = new FullMerkleTestContract(zeroHash); + FullMerkleMemory.FullTree memory memoryTree = _setupMemoryTree(testSizes[s]); + + // Add same elements to both + for (uint256 i = 0; i < testSizes[s]; i++) { + bytes32 value = keccak256(abi.encodePacked("edge_test", s, i)); + merkleTest.pushNewLeaf(value); + memoryTree.pushNewLeaf(value); + } + + // Verify equivalence + assertEq(merkleTest.root(), memoryTree.root(), "Storage and memory roots should match"); + assertEq(merkleTest.index(), memoryTree._leafNumber, "Leaf counts should match"); + } + } + + /// @dev Test large tree operations for gas and correctness + function test_largeTreeOperations() public { + uint256 treeSize = 63; // Large non-power-of-2 number + FullMerkleMemory.FullTree memory memoryTree = _setupMemoryTree(treeSize); + + // Fill tree + for (uint256 i = 0; i < treeSize; i++) { + memoryTree.pushNewLeaf(keccak256(abi.encodePacked("large_tree", i))); + } + + bytes32 initialRoot = memoryTree.root(); + + // Perform updates at various positions + memoryTree.updateLeaf(0, keccak256("updated_0")); + memoryTree.updateLeaf(31, keccak256("updated_31")); + memoryTree.updateLeaf(62, keccak256("updated_62")); + + bytes32 finalRoot = memoryTree.root(); + assertTrue(initialRoot != finalRoot, "Root should change after updates"); + + // Verify tree integrity + assertEq(memoryTree._leafNumber, treeSize); + } +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/PushNewLeaf.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/PushNewLeaf.t.sol index dc08fde8a4..1e99c2ef3d 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/PushNewLeaf.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/PushNewLeaf.t.sol @@ -2,12 +2,19 @@ pragma solidity ^0.8.24; import {FullMerkleTest} from "./_FullMerkle_Shared.t.sol"; +import {FullMerkleMemory} from "contracts/common/libraries/FullMerkleMemory.sol"; +import {console2 as console} from "forge-std/console2.sol"; contract PushNewLeafTest is FullMerkleTest { + using FullMerkleMemory for FullMerkleMemory.FullTree; + function test_oneLeaf() public { + FullMerkleMemory.FullTree memory merkleTestMemory = _setupMemoryTree(1); + // Inserting one leaf bytes32 leaf0 = keccak256("Leaf 0"); merkleTest.pushNewLeaf(leaf0); + merkleTestMemory.pushNewLeaf(leaf0); // Checking the tree structure assertEq(merkleTest.height(), 0, "Height should be 0 after one insert"); @@ -18,15 +25,32 @@ contract PushNewLeafTest is FullMerkleTest { // Chekcking zeros tree structure assertEq(merkleTest.zeros(0), zeroHash, "Zero 0 should be correctly inserted"); + + // Checking the tree structure + assertEq(merkleTestMemory._height, 0, "Height should be 0 after one insert"); + assertEq(merkleTestMemory._leafNumber, 1, "Leaf number should be 1 after one insert"); + + // Checking leaf node + assertEq(merkleTestMemory._nodes[0][0], leaf0, "Node 0,0 should be correctly inserted"); + + // Chekcking zeros tree structure + assertEq(merkleTestMemory._zeros[0], zeroHash, "Zero 0 should be correctly inserted"); } function test_twoLeaves() public { + FullMerkleMemory.FullTree memory merkleTestMemory = _setupMemoryTree(2); + console.log("merkleTestMemory._nodes[0].length", merkleTestMemory._nodes[0].length); + // Inserting two leaves bytes32 leaf0 = keccak256("Leaf 0"); bytes32 leaf1 = keccak256("Leaf 1"); merkleTest.pushNewLeaf(leaf0); merkleTest.pushNewLeaf(leaf1); + merkleTestMemory.pushNewLeaf(leaf0); + console.log("merkleTestMemory._nodes[0].length", merkleTestMemory._nodes[0].length); + merkleTestMemory.pushNewLeaf(leaf1); + // Checking the tree structure assertEq(merkleTest.height(), 1, "Height should be 1 after two inserts"); assertEq(merkleTest.index(), 2, "Leaf number should be 2 after two inserts"); @@ -42,9 +66,25 @@ contract PushNewLeafTest is FullMerkleTest { // Checking zeros bytes32 zeroHashed = keccak(zeroHash, zeroHash); assertEq(merkleTest.zeros(1), zeroHashed, "Zero 1 should be correctly inserted"); + + // Checking the tree structure + assertEq(merkleTestMemory._height, 1, "Height should be 1 after two inserts"); + assertEq(merkleTestMemory._leafNumber, 2, "Leaf number should be 2 after two inserts"); + + // Checking leaf nodes + assertEq(merkleTestMemory._nodes[0][0], leaf0, "Node 0,0 should be correctly inserted"); + assertEq(merkleTestMemory._nodes[0][1], leaf1, "Node 0,1 should be correctly inserted"); + + // Checking parent node + assertEq(merkleTestMemory._nodes[1][0], l01Hashed, "Node 1,0 should be correctly inserted"); + + // Checking zeros + assertEq(merkleTestMemory._zeros[1], zeroHashed, "Zero 1 should be correctly inserted"); } function test_threeLeaves() public { + FullMerkleMemory.FullTree memory merkleTestMemory = _setupMemoryTree(3); + // Insert three leaves bytes32 leaf0 = keccak256("Leaf 0"); bytes32 leaf1 = keccak256("Leaf 1"); @@ -53,6 +93,10 @@ contract PushNewLeafTest is FullMerkleTest { merkleTest.pushNewLeaf(leaf1); merkleTest.pushNewLeaf(leaf2); + merkleTestMemory.pushNewLeaf(leaf0); + merkleTestMemory.pushNewLeaf(leaf1); + merkleTestMemory.pushNewLeaf(leaf2); + // Checking the tree structure assertEq(merkleTest.height(), 2, "Height should be 2 after three inserts"); assertEq(merkleTest.index(), 3, "Leaf number should be 3 after three inserts"); @@ -78,5 +122,26 @@ contract PushNewLeafTest is FullMerkleTest { assertEq(merkleTest.zeros(1), zeroHashed, "Zero 1 should be correctly inserted"); bytes32 zhHashed = keccak(zeroHashed, zeroHashed); assertEq(merkleTest.zeros(2), zhHashed, "Zero 2 should be correctly inserted"); + + // // Checking the tree structure + // assertEq(merkleTestMemory._height, 2, "Height should be 2 after three inserts"); + // assertEq(merkleTestMemory._leafNumber, 3, "Leaf number should be 3 after three inserts"); + + // // Checking leaf nodes + // assertEq(merkleTestMemory._nodes[0][0], leaf0, "Node 0,0 should be correctly inserted"); + // assertEq(merkleTestMemory._nodes[0][1], leaf1, "Node 0,1 should be correctly inserted"); + // assertEq(merkleTestMemory._nodes[0][2], leaf2, "Node 0,2 should be correctly inserted"); + + // // Checking parent nodes + // assertEq(merkleTestMemory._nodes[1][0], l01Hashed, "Node 1,0 should be correctly inserted"); + // // there is no leaf3 so we hash leaf2 with zero + // assertEq(merkleTestMemory._nodes[1][1], l23Hashed, "Node 1,1 should be correctly inserted"); + + // // Checking root node + // assertEq(merkleTestMemory._nodes[2][0], l01l23Hashed, "Node 2,0 should be correctly inserted"); + + // // Checking zero + // assertEq(merkleTestMemory._zeros[1], zeroHashed, "Zero 1 should be correctly inserted"); + // assertEq(merkleTestMemory._zeros[2], zhHashed, "Zero 2 should be correctly inserted"); } } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/Root.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/Root.t.sol index 3ae5192594..9ac4b58f2d 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/Root.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/Root.t.sol @@ -2,20 +2,30 @@ pragma solidity ^0.8.24; import {FullMerkleTest} from "./_FullMerkle_Shared.t.sol"; +import {FullMerkleMemory} from "contracts/common/libraries/FullMerkleMemory.sol"; contract RootTest is FullMerkleTest { + using FullMerkleMemory for FullMerkleMemory.FullTree; + function test_emptyTree() public view { + FullMerkleMemory.FullTree memory merkleTestMemory = _setupMemoryTree(1); + // Initially tree is empty, root is the zero hash assertEq(merkleTest.root(), zeroHash, "Root should be zero hash initially"); + assertEq(merkleTestMemory.root(), zeroHash, "Root 0,0 should be zero hash initially"); } function test_oneLeaf() public { + FullMerkleMemory.FullTree memory merkleTestMemory = _setupMemoryTree(1); + // Inserting one leaf bytes32 leaf = keccak256("Leaf 0"); merkleTest.pushNewLeaf(leaf); + merkleTestMemory.pushNewLeaf(leaf); // With one leaf, root is the leaf itself assertEq(merkleTest.root(), leaf, "Root should be the leaf hash"); + assertEq(merkleTestMemory.root(), leaf, "Root 0,0 should be the leaf hash"); } function test_twoLeaves() public { diff --git a/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/_FullMerkle_Shared.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/_FullMerkle_Shared.t.sol index 29c271eddc..e2d6fd08f2 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/_FullMerkle_Shared.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/FullMerkle/_FullMerkle_Shared.t.sol @@ -4,8 +4,12 @@ pragma solidity ^0.8.24; import {Test} from "forge-std/Test.sol"; import {FullMerkleTest as FullMerkleTestContract} from "contracts/dev-contracts/test/FullMerkleTest.sol"; +import {FullMerkleMemory} from "contracts/common/libraries/FullMerkleMemory.sol"; +import {console2 as console} from "forge-std/console2.sol"; contract FullMerkleTest is Test { + using FullMerkleMemory for FullMerkleMemory.FullTree; + // add this to be excluded from coverage report function test() internal {} @@ -20,4 +24,11 @@ contract FullMerkleTest is Test { function keccak(bytes32 left, bytes32 right) internal pure returns (bytes32) { return keccak256(abi.encodePacked(left, right)); } + + function _setupMemoryTree(uint256 _maxLeafNumber) internal view returns (FullMerkleMemory.FullTree memory) { + FullMerkleMemory.FullTree memory memoryTree; + memoryTree.createTree(_maxLeafNumber); + memoryTree.setup(zeroHash); + return memoryTree; + } } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/IncrementalMerkle/IncrementalMerkle.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/IncrementalMerkle/IncrementalMerkle.t.sol index 04bbb7d1bc..9efd43255e 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/IncrementalMerkle/IncrementalMerkle.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/common/libraries/IncrementalMerkle/IncrementalMerkle.t.sol @@ -3,73 +3,547 @@ pragma solidity 0.8.28; import {Test} from "forge-std/Test.sol"; import {IncrementalMerkleTest} from "contracts/dev-contracts/test/IncrementalMerkleTest.sol"; +import {DynamicIncrementalMerkle} from "contracts/common/libraries/DynamicIncrementalMerkle.sol"; +import {DynamicIncrementalMerkleMemory} from "contracts/common/libraries/DynamicIncrementalMerkleMemory.sol"; contract IncrementalMerkleTestTest is Test { + using DynamicIncrementalMerkle for DynamicIncrementalMerkle.Bytes32PushTree; + using DynamicIncrementalMerkleMemory for DynamicIncrementalMerkleMemory.Bytes32PushTree; + IncrementalMerkleTest merkleTest; - bytes32[] elements; - bytes32 root; - bytes32 zero = "0x1234567"; + bytes32 constant zero = 0x72abee45b59e344af8a6e520241c4744aff26ed411f4c4b00f8af09adada43ba; function setUp() public { merkleTest = new IncrementalMerkleTest(zero); } - function testCheckSetup() public { + function setUpMemory() public returns (DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleTestMemory) { + merkleTestMemory = DynamicIncrementalMerkleMemory.Bytes32PushTree( + 0, + new bytes32[](14), + new bytes32[](14), + 0, + 0, + false, + bytes32(0) + ); + merkleTestMemory.setup(zero); + } + + /// @dev Test basic setup and initialization (storage vs memory) + function testSetup() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleTestMemory = setUpMemory(); + + // Storage tree assertEq(merkleTest.height(), 0); assertEq(merkleTest.index(), 0); + + // Memory tree + assertEq(merkleTestMemory.height(), 0); + assertEq(merkleTestMemory.index(), 0); + + // Both should have empty root initially + assertEq(merkleTest.root(), bytes32(0)); + assertEq(merkleTestMemory.root(), bytes32(0)); } + /// @dev Test single element insertion (storage vs memory) function testSingleElement() public { - addMoreElements(1); + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleTestMemory = setUpMemory(); + + bytes32 testValue = bytes32(uint256(0)); + + // Storage tree + merkleTest.push(testValue); - assertEq(merkleTest.root(), bytes32(abi.encodePacked(uint256(0)))); + // Memory tree + merkleTestMemory.push(testValue); + + // Verify storage tree state + assertEq(merkleTest.root(), testValue); assertEq(merkleTest.height(), 0); assertEq(merkleTest.index(), 1); + + // Verify memory tree state + assertEq(merkleTestMemory.root(), testValue); + assertEq(merkleTestMemory.height(), 0); + assertEq(merkleTestMemory.index(), 1); + + // Compare storage vs memory + assertEq(merkleTest.root(), merkleTestMemory.root()); + assertEq(merkleTest.height(), merkleTestMemory.height()); + assertEq(merkleTest.index(), merkleTestMemory.index()); } + /// @dev Test two elements (storage vs memory) - triggers first tree expansion function testTwoElements() public { - addMoreElements(2); + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleTestMemory = setUpMemory(); - assertEq(merkleTest.root(), keccak256(abi.encodePacked(uint256(0), uint256(1)))); - assertEq(merkleTest.index(), 2); + // Storage tree + merkleTest.push(bytes32(uint256(0))); + merkleTest.push(bytes32(uint256(1))); + + // Memory tree + merkleTestMemory.push(bytes32(uint256(0))); + merkleTestMemory.push(bytes32(uint256(1))); + + bytes32 expectedRoot = keccak256(abi.encodePacked(uint256(0), uint256(1))); + + // Verify both trees + assertEq(merkleTest.root(), expectedRoot); assertEq(merkleTest.height(), 1); + assertEq(merkleTest.index(), 2); + + assertEq(merkleTestMemory.root(), expectedRoot); + assertEq(merkleTestMemory.height(), 1); + assertEq(merkleTestMemory.index(), 2); + + // Compare storage vs memory + assertEq(merkleTest.root(), merkleTestMemory.root()); + assertEq(merkleTest.height(), merkleTestMemory.height()); + assertEq(merkleTest.index(), merkleTestMemory.index()); } - function testPrepare3Elements() public { - merkleTest.push(bytes32(uint256(2))); - merkleTest.push(bytes32(uint256(zero))); - assertEq(merkleTest.index(), 2); - assertEq(merkleTest.height(), 1); - assertEq(merkleTest.zeros(0), zero); + /// @dev Test lazy vs regular pushes in memory (single element) + function testLazyVsRegularSingle() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleRegular = setUpMemory(); + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleLazy = setUpMemory(); + + bytes32 testValue = keccak256("test"); - assertEq(merkleTest.root(), keccak256(abi.encodePacked(uint256(2), uint256(zero)))); + merkleRegular.push(testValue); + merkleLazy.pushLazy(testValue); + + assertEq(merkleRegular.root(), merkleLazy.root()); + assertEq(merkleRegular.index(), merkleLazy.index()); + assertEq(merkleRegular.height(), merkleLazy.height()); } - function testThreeElements() public { - addMoreElements(3); + /// @dev Test mixed lazy and regular operations + function testMixedLazyRegular() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleRegular = setUpMemory(); + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleMixed = setUpMemory(); - assertEq(merkleTest.index(), 3); - assertEq(merkleTest.height(), 2); - assertEq(merkleTest.zeros(0), zero); - assertEq(merkleTest.zeros(1), keccak256(abi.encodePacked(uint256(zero), uint256(zero)))); - assertEq(merkleTest.zeros(2), keccak256(abi.encodePacked(merkleTest.zeros(1), merkleTest.zeros(1)))); - assertEq(merkleTest.side(0), bytes32((uint256(2)))); - assertEq(merkleTest.side(1), keccak256(abi.encodePacked(uint256(0), uint256(1)))); + // Regular approach + merkleRegular.push(bytes32(uint256(0))); + merkleRegular.push(bytes32(uint256(1))); + merkleRegular.push(bytes32(uint256(2))); + merkleRegular.push(bytes32(uint256(3))); + + // Mixed approach - some lazy, some regular + merkleMixed.pushLazy(bytes32(uint256(0))); + merkleMixed.pushLazy(bytes32(uint256(1))); + merkleMixed.push(bytes32(uint256(2))); // This should process pending leaves + merkleMixed.push(bytes32(uint256(3))); + + // Both should produce the same root + assertEq(merkleRegular.root(), merkleMixed.root()); + assertEq(merkleRegular.index(), merkleMixed.index()); + assertEq(merkleRegular.height(), merkleMixed.height()); + } + + /// @dev Test sequential values comparing storage tree with memory trees + function testSequentialValues() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleTestMemory = setUpMemory(); + + uint256 numElements = 42; + + // Storage tree pushes + for (uint256 i = 0; i < numElements; i++) { + merkleTest.push(bytes32(i)); + } + + // Memory tree pushes + for (uint256 i = 0; i < numElements; i++) { + merkleTestMemory.push(bytes32(i)); + } + + // Compare storage vs memory + assertEq(merkleTest.root(), merkleTestMemory.root()); + assertEq(merkleTest.index(), merkleTestMemory.index()); + assertEq(merkleTest.height(), merkleTestMemory.height()); + } + + /// @dev Test the original failing lazy push batch processing + function testPushLazyBatchProcessing() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleTestRegular = setUpMemory(); + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleTestLazy = setUpMemory(); + + uint256 numElements = 42; + + // Regular pushes + for (uint256 i = 0; i < numElements; i++) { + merkleTestRegular.push(bytes32(i)); + } + + // Lazy pushes + for (uint256 i = 0; i < numElements; i++) { + merkleTestLazy.pushLazy(bytes32(i)); + } + + // Both should produce the same root + assertEq(merkleTestRegular.root(), merkleTestLazy.root()); + assertEq(merkleTestRegular.index(), merkleTestLazy.index()); + assertEq(merkleTestRegular.height(), merkleTestLazy.height()); + } + + /// @dev Test non-sequential arbitrary values + function testNonSequentialOddIndex() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleRegular = setUpMemory(); + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleLazy = setUpMemory(); + + bytes32[] memory values = new bytes32[](7); + values[0] = keccak256("value0"); + values[1] = keccak256("value1"); + values[2] = bytes32(uint256(0xAAAAAAA)); + values[3] = bytes32(uint256(0xBBBBBBB)); + values[4] = keccak256(abi.encodePacked(block.timestamp)); + values[5] = bytes32(type(uint256).max); + values[6] = keccak256("final_odd"); + + for (uint256 i = 0; i < values.length; i++) { + DynamicIncrementalMerkleMemory.push(merkleRegular, values[i]); + DynamicIncrementalMerkleMemory.pushLazy(merkleLazy, values[i]); + } + + bytes32 finalOdd = bytes32(uint256(0x123456789)); + DynamicIncrementalMerkleMemory.push(merkleRegular, finalOdd); + DynamicIncrementalMerkleMemory.pushLazy(merkleLazy, finalOdd); + + // This tests the _lastLeafValue reconstruction path + assertEq(DynamicIncrementalMerkleMemory.root(merkleRegular), DynamicIncrementalMerkleMemory.root(merkleLazy)); + assertEq(merkleRegular.index(), merkleLazy.index()); assertEq( - merkleTest.root(), - keccak256( - abi.encodePacked( - keccak256(abi.encodePacked(uint256(0), uint256(1))), - keccak256(abi.encodePacked(uint256(2), uint256(zero))) - ) - ) + DynamicIncrementalMerkleMemory.height(merkleRegular), + DynamicIncrementalMerkleMemory.height(merkleLazy) ); } - function addMoreElements(uint256 n) public { - for (uint256 i = 0; i < n; i++) { - elements.push(bytes32(abi.encodePacked(i))); - merkleTest.push(elements[i]); + /// @dev Test edge cases - zero values and extreme values + function testEdgeCases() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleRegular = setUpMemory(); + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleLazy = setUpMemory(); + + // Test with edge case values + bytes32[] memory edgeValues = new bytes32[](5); + edgeValues[0] = bytes32(0); + edgeValues[1] = bytes32(type(uint256).max); + edgeValues[2] = bytes32(uint256(1)); + edgeValues[3] = zero; + edgeValues[4] = keccak256("edge"); + + for (uint256 i = 0; i < edgeValues.length; i++) { + merkleRegular.push(edgeValues[i]); + merkleLazy.pushLazy(edgeValues[i]); + } + + assertEq(merkleRegular.root(), merkleLazy.root()); + assertEq(merkleRegular.index(), merkleLazy.index()); + assertEq(merkleRegular.height(), merkleLazy.height()); + } + + /// @dev Test power-of-2 boundary expansions + function testPowerOfTwoBoundaries() public { + // Test critical power-of-2 transitions + uint256[] memory boundaries = new uint256[](6); + boundaries[0] = 1; // Single element + boundaries[1] = 2; // First expansion + boundaries[2] = 4; // Second expansion + boundaries[3] = 8; // Third expansion + boundaries[4] = 16; // Fourth expansion + boundaries[5] = 32; // Fifth expansion + + for (uint256 b = 0; b < boundaries.length; b++) { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleRegular = setUpMemory(); + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleLazy = setUpMemory(); + + for (uint256 i = 0; i < boundaries[b]; i++) { + bytes32 value = keccak256(abi.encodePacked("boundary", b, "element", i)); + merkleRegular.push(value); + merkleLazy.pushLazy(value); + } + + assertEq(merkleRegular.root(), merkleLazy.root(), "Boundary test failed"); + assertEq(merkleRegular.height(), merkleLazy.height(), "Height mismatch"); + assertEq(merkleRegular.index(), merkleLazy.index(), "Index mismatch"); + } + } + + /// @dev Test intermediate root calls during lazy operations + function testIntermediateRoots() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleRegular = setUpMemory(); + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleLazy = setUpMemory(); + + // Test that calling root() at various stages works correctly + for (uint256 i = 0; i < 15; i++) { + bytes32 value = keccak256(abi.encodePacked("intermediate", i)); + merkleRegular.push(value); + merkleLazy.pushLazy(value); + + // Check root after each insertion + assertEq(merkleRegular.root(), merkleLazy.root(), "Intermediate root mismatch"); + assertEq(merkleRegular.index(), merkleLazy.index(), "Index mismatch"); + assertEq(merkleRegular.height(), merkleLazy.height(), "Height mismatch"); + } + } + + /// @dev Test storage vs memory with larger dataset + function testStorageVsMemoryLarge() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleTestMemory = setUpMemory(); + + uint256 numElements = 25; + + // Push elements to both trees + for (uint256 i = 0; i < numElements; i++) { + bytes32 value = keccak256(abi.encodePacked("element", i)); + merkleTest.push(value); + merkleTestMemory.push(value); + } + + // Compare storage vs memory + assertEq(merkleTest.root(), merkleTestMemory.root()); + assertEq(merkleTest.index(), merkleTestMemory.index()); + assertEq(merkleTest.height(), merkleTestMemory.height()); + } + + /// @dev Test large tree with various data patterns + function testLargeTreeVariedPatterns() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleRegular = setUpMemory(); + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleLazy = setUpMemory(); + + uint256 numElements = 100; + + for (uint256 i = 0; i < numElements; i++) { + bytes32 value; + // Mix different data patterns to stress test + if (i % 5 == 0) { + value = keccak256(abi.encodePacked("pattern", i)); + } else if (i % 5 == 1) { + value = bytes32(i); + } else if (i % 5 == 2) { + value = bytes32(type(uint256).max - i); + } else if (i % 5 == 3) { + value = bytes32(0); + } else { + value = keccak256(abi.encodePacked(i, block.timestamp)); + } + + merkleRegular.push(value); + merkleLazy.pushLazy(value); + } + + assertEq(merkleRegular.root(), merkleLazy.root()); + assertEq(merkleRegular.index(), merkleLazy.index()); + assertEq(merkleRegular.height(), merkleLazy.height()); + } + + /// @dev Test reset() function - should clear and reinitialize the tree + function testReset() public { + merkleTest.push(bytes32(uint256(1))); + merkleTest.push(bytes32(uint256(2))); + merkleTest.push(bytes32(uint256(3))); + + // Verify tree has data + assertTrue(merkleTest.root() != bytes32(0)); + assertEq(merkleTest.index(), 3); + assertTrue(merkleTest.height() > 0); + + // Reset with different zero value + bytes32 newZero = keccak256("NEW_ZERO"); + merkleTest.reset(newZero); + + // Verify tree is reset + assertEq(merkleTest.root(), bytes32(0)); + assertEq(merkleTest.index(), 0); + assertEq(merkleTest.height(), 0); + + // Verify it works with new zero value + merkleTest.push(bytes32(uint256(42))); + assertEq(merkleTest.root(), bytes32(uint256(42))); + } + + /// @dev Test clear() function by testing reset() behavior + function testClear() public { + merkleTest.push(bytes32(uint256(100))); + merkleTest.push(bytes32(uint256(200))); + + // Verify tree has data before reset + assertTrue(merkleTest.root() != bytes32(0)); + assertEq(merkleTest.index(), 2); + + // Reset should call clear internally + merkleTest.reset(zero); + + // Verify tree is cleared + assertEq(merkleTest.root(), bytes32(0)); + assertEq(merkleTest.index(), 0); + assertEq(merkleTest.height(), 0); + } + + /// @dev Test extendUntilEnd() edge cases + function testExtendUntilEndEdgeCases() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleMemory = setUpMemory(); + + // Test extending from empty tree (nextLeafIndex == 0) + merkleMemory._nextLeafIndex = 0; + merkleMemory._sides = new bytes32[](1); + merkleMemory._zeros = new bytes32[](1); + merkleMemory._sides[0] = zero; + merkleMemory._zeros[0] = zero; + merkleMemory._sidesLengthMemory = 1; + merkleMemory._zerosLengthMemory = 1; + + // Extend the tree to a larger depth + bytes32[] memory newSides = new bytes32[](5); + bytes32[] memory newZeros = new bytes32[](5); + for (uint i = 0; i < 1; i++) { + newSides[i] = merkleMemory._sides[i]; + newZeros[i] = merkleMemory._zeros[i]; + } + merkleMemory._sides = newSides; + merkleMemory._zeros = newZeros; + + // This should extend the tree properly + DynamicIncrementalMerkleMemory.extendUntilEnd(merkleMemory); + + // Verify extension worked + assertEq(merkleMemory._sidesLengthMemory, 5); + assertEq(merkleMemory._zerosLengthMemory, 5); + assertTrue(merkleMemory._sides[0] == zero); // Should set _sides[0] = currentZero when _nextLeafIndex == 0 + } + + /// @dev Gas comparison test - performance validation + function testGasComparison() public { + uint256 numElements = 50; + + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleRegular = setUpMemory(); + uint256 gasStartRegular = gasleft(); + + for (uint256 i = 0; i < numElements; i++) { + merkleRegular.push(keccak256(abi.encodePacked("element", i))); + } + bytes32 regularRoot = merkleRegular.root(); + uint256 gasUsedRegular = gasStartRegular - gasleft(); + + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleLazy = setUpMemory(); + uint256 gasStartLazy = gasleft(); + + for (uint256 i = 0; i < numElements; i++) { + merkleLazy.pushLazy(keccak256(abi.encodePacked("element", i))); + } + bytes32 lazyRoot = merkleLazy.root(); + uint256 gasUsedLazy = gasStartLazy - gasleft(); + + // Verify correctness + assertEq(regularRoot, lazyRoot); + + // Lazy should be significantly more efficient + assertLt(gasUsedLazy, gasUsedRegular, "Lazy should use less gas"); + + // Log for visibility + emit log_named_uint("Regular gas used", gasUsedRegular); + emit log_named_uint("Lazy gas used", gasUsedLazy); + emit log_named_uint("Gas savings", gasUsedRegular - gasUsedLazy); + + // Verify significant savings (should be >40%) + uint256 savingsPercent = ((gasUsedRegular - gasUsedLazy) * 100) / gasUsedRegular; + assertGt(savingsPercent, 40, "Should achieve significant gas savings"); + } + + /// @dev Test createTree() function initialization + function testCreateTreeInitialization() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleMemory; + + // Initialize with createTree + DynamicIncrementalMerkleMemory.createTree(merkleMemory, 10); + + // Verify proper initialization + assertEq(merkleMemory._sides.length, 10); + assertEq(merkleMemory._zeros.length, 10); + assertEq(merkleMemory._sidesLengthMemory, 0); + assertEq(merkleMemory._zerosLengthMemory, 0); + assertEq(merkleMemory._nextLeafIndex, 0); + assertFalse(merkleMemory._needsRootRecalculation); + assertEq(merkleMemory._lastLeafValue, bytes32(0)); + } + + /// @dev Test _recalculateRoot() with empty tree (leafCount == 0) + function testRecalculateRootEmptyTree() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleMemory = setUpMemory(); + + // Ensure tree is empty + merkleMemory._nextLeafIndex = 0; + + // Call root() which internally calls _recalculateRoot() + bytes32 rootResult = merkleMemory.root(); + + // Should return bytes32(0) for empty tree + assertEq(rootResult, bytes32(0)); + } + + /// @dev Test various extendUntilEnd() scenarios for memory tree + function testExtendUntilEndScenarios() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleMemory = setUpMemory(); + + // Setup initial state with some elements + merkleMemory.push(bytes32(uint256(1))); + merkleMemory.push(bytes32(uint256(2))); + + // Manually extend the arrays to test extending behavior + bytes32[] memory newSides = new bytes32[](8); + bytes32[] memory newZeros = new bytes32[](8); + + // Copy existing data + for (uint i = 0; i < merkleMemory._sidesLengthMemory && i < newSides.length; i++) { + newSides[i] = merkleMemory._sides[i]; + } + for (uint i = 0; i < merkleMemory._zerosLengthMemory && i < newZeros.length; i++) { + newZeros[i] = merkleMemory._zeros[i]; + } + + merkleMemory._sides = newSides; + merkleMemory._zeros = newZeros; + + // Test extension + DynamicIncrementalMerkleMemory.extendUntilEnd(merkleMemory); + + // Verify extension completed + assertEq(merkleMemory._sidesLengthMemory, 8); + assertEq(merkleMemory._zerosLengthMemory, 8); + assertFalse(merkleMemory._needsRootRecalculation); + + // Verify we can still get a valid root + bytes32 rootAfterExtend = merkleMemory.root(); + assertTrue(rootAfterExtend != bytes32(0)); + } + + /// @dev Test comprehensive storage vs memory equivalence + function testStorageMemoryEquivalenceComprehensive() public { + DynamicIncrementalMerkleMemory.Bytes32PushTree memory merkleMemory = setUpMemory(); + + // Test various scenarios + uint256[] memory testSizes = new uint256[](4); + testSizes[0] = 1; // Single element + testSizes[1] = 7; // Odd number + testSizes[2] = 16; // Power of 2 + testSizes[3] = 33; // After expansion + + for (uint256 t = 0; t < testSizes.length; t++) { + // Reset trees + merkleTest = new IncrementalMerkleTest(zero); + merkleMemory = setUpMemory(); + + // Push same elements to both + for (uint256 i = 0; i < testSizes[t]; i++) { + bytes32 value = keccak256(abi.encodePacked("test", t, "elem", i)); + merkleTest.push(value); + merkleMemory.push(value); + } + + // Verify equivalence + assertEq(merkleTest.root(), merkleMemory.root(), "Root mismatch in comprehensive test"); + assertEq(merkleTest.height(), merkleMemory.height(), "Height mismatch in comprehensive test"); + assertEq(merkleTest.index(), merkleMemory.index(), "Index mismatch in comprehensive test"); } } } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/ChainTypeManager/Initialize.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/ChainTypeManager/Initialize.t.sol index 973926a08f..79d594b019 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/ChainTypeManager/Initialize.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/ChainTypeManager/Initialize.t.sol @@ -28,7 +28,7 @@ contract ChainTypeManagerInitializeTest is ChainTypeManagerTest { serverNotifier: serverNotifier }); - EraChainTypeManager ctm = new EraChainTypeManager(address(bridgehub)); + EraChainTypeManager ctm = new EraChainTypeManager(address(bridgehub), interopCenterAddress); vm.expectRevert(err); TransparentUpgradeableProxy transparentUpgradeableProxy = new TransparentUpgradeableProxy( diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/ChainTypeManager/RevertBatches.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/ChainTypeManager/RevertBatches.t.sol index b9421cd96e..ea1ccacf61 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/ChainTypeManager/RevertBatches.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/ChainTypeManager/RevertBatches.t.sol @@ -5,7 +5,7 @@ import {Vm} from "forge-std/Test.sol"; import {SafeCast} from "@openzeppelin/contracts-v4/utils/math/SafeCast.sol"; -import {L2_DA_COMMITMENT_SCHEME, L2_SYSTEM_CONTEXT_ADDRESS, Utils} from "../../Utils/Utils.sol"; +import {EVENT_INDEX, L2_DA_COMMITMENT_SCHEME, L2_SYSTEM_CONTEXT_ADDRESS, Utils} from "../../Utils/Utils.sol"; import {ChainTypeManagerTest} from "./_ChainTypeManager_Shared.t.sol"; import {DEFAULT_L2_LOGS_TREE_ROOT_HASH, POINT_EVALUATION_PRECOMPILE_ADDR, TESTNET_COMMIT_TIMESTAMP_NOT_OLDER} from "contracts/common/Config.sol"; @@ -20,7 +20,7 @@ import {IL2GenesisUpgrade} from "contracts/state-transition/l2-deps/IL2GenesisUp import {IComplexUpgrader} from "contracts/state-transition/l2-deps/IComplexUpgrader.sol"; import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; -contract revertBatchesTest is ChainTypeManagerTest { +contract RevertBatchesTest is ChainTypeManagerTest { // Items for logs & commits uint256 internal currentTimestamp; IExecutor.CommitBatchInfo internal newCommitBatchInfo; @@ -100,6 +100,8 @@ contract revertBatchesTest is ChainTypeManagerTest { (, uint32 minorVersion, ) = SemVer.unpackSemVer(SafeCast.toUint96(0)); } + mockDiamondInitInteropCenterCallsWithAddress(address(bridgehub), sharedBridge, baseTokenAssetId); + newChainAddress = createNewChain(getDiamondCutData(diamondInit)); vm.mockCall( address(bridgehub), @@ -195,24 +197,24 @@ contract revertBatchesTest is ChainTypeManagerTest { Vm.Log[] memory entries = vm.getRecordedLogs(); - assertEq(entries.length, 1); - assertEq(entries[0].topics[0], keccak256("BlockCommit(uint256,bytes32,bytes32)")); - assertEq(entries[0].topics[1], bytes32(uint256(1))); // batchNumber - assertEq(entries[0].topics[2], correctNewCommitBatchInfo.newStateRoot); // batchHash + assertEq(entries.length, 1 + EVENT_INDEX); + assertEq(entries[EVENT_INDEX].topics[0], keccak256("BlockCommit(uint256,bytes32,bytes32)")); + assertEq(entries[EVENT_INDEX].topics[1], bytes32(uint256(1))); // batchNumber + assertEq(entries[EVENT_INDEX].topics[2], correctNewCommitBatchInfo.newStateRoot); // batchHash uint256 totalBatchesCommitted = gettersFacet.getTotalBatchesCommitted(); assertEq(totalBatchesCommitted, 1); newStoredBatchInfo = IExecutor.StoredBatchInfo({ batchNumber: 1, - batchHash: entries[0].topics[2], + batchHash: entries[EVENT_INDEX].topics[2], indexRepeatedStorageChanges: 0, numberOfLayer1Txs: 0, priorityOperationsHash: keccak256(""), l2LogsTreeRoot: DEFAULT_L2_LOGS_TREE_ROOT_HASH, dependencyRootsRollingHash: bytes32(0), timestamp: currentTimestamp, - commitment: entries[0].topics[3] + commitment: entries[EVENT_INDEX].topics[3] }); IExecutor.StoredBatchInfo[] memory storedBatchInfoArray = new IExecutor.StoredBatchInfo[](1); diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/ChainTypeManager/_ChainTypeManager_Shared.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/ChainTypeManager/_ChainTypeManager_Shared.t.sol index 37764ded57..cab923fac9 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/ChainTypeManager/_ChainTypeManager_Shared.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/ChainTypeManager/_ChainTypeManager_Shared.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.21; -import {Test} from "forge-std/Test.sol"; +import {StdStorage, Test, stdStorage} from "forge-std/Test.sol"; import {console2 as console} from "forge-std/Script.sol"; import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; @@ -13,10 +13,12 @@ import {Utils} from "foundry-test/l1/unit/concrete/Utils/Utils.sol"; import {L1Bridgehub} from "contracts/bridgehub/L1Bridgehub.sol"; import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; import {IL1Nullifier} from "contracts/bridge/interfaces/IL1Nullifier.sol"; +import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; import {UtilsFacet} from "foundry-test/l1/unit/concrete/Utils/UtilsFacet.sol"; import {AdminFacet} from "contracts/state-transition/chain-deps/facets/Admin.sol"; import {ExecutorFacet} from "contracts/state-transition/chain-deps/facets/Executor.sol"; import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; +import {MailboxFacet} from "contracts/state-transition/chain-deps/facets/Mailbox.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {DiamondInit} from "contracts/state-transition/chain-deps/DiamondInit.sol"; import {L1GenesisUpgrade} from "contracts/upgrades/L1GenesisUpgrade.sol"; @@ -29,21 +31,31 @@ import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; import {ZeroAddress} from "contracts/common/L1ContractErrors.sol"; import {ICTMDeploymentTracker} from "contracts/bridgehub/ICTMDeploymentTracker.sol"; import {L1MessageRoot} from "contracts/bridgehub/L1MessageRoot.sol"; +import {PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "contracts/common/Config.sol"; + import {L1AssetRouter} from "contracts/bridge/asset-router/L1AssetRouter.sol"; import {RollupDAManager} from "contracts/state-transition/data-availability/RollupDAManager.sol"; import {IERC20Metadata} from "@openzeppelin/contracts-v4/token/ERC20/extensions/IERC20Metadata.sol"; +import {IEIP7702Checker} from "contracts/state-transition/chain-interfaces/IEIP7702Checker.sol"; import {IVerifierV2} from "contracts/state-transition/chain-interfaces/IVerifierV2.sol"; import {IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; +import {UtilsTest} from "foundry-test/l1/unit/concrete/Utils/Utils.t.sol"; +import {L1ChainAssetHandler} from "contracts/bridgehub/L1ChainAssetHandler.sol"; +import {CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "contracts/common/Config.sol"; + +contract ChainTypeManagerTest is UtilsTest { + using stdStorage for StdStorage; -contract ChainTypeManagerTest is Test { EraChainTypeManager internal chainTypeManager; EraChainTypeManager internal chainContractAddress; L1GenesisUpgrade internal genesisUpgradeContract; L1Bridgehub internal bridgehub; - L1MessageRoot internal messageRoot; + L1ChainAssetHandler internal chainAssetHandler; + L1MessageRoot internal messageroot; address internal rollupL1DAValidator; address internal diamondInit; + address internal interopCenterAddress; address internal governor; address internal admin; address internal baseToken; @@ -51,6 +63,7 @@ contract ChainTypeManagerTest is Test { address internal validator; address internal l1Nullifier; address internal serverNotifier; + bytes32 internal baseTokenAssetId = DataEncoding.encodeNTVAssetId(block.chainid, baseToken); address internal newChainAdmin; uint256 l1ChainId = 5; uint256 chainId = 112; @@ -63,6 +76,10 @@ contract ChainTypeManagerTest is Test { Diamond.FacetCut[] internal facetCuts; function deploy() public { + // Timestamp needs to be late enough for `pauseDepositsBeforeInitiatingMigration` time checks + vm.warp(PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + 1); + + interopCenterAddress = makeAddr("interopCenter"); governor = makeAddr("governor"); admin = makeAddr("admin"); baseToken = makeAddr("baseToken"); @@ -71,9 +88,28 @@ contract ChainTypeManagerTest is Test { l1Nullifier = makeAddr("l1Nullifier"); serverNotifier = makeAddr("serverNotifier"); bridgehub = new L1Bridgehub(governor, MAX_NUMBER_OF_ZK_CHAINS); - L1MessageRoot messageroot = new L1MessageRoot(address(bridgehub)); + messageroot = new L1MessageRoot(address(bridgehub), 1); + chainAssetHandler = new L1ChainAssetHandler( + governor, + address(bridgehub), + address(0), + address(messageroot), + address(0), + IL1Nullifier(address(0)) + ); + stdstore + .target(address(messageroot)) + .sig(IMessageRoot.v30UpgradeChainBatchNumber.selector) + .with_key(chainId) + .checked_write(uint256(1)); vm.prank(governor); - bridgehub.setAddresses(sharedBridge, ICTMDeploymentTracker(address(0)), messageRoot, address(0)); + bridgehub.setAddresses( + sharedBridge, + ICTMDeploymentTracker(address(0)), + messageroot, + address(chainAssetHandler), + address(0) + ); vm.mockCall( address(sharedBridge), @@ -84,7 +120,7 @@ contract ChainTypeManagerTest is Test { newChainAdmin = makeAddr("chainadmin"); vm.startPrank(address(bridgehub)); - chainTypeManager = new EraChainTypeManager(address(IBridgehubBase(address(bridgehub)))); + chainTypeManager = new EraChainTypeManager(address(bridgehub), interopCenterAddress); diamondInit = address(new DiamondInit(false)); genesisUpgradeContract = new L1GenesisUpgrade(); @@ -98,7 +134,16 @@ contract ChainTypeManagerTest is Test { ); facetCuts.push( Diamond.FacetCut({ - facet: address(new AdminFacet(block.chainid, RollupDAManager(address(0)))), + facet: address( + new AdminFacet( + block.chainid, + RollupDAManager(address(0)), + CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, + CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ) + ), action: Diamond.Action.Add, isFreezable: false, selectors: Utils.getAdminSelectors() @@ -120,6 +165,23 @@ contract ChainTypeManagerTest is Test { selectors: Utils.getGettersSelectors() }) ); + facetCuts.push( + Diamond.FacetCut({ + facet: address( + new MailboxFacet( + eraChainId, + block.chainid, + address(0), + IEIP7702Checker(makeAddr("eip7702Checker")), + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ) + ), + action: Diamond.Action.Add, + isFreezable: false, + selectors: Utils.getMailboxSelectors() + }) + ); ChainCreationParams memory chainCreationParams = ChainCreationParams({ genesisUpgrade: address(genesisUpgradeContract), @@ -209,10 +271,11 @@ contract ChainTypeManagerTest is Test { vm.mockCall(address(baseToken), abi.encodeWithSelector(IERC20Metadata.name.selector), abi.encode("TestToken")); vm.mockCall(address(baseToken), abi.encodeWithSelector(IERC20Metadata.symbol.selector), abi.encode("TT")); + mockDiamondInitInteropCenterCallsWithAddress(address(bridgehub), sharedBridge, baseTokenAssetId); return chainContractAddress.createNewChain({ _chainId: chainId, - _baseTokenAssetId: DataEncoding.encodeNTVAssetId(block.chainid, baseToken), + _baseTokenAssetId: baseTokenAssetId, _admin: newChainAdmin, _initData: abi.encode(abi.encode(_diamondCut), bytes("")), _factoryDeps: new bytes[](0) diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/DiamondInit/Initialize.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/DiamondInit/Initialize.t.sol index e326008866..dea04457a8 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/DiamondInit/Initialize.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/DiamondInit/Initialize.t.sol @@ -8,14 +8,13 @@ import {UtilsFacet} from "foundry-test/l1/unit/concrete/Utils/UtilsFacet.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {DiamondInit} from "contracts/state-transition/chain-deps/DiamondInit.sol"; import {DiamondProxy} from "contracts/state-transition/chain-deps/DiamondProxy.sol"; -import {InitializeData} from "contracts/state-transition/chain-interfaces/IDiamondInit.sol"; + import {IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; import {MAX_GAS_PER_TRANSACTION} from "contracts/common/Config.sol"; import {EmptyAssetId, TooMuchGas, ZeroAddress} from "contracts/common/L1ContractErrors.sol"; contract InitializeTest is DiamondInitTest { function test_revertWhen_verifierIsZeroAddress() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); initializeData.verifier = IVerifier(address(0)); Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ @@ -29,7 +28,6 @@ contract InitializeTest is DiamondInitTest { } function test_revertWhen_governorIsZeroAddress() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); initializeData.admin = address(0); Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ @@ -43,7 +41,6 @@ contract InitializeTest is DiamondInitTest { } function test_revertWhen_validatorTimelockIsZeroAddress() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); initializeData.validatorTimelock = address(0); Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ @@ -57,7 +54,6 @@ contract InitializeTest is DiamondInitTest { } function test_revertWhen_priorityTxMaxGasLimitIsGreaterThanMaxGasPerTransaction() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); initializeData.priorityTxMaxGasLimit = MAX_GAS_PER_TRANSACTION + 1; Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ @@ -71,7 +67,6 @@ contract InitializeTest is DiamondInitTest { } function test_revertWhen_bridgehubAddressIsZero() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); initializeData.bridgehub = address(0); Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ @@ -85,7 +80,6 @@ contract InitializeTest is DiamondInitTest { } function test_revertWhen_chainTypeManagerAddressIsZero() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); initializeData.chainTypeManager = address(0); Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ @@ -99,7 +93,6 @@ contract InitializeTest is DiamondInitTest { } function test_revertWhen_baseTokenAssetIdIsZero() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); initializeData.baseTokenAssetId = bytes32(0); Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ @@ -113,8 +106,6 @@ contract InitializeTest is DiamondInitTest { } function test_valuesCorrectWhenSuccessfulInit() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); - Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ facetCuts: facetCuts, initAddress: address(new DiamondInit(false)), diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/DiamondInit/_DiamondInit_Shared.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/DiamondInit/_DiamondInit_Shared.t.sol index 972f4ce4ad..0c38f416a2 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/DiamondInit/_DiamondInit_Shared.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/DiamondInit/_DiamondInit_Shared.t.sol @@ -10,10 +10,15 @@ import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {EraTestnetVerifier} from "contracts/state-transition/verifiers/EraTestnetVerifier.sol"; import {IVerifierV2} from "contracts/state-transition/chain-interfaces/IVerifierV2.sol"; import {IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; +import {UtilsTest} from "foundry-test/l1/unit/concrete/Utils/Utils.t.sol"; +import {DummyBridgehub} from "contracts/dev-contracts/test/DummyBridgehub.sol"; +import {InitializeData} from "contracts/state-transition/chain-interfaces/IDiamondInit.sol"; -contract DiamondInitTest is Test { +contract DiamondInitTest is UtilsTest { Diamond.FacetCut[] internal facetCuts; address internal testnetVerifier = address(new EraTestnetVerifier(IVerifierV2(address(0)), IVerifier(address(0)))); + DummyBridgehub internal dummyBridgehub; + InitializeData internal initializeData; function setUp() public virtual { facetCuts.push( @@ -24,8 +29,12 @@ contract DiamondInitTest is Test { selectors: Utils.getUtilsFacetSelectors() }) ); + dummyBridgehub = new DummyBridgehub(); + initializeData = Utils.makeInitializeData(testnetVerifier, address(dummyBridgehub)); + + mockDiamondInitInteropCenterCallsWithAddress(address(dummyBridgehub), address(0), bytes32(0)); } // add this to be excluded from coverage report - function test() internal virtual {} + function test() internal virtual override {} } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/DiamondProxy/DiamondProxy.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/DiamondProxy/DiamondProxy.t.sol index 23b6eede59..4a2ab93a6d 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/DiamondProxy/DiamondProxy.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/DiamondProxy/DiamondProxy.t.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.28; import {Test} from "forge-std/Test.sol"; import {Utils} from "foundry-test/l1/unit/concrete/Utils/Utils.sol"; +import {UtilsTest} from "foundry-test/l1/unit/concrete/Utils/Utils.t.sol"; import {UtilsFacet} from "foundry-test/l1/unit/concrete/Utils/UtilsFacet.sol"; import {InitializeData} from "contracts/state-transition/chain-interfaces/IDiamondInit.sol"; @@ -15,6 +16,7 @@ import {EraTestnetVerifier} from "contracts/state-transition/verifiers/EraTestne import {InvalidSelector, ValueMismatch} from "contracts/common/L1ContractErrors.sol"; import {IVerifierV2} from "contracts/state-transition/chain-interfaces/IVerifierV2.sol"; import {IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; +import {DummyBridgehub} from "contracts/dev-contracts/test/DummyBridgehub.sol"; contract TestFacet is ZKChainBase { function func() public pure returns (bool) { @@ -25,9 +27,11 @@ contract TestFacet is ZKChainBase { function test() internal virtual {} } -contract DiamondProxyTest is Test { +contract DiamondProxyTest is UtilsTest { Diamond.FacetCut[] internal facetCuts; address internal testnetVerifier = address(new EraTestnetVerifier(IVerifierV2(address(0)), IVerifier(address(0)))); + DummyBridgehub internal dummyBridgehub; + InitializeData internal initializeData; function getTestFacetSelectors() public pure returns (bytes4[] memory selectors) { selectors = new bytes4[](1); @@ -51,11 +55,13 @@ contract DiamondProxyTest is Test { selectors: Utils.getUtilsFacetSelectors() }) ); + dummyBridgehub = new DummyBridgehub(); + initializeData = Utils.makeInitializeData(testnetVerifier, address(dummyBridgehub)); + + mockDiamondInitInteropCenterCallsWithAddress(initializeData.bridgehub, address(0), bytes32(0)); } function test_revertWhen_chainIdDiffersFromBlockChainId() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); - Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ facetCuts: facetCuts, initAddress: address(new DiamondInit(false)), @@ -67,8 +73,6 @@ contract DiamondProxyTest is Test { } function test_revertWhen_calledWithEmptyMsgData() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); - Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ facetCuts: facetCuts, initAddress: address(new DiamondInit(false)), @@ -83,8 +87,6 @@ contract DiamondProxyTest is Test { } function test_revertWhen_calledWithFullSelectorInMsgData() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); - Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ facetCuts: facetCuts, initAddress: address(new DiamondInit(false)), @@ -99,8 +101,6 @@ contract DiamondProxyTest is Test { } function test_revertWhen_proxyHasNoFacetForSelector() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); - Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ facetCuts: new Diamond.FacetCut[](0), initAddress: address(new DiamondInit(false)), @@ -115,8 +115,6 @@ contract DiamondProxyTest is Test { } function test_revertWhenFacetIsFrozen() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); - Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ facetCuts: facetCuts, initAddress: address(new DiamondInit(false)), @@ -134,8 +132,6 @@ contract DiamondProxyTest is Test { } function test_successfulExecution() public { - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); - Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ facetCuts: facetCuts, initAddress: address(new DiamondInit(false)), @@ -159,8 +155,6 @@ contract DiamondProxyTest is Test { selectors: getTestFacetSelectors() }); - InitializeData memory initializeData = Utils.makeInitializeData(testnetVerifier); - Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ facetCuts: cuts, initAddress: address(new DiamondInit(false)), diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Admin/PauseDeposits.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Admin/PauseDeposits.t.sol new file mode 100644 index 0000000000..7c4c13dadd --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Admin/PauseDeposits.t.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {AdminTest} from "./_Admin_Shared.t.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; +import {DepositsAlreadyPaused, NotL1} from "contracts/state-transition/L1StateTransitionErrors.sol"; +import {PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "contracts/common/Config.sol"; + +contract PauseDepositsTest is AdminTest { + event DepositsPaused(uint256 chainId, uint256 pausedDepositsTimestamp); + + // The `pausedDepositsTimestamp` sits at slot 62 of ZKChainStorage + bytes32 pausedDepositsTimestampSlot = bytes32(uint256(62)); + + function setUp() public override { + // Timestamp needs to be late enough for `pauseDepositsBeforeInitiatingMigration` time checks + vm.warp(PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + 1); + super.setUp(); + } + + function test_revertWhen_calledByNonAdminOrChainTypeManager() public { + address nonAdminOrChainTypeManager = makeAddr("nonAdminOrChainTypeManager"); + + vm.startPrank(nonAdminOrChainTypeManager); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonAdminOrChainTypeManager)); + adminFacet.pauseDepositsBeforeInitiatingMigration(); + } + + function test_revertWhen_notL1() public { + uint256 fakeChainId = 1337; + vm.chainId(fakeChainId); + address admin = utilsFacet.util_getAdmin(); + + vm.startPrank(admin); + vm.expectRevert(abi.encodeWithSelector(NotL1.selector, fakeChainId)); + adminFacet.pauseDepositsBeforeInitiatingMigration(); + } + + function test_successfulCall_newChain() public { + uint256 chainId = utilsFacet.util_getChainId(); + uint256 expectedTimestamp = block.timestamp - PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET; + address admin = utilsFacet.util_getAdmin(); + + vm.startPrank(admin); + vm.expectEmit(true, false, false, false); + emit DepositsPaused(chainId, expectedTimestamp); + adminFacet.pauseDepositsBeforeInitiatingMigration(); + + // Read storage to check that the recorded timestamp matches the event + uint256 pausedDepositsTimestamp = uint256(vm.load(address(adminFacet), pausedDepositsTimestampSlot)); + assertEq(pausedDepositsTimestamp, expectedTimestamp); + } + + function test_successfulCall_existingChain() public { + uint256 chainId = utilsFacet.util_getChainId(); + address admin = utilsFacet.util_getAdmin(); + + // The priorityTree sits at slot 51 of ZKChainStorage + bytes32 slot = bytes32(uint256(51)); + // Fake a deposit by extending the priority tree so `getTotalPriorityTxs` returns non-zero + vm.store(address(adminFacet), slot, bytes32(uint256(1))); + + vm.startPrank(admin); + vm.expectEmit(true, false, false, false); + emit DepositsPaused(chainId, block.timestamp); + adminFacet.pauseDepositsBeforeInitiatingMigration(); + + // Read storage to check that the recorded timestamp matches the event + uint256 pausedDepositsTimestamp = uint256(vm.load(address(adminFacet), pausedDepositsTimestampSlot)); + assertEq(pausedDepositsTimestamp, block.timestamp); + } + + function test_revertWhen_depositsAlreadyPaused() public { + address admin = utilsFacet.util_getAdmin(); + // Pause deposits, works + vm.startPrank(admin); + adminFacet.pauseDepositsBeforeInitiatingMigration(); + // Try to pause them again, reverts + vm.startPrank(admin); + vm.expectRevert(abi.encodeWithSelector(DepositsAlreadyPaused.selector)); + adminFacet.pauseDepositsBeforeInitiatingMigration(); + } +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Admin/UnpauseDeposits.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Admin/UnpauseDeposits.t.sol new file mode 100644 index 0000000000..8547fc4860 --- /dev/null +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Admin/UnpauseDeposits.t.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +import {AdminTest} from "./_Admin_Shared.t.sol"; +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; +import {IL1ChainAssetHandler} from "contracts/bridgehub/IL1ChainAssetHandler.sol"; +import {DepositsNotPaused, MigrationInProgress} from "contracts/state-transition/L1StateTransitionErrors.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; +import {PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "contracts/common/Config.sol"; + +contract UnpauseDepositsTest is AdminTest { + event DepositsUnpaused(uint256 chainId); + + // The `pausedDepositsTimestamp` sits at slot 62 of ZKChainStorage + bytes32 pausedDepositsTimestampSlot = bytes32(uint256(62)); + + function setUp() public override { + // Timestamp needs to be late enough for `pauseDepositsBeforeInitiatingMigration` time checks + vm.warp(PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + 1); + super.setUp(); + } + + function _pauseDeposits() internal { + // We first need to pause deposits before we get to unpause them + address admin = utilsFacet.util_getAdmin(); + vm.startPrank(admin); + adminFacet.pauseDepositsBeforeInitiatingMigration(); + } + + function test_revertWhen_calledByNonAdmin() public { + _pauseDeposits(); + address nonAdmin = makeAddr("nonAdmin"); + + vm.startPrank(nonAdmin); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonAdmin)); + adminFacet.unpauseDeposits(); + } + + function test_revertWhen_depositsNotPaused() public { + // Call reverts when deposits if deposits were not paused + address admin = utilsFacet.util_getAdmin(); + vm.startPrank(admin); + vm.expectRevert(abi.encodeWithSelector(DepositsNotPaused.selector)); + adminFacet.unpauseDeposits(); + + // The priorityTree sits at slot 51 of ZKChainStorage + bytes32 slot = bytes32(uint256(51)); + // Fake a deposit by extending the priority tree so `getTotalPriorityTxs` returns non-zero + vm.store(address(adminFacet), slot, bytes32(uint256(1))); + // The `pausedDepositsTimestamp` will therefore be set to the current `block.timestamp` + _pauseDeposits(); + + // Call reverts before the paused window comes into effect + vm.expectRevert(abi.encodeWithSelector(DepositsNotPaused.selector)); + adminFacet.unpauseDeposits(); + // Call also reverts after the paused window ends + vm.warp(block.timestamp + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET); + vm.expectRevert(abi.encodeWithSelector(DepositsNotPaused.selector)); + adminFacet.unpauseDeposits(); + } + + function test_revertWhen_migrationInProgress() public { + _pauseDeposits(); + uint256 chainId = utilsFacet.util_getChainId(); + address admin = utilsFacet.util_getAdmin(); + address bridgehub = utilsFacet.util_getBridgehub(); + address mockChainAssetHandler = makeAddr("mockChainAssetHandler"); + + // We need to fake a migration in progress + vm.mockCall( + bridgehub, + abi.encodeWithSelector(IBridgehubBase.chainAssetHandler.selector), + abi.encode(mockChainAssetHandler) + ); + vm.mockCall( + mockChainAssetHandler, + abi.encodeWithSelector(IL1ChainAssetHandler.isMigrationInProgress.selector, chainId), + abi.encode(true) + ); + + vm.startPrank(admin); + vm.expectRevert(abi.encodeWithSelector(MigrationInProgress.selector)); + adminFacet.unpauseDeposits(); + } + + function test_successfulCall() public { + _pauseDeposits(); + uint256 chainId = utilsFacet.util_getChainId(); + address admin = utilsFacet.util_getAdmin(); + address bridgehub = utilsFacet.util_getBridgehub(); + address mockChainAssetHandler = makeAddr("mockChainAssetHandler"); + + vm.mockCall( + bridgehub, + abi.encodeWithSelector(IBridgehubBase.chainAssetHandler.selector), + abi.encode(mockChainAssetHandler) + ); + vm.mockCall( + mockChainAssetHandler, + abi.encodeWithSelector(IL1ChainAssetHandler.isMigrationInProgress.selector, chainId), + abi.encode(false) + ); + + vm.startPrank(admin); + vm.expectEmit(true, false, false, false); + emit DepositsUnpaused(chainId); + adminFacet.unpauseDeposits(); + + // Read storage to check that the recorded timestamp is reset to 0 + uint256 pausedDepositsTimestamp = uint256(vm.load(address(adminFacet), pausedDepositsTimestampSlot)); + assertEq(pausedDepositsTimestamp, 0); + } +} diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Admin/_Admin_Shared.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Admin/_Admin_Shared.t.sol index c1e5a79456..ae0915b0fa 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Admin/_Admin_Shared.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Admin/_Admin_Shared.t.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.28; import {Test} from "forge-std/Test.sol"; import {Utils} from "foundry-test/l1/unit/concrete/Utils/Utils.sol"; +import {UtilsTest} from "foundry-test/l1/unit/concrete/Utils/Utils.t.sol"; import {UtilsFacet} from "foundry-test/l1/unit/concrete/Utils/UtilsFacet.sol"; import {AdminFacet} from "contracts/state-transition/chain-deps/facets/Admin.sol"; @@ -13,14 +14,17 @@ import {EraTestnetVerifier} from "contracts/state-transition/verifiers/EraTestne import {RollupDAManager} from "contracts/state-transition/data-availability/RollupDAManager.sol"; import {IVerifierV2} from "contracts/state-transition/chain-interfaces/IVerifierV2.sol"; import {IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; +import {DummyBridgehub} from "contracts/dev-contracts/test/DummyBridgehub.sol"; +import {CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "contracts/common/Config.sol"; -contract AdminTest is Test { +contract AdminTest is UtilsTest { IAdmin internal adminFacet; UtilsFacet internal utilsFacet; address internal testnetVerifier = address(new EraTestnetVerifier(IVerifierV2(address(0)), IVerifier(address(0)))); + DummyBridgehub internal dummyBridgehub; function getAdminSelectors() public pure returns (bytes4[] memory) { - bytes4[] memory selectors = new bytes4[](14); + bytes4[] memory selectors = new bytes4[](16); uint256 i = 0; selectors[i++] = IAdmin.setPendingAdmin.selector; selectors[i++] = IAdmin.acceptAdmin.selector; @@ -33,6 +37,8 @@ contract AdminTest is Test { selectors[i++] = IAdmin.executeUpgrade.selector; selectors[i++] = IAdmin.freezeDiamond.selector; selectors[i++] = IAdmin.unfreezeDiamond.selector; + selectors[i++] = IAdmin.pauseDepositsBeforeInitiatingMigration.selector; + selectors[i++] = IAdmin.unpauseDeposits.selector; selectors[i++] = IAdmin.setTransactionFilterer.selector; selectors[i++] = IAdmin.setPubdataPricingMode.selector; selectors[i++] = IAdmin.setDAValidatorPair.selector; @@ -42,7 +48,16 @@ contract AdminTest is Test { function setUp() public virtual { Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](2); facetCuts[0] = Diamond.FacetCut({ - facet: address(new AdminFacet(block.chainid, RollupDAManager(address(0)))), + facet: address( + new AdminFacet( + block.chainid, + RollupDAManager(address(0)), + CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, + CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ) + ), action: Diamond.Action.Add, isFreezable: true, selectors: getAdminSelectors() @@ -54,11 +69,13 @@ contract AdminTest is Test { selectors: Utils.getUtilsFacetSelectors() }); - address diamondProxy = Utils.makeDiamondProxy(facetCuts, testnetVerifier); + dummyBridgehub = new DummyBridgehub(); + mockDiamondInitInteropCenterCallsWithAddress(address(dummyBridgehub), address(0), bytes32(0)); + address diamondProxy = Utils.makeDiamondProxy(facetCuts, testnetVerifier, address(dummyBridgehub)); adminFacet = IAdmin(diamondProxy); utilsFacet = UtilsFacet(diamondProxy); } // add this to be excluded from coverage report - function test() internal virtual {} + function test() internal virtual override {} } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Base/_Base_Shared.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Base/_Base_Shared.t.sol index 586218315a..68b48b1552 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Base/_Base_Shared.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Base/_Base_Shared.t.sol @@ -11,6 +11,8 @@ import {ZKChainBase} from "contracts/state-transition/chain-deps/facets/Admin.so import {EraTestnetVerifier} from "contracts/state-transition/verifiers/EraTestnetVerifier.sol"; import {IVerifierV2} from "contracts/state-transition/chain-interfaces/IVerifierV2.sol"; import {IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; +import {UtilsTest} from "foundry-test/l1/unit/concrete/Utils/Utils.t.sol"; +import {DummyBridgehub} from "contracts/dev-contracts/test/DummyBridgehub.sol"; contract TestBaseFacet is ZKChainBase { function functionWithOnlyAdminModifier() external onlyAdmin {} @@ -36,10 +38,11 @@ bytes constant ERROR_ONLY_BRIDGEHUB = "ZKChain: not bridgehub"; bytes constant ERROR_ONLY_ADMIN_OR_STATE_TRANSITION_MANAGER = "ZKChain: Only by admin or state transition manager"; bytes constant ERROR_ONLY_VALIDATOR_OR_STATE_TRANSITION_MANAGER = "ZKChain: Only by validator or state transition manager"; -contract ZKChainBaseTest is Test { +contract ZKChainBaseTest is UtilsTest { TestBaseFacet internal testBaseFacet; UtilsFacet internal utilsFacet; address internal testnetVerifier = address(new EraTestnetVerifier(IVerifierV2(address(0)), IVerifier(address(0)))); + DummyBridgehub internal dummyBridgehub; function getTestBaseFacetSelectors() public pure returns (bytes4[] memory selectors) { selectors = new bytes4[](6); @@ -66,11 +69,13 @@ contract ZKChainBaseTest is Test { selectors: Utils.getUtilsFacetSelectors() }); - address diamondProxy = Utils.makeDiamondProxy(facetCuts, testnetVerifier); + dummyBridgehub = new DummyBridgehub(); + mockDiamondInitInteropCenterCallsWithAddress(address(dummyBridgehub), address(0), bytes32(0)); + address diamondProxy = Utils.makeDiamondProxy(facetCuts, testnetVerifier, address(dummyBridgehub)); testBaseFacet = TestBaseFacet(diamondProxy); utilsFacet = UtilsFacet(diamondProxy); } // add this to be excluded from coverage report - function test() internal virtual {} + function test() internal virtual override {} } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/BaseMailboxTests.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/BaseMailboxTests.t.sol index 2cbb27779e..39cd007d07 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/BaseMailboxTests.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/BaseMailboxTests.t.sol @@ -16,7 +16,7 @@ contract MailboxBaseTests is MailboxTest { } function test_mailboxConstructor() public { - DummyZKChain h = new DummyZKChain(address(0), eraChainId, block.chainid, eip7702Checker); + DummyZKChain h = new DummyZKChain(address(0), eraChainId, block.chainid, address(0), eip7702Checker); assertEq(h.getEraChainId(), eraChainId); } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/BridgehubRequestL2Transaction.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/BridgehubRequestL2Transaction.t.sol index fdde928276..b5128128a5 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/BridgehubRequestL2Transaction.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/BridgehubRequestL2Transaction.t.sol @@ -23,7 +23,7 @@ contract MailboxBridgehubRequestL2TransactionTest is MailboxTest { BridgehubL2TransactionRequest memory req = getBridgehubRequestL2TransactionRequest(); - vm.deal(bridgehub, 100 ether); + vm.deal(interopCenter, 100 ether); vm.prank(address(bridgehub)); bytes32 canonicalTxHash = mailboxFacet.bridgehubRequestL2Transaction(req); assertTrue(canonicalTxHash != bytes32(0), "canonicalTxHash should not be 0"); @@ -40,7 +40,7 @@ contract MailboxBridgehubRequestL2TransactionTest is MailboxTest { BridgehubL2TransactionRequest memory req = getBridgehubRequestL2TransactionRequest(); - vm.deal(bridgehub, 100 ether); + vm.deal(interopCenter, 100 ether); vm.prank(address(bridgehub)); bytes32 canonicalTxHash = mailboxFacet.bridgehubRequestL2Transaction(req); assertTrue(canonicalTxHash != bytes32(0), "canonicalTxHash should not be 0"); @@ -57,7 +57,7 @@ contract MailboxBridgehubRequestL2TransactionTest is MailboxTest { BridgehubL2TransactionRequest memory req = getBridgehubRequestL2TransactionRequest(); - vm.deal(bridgehub, 100 ether); + vm.deal(interopCenter, 100 ether); vm.prank(address(bridgehub)); vm.expectRevert(TransactionNotAllowed.selector); mailboxFacet.bridgehubRequestL2Transaction(req); @@ -94,6 +94,7 @@ contract MailboxBridgehubRequestL2TransactionTest is MailboxTest { bytes32 oldRootHash = gettersFacet.getPriorityTreeRoot(); assertEq(oldRootHash, bytes32(0), "root hash should be 0"); + address oldBridgehub = address(bridgehub); address bridgehub = makeAddr("bridgehub"); utilsFacet.util_setBridgehub(bridgehub); @@ -102,8 +103,8 @@ contract MailboxBridgehubRequestL2TransactionTest is MailboxTest { BridgehubL2TransactionRequest memory req = getBridgehubRequestL2TransactionRequest(); - vm.deal(bridgehub, 100 ether); - vm.prank(address(bridgehub)); + vm.deal(interopCenter, 100 ether); + vm.prank(address(oldBridgehub)); bytes32 canonicalTxHash = mailboxFacet.bridgehubRequestL2Transaction(req); assertTrue(canonicalTxHash != bytes32(0), "canonicalTxHash should not be 0"); diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/ProvingL2LogsInclusion.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/ProvingL2LogsInclusion.t.sol index e1f4db715a..1bdc001bea 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/ProvingL2LogsInclusion.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/ProvingL2LogsInclusion.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.28; import {MailboxTest} from "./_Mailbox_Shared.t.sol"; -import {L2Log, L2Message} from "contracts/common/Messaging.sol"; +import {L2CanonicalTransaction, L2Log, L2Message, MessageInclusionProof} from "contracts/common/Messaging.sol"; import "forge-std/Test.sol"; import {L2_TO_L1_LOG_SERIALIZE_SIZE} from "contracts/common/Config.sol"; import {L2_BOOTLOADER_ADDRESS, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; @@ -15,7 +15,7 @@ import {TxStatus} from "contracts/state-transition/chain-deps/facets/Mailbox.sol import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; import {MerkleTreeNoSort} from "test/foundry/l1/unit/concrete/common/libraries/Merkle/MerkleTreeNoSort.sol"; -import {MessageHashing} from "contracts/common/libraries/MessageHashing.sol"; +import {MessageHashing, ProofData} from "contracts/common/libraries/MessageHashing.sol"; import {IMailbox} from "contracts/state-transition/chain-interfaces/IMailbox.sol"; import {IGetters} from "contracts/state-transition/chain-interfaces/IGetters.sol"; import {UtilsFacet} from "foundry-test/l1/unit/concrete/Utils/UtilsFacet.sol"; @@ -373,6 +373,70 @@ contract MailboxL2LogsProve is MailboxTest { ); } + function test_calculateRoot() public { + // these txs can be printed out in the server. + bytes + memory txData = hex"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000071000000000000000000000000c9c7594f8f60b77dbdacdc374c5ef822d5733fa700000000000000000000000000000000000000000000000000000000000100090000000000000000000000000000000000000000000000000000000001c9c380000000000000000000000000000000000000000000000000000000000000c350000000000000000000000000000000000000000000000000000000000bebc200000000000000000000000000000000000000000000000000000000000bebc200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000b4000000000000000000000000000000000000000000000000000000000000017e00000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000182000000000000000000000000000000000000000000000000000000000000008c0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002e00000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001f90000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000800a000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000000000000000000000000002c68af0bb14000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d59d06315439cbf54db8ae7ae50ca8f0f5c29738000000000000000000000000c9c7594f8f60b77dbdacdc374c5ef822d5733fa700000000000000000000000000000000000000000000000002c68af0bb140000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c9c7594f8f60b77dbdacdc374c5ef822d5733fa700000000000000000000000000000000000000000000000000000000000005c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001f90000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000056000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000008001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000100030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000003249c884fd1000000000000000000000000000000000000000000000000000000000000010f0338e2cc82046e415792e108c850888b4b26d398bc99dc31b4c3df8f45f16728000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000c9c7594f8f60b77dbdacdc374c5ef822d5733fa7000000000000000000000000d59d06315439cbf54db8ae7ae50ca8f0f5c297380000000000000000000000003d95b0fb27c1de0018d61d1a858c2fd21a72d13b000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c101000000000000000000000000000000000000000000000000000000000000010f000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000007546f6b656e2041000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000024141000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c80000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010f0000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001f90000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000800a000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000000000000000000000000002c68af0bb14000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d59d06315439cbf54db8ae7ae50ca8f0f5c29738000000000000000000000000c9c7594f8f60b77dbdacdc374c5ef822d5733fa700000000000000000000000000000000000000000000000002c68af0bb140000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000c9c7594f8f60b77dbdacdc374c5ef822d5733fa700000000000000000000000000000000000000000000000000000000000000040103000100000000000000000000000000000000000000000000000000000000c71ea440e57fddd8a73a031a4fbc206c65dd4d1c6e55c9e43a52732a67f39b7c24281d22a628042d2746797ee386a7e70d6bdb3355198978c22cf4aa6326fb56e4ed1ec13a28c40715db6399f6f99ce04e5f19d60ad3ff6831f098cb6cf7594400000000000000000000000000000000000000000000000000000000000007a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010f0000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010008000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000005c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001f90000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000056000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000008001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000100030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000003249c884fd1000000000000000000000000000000000000000000000000000000000000010f0338e2cc82046e415792e108c850888b4b26d398bc99dc31b4c3df8f45f16728000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000c9c7594f8f60b77dbdacdc374c5ef822d5733fa7000000000000000000000000d59d06315439cbf54db8ae7ae50ca8f0f5c297380000000000000000000000003d95b0fb27c1de0018d61d1a858c2fd21a72d13b000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c101000000000000000000000000000000000000000000000000000000000000010f000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000007546f6b656e20410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000241410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040103000100000000000000000000000000000000000000000000000000000000579f6c638b50723ea754b2b6046d5f0efb55d8344d0c4e9f602ad137411d909a24281d22a628042d2746797ee386a7e70d6bdb3355198978c22cf4aa6326fb56e4ed1ec13a28c40715db6399f6f99ce04e5f19d60ad3ff6831f098cb6cf75944000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + L2CanonicalTransaction memory trx = abi.decode(txData, (L2CanonicalTransaction)); + (bytes memory paymasterBundle, ) = abi.decode(trx.data, (bytes, bytes)); + (bytes memory paymasterProof, ) = abi.decode(trx.signature, (bytes, bytes)); + MessageInclusionProof memory paymasterInclusionProof = abi.decode(paymasterProof, (MessageInclusionProof)); + paymasterInclusionProof.message.data = paymasterBundle; + // console.log("chainId", paymasterInclusionProof.chainId); + // console.log("l1BatchNumber", paymasterInclusionProof.l1BatchNumber); + // console.log("l2MessageIndex", paymasterInclusionProof.l2MessageIndex); + // // console.logBytes(trx.data); + // console.log(trx.to); + // console.log("l2TxNumberInBlock", paymasterInclusionProof.message[0]); + // console.log("l2Sender", paymasterInclusionProof.message[1]); + // console.log("l2Data", paymasterInclusionProof.message[2]); + // for (uint256 i = 0; i < paymasterInclusionProof.proof.length; i++) { + // console.logBytes32(paymasterInclusionProof.proof[i]); + // } + ProofData memory result = this.getMessageHash( + paymasterInclusionProof.chainId, + paymasterInclusionProof.l1BatchNumber, + paymasterInclusionProof.l2MessageIndex, + paymasterInclusionProof.message, + paymasterInclusionProof.proof + ); + // console.logBytes32(result.batchSettlementRoot); + // // assertEq(proofHash, hashedLog); + } + + function getMessageHash( + uint256 _chainId, + uint256 _l1BatchNumber, + uint256 _l2MessageIndex, + L2Message calldata _message, + bytes32[] calldata _proof + ) public returns (ProofData memory) { + L2Log memory _log = _L2MessageToLog(_message); + // console.log("Log l2"); + // console.log(_log.sender); + // console.log(_log.txNumberInBatch); + // console.logBytes32(_log.key); + // console.logBytes32(_log.value); + bytes32 hashedLog = keccak256( + // solhint-disable-next-line func-named-parameters + abi.encodePacked(_log.l2ShardId, _log.isService, _log.txNumberInBatch, _log.sender, _log.key, _log.value) + ); + return MessageHashing._getProofData(_chainId, _l1BatchNumber, _l2MessageIndex, hashedLog, _proof); + } + + /// @dev Convert arbitrary-length message to the raw l2 log + function _L2MessageToLog(L2Message calldata _message) internal pure returns (L2Log memory) { + return + L2Log({ + l2ShardId: 0, + isService: true, + txNumberInBatch: _message.txNumberInBatch, + sender: L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + key: bytes32(uint256(uint160(_message.sender))), + value: keccak256(_message.data) + }); + } + /// @notice Proves L1 to L2 transaction status and cross-checks new and old encoding function _proveL1ToL2TransactionStatus( bytes32 _l2TxHash, diff --git a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/_Mailbox_Shared.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/_Mailbox_Shared.t.sol index babf58dbd0..4d27237d89 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/_Mailbox_Shared.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/state-transition/chain-deps/facets/Mailbox/_Mailbox_Shared.t.sol @@ -13,9 +13,14 @@ import {IGetters} from "contracts/state-transition/chain-interfaces/IGetters.sol import {EraTestnetVerifier} from "contracts/state-transition/verifiers/EraTestnetVerifier.sol"; import {IVerifierV2} from "contracts/state-transition/chain-interfaces/IVerifierV2.sol"; import {IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; +import {UtilsTest} from "foundry-test/l1/unit/concrete/Utils/Utils.t.sol"; +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; +import {IChainAssetHandler} from "contracts/bridgehub/IChainAssetHandler.sol"; +import {IL1ChainAssetHandler} from "contracts/bridgehub/IL1ChainAssetHandler.sol"; import {IEIP7702Checker} from "contracts/state-transition/chain-interfaces/IEIP7702Checker.sol"; +import {PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "contracts/common/Config.sol"; -contract MailboxTest is Test { +contract MailboxTest is UtilsTest { IMailbox internal mailboxFacet; UtilsFacet internal utilsFacet; IGetters internal gettersFacet; @@ -24,18 +29,33 @@ contract MailboxTest is Test { address internal testnetVerifier = address(new EraTestnetVerifier(IVerifierV2(address(0)), IVerifier(address(0)))); address diamondProxy; address bridgehub; + address chainAssetHandler; + address interopCenter; IEIP7702Checker eip7702Checker; function deployDiamondProxy() internal returns (address proxy) { sender = makeAddr("sender"); bridgehub = makeAddr("bridgehub"); + chainAssetHandler = makeAddr("chainAssetHandler"); + interopCenter = makeAddr("interopCenter"); vm.deal(sender, 100 ether); + // Warp time past the initial pause deposits window (2 days for testnet) + vm.warp(PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + 1); eip7702Checker = IEIP7702Checker(Utils.deployEIP7702Checker()); Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](3); facetCuts[0] = Diamond.FacetCut({ - facet: address(new MailboxFacet(eraChainId, block.chainid, eip7702Checker)), + facet: address( + new MailboxFacet( + eraChainId, + block.chainid, + address(chainAssetHandler), + eip7702Checker, + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ) + ), action: Diamond.Action.Add, isFreezable: true, selectors: Utils.getMailboxSelectors() @@ -53,7 +73,23 @@ contract MailboxTest is Test { selectors: Utils.getGettersSelectors() }); - proxy = Utils.makeDiamondProxy(facetCuts, testnetVerifier); + mockDiamondInitInteropCenterCallsWithAddress(bridgehub, address(0), bytes32(0)); + vm.mockCall( + address(bridgehub), + abi.encodeWithSelector(IBridgehubBase.chainAssetHandler.selector), + abi.encode(chainAssetHandler) + ); + vm.mockCall( + address(chainAssetHandler), + abi.encodeWithSelector(IChainAssetHandler.migrationNumber.selector), + abi.encode(1) + ); + vm.mockCall( + address(chainAssetHandler), + abi.encodeWithSelector(IL1ChainAssetHandler.isMigrationInProgress.selector), + abi.encode(false) + ); + proxy = Utils.makeDiamondProxy(facetCuts, testnetVerifier, bridgehub); utilsFacet = UtilsFacet(proxy); utilsFacet.util_setBridgehub(bridgehub); } @@ -64,8 +100,11 @@ contract MailboxTest is Test { mailboxFacet = IMailbox(diamondProxy); utilsFacet = UtilsFacet(diamondProxy); gettersFacet = IGetters(diamondProxy); + + // utilsFacet.util_setBridgehub(bridgehub); + // utilsFacet.util_setInteropCenter(interopCenter); } // add this to be excluded from coverage report - function test() internal virtual {} + function test() internal virtual override {} } diff --git a/l1-contracts/test/foundry/l1/unit/concrete/upgrades/L1GatewayBase.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/upgrades/L1GatewayBase.t.sol index 2602643dad..0da3d8a627 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/upgrades/L1GatewayBase.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/upgrades/L1GatewayBase.t.sol @@ -8,6 +8,8 @@ import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; import {IL1SharedBridgeLegacy} from "contracts/bridge/interfaces/IL1SharedBridgeLegacy.sol"; import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; import {ZKChainSpecificForceDeploymentsData} from "contracts/state-transition/l2-deps/IL2GenesisUpgrade.sol"; +import {IL1AssetRouter} from "contracts/bridge/asset-router/IL1AssetRouter.sol"; +import {INativeTokenVaultBase} from "contracts/bridge/ntv/INativeTokenVaultBase.sol"; // Concrete implementation of L1FixedForceDeploymentsHelper for testing contract TestL1FixedForceDeploymentsHelper is L1FixedForceDeploymentsHelper { @@ -59,6 +61,7 @@ contract L1FixedForceDeploymentsHelperTest is Test { // Mocks for dependencies address bridgehubMock; address sharedBridgeMock; + address nativeTokenVaultMock; // MockL2WrappedBaseTokenStore wrappedBaseTokenStoreMock; // Addresses @@ -73,6 +76,7 @@ contract L1FixedForceDeploymentsHelperTest is Test { baseTokenAssetId = bytes32("baseTokenAssetId"); bridgehubMock = makeAddr("bridgehubMock"); sharedBridgeMock = makeAddr("sharedBridgeMock"); + nativeTokenVaultMock = makeAddr("nativeTokenVaultMock"); legacySharedBridgeAddress = makeAddr("legacySharedBridgeAddress"); testGateway = new TestL1FixedForceDeploymentsHelper(); @@ -89,6 +93,21 @@ contract L1FixedForceDeploymentsHelperTest is Test { abi.encodeCall(IL1SharedBridgeLegacy.l2BridgeAddress, (chainId)), abi.encode(address(legacySharedBridgeAddress)) ); + vm.mockCall( + sharedBridgeMock, + abi.encodeCall(IL1AssetRouter.nativeTokenVault, ()), + abi.encode(nativeTokenVaultMock) + ); + vm.mockCall( + nativeTokenVaultMock, + abi.encodeCall(INativeTokenVaultBase.originChainId, (baseTokenAssetId)), + abi.encode(chainId) + ); + vm.mockCall( + nativeTokenVaultMock, + abi.encodeCall(INativeTokenVaultBase.originToken, (baseTokenAssetId)), + abi.encode(ETH_TOKEN_ADDRESS) + ); } // Test with ETH as the base token diff --git a/l1-contracts/test/foundry/l1/unit/concrete/upgrades/L2GenesisForceDeploymentHelper.t.sol b/l1-contracts/test/foundry/l1/unit/concrete/upgrades/L2GenesisForceDeploymentHelper.t.sol index 0236c544b1..5a9ca7e469 100644 --- a/l1-contracts/test/foundry/l1/unit/concrete/upgrades/L2GenesisForceDeploymentHelper.t.sol +++ b/l1-contracts/test/foundry/l1/unit/concrete/upgrades/L2GenesisForceDeploymentHelper.t.sol @@ -75,6 +75,7 @@ contract L2GenesisForceDeploymentsHelperTest is Test { bytes memory fixedEncoded = abi.encode(fixedData); bytes memory additionalEncoded = abi.encode(additionalData); + _deployMockContract(GW_ASSET_TRACKER_ADDR); // Mock the SystemContractProxyAdmin.owner() call to return the expected owner vm.mockCall(L2_SYSTEM_CONTRACT_PROXY_ADMIN_ADDR, abi.encodeWithSignature("owner()"), abi.encode(address(this))); @@ -104,12 +105,15 @@ contract L2GenesisForceDeploymentsHelperTest is Test { assertEq(etchedDeployer.deploymentCount(L2_NATIVE_TOKEN_VAULT_ADDR), 1); assertEq(etchedDeployer.deploymentCount(L2_CHAIN_ASSET_HANDLER_ADDR), 1); assertEq(etchedDeployer.deploymentCount(L2_NTV_BEACON_DEPLOYER_ADDR), 1); + assertEq(etchedDeployer.deploymentCount(L2_INTEROP_CENTER_ADDR), 1); + assertEq(etchedDeployer.deploymentCount(L2_INTEROP_HANDLER_ADDR), 1); + assertEq(etchedDeployer.deploymentCount(L2_ASSET_TRACKER_ADDR), 1); // Verify proxy upgrades were called - use the etched contract at the system address MockSystemContractProxyAdmin etchedProxyAdmin = MockSystemContractProxyAdmin( L2_SYSTEM_CONTRACT_PROXY_ADMIN_ADDR ); - assertEq(etchedProxyAdmin.upgradeCallCount(), 6); + assertEq(etchedProxyAdmin.upgradeCallCount(), 9); } function testZKsyncOSSystemProxyUpgrade_NonGenesis() public { @@ -126,6 +130,7 @@ contract L2GenesisForceDeploymentsHelperTest is Test { _deployMockContract(L2_ASSET_ROUTER_ADDR); _deployMockContract(L2_NATIVE_TOKEN_VAULT_ADDR); _deployMockContract(L2_CHAIN_ASSET_HANDLER_ADDR); + _deployMockContract(GW_ASSET_TRACKER_ADDR); vm.mockCall(L2_SYSTEM_CONTRACT_PROXY_ADMIN_ADDR, abi.encodeWithSignature("owner()"), abi.encode(address(this))); @@ -152,7 +157,7 @@ contract L2GenesisForceDeploymentsHelperTest is Test { MockSystemContractProxyAdmin etchedProxyAdmin = MockSystemContractProxyAdmin( L2_SYSTEM_CONTRACT_PROXY_ADMIN_ADDR ); - assertEq(etchedProxyAdmin.upgradeCallCount(), 5); + assertEq(etchedProxyAdmin.upgradeCallCount(), 8); } function testEraForceDeployment() public { @@ -161,6 +166,7 @@ contract L2GenesisForceDeploymentsHelperTest is Test { bytes memory fixedEncoded = abi.encode(fixedData); bytes memory additionalEncoded = abi.encode(additionalData); + _deployMockContract(GW_ASSET_TRACKER_ADDR); // For Era deployments, no proxy admin is needed vm.startPrank(L2_COMPLEX_UPGRADER_ADDR); @@ -220,6 +226,18 @@ contract L2GenesisForceDeploymentsHelperTest is Test { abi.encode(keccak256("chainHandler_impl"), uint32(0), bytes32(0)), abi.encode(keccak256("chainHandler_proxy"), uint32(0), bytes32(0)) ); + data.interopCenterBytecodeInfo = abi.encode( + abi.encode(keccak256("interopCenter_impl"), uint32(0), bytes32(0)), + abi.encode(keccak256("interopCenter_proxy"), uint32(0), bytes32(0)) + ); + data.interopHandlerBytecodeInfo = abi.encode( + abi.encode(keccak256("interopHandler_impl"), uint32(0), bytes32(0)), + abi.encode(keccak256("interopHandler_proxy"), uint32(0), bytes32(0)) + ); + data.assetTrackerBytecodeInfo = abi.encode( + abi.encode(keccak256("assetTracker_impl"), uint32(0), bytes32(0)), + abi.encode(keccak256("assetTracker_proxy"), uint32(0), bytes32(0)) + ); if (isGenesis) { data.beaconDeployerInfo = abi.encode( @@ -247,6 +265,9 @@ contract L2GenesisForceDeploymentsHelperTest is Test { data.l2AssetRouterBytecodeInfo = abi.encode(keccak256("assetRouter")); data.l2NtvBytecodeInfo = abi.encode(keccak256("ntv")); data.chainAssetHandlerBytecodeInfo = abi.encode(keccak256("chainHandler")); + data.interopCenterBytecodeInfo = abi.encode(keccak256("interopCenter")); + data.interopHandlerBytecodeInfo = abi.encode(keccak256("interopHandler")); + data.assetTrackerBytecodeInfo = abi.encode(keccak256("assetTracker")); data.beaconDeployerInfo = abi.encode(keccak256("beaconDeployer")); return data; @@ -272,13 +293,16 @@ contract L2GenesisForceDeploymentsHelperTest is Test { function _etchAllDeferredContracts() internal { // Etch contracts to addresses that need function calls to work - address[] memory addressesToEtch = new address[](6); + address[] memory addressesToEtch = new address[](9); addressesToEtch[0] = L2_MESSAGE_ROOT_ADDR; addressesToEtch[1] = L2_BRIDGEHUB_ADDR; addressesToEtch[2] = L2_ASSET_ROUTER_ADDR; addressesToEtch[3] = L2_NATIVE_TOKEN_VAULT_ADDR; addressesToEtch[4] = L2_CHAIN_ASSET_HANDLER_ADDR; addressesToEtch[5] = L2_NTV_BEACON_DEPLOYER_ADDR; + addressesToEtch[6] = L2_INTEROP_CENTER_ADDR; + addressesToEtch[7] = L2_INTEROP_HANDLER_ADDR; + addressesToEtch[8] = L2_ASSET_TRACKER_ADDR; for (uint256 i = 0; i < addressesToEtch.length; i++) { if (addressesToEtch[i].code.length == 0) { diff --git a/l1-contracts/test/foundry/l1/upgrades/_SharedBaseUpgrade.t.sol b/l1-contracts/test/foundry/l1/upgrades/_SharedBaseUpgrade.t.sol index dfb853f2cb..0f6c70a9df 100644 --- a/l1-contracts/test/foundry/l1/upgrades/_SharedBaseUpgrade.t.sol +++ b/l1-contracts/test/foundry/l1/upgrades/_SharedBaseUpgrade.t.sol @@ -7,7 +7,7 @@ import {L2CanonicalTransaction} from "contracts/common/Messaging.sol"; import {VerifierParams} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; import {PRIORITY_TX_MAX_GAS_LIMIT, REQUIRED_L2_GAS_PRICE_PER_PUBDATA, SYSTEM_UPGRADE_L2_TX_TYPE} from "contracts/common/Config.sol"; import {L2_FORCE_DEPLOYER_ADDR, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; -import {ISystemContext} from "contracts/state-transition/l2-deps/ISystemContext.sol"; +import {ISystemContext} from "contracts/common/interfaces/ISystemContext.sol"; import {L2ContractHelper} from "contracts/common/l2-helpers/L2ContractHelper.sol"; import {SemVer} from "contracts/common/libraries/SemVer.sol"; diff --git a/l1-contracts/test/foundry/l2/integration/L2ERC20BridgeTest.t.sol b/l1-contracts/test/foundry/l2/integration/L2ERC20BridgeTest.t.sol index 5c37069418..d2a4ca4283 100644 --- a/l1-contracts/test/foundry/l2/integration/L2ERC20BridgeTest.t.sol +++ b/l1-contracts/test/foundry/l2/integration/L2ERC20BridgeTest.t.sol @@ -7,19 +7,10 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; import "forge-std/console.sol"; -import {BridgedStandardERC20} from "contracts/bridge/BridgedStandardERC20.sol"; -import {L2AssetRouter} from "contracts/bridge/asset-router/L2AssetRouter.sol"; -import {IL2NativeTokenVault} from "contracts/bridge/ntv/IL2NativeTokenVault.sol"; - -import {L2_ASSET_ROUTER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; - -import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol"; - -import {DeployUtils} from "deploy-scripts/DeployUtils.s.sol"; -import {L2Utils, SystemContractsArgs} from "./L2Utils.sol"; -import {SharedL2ContractL2Deployer} from "./_SharedL2ContractL2Deployer.sol"; +import {SystemContractsArgs} from "./L2Utils.sol"; import {L2Erc20TestAbstract} from "../../l1/integration/l2-tests-abstract/L2Erc20TestAbstract.t.sol"; import {SharedL2ContractDeployer} from "../../l1/integration/l2-tests-abstract/_SharedL2ContractDeployer.sol"; +import {SharedL2ContractL2Deployer} from "./_SharedL2ContractL2Deployer.sol"; import {Create2FactoryUtils} from "deploy-scripts/Create2FactoryUtils.s.sol"; diff --git a/l1-contracts/test/foundry/l2/integration/L2GatewayTests.t.sol b/l1-contracts/test/foundry/l2/integration/L2GatewayTests.t.sol index 25134f43f7..c8280b2564 100644 --- a/l1-contracts/test/foundry/l2/integration/L2GatewayTests.t.sol +++ b/l1-contracts/test/foundry/l2/integration/L2GatewayTests.t.sol @@ -53,4 +53,11 @@ contract L2GatewayTests is Test, L2GatewayTestAbstract, SharedL2ContractL2Deploy ) public override(SharedL2ContractL2Deployer, SharedL2ContractDeployer) { super.deployL2Contracts(_l1ChainId); } + + function getCreationCode( + string memory contractName, + bool isZKBytecode + ) internal view virtual override returns (bytes memory) { + return super.getCreationCode(contractName, false); + } } diff --git a/l1-contracts/test/foundry/l2/integration/L2GenesisUpgrade.t.sol b/l1-contracts/test/foundry/l2/integration/L2GenesisUpgrade.t.sol index 6c54c8cd6b..b2234c95bc 100644 --- a/l1-contracts/test/foundry/l2/integration/L2GenesisUpgrade.t.sol +++ b/l1-contracts/test/foundry/l2/integration/L2GenesisUpgrade.t.sol @@ -4,10 +4,12 @@ pragma solidity 0.8.28; import {Test} from "forge-std/Test.sol"; +import {StdStorage, Test, stdStorage} from "forge-std/Test.sol"; + import {L2ComplexUpgrader} from "contracts/l2-upgrades/L2ComplexUpgrader.sol"; import {L2GenesisUpgrade} from "contracts/l2-upgrades/L2GenesisUpgrade.sol"; import {IL2GenesisUpgrade} from "contracts/state-transition/l2-deps/IL2GenesisUpgrade.sol"; -import {L2_COMPLEX_UPGRADER_ADDR, L2_FORCE_DEPLOYER_ADDR, L2_GENESIS_UPGRADE_ADDR, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, L2_MESSAGE_ROOT_ADDR, L2_BRIDGEHUB_ADDR, L2_ASSET_ROUTER_ADDR, L2_WRAPPED_BASE_TOKEN_IMPL_ADDR, L2_NTV_BEACON_DEPLOYER_ADDR, L2_KNOWN_CODE_STORAGE_SYSTEM_CONTRACT_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {L2_COMPLEX_UPGRADER_ADDR, L2_FORCE_DEPLOYER_ADDR, L2_INTEROP_HANDLER_ADDR, L2_GENESIS_UPGRADE_ADDR, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, L2_MESSAGE_ROOT_ADDR, L2_BRIDGEHUB_ADDR, L2_ASSET_ROUTER_ADDR, L2_WRAPPED_BASE_TOKEN_IMPL_ADDR, L2_NTV_BEACON_DEPLOYER_ADDR, L2_KNOWN_CODE_STORAGE_SYSTEM_CONTRACT_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {Utils} from "deploy-scripts/Utils.sol"; import {L2ContractHelper} from "contracts/common/l2-helpers/L2ContractHelper.sol"; import {FixedForceDeploymentsData, ZKChainSpecificForceDeploymentsData} from "contracts/state-transition/l2-deps/IL2GenesisUpgrade.sol"; @@ -21,7 +23,7 @@ import {SharedL2ContractDeployer} from "../../l1/integration/l2-tests-abstract/_ import {SharedL2ContractL2Deployer} from "./_SharedL2ContractL2Deployer.sol"; import {SystemContractsArgs} from "./L2Utils.sol"; import {SharedL2ContractL2Deployer} from "./_SharedL2ContractL2Deployer.sol"; -import {ISystemContext} from "contracts/state-transition/l2-deps/ISystemContext.sol"; +import {ISystemContext} from "contracts/common/interfaces/ISystemContext.sol"; import {L2GatewayTestAbstract} from "../../l1/integration/l2-tests-abstract/L2GatewayTestAbstract.t.sol"; import {SharedL2ContractDeployer} from "../../l1/integration/l2-tests-abstract/_SharedL2ContractDeployer.sol"; import {Create2FactoryUtils} from "deploy-scripts/Create2FactoryUtils.s.sol"; @@ -29,6 +31,8 @@ import {SystemContractProxyAdmin} from "contracts/l2-upgrades/SystemContractProx import {L2_SYSTEM_CONTRACT_PROXY_ADMIN_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; contract L2GenesisUpgradeTest is Test, SharedL2ContractDeployer, SharedL2ContractL2Deployer { + using stdStorage for StdStorage; + uint256 constant CHAIN_ID = 270; address ctmDeployerAddress = makeAddr("ctmDeployer"); address bridgehubOwnerAddress = makeAddr("bridgehubOwner"); @@ -60,6 +64,12 @@ contract L2GenesisUpgradeTest is Test, SharedL2ContractDeployer, SharedL2Contrac function setUp() public override { super.setUp(); + vm.store( + L2_INTEROP_HANDLER_ADDR, + bytes32(0x8e94fed44239eb2314ab7a406345e6c5a8f0ccedf3b600de3d004e672c33abf4), + bytes32(uint256(0)) + ); + // Deploy and etch L2ComplexUpgrader bytes memory complexUpgraderCode = Utils.readZKFoundryBytecodeL1("L2ComplexUpgrader.sol", "L2ComplexUpgrader"); vm.etch(L2_COMPLEX_UPGRADER_ADDR, complexUpgraderCode); @@ -104,7 +114,9 @@ contract L2GenesisUpgradeTest is Test, SharedL2ContractDeployer, SharedL2Contrac predeployedL2WethAddress: address(1), baseTokenL1Address: address(1), baseTokenName: "Ether", - baseTokenSymbol: "ETH" + baseTokenSymbol: "ETH", + baseTokenOriginChainId: 1, + baseTokenOriginAddress: address(1) }) ); @@ -117,29 +129,42 @@ contract L2GenesisUpgradeTest is Test, SharedL2ContractDeployer, SharedL2Contrac ); bytes memory l2NtvBytecodeInfo = abi.encode(L2ContractHelper.hashL2Bytecode(l2NativeTokenVaultBytecode)); - bytes memory l2AssetRouterBytecode = Utils.readZKFoundryBytecodeL1("L2AssetRouter.sol", "L2AssetRouter"); - bytes memory l2AssetRouterBytecodeInfo = abi.encode(L2ContractHelper.hashL2Bytecode(l2AssetRouterBytecode)); - - bytes memory bridgehubBytecode = Utils.readZKFoundryBytecodeL1("L2Bridgehub.sol", "L2Bridgehub"); - bytes memory bridgehubBytecodeInfo = abi.encode(L2ContractHelper.hashL2Bytecode(bridgehubBytecode)); + bytes memory l2AssetRouterBytecodeInfo = abi.encode( + L2ContractHelper.hashL2Bytecode(Utils.readZKFoundryBytecodeL1("L2AssetRouter.sol", "L2AssetRouter")) + ); - bytes memory chainAssetHandlerBytecode = Utils.readZKFoundryBytecodeL1( - "L2ChainAssetHandler.sol", - "L2ChainAssetHandler" + bytes memory bridgehubBytecodeInfo = abi.encode( + L2ContractHelper.hashL2Bytecode(Utils.readZKFoundryBytecodeL1("L2Bridgehub.sol", "L2Bridgehub")) ); + bytes memory chainAssetHandlerBytecodeInfo = abi.encode( - L2ContractHelper.hashL2Bytecode(chainAssetHandlerBytecode) + L2ContractHelper.hashL2Bytecode( + Utils.readZKFoundryBytecodeL1("L2ChainAssetHandler.sol", "L2ChainAssetHandler") + ) ); - bytes memory beaconDeployerBytecode = Utils.readZKFoundryBytecodeL1( - "UpgradeableBeaconDeployer.sol", - "UpgradeableBeaconDeployer" + bytes memory beaconDeployerBytecodeInfo = abi.encode( + L2ContractHelper.hashL2Bytecode( + Utils.readZKFoundryBytecodeL1("UpgradeableBeaconDeployer.sol", "UpgradeableBeaconDeployer") + ) + ); + + bytes memory interopCenterBytecodeInfo = abi.encode( + L2ContractHelper.hashL2Bytecode(Utils.readZKFoundryBytecodeL1("InteropCenter.sol", "InteropCenter")) + ); + + bytes memory interopHandlerBytecodeInfo = abi.encode( + L2ContractHelper.hashL2Bytecode(Utils.readZKFoundryBytecodeL1("InteropHandler.sol", "InteropHandler")) + ); + + bytes memory assetTrackerBytecodeInfo = abi.encode( + L2ContractHelper.hashL2Bytecode(Utils.readZKFoundryBytecodeL1("L2AssetTracker.sol", "L2AssetTracker")) ); - bytes memory beaconDeployerBytecodeInfo = abi.encode(L2ContractHelper.hashL2Bytecode(beaconDeployerBytecode)); fixedForceDeploymentsData = abi.encode( FixedForceDeploymentsData({ l1ChainId: 1, + gatewayChainId: 1, eraChainId: CHAIN_ID, l1AssetRouter: address(1), l2TokenProxyBytecodeHash: bytes32(0x0100056f53fd9e940906d998a80ed53392e5c50a8eb198baf9f78fd84ce7ec70), @@ -150,10 +175,14 @@ contract L2GenesisUpgradeTest is Test, SharedL2ContractDeployer, SharedL2Contrac l2NtvBytecodeInfo: l2NtvBytecodeInfo, messageRootBytecodeInfo: messageRootBytecodeInfo, chainAssetHandlerBytecodeInfo: chainAssetHandlerBytecodeInfo, + interopCenterBytecodeInfo: interopCenterBytecodeInfo, + interopHandlerBytecodeInfo: interopHandlerBytecodeInfo, + assetTrackerBytecodeInfo: assetTrackerBytecodeInfo, beaconDeployerInfo: beaconDeployerBytecodeInfo, // For genesis upgrade these values will always be zero l2SharedBridgeLegacyImpl: address(0), l2BridgedStandardERC20Impl: address(0), + aliasedChainRegistrationSender: address(1), dangerousTestOnlyForcedBeacon: address(0) }) ); diff --git a/l1-contracts/test/foundry/l2/integration/L2InteropTest.t.sol b/l1-contracts/test/foundry/l2/integration/L2InteropTest.t.sol new file mode 100644 index 0000000000..b88656f09d --- /dev/null +++ b/l1-contracts/test/foundry/l2/integration/L2InteropTest.t.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +// solhint-disable gas-custom-errors + +import {Test} from "forge-std/Test.sol"; +import "forge-std/console.sol"; + +import {SystemContractsArgs} from "./L2Utils.sol"; + +import {SharedL2ContractL2Deployer} from "./_SharedL2ContractL2Deployer.sol"; + +import {L2InteropTestAbstract} from "../../l1/integration/l2-tests-abstract/L2InteropTestAbstract.t.sol"; +import {SharedL2ContractDeployer} from "../../l1/integration/l2-tests-abstract/_SharedL2ContractDeployer.sol"; +import {Create2FactoryUtils} from "deploy-scripts/Create2FactoryUtils.s.sol"; + +contract L2InteropTests is Test, L2InteropTestAbstract, SharedL2ContractL2Deployer { + // We need to emulate a L1->L2 transaction from the L1 bridge to L2 counterpart. + // It is a bit easier to use EOA and it is sufficient for the tests. + function test() internal virtual override(SharedL2ContractDeployer, SharedL2ContractL2Deployer) {} + + function initSystemContracts( + SystemContractsArgs memory _args + ) internal override(SharedL2ContractDeployer, SharedL2ContractL2Deployer) { + super.initSystemContracts(_args); + } + + function deployViaCreate2( + bytes memory creationCode, + bytes memory constructorArgs + ) internal override(Create2FactoryUtils, SharedL2ContractL2Deployer) returns (address) { + return super.deployViaCreate2(creationCode, constructorArgs); + } + + function deployL2Contracts( + uint256 _l1ChainId + ) public override(SharedL2ContractL2Deployer, SharedL2ContractDeployer) { + super.deployL2Contracts(_l1ChainId); + } + + function getCreationCode( + string memory contractName, + bool isZKBytecode + ) internal view virtual override returns (bytes memory) { + return super.getCreationCode(contractName, false); + } +} diff --git a/l1-contracts/test/foundry/l2/integration/L2NativeTokenVault.t.sol b/l1-contracts/test/foundry/l2/integration/L2NativeTokenVault.t.sol index f43ff12be4..5e55f9dcd1 100644 --- a/l1-contracts/test/foundry/l2/integration/L2NativeTokenVault.t.sol +++ b/l1-contracts/test/foundry/l2/integration/L2NativeTokenVault.t.sol @@ -9,7 +9,6 @@ import {Test} from "forge-std/Test.sol"; import {SystemContractsArgs} from "./L2Utils.sol"; -import {DeployUtils} from "deploy-scripts/DeployUtils.s.sol"; import {L2NativeTokenVaultTestAbstract} from "../../l1/integration/l2-tests-abstract/L2NativeTokenVaultTestAbstract.t.sol"; import {SharedL2ContractL2Deployer} from "./_SharedL2ContractL2Deployer.sol"; import {SharedL2ContractDeployer} from "../../l1/integration/l2-tests-abstract/_SharedL2ContractDeployer.sol"; @@ -39,4 +38,11 @@ contract L2NativeTokenVaultTest is Test, SharedL2ContractL2Deployer, L2NativeTok ) public override(SharedL2ContractL2Deployer, SharedL2ContractDeployer) { super.deployL2Contracts(_l1ChainId); } + + function getCreationCode( + string memory contractName, + bool isZKBytecode + ) internal view virtual override returns (bytes memory) { + return super.getCreationCode(contractName, false); + } } diff --git a/l1-contracts/test/foundry/l2/integration/L2Utils.sol b/l1-contracts/test/foundry/l2/integration/L2Utils.sol index bd95ca5e0b..1f53413c99 100644 --- a/l1-contracts/test/foundry/l2/integration/L2Utils.sol +++ b/l1-contracts/test/foundry/l2/integration/L2Utils.sol @@ -6,7 +6,7 @@ import {Vm} from "forge-std/Vm.sol"; import "forge-std/console.sol"; -import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR, L2_COMPLEX_UPGRADER_ADDR, L2_DEPLOYER_SYSTEM_CONTRACT_ADDR, L2_MESSAGE_ROOT_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR, L2_COMPLEX_UPGRADER_ADDR, L2_DEPLOYER_SYSTEM_CONTRACT_ADDR, L2_FORCE_DEPLOYER_ADDR, L2_INTEROP_CENTER_ADDR, L2_INTEROP_HANDLER_ADDR, L2_ASSET_TRACKER_ADDR, GW_ASSET_TRACKER_ADDR, L2_INTEROP_ROOT_STORAGE, L2_MESSAGE_ROOT_ADDR, L2_MESSAGE_VERIFICATION, L2_NATIVE_TOKEN_VAULT_ADDR, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {IContractDeployer, L2ContractHelper} from "contracts/common/l2-helpers/L2ContractHelper.sol"; import {L2AssetRouter} from "contracts/bridge/asset-router/L2AssetRouter.sol"; @@ -15,15 +15,23 @@ import {IL2SharedBridgeLegacy} from "contracts/bridge/interfaces/IL2SharedBridge import {L2NativeTokenVault} from "contracts/bridge/ntv/L2NativeTokenVault.sol"; import {IMessageRoot} from "contracts/bridgehub/IMessageRoot.sol"; import {ICTMDeploymentTracker} from "contracts/bridgehub/ICTMDeploymentTracker.sol"; + +import {L2MessageVerification} from "contracts/interop/L2MessageVerification.sol"; +import {DummyL2InteropRootStorage} from "contracts/dev-contracts/test/DummyL2InteropRootStorage.sol"; +import {InteropCenter} from "contracts/interop/InteropCenter.sol"; +import {InteropHandler} from "contracts/interop/InteropHandler.sol"; +import {L2AssetTracker} from "contracts/bridge/asset-tracker/L2AssetTracker.sol"; +import {GWAssetTracker} from "contracts/bridge/asset-tracker/GWAssetTracker.sol"; +// import {InteropAccount} from "contracts/interop/InteropAccount.sol"; import {L2Bridgehub} from "contracts/bridgehub/L2Bridgehub.sol"; import {IL2Bridgehub} from "contracts/bridgehub/IL2Bridgehub.sol"; import {L2MessageRoot} from "contracts/bridgehub/L2MessageRoot.sol"; import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; - import {DataEncoding} from "contracts/common/libraries/DataEncoding.sol"; import {DeployFailed} from "contracts/common/L1ContractErrors.sol"; + import {SystemContractsArgs} from "../../l1/integration/l2-tests-abstract/_SharedL2ContractDeployer.sol"; import {Utils} from "deploy-scripts/Utils.sol"; @@ -33,6 +41,8 @@ library L2Utils { address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); Vm internal constant vm = Vm(VM_ADDRESS); + /// rich account on era_test_node + address internal constant RANDOM_ADDRESS = address(0xBC989fDe9e54cAd2aB4392Af6dF60f04873A033A); address internal constant L2_FORCE_DEPLOYER_ADDR = address(0x8007); uint256 internal constant L1_CHAIN_ID = 1; @@ -47,24 +57,37 @@ library L2Utils { } function forceDeploySystemContracts(SystemContractsArgs memory _args) internal { - forceDeployMessageRoot(_args); forceDeployBridgehub(_args); + forceDeployMessageRoot(_args); forceDeployChainAssetHandler(_args); forceDeployAssetRouter(_args); forceDeployNativeTokenVault(_args); + forceDeployL2MessageVerification(_args); + forceDeployL2InteropRootStorage(_args); + forceDeployInteropCenter(_args); + forceDeployInteropHandler(_args); + forceDeployL2AssetTracker(_args); + forceDeployGWAssetTracker(_args); + + initializeBridgehub(_args); } function forceDeployMessageRoot(SystemContractsArgs memory _args) internal { new L2MessageRoot(); forceDeployWithoutConstructor("L2MessageRoot", L2_MESSAGE_ROOT_ADDR); vm.prank(L2_COMPLEX_UPGRADER_ADDR); - L2MessageRoot(L2_MESSAGE_ROOT_ADDR).initL2(_args.l1ChainId); + L2MessageRoot(L2_MESSAGE_ROOT_ADDR).initL2(_args.l1ChainId, _args.gatewayChainId); } function forceDeployBridgehub(SystemContractsArgs memory _args) internal { new L2Bridgehub(); forceDeployWithoutConstructor("L2Bridgehub", L2_BRIDGEHUB_ADDR); L2Bridgehub bridgehub = L2Bridgehub(L2_BRIDGEHUB_ADDR); + } + + function initializeBridgehub(SystemContractsArgs memory _args) internal { + L2Bridgehub bridgehub = L2Bridgehub(L2_BRIDGEHUB_ADDR); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); bridgehub.initL2(_args.l1ChainId, _args.aliasedOwner, 100); vm.prank(_args.aliasedOwner); @@ -72,7 +95,8 @@ library L2Utils { L2_ASSET_ROUTER_ADDR, ICTMDeploymentTracker(_args.l1CtmDeployer), IMessageRoot(L2_MESSAGE_ROOT_ADDR), - L2_CHAIN_ASSET_HANDLER_ADDR + L2_CHAIN_ASSET_HANDLER_ADDR, + address(0) ); } @@ -90,6 +114,48 @@ library L2Utils { ); } + function forceDeployL2MessageVerification(SystemContractsArgs memory _args) internal { + new L2MessageVerification(); + + forceDeployWithoutConstructor("L2MessageVerification", address(L2_MESSAGE_VERIFICATION)); + } + + function forceDeployL2InteropRootStorage(SystemContractsArgs memory _args) internal { + new DummyL2InteropRootStorage(); + + forceDeployWithoutConstructor("DummyL2InteropRootStorage", address(L2_INTEROP_ROOT_STORAGE)); + } + + function forceDeployInteropCenter(SystemContractsArgs memory _args) internal { + new InteropCenter(); + + forceDeployWithoutConstructor("InteropCenter", L2_INTEROP_CENTER_ADDR); + InteropCenter interopCenter = InteropCenter(L2_INTEROP_CENTER_ADDR); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + InteropCenter(L2_INTEROP_CENTER_ADDR).initL2(_args.l1ChainId, _args.aliasedOwner); + } + + function forceDeployInteropHandler(SystemContractsArgs memory _args) internal { + new InteropHandler(); + + forceDeployWithoutConstructor("InteropHandler", L2_INTEROP_HANDLER_ADDR); + InteropHandler interopHandler = InteropHandler(L2_INTEROP_HANDLER_ADDR); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + interopHandler.initL2(_args.l1ChainId); + } + + function forceDeployL2AssetTracker(SystemContractsArgs memory _args) internal { + new L2AssetTracker(); + + forceDeployWithoutConstructor("L2AssetTracker", L2_ASSET_TRACKER_ADDR); + } + + function forceDeployGWAssetTracker(SystemContractsArgs memory _args) internal { + new GWAssetTracker(); + + forceDeployWithoutConstructor("GWAssetTracker", GW_ASSET_TRACKER_ADDR); + } + /// @notice Deploys the L2AssetRouter contract. function forceDeployAssetRouter(SystemContractsArgs memory _args) internal { // to ensure that the bytecode is known @@ -127,7 +193,9 @@ library L2Utils { _args.legacySharedBridge, _args.l2TokenBeacon, address(0), - ethAssetId + ethAssetId, + ETH_TOKEN_ADDRESS, + _args.l1ChainId ); } @@ -144,8 +212,9 @@ library L2Utils { value: 0, input: "" }); + console.logBytes32(bytecodehash); - vm.prank(L2_FORCE_DEPLOYER_ADDR); + prankOrBroadcast(false, L2_FORCE_DEPLOYER_ADDR); IContractDeployer(L2_DEPLOYER_SYSTEM_CONTRACT_ADDR).forceDeployOnAddresses(deployments); } @@ -168,4 +237,32 @@ library L2Utils { } return contractAddress; } + + // function getCreationCode(string memory _contractName) internal view returns (bytes memory) { + // if (keccak256(abi.encode(_contractName)) == keccak256(abi.encode("L2StandardTriggerAccount"))) { + // return + // abi.encodePacked( + // readZKFoundryBytecodeSystemContracts(string.concat(_contractName, ".sol"), _contractName) + // ); + // } else if (keccak256(abi.encode(_contractName)) == keccak256(abi.encode("InteropAccount"))) { + // return + // abi.encodePacked( + // readZKFoundryBytecodeSystemContracts(string.concat(_contractName, ".sol"), _contractName) + // ); + // } + // bytes memory bytecode = readZKFoundryBytecodeL1(string.concat(_contractName, ".sol"), _contractName); + // return bytecode; + // } + + function prankOrBroadcast(bool _broadcast, address _from) public { + if (_broadcast) { + if (_from != L2_FORCE_DEPLOYER_ADDR) { + vm.broadcast(_from); + } else { + vm.broadcast(); + } + } else { + vm.prank(_from); + } + } } diff --git a/l1-contracts/test/foundry/l2/integration/WETH.t.sol b/l1-contracts/test/foundry/l2/integration/WETH.t.sol index ad4119eefa..4bedeb9b7f 100644 --- a/l1-contracts/test/foundry/l2/integration/WETH.t.sol +++ b/l1-contracts/test/foundry/l2/integration/WETH.t.sol @@ -4,8 +4,6 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; -import {DeployUtils} from "deploy-scripts/DeployUtils.s.sol"; - import {DeployIntegrationUtils} from "../../l1/integration/deploy-scripts/DeployIntegrationUtils.s.sol"; import {SharedL2ContractDeployer} from "../../l1/integration/l2-tests-abstract/_SharedL2ContractDeployer.sol"; diff --git a/l1-contracts/test/foundry/l2/integration/_SharedL2ContractL2Deployer.sol b/l1-contracts/test/foundry/l2/integration/_SharedL2ContractL2Deployer.sol index c1195be3eb..54fa2fa36e 100644 --- a/l1-contracts/test/foundry/l2/integration/_SharedL2ContractL2Deployer.sol +++ b/l1-contracts/test/foundry/l2/integration/_SharedL2ContractL2Deployer.sol @@ -4,7 +4,8 @@ pragma solidity ^0.8.24; import {Test, stdToml} from "forge-std/Test.sol"; import {Script, console2 as console} from "forge-std/Script.sol"; -import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {L2_ASSET_ROUTER_ADDR, L2_BRIDGEHUB_ADDR, L2_INTEROP_CENTER_ADDR, L2_NATIVE_TOKEN_VAULT_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; +import {CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "contracts/common/Config.sol"; import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {L2Utils} from "./L2Utils.sol"; @@ -37,7 +38,8 @@ contract SharedL2ContractL2Deployer is SharedL2ContractDeployer { L2Utils.initSystemContracts(_args); } - // note this is duplicate code, but the inheritance is already complex + /// @notice this is duplicate code, but the inheritance is already complex + /// here we have to deploy contracts manually with new Contract(), because that can be handled by the compiler. function deployL2Contracts(uint256 _l1ChainId) public virtual override { string memory root = vm.projectRoot(); string memory inputPath = string.concat( @@ -45,10 +47,7 @@ contract SharedL2ContractL2Deployer is SharedL2ContractDeployer { "/test/foundry/l1/integration/deploy-scripts/script-config/config-deploy-l1.toml" ); initializeConfig(inputPath); - addresses.transparentProxyAdmin = makeAddr("transparentProxyAdmin"); - addresses.bridgehub.bridgehubProxy = L2_BRIDGEHUB_ADDR; - addresses.bridges.l1AssetRouterProxy = L2_ASSET_ROUTER_ADDR; - addresses.vaults.l1NativeTokenVaultProxy = L2_NATIVE_TOKEN_VAULT_ADDR; + addresses.transparentProxyAdmin = address(0x1); config.l1ChainId = _l1ChainId; console.log("Deploying L2 contracts"); instantiateCreate2Factory(); @@ -66,21 +65,35 @@ contract SharedL2ContractL2Deployer is SharedL2ContractDeployer { ); addresses.stateTransition.executorFacet = address(new ExecutorFacet(config.l1ChainId)); addresses.stateTransition.adminFacet = address( - new AdminFacet(config.l1ChainId, RollupDAManager(addresses.daAddresses.rollupDAManager)) + new AdminFacet( + config.l1ChainId, + RollupDAManager(addresses.daAddresses.rollupDAManager), + CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, + CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ) ); addresses.stateTransition.mailboxFacet = address( - new MailboxFacet(config.eraChainId, config.l1ChainId, IEIP7702Checker(address(0))) + new MailboxFacet( + config.eraChainId, + config.l1ChainId, + L2_CHAIN_ASSET_HANDLER_ADDR, + IEIP7702Checker(address(0)), + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ) ); addresses.stateTransition.gettersFacet = address(new GettersFacet()); addresses.stateTransition.diamondInit = address(new DiamondInit(false)); // Deploy ChainTypeManager implementation if (config.isZKsyncOS) { addresses.stateTransition.chainTypeManagerImplementation = address( - new ZKsyncOSChainTypeManager(addresses.bridgehub.bridgehubProxy) + new ZKsyncOSChainTypeManager(L2_BRIDGEHUB_ADDR, L2_INTEROP_CENTER_ADDR) ); } else { addresses.stateTransition.chainTypeManagerImplementation = address( - new EraChainTypeManager(addresses.bridgehub.bridgehubProxy) + new EraChainTypeManager(L2_BRIDGEHUB_ADDR, L2_INTEROP_CENTER_ADDR) ); } @@ -109,28 +122,4 @@ contract SharedL2ContractL2Deployer is SharedL2ContractDeployer { // add this to be excluded from coverage report function test() internal virtual override {} - - function getCreationCode( - string memory contractName, - bool isZKBytecode - ) internal view virtual override returns (bytes memory) { - revert("Not implemented"); - } - - function getInitializeCalldata( - string memory contractName, - bool isZKBytecode - ) internal virtual override returns (bytes memory) { - return ("Not implemented initialize calldata"); - } - - function deployTuppWithContract( - string memory contractName, - bool isZKBytecode - ) internal virtual override returns (address implementation, address proxy) { - revert("Not implemented tupp"); - } - - // function getCreationCalldata(string memory contractName) internal view virtual override returns (bytes memory) { - // } } diff --git a/l1-contracts/test/foundry/l2/unit/GatewayCTMDeployer/GatewayCTMDeployer.t.sol b/l1-contracts/test/foundry/l2/unit/GatewayCTMDeployer/GatewayCTMDeployer.t.sol index 3d08210011..1e8cb14d6c 100644 --- a/l1-contracts/test/foundry/l2/unit/GatewayCTMDeployer/GatewayCTMDeployer.t.sol +++ b/l1-contracts/test/foundry/l2/unit/GatewayCTMDeployer/GatewayCTMDeployer.t.sol @@ -8,6 +8,7 @@ import {console2 as console} from "forge-std/Script.sol"; import {DAContracts, DeployedContracts, GatewayCTMDeployer, GatewayCTMDeployerConfig, StateTransitionContracts} from "contracts/state-transition/chain-deps/GatewayCTMDeployer.sol"; import {VerifierParams} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; import {IEIP7702Checker} from "contracts/state-transition/chain-interfaces/IEIP7702Checker.sol"; +import {CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET} from "contracts/common/Config.sol"; import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-deps/ZKChainStorage.sol"; import {ServerNotifier} from "contracts/governance/ServerNotifier.sol"; @@ -35,8 +36,7 @@ import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {ZKsyncOSChainTypeManager} from "contracts/state-transition/ZKsyncOSChainTypeManager.sol"; import {EraChainTypeManager} from "contracts/state-transition/EraChainTypeManager.sol"; -import {L2_BRIDGEHUB_ADDR, L2_CREATE2_FACTORY_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; -import {L2DACommitmentScheme} from "contracts/common/Config.sol"; +import {L2_BRIDGEHUB_ADDR, L2_CREATE2_FACTORY_ADDR, L2_CHAIN_ASSET_HANDLER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; @@ -63,18 +63,32 @@ contract GatewayCTMDeployerTest is Test { // This is done merely to publish the respective bytecodes. function _predeployContracts() internal { - new MailboxFacet(1, 1, IEIP7702Checker(address(0))); + new MailboxFacet( + 1, + 1, + L2_CHAIN_ASSET_HANDLER_ADDR, + IEIP7702Checker(address(0)), + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ); new ExecutorFacet(1); new GettersFacet(); - new AdminFacet(1, RollupDAManager(address(0))); + new AdminFacet( + 1, + RollupDAManager(address(0)), + CHAIN_MIGRATION_TIME_WINDOW_START_TESTNET, + CHAIN_MIGRATION_TIME_WINDOW_END_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_START_TESTNET, + PAUSE_DEPOSITS_TIME_WINDOW_END_TESTNET + ); new DiamondInit(false); new L1GenesisUpgrade(); new RollupDAManager(); new ValidiumL1DAValidator(); new RelayedSLDAValidator(); - new ZKsyncOSChainTypeManager(address(0)); - new EraChainTypeManager(address(0)); + new ZKsyncOSChainTypeManager(address(0), address(0)); + new EraChainTypeManager(address(0), address(0)); new ProxyAdmin(); new EraVerifierFflonk(); diff --git a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol index 9a4b569cbb..b3e82cab40 100644 --- a/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/chain-registrator/ChainRegistrar.t.sol @@ -7,7 +7,10 @@ import {DummyChainTypeManagerWBH} from "contracts/dev-contracts/test/DummyChainT import {IVerifier, VerifierParams} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; import {IEIP7702Checker} from "contracts/state-transition/chain-interfaces/IEIP7702Checker.sol"; +import {InteropCenter} from "contracts/interop/InteropCenter.sol"; +import {L1MessageRoot} from "contracts/bridgehub/L1MessageRoot.sol"; import "contracts/bridgehub/L1Bridgehub.sol"; +import {IBridgehubBase} from "contracts/bridgehub/IBridgehubBase.sol"; import "contracts/chain-registrar/ChainRegistrar.sol"; import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-deps/ZKChainStorage.sol"; import {InitializeDataNewChain as DiamondInitializeDataNewChain} from "contracts/state-transition/chain-interfaces/IDiamondInit.sol"; @@ -22,12 +25,15 @@ import {TestnetERC20Token} from "contracts/dev-contracts/TestnetERC20Token.sol"; import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {L1Nullifier} from "contracts/bridge/L1Nullifier.sol"; +import {L2_COMPLEX_UPGRADER_ADDR} from "contracts/common/l2-helpers/L2ContractAddresses.sol"; import {L1NullifierDev} from "contracts/dev-contracts/L1NullifierDev.sol"; import {Utils} from "foundry-test/l1/unit/concrete/Utils/Utils.sol"; contract ChainRegistrarTest is Test { DummyBridgehub private bridgeHub; + InteropCenter private interopCenter; + L1MessageRoot private messageRoot; DummyChainTypeManagerWBH private ctm; address private admin; address private deployer; @@ -41,6 +47,10 @@ contract ChainRegistrarTest is Test { constructor() { bridgeHub = new DummyBridgehub(); + interopCenter = new InteropCenter(); + vm.prank(L2_COMPLEX_UPGRADER_ADDR); + interopCenter.initL2(block.chainid, makeAddr("admin")); + messageRoot = new L1MessageRoot(address(bridgeHub), 1); ctm = new DummyChainTypeManagerWBH(address(bridgeHub)); admin = makeAddr("admin"); deployer = makeAddr("deployer"); @@ -48,6 +58,8 @@ contract ChainRegistrarTest is Test { l1NullifierImpl = new L1NullifierDev({ _bridgehub: IL1Bridgehub(address(bridgeHub)), + _messageRoot: IMessageRoot(address(messageRoot)), + _interopCenter: (interopCenter), _eraChainId: 270, _eraDiamondProxy: makeAddr("era") }); @@ -254,7 +266,7 @@ contract ChainRegistrarTest is Test { function registerChainAndVerify(address author, uint256 chainId) internal { IEIP7702Checker eip7702Checker = IEIP7702Checker(Utils.deployEIP7702Checker()); - DummyZKChain zkChain = new DummyZKChain(address(bridgeHub), 270, 6, eip7702Checker); + DummyZKChain zkChain = new DummyZKChain(address(bridgeHub), 270, 6, address(0), eip7702Checker); vm.prank(admin); ctm.setZKChain(1, address(zkChain)); vm.prank(admin); diff --git a/l1-contracts/test/invariant/l1-context/AssetRouterTest.t.sol b/l1-contracts/test/invariant/l1-context/AssetRouterTest.t.sol index 5928556fea..acb226d3af 100644 --- a/l1-contracts/test/invariant/l1-context/AssetRouterTest.t.sol +++ b/l1-contracts/test/invariant/l1-context/AssetRouterTest.t.sol @@ -4,12 +4,10 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; -import {DeployUtils} from "deploy-scripts/DeployUtils.s.sol"; - import {AssetRouter_ActorHandler_Deployer} from "../deployers/AssetRouter_ActorHandler_Deployer.sol"; import {AssetRouterProperties} from "../properties/AssetRouterProperties.sol"; -import {SharedL2ContractL1Deployer, SystemContractsArgs} from "../../foundry/l1/integration/l2-tests-abstract/_SharedL2ContractL1Deployer.sol"; +import {SharedL2ContractL1Deployer, SystemContractsArgs} from "../../foundry/l1/integration/l2-tests-in-l1-context/_SharedL2ContractL1Deployer.sol"; import {SharedL2ContractDeployer} from "../../foundry/l1/integration/l2-tests-abstract/_SharedL2ContractDeployer.sol"; contract AssetRouterTest is @@ -19,8 +17,6 @@ contract AssetRouterTest is AssetRouterProperties, AssetRouter_ActorHandler_Deployer { - function test() internal virtual override(DeployUtils, SharedL2ContractL1Deployer) {} - function initSystemContracts( SystemContractsArgs memory _args ) internal virtual override(SharedL2ContractDeployer, SharedL2ContractL1Deployer) { diff --git a/l1-contracts/test/invariant/l2-context/AssetRouterTest.t.sol b/l1-contracts/test/invariant/l2-context/AssetRouterTest.t.sol index c1d16f9ab1..a7f025807f 100644 --- a/l1-contracts/test/invariant/l2-context/AssetRouterTest.t.sol +++ b/l1-contracts/test/invariant/l2-context/AssetRouterTest.t.sol @@ -4,13 +4,11 @@ pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; -import {DeployUtils} from "deploy-scripts/DeployUtils.s.sol"; - import {AssetRouter_ActorHandler_Deployer} from "../deployers/AssetRouter_ActorHandler_Deployer.sol"; import {AssetRouterProperties} from "../properties/AssetRouterProperties.sol"; import {SharedL2ContractL2Deployer, SystemContractsArgs} from "../../foundry/l2/integration/_SharedL2ContractL2Deployer.sol"; -import {SharedL2ContractL1Deployer} from "../../foundry/l1/integration/l2-tests-abstract/_SharedL2ContractL1Deployer.sol"; +import {SharedL2ContractL1Deployer} from "../../foundry/l1/integration/l2-tests-in-l1-context/_SharedL2ContractL1Deployer.sol"; import {SharedL2ContractDeployer} from "../../foundry/l1/integration/l2-tests-abstract/_SharedL2ContractDeployer.sol"; contract AssetRouterTest is @@ -20,21 +18,12 @@ contract AssetRouterTest is AssetRouterProperties, AssetRouter_ActorHandler_Deployer { - function test() internal virtual override(DeployUtils, SharedL2ContractL2Deployer) {} - function initSystemContracts( SystemContractsArgs memory _args ) internal virtual override(SharedL2ContractDeployer, SharedL2ContractL2Deployer) { super.initSystemContracts(_args); } - function deployViaCreate2( - bytes memory creationCode, - bytes memory constructorArgs - ) internal override(DeployUtils, SharedL2ContractL2Deployer) returns (address) { - return super.deployViaCreate2(creationCode, constructorArgs); - } - function deployL2Contracts( uint256 _l1ChainId ) public virtual override(SharedL2ContractDeployer, SharedL2ContractL1Deployer) { diff --git a/l1-contracts/test/unit_tests/custom_base_token.spec.ts b/l1-contracts/test/unit_tests/custom_base_token.spec.ts index 2fc87d1999..1658c72b6f 100644 --- a/l1-contracts/test/unit_tests/custom_base_token.spec.ts +++ b/l1-contracts/test/unit_tests/custom_base_token.spec.ts @@ -13,7 +13,7 @@ import { IL1NativeTokenVaultFactory } from "../../typechain/IL1NativeTokenVaultF import { getTokens } from "../../src.ts/deploy-token"; import type { Deployer } from "../../src.ts/deploy"; -import { ethTestConfig } from "../../src.ts/utils"; +import { ethTestConfig } from "../../src.ts/constants"; import { initialTestnetDeploymentProcess } from "../../src.ts/deploy-test-process"; import { getCallRevertReason, REQUIRED_L2_GAS_PRICE_PER_PUBDATA } from "./utils"; diff --git a/l1-contracts/test/unit_tests/gateway.spec.ts b/l1-contracts/test/unit_tests/gateway.spec.ts index 92ccb18c78..bef999e184 100644 --- a/l1-contracts/test/unit_tests/gateway.spec.ts +++ b/l1-contracts/test/unit_tests/gateway.spec.ts @@ -11,12 +11,8 @@ import { defaultDeployerForTests, registerZKChainWithBridgeRegistration, } from "../../src.ts/deploy-test-process"; -import { - ethTestConfig, - REQUIRED_L2_GAS_PRICE_PER_PUBDATA, - priorityTxMaxGasLimit, - L2_BRIDGEHUB_ADDRESS, -} from "../../src.ts/utils"; +import { ethTestConfig, REQUIRED_L2_GAS_PRICE_PER_PUBDATA, L2_BRIDGEHUB_ADDRESS } from "../../src.ts/constants"; +import { priorityTxMaxGasLimit } from "../../src.ts/utils"; import { SYSTEM_CONFIG } from "../../scripts/utils"; import type { Deployer } from "../../src.ts/deploy"; diff --git a/l1-contracts/test/unit_tests/initial_deployment_test.spec.ts b/l1-contracts/test/unit_tests/initial_deployment_test.spec.ts index f5b417ff57..2668a54344 100644 --- a/l1-contracts/test/unit_tests/initial_deployment_test.spec.ts +++ b/l1-contracts/test/unit_tests/initial_deployment_test.spec.ts @@ -13,7 +13,7 @@ import { } from "../../typechain"; import { initialTestnetDeploymentProcess } from "../../src.ts/deploy-test-process"; -import { ethTestConfig } from "../../src.ts/utils"; +import { ethTestConfig } from "../../src.ts/constants"; import type { Deployer } from "../../src.ts/deploy"; import { registerZKChain } from "../../src.ts/deploy-process"; diff --git a/l1-contracts/test/unit_tests/l1_shared_bridge_test.spec.ts b/l1-contracts/test/unit_tests/l1_shared_bridge_test.spec.ts index e1e17128b3..210a5629d7 100644 --- a/l1-contracts/test/unit_tests/l1_shared_bridge_test.spec.ts +++ b/l1-contracts/test/unit_tests/l1_shared_bridge_test.spec.ts @@ -12,7 +12,7 @@ import { L1NativeTokenVaultFactory } from "../../typechain/L1NativeTokenVaultFac import { getTokens } from "../../src.ts/deploy-token"; import { Action, facetCut } from "../../src.ts/diamondCut"; -import { ethTestConfig } from "../../src.ts/utils"; +import { ethTestConfig } from "../../src.ts/constants"; import type { Deployer } from "../../src.ts/deploy"; import { initialTestnetDeploymentProcess } from "../../src.ts/deploy-test-process"; diff --git a/l1-contracts/test/unit_tests/l2-upgrade.test.spec.ts b/l1-contracts/test/unit_tests/l2-upgrade.test.spec.ts index ad7c1ccb4e..55640f0813 100644 --- a/l1-contracts/test/unit_tests/l2-upgrade.test.spec.ts +++ b/l1-contracts/test/unit_tests/l2-upgrade.test.spec.ts @@ -22,7 +22,8 @@ import { L2_BOOTLOADER_BYTECODE_HASH, L2_DEFAULT_ACCOUNT_BYTECODE_HASH } from ". import { initialTestnetDeploymentProcess } from "../../src.ts/deploy-test-process"; import type { ProposedUpgrade, VerifierParams } from "../../src.ts/utils"; -import { ethTestConfig, EMPTY_STRING_KECCAK } from "../../src.ts/utils"; +import { ethTestConfig, EMPTY_STRING_KECCAK } from "../../src.ts/constants"; + import { diamondCut, Action, facetCut } from "../../src.ts/diamondCut"; import type { CommitBatchInfo, StoredBatchInfo, CommitBatchInfoWithTimestamp } from "./utils"; @@ -41,7 +42,7 @@ import { makeExecutedEqualCommitted, getBatchStoredInfo, buildL2DARollupPubdataCommitment, - L2_TO_L1_MESSENGER, + L2_TO_L1_MESSENGER_SYSTEM_CONTRACT, } from "./utils"; import { packSemver, unpackStringSemVer, addToProtocolVersion } from "../../scripts/utils"; @@ -921,7 +922,7 @@ async function buildCommitBatchInfoWithCustomLogs( ); systemLogs[SYSTEM_LOG_KEYS.L2_DA_VALIDATOR_OUTPUT_HASH_KEY] = constructL2Log( true, - L2_TO_L1_MESSENGER, + L2_TO_L1_MESSENGER_SYSTEM_CONTRACT, SYSTEM_LOG_KEYS.L2_DA_VALIDATOR_OUTPUT_HASH_KEY, l1DAOutputHash ); diff --git a/l1-contracts/test/unit_tests/legacy_era_test.spec.ts b/l1-contracts/test/unit_tests/legacy_era_test.spec.ts index 5a0d6e9954..5777a4b8b4 100644 --- a/l1-contracts/test/unit_tests/legacy_era_test.spec.ts +++ b/l1-contracts/test/unit_tests/legacy_era_test.spec.ts @@ -17,7 +17,7 @@ import type { IL1ERC20Bridge } from "../../typechain/IL1ERC20Bridge"; import { IL1ERC20BridgeFactory } from "../../typechain/IL1ERC20BridgeFactory"; import type { IMailbox } from "../../typechain/IMailbox"; -import { ethTestConfig } from "../../src.ts/utils"; +import { ethTestConfig } from "../../src.ts/constants"; import { Action, facetCut } from "../../src.ts/diamondCut"; import { getTokens } from "../../src.ts/deploy-token"; import type { Deployer } from "../../src.ts/deploy"; diff --git a/l1-contracts/test/unit_tests/mailbox_test.spec.ts b/l1-contracts/test/unit_tests/mailbox_test.spec.ts index c78cc646d9..0948db3c37 100644 --- a/l1-contracts/test/unit_tests/mailbox_test.spec.ts +++ b/l1-contracts/test/unit_tests/mailbox_test.spec.ts @@ -13,7 +13,9 @@ import { } from "../../typechain"; import type { IMailbox } from "../../typechain/IMailbox"; -import { PubdataPricingMode, ethTestConfig } from "../../src.ts/utils"; +import { PubdataPricingMode } from "../../src.ts/utils"; +import { ethTestConfig } from "../../src.ts/constants"; + import { initialTestnetDeploymentProcess } from "../../src.ts/deploy-test-process"; import { Action, facetCut } from "../../src.ts/diamondCut"; diff --git a/l1-contracts/test/unit_tests/proxy_test.spec.ts b/l1-contracts/test/unit_tests/proxy_test.spec.ts index 5e3fc23d8c..ba443be061 100644 --- a/l1-contracts/test/unit_tests/proxy_test.spec.ts +++ b/l1-contracts/test/unit_tests/proxy_test.spec.ts @@ -93,7 +93,7 @@ describe("Diamond proxy tests", function () { admin: governorAddress, validatorTimelock: governorAddress, baseTokenAssetId: "0x0000000000000000000000000000000000000000000000000000000000000001", - baseTokenBridge: "0x0000000000000000000000000000000000000001", + interopCenter: "0x0000000000000000000000000000000000000001", storedBatchZero: "0x02c775f0a90abf7a0e8043f2fdc38f0580ca9f9996a895d05a501bfeaa3b2e21", verifier: "0x0000000000000000000000000000000000000001", verifierParams: dummyVerifierParams, diff --git a/l1-contracts/test/unit_tests/utils.ts b/l1-contracts/test/unit_tests/utils.ts index 1114ed5f4e..9a2813b4b7 100644 --- a/l1-contracts/test/unit_tests/utils.ts +++ b/l1-contracts/test/unit_tests/utils.ts @@ -10,14 +10,15 @@ import type { IMailbox } from "../../typechain/IMailbox"; import type { ExecutorFacet } from "../../typechain"; import type { FeeParams, L2CanonicalTransaction } from "../../src.ts/utils"; +import { PubdataPricingMode } from "../../src.ts/utils"; import { ADDRESS_ONE, - PubdataPricingMode, EMPTY_STRING_KECCAK, STORED_BATCH_INFO_ABI_STRING, COMMIT_BATCH_INFO_ABI_STRING, PRIORITY_OPS_BATCH_INFO_ABI_STRING, -} from "../../src.ts/utils"; +} from "../../src.ts/constants"; + import { packSemver } from "../../scripts/utils"; import { keccak256, hexConcat, defaultAbiCoder } from "ethers/lib/utils"; diff --git a/l1-contracts/upgrade-envs/v0.29.2-interopA-ff/mainnet-gateway.toml b/l1-contracts/upgrade-envs/v0.29.2-interopA-ff/mainnet-gateway.toml new file mode 100644 index 0000000000..f56afa826a --- /dev/null +++ b/l1-contracts/upgrade-envs/v0.29.2-interopA-ff/mainnet-gateway.toml @@ -0,0 +1,5 @@ +[chain] +chain_id = 9075 + +[contracts] +bridgehub_proxy_address = "0x303a465B659cBB0ab36eE643eA362c509EEb5213" diff --git a/l2-contracts/contracts/L2ContractHelper.sol b/l2-contracts/contracts/L2ContractHelper.sol index 8b8d639742..5816ef98d3 100644 --- a/l2-contracts/contracts/L2ContractHelper.sol +++ b/l2-contracts/contracts/L2ContractHelper.sol @@ -77,8 +77,6 @@ address constant DEPLOYER_SYSTEM_CONTRACT = address(SYSTEM_CONTRACTS_OFFSET + 0x address constant L2_BRIDGEHUB_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x02); -uint256 constant L1_CHAIN_ID = 1; - IL1Messenger constant L2_MESSENGER = IL1Messenger(address(SYSTEM_CONTRACTS_OFFSET + 0x08)); IBaseToken constant L2_BASE_TOKEN_ADDRESS = IBaseToken(address(SYSTEM_CONTRACTS_OFFSET + 0x0a)); diff --git a/l2-contracts/foundry.toml b/l2-contracts/foundry.toml index 6a5484b56a..aa4cb00095 100644 --- a/l2-contracts/foundry.toml +++ b/l2-contracts/foundry.toml @@ -22,6 +22,6 @@ fs_permissions = [ { access = "read", path = "../system-contracts/artifacts-zk/contracts-preprocessed" } ] -[profile.default.zksync] +[profile.default.zksync] enable_eravm_extensions = true zksolc = "1.5.11" diff --git a/l2-contracts/src/publish-bridge-preimages.ts b/l2-contracts/src/publish-bridge-preimages.ts index efde2f1c6f..3a1f9feb04 100644 --- a/l2-contracts/src/publish-bridge-preimages.ts +++ b/l2-contracts/src/publish-bridge-preimages.ts @@ -38,9 +38,9 @@ async function main() { console.log(`Using gas price: ${gasPrice}`); const deployer = new Deployer({ deployWallet: wallet }); - const bridgehub = deployer.bridgehubContract(wallet); + const interopCenter = deployer.interopCenter(wallet); - const publishL2SharedBridgeTx = await bridgehub.requestL2TransactionDirect( + const publishL2SharedBridgeTx = await interopCenter.requestL2TransactionDirect( { chainId, l2Contract: ethers.constants.AddressZero, diff --git a/l2-contracts/src/utils.ts b/l2-contracts/src/utils.ts index fc89ba668d..656ba64af0 100644 --- a/l2-contracts/src/utils.ts +++ b/l2-contracts/src/utils.ts @@ -3,7 +3,8 @@ import { artifacts } from "hardhat"; import { Interface } from "ethers/lib/utils"; import { deployedAddressesFromEnv } from "../../l1-contracts/src.ts/deploy-utils"; import type { Deployer } from "../../l1-contracts/src.ts/deploy"; -import { ADDRESS_ONE, getNumberFromEnv } from "../../l1-contracts/src.ts/utils"; +import { ADDRESS_ONE } from "../../l1-contracts/src.ts/constants"; +import { getNumberFromEnv } from "../../l1-contracts/src.ts/utils"; import { IBridgehubFactory } from "../../l1-contracts/typechain/IBridgehubFactory"; import { web3Provider } from "../../l1-contracts/scripts/utils"; @@ -136,7 +137,7 @@ export async function requestL2TransactionDirect( const ntv = IL1NativeTokenVaultFactory.connect(deployedAddresses.Bridges.NativeTokenVaultProxy, wallet); gasPrice ??= await bridgehub.provider.getGasPrice(); - const expectedCost = await bridgehub.l2TransactionBaseCost( + const expectedCost = await interopCenter.l2TransactionBaseCost( chainId, gasPrice, l2GasLimit, @@ -153,7 +154,7 @@ export async function requestL2TransactionDirect( const tx = await baseToken.approve(baseTokenBridge, expectedCost); await tx.wait(); } - return await bridgehub.requestL2TransactionDirect( + return await interopCenter.requestL2TransactionDirect( { chainId, l2Contract: l2Contract, diff --git a/system-contracts/README.md b/system-contracts/README.md index cd43f8fe37..4384fff8ce 100644 --- a/system-contracts/README.md +++ b/system-contracts/README.md @@ -135,7 +135,7 @@ Many examples can be found in [test](test). #### Manual tests -Manual tests are not part of the main test suite and are rather run manually against an anvil-zksync fork of the chain to be upgraded. Currently there is only one manual test for the [L2V29Upgrade](contracts/L2V29Upgrade.sol) that can be run by doing: +Manual tests are not part of the main test suite and are rather run manually against an anvil-zksync fork of the chain to be upgraded. Currently there is only one manual test for the [L2V29Upgrade](contracts/upgrades/L2V29Upgrade.sol) that can be run by doing: ``` ./bin/anvil-zksync fork --fork-url [chain-rpc-url] &> era_test_node.log.anvil & diff --git a/system-contracts/bootloader/bootloader.yul b/system-contracts/bootloader/bootloader.yul index 238f70b4d7..99dc7c9931 100644 --- a/system-contracts/bootloader/bootloader.yul +++ b/system-contracts/bootloader/bootloader.yul @@ -435,6 +435,18 @@ object "Bootloader" { ret := mul(INTEROP_ROOT_ROLLING_HASH_SLOT(), 32) } + function SETTLEMENT_LAYER_CHAIN_ID_SLOT() -> ret { + ret := add(INTEROP_ROOT_ROLLING_HASH_SLOT(), 1) + } + + function SETTLEMENT_LAYER_CHAIN_ID_BYTE() -> ret { + ret := mul(SETTLEMENT_LAYER_CHAIN_ID_SLOT(), 32) + } + + function getSettlementLayerChainId() -> ret { + ret := mload(SETTLEMENT_LAYER_CHAIN_ID_BYTE()) + } + /// @dev The slot starting from which the compressed bytecodes are located in the bootloader's memory. /// Each compressed bytecode is provided in the following format: /// - 32 byte formatted bytecode hash @@ -446,7 +458,7 @@ object "Bootloader" { /// At the start of the bootloader, the value stored at the `TX_OPERATOR_TRUSTED_GAS_LIMIT_BEGIN_SLOT` is equal to /// `TX_OPERATOR_TRUSTED_GAS_LIMIT_BEGIN_SLOT + 32`, where the hash of the first compressed bytecode to publish should be stored. function COMPRESSED_BYTECODES_BEGIN_SLOT() -> ret { - ret := add(INTEROP_ROOT_ROLLING_HASH_SLOT(), 1) + ret := add(SETTLEMENT_LAYER_CHAIN_ID_SLOT(), 1) } /// @dev The byte starting from which the compressed bytecodes are located in the bootloader's memory. @@ -664,6 +676,10 @@ object "Bootloader" { ret := 0x0000000000000000000000000000000000010008 } + function L2_INTEROP_CENTER_ADDR() -> ret { + ret := 0x000000000000000000000000000000000001000b + } + /// @dev The minimal allowed distance in bytes between the pointer to the compressed data /// and the end of the area dedicated for the compressed bytecodes. /// In fact, only distance of 192 should be sufficient: there it would be possible to insert @@ -844,7 +860,7 @@ object "Bootloader" { // (`assertSuccess` = true), then we should panic. if iszero(success) { if assertSuccess { - // The call must've succeeded, but it didn't. So we revert the bootloader. + // The call must have succeeded, but it didn't. So we revert the bootloader. assertionError("getRawCodeHash failed") } @@ -1204,10 +1220,10 @@ object "Bootloader" { debugLog("Send message to L1", success) - // Sending the L2->L1 log so users will be able to prove transaction execution result on L1. - sendL2LogUsingL1Messenger(true, canonicalL1TxHash, success) - if isPriorityOp { + // Sending the L2->L1 log so users will be able to prove transaction execution result on L1. + sendL2LogUsingL1Messenger(true, canonicalL1TxHash, success) + // Update priority txs L1 data mstore(0, mload(PRIORITY_TXS_L1_DATA_BEGIN_BYTE())) mstore(32, canonicalL1TxHash) @@ -1725,6 +1741,25 @@ object "Bootloader" { ret := mload(0) } + function getCodeSize(address) -> ret { + mstore(0, {{GET_CODE_SIZE_SELECTOR}}) + mstore(4, address) + let success := call( + gas(), + KNOWN_CODES_CONTRACT_ADDR(), + 0, + 0, + 36, + 0, + 32 + ) + + if iszero(success) { + nearCallPanic() + } + + ret := mload(0) + } /// @dev Used to refund the current transaction. /// @param txDataOffset The offset to the ABI-encoded Transaction struct. @@ -3055,6 +3090,38 @@ object "Bootloader" { } } + function setSettlementLayerChainId(currentSettlementLayerChainId) { + mstore(0, {{RIGHT_PADDED_SET_SETTLEMENT_LAYER_CHAIN_ID_SELECTOR}}) + mstore(4, currentSettlementLayerChainId) + + debugLog("Setting settlement layer chain id: ", currentSettlementLayerChainId) + + let success := call( + gas(), + SYSTEM_CONTEXT_ADDR(), + 0, + 0, + 36, + 0, + 0 + ) + + if iszero(success) { + debugLog("Failed to set new settlement layer chain id: ", currentSettlementLayerChainId) + + /// here during the upgrade the setting of the settlement layer chain will fail, as the system context is not yet upgraded. + /// todo remove after v30 upgrade. + /// We want to check if the interop center is deployed or not, i.e. did we execute V30 upgrade. + let codeSize := getCodeSize(L2_INTEROP_CENTER_ADDR()) + debugLog("codeSize", codeSize) + /// nothing is deployed at this address. + let codeSize2 := getCodeSize(add(L2_INTEROP_ROOT_STORAGE(), 10)) + if iszero(eq(codeSize, codeSize2)) { + revertWithReason(FAILED_TO_SET_NEW_SETTLEMENT_LAYER_CHAIN_ID_ERR_CODE(), 1) + } + } + } + /// @notice Sets the context information for the current L2 block. /// @param txId The index of the transaction in the batch for which to get the L2 block information. function setL2Block(txId) { @@ -3457,6 +3524,7 @@ object "Bootloader" { let from := getFrom(innerTxDataOffset) let iseoa := isEOA(from) + assertEq(iseoa, true, "Only EIP-712 can use non-EOA") @@ -3467,7 +3535,9 @@ object "Bootloader" { assertEq(getPaymaster(innerTxDataOffset), 0, "paymaster non zero") + assertEq(gt(getFrom(innerTxDataOffset), MAX_SYSTEM_CONTRACT_ADDR()), 1, "from in kernel space") + // reserved1 used as marker that tx doesn't have field "to" @@ -3485,16 +3555,21 @@ object "Bootloader" { let from := getFrom(innerTxDataOffset) let iseoa := isEOA(from) + assertEq(iseoa, true, "Only EIP-712 can use non-EOA") + assertEq(lte(getGasPerPubdataByteLimit(innerTxDataOffset), MAX_L2_GAS_PER_PUBDATA()), 1, "Gas per pubdata is wrong") assertEq(getPaymaster(innerTxDataOffset), 0, "paymaster non zero") + assertEq(gt(getFrom(innerTxDataOffset), MAX_SYSTEM_CONTRACT_ADDR()), 1, "from in kernel space") + + assertEq(getReserved0(innerTxDataOffset), 0, "reserved0 non zero") // reserved1 used as marker that tx doesn't have field "to" assertEq(getReserved2(innerTxDataOffset), 0, "reserved2 non zero") @@ -3510,12 +3585,16 @@ object "Bootloader" { let from := getFrom(innerTxDataOffset) let iseoa := isEOA(from) + assertEq(iseoa, true, "Only EIP-712 can use non-EOA") + + assertEq(gt(getFrom(innerTxDataOffset), MAX_SYSTEM_CONTRACT_ADDR()), 1, "from in kernel space") + assertEq(getReserved0(innerTxDataOffset), 0, "reserved0 non zero") @@ -3535,7 +3614,9 @@ object "Bootloader" { } + assertEq(gt(getFrom(innerTxDataOffset), MAX_SYSTEM_CONTRACT_ADDR()), 1, "from in kernel space") + assertEq(getReserved0(innerTxDataOffset), 0, "reserved0 non zero") // reserved1 used as marker that tx doesn't have field "to" @@ -4104,6 +4185,10 @@ object "Bootloader" { ret := 37 } + function FAILED_TO_SET_NEW_SETTLEMENT_LAYER_CHAIN_ID_ERR_CODE() -> ret { + ret := 38 + } + /// @dev Accepts a 1-word literal and returns its length in bytes /// @param str A string literal function getStrLen(str) -> len { @@ -4286,10 +4371,15 @@ object "Bootloader" { } /// @dev Log key used by Executor.sol for processing. See Constants.sol::SystemLogKey enum - function protocolUpgradeTxHashKey() -> ret { + function settlementLayerChainIdLogKey() -> ret { ret := 9 } + /// @dev Log key used by Executor.sol for processing. See Constants.sol::SystemLogKey enum + function protocolUpgradeTxHashKey() -> ret { + ret := 10 + } + //////////////////////////////////////////////////////////////////////////// // Main Transaction Processing //////////////////////////////////////////////////////////////////////////// @@ -4327,6 +4417,9 @@ object "Bootloader" { /// the operator still provides it to make sure that its data is in sync. let EXPECTED_BASE_FEE := mload(192) + /// @notice The settlement layer chain id. + let SETTLEMENT_LAYER_CHAIN_ID := getSettlementLayerChainId() + validateOperatorProvidedPrices(FAIR_L2_GAS_PRICE, FAIR_PUBDATA_PRICE) @@ -4351,6 +4444,9 @@ object "Bootloader" { setNewBatch(PREV_BATCH_HASH, NEW_BATCH_TIMESTAMP, NEW_BATCH_NUMBER, EXPECTED_BASE_FEE) + + setSettlementLayerChainId(SETTLEMENT_LAYER_CHAIN_ID) + @@ -4365,6 +4461,8 @@ object "Bootloader" { setNewBatch(PREV_BATCH_HASH, NEW_BATCH_TIMESTAMP, NEW_BATCH_NUMBER, EXPECTED_BASE_FEE) } + setSettlementLayerChainId(SETTLEMENT_LAYER_CHAIN_ID) + GAS_PRICE_PER_PUBDATA := gasPerPubdataFromBaseFee(EXPECTED_BASE_FEE, FAIR_PUBDATA_PRICE) @@ -4505,7 +4603,8 @@ object "Bootloader" { sendToL1Native(true, chainedPriorityTxnHashLogKey(), mload(PRIORITY_TXS_L1_DATA_BEGIN_BYTE())) sendToL1Native(true, numberOfLayer1TxsLogKey(), mload(add(PRIORITY_TXS_L1_DATA_BEGIN_BYTE(), 32))) sendToL1Native(true, txsStatusRollingHashKey(), mload(TXS_STATUS_ROLLING_HASH_BEGIN_BYTE())) - + sendToL1Native(true, settlementLayerChainIdLogKey(), getSettlementLayerChainId()) + // After all of the interop roots are processed, sending hash to L1. let rollingHashOfProcessedRoots := mload(INTEROP_ROOT_ROLLING_HASH_BYTE()) sendToL1Native(true, interopRootRollingHashLogKey(), rollingHashOfProcessedRoots) diff --git a/system-contracts/bootloader/test_infra/Cargo.lock b/system-contracts/bootloader/test_infra/Cargo.lock index 224a339e60..c3d6620bfd 100644 --- a/system-contracts/bootloader/test_infra/Cargo.lock +++ b/system-contracts/bootloader/test_infra/Cargo.lock @@ -15,9 +15,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] @@ -65,9 +65,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arr_macro" @@ -86,7 +86,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0609c78bd572f4edc74310dfb63a01f5609d53fa8b4dd7c4d98aef3b3e8d72d1" dependencies = [ "proc-macro-hack", - "quote 1.0.40", + "quote 1.0.41", "syn 1.0.109", ] @@ -135,7 +135,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -146,7 +146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -173,9 +173,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-config" -version = "1.8.6" +version = "1.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bc1b40fb26027769f16960d2f4a6bc20c4bb755d403e552c8c1a73af433c246" +checksum = "04b37ddf8d2e9744a0b9c19ce0b78efe4795339a90b66b7bae77987092cd2e69" dependencies = [ "aws-credential-types", "aws-runtime", @@ -198,9 +198,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.6" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d025db5d9f52cbc413b167136afb3d8aeea708c0d8884783cf6253be5e22f6f2" +checksum = "799a1290207254984cb7c05245111bc77958b92a3c9bb449598044b36341cce6" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -233,9 +233,9 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.5.10" +version = "1.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c034a1bc1d70e16e7f4e4caf7e9f7693e4c9c24cd91cf17c2a0b21abaebc7c8b" +checksum = "2e1ed337dabcf765ad5f2fb426f13af22d576328aaf09eac8f70953530798ec0" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -258,9 +258,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.105.0" +version = "1.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c99789e929b5e1d9a5aa3fa1d81317f3a789afc796141d11b0eaafd9d9f47e38" +checksum = "adb9118b3454ba89b30df55931a1fa7605260fc648e070b5aab402c24b375b1f" dependencies = [ "aws-credential-types", "aws-runtime", @@ -292,9 +292,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.85.0" +version = "1.87.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410309ad0df4606bc721aff0d89c3407682845453247213a0ccc5ff8801ee107" +checksum = "5871bec9a79a3e8d928c7788d654f135dde0e71d2dd98089388bab36b37ef607" dependencies = [ "aws-credential-types", "aws-runtime", @@ -406,9 +406,9 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147e8eea63a40315d704b97bf9bc9b8c1402ae94f89d5ad6f7550d963309da1b" +checksum = "734b4282fbb7372923ac339cc2222530f8180d9d4745e582de19a18cee409fd8" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -425,11 +425,11 @@ dependencies = [ "hyper-util", "pin-project-lite", "rustls 0.21.12", - "rustls 0.23.31", + "rustls 0.23.32", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower", "tracing", ] @@ -464,9 +464,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3946acbe1ead1301ba6862e712c7903ca9bb230bdf1fbd1b5ac54158ef2ab1f" +checksum = "4fa63ad37685ceb7762fa4d73d06f1d5493feb88e3f27259b9ed277f4c01b185" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -566,9 +566,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.75" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -576,7 +576,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link 0.2.0", ] [[package]] @@ -667,7 +667,7 @@ dependencies = [ "peeking_take_while", "prettyplease", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "regex", "rustc-hash 1.1.0", "shlex", @@ -687,7 +687,7 @@ dependencies = [ "log", "prettyplease", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "regex", "rustc-hash 2.1.1", "shlex", @@ -808,9 +808,9 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "blst" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fd49896f12ac9b6dcd7a5998466b9b58263a695a3dd1ecc1aaca2e12a90b080" +checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" dependencies = [ "cc", "glob", @@ -820,9 +820,9 @@ dependencies = [ [[package]] name = "boojum" -version = "0.32.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "362ea97026dfd07739f451438708ad2bd0bf812067c009592bcc50ac9758292c" +checksum = "c35c29c5d3bceefddceb36d518d5b77db15e481ac2ce9216d065ca3a2b7dd027" dependencies = [ "arrayvec 0.7.6", "bincode", @@ -866,9 +866,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" dependencies = [ "once_cell", - "proc-macro-crate 3.3.0", + "proc-macro-crate 3.4.0", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -902,7 +902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 1.0.109", ] @@ -946,11 +946,11 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.12" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5" +checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -977,9 +977,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.36" +version = "1.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" +checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" dependencies = [ "find-msvc-tools", "jobserver", @@ -1049,9 +1049,9 @@ dependencies = [ [[package]] name = "circuit_definitions" -version = "0.152.4" +version = "0.153.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be380f1e0caba206aa731d3d24a20de53b106ad51cd367557807a413ed0e8587" +checksum = "bd7110350fbe678be432d0622a0186c3fde792d764a3c27ebba57fa11de513fb" dependencies = [ "circuit_encodings", "crossbeam", @@ -1063,26 +1063,26 @@ dependencies = [ [[package]] name = "circuit_encodings" -version = "0.152.4" +version = "0.153.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3cff3465b8da5aa0a566094910e3fe72b7f196e471da1607a0be0395e4d6fab" +checksum = "39c5d595b3fb188ac284b04f787f98975790a8f6d70de4858957e1245bd36747" dependencies = [ "derivative", "serde", - "zk_evm 0.152.4", + "zk_evm 0.153.1", "zkevm_circuits", ] [[package]] name = "circuit_sequencer_api" -version = "0.152.4" +version = "0.153.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c56d8a70d5d1e4a3e50b0256bb95e143721d8d9a3b155d7945df898d03e1c67" +checksum = "92fc7d38da8b755a420debb62a0411ed0ef7475f76ac8939a3c20b45afd0021d" dependencies = [ "derivative", "rayon", "serde", - "zk_evm 0.152.4", + "zk_evm 0.153.1", "zksync_bellman", ] @@ -1148,9 +1148,9 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.34" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" dependencies = [ "const_format_proc_macros", ] @@ -1162,7 +1162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "unicode-xid 0.2.6", ] @@ -1365,7 +1365,7 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -1392,7 +1392,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -1415,7 +1415,7 @@ dependencies = [ "fnv", "ident_case", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "strsim", "syn 1.0.109", ] @@ -1427,7 +1427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", - "quote 1.0.40", + "quote 1.0.41", "syn 1.0.109", ] @@ -1477,12 +1477,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" dependencies = [ "powerfmt", - "serde", + "serde_core", ] [[package]] @@ -1492,7 +1492,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 1.0.109", ] @@ -1512,7 +1512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", "unicode-xid 0.2.6", ] @@ -1551,7 +1551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -1699,7 +1699,7 @@ checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" dependencies = [ "once_cell", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -1716,7 +1716,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -1822,9 +1822,9 @@ dependencies = [ [[package]] name = "fflonk" -version = "0.32.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9818994e51d8529a1d8269f23edbd2038d82fb81ae5cd08e61662f6133864994" +checksum = "6f9301b382a04b084c618f75ab710c1bd421e5a9700fc9ae70262bc494f84fbf" dependencies = [ "bincode", "byteorder", @@ -1845,9 +1845,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find-msvc-tools" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" +checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" [[package]] name = "findshlibs" @@ -1887,9 +1887,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" dependencies = [ "crc32fast", "miniz_oxide", @@ -1944,9 +1944,9 @@ dependencies = [ [[package]] name = "franklin-crypto" -version = "0.32.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb8609d52029149287245dec1b2840b21883943cfbd84eece77e05f531206ff5" +checksum = "2bf5d7ba101487a7977c9c324e5aab1fdab98e4ed1240acb857836367c90ae8e" dependencies = [ "arr_macro", "bit-vec", @@ -2060,7 +2060,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -2127,14 +2127,14 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.5+wasi-0.2.4", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "glob" @@ -2251,7 +2251,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.11.1", + "indexmap 2.11.4", "slab", "tokio", "tokio-util", @@ -2270,7 +2270,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.3.1", - "indexmap 2.11.1", + "indexmap 2.11.4", "slab", "tokio", "tokio-util", @@ -2327,6 +2327,12 @@ dependencies = [ "foldhash", ] +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + [[package]] name = "hashlink" version = "0.10.0" @@ -2532,11 +2538,11 @@ dependencies = [ "http 1.3.1", "hyper 1.7.0", "hyper-util", - "rustls 0.23.31", + "rustls 0.23.32", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower-service", ] @@ -2571,9 +2577,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ "base64 0.22.1", "bytes", @@ -2597,9 +2603,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2766,7 +2772,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -2782,12 +2788,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.1" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206a8042aec68fa4a62e8d3f7aa4ceb508177d9324faf261e1959e495b7a1921" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.15.5", + "hashbrown 0.16.0", ] [[package]] @@ -2880,9 +2886,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.78" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" dependencies = [ "once_cell", "wasm-bindgen", @@ -2955,18 +2961,18 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.175" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "libloading" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets 0.53.3", + "windows-link 0.2.0", ] [[package]] @@ -2977,9 +2983,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ "bitflags 2.9.4", "libc", @@ -3037,11 +3043,10 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] @@ -3069,7 +3074,7 @@ dependencies = [ "beef", "fnv", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "regex-syntax 0.6.29", "syn 2.0.106", ] @@ -3129,9 +3134,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "miette" @@ -3152,7 +3157,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -3200,6 +3205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -3428,7 +3434,7 @@ checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -3438,17 +3444,17 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ - "proc-macro-crate 3.3.0", + "proc-macro-crate 3.4.0", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -3487,7 +3493,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -3519,7 +3525,7 @@ dependencies = [ "futures-sink", "js-sys", "pin-project-lite", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", ] @@ -3561,7 +3567,7 @@ dependencies = [ "opentelemetry_sdk", "prost 0.13.5", "reqwest 0.12.23", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", ] @@ -3596,7 +3602,7 @@ dependencies = [ "percent-encoding", "rand 0.9.2", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -3671,9 +3677,9 @@ version = "3.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" dependencies = [ - "proc-macro-crate 3.3.0", + "proc-macro-crate 3.4.0", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -3685,9 +3691,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -3695,15 +3701,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link 0.2.0", ] [[package]] @@ -3745,20 +3751,19 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.1" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" +checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" dependencies = [ "memchr", - "thiserror 2.0.16", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.1" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" +checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de" dependencies = [ "pest", "pest_generator", @@ -3766,22 +3771,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.1" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" +checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843" dependencies = [ "pest", "pest_meta", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] [[package]] name = "pest_meta" -version = "2.8.1" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" +checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a" dependencies = [ "pest", "sha2 0.10.8", @@ -3794,7 +3799,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.11.1", + "indexmap 2.11.4", ] [[package]] @@ -3813,7 +3818,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -3868,12 +3873,12 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plist" -version = "1.7.4" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af6b589e163c5a788fab00ce0c0366f6efbb9959c2f9874b224936af7fce7e1" +checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" dependencies = [ "base64 0.22.1", - "indexmap 2.11.1", + "indexmap 2.11.4", "quick-xml", "serde", "time", @@ -3957,11 +3962,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.22.27", + "toml_edit 0.23.6", ] [[package]] @@ -3972,7 +3977,7 @@ checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 1.0.109", "version_check", ] @@ -3984,7 +3989,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "version_check", ] @@ -4031,7 +4036,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -4085,7 +4090,7 @@ dependencies = [ "anyhow", "itertools 0.12.1", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -4098,7 +4103,7 @@ dependencies = [ "anyhow", "itertools 0.14.0", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -4170,7 +4175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 1.0.109", ] @@ -4220,9 +4225,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2 1.0.101", ] @@ -4357,18 +4362,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags 2.9.4", ] [[package]] name = "regex" -version = "1.11.2" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" dependencies = [ "aho-corasick", "memchr", @@ -4378,9 +4383,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" dependencies = [ "aho-corasick", "memchr", @@ -4516,9 +4521,9 @@ dependencies = [ [[package]] name = "rescue_poseidon" -version = "0.32.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5882e5f163b5ad2b4207684dbdddb0c2e79adb5ff0e0a26ff9caec5cf758d7d" +checksum = "3dd38e0a7af1949d057e9aca6535d664acee3ccd5c36cd282ab123af682ef2e0" dependencies = [ "addchain", "arrayvec 0.7.6", @@ -4599,7 +4604,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 1.0.109", ] @@ -4645,9 +4650,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.37.2" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b203a6425500a03e0919c42d3c47caca51e79f1132046626d2c8871c5092035d" +checksum = "c8975fc98059f365204d635119cf9c5a60ae67b841ed49b5422a9a7e56cdfac0" dependencies = [ "arrayvec 0.7.6", "borsh", @@ -4702,7 +4707,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -4719,14 +4724,14 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.31" +version = "0.23.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ "aws-lc-rs", "once_cell", "rustls-pki-types", - "rustls-webpki 0.103.4", + "rustls-webpki 0.103.7", "subtle", "zeroize", ] @@ -4752,7 +4757,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.4.0", + "security-framework 3.5.1", ] [[package]] @@ -4785,9 +4790,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" dependencies = [ "aws-lc-rs", "ring", @@ -4822,7 +4827,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -4917,9 +4922,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.4.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ "bitflags 2.9.4", "core-foundation 0.10.1", @@ -4940,11 +4945,12 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" dependencies = [ "serde", + "serde_core", ] [[package]] @@ -5063,10 +5069,11 @@ checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -5080,27 +5087,37 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -5135,7 +5152,7 @@ checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ "darling", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 1.0.109", ] @@ -5145,7 +5162,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.11.1", + "indexmap 2.11.4", "itoa", "ryu", "serde", @@ -5274,6 +5291,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "simdutf8" version = "0.1.5" @@ -5288,7 +5311,7 @@ checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" dependencies = [ "num-bigint 0.4.6", "num-traits", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", ] @@ -5346,15 +5369,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5fede39e20d50047e6eb1aee008bd44db17e6a851b1e1b00bce117bdf74d50" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] [[package]] name = "snark_wrapper" -version = "0.32.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0b48868dbee820298ccbb4eadb96cd8030697bae43695d9d3ff6f2c1a157b52" +checksum = "88d5cdc2d76f0bd230918b7b9b2180093dbb14a33fa4651d9ecc79a2fceb1fae" dependencies = [ "derivative", "rand 0.4.6", @@ -5450,7 +5473,7 @@ dependencies = [ "futures-util", "hashbrown 0.15.5", "hashlink", - "indexmap 2.11.1", + "indexmap 2.11.4", "ipnetwork", "log", "memchr", @@ -5462,7 +5485,7 @@ dependencies = [ "serde_json", "sha2 0.10.8", "smallvec", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tokio-stream", "tracing", @@ -5476,7 +5499,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "sqlx-core", "sqlx-macros-core", "syn 2.0.106", @@ -5494,7 +5517,7 @@ dependencies = [ "hex", "once_cell", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "serde", "serde_json", "sha2 0.10.8", @@ -5547,7 +5570,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "whoami", ] @@ -5589,7 +5612,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "whoami", ] @@ -5614,7 +5637,7 @@ dependencies = [ "serde", "serde_urlencoded", "sqlx-core", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "url", ] @@ -5665,7 +5688,7 @@ checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ "heck", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "rustversion", "syn 2.0.106", ] @@ -5694,7 +5717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "unicode-ident", ] @@ -5705,7 +5728,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "unicode-ident", ] @@ -5731,7 +5754,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -5791,15 +5814,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.22.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -5832,11 +5855,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -5846,18 +5869,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -5881,11 +5904,12 @@ dependencies = [ [[package]] name = "time" -version = "0.3.43" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", + "itoa", "num-conv", "powerfmt", "serde", @@ -5979,7 +6003,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -6005,11 +6029,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.31", + "rustls 0.23.32", "tokio", ] @@ -6043,25 +6067,44 @@ version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +[[package]] +name = "toml_datetime" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.11.1", - "toml_datetime", + "indexmap 2.11.4", + "toml_datetime 0.6.11", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.27" +version = "0.23.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +dependencies = [ + "indexmap 2.11.4", + "toml_datetime 0.7.2", + "toml_parser", + "winnow 0.7.13", +] + +[[package]] +name = "toml_parser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" dependencies = [ - "indexmap 2.11.1", - "toml_datetime", "winnow 0.7.13", ] @@ -6150,7 +6193,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -6227,9 +6270,9 @@ dependencies = [ [[package]] name = "triomphe" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" +checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" [[package]] name = "try-lock" @@ -6245,9 +6288,9 @@ checksum = "74b08b0c1257381af16a5c3605254d529d3e7e109f3c62befc5d168968192998" [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "ucd-trie" @@ -6339,7 +6382,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ad948c1cb799b1a70f836077721a92a35ac177d4daddf4c20a633786d4cf618" dependencies = [ - "quote 1.0.40", + "quote 1.0.41", "syn 1.0.109", ] @@ -6457,7 +6500,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe466916e9bf50cc69aba41affc11970885e9dd2b9e448e20e1fb8fc726132ed" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -6494,18 +6537,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.5+wasi-0.2.4" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4494f6290a82f5fe584817a676a34b9d6763e8d9d18204009fb31dceca98fd4" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" dependencies = [ "wasip2", ] [[package]] name = "wasip2" -version = "1.0.0+wasi-0.2.4" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03fa2761397e5bd52002cd7e73110c71af2109aca4e521a9f40473fe685b0a24" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] @@ -6518,9 +6561,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" dependencies = [ "cfg-if", "once_cell", @@ -6531,23 +6574,23 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" dependencies = [ "bumpalo", "log", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.51" +version = "0.4.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" +checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" dependencies = [ "cfg-if", "js-sys", @@ -6558,22 +6601,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ - "quote 1.0.40", + "quote 1.0.41", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -6581,9 +6624,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" dependencies = [ "unicode-ident", ] @@ -6603,9 +6646,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.78" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" dependencies = [ "js-sys", "wasm-bindgen", @@ -6653,7 +6696,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -6664,36 +6707,36 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.61.2" +version = "0.62.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.1.3", - "windows-result", - "windows-strings", + "windows-link 0.2.0", + "windows-result 0.4.0", + "windows-strings 0.5.0", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -6716,8 +6759,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ "windows-link 0.1.3", - "windows-result", - "windows-strings", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] @@ -6729,6 +6772,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-strings" version = "0.4.2" @@ -6738,6 +6790,15 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -6767,9 +6828,9 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" dependencies = [ "windows-link 0.2.0", ] @@ -6798,30 +6859,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" -dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -6834,12 +6878,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -6852,12 +6890,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -6870,24 +6902,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -6900,12 +6920,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -6918,12 +6932,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -6936,12 +6944,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -6954,12 +6956,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "winnow" version = "0.5.40" @@ -6990,9 +6986,9 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" @@ -7040,7 +7036,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", "synstructure", ] @@ -7061,7 +7057,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -7081,16 +7077,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] @@ -7102,7 +7098,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -7135,7 +7131,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] @@ -7222,9 +7218,9 @@ dependencies = [ [[package]] name = "zk_evm" -version = "0.152.4" +version = "0.153.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "382a5f7501b49f6e0bc082d3dc7c47191bb188678e354064ab8a0818cb42aa0b" +checksum = "c168c8a9624dfaccc7ec326458af41592f9fe9352e2a5c9a5b9354b0bfe83818" dependencies = [ "anyhow", "lazy_static", @@ -7232,7 +7228,7 @@ dependencies = [ "serde", "serde_json", "static_assertions", - "zk_evm_abstractions 0.152.4", + "zk_evm_abstractions 0.153.1", ] [[package]] @@ -7276,22 +7272,35 @@ dependencies = [ [[package]] name = "zk_evm_abstractions" -version = "0.152.4" +version = "0.152.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1f3a33e3127bf2c458f18a3173d626a69cbbca39804f65db461b78046646281" +dependencies = [ + "anyhow", + "num_enum 0.6.1", + "serde", + "static_assertions", + "zkevm_opcode_defs 0.152.6", +] + +[[package]] +name = "zk_evm_abstractions" +version = "0.153.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8c376763e04f0f06a533fa578dd2028e0fab2b9c76ca9d7aba3657399e3dac" +checksum = "ff09d4f75f8e6951a5ffb4d4addb07e7374b99b82f6ac80feb783f070d78bceb" dependencies = [ "anyhow", "num_enum 0.6.1", "serde", "static_assertions", - "zkevm_opcode_defs 0.152.4", + "zkevm_opcode_defs 0.153.1", ] [[package]] name = "zkevm_circuits" -version = "0.152.4" +version = "0.153.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f429ed1bcedd31260ca4988d66e4ace1e45d8545f8074445d30596d478b0ae" +checksum = "d5d4e7b79d7a2b65a8efbf2932c1ac466b177e9f8c1d9fe537fd82034b4dd6b7" dependencies = [ "arrayvec 0.7.6", "boojum", @@ -7305,7 +7314,7 @@ dependencies = [ "serde", "serde_json", "smallvec", - "zkevm_opcode_defs 0.152.4", + "zkevm_opcode_defs 0.153.1", "zksync_cs_derive", ] @@ -7370,9 +7379,27 @@ dependencies = [ [[package]] name = "zkevm_opcode_defs" -version = "0.152.4" +version = "0.152.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7afb94511b6835047782d173c224ae7cfc0654c5db5022e3956ebb52e9eaebb2" +dependencies = [ + "bitflags 2.9.4", + "blake2 0.10.6", + "ethereum-types", + "k256 0.13.4", + "lazy_static", + "p256 0.13.2", + "serde", + "sha2 0.10.8", + "sha3 0.10.8", + "zksync_pairing", +] + +[[package]] +name = "zkevm_opcode_defs" +version = "0.153.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4f77fb59a9481fd44574b8888f5afda11d44956a785da6f92f86ddaeef4859" +checksum = "15761b9870a4898056468228750283bb3a78510f51d3ea3db8d2022e59622604" dependencies = [ "bitflags 2.9.4", "blake2 0.10.6", @@ -7388,8 +7415,8 @@ dependencies = [ [[package]] name = "zksync_basic_types" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "anyhow", "chrono", @@ -7403,7 +7430,7 @@ dependencies = [ "serde_with", "sha2 0.10.8", "strum", - "thiserror 2.0.16", + "thiserror 2.0.17", "tiny-keccak 2.0.2", "url", "vise", @@ -7411,9 +7438,9 @@ dependencies = [ [[package]] name = "zksync_bellman" -version = "0.32.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dda34f04d6e840723172101e0961a85da204ea0ceef0190fdd394975853b08f" +checksum = "36b7adabfa1ad8be83520732b2f8d9669edf0d61fb19f6ac7ceb23c52141ce14" dependencies = [ "arrayvec 0.7.6", "bit-vec", @@ -7453,8 +7480,8 @@ dependencies = [ [[package]] name = "zksync_config" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "anyhow", "secrecy", @@ -7537,8 +7564,8 @@ dependencies = [ [[package]] name = "zksync_contracts" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "hex", "once_cell", @@ -7550,8 +7577,8 @@ dependencies = [ [[package]] name = "zksync_crypto_primitives" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "anyhow", "blake2 0.10.6", @@ -7561,26 +7588,26 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.8", - "thiserror 2.0.16", + "thiserror 2.0.17", "zksync_basic_types", ] [[package]] name = "zksync_cs_derive" -version = "0.32.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cba4ebb398f1ba780690d07a8d0368177261d059e63f0c3746e2e82855588892" +checksum = "a5712a7dcf9e6735cb85f5a8e919f841c671fa5d206c3fbdb65fb1e9e1983148" dependencies = [ "proc-macro-error", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "syn 1.0.109", ] [[package]] name = "zksync_dal" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "anyhow", "async-trait", @@ -7596,7 +7623,7 @@ dependencies = [ "serde_json", "sqlx", "strum", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", "vise", @@ -7618,15 +7645,15 @@ dependencies = [ [[package]] name = "zksync_db_connection" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "anyhow", "rand 0.8.5", "serde", "serde_json", "sqlx", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "tracing", "vise", @@ -7635,9 +7662,9 @@ dependencies = [ [[package]] name = "zksync_ff" -version = "0.32.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebf1eedfc02d875f9553f88d96cd44945fa2978bc380498328f4bdc3961d09c" +checksum = "d022ca3f1578fdac8da7aa1fbf66b8d2023d89f540e89db82c179821bdf3708a" dependencies = [ "byteorder", "hex", @@ -7648,24 +7675,24 @@ dependencies = [ [[package]] name = "zksync_ff_derive" -version = "0.32.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "894d4fd05cde3567a547d5c31505511f79862edd7c9b0c5addfd0533724803dd" +checksum = "159a8aa244908f2d89cf638b1a7817ef3d2c96491fc360114b7135c1787e32f4" dependencies = [ "num-bigint 0.4.6", "num-integer", "num-traits", "proc-macro2 1.0.101", - "quote 1.0.40", + "quote 1.0.41", "serde", "syn 1.0.109", ] [[package]] name = "zksync_kzg" -version = "0.152.4" +version = "0.153.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7068a7c2d89107be13304c9aad8fa2bb4c52f57869a59eff18d4e95d83dd690c" +checksum = "bb8aa6e427a0fffafe3cd6e51f4c0ee6ab0c58ab165877baacbda8ae85b340ab" dependencies = [ "boojum", "derivative", @@ -7680,8 +7707,8 @@ dependencies = [ [[package]] name = "zksync_l1_contract_interface" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "anyhow", "circuit_definitions", @@ -7698,8 +7725,8 @@ dependencies = [ [[package]] name = "zksync_mini_merkle_tree" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "once_cell", "zksync_basic_types", @@ -7708,8 +7735,8 @@ dependencies = [ [[package]] name = "zksync_multivm" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "anyhow", "circuit_sequencer_api", @@ -7717,7 +7744,7 @@ dependencies = [ "hex", "itertools 0.13.0", "once_cell", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "vise", "zk_evm 0.131.0-rc.2", @@ -7725,7 +7752,7 @@ dependencies = [ "zk_evm 0.140.0", "zk_evm 0.141.0", "zk_evm 0.151.8", - "zk_evm 0.152.4", + "zk_evm 0.153.1", "zksync_contracts", "zksync_mini_merkle_tree", "zksync_system_constants", @@ -7736,8 +7763,8 @@ dependencies = [ [[package]] name = "zksync_object_store" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "anyhow", "async-trait", @@ -7763,9 +7790,9 @@ dependencies = [ [[package]] name = "zksync_pairing" -version = "0.32.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3895f40044daf50998b531bd5053181a245eff58ddfdf5b3bc7055c0e77c1411" +checksum = "842aa42498e47c187a0e9603d1fb03f755126bc9ed98fa304780c35f62a3898c" dependencies = [ "byteorder", "cfg-if", @@ -7808,14 +7835,14 @@ dependencies = [ "prost-build", "prost-reflect", "protox", - "quote 1.0.40", + "quote 1.0.41", "syn 2.0.106", ] [[package]] name = "zksync_prover_interface" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "chrono", "ciborium", @@ -7831,8 +7858,8 @@ dependencies = [ [[package]] name = "zksync_shared_metrics" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "rustc_version", "serde", @@ -7844,9 +7871,9 @@ dependencies = [ [[package]] name = "zksync_solidity_vk_codegen" -version = "0.32.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc67a96bb5d6a9a48d9b08be9b84757238bdcca479f7fe1ccdfe3e434eb4fe62" +checksum = "6cb84e831959a8b28d1b91882aa211c383ddeea80318d6ca14e57c9dee4992e5" dependencies = [ "ethereum-types", "franklin-crypto", @@ -7861,8 +7888,8 @@ dependencies = [ [[package]] name = "zksync_state" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "anyhow", "async-trait", @@ -7883,8 +7910,8 @@ dependencies = [ [[package]] name = "zksync_storage" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "num_cpus", "once_cell", @@ -7896,8 +7923,8 @@ dependencies = [ [[package]] name = "zksync_system_constants" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "once_cell", "zksync_basic_types", @@ -7905,8 +7932,8 @@ dependencies = [ [[package]] name = "zksync_types" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "anyhow", "async-trait", @@ -7922,7 +7949,7 @@ dependencies = [ "serde", "serde_json", "serde_with", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "zksync_basic_types", "zksync_contracts", @@ -7935,8 +7962,8 @@ dependencies = [ [[package]] name = "zksync_utils" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "anyhow", "once_cell", @@ -7946,8 +7973,8 @@ dependencies = [ [[package]] name = "zksync_vlog" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "anyhow", "async-trait", @@ -7960,7 +7987,7 @@ dependencies = [ "sentry", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "tokio", "tracing", @@ -7979,8 +8006,8 @@ checksum = "43b3bc8ecfdfdc986aff5229f995340cad4c7c1967f0ad96ac870d354847925f" dependencies = [ "enum_dispatch", "primitive-types", - "zk_evm_abstractions 0.152.4", - "zkevm_opcode_defs 0.152.4", + "zk_evm_abstractions 0.152.6", + "zkevm_opcode_defs 0.152.6", "zksync_vm2_interface", ] @@ -7995,15 +8022,15 @@ dependencies = [ [[package]] name = "zksync_vm_interface" -version = "29.2.0-non-semver-compat" -source = "git+https://github.com/matter-labs/zksync-era.git?rev=f4e890a61db5fc372bf23fd0ffc501d3bce41f75#f4e890a61db5fc372bf23fd0ffc501d3bce41f75" +version = "29.4.1-non-semver-compat" +source = "git+https://github.com/matter-labs/zksync-era.git?rev=636b70c91c6df309799e7f0cd831a9d63ec24727#636b70c91c6df309799e7f0cd831a9d63ec24727" dependencies = [ "anyhow", "async-trait", "hex", "pretty_assertions", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", "zksync_contracts", "zksync_system_constants", diff --git a/system-contracts/bootloader/test_infra/Cargo.toml b/system-contracts/bootloader/test_infra/Cargo.toml index fe5a068dd3..20c210f65d 100644 --- a/system-contracts/bootloader/test_infra/Cargo.toml +++ b/system-contracts/bootloader/test_infra/Cargo.toml @@ -7,12 +7,12 @@ edition = "2021" [dependencies] -zksync_multivm = { git = "https://github.com/matter-labs/zksync-era.git", rev = "f4e890a61db5fc372bf23fd0ffc501d3bce41f75" } -zksync_types = { git = "https://github.com/matter-labs/zksync-era.git", rev = "f4e890a61db5fc372bf23fd0ffc501d3bce41f75" } -zksync_contracts = { git = "https://github.com/matter-labs/zksync-era.git", rev = "f4e890a61db5fc372bf23fd0ffc501d3bce41f75" } -zksync_utils = { git = "https://github.com/matter-labs/zksync-era.git", rev = "f4e890a61db5fc372bf23fd0ffc501d3bce41f75" } -zksync_state = { git = "https://github.com/matter-labs/zksync-era.git", rev = "f4e890a61db5fc372bf23fd0ffc501d3bce41f75" } -zksync_vlog = { git = "https://github.com/matter-labs/zksync-era.git", rev = "f4e890a61db5fc372bf23fd0ffc501d3bce41f75" } +zksync_multivm = { git = "https://github.com/matter-labs/zksync-era.git", rev = "636b70c91c6df309799e7f0cd831a9d63ec24727" } +zksync_types = { git = "https://github.com/matter-labs/zksync-era.git", rev = "636b70c91c6df309799e7f0cd831a9d63ec24727" } +zksync_contracts = { git = "https://github.com/matter-labs/zksync-era.git", rev = "636b70c91c6df309799e7f0cd831a9d63ec24727" } +zksync_utils = { git = "https://github.com/matter-labs/zksync-era.git", rev = "636b70c91c6df309799e7f0cd831a9d63ec24727" } +zksync_state = { git = "https://github.com/matter-labs/zksync-era.git", rev = "636b70c91c6df309799e7f0cd831a9d63ec24727" } +zksync_vlog = { git = "https://github.com/matter-labs/zksync-era.git", rev = "636b70c91c6df309799e7f0cd831a9d63ec24727" } colored = "2.0" hex = "0.4" diff --git a/system-contracts/bootloader/test_infra/src/hook.rs b/system-contracts/bootloader/test_infra/src/hook.rs index 8c271b69b3..142dc7856c 100644 --- a/system-contracts/bootloader/test_infra/src/hook.rs +++ b/system-contracts/bootloader/test_infra/src/hook.rs @@ -9,7 +9,7 @@ use zksync_multivm::zk_evm_latest::{ zkevm_opcode_defs::{FatPointer, Opcode, UMAOpcode}, }; -use zksync_types::{U256, u256_to_h256}; +use zksync_types::{u256_to_h256, U256}; #[derive(Clone, Debug)] pub(crate) enum TestVmHook { diff --git a/system-contracts/bootloader/test_infra/src/main.rs b/system-contracts/bootloader/test_infra/src/main.rs index cf00217988..f334da9d93 100644 --- a/system-contracts/bootloader/test_infra/src/main.rs +++ b/system-contracts/bootloader/test_infra/src/main.rs @@ -3,12 +3,11 @@ use colored::Colorize; use once_cell::sync::OnceCell; use std::process; use zksync_multivm::interface::{ - L1BatchEnv, L2BlockEnv, SystemEnv, TxExecutionMode, InspectExecutionMode, VmFactory, VmInterface, + InspectExecutionMode, L1BatchEnv, L2BlockEnv, SystemEnv, TxExecutionMode, VmFactory, + VmInterface, }; use zksync_multivm::vm_latest::{HistoryDisabled, ToTracerPointer, TracerDispatcher, Vm}; -use zksync_state::interface::{ - InMemoryStorage, StoragePtr, StorageView, IN_MEMORY_STORAGE_DEFAULT_NETWORK_ID, -}; +use zksync_state::interface::{InMemoryStorage, StorageView, IN_MEMORY_STORAGE_DEFAULT_NETWORK_ID}; use zksync_types::fee_model::BatchFeeInput; use std::{env, sync::Arc}; @@ -16,14 +15,15 @@ use tracing_subscriber::fmt; use tracing_subscriber::prelude::__tracing_subscriber_SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; use zksync_contracts::{ - BaseSystemContracts, ContractLanguage, SystemContractCode, - SystemContractsRepo, + BaseSystemContracts, ContractLanguage, SystemContractCode, SystemContractsRepo, }; use zksync_multivm::interface::{ExecutionResult, Halt}; +use zksync_types::bytecode::BytecodeHash; use zksync_types::system_contracts::get_system_smart_contracts_from_dir; -use zksync_types::{block::L2BlockHasher, Address, L1BatchNumber, L2BlockNumber, U256, u256_to_h256, }; +use zksync_types::{ + block::L2BlockHasher, settlement::SettlementLayer, u256_to_h256, Address, L1BatchNumber, L2BlockNumber, SLChainId, U256, +}; use zksync_types::{L2ChainId, Transaction}; -use zksync_types::bytecode::BytecodeHash; mod hook; mod test_count_tracer; @@ -41,15 +41,20 @@ fn execute_internal_bootloader_test() { root: env::current_dir().unwrap().join("../../"), }; - let bytecode = repo.read_sys_contract_bytecode(artifacts_location, "bootloader_test", Some("Bootloader"), ContractLanguage::Yul); + let bytecode = repo.read_sys_contract_bytecode( + artifacts_location, + "bootloader_test", + Some("Bootloader"), + ContractLanguage::Yul, + ); let hash = BytecodeHash::for_bytecode(&bytecode).value(); let bootloader = SystemContractCode { code: bytecode, hash, }; - - let bytecode = repo.read_sys_contract_bytecode("", "DefaultAccount", None, ContractLanguage::Sol); + let bytecode = + repo.read_sys_contract_bytecode("", "DefaultAccount", None, ContractLanguage::Sol); let hash = BytecodeHash::for_bytecode(&bytecode).value(); let default_aa = SystemContractCode { code: bytecode, @@ -70,6 +75,7 @@ fn execute_internal_bootloader_test() { execution_mode: TxExecutionMode::VerifyExecute, default_validation_computational_gas_limit: u32::MAX, chain_id: zksync_types::L2ChainId::from(299), + // pubdata_params: Default::default(), }; let mut l1_batch_env = L1BatchEnv { @@ -87,18 +93,16 @@ fn execute_internal_bootloader_test() { max_virtual_blocks_to_create: 1, interop_roots: vec![], }, + settlement_layer: SettlementLayer::L1(SLChainId(10)), }; // First - get the number of tests. let test_count = { - let storage: StoragePtr> = - StorageView::new(InMemoryStorage::with_custom_system_contracts_and_chain_id( - L2ChainId::from(IN_MEMORY_STORAGE_DEFAULT_NETWORK_ID), - get_system_smart_contracts_from_dir( - env::current_dir().unwrap().join("../../"), - ), - )) - .to_rc_ptr(); + let storage = StorageView::new(InMemoryStorage::with_custom_system_contracts_and_chain_id( + L2ChainId::from(IN_MEMORY_STORAGE_DEFAULT_NETWORK_ID), + get_system_smart_contracts_from_dir(env::current_dir().unwrap().join("../../")), + )) + .to_rc_ptr(); let mut vm: Vm<_, HistoryDisabled> = VmFactory::new(l1_batch_env.clone(), system_env.clone(), storage.clone()); @@ -121,20 +125,18 @@ fn execute_internal_bootloader_test() { for test_id in 1..=test_count { println!("\n === Running test {}", test_id); - let storage: StoragePtr> = - StorageView::new(InMemoryStorage::with_custom_system_contracts_and_chain_id( - L2ChainId::from(IN_MEMORY_STORAGE_DEFAULT_NETWORK_ID), - get_system_smart_contracts_from_dir( - env::current_dir().unwrap().join("../../"), - ), - )) - .to_rc_ptr(); + let storage = StorageView::new(InMemoryStorage::with_custom_system_contracts_and_chain_id( + L2ChainId::from(IN_MEMORY_STORAGE_DEFAULT_NETWORK_ID), + get_system_smart_contracts_from_dir(env::current_dir().unwrap().join("../../")), + )) + .to_rc_ptr(); // We are passing id of the test in location (0) where we normally put the operator. // This is then picked up by the testing framework. l1_batch_env.fee_account = zksync_types::H160::from(u256_to_h256(U256::from(test_id))); let mut vm: Vm<_, HistoryDisabled> = Vm::new(l1_batch_env.clone(), system_env.clone(), storage.clone()); + let test_result = Arc::new(OnceCell::default()); let requested_assert = Arc::new(OnceCell::default()); let test_name = Arc::new(OnceCell::default()); @@ -176,7 +178,8 @@ fn execute_internal_bootloader_test() { )), ExecutionResult::Halt { reason } => { if let Halt::UnexpectedVMBehavior(reason) = reason { - let reason = reason.strip_prefix("Assertion error: ").unwrap_or(reason); + let reason = + reason.strip_prefix("Assertion error: ").unwrap_or(&reason); if reason == requested_assert { Ok(()) } else { diff --git a/system-contracts/bootloader/tests/bootloader/bootloader_test.yul b/system-contracts/bootloader/tests/bootloader/bootloader_test.yul index ccbca2aa36..0f99bf3d15 100644 --- a/system-contracts/bootloader/tests/bootloader/bootloader_test.yul +++ b/system-contracts/bootloader/tests/bootloader/bootloader_test.yul @@ -188,7 +188,7 @@ function TEST_systemLogKeys() { let protocolUpgradeTxHashKey := protocolUpgradeTxHashKey() testing_assertEq(chainedPriorityTxnHashLogKey, 2, "Invalid priority txn hash log key") testing_assertEq(numberOfLayer1TxsLogKey, 3, "Invalid num layer 1 txns log key") - testing_assertEq(protocolUpgradeTxHashKey, 9, "Invalid protocol upgrade txn hash log key") + testing_assertEq(protocolUpgradeTxHashKey, 10, "Invalid protocol upgrade txn hash log key") } function TEST_safeAdd() { diff --git a/system-contracts/contracts/Constants.sol b/system-contracts/contracts/Constants.sol index 5acdbe42f7..509472436f 100644 --- a/system-contracts/contracts/Constants.sol +++ b/system-contracts/contracts/Constants.sol @@ -10,6 +10,8 @@ import {IImmutableSimulator} from "./interfaces/IImmutableSimulator.sol"; import {IBaseToken} from "./interfaces/IBaseToken.sol"; import {IBridgehub} from "./interfaces/IBridgehub.sol"; import {IL1Messenger} from "./interfaces/IL1Messenger.sol"; +import {IMessageVerification} from "./interfaces/IMessageVerification.sol"; +import {IChainAssetHandler} from "./interfaces/IChainAssetHandler.sol"; import {ISystemContext} from "./interfaces/ISystemContext.sol"; import {ICompressor} from "./interfaces/ICompressor.sol"; import {IComplexUpgrader} from "./interfaces/IComplexUpgrader.sol"; @@ -19,7 +21,12 @@ import {IMessageRoot} from "./interfaces/IMessageRoot.sol"; import {ICreate2Factory} from "./interfaces/ICreate2Factory.sol"; import {IEvmHashesStorage} from "./interfaces/IEvmHashesStorage.sol"; import {IL2AssetRouter} from "./interfaces/IL2AssetRouter.sol"; +import {IL2AssetTracker} from "./interfaces/IL2AssetTracker.sol"; +import {IGWAssetTracker} from "./interfaces/IGWAssetTracker.sol"; import {IL2NativeTokenVault} from "./interfaces/IL2NativeTokenVault.sol"; +import {IInteropHandler} from "./interfaces/IInteropHandler.sol"; +import {IInteropCenter} from "./interfaces/IInteropCenter.sol"; +import {IL2InteropRootStorage} from "./interfaces/IL2InteropRootStorage.sol"; /// @dev All the system contracts introduced by ZKsync have their addresses /// started from 2^15 in order to avoid collision with Ethereum precompiles. @@ -113,15 +120,27 @@ address constant L2_DA_VALIDATOR = address(SYSTEM_CONTRACTS_OFFSET + 0x16); ICreate2Factory constant L2_CREATE2_FACTORY = ICreate2Factory(address(USER_CONTRACTS_OFFSET)); IL2AssetRouter constant L2_ASSET_ROUTER = IL2AssetRouter(address(USER_CONTRACTS_OFFSET + 0x03)); IBridgehub constant L2_BRIDGE_HUB = IBridgehub(address(USER_CONTRACTS_OFFSET + 0x02)); -IL2NativeTokenVault constant L2_NATIVE_TOKEN_VAULT = IL2NativeTokenVault(address(USER_CONTRACTS_OFFSET + 0x04)); +address constant L2_NATIVE_TOKEN_VAULT_ADDR = address(USER_CONTRACTS_OFFSET + 0x04); +IL2NativeTokenVault constant L2_NATIVE_TOKEN_VAULT = IL2NativeTokenVault(L2_NATIVE_TOKEN_VAULT_ADDR); IMessageRoot constant L2_MESSAGE_ROOT = IMessageRoot(address(USER_CONTRACTS_OFFSET + 0x05)); // Note, that on its own this contract does not provide much functionality, but having it on a constant address // serves as a convenient storage for its bytecode to be accessible via `extcodehash`. address constant SLOAD_CONTRACT_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x06); address constant WRAPPED_BASE_TOKEN_IMPL_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x07); +IL2InteropRootStorage constant L2_INTEROP_ROOT_STORAGE = IL2InteropRootStorage(address(USER_CONTRACTS_OFFSET + 0x08)); +IMessageVerification constant L2_MESSAGE_VERIFICATION = IMessageVerification(address(USER_CONTRACTS_OFFSET + 0x09)); +address constant L2_CHAIN_ASSET_HANDLER_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x0a); +IChainAssetHandler constant L2_CHAIN_ASSET_HANDLER = IChainAssetHandler(L2_CHAIN_ASSET_HANDLER_ADDRESS); +address constant L2_UPGRADEABLE_BEACON_DEPLOYER_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x0b); +address constant L2_INTEROP_CENTER_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x0c); +IInteropCenter constant L2_INTEROP_CENTER = IInteropCenter(L2_INTEROP_CENTER_ADDRESS); +IInteropHandler constant L2_INTEROP_HANDLER = IInteropHandler(address(USER_CONTRACTS_OFFSET + 0x0d)); +address constant L2_ASSET_TRACKER_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x0e); +IL2AssetTracker constant L2_ASSET_TRACKER = IL2AssetTracker(address(L2_ASSET_TRACKER_ADDRESS)); +address constant GW_ASSET_TRACKER_ADDRESS = address(USER_CONTRACTS_OFFSET + 0x0f); +IGWAssetTracker constant GW_ASSET_TRACKER = IGWAssetTracker(address(GW_ASSET_TRACKER_ADDRESS)); -address constant L2_CHAIN_ASSET_HANDLER = address(USER_CONTRACTS_OFFSET + 0x0a); /// @dev If the bitwise AND of the extraAbi[2] param when calling the MSG_VALUE_SIMULATOR /// is non-zero, the call will be assumed to be a system one. @@ -168,6 +187,7 @@ enum SystemLogKey { USED_L2_DA_VALIDATION_COMMITMENT_SCHEME_KEY, MESSAGE_ROOT_ROLLING_HASH_KEY, L2_TXS_STATUS_ROLLING_HASH_KEY, + SETTLEMENT_LAYER_CHAIN_ID_KEY, EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY } @@ -175,6 +195,8 @@ enum SystemLogKey { /// While formally a tree of any length is acceptable, the node supports only a constant length of 16384 leaves. uint256 constant L2_TO_L1_LOGS_MERKLE_TREE_LEAVES = 16_384; +uint256 constant L2_TO_L1_LOGS_MERKLE_TREE_DEPTH = 14 + 1; + /// @dev The length of the derived key in bytes inside compressed state diffs. uint256 constant DERIVED_KEY_LENGTH = 32; /// @dev The length of the enum index in bytes inside compressed state diffs. @@ -227,3 +249,6 @@ enum L2DACommitmentScheme { BLOBS_AND_PUBDATA_KECCAK256, BLOBS_ZKSYNC_OS } + +/// @dev The metadata version that is supported by the ZK Chains to prove that an L2->L1 log was included in a batch. +uint256 constant SUPPORTED_PROOF_METADATA_VERSION = 1; diff --git a/system-contracts/contracts/L2BaseToken.sol b/system-contracts/contracts/L2BaseToken.sol index 2f62850f55..6d87af8599 100644 --- a/system-contracts/contracts/L2BaseToken.sol +++ b/system-contracts/contracts/L2BaseToken.sol @@ -4,8 +4,8 @@ pragma solidity 0.8.28; import {IBaseToken} from "./interfaces/IBaseToken.sol"; import {SystemContractBase} from "./abstract/SystemContractBase.sol"; -import {BOOTLOADER_FORMAL_ADDRESS, DEPLOYER_SYSTEM_CONTRACT, L1_MESSENGER_CONTRACT, MSG_VALUE_SYSTEM_CONTRACT} from "./Constants.sol"; -import {IMailbox} from "./interfaces/IMailbox.sol"; +import {BOOTLOADER_FORMAL_ADDRESS, DEPLOYER_SYSTEM_CONTRACT, L1_MESSENGER_CONTRACT, L2_ASSET_TRACKER, MSG_VALUE_SYSTEM_CONTRACT} from "./Constants.sol"; +import {IMailboxImpl} from "./interfaces/IMailboxImpl.sol"; import {InsufficientFunds, Unauthorized} from "./SystemContractErrors.sol"; /** @@ -65,7 +65,8 @@ contract L2BaseToken is IBaseToken, SystemContractBase { /// @dev This method is only callable by the bootloader. /// @param _account The address which to mint the funds to. /// @param _amount The amount of ETH in wei to be minted. - function mint(address _account, uint256 _amount) external override onlyCallFromBootloader { + function mint(address _account, uint256 _amount) external override onlyCallFromBootloaderOrInteropHandler { + L2_ASSET_TRACKER.handleFinalizeBaseTokenBridgingOnL2(_amount); totalSupply += _amount; balance[_account] += _amount; emit Mint(_account, _amount); @@ -102,6 +103,8 @@ contract L2BaseToken is IBaseToken, SystemContractBase { /// So the balance of `address(this)` is always bigger or equal to the `msg.value`! function _burnMsgValue() internal returns (uint256 amount) { amount = msg.value; + /// @dev This function is called to check if the token is withdrawable. + L2_ASSET_TRACKER.handleInitiateBaseTokenBridgingOnL2(amount); // Silent burning of the ether unchecked { @@ -112,9 +115,13 @@ contract L2BaseToken is IBaseToken, SystemContractBase { } } + function burnMsgValue() external payable override onlyCallFromInteropCenter { + _burnMsgValue(); + } + /// @dev Get the message to be sent to L1 to initiate a withdrawal. function _getL1WithdrawMessage(address _to, uint256 _amount) internal pure returns (bytes memory) { - return abi.encodePacked(IMailbox.finalizeEthWithdrawal.selector, _to, _amount); + return abi.encodePacked(IMailboxImpl.finalizeEthWithdrawal.selector, _to, _amount); } /// @dev Get the message to be sent to L1 to initiate a withdrawal. @@ -125,6 +132,6 @@ contract L2BaseToken is IBaseToken, SystemContractBase { bytes memory _additionalData ) internal pure returns (bytes memory) { // solhint-disable-next-line func-named-parameters - return abi.encodePacked(IMailbox.finalizeEthWithdrawal.selector, _to, _amount, _sender, _additionalData); + return abi.encodePacked(IMailboxImpl.finalizeEthWithdrawal.selector, _to, _amount, _sender, _additionalData); } } diff --git a/system-contracts/contracts/SystemContext.sol b/system-contracts/contracts/SystemContext.sol index b8910916ea..d8fb7a502f 100644 --- a/system-contracts/contracts/SystemContext.sol +++ b/system-contracts/contracts/SystemContext.sol @@ -6,7 +6,7 @@ import {ISystemContext} from "./interfaces/ISystemContext.sol"; import {SystemContractBase} from "./abstract/SystemContractBase.sol"; import {ISystemContextDeprecated} from "./interfaces/ISystemContextDeprecated.sol"; import {SystemContractHelper} from "./libraries/SystemContractHelper.sol"; -import {BOOTLOADER_FORMAL_ADDRESS, COMPLEX_UPGRADER_CONTRACT, SystemLogKey} from "./Constants.sol"; +import {BOOTLOADER_FORMAL_ADDRESS, COMPLEX_UPGRADER_CONTRACT, L2_CHAIN_ASSET_HANDLER, SystemLogKey} from "./Constants.sol"; import {CannotInitializeFirstVirtualBlock, CannotReuseL2BlockNumberFromPreviousBatch, CurrentBatchNumberMustBeGreaterThanZero, DeprecatedFunction, InconsistentNewBatchTimestamp, IncorrectL2BlockHash, IncorrectSameL2BlockPrevBlockHash, IncorrectSameL2BlockTimestamp, IncorrectVirtualBlockInsideMiniblock, InvalidNewL2BlockNumber, L2BlockAndBatchTimestampMismatch, L2BlockNumberZero, NoVirtualBlocks, NonMonotonicL2BlockTimestamp, PreviousL2BlockHashIsIncorrect, ProvidedBatchNumberIsNotCorrect, TimestampsShouldBeIncremental, UpgradeTransactionMustBeFirst} from "contracts/SystemContractErrors.sol"; /** @@ -83,12 +83,23 @@ contract SystemContext is ISystemContext, ISystemContextDeprecated, SystemContra /// @notice The information about the virtual blocks upgrade, which tracks when the migration to the L2 blocks has started and finished. VirtualBlockUpgradeInfo internal virtualBlockUpgradeInfo; + /// @notice The chainId of the settlement layer. + /// @notice This value will be deprecated in the future, it should not be used by external contracts. + uint256 public currentSettlementLayerChainId; + /// @notice Set the chainId origin. /// @param _newChainId The chainId function setChainId(uint256 _newChainId) external onlyCallFrom(address(COMPLEX_UPGRADER_CONTRACT)) { chainId = _newChainId; } + function setSettlementLayerChainId(uint256 _newSettlementLayerChainId) external onlyCallFromBootloader { + if (currentSettlementLayerChainId != _newSettlementLayerChainId) { + L2_CHAIN_ASSET_HANDLER.setSettlementLayerChainId(currentSettlementLayerChainId, _newSettlementLayerChainId); + currentSettlementLayerChainId = _newSettlementLayerChainId; + } + } + /// @notice Number of current transaction in block. uint16 public txNumberInBlock; diff --git a/system-contracts/contracts/SystemContractErrors.sol b/system-contracts/contracts/SystemContractErrors.sol index 399a69c784..8a8d569aa4 100644 --- a/system-contracts/contracts/SystemContractErrors.sol +++ b/system-contracts/contracts/SystemContractErrors.sol @@ -6,6 +6,8 @@ pragma solidity ^0.8.20; error CallerMustBeBootloader(); // 0xbe4bf9e4 error CallerMustBeEvmContract(); +// 0x775f8864 +error CallerMustBeInteropCenter(); // 0x9eedbd2b error CallerMustBeSystemContract(); // 0xee455381 @@ -108,6 +110,12 @@ error L2BlockNumberZero(); error LegacyBridgeNotProxy(); // 0x43e266b0 error MalformedBytecode(BytecodeError); +// 0x9bb54c35 +error MerkleIndexOutOfBounds(); +// 0x8e23ac1a +error MerklePathEmpty(); +// 0x1c500385 +error MerklePathOutOfBounds(); // 0xe90aded4 error NonceAlreadyUsed(address account, uint256 nonce); // 0xbac091ee diff --git a/system-contracts/contracts/abstract/SystemContractBase.sol b/system-contracts/contracts/abstract/SystemContractBase.sol index c809652878..f823152a44 100644 --- a/system-contracts/contracts/abstract/SystemContractBase.sol +++ b/system-contracts/contracts/abstract/SystemContractBase.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.20; import {SystemContractHelper} from "../libraries/SystemContractHelper.sol"; -import {BOOTLOADER_FORMAL_ADDRESS} from "../Constants.sol"; -import {CallerMustBeBootloader, CallerMustBeEvmContract, CallerMustBeSystemContract, SystemCallFlagRequired, Unauthorized} from "../SystemContractErrors.sol"; +import {BOOTLOADER_FORMAL_ADDRESS, L2_INTEROP_CENTER, L2_INTEROP_HANDLER} from "../Constants.sol"; +import {CallerMustBeBootloader, CallerMustBeEvmContract, CallerMustBeInteropCenter, CallerMustBeSystemContract, SystemCallFlagRequired, Unauthorized} from "../SystemContractErrors.sol"; /** * @author Matter Labs @@ -60,4 +60,22 @@ abstract contract SystemContractBase { } _; } + + /// @notice Modifier that makes sure that the method + /// can only be called from the bootloader. + modifier onlyCallFromBootloaderOrInteropHandler() { + if (msg.sender != BOOTLOADER_FORMAL_ADDRESS && msg.sender != address(L2_INTEROP_HANDLER)) { + revert CallerMustBeBootloader(); + } + _; + } + + /// @notice Modifier that makes sure that the method + /// can only be called from the interop center. + modifier onlyCallFromInteropCenter() { + if (msg.sender != address(L2_INTEROP_CENTER)) { + revert CallerMustBeInteropCenter(); + } + _; + } } diff --git a/system-contracts/contracts/interfaces/IBaseToken.sol b/system-contracts/contracts/interfaces/IBaseToken.sol index e2afaef739..f166de5223 100644 --- a/system-contracts/contracts/interfaces/IBaseToken.sol +++ b/system-contracts/contracts/interfaces/IBaseToken.sol @@ -17,6 +17,8 @@ interface IBaseToken { function withdrawWithMessage(address _l1Receiver, bytes calldata _additionalData) external payable; + function burnMsgValue() external payable; + event Mint(address indexed account, uint256 amount); event Transfer(address indexed from, address indexed to, uint256 value); diff --git a/system-contracts/contracts/interfaces/IBridgehub.sol b/system-contracts/contracts/interfaces/IBridgehub.sol index cac767b55e..a35e05f475 100644 --- a/system-contracts/contracts/interfaces/IBridgehub.sol +++ b/system-contracts/contracts/interfaces/IBridgehub.sol @@ -9,7 +9,8 @@ interface IBridgehub { address _assetRouter, address _ctmDeployer, address _messageRoot, - address _chainAssetHandler + address _chainAssetHandler, + address _chainRegistrationSender ) external; function setChainAssetHandler(address _chainAssetHandler) external; diff --git a/system-contracts/contracts/interfaces/IChainAssetHandler.sol b/system-contracts/contracts/interfaces/IChainAssetHandler.sol new file mode 100644 index 0000000000..9604f9cce1 --- /dev/null +++ b/system-contracts/contracts/interfaces/IChainAssetHandler.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IChainAssetHandler { + function setSettlementLayerChainId( + uint256 _previousSettlementLayerChainId, + uint256 _currentSettlementLayerChainId + ) external; +} diff --git a/system-contracts/contracts/interfaces/IGWAssetTracker.sol b/system-contracts/contracts/interfaces/IGWAssetTracker.sol new file mode 100644 index 0000000000..2042611683 --- /dev/null +++ b/system-contracts/contracts/interfaces/IGWAssetTracker.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.20; + +/** + * @author Matter Labs + * @custom:security-contact security@matterlabs.dev + * @notice The interface for the GWAssetTracker contract + */ +interface IGWAssetTracker { + function setAddresses(uint256 _l1ChainId) external; +} diff --git a/system-contracts/contracts/interfaces/IInteropCenter.sol b/system-contracts/contracts/interfaces/IInteropCenter.sol new file mode 100644 index 0000000000..5c9e4a615d --- /dev/null +++ b/system-contracts/contracts/interfaces/IInteropCenter.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.20; + +interface IInteropCenter { + function setAddresses(address _assetRouter, address _assetTracker) external; +} diff --git a/system-contracts/contracts/interfaces/IInteropHandler.sol b/system-contracts/contracts/interfaces/IInteropHandler.sol new file mode 100644 index 0000000000..b7a9b5329b --- /dev/null +++ b/system-contracts/contracts/interfaces/IInteropHandler.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.20; + +import {MessageInclusionProof} from "../libraries/Messaging.sol"; + +enum CallStatus { + Unprocessed, + Executed, + Cancelled +} + +enum BundleStatus { + Unreceived, + Verified, + FullyExecuted, + Unbundled +} + +interface IInteropHandler { + function executeBundle(bytes memory _bundle, MessageInclusionProof memory _proof) external; + function verifyBundle(bytes memory _bundle, MessageInclusionProof memory _proof) external; + function unbundleBundle( + uint256 _sourceChainId, + uint256 _l2MessageIndex, + bytes memory _bundle, + CallStatus[] calldata _callStatus + ) external; +} diff --git a/system-contracts/contracts/interfaces/IL1Messenger.sol b/system-contracts/contracts/interfaces/IL1Messenger.sol index 7beeab20c5..75610dbee6 100644 --- a/system-contracts/contracts/interfaces/IL1Messenger.sol +++ b/system-contracts/contracts/interfaces/IL1Messenger.sol @@ -2,6 +2,8 @@ // We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. pragma solidity ^0.8.20; +import {L2DACommitmentScheme} from "../Constants.sol"; + /// @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 /// @param isService A boolean flag that is part of the log along with `key`, `value`, and `sender` address. @@ -40,4 +42,10 @@ interface IL1Messenger { // This function is expected to be called only by the KnownCodesStorage system contract function requestBytecodeL1Publication(bytes32 _bytecodeHash) external; + + // This function is expected to be called only by the Bootloader system contract + function publishPubdataAndClearState( + L2DACommitmentScheme _l2DACommitmentScheme, + bytes calldata _operatorInput + ) external; } diff --git a/system-contracts/contracts/interfaces/IL2AssetTracker.sol b/system-contracts/contracts/interfaces/IL2AssetTracker.sol new file mode 100644 index 0000000000..8005de9947 --- /dev/null +++ b/system-contracts/contracts/interfaces/IL2AssetTracker.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.20; + +/** + * @author Matter Labs + * @custom:security-contact security@matterlabs.dev + * @notice The interface for the L2AssetTracker contract + */ +interface IL2AssetTracker { + function setAddresses(uint256 _l1ChainId, bytes32 _baseTokenAssetId) external; + + function handleInitiateBaseTokenBridgingOnL2(uint256 _amount) external; + + function handleFinalizeBaseTokenBridgingOnL2(uint256 _amount) external; + + function setLegacySharedBridgeAddress(uint256 _chainId, address _legacySharedBridgeAddress) external; +} diff --git a/system-contracts/contracts/interfaces/IL2GenesisUpgrade.sol b/system-contracts/contracts/interfaces/IL2GenesisUpgrade.sol index b828dd5d76..09ad05dcd6 100644 --- a/system-contracts/contracts/interfaces/IL2GenesisUpgrade.sol +++ b/system-contracts/contracts/interfaces/IL2GenesisUpgrade.sol @@ -12,6 +12,9 @@ struct ZKChainSpecificForceDeploymentsData { /// needed to deploy weth token in case it is not present string baseTokenName; string baseTokenSymbol; + uint256 baseTokenOriginChainId; + /// The address of the base token on the origin chain. + address baseTokenOriginAddress; } /// @notice The structure that describes force deployments that are the same for each chain. @@ -21,6 +24,7 @@ struct ZKChainSpecificForceDeploymentsData { // solhint-disable-next-line gas-struct-packing struct FixedForceDeploymentsData { uint256 l1ChainId; + uint256 gatewayChainId; uint256 eraChainId; address l1AssetRouter; bytes32 l2TokenProxyBytecodeHash; @@ -31,8 +35,12 @@ struct FixedForceDeploymentsData { bytes32 l2NtvBytecodeHash; bytes32 messageRootBytecodeHash; bytes32 chainAssetHandlerBytecodeHash; + bytes32 interopCenterBytecodeHash; + bytes32 interopHandlerBytecodeHash; + bytes32 assetTrackerBytecodeHash; address l2SharedBridgeLegacyImpl; address l2BridgedStandardERC20Impl; + address aliasedChainRegistrationSender; // The forced beacon address. It is needed only for internal testing. // MUST be equal to 0 in production. // It will be the job of the governance to ensure that this value is set correctly. diff --git a/system-contracts/contracts/interfaces/IL2InteropRootStorage.sol b/system-contracts/contracts/interfaces/IL2InteropRootStorage.sol new file mode 100644 index 0000000000..7f585b4f17 --- /dev/null +++ b/system-contracts/contracts/interfaces/IL2InteropRootStorage.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.20; + +interface IL2InteropRootStorage { + // function getAggregatedRoot() external view returns (bytes32); + function addMessageRoot(uint256 chainId, uint256 blockNumber, bytes32 msgRoot) external; + + function msgRoots(uint256 _chainId, uint256 _batchNumber) external view returns (bytes32); +} diff --git a/system-contracts/contracts/interfaces/IL2NativeTokenVault.sol b/system-contracts/contracts/interfaces/IL2NativeTokenVault.sol index dd46ca44ea..6a8ee48e3d 100644 --- a/system-contracts/contracts/interfaces/IL2NativeTokenVault.sol +++ b/system-contracts/contracts/interfaces/IL2NativeTokenVault.sol @@ -9,4 +9,6 @@ pragma solidity ^0.8.20; */ interface IL2NativeTokenVault { function tokenAddress(bytes32 _assetId) external view returns (address); + + function setAddresses(uint256 _baseTokenOriginChainId) external; } diff --git a/system-contracts/contracts/interfaces/IMailboxImpl.sol b/system-contracts/contracts/interfaces/IMailboxImpl.sol new file mode 100644 index 0000000000..012d1aaf10 --- /dev/null +++ b/system-contracts/contracts/interfaces/IMailboxImpl.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.20; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IMailboxImpl { + function finalizeEthWithdrawal( + uint256 _l2BatchNumber, + uint256 _l2MessageIndex, + uint16 _l2TxNumberInBlock, + bytes calldata _message, + bytes32[] calldata _merkleProof + ) external; +} diff --git a/system-contracts/contracts/interfaces/IMessageRoot.sol b/system-contracts/contracts/interfaces/IMessageRoot.sol index 3966caa15d..4e40def825 100644 --- a/system-contracts/contracts/interfaces/IMessageRoot.sol +++ b/system-contracts/contracts/interfaces/IMessageRoot.sol @@ -11,4 +11,6 @@ interface IMessageRoot { /// @notice The aggregated root of the batches from different chains. /// @return aggregatedRoot of the batches from different chains. function getAggregatedRoot() external view returns (bytes32 aggregatedRoot); + + function setAddresses(address _assetTracker) external; } diff --git a/system-contracts/contracts/interfaces/IMessageVerification.sol b/system-contracts/contracts/interfaces/IMessageVerification.sol new file mode 100644 index 0000000000..52ed9f38e3 --- /dev/null +++ b/system-contracts/contracts/interfaces/IMessageVerification.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.21; + +import {L2Log, L2Message} from "../libraries/Messaging.sol"; + +/// @title The interface of the ZKsync Mailbox contract that provides interfaces for L1 <-> L2 interaction. +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +interface IMessageVerification { + /// @notice Prove that a specific arbitrary-length message was sent in a specific L2 batch number + /// @param _chainId The chain id of the L2 + /// @param _batchNumber The executed L2 batch number in which the message appeared + /// @param _index The position in the L2 logs Merkle tree of the l2Log that was sent with the message + /// @param _message Information about the sent message: sender address, the message itself, tx index in the L2 batch where the message was sent + /// @param _proof Merkle proof for inclusion of L2 log that was sent with the message + /// @return Whether the proof is valid + function proveL2MessageInclusionShared( + uint256 _chainId, + uint256 _batchNumber, + uint256 _index, + L2Message calldata _message, + bytes32[] calldata _proof + ) external view returns (bool); + + /// @notice Prove that a specific L2 log was sent in a specific L2 batch + /// @param _chainId The chain id of the L2 + /// @param _batchNumber The executed L2 batch number in which the log appeared + /// @param _index The position of the l2log in the L2 logs Merkle tree + /// @param _log Information about the sent log + /// @param _proof Merkle proof for inclusion of the L2 log + /// @return Whether the proof is correct and L2 log is included in batch + function proveL2LogInclusionShared( + uint256 _chainId, + uint256 _batchNumber, + uint256 _index, + L2Log memory _log, + bytes32[] calldata _proof + ) external view returns (bool); + + /// Proves that a certain leaf was included as part of the log merkle tree. + function proveL2LeafInclusionShared( + uint256 _chainId, + uint256 _batchNumber, + uint256 _batchRootMask, + bytes32 _leaf, + bytes32[] calldata _proof + ) external view returns (bool); +} diff --git a/system-contracts/contracts/libraries/DynamicIncrementalMerkle.sol b/system-contracts/contracts/libraries/DynamicIncrementalMerkle.sol new file mode 100644 index 0000000000..88b5b665dc --- /dev/null +++ b/system-contracts/contracts/libraries/DynamicIncrementalMerkle.sol @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.28; + +import {Merkle} from "./Merkle.sol"; +import {Arrays} from "@openzeppelin/contracts-v4/utils/Arrays.sol"; + +/** + * @dev Library for managing https://wikipedia.org/wiki/Merkle_Tree[Merkle Tree] data structures. + * + * Each tree is a complete binary tree with the ability to sequentially insert leaves, changing them from a zero to a + * non-zero value and updating its root. This structure allows inserting commitments (or other entries) that are not + * stored, but can be proven to be part of the tree at a later time if the root is kept. See {MerkleProof}. + * + * A tree is defined by the following parameters: + * + * * Depth: The number of levels in the tree, it also defines the maximum number of leaves as 2**depth. + * * Zero value: The value that represents an empty leaf. Used to avoid regular zero values to be part of the tree. + * * Hashing function: A cryptographic hash function used to produce internal nodes. + * + * This is a fork of OpenZeppelin's [`MerkleTree`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/9af280dc4b45ee5bda96ba47ff829b407eaab67e/contracts/utils/structs/MerkleTree.sol) + * library, with the changes to support dynamic tree growth (doubling the size when full). + */ +library DynamicIncrementalMerkle { + /** + * @dev A complete `bytes32` Merkle tree. + * + * The `sides` and `zero` arrays are set to have a length equal to the depth of the tree during setup. + * + * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to + * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and + * lead to unexpected behavior. + * + * NOTE: The `root` and the updates history is not stored within the tree. Consider using a secondary structure to + * store a list of historical roots from the values returned from {setup} and {push} (e.g. a mapping, {BitMaps} or + * {Checkpoints}). + * + * WARNING: Updating any of the tree's parameters after the first insertion will result in a corrupted tree. + */ + struct Bytes32PushTree { + uint256 _nextLeafIndex; + bytes32[] _sides; + bytes32[] _zeros; + uint256 _sidesLengthMemory; + uint256 _zerosLengthMemory; + bool _needsRootRecalculation; + } + + /** + * @dev Initialize a {Bytes32PushTree} using {Hashes-Keccak256} to hash internal nodes. + * The capacity of the tree (i.e. number of leaves) is set to `2**levels`. + * + * IMPORTANT: The zero value should be carefully chosen since it will be stored in the tree representing + * empty leaves. It should be a value that is not expected to be part of the tree. + */ + function setup(Bytes32PushTree storage self, bytes32 zero) internal returns (bytes32 initialRoot) { + self._nextLeafIndex = 0; + self._zeros.push(zero); + self._sides.push(bytes32(0)); + return bytes32(0); + } + + /// @dev Same as above, but for memory tree. + function setupMemory(Bytes32PushTree memory self, bytes32 zero) internal pure returns (bytes32 initialRoot) { + self._nextLeafIndex = 0; + self._zeros[0] = zero; + self._zerosLengthMemory = 1; + self._sides[0] = bytes32(0); + self._sidesLengthMemory = 1; + return bytes32(0); + } + + /** + * @dev Resets the tree to a blank state. + * Calling this function on MerkleTree that was already setup and used will reset it to a blank state. + */ + function reset(Bytes32PushTree storage self, bytes32 zero) internal returns (bytes32 initialRoot) { + clear(self); + setup(self, zero); + } + + function clear(Bytes32PushTree storage self) internal { + self._nextLeafIndex = 0; + uint256 length = self._zeros.length; + for (uint256 i = length; 0 < i; --i) { + self._zeros.pop(); + } + length = self._sides.length; + for (uint256 i = length; 0 < i; --i) { + self._sides.pop(); + } + } + + /// @dev Same as above, but for memory tree. + function clearMemory(Bytes32PushTree memory self) internal pure { + self._nextLeafIndex = 0; + uint256 length = self._zerosLengthMemory; + for (uint256 i = length; 0 < i; --i) { + self._zeros[i] = bytes32(0); + } + length = self._sidesLengthMemory; + for (uint256 i = length; 0 < i; --i) { + self._sides[i] = bytes32(0); + } + } + + /** + * @dev Internal function that handles both lazy and non-lazy push operations for storage. + * Returns the index and optionally the new root (if not lazy). + */ + function _pushInner( + Bytes32PushTree storage self, + bytes32 leaf, + bool isLazy + ) internal returns (uint256 index, bytes32 newRoot) { + // Cache read + uint256 levels = self._zeros.length - 1; + + // Get leaf index + // solhint-disable-next-line gas-increment-by-one + index = self._nextLeafIndex++; + + // Check if tree is full. + if (index == 1 << levels) { + bytes32 zero = self._zeros[levels]; + bytes32 newZero = Merkle.efficientHash(zero, zero); + self._zeros.push(newZero); + self._sides.push(bytes32(0)); + ++levels; + } + + // Rebuild branch from leaf to root + uint256 currentIndex = index; + bytes32 currentLevelHash = leaf; + bool updatedSides = false; + for (uint32 i = 0; i < levels; ++i) { + // Reaching the parent node, is currentLevelHash the left child? + bool isLeft = currentIndex % 2 == 0; + + // If so, next time we will come from the right, so we need to save it + if (isLeft && !updatedSides) { + Arrays.unsafeAccess(self._sides, i).value = currentLevelHash; + updatedSides = true; + if (isLazy) { + // Mark that root needs recalculation due to lazy update + self._needsRootRecalculation = true; + // Early return when sides are updated - we don't need to continue + return (index, bytes32(0)); + } + } + + // Compute the current node hash by using the hash function + // with either its sibling (side) or the zero value for that level. + currentLevelHash = Merkle.efficientHash( + isLeft ? currentLevelHash : Arrays.unsafeAccess(self._sides, i).value, + isLeft ? Arrays.unsafeAccess(self._zeros, i).value : currentLevelHash + ); + + // Update node index + currentIndex >>= 1; + } + + Arrays.unsafeAccess(self._sides, levels).value = currentLevelHash; + self._needsRootRecalculation = false; + return (index, currentLevelHash); + } + + /** + * @dev Insert a new leaf in the tree lazily. Returns the position of the inserted leaf in the + * tree. This is the lazy version that updates only the needed side array entry and defers + * root computation until root() is called. + * + * Hashing the leaf before calling this function is recommended as a protection against + * second pre-image attacks. + */ + function pushLazy(Bytes32PushTree storage self, bytes32 leaf) internal returns (uint256 index) { + (index, ) = _pushInner(self, leaf, true); + } + + /** + * @dev Insert a new leaf in the tree, and compute the new root. Returns the position of the inserted leaf in the + * tree, and the resulting root. + * + * Hashing the leaf before calling this function is recommended as a protection against + * second pre-image attacks. + */ + function push(Bytes32PushTree storage self, bytes32 leaf) internal returns (uint256 index, bytes32 newRoot) { + return _pushInner(self, leaf, false); + } + + /** + * @dev Internal function that handles both lazy and non-lazy push operations for memory. + * Returns the index and optionally the new root (if not lazy). + */ + function _pushInnerMemory( + Bytes32PushTree memory self, + bytes32 leaf, + bool isLazy + ) internal pure returns (uint256 index, bytes32 newRoot) { + // Cache read + uint256 levels = self._zerosLengthMemory - 1; + + // Get leaf index + // solhint-disable-next-line gas-increment-by-one + index = self._nextLeafIndex++; + + // Check if tree is full. + if (index == 1 << levels) { + bytes32 zero = self._zeros[levels]; + bytes32 newZero = Merkle.efficientHash(zero, zero); + self._zeros[self._zerosLengthMemory] = newZero; + ++self._zerosLengthMemory; + self._sides[self._sidesLengthMemory] = bytes32(0); + ++self._sidesLengthMemory; + ++levels; + } + + // Rebuild branch from leaf to root + uint256 currentIndex = index; + bytes32 currentLevelHash = leaf; + bool updatedSides = false; + for (uint32 i = 0; i < levels; ++i) { + // Reaching the parent node, is currentLevelHash the left child? + bool isLeft = currentIndex % 2 == 0; + + // If so, next time we will come from the right, so we need to save it + if (isLeft && !updatedSides) { + self._sides[i] = currentLevelHash; + updatedSides = true; + if (isLazy) { + // Mark that root needs recalculation due to lazy update + self._needsRootRecalculation = true; + // Early return when sides are updated - we don't need to continue + return (index, bytes32(0)); + } + // Note: in order to update the sides we should stop here. We continue in order to store the new root. + } + + // Compute the current node hash by using the hash function + // with either its sibling (side) or the zero value for that level. + currentLevelHash = Merkle.efficientHash( + isLeft ? currentLevelHash : self._sides[i], + isLeft ? self._zeros[i] : currentLevelHash + ); + + // Update node index + currentIndex >>= 1; + } + // Note this is overloading the sides array with the root. + self._sides[levels] = currentLevelHash; + self._needsRootRecalculation = false; + return (index, currentLevelHash); + } + + /// @dev Same as above, but for memory tree. + function pushMemory( + Bytes32PushTree memory self, + bytes32 leaf + ) internal pure returns (uint256 index, bytes32 newRoot) { + return _pushInnerMemory(self, leaf, false); + } + + /** + * @dev Insert a new leaf in the memory tree lazily. Returns the position of the inserted leaf in the + * tree. This is the lazy version that updates only the needed side array entry and defers + * root computation until rootMemory() is called. + * + * Hashing the leaf before calling this function is recommended as a protection against + * second pre-image attacks. + */ + function pushLazyMemory(Bytes32PushTree memory self, bytes32 leaf) internal pure returns (uint256 index) { + (index, ) = _pushInnerMemory(self, leaf, true); + } + + /** + * @dev Extend until end. + */ + function extendUntilEnd(Bytes32PushTree storage self, uint256 finalDepth) internal { + bytes32 currentZero = self._zeros[self._zeros.length - 1]; + if (self._nextLeafIndex == 0) { + self._sides[0] = currentZero; + } + bytes32 currentSide = self._sides[self._sides.length - 1]; + for (uint256 i = self._sides.length; i < finalDepth; ++i) { + currentSide = Merkle.efficientHash(currentSide, currentZero); + currentZero = Merkle.efficientHash(currentZero, currentZero); + // at i + self._zeros.push(currentZero); + self._sides.push(currentSide); + } + self._needsRootRecalculation = false; + } + + /// @dev Same as above, but for memory tree. + function extendUntilEndMemory(Bytes32PushTree memory self) internal pure { + bytes32 currentZero = self._zeros[self._zerosLengthMemory - 1]; + if (self._nextLeafIndex == 0) { + self._sides[0] = currentZero; + } + bytes32 currentSide = self._sides[self._sidesLengthMemory - 1]; + uint256 finalDepth = self._sides.length; + for (uint256 i = self._sidesLengthMemory; i < finalDepth; ++i) { + currentSide = Merkle.efficientHash(currentSide, currentZero); + currentZero = Merkle.efficientHash(currentZero, currentZero); + self._zeros[i] = currentZero; + self._sides[i] = currentSide; + } + self._sidesLengthMemory = self._sides.length; + self._zerosLengthMemory = self._zeros.length; + self._needsRootRecalculation = false; + } + + /** + * @dev Recalculate the root from current tree state when lazy updates have been made. + */ + function _recalculateRoot(Bytes32PushTree storage self) internal view returns (bytes32) { + uint256 levels = self._zeros.length - 1; + uint256 leafCount = self._nextLeafIndex; + + if (leafCount == 0) { + return bytes32(0); + } + + uint256 currentIndex = leafCount - 1; + + bytes32 currentLevelHash = Arrays.unsafeAccess(self._sides, 0).value; + + for (uint32 i = 0; i < levels; ++i) { + bool isLeft = (currentIndex % 2) == 0; + + currentLevelHash = Merkle.efficientHash( + isLeft ? currentLevelHash : Arrays.unsafeAccess(self._sides, i).value, + isLeft ? Arrays.unsafeAccess(self._zeros, i).value : currentLevelHash + ); + + currentIndex >>= 1; + } + + return currentLevelHash; + } + + /** + * @dev Tree's root. + */ + function root(Bytes32PushTree storage self) internal returns (bytes32) { + if (self._needsRootRecalculation) { + bytes32 newRoot = _recalculateRoot(self); + Arrays.unsafeAccess(self._sides, self._sides.length - 1).value = newRoot; + self._needsRootRecalculation = false; + return newRoot; + } + return Arrays.unsafeAccess(self._sides, self._sides.length - 1).value; + } + + /** + * @dev Recalculate the root from current tree state when lazy updates have been made. + * This simulates what a complete pushes sequence would have computed. + */ + function _recalculateRootMemory(Bytes32PushTree memory self) internal pure returns (bytes32) { + uint256 levels = self._zerosLengthMemory - 1; + uint256 leafCount = self._nextLeafIndex; + + if (leafCount == 0) { + return bytes32(0); + } + + uint256 currentIndex = leafCount - 1; + + bytes32 currentLevelHash = self._sides[0]; + + for (uint32 i = 0; i < levels; ++i) { + bool isLeft = (currentIndex % 2) == 0; + + currentLevelHash = Merkle.efficientHash( + isLeft ? currentLevelHash : self._sides[i], + isLeft ? self._zeros[i] : currentLevelHash + ); + + currentIndex >>= 1; + } + + return currentLevelHash; + } + + /// @dev Same as above, but for memory tree. + function rootMemory(Bytes32PushTree memory self) internal pure returns (bytes32) { + if (self._needsRootRecalculation) { + bytes32 newRoot = _recalculateRootMemory(self); + self._sides[self._sidesLengthMemory - 1] = newRoot; + self._needsRootRecalculation = false; + return newRoot; + } + return self._sides[self._sidesLengthMemory - 1]; + } + + /** + * @dev Tree's height (does not include the root node). + */ + function height(Bytes32PushTree storage self) internal view returns (uint256) { + return self._sides.length - 1; + } + + /// @dev Same as above, but for memory tree. + function heightMemory(Bytes32PushTree memory self) internal pure returns (uint256) { + return self._sidesLengthMemory - 1; + } +} diff --git a/system-contracts/contracts/libraries/Merkle.sol b/system-contracts/contracts/libraries/Merkle.sol new file mode 100644 index 0000000000..0bdf33d6f8 --- /dev/null +++ b/system-contracts/contracts/libraries/Merkle.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.21; + +// solhint-disable gas-custom-errors + +import {UncheckedMath} from "./UncheckedMath.sol"; +import {MerkleIndexOutOfBounds, MerklePathEmpty, MerklePathOutOfBounds} from "../SystemContractErrors.sol"; + +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +library Merkle { + using UncheckedMath for uint256; + + /// @dev Calculate Merkle root by the provided Merkle proof. + /// NOTE: When using this function, check that the _path length is equal to the tree height to prevent shorter/longer paths attack + /// @param _path Merkle path from the leaf to the root + /// @param _index Leaf index in the tree + /// @param _itemHash Hash of leaf content + /// @return The Merkle root + function calculateRoot( + bytes32[] calldata _path, + uint256 _index, + bytes32 _itemHash + ) internal pure returns (bytes32) { + uint256 pathLength = _path.length; + _validatePathLengthForSingleProof(_index, pathLength); + + bytes32 currentHash = _itemHash; + for (uint256 i; i < pathLength; i = i.uncheckedInc()) { + currentHash = (_index % 2 == 0) + ? efficientHash(currentHash, _path[i]) + : efficientHash(_path[i], currentHash); + _index /= 2; + } + + return currentHash; + } + + /// @dev Calculate Merkle root by the provided Merkle proof. + /// NOTE: When using this function, check that the _path length is equal to the tree height to prevent shorter/longer paths attack + /// @param _path Merkle path from the leaf to the root + /// @param _index Leaf index in the tree + /// @param _itemHash Hash of leaf content + /// @return The Merkle root + function calculateRootMemory( + bytes32[] memory _path, + uint256 _index, + bytes32 _itemHash + ) internal pure returns (bytes32) { + uint256 pathLength = _path.length; + _validatePathLengthForSingleProof(_index, pathLength); + + bytes32 currentHash = _itemHash; + for (uint256 i; i < pathLength; i = i.uncheckedInc()) { + currentHash = (_index % 2 == 0) + ? efficientHash(currentHash, _path[i]) + : efficientHash(_path[i], currentHash); + _index /= 2; + } + + return currentHash; + } + + /// @dev Calculate Merkle root by the provided Merkle proof for a range of elements + /// NOTE: When using this function, check that the _startPath and _endPath lengths are equal to the tree height to prevent shorter/longer paths attack + /// @param _startPath Merkle path from the first element of the range to the root + /// @param _endPath Merkle path from the last element of the range to the root + /// @param _startIndex Index of the first element of the range in the tree + /// @param _itemHashes Hashes of the elements in the range + /// @return The Merkle root + function calculateRootPaths( + bytes32[] memory _startPath, + bytes32[] memory _endPath, + uint256 _startIndex, + bytes32[] memory _itemHashes + ) internal pure returns (bytes32) { + uint256 pathLength = _startPath.length; + require(pathLength == _endPath.length, "Merkle: path length mismatch"); + if (pathLength >= 256) { + revert MerklePathOutOfBounds(); + } + uint256 levelLen = _itemHashes.length; + // Edge case: we want to be able to prove an element in a single-node tree. + if (pathLength == 0 && (_startIndex != 0 || levelLen != 1)) { + revert MerklePathEmpty(); + } + require(levelLen > 0, "Merkle: nothing to prove"); + require(_startIndex + levelLen <= (1 << pathLength), "Merkle: index/height mismatch"); + bytes32[] memory itemHashes = _itemHashes; + + for (uint256 level; level < pathLength; level = level.uncheckedInc()) { + uint256 parity = _startIndex % 2; + // We get an extra element on the next level if on the current level elements either + // start on an odd index (`parity == 1`) or end on an even index (`levelLen % 2 == 1`) + uint256 nextLevelLen = levelLen / 2 + (parity | (levelLen % 2)); + for (uint256 i; i < nextLevelLen; i = i.uncheckedInc()) { + bytes32 lhs = (i == 0 && parity == 1) ? _startPath[level] : itemHashes[2 * i - parity]; + bytes32 rhs = (i == nextLevelLen - 1 && (levelLen - parity) % 2 == 1) + ? _endPath[level] + : itemHashes[2 * i + 1 - parity]; + itemHashes[i] = efficientHash(lhs, rhs); + } + levelLen = nextLevelLen; + _startIndex /= 2; + } + + return itemHashes[0]; + } + + /// @dev Keccak hash of the concatenation of two 32-byte words + function efficientHash(bytes32 _lhs, bytes32 _rhs) internal pure returns (bytes32 result) { + assembly { + mstore(0x00, _lhs) + mstore(0x20, _rhs) + result := keccak256(0x00, 0x40) + } + } + + function _validatePathLengthForSingleProof(uint256 _index, uint256 _pathLength) private pure { + if (_pathLength == 0) { + revert MerklePathEmpty(); + } + if (_pathLength >= 256) { + revert MerklePathOutOfBounds(); + } + if (_index >= (1 << _pathLength)) { + revert MerkleIndexOutOfBounds(); + } + } +} diff --git a/system-contracts/contracts/libraries/Messaging.sol b/system-contracts/contracts/libraries/Messaging.sol new file mode 100644 index 0000000000..6415f5fdc8 --- /dev/null +++ b/system-contracts/contracts/libraries/Messaging.sol @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.21; + +bytes1 constant BUNDLE_IDENTIFIER = 0x01; +bytes1 constant TRIGGER_IDENTIFIER = 0x02; + +/// @dev The enum that represents the transaction execution status +/// @param Failure The transaction execution failed +/// @param Success The transaction execution succeeded +enum TxStatus { + Failure, + Success +} + +/// @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 +/// @param isService A boolean flag that is part of the log along with `key`, `value`, and `sender` address. +/// This field is required formally but does not have any special meaning +/// @param txNumberInBatch The L2 transaction number in a Batch, in which the log was sent +/// @param sender The L2 address which sent the log +/// @param key The 32 bytes of information that was sent in the log +/// @param value The 32 bytes of information that was sent in the log +// Both `key` and `value` are arbitrary 32-bytes selected by the log sender +struct L2Log { + uint8 l2ShardId; + bool isService; + uint16 txNumberInBatch; + address sender; + bytes32 key; + bytes32 value; +} + +/// @dev An arbitrary length message passed from L2 +/// @notice Under the hood it is `L2Log` sent from the special system L2 contract +/// @param txNumberInBatch The L2 transaction number in a Batch, in which the message was sent +/// @param sender The address of the L2 account from which the message was passed +/// @param data An arbitrary length message +struct L2Message { + uint16 txNumberInBatch; + address sender; + bytes data; +} + +/// @dev Internal structure that contains the parameters for the writePriorityOp +/// internal function. +/// @param txId The id of the priority transaction. +/// @param l2GasPrice The gas price for the l2 priority operation. +/// @param expirationTimestamp The timestamp by which the priority operation must be processed by the operator. +/// @param request The external calldata request for the priority operation. +struct WritePriorityOpParams { + uint256 txId; + uint256 l2GasPrice; + uint64 expirationTimestamp; + BridgehubL2TransactionRequest request; +} + +/// @dev Structure that includes all fields of the L2 transaction +/// @dev The hash of this structure is the "canonical L2 transaction hash" and can +/// be used as a unique identifier of a tx +/// @param txType The tx type number, depending on which the L2 transaction can be +/// interpreted differently +/// @param from The sender's address. `uint256` type for possible address format changes +/// and maintaining backward compatibility +/// @param to The recipient's address. `uint256` type for possible address format changes +/// and maintaining backward compatibility +/// @param gasLimit The L2 gas limit for L2 transaction. Analog to the `gasLimit` on an +/// L1 transactions +/// @param gasPerPubdataByteLimit Maximum number of L2 gas that will cost one byte of pubdata +/// (every piece of data that will be stored on L1 as calldata) +/// @param maxFeePerGas The absolute maximum sender willing to pay per unit of L2 gas to get +/// the transaction included in a Batch. Analog to the EIP-1559 `maxFeePerGas` on an L1 transactions +/// @param maxPriorityFeePerGas The additional fee that is paid directly to the validator +/// to incentivize them to include the transaction in a Batch. Analog to the EIP-1559 +/// `maxPriorityFeePerGas` on an L1 transactions +/// @param paymaster The address of the EIP-4337 paymaster, that will pay fees for the +/// transaction. `uint256` type for possible address format changes and maintaining backward compatibility +/// @param nonce The nonce of the transaction. For L1->L2 transactions it is the priority +/// operation Id +/// @param value The value to pass with the transaction +/// @param reserved The fixed-length fields for usage in a future extension of transaction +/// formats +/// @param data The calldata that is transmitted for the transaction call +/// @param signature An abstract set of bytes that are used for transaction authorization +/// @param factoryDeps The set of L2 bytecode hashes whose preimages were shown on L1 +/// @param paymasterInput The arbitrary-length data that is used as a calldata to the paymaster pre-call +/// @param reservedDynamic The arbitrary-length field for usage in a future extension of transaction formats +struct L2CanonicalTransaction { + uint256 txType; + uint256 from; + uint256 to; + uint256 gasLimit; + uint256 gasPerPubdataByteLimit; + uint256 maxFeePerGas; + uint256 maxPriorityFeePerGas; + uint256 paymaster; + uint256 nonce; + uint256 value; + // In the future, we might want to add some + // new fields to the struct. The `txData` struct + // is to be passed to account and any changes to its structure + // would mean a breaking change to these accounts. To prevent this, + // we should keep some fields as "reserved" + // It is also recommended that their length is fixed, since + // it would allow easier proof integration (in case we will need + // some special circuit for preprocessing transactions) + uint256[4] reserved; + bytes data; + bytes signature; + uint256[] factoryDeps; + bytes paymasterInput; + // Reserved dynamic type for the future use-case. Using it should be avoided, + // But it is still here, just in case we want to enable some additional functionality + bytes reservedDynamic; +} + +/// @param sender The sender's address. +/// @param contractAddressL2 The address of the contract on L2 to call. +/// @param valueToMint The amount of base token that should be minted on L2 as the result of this transaction. +/// @param l2Value The msg.value of the L2 transaction. +/// @param l2Calldata The calldata for the L2 transaction. +/// @param l2GasLimit The limit of the L2 gas for the L2 transaction +/// @param l2GasPerPubdataByteLimit The price for a single pubdata byte in L2 gas. +/// @param factoryDeps The array of L2 bytecodes that the tx depends on. +/// @param refundRecipient The recipient of the refund for the transaction on L2. If the transaction fails, then +/// this address will receive the `l2Value`. +// solhint-disable-next-line gas-struct-packing +struct BridgehubL2TransactionRequest { + address sender; + address contractL2; + uint256 mintValue; + uint256 l2Value; + bytes l2Calldata; + uint256 l2GasLimit; + uint256 l2GasPerPubdataByteLimit; + bytes[] factoryDeps; + address refundRecipient; +} + +struct InteropCallStarter { + bool indirectCall; + address nextContract; + bytes data; + uint256 value; + // The value that is requested for the interop call. + // This has to be known beforehand, as the funds in the interop call belong to the user. + // This is because we cannot guarantee atomicity of xL2 txs (just the atimicity of calls on the destination chain) + // So contracts cannot send their own value, only stamp the value that belongs to the user. + uint256 requestedInteropCallValue; +} + +struct InteropCall { + bool indirectCall; + address to; + address from; + uint256 value; + bytes data; +} + +struct InteropBundle { + uint256 sourceChainId; + uint256 destinationChainId; + InteropCall[] calls; + // If not set - anyone can execute it. + address executionAddress; +} + +struct GasFields { + uint256 gasLimit; + uint256 gasPerPubdataByteLimit; + address refundRecipient; + address paymaster; + bytes paymasterInput; +} + +struct InteropTrigger { + uint256 destinationChainId; + address sender; + address recipient; + bytes32 feeBundleHash; + bytes32 executionBundleHash; + GasFields gasFields; +} + +/// @param l2MessageIndex The position in the L2 logs Merkle tree of the l2Log that was sent with the message +struct MessageInclusionProof { + uint256 chainId; + uint256 l1BatchNumber; + uint256 l2MessageIndex; + L2Message message; + bytes32[] proof; +} + +struct LogInclusionProof { + uint256 chainId; + uint256 l1BatchNumber; + uint256 l2LogIndex; + L2Log log; + bytes32[] proof; +} + +struct LeafInclusionProof { + uint256 chainId; + uint256 l1BatchNumber; + uint256 l2LeafProofMask; + bytes32 leaf; + bytes32[] proof; +} + +struct MessageRoot { + uint256 chainId; + uint256 batchNumber; + // We double overloading this. The sides normally contain the root, as well as the sides. So the length is at least 2. + // Second overloading: if the length is 1, we are importing a chainBatchRoot/messageRoot instead of sides. + bytes32[] sides; +} diff --git a/system-contracts/contracts/libraries/UncheckedMath.sol b/system-contracts/contracts/libraries/UncheckedMath.sol new file mode 100644 index 0000000000..a41a9c6ea3 --- /dev/null +++ b/system-contracts/contracts/libraries/UncheckedMath.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +// We use a floating point pragma here so it can be used within other projects that interact with the ZKsync ecosystem without using our exact pragma version. +pragma solidity ^0.8.21; + +/** + * @author Matter Labs + * @custom:security-contact security@matterlabs.dev + * @notice The library for unchecked math. + */ +library UncheckedMath { + function uncheckedInc(uint256 _number) internal pure returns (uint256) { + unchecked { + return _number + 1; + } + } + + function uncheckedAdd(uint256 _lhs, uint256 _rhs) internal pure returns (uint256) { + unchecked { + return _lhs + _rhs; + } + } +} diff --git a/system-contracts/contracts/test-contracts/DummyAssetTracker.sol b/system-contracts/contracts/test-contracts/DummyAssetTracker.sol new file mode 100644 index 0000000000..72dc35cc59 --- /dev/null +++ b/system-contracts/contracts/test-contracts/DummyAssetTracker.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +contract DummyAssetTracker { + address public owner; + + constructor( + uint256 _l1ChainId, + address _bridgehub, + address _assetRouter, + address _nativeTokenVault, + address _messageRoot + ) {} +} diff --git a/system-contracts/contracts/test-contracts/DummyInteropCenter.sol b/system-contracts/contracts/test-contracts/DummyInteropCenter.sol new file mode 100644 index 0000000000..387ecd671f --- /dev/null +++ b/system-contracts/contracts/test-contracts/DummyInteropCenter.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.28; + +contract DummyInteropCenter { + constructor(uint256 _l1ChainId, address _owner) {} +} diff --git a/system-contracts/contracts/test-contracts/DummyInteropHandler.sol b/system-contracts/contracts/test-contracts/DummyInteropHandler.sol new file mode 100644 index 0000000000..1dbb73bc83 --- /dev/null +++ b/system-contracts/contracts/test-contracts/DummyInteropHandler.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {BASE_TOKEN_SYSTEM_CONTRACT, L2_MESSAGE_VERIFICATION} from "../Constants.sol"; +import {BUNDLE_IDENTIFIER, InteropBundle, InteropCall, L2Message, MessageInclusionProof} from "../libraries/Messaging.sol"; + +error MessageNotIncluded(); +error BundleAlreadyExecuted(bytes32 bundleHash); + +/** + * @author Matter Labs + * @custom:security-contact security@matterlabs.dev + * @notice The contract that handles the interop bundles. + */ +contract DummyInteropHandler { + bytes32 public bytecodeHash; + + constructor() {} + + /// @notice The balances of the users. + mapping(bytes32 bundleHash => bool bundleExecuted) public bundleExecuted; + + function executeBundle(bytes memory _bundle, MessageInclusionProof memory _proof) public { + _proof.message.data = bytes.concat(BUNDLE_IDENTIFIER, _bundle); + bool isIncluded = L2_MESSAGE_VERIFICATION.proveL2MessageInclusionShared( + _proof.chainId, + _proof.l1BatchNumber, + _proof.l2MessageIndex, + _proof.message, + _proof.proof + ); + if (!isIncluded) { + revert MessageNotIncluded(); + } + bytes32 bundleHash = keccak256( + abi.encode(_proof.chainId, _proof.l1BatchNumber, _proof.l2MessageIndex, _bundle) + ); + if (bundleExecuted[bundleHash]) { + revert BundleAlreadyExecuted(bundleHash); + } + bundleExecuted[bundleHash] = true; + + InteropBundle memory interopBundle = abi.decode(_bundle, (InteropBundle)); + InteropCall memory baseTokenCall = interopBundle.calls[0]; + + for (uint256 i = 1; i < interopBundle.calls.length; i++) { + InteropCall memory interopCall = interopBundle.calls[i]; + // if (_skipEmptyCalldata && interopCall.data.length == 0) { + // // kl todo: we skip calls in the account validation phase for now, as empty contracts cannot be called. + // BASE_TOKEN_SYSTEM_CONTRACT.mint(interopCall.to, interopCall.value); + // continue; + // } + + // address accountAddress = getAliasedAccount(interopCall.from, _proof.chainId); + // IInteropAccount account = IInteropAccount(payable(accountAddress)); // kl todo add chainId + // uint256 codeSize; + // assembly { + // codeSize := extcodesize(accountAddress) + // } + // if (codeSize == 0) { + // // kl todo use create3. + // address deployedAccount = deployInteropAccount(interopCall.from, _proof.chainId); + // require(address(account) == deployedAccount, "calculated address incorrect"); + // } + + // BASE_TOKEN_SYSTEM_CONTRACT.mint(address(account), interopCall.value); + // account.forwardFromIC(interopCall.to, interopCall.value, interopCall.data); + } + } +} diff --git a/system-contracts/contracts/test-contracts/DummyL2MessageVerification.sol b/system-contracts/contracts/test-contracts/DummyL2MessageVerification.sol new file mode 100644 index 0000000000..f2050ee59d --- /dev/null +++ b/system-contracts/contracts/test-contracts/DummyL2MessageVerification.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {MessageVerification} from "./DummyMessageVerification.sol"; +import {MessageHashing, ProofData} from "./libraries/MessageHashing.sol"; +import {L2_INTEROP_ROOT_STORAGE} from "../Constants.sol"; + +contract DummyL2MessageVerification is MessageVerification { + function _proveL2LeafInclusion( + uint256 _chainId, + uint256 _batchNumber, + uint256 _leafProofMask, + bytes32 _leaf, + bytes32[] calldata _proof + ) internal view override returns (bool) { + ProofData memory proofVerificationResult = MessageHashing.hashProof( + _chainId, + _batchNumber, + _leafProofMask, + _leaf, + _proof + ); + if (proofVerificationResult.finalProofNode) { + bytes32 correctBatchRoot = L2_INTEROP_ROOT_STORAGE.msgRoots(_chainId, _batchNumber); + return correctBatchRoot == proofVerificationResult.batchSettlementRoot; + } + // kl todo think this through. Does it work for the global MessageRoot, and for GW based chains, and both? + return + this.proveL2LeafInclusionShared( + proofVerificationResult.settlementLayerChainId, + proofVerificationResult.settlementLayerBatchNumber, + proofVerificationResult.settlementLayerBatchRootMask, + proofVerificationResult.chainIdLeaf, + MessageHashing.extractSliceUntilEnd(_proof, proofVerificationResult.ptr) + ); + } +} diff --git a/system-contracts/contracts/test-contracts/DummyMessageVerification.sol b/system-contracts/contracts/test-contracts/DummyMessageVerification.sol new file mode 100644 index 0000000000..0b3ef7defa --- /dev/null +++ b/system-contracts/contracts/test-contracts/DummyMessageVerification.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {L2Log, L2Message} from "../libraries/Messaging.sol"; +import {IMessageVerification} from "../interfaces/IMessageVerification.sol"; +import {L1_MESSENGER_CONTRACT, L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH} from "../Constants.sol"; +error HashedLogIsDefault(); + +abstract contract MessageVerification is IMessageVerification { + /// @inheritdoc IMessageVerification + function proveL2MessageInclusionShared( + uint256 _chainId, + uint256 _batchNumber, + uint256 _index, + L2Message calldata _message, + bytes32[] calldata _proof + ) public view returns (bool) { + return _proveL2LogInclusion(_chainId, _batchNumber, _index, _L2MessageToLog(_message), _proof); + } + + /// @inheritdoc IMessageVerification + function proveL2LeafInclusionShared( + uint256 _chainId, + uint256 _batchNumber, + uint256 _leafProofMask, + bytes32 _leaf, + bytes32[] calldata _proof + ) external view override returns (bool) { + return _proveL2LeafInclusion(_chainId, _batchNumber, _leafProofMask, _leaf, _proof); + } + + function _proveL2LeafInclusion( + uint256 _chainId, + uint256 _batchNumber, + uint256 _leafProofMask, + bytes32 _leaf, + bytes32[] calldata _proof + ) internal view virtual returns (bool); + + /// @dev Prove that a specific L2 log was sent in a specific L2 batch number + function _proveL2LogInclusion( + uint256 _chainId, + uint256 _batchNumber, + uint256 _index, + L2Log memory _log, + bytes32[] calldata _proof + ) internal view returns (bool) { + bytes32 hashedLog = keccak256( + // solhint-disable-next-line func-named-parameters + abi.encodePacked(_log.l2ShardId, _log.isService, _log.txNumberInBatch, _log.sender, _log.key, _log.value) + ); + // Check that hashed log is not the default one, + // otherwise it means that the value is out of range of sent L2 -> L1 logs + if (hashedLog == L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH) { + revert HashedLogIsDefault(); + } + + // It is ok to not check length of `_proof` array, as length + // of leaf preimage (which is `L2_TO_L1_LOG_SERIALIZE_SIZE`) is not + // equal to the length of other nodes preimages (which are `2 * 32`) + + // We can use `index` as a mask, since the `localMessageRoot` is on the left part of the tree. + + return _proveL2LeafInclusion(_chainId, _batchNumber, _index, hashedLog, _proof); + } + + /// @dev Convert arbitrary-length message to the raw l2 log + function _L2MessageToLog(L2Message calldata _message) internal pure returns (L2Log memory) { + return + L2Log({ + l2ShardId: 0, + isService: true, + txNumberInBatch: _message.txNumberInBatch, + sender: address(L1_MESSENGER_CONTRACT), + key: bytes32(uint256(uint160(_message.sender))), + value: keccak256(_message.data) + }); + } + + /// @inheritdoc IMessageVerification + function proveL2LogInclusionShared( + uint256 _chainId, + uint256 _batchNumber, + uint256 _index, + L2Log calldata _log, + bytes32[] calldata _proof + ) external view returns (bool) { + return _proveL2LogInclusion(_chainId, _batchNumber, _index, _log, _proof); + } +} diff --git a/system-contracts/contracts/test-contracts/libraries/MessageHashing.sol b/system-contracts/contracts/test-contracts/libraries/MessageHashing.sol new file mode 100644 index 0000000000..83593d3804 --- /dev/null +++ b/system-contracts/contracts/test-contracts/libraries/MessageHashing.sol @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +import {Merkle} from "../../libraries/Merkle.sol"; +import {SUPPORTED_PROOF_METADATA_VERSION} from "../../Constants.sol"; +import {UncheckedMath} from "../../libraries/UncheckedMath.sol"; + +error MerklePathEmpty(); +error UnsupportedProofMetadataVersion(uint256 metadataVersion); +error InvalidProofLengthForFinalNode(); + +bytes32 constant BATCH_LEAF_PADDING = keccak256("zkSync:BatchLeaf"); +bytes32 constant CHAIN_ID_LEAF_PADDING = keccak256("zkSync:ChainIdLeaf"); + +struct ProofData { + uint256 settlementLayerChainId; + uint256 settlementLayerBatchNumber; + uint256 settlementLayerBatchRootMask; + uint256 batchLeafProofLen; + bytes32 batchSettlementRoot; + bytes32 chainIdLeaf; + uint256 ptr; + bool finalProofNode; +} + +library MessageHashing { + using UncheckedMath for uint256; + + /// @dev Returns the leaf hash for a chain with batch number and batch root. + /// @param batchRoot The root hash of the batch. + /// @param batchNumber The number of the batch. + function batchLeafHash(bytes32 batchRoot, uint256 batchNumber) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(BATCH_LEAF_PADDING, batchRoot, batchNumber)); + } + + /// @dev Returns the leaf hash for a chain with chain root and chain id. + /// @param chainIdRoot The root hash of the chain. + /// @param chainId The id of the chain. + function chainIdLeafHash(bytes32 chainIdRoot, uint256 chainId) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(CHAIN_ID_LEAF_PADDING, chainIdRoot, chainId)); + } + + struct ProofMetadata { + uint256 proofStartIndex; + uint256 logLeafProofLen; + uint256 batchLeafProofLen; + bool finalProofNode; + } + + function parseProofMetadata(bytes32[] calldata _proof) internal pure returns (ProofMetadata memory result) { + bytes32 proofMetadata = _proof[0]; + + // We support two formats of the proofs: + // 1. The old format, where `_proof` is just a plain Merkle proof. + // 2. The new format, where the first element of the `_proof` is encoded metadata, which consists of the following: + // - first byte: metadata version (0x01). + // - second byte: length of the log leaf proof (the proof that the log belongs to a batch). + // - third byte: length of the batch leaf proof (the proof that the batch belongs to another settlement layer, if any). + // - the rest of the bytes are zeroes. + // - fourth byte: whether the current proof is the last in the links of recursive proofs for settlement layers. + // + // In the future the old version will be disabled, and only the new version will be supported. + // For now, we need to support both for backwards compatibility. We distinguish between those based on whether the last 28 bytes are zeroes. + // It is safe, since the elements of the proof are hashes and are unlikely to have 28 zero bytes in them. + + // We shift left by 4 bytes = 32 bits to remove the top 32 bits of the metadata. + uint256 metadataAsUint256 = (uint256(proofMetadata) << 32); + + if (metadataAsUint256 == 0) { + // It is the new version + bytes1 metadataVersion = bytes1(proofMetadata); + if (uint256(uint8(metadataVersion)) != SUPPORTED_PROOF_METADATA_VERSION) { + revert UnsupportedProofMetadataVersion(uint256(uint8(metadataVersion))); + } + + result.proofStartIndex = 1; + result.logLeafProofLen = uint256(uint8(proofMetadata[1])); + result.batchLeafProofLen = uint256(uint8(proofMetadata[2])); + result.finalProofNode = uint256(uint8(proofMetadata[3])) != 0; + } else { + // It is the old version + + // The entire proof is a merkle path + result.proofStartIndex = 0; + result.logLeafProofLen = _proof.length; + result.batchLeafProofLen = 0; + result.finalProofNode = true; + } + if (result.finalProofNode && result.batchLeafProofLen != 0) { + revert InvalidProofLengthForFinalNode(); + } + } + + function hashProof( + uint256 _chainId, + uint256 _batchNumber, + uint256 _leafProofMask, + bytes32 _leaf, + bytes32[] calldata _proof + ) internal pure returns (ProofData memory result) { + if (_proof.length == 0) { + revert MerklePathEmpty(); + } + + ProofMetadata memory proofMetadata = MessageHashing.parseProofMetadata(_proof); + result.ptr = proofMetadata.proofStartIndex; + + { + bytes32 batchSettlementRoot = Merkle.calculateRootMemory( + extractSlice(_proof, result.ptr, result.ptr + proofMetadata.logLeafProofLen), + _leafProofMask, + _leaf + ); + result.ptr += proofMetadata.logLeafProofLen; + result.batchSettlementRoot = batchSettlementRoot; + result.finalProofNode = proofMetadata.finalProofNode; + + if (proofMetadata.batchLeafProofLen == 0) { + return result; + } + // Now, we'll have to check that the Gateway included the message. + bytes32 localBatchLeafHash = MessageHashing.batchLeafHash(batchSettlementRoot, _batchNumber); + + uint256 batchLeafProofMask = uint256(bytes32(_proof[result.ptr])); + ++result.ptr; + + bytes32 chainIdRoot = Merkle.calculateRootMemory( + extractSlice(_proof, result.ptr, result.ptr + proofMetadata.batchLeafProofLen), + batchLeafProofMask, + localBatchLeafHash + ); + result.ptr += proofMetadata.batchLeafProofLen; + + result.chainIdLeaf = MessageHashing.chainIdLeafHash(chainIdRoot, _chainId); + } + uint256 settlementLayerChainId; + uint256 settlementLayerBatchNumber; + uint256 settlementLayerBatchRootMask; + // Preventing stack too deep error + { + // Now, we just need to double check whether this chainId leaf was present in the tree. + uint256 settlementLayerPackedBatchInfo = uint256(_proof[result.ptr]); + ++result.ptr; + settlementLayerBatchNumber = uint256(settlementLayerPackedBatchInfo >> 128); + settlementLayerBatchRootMask = uint256(settlementLayerPackedBatchInfo & ((1 << 128) - 1)); + + settlementLayerChainId = uint256(_proof[result.ptr]); + ++result.ptr; + } + + result = ProofData({ + settlementLayerChainId: settlementLayerChainId, + settlementLayerBatchNumber: settlementLayerBatchNumber, + settlementLayerBatchRootMask: settlementLayerBatchRootMask, + batchLeafProofLen: proofMetadata.batchLeafProofLen, + batchSettlementRoot: result.batchSettlementRoot, + chainIdLeaf: result.chainIdLeaf, + ptr: result.ptr, + finalProofNode: proofMetadata.finalProofNode + }); + } + + function extractSlice( + bytes32[] calldata _proof, + uint256 _left, + uint256 _right + ) internal pure returns (bytes32[] memory slice) { + slice = new bytes32[](_right - _left); + for (uint256 i = _left; i < _right; i = i.uncheckedInc()) { + slice[i - _left] = _proof[i]; + } + } + + /// @notice Extracts slice until the end of the array. + /// @dev It is used in one place in order to circumvent the stack too deep error. + function extractSliceUntilEnd( + bytes32[] calldata _proof, + uint256 _start + ) internal pure returns (bytes32[] memory slice) { + slice = extractSlice(_proof, _start, _proof.length); + } +} diff --git a/system-contracts/contracts/test-deps/DIMTLegacyTester.sol b/system-contracts/contracts/test-deps/DIMTLegacyTester.sol new file mode 100644 index 0000000000..f1f3e647fe --- /dev/null +++ b/system-contracts/contracts/test-deps/DIMTLegacyTester.sol @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import {DynamicIncrementalMerkle} from "../libraries/DynamicIncrementalMerkle.sol"; + +/** + * @dev Test contract to verify equivalence between DIMT and legacy L1Messenger MerkleTree + */ +contract DIMTLegacyTester { + using DynamicIncrementalMerkle for DynamicIncrementalMerkle.Bytes32PushTree; + + bytes32 public constant ZERO_HASH = hex"72abee45b59e344af8a6e520241c4744aff26ed411f4c4b00f8af09adada43ba"; + + DynamicIncrementalMerkle.Bytes32PushTree private regularTree; + DynamicIncrementalMerkle.Bytes32PushTree private lazyTree; + DynamicIncrementalMerkle.Bytes32PushTree private mixedTree; + + /** + * @dev Recreates the old L1Messenger MerkleTree root calculation logic + * This mimics the algorithm from the draft-v29 L1Messenger contract + */ + function calculateLegacyMerkleRoot(bytes32[] calldata leaves) public pure returns (bytes32) { + uint256 leavesLength = leaves.length; + + // Legacy L1Messenger uses a fixed tree size of 16384 leaves (2^14) + uint256 targetSize = 16384; // L2_TO_L1_LOGS_MERKLE_TREE_LEAVES + + // Create a working array padded to fixed size with DIMT zero values + bytes32[] memory workingArray = new bytes32[](targetSize); + for (uint256 i = 0; i < leavesLength; ++i) { + workingArray[i] = leaves[i]; + } + // Pad remaining elements with DIMT zero hash (L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH) + for (uint256 i = leavesLength; i < targetSize; ++i) { + workingArray[i] = ZERO_HASH; + } + + uint256 nodesOnCurrentLevel = targetSize; + + // Bottom-up merkle tree construction (only works for power-of-2 trees) + while (nodesOnCurrentLevel > 1) { + nodesOnCurrentLevel /= 2; + for (uint256 i = 0; i < nodesOnCurrentLevel; ++i) { + workingArray[i] = keccak256(abi.encode(workingArray[2 * i], workingArray[2 * i + 1])); + } + } + + return workingArray[0]; + } + + /** + * @dev Calculate DIMT root for given leaves using memory functions + */ + function calculateDIMTRoot(bytes32[] calldata leaves) public pure returns (bytes32) { + DynamicIncrementalMerkle.Bytes32PushTree memory dimtTree = DynamicIncrementalMerkle.Bytes32PushTree({ + _nextLeafIndex: 0, + _sides: new bytes32[](15), + _zeros: new bytes32[](15), + _sidesLengthMemory: 0, + _zerosLengthMemory: 0, + _needsRootRecalculation: false + }); + + dimtTree.setupMemory(ZERO_HASH); + + uint256 leavesLength = leaves.length; + for (uint256 i = 0; i < leavesLength; ++i) { + dimtTree.pushMemory(leaves[i]); + } + + dimtTree.extendUntilEndMemory(); + + return dimtTree.rootMemory(); + } + + /** + * @dev Test equivalence between legacy and DIMT implementations + */ + function testEquivalence( + bytes32[] calldata leaves + ) external pure returns (bool equivalent, bytes32 legacyRoot, bytes32 dimtRoot) { + legacyRoot = calculateLegacyMerkleRoot(leaves); + dimtRoot = calculateDIMTRoot(leaves); + equivalent = (legacyRoot == dimtRoot); + } + + /** + * @dev Batch test multiple leaf configurations + */ + function batchTestEquivalence( + bytes32[][] calldata leafSets + ) external pure returns (bool[] memory equivalences, bytes32[] memory legacyRoots, bytes32[] memory dimtRoots) { + equivalences = new bool[](leafSets.length); + legacyRoots = new bytes32[](leafSets.length); + dimtRoots = new bytes32[](leafSets.length); + + uint256 leafSetsLength = leafSets.length; + for (uint256 i = 0; i < leafSetsLength; ++i) { + bytes32 legacyRoot = calculateLegacyMerkleRoot(leafSets[i]); + bytes32 dimtRoot = calculateDIMTRoot(leafSets[i]); + bool equivalent = (legacyRoot == dimtRoot); + + equivalences[i] = equivalent; + legacyRoots[i] = legacyRoot; + dimtRoots[i] = dimtRoot; + } + } + + /** + * @dev Test lazy functionality by comparing pushLazy + root() vs regular pushes + */ + function testLazyEquivalence(bytes32[] calldata leaves) external returns (bytes32 regularRoot, bytes32 lazyRoot) { + if (leaves.length == 0) { + return (bytes32(0), bytes32(0)); + } + + regularTree.reset(ZERO_HASH); + lazyTree.reset(ZERO_HASH); + + uint256 leavesLength = leaves.length; + + // Regular pushes + for (uint256 i = 0; i < leavesLength; ++i) { + (, regularRoot) = regularTree.push(leaves[i]); + } + // Extend until end before getting root + regularTree.extendUntilEnd(15); + regularRoot = regularTree.root(); + + // Lazy pushes + for (uint256 i = 0; i < leavesLength; ++i) { + lazyTree.pushLazy(leaves[i]); + } + // Need to extend until end before getting root for lazy operations + lazyTree.extendUntilEnd(15); + lazyRoot = lazyTree.root(); + + return (regularRoot, lazyRoot); + } + + /** + * @dev Test mixed lazy and regular operations + */ + function testMixedLazyOperations( + bytes32[] calldata initialLeaves, + bytes32[] calldata lazyLeaves, + bytes32[] calldata finalLeaves + ) external returns (bytes32 regularRoot, bytes32 mixedRoot) { + regularTree.reset(ZERO_HASH); + mixedTree.reset(ZERO_HASH); + + // Regular tree: push all leaves normally + uint256 i; + uint256 initialLeavesLength = initialLeaves.length; + for (i = 0; i < initialLeavesLength; ++i) { + regularTree.push(initialLeaves[i]); + } + uint256 lazyLeavesLength = lazyLeaves.length; + for (i = 0; i < lazyLeavesLength; ++i) { + regularTree.push(lazyLeaves[i]); + } + uint256 finalLeavesLength = finalLeaves.length; + for (i = 0; i < finalLeavesLength; ++i) { + (, regularRoot) = regularTree.push(finalLeaves[i]); + } + // Extend until end before getting root + regularTree.extendUntilEnd(15); + regularRoot = regularTree.root(); + + // Mixed tree: initial pushes, then lazy pushes, then final pushes + for (i = 0; i < initialLeavesLength; ++i) { + mixedTree.push(initialLeaves[i]); + } + for (i = 0; i < lazyLeavesLength; ++i) { + mixedTree.pushLazy(lazyLeaves[i]); + } + for (i = 0; i < finalLeavesLength; ++i) { + (, mixedRoot) = mixedTree.push(finalLeaves[i]); + } + // Ensure any remaining lazy operations are processed + mixedTree.extendUntilEnd(15); + mixedRoot = mixedTree.root(); + + return (regularRoot, mixedRoot); + } +} diff --git a/system-contracts/contracts/L2UpgradeUtils.sol b/system-contracts/contracts/upgrades/L2UpgradeUtils.sol similarity index 97% rename from system-contracts/contracts/L2UpgradeUtils.sol rename to system-contracts/contracts/upgrades/L2UpgradeUtils.sol index f7cd012e01..d2d8ec7ce9 100644 --- a/system-contracts/contracts/L2UpgradeUtils.sol +++ b/system-contracts/contracts/upgrades/L2UpgradeUtils.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.28; -import {SystemContractHelper} from "./libraries/SystemContractHelper.sol"; +import {SystemContractHelper} from "../libraries/SystemContractHelper.sol"; import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol"; diff --git a/system-contracts/contracts/L2V29Upgrade.sol b/system-contracts/contracts/upgrades/L2V29Upgrade.sol similarity index 95% rename from system-contracts/contracts/L2V29Upgrade.sol rename to system-contracts/contracts/upgrades/L2V29Upgrade.sol index b60834a1a0..cb92eb4c06 100644 --- a/system-contracts/contracts/L2V29Upgrade.sol +++ b/system-contracts/contracts/upgrades/L2V29Upgrade.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; -import {SystemContractHelper} from "./libraries/SystemContractHelper.sol"; +import {SystemContractHelper} from "../libraries/SystemContractHelper.sol"; import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; -import {IL2SharedBridgeLegacy} from "./interfaces/IL2SharedBridgeLegacy.sol"; +import {IL2SharedBridgeLegacy} from "../interfaces/IL2SharedBridgeLegacy.sol"; import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol"; import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; import {Ownable2Step} from "@openzeppelin/contracts-v4/access/Ownable2Step.sol"; -import {L2_ASSET_ROUTER, L2_BRIDGE_HUB, L2_CHAIN_ASSET_HANDLER, L2_NATIVE_TOKEN_VAULT} from "./Constants.sol"; -import {IBridgedStandardERC20} from "./interfaces/IBridgedStandardERC20.sol"; -import {LegacyBridgeNotProxy} from "./SystemContractErrors.sol"; -import {IBridgehub} from "./interfaces/IBridgehub.sol"; +import {L2_ASSET_ROUTER, L2_BRIDGE_HUB, L2_CHAIN_ASSET_HANDLER, L2_NATIVE_TOKEN_VAULT} from "../Constants.sol"; +import {IBridgedStandardERC20} from "../interfaces/IBridgedStandardERC20.sol"; +import {LegacyBridgeNotProxy} from "../SystemContractErrors.sol"; +import {IBridgehub} from "../interfaces/IBridgehub.sol"; /// @dev Storage slot with the admin of the contract used for EIP‑1967 proxies (e.g., TUP, BeaconProxy, etc.). bytes32 constant PROXY_ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; @@ -63,7 +63,7 @@ contract L2V29Upgrade { SystemContractHelper.mimicCallWithPropagatedRevert( address(L2_BRIDGE_HUB), owner, - abi.encodeCall(IBridgehub.setChainAssetHandler, (L2_CHAIN_ASSET_HANDLER)) + abi.encodeCall(IBridgehub.setChainAssetHandler, address(L2_CHAIN_ASSET_HANDLER)) ); } diff --git a/system-contracts/package.json b/system-contracts/package.json index 61bbea64a4..fd1b0a3b84 100644 --- a/system-contracts/package.json +++ b/system-contracts/package.json @@ -52,14 +52,14 @@ ] }, "scripts": { - "build": "yarn build:system-contracts && yarn build:bootloader", - "build:foundry": "yarn preprocess:emulator && yarn preprocess:system-contracts && forge build --zksync && yarn preprocess:bootloader && forge build --zksync", + "build": "yarn preprocess:emulator && yarn preprocess:system-contracts && forge build --zksync && yarn preprocess:bootloader && forge build --zksync", + "build:foundry": "yarn build", "build:bootloader": "yarn preprocess:bootloader && yarn compile-yul compile-bootloader", "build:system-contracts": "yarn preprocess:emulator && yarn preprocess:system-contracts && hardhat compile && yarn compile-yul compile-precompiles", "build:test-system-contracts": "yarn preprocess:system-contracts --test-mode && hardhat compile && yarn compile-yul compile-precompiles && yarn compile-zasm", "clean": "yarn clean:bootloader && yarn clean:system-contracts", "clean:bootloader": "rm -rf ./bootloader/build ./bootloader/tests/artifacts", - "clean:system-contracts": "rm -rf ./contracts-preprocessed && hardhat clean", + "clean:system-contracts": "rm -rf ./contracts-preprocessed && hardhat clean && forge clean", "compile-yul": "ts-node scripts/compile-yul.ts", "compile-zasm": "ts-node scripts/compile-zasm.ts", "deploy-preimages": "ts-node scripts/deploy-preimages.ts", diff --git a/system-contracts/scripts/constants.ts b/system-contracts/scripts/constants.ts index 90cb9d991e..a35b163dd7 100644 --- a/system-contracts/scripts/constants.ts +++ b/system-contracts/scripts/constants.ts @@ -265,6 +265,30 @@ export const SYSTEM_CONTRACTS: ISystemContracts = { lang: Language.Solidity, location: SourceLocation.L1Contracts, }, + L2InteropRootStorage: { + address: "0x000000000000000000000000000000000001000b", + codeName: "L2InteropRootStorage", + lang: Language.Solidity, + location: SourceLocation.L1Contracts, + }, + L2InteropCenter: { + // This is explicitly a non-system-contract address. + // We do not use the same address as create2 factories on EVM, since + // this is a zkEVM create2 factory. + address: "0x0000000000000000000000000000000000010008", + codeName: "InteropCenter", + lang: Language.Solidity, + location: SourceLocation.L1Contracts, + }, + L2InteropHandler: { + // This is explicitly a non-system-contract address. + // We do not use the same address as create2 factories on EVM, since + // this is a zkEVM create2 factory. + address: "0x0000000000000000000000000000000000010009", + codeName: "InteropHandler", + lang: Language.Solidity, + location: SourceLocation.L1Contracts, + }, } as const; export const EIP712_TX_ID = 113; diff --git a/system-contracts/scripts/preprocess-bootloader.ts b/system-contracts/scripts/preprocess-bootloader.ts index 6c0e5600e9..c1a4c02d3e 100644 --- a/system-contracts/scripts/preprocess-bootloader.ts +++ b/system-contracts/scripts/preprocess-bootloader.ts @@ -82,6 +82,7 @@ const params = { RIGHT_PADDED_SEND_L2_TO_L1_LOG_SELECTOR: getPaddedSelector("L1Messenger", "sendL2ToL1Log"), PUBLISH_PUBDATA_SELECTOR: getSelector("L1Messenger", "publishPubdataAndClearState"), RIGHT_PADDED_SET_NEW_BATCH_SELECTOR: getPaddedSelector("SystemContext", "setNewBatch"), + RIGHT_PADDED_SET_SETTLEMENT_LAYER_CHAIN_ID_SELECTOR: getPaddedSelector("SystemContext", "setSettlementLayerChainId"), RIGHT_PADDED_OVERRIDE_BATCH_SELECTOR: getPaddedSelector("SystemContext", "unsafeOverrideBatch"), // Error REVERT_ERROR_SELECTOR: padZeroRight(getRevertSelector(), PADDED_SELECTOR_LENGTH), @@ -99,6 +100,7 @@ const params = { SUCCESSFUL_PAYMASTER_VALIDATION_MAGIC_VALUE: getPaddedSelector("IPaymaster", "validateAndPayForPaymasterTransaction"), PUBLISH_COMPRESSED_BYTECODE_SELECTOR: getSelector("Compressor", "publishCompressedBytecode"), GET_MARKER_PADDED_SELECTOR: getPaddedSelector("KnownCodesStorage", "getMarker"), + GET_CODE_SIZE_SELECTOR: getPaddedSelector("AccountCodeStorage", "getCodeSize"), RIGHT_PADDED_SET_L2_BLOCK_SELECTOR: getPaddedSelector("SystemContext", "setL2Block"), RIGHT_PADDED_APPEND_TRANSACTION_TO_L2_BLOCK_SELECTOR: getPaddedSelector( "SystemContext", diff --git a/system-contracts/selectors.sh b/system-contracts/selectors.sh new file mode 100755 index 0000000000..95a7df9b83 --- /dev/null +++ b/system-contracts/selectors.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# Define the directory and output file +CONTRACTS_DIR="./contracts" +OUTPUT_FILE="sysSelectors.txt" + +# Ensure the output file is empty before appending +> "$OUTPUT_FILE" + +# Iterate over all .sol files in the contracts directory +find "$CONTRACTS_DIR" -type f -name "*.sol" | while read -r file; do + if [[ -f $file ]]; then + echo "Processing $file..." + forge selectors list --contracts "$file" >> "$OUTPUT_FILE" + else + echo "No .sol files found in $CONTRACTS_DIR" + fi +done + +echo "Selectors have been written to $OUTPUT_FILE" \ No newline at end of file diff --git a/system-contracts/test/Compressor.spec.ts b/system-contracts/test/Compressor.spec.ts index 184d675c8c..7f793b21d9 100644 --- a/system-contracts/test/Compressor.spec.ts +++ b/system-contracts/test/Compressor.spec.ts @@ -1,5 +1,4 @@ import { expect } from "chai"; -import { BigNumber } from "ethers"; import { ethers, network } from "hardhat"; import type { Wallet } from "zksync-ethers"; import * as zksync from "zksync-ethers"; @@ -188,8 +187,8 @@ describe("Compressor tests", function () { { key: "0x1234567890123456789012345678901234567890123456789012345678901234", index: 0, - initValue: BigNumber.from(0), - finalValue: BigNumber.from("0x1234567890123456789012345678901234567890123456789012345678901234"), + initValue: 0n, + finalValue: 0x1234567890123456789012345678901234567890123456789012345678901234n, }, ]; const encodedStateDiffs = encodeStateDiffs(stateDiffs); @@ -205,8 +204,8 @@ describe("Compressor tests", function () { { key: "0x1234567890123456789012345678901234567890123456789012345678901234", index: 0, - initValue: BigNumber.from(1), - finalValue: BigNumber.from(0), + initValue: 1n, + finalValue: 0n, }, ]; const encodedStateDiffs = encodeStateDiffs(stateDiffs); @@ -222,8 +221,8 @@ describe("Compressor tests", function () { { key: "0x1234567890123456789012345678901234567890123456789012345678901234", index: 1, - initValue: BigNumber.from(1), - finalValue: BigNumber.from(0), + initValue: 1n, + finalValue: 0n, }, ]; const encodedStateDiffs = encodeStateDiffs(stateDiffs); @@ -239,18 +238,18 @@ describe("Compressor tests", function () { { key: "0x1234567890123456789012345678901234567890123456789012345678901234", index: 1, - initValue: BigNumber.from(1), - finalValue: BigNumber.from(0), + initValue: 1n, + finalValue: 0n, }, { key: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", index: 0, - initValue: TWO_IN_256.div(2), - finalValue: TWO_IN_256.sub(2), + initValue: TWO_IN_256 / 2n, + finalValue: TWO_IN_256 - 2n, }, ]; const encodedStateDiffs = encodeStateDiffs(stateDiffs); - stateDiffs[1].finalValue = TWO_IN_256.sub(1); + stateDiffs[1].finalValue = TWO_IN_256 - 1n; const compressedStateDiffs = compressStateDiffs(3, stateDiffs); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(2, 3, encodedStateDiffs, compressedStateDiffs) @@ -262,18 +261,18 @@ describe("Compressor tests", function () { { key: "0x1234567890123456789012345678901234567890123456789012345678901234", index: 255, - initValue: BigNumber.from(1), - finalValue: BigNumber.from(0), + initValue: 1n, + finalValue: 0n, }, { key: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", index: 0, - initValue: TWO_IN_256.div(2), - finalValue: BigNumber.from(1), + initValue: TWO_IN_256 / 2n, + finalValue: 1n, }, ]; const encodedStateDiffs = encodeStateDiffs(stateDiffs); - stateDiffs[1].finalValue = BigNumber.from(0); + stateDiffs[1].finalValue = 0n; const compressedStateDiffs = compressStateDiffs(1, stateDiffs); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(2, 1, encodedStateDiffs, compressedStateDiffs) @@ -285,12 +284,12 @@ describe("Compressor tests", function () { { key: "0x1234567890123456789012345678901234567890123456789012345678901235", index: 255, - initValue: TWO_IN_256.div(2).sub(2), - finalValue: TWO_IN_256.div(2).sub(1), + initValue: TWO_IN_256 / 2n - 2n, + finalValue: TWO_IN_256 / 2n - 1n, }, ]; const encodedStateDiffs = encodeStateDiffs(stateDiffs); - stateDiffs[0].finalValue = TWO_IN_256.div(2); + stateDiffs[0].finalValue = TWO_IN_256 / 2n; const compressedStateDiffs = compressStateDiffs(1, stateDiffs); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(1, 1, encodedStateDiffs, compressedStateDiffs) @@ -302,12 +301,12 @@ describe("Compressor tests", function () { { key: "0x1234567890123456789012345678901234567890123456789012345678901236", index: 0, - initValue: TWO_IN_256.div(4), - finalValue: TWO_IN_256.div(4).sub(5), + initValue: TWO_IN_256 / 4n, + finalValue: TWO_IN_256 / 4n - 5n, }, ]; const encodedStateDiffs = encodeStateDiffs(stateDiffs); - stateDiffs[0].finalValue = TWO_IN_256.div(4).sub(1); + stateDiffs[0].finalValue = TWO_IN_256 / 4n - 1n; const compressedStateDiffs = compressStateDiffs(1, stateDiffs); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(1, 1, encodedStateDiffs, compressedStateDiffs) @@ -319,8 +318,8 @@ describe("Compressor tests", function () { { key: "0x1234567890123456789012345678901234567890123456789012345678901236", index: 0, - initValue: TWO_IN_256.div(4), - finalValue: TWO_IN_256.div(4).sub(5), + initValue: TWO_IN_256 / 4n, + finalValue: TWO_IN_256 / 4n - 5n, }, ]; const encodedStateDiffs = encodeStateDiffs(stateDiffs); @@ -338,22 +337,22 @@ describe("Compressor tests", function () { { key: "0x1234567890123456789012345678901234567890123456789012345678901236", index: 0, - initValue: TWO_IN_256.div(4), - finalValue: TWO_IN_256.div(4).sub(5), + initValue: TWO_IN_256 / 4n, + finalValue: TWO_IN_256 / 4n - 5n, }, { key: "0x1234567890123456789012345678901234567890123456789012345678901239", index: 121, - initValue: TWO_IN_256.sub(1), - finalValue: BigNumber.from(0), + initValue: TWO_IN_256 - 1n, + finalValue: 0n, }, ]; const encodedStateDiffs = encodeStateDiffs(stateDiffs); stateDiffs.push({ key: "0x0234567890123456789012345678901234567890123456789012345678901231", index: 0, - initValue: BigNumber.from(0), - finalValue: BigNumber.from(1), + initValue: 0n, + finalValue: 1n, }); const compressedStateDiffs = compressStateDiffs(1, stateDiffs); await expect( @@ -366,22 +365,22 @@ describe("Compressor tests", function () { { key: "0x1234567890123456789012345678901234567890123456789012345678901236", index: 0, - initValue: TWO_IN_256.div(4), - finalValue: TWO_IN_256.div(4).sub(5), + initValue: TWO_IN_256 / 4n, + finalValue: TWO_IN_256 / 4n - 5n, }, { key: "0x1234567890123456789012345678901234567890123456789012345678901239", index: 121, - initValue: TWO_IN_256.sub(1), - finalValue: BigNumber.from(0), + initValue: TWO_IN_256 - 1n, + finalValue: 0n, }, ]; const encodedStateDiffs = encodeStateDiffs(stateDiffs); stateDiffs.push({ key: "0x0234567890123456789012345678901234567890123456789012345678901231", index: 1, - initValue: BigNumber.from(0), - finalValue: BigNumber.from(1), + initValue: 0n, + finalValue: 1n, }); const compressedStateDiffs = compressStateDiffs(1, stateDiffs); await expect( @@ -394,32 +393,32 @@ describe("Compressor tests", function () { { key: "0x1234567890123456789012345678901234567890123456789012345678901230", index: 0, - initValue: BigNumber.from("0x1234567890123456789012345678901234567890123456789012345678901231"), - finalValue: BigNumber.from("0x1234567890123456789012345678901234567890123456789012345678901230"), + initValue: 0x1234567890123456789012345678901234567890123456789012345678901231n, + finalValue: 0x1234567890123456789012345678901234567890123456789012345678901230n, }, { key: "0x1234567890123456789012345678901234567890123456789012345678901232", index: 1, - initValue: TWO_IN_256.sub(1), - finalValue: BigNumber.from(1), + initValue: TWO_IN_256 - 1n, + finalValue: 1n, }, { key: "0x1234567890123456789012345678901234567890123456789012345678901234", index: 0, - initValue: TWO_IN_256.div(2), - finalValue: BigNumber.from(1), + initValue: TWO_IN_256 / 2n, + finalValue: 1n, }, { key: "0x1234567890123456789012345678901234567890123456789012345678901236", index: 2323, - initValue: BigNumber.from("0x1234567890123456789012345678901234567890123456789012345678901237"), - finalValue: BigNumber.from("0x0239329298382323782378478237842378478237847237237872373272373272"), + initValue: 0x1234567890123456789012345678901234567890123456789012345678901237n, + finalValue: 0x0239329298382323782378478237842378478237847237237872373272373272n, }, { key: "0x1234567890123456789012345678901234567890123456789012345678901238", index: 2, - initValue: BigNumber.from(0), - finalValue: BigNumber.from(1), + initValue: 0n, + finalValue: 1n, }, ]; const encodedStateDiffs = encodeStateDiffs(stateDiffs); diff --git a/system-contracts/test/DIMTLegacyEquivalence.spec.ts b/system-contracts/test/DIMTLegacyEquivalence.spec.ts new file mode 100644 index 0000000000..48373daf9f --- /dev/null +++ b/system-contracts/test/DIMTLegacyEquivalence.spec.ts @@ -0,0 +1,198 @@ +import { expect } from "chai"; +import { ethers } from "hardhat"; +import type { DIMTLegacyTester } from "../typechain"; +import { DIMTLegacyTesterFactory } from "../typechain"; +import { prepareEnvironment } from "./shared/mocks"; +import { deployContractOnAddress, getWallets } from "./shared/utils"; +import type { Wallet } from "zksync-ethers"; + +const TEST_DIMT_TESTER_ADDRESS = "0x0000000000000000000000000000000000009020"; + +describe("DIMT Legacy Equivalence", function () { + let dimtTester: DIMTLegacyTester; + let wallet: Wallet; + + before(async function () { + await prepareEnvironment(); + wallet = getWallets()[0]; + await deployContractOnAddress(TEST_DIMT_TESTER_ADDRESS, "DIMTLegacyTester"); + dimtTester = DIMTLegacyTesterFactory.connect(TEST_DIMT_TESTER_ADDRESS, wallet); + }); + + it("should verify DIMT equivalence with legacy MerkleTree for various tree sizes", async function () { + const testCases = [ + { + name: "2 leaves", + leaves: [ + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("leaf1")), + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("leaf2")), + ], + }, + { + name: "3 leaves", + leaves: [ + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("leaf1")), + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("leaf2")), + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("leaf3")), + ], + }, + { + name: "4 leaves", + leaves: [ + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["leaf", 0])), + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["leaf", 1])), + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["leaf", 2])), + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["leaf", 3])), + ], + }, + { + name: "8 leaves", + leaves: Array.from({ length: 8 }, (_, i) => + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["leaf", i])) + ), + }, + { + name: "12 leaves", + leaves: Array.from({ length: 12 }, (_, i) => + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["leaf", i])) + ), + }, + { + name: "13 leaves", + leaves: Array.from({ length: 13 }, (_, i) => + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["leaf", i])) + ), + }, + { + name: "16 leaves", + leaves: Array.from({ length: 16 }, (_, i) => + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["leaf", i])) + ), + }, + ]; + + for (const testCase of testCases) { + const result = await dimtTester.testEquivalence(testCase.leaves); + const { equivalent, legacyRoot, dimtRoot } = result; + + expect(legacyRoot).to.not.equal(ethers.constants.HashZero); + expect(dimtRoot).to.not.equal(ethers.constants.HashZero); + expect(equivalent).to.equal(true, `Legacy and DIMT should be equivalent for ${testCase.name}`); + } + }); + + it("should demonstrate edge cases for equivalence testing", async function () { + const edgeCases = [ + { + name: "Single leaf", + leaves: [ethers.utils.keccak256(ethers.utils.toUtf8Bytes("single"))], + }, + { + name: "Identical leaves", + leaves: Array(4).fill(ethers.utils.keccak256(ethers.utils.toUtf8Bytes("identical"))), + }, + { + name: "Zero values mixed", + leaves: [ + ethers.constants.HashZero, + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("nonzero1")), + ethers.constants.HashZero, + ethers.utils.keccak256(ethers.utils.toUtf8Bytes("nonzero2")), + ], + }, + ]; + + for (const testCase of edgeCases) { + const result = await dimtTester.testEquivalence(testCase.leaves); + const { equivalent, legacyRoot, dimtRoot } = result; + + expect(legacyRoot).to.not.equal(ethers.constants.HashZero); + expect(dimtRoot).to.not.equal(ethers.constants.HashZero); + expect(equivalent).to.equal(true, `Legacy and DIMT should be equivalent for ${testCase.name}`); + } + }); + + it("should verify lazy push functionality produces identical roots", async function () { + const testCases = [ + { + name: "Small batch", + leaves: Array.from({ length: 3 }, (_, i) => + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["lazy", i])) + ), + }, + { + name: "Medium batch", + leaves: Array.from({ length: 7 }, (_, i) => + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["batch", i])) + ), + }, + { + name: "Large batch", + leaves: Array.from({ length: 15 }, (_, i) => + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["large", i])) + ), + }, + { + name: "Power of 2 batch", + leaves: Array.from({ length: 16 }, (_, i) => + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["pow2", i])) + ), + }, + ]; + + for (const testCase of testCases) { + const result = await dimtTester.testLazyEquivalence(testCase.leaves); + const { regularRoot, lazyRoot } = result; + + expect(regularRoot).to.equal(lazyRoot, `Lazy push failed for ${testCase.name}`); + expect(regularRoot).to.not.equal(ethers.constants.HashZero); + } + }); + + it("should verify mixed lazy and regular operations", async function () { + const initialLeaves = Array.from({ length: 2 }, (_, i) => + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["initial", i])) + ); + const lazyLeaves = Array.from({ length: 5 }, (_, i) => + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["lazy", i])) + ); + const finalLeaves = Array.from({ length: 3 }, (_, i) => + ethers.utils.keccak256(ethers.utils.defaultAbiCoder.encode(["string", "uint256"], ["final", i])) + ); + + const result = await dimtTester.testMixedLazyOperations(initialLeaves, lazyLeaves, finalLeaves); + const { regularRoot, mixedRoot } = result; + + expect(regularRoot).to.equal(mixedRoot, "Mixed lazy operations should produce same root as regular pushes"); + expect(regularRoot).to.not.equal(ethers.constants.HashZero); + }); + + it("should handle edge cases in lazy operations", async function () { + const edgeCases = [ + { + name: "Single lazy leaf", + leaves: [ethers.utils.keccak256(ethers.utils.toUtf8Bytes("single_lazy"))], + }, + { + name: "Empty then lazy", + leaves: [], + }, + { + name: "Many identical lazy leaves", + leaves: Array(10).fill(ethers.utils.keccak256(ethers.utils.toUtf8Bytes("identical_lazy"))), + }, + ]; + + for (const testCase of edgeCases) { + if (testCase.leaves.length === 0) { + // Skip empty array test case for now, there's an issue with the ethers.js binding + continue; + } + + const result = await dimtTester.testLazyEquivalence(testCase.leaves); + const { regularRoot, lazyRoot } = result; + expect(regularRoot).to.equal(lazyRoot, `Lazy edge case failed for ${testCase.name}`); + expect(regularRoot).to.not.equal(ethers.constants.HashZero); + } + }); +}); diff --git a/system-contracts/test/Interop.spec.ts b/system-contracts/test/Interop.spec.ts new file mode 100644 index 0000000000..e27b6cab82 --- /dev/null +++ b/system-contracts/test/Interop.spec.ts @@ -0,0 +1,259 @@ +// import * as hre from "hardhat"; +import { expect } from "chai"; +// import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { ethers, network } from "hardhat"; +import { defaultAbiCoder } from "ethers/lib/utils"; +import type { Wallet } from "zksync-ethers"; +// import * as zksyncV6 from "zksync-ethers-v6"; +import * as zksync from "zksync-ethers"; + +import { serialize } from "zksync-ethers/build/utils"; +import type { DefaultAccount } from "../typechain"; +import { DefaultAccountFactory } from "../typechain"; +import { + TEST_BASE_TOKEN_SYSTEM_CONTRACT_ADDRESS, + TEST_BOOTLOADER_FORMAL_ADDRESS, + REAL_L2_INTEROP_HANDLER_ADDRESS, + TEST_L2_ASSET_ROUTER_ADDRESS, + INTEROP_BUNDLE_ABI, + TEST_ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT_ADDRESS, + REAL_L2_MESSAGE_VERIFICATION_ADDRESS, + REAL_L2_INTEROP_ROOT_STORAGE_ADDRESS, +} from "./shared/constants"; +import { signedTxToTransactionData } from "./shared/transactions"; +import { deployContractOnAddress, getWallets } from "./shared/utils"; +// import { ethers as ethersV5 } from "ethers"; + +// TODO: more test cases can be added. +describe("Interop tests", function () { + let wallet: Wallet; + let bootloaderAccount: ethers.Signer; + + let defaultAccount: DefaultAccount; + let account: Wallet; + const RANDOM_ADDRESS = ethers.utils.getAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); + + before("Interop", async () => { + wallet = getWallets()[0]; + account = getWallets()[2]; + await deployContractOnAddress(account.address, "DefaultAccount"); + defaultAccount = DefaultAccountFactory.connect(account.address, wallet); + + await deployContractOnAddress(TEST_ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT_ADDRESS, "AccountCodeStorage", false); + + await deployContractOnAddress(REAL_L2_INTEROP_HANDLER_ADDRESS, "DummyInteropHandler", false); + + await deployContractOnAddress(REAL_L2_MESSAGE_VERIFICATION_ADDRESS, "DummyL2MessageVerification", false); + + await deployContractOnAddress(REAL_L2_INTEROP_ROOT_STORAGE_ADDRESS, "L2InteropRootStorage", false); + + await deployContractOnAddress(TEST_BASE_TOKEN_SYSTEM_CONTRACT_ADDRESS, "L2BaseToken"); + // console.log("kl todo 6"); + await deployContractOnAddress( + TEST_L2_ASSET_ROUTER_ADDRESS, + "DummyL2AssetRouter", + true, + defaultAbiCoder.encode( + ["uint256", "address", "address", "bytes32", "uint256"], + [1, RANDOM_ADDRESS, RANDOM_ADDRESS, ethers.constants.HashZero, 1] + ) + ); + + bootloaderAccount = await ethers.getImpersonatedSigner(TEST_BOOTLOADER_FORMAL_ADDRESS); + }); + + it("successfully executed interop 1.5", async () => { + // const hexTx = + // "0x71f91c8405840bebc200840bebc2008423c3460094000000000000000000000000000000000001000980b90ea0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000005c00000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001040000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000001000d0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000008001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000100030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000003249c884fd1000000000000000000000000000000000000000000000000000000000000010f0da2e607b35983d2ec75e38816c18f823db0015bdc7065e49e63526ed3dbfe15000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000001cc222598e0c44430e08bd3ea0f5a3bd8b210ddf0000000000000000000000008adcd7e93d2b402c92e3ef611ca52a4d780434fb000000000000000000000000550dde671fd8c05d217ba3ffa7375f600d80c17f000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c101000000000000000000000000000000000000000000000000000000000000010f000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000007546f6b656e204100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002414100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008c00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010f000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000006800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001040000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000001000d0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000800a0000000000000000000000000000000000000000000000000000000000008001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000100030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000003249c884fd1000000000000000000000000000000000000000000000000000000000000010f0da2e607b35983d2ec75e38816c18f823db0015bdc7065e49e63526ed3dbfe15000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000001cc222598e0c44430e08bd3ea0f5a3bd8b210ddf0000000000000000000000008adcd7e93d2b402c92e3ef611ca52a4d780434fb000000000000000000000000550dde671fd8c05d217ba3ffa7375f600d80c17f000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c101000000000000000000000000000000000000000000000000000000000000010f000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000007546f6b656e20410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000241410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010010f000100000000000000000000000000000000000000000000000000000000f2502b72a0cb8a3e2798e8ac7c05dcdfd3c2a12544bbb5a9619bf00379894c615ded0fef81852eab61f6160e073806bebb560962fa5d614a552e42f218300cade3697c7f33c31a9b0f0aeb8542287d0d21e8c4cf82163d0c44c7a98aa11aa111199cc5812543ddceeddd0fc82807646a4899444240db2c0d2f20c3cceb5f51fae4733f281f18ba3ea8775dd62d2fcd84011c8c938f16ea5790fd29a03bf8db891798a1fd9c8fbb818c98cff190daa7cc10b6e5ac9716b4a2649f7c2ebcef227266d7c5983afe44cf15ea8cf565b34c6c31ff0cb4dd744524f7842b942d08770db04e5ee349086985f74b73971ce9dfe76bbed95c84906c5dffd96504e1e5396cac506ecb5465659b3a927143f6d724f91d8d9c4bdb2463aee111d9aa869874db124b05ec272cecd7538fdafe53b6628d31188ffb6f345139aac3c3c1fd2e470fc3be9cbd19304d84cca3d045e06b8db3acd68c304fc9cd4cbffe6d18036cb13ffef7bd9f889811e59e4076a0174087135f080177302763019adaf531257e3a87a707d1c62d8be699d34cb74804fdd7b4c568b6c1a821066f126c680d4b83e00bf6e093070e0389d2e529d60fadb855fdded54976ec50ac709e3a36ceaa64c291e4ed1ec13a28c40715db6399f6f99ce04e5f19d60ad3ff6831f098cb6cf75944820104808082010494000000000000000000000000000000000001000d820320c0b90d80000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000001cc222598e0c44430e08bd3ea0f5a3bd8b210ddf00000000000000000000000000000000000000000000000000000000000008600000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001040000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000001000d0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000800a000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000000000000000000000000002c68af0bb140000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008adcd7e93d2b402c92e3ef611ca52a4d780434fb0000000000000000000000001cc222598e0c44430e08bd3ea0f5a3bd8b210ddf00000000000000000000000000000000000000000000000002c68af0bb1400000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010f000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001040000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000001000d0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000800a000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000000000000000000000000002c68af0bb140000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008adcd7e93d2b402c92e3ef611ca52a4d780434fb0000000000000000000000001cc222598e0c44430e08bd3ea0f5a3bd8b210ddf00000000000000000000000000000000000000000000000002c68af0bb140000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010010f0001000000000000000000000000000000000000000000000000000000006e14c83984bf7a98c7443f92bd8a02dc01c9e62f79730e344c411ec8a16502765ded0fef81852eab61f6160e073806bebb560962fa5d614a552e42f218300cade3697c7f33c31a9b0f0aeb8542287d0d21e8c4cf82163d0c44c7a98aa11aa111199cc5812543ddceeddd0fc82807646a4899444240db2c0d2f20c3cceb5f51fae4733f281f18ba3ea8775dd62d2fcd84011c8c938f16ea5790fd29a03bf8db891798a1fd9c8fbb818c98cff190daa7cc10b6e5ac9716b4a2649f7c2ebcef227266d7c5983afe44cf15ea8cf565b34c6c31ff0cb4dd744524f7842b942d08770db04e5ee349086985f74b73971ce9dfe76bbed95c84906c5dffd96504e1e5396cac506ecb5465659b3a927143f6d724f91d8d9c4bdb2463aee111d9aa869874db124b05ec272cecd7538fdafe53b6628d31188ffb6f345139aac3c3c1fd2e470fc3be9cbd19304d84cca3d045e06b8db3acd68c304fc9cd4cbffe6d18036cb13ffef7bd9f889811e59e4076a0174087135f080177302763019adaf531257e3a87a707d1c62d8be699d34cb74804fdd7b4c568b6c1a821066f126c680d4b83e00bf6e093070e0389d2e529d60fadb855fdded54976ec50ac709e3a36ceaa64c291e4ed1ec13a28c40715db6399f6f99ce04e5f19d60ad3ff6831f098cb6cf7594400000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010f000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010008000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001040000000000000000000000001cc222598e0c44430e08bd3ea0f5a3bd8b210ddf000000000000000000000000000000000000000000000000000000000001000d39a2043688bb787ee7cf74d27211a5708748616513ce9dac0e17bdd1b072235667aa94840ae5cd8b080927ddad599bde72e56a4f3911df7043c808ce868c78ac00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000023c3460000000000000000000000000000000000000000000000000000000000000003200000000000000000000000001cc222598e0c44430e08bd3ea0f5a3bd8b210ddf000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010010f00010000000000000000000000000000000000000000000000000000000072abee45b59e344af8a6e520241c4744aff26ed411f4c4b00f8af09adada43bad8f2e335ad06a7ca3fe043719eb330cfaf3945b6fb042559d0fa675b240c035de3697c7f33c31a9b0f0aeb8542287d0d21e8c4cf82163d0c44c7a98aa11aa111199cc5812543ddceeddd0fc82807646a4899444240db2c0d2f20c3cceb5f51fae4733f281f18ba3ea8775dd62d2fcd84011c8c938f16ea5790fd29a03bf8db891798a1fd9c8fbb818c98cff190daa7cc10b6e5ac9716b4a2649f7c2ebcef227266d7c5983afe44cf15ea8cf565b34c6c31ff0cb4dd744524f7842b942d08770db04e5ee349086985f74b73971ce9dfe76bbed95c84906c5dffd96504e1e5396cac506ecb5465659b3a927143f6d724f91d8d9c4bdb2463aee111d9aa869874db124b05ec272cecd7538fdafe53b6628d31188ffb6f345139aac3c3c1fd2e470fc3be9cbd19304d84cca3d045e06b8db3acd68c304fc9cd4cbffe6d18036cb13ffef7bd9f889811e59e4076a0174087135f080177302763019adaf531257e3a87a707d1c62d8be699d34cb74804fdd7b4c568b6c1a821066f126c680d4b83e00bf6e093070e0389d2e529d60fadb855fdded54976ec50ac709e3a36ceaa64c291e4ed1ec13a28c40715db6399f6f99ce04e5f19d60ad3ff6831f098cb6cf75944d694000000000000000000000000000000000000000080"; + // const legacyTx = await account.populateTransaction({ + // type: 0, + // to: REAL_L2_INTEROP_HANDLER_ADDRESS, + // from: account.address, + // nonce: await account.getNonce(), + // data: "0x", + // value: 0, + // gasLimit: 50000, + // }); + // const txBytes = await account.signTransaction(legacyTx); + // const parsedTx = await zksync.utils.parseTransaction(txBytes); + // const parsedTx2 = await zksyncV6.utils.parseEip712(txBytes); + // const hexTx = zksync.utils.serialize(interopTx); + // await broadcastTransaction(hexTx, account.provider); + // await (account.provider as any).broadcastTransaction(hexTx); + }); + + // function calculateInteropTxData() { + // const interopTxString = ["tuple(address to, address from, bytes data, uint256 value)"]; + + // const paymasterBundle = defaultAbiCoder.encode(interopTxString, [ + // { to: RANDOM_ADDRESS, from: account.address, data: RANDOM_ADDRESS, value: 10000000000000000000n }, + // ]); + // const l2AssetRouterString = + // "0x9c884fd100000000000000000000000000000000000000000000000000000000000001109c0d4add1b94fd348199e854b0efbc68c1ec865016908282cfa32b5c02a69606000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000001a36f9dbffc50cd7c7d5ccec1ce3232d1f08280b0000000000000000000000008da7cffaf1eab3bce2817d0c20ef5cd7ce82455a00000000000000000000000060d16f709e9179f961d5786f8d035e337990971f0000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c1010000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004574254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000457425443000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000"; + // const l2AssetRouterData = ethers.utils.arrayify(l2AssetRouterString); + // // console.log("kl todo l2AssetRouterData", l2AssetRouterData) + // // const call = defaultAbiCoder.encode(interopTxString, [ + // // { to: TEST_L2_ASSET_ROUTER_ADDRESS, from: TEST_L2_ASSET_ROUTER_ADDRESS, data: l2AssetRouterData, value: 0 }, + // // ]); + // const executionBundle = defaultAbiCoder.encode( + // [INTEROP_BUNDLE_ABI], + // [ + // { + // destinationChainId: 1, + // calls: [ + // { + // to: TEST_L2_ASSET_ROUTER_ADDRESS, + // from: TEST_L2_ASSET_ROUTER_ADDRESS, + // data: l2AssetRouterData, + // value: 10000, + // }, + // ], + // executionAddresses: [ethers.constants.AddressZero], + // cancellationAddress: ethers.constants.AddressZero, + // }, + // ] + // ); + // // console.log("kl todo executionBundle length", executionBundle.length) + // // console.log("kl todo executionBundle", executionBundle) + // interopTxData = defaultAbiCoder.encode(["bytes", "bytes"], [paymasterBundle, executionBundle]); + // // let [feeBytes, execBytes] = defaultAbiCoder.decode(["bytes", "bytes"], interopTxData) + // // console.log(feeBytes, execBytes) + // // const interopBundle = defaultAbiCoder.decode([INTEROP_BUNDLE_ABI], execBytes) + // // console.log(interopBundle) + // // console.log(interopBundle[0].executionAddresses) + // // console.log(interopBundle[0].calls) + // } + + after(async function () { + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [TEST_BOOTLOADER_FORMAL_ADDRESS], + }); + }); + + // it("successfully executed interop", async () => { + // const legacyTx = await account.populateTransaction({ + // type: 0, + // to: TEST_L2_INTEROP_HANDLER_ADDRESS, + // from: account.address, + // nonce: 111, + // data: ethers.utils.arrayify(interopTxData), + // value: 0, + // gasLimit: 50000, + // }); + // const txBytes = await account.signTransaction(legacyTx); + // const parsedTx = zksync.utils.parseTransaction(txBytes); + // const txData = signedTxToTransactionData(parsedTx)!; + // console.log(txData); + + // const txHash = parsedTx.hash; + // delete legacyTx.from; + // const signedHash = ethers.utils.keccak256(serialize(legacyTx)); + + // await expect(await defaultAccount.connect(bootloaderAccount).executeTransaction(txHash, signedHash, txData)); + // // .to.emit(TEST_L2_ASSET_ROUTER_ADDRESS, "Called") + // // .withArgs("0xdeadbeef"); + // }); + + it.skip("successfully executed interop 2", async () => { + const data = ethers.arrayify( + "0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000022000000000000000000000000000000000000000000000000000000000000001c0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001f900000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000800a00000000000000000000000000000000000000000000000000000000000080010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000826bd95eac751efac2e72071688726559137f82a0000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001f900000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000ba00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000007200000000000000000000000000000000000000000000000000000000000000820000000000000000000000000000000000000000000000000000000000000800a000000000000000000000000000000000000000000000000000000000000800100000000000000000000000000000000000000000000000002c68af0bb14000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000100030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000003249c884fd1000000000000000000000000000000000000000000000000000000000000010fdf39940cb1a0afc5250040a5804f8ff7bc140ebf2e75f256e7c459012845b4a3000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000826bd95eac751efac2e72071688726559137f82a000000000000000000000000826bd95eac751efac2e72071688726559137f82a0000000000000000000000009a81a024873e01c4e337e044065016ac60eca97b000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001c101000000000000000000000000000000000000000000000000000000000000010f000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000007546f6b656e20410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000241410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c3fa32a3cb219b21aff6d019573f953447ed5d8000000000000000000000000826bd95eac751efac2e72071688726559137f82a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000002a628cc3659a7c82a6c8ca1e9e933e1676cf3865000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000000000000000000000000000000000000000000000000000000000002a628cc3659a7c82a6c8ca1e9e933e1676cf3865000000000000000000000000826bd95eac751efac2e72071688726559137f82a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000002494b918de000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000000000000000000000000000000000000000000000000000000000009a81a024873e01c4e337e044065016ac60eca97b000000000000000000000000826bd95eac751efac2e72071688726559137f82a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000000000000000000000000000000000000001000400000000000000000000000000000000000000000000000002c68af0bb140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010002000000000000000000000000826bd95eac751efac2e72071688726559137f82a00000000000000000000000000000000000000000000000002c68af0bb1400000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000022424fd57fb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000010f00000000000000000000000000000000000000000000000002c68af0bb14000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c9c3800000000000000000000000000000000000000000000000000000000000000320000000000000000000000000826bd95eac751efac2e72071688726559137f82a00000000000000000000000000000000000000000000000000000000000100030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a101ef75419b62712bace2de51cafa88b81ac028336312b659447726542afa5d8f0d00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000016345785d8a0000000000000000000000000000826bd95eac751efac2e72071688726559137f82a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" + ); + // console.log(data) + const [feeBytes, execBytes] = defaultAbiCoder.decode(["bytes", "bytes"], data); + // console.log(feeBytes, execBytes); + const interopBundle = defaultAbiCoder.decode([INTEROP_BUNDLE_ABI], execBytes); + const feeBundle = defaultAbiCoder.decode([INTEROP_BUNDLE_ABI], feeBytes); + // console.log("exec bundle", interopBundle); + // console.log("feeBundle", feeBundle); + // console.log("exec address", interopBundle[0].executionAddresses) + // console.log("exec calls", interopBundle[0].calls); + // console.log("fee calls", feeBundle[0].calls); + const reencoded = defaultAbiCoder.encode([INTEROP_BUNDLE_ABI], interopBundle); + const reencodedFee = defaultAbiCoder.encode([INTEROP_BUNDLE_ABI], feeBundle); + // console.log(reencoded); + const reencodedComplete = defaultAbiCoder.encode(["bytes", "bytes"], [reencodedFee, reencoded]); + // console.log("reencoded", reencodedComplete); + // console.log("number of calls", interopBundle[0].calls.length); + for (const call of interopBundle[0].calls) { + // console.log(call.from); + const from = BigInt(0x1111000000000000000000000000000000000000) + BigInt(call.from) + BigInt(0x1111); + // console.log("0x" + from.toString(16)); + await deployContractOnAddress("0x" + from.toString(16), "DefaultAccount"); + } + + const legacyTx = await account.populateTransaction({ + type: 0, + to: REAL_L2_INTEROP_HANDLER_ADDRESS, + from: account.address, + nonce: await account.getNonce(), + data: reencodedComplete, + value: 0, + gasLimit: 50000, + }); + + const txBytes = await account.signTransaction(legacyTx); + const parsedTx = zksync.utils.parseTransaction(txBytes); + const txData = signedTxToTransactionData(parsedTx)!; + + const txHash = parsedTx.hash; + delete legacyTx.from; + const signedHash = ethers.keccak256(serialize(legacyTx)); + + await expect(await defaultAccount.connect(bootloaderAccount).executeTransaction(txHash, signedHash, txData)); + }); +}); + +// async function broadcastTransaction(signedTx: string, provider: zksync.Provider): Promise { +// const { blockNumber, hash } = await ethersV5.utils.resolveProperties({ +// blockNumber: provider.getBlockNumber(), +// hash: _perform( +// { +// method: "broadcastTransaction", +// signedTransaction: signedTx, +// }, +// provider +// ), +// network: provider.getNetwork(), +// }); + +// const tx = ethers.Transaction.from(signedTx); +// if (tx.hash !== hash) { +// throw new Error("@TODO: the returned hash did not match!"); +// } + +// // eslint-disable-next-line @typescript-eslint/no-explicit-any +// return this._wrapTransactionResponse(tx).replaceableTransaction(blockNumber); +// } + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +// async function _perform(req: ethers.PerformActionRequest, provider: zksync.Provider): Promise { +// // Legacy networks do not like the type field being passed along (which +// // is fair), so we delete type if it is 0 and a non-EIP-1559 network +// if (req.method === "call" || req.method === "estimateGas") { +// const tx = req.transaction; +// if (tx && tx.type != null && ethers.getBigInt(tx.type)) { +// // If there are no EIP-1559 or newer properties, it might be pre-EIP-1559 +// if (tx.maxFeePerGas == null && tx.maxPriorityFeePerGas == null) { +// const feeData = await provider.getFeeData(); +// if (feeData.maxFeePerGas == null && feeData.maxPriorityFeePerGas == null) { +// // Network doesn't know about EIP-1559 (and hence type) +// req = Object.assign({}, req, { +// transaction: Object.assign({}, tx, { type: undefined }), +// }); +// } +// } +// } +// } + +// const request = { +// method: "eth_sendRawTransaction", +// args: [req.signedTransaction], +// }; + +// if (request != null) { +// return await provider.send(request.method, request.args); +// } + +// // return provider._perform(req); +// } diff --git a/system-contracts/test/shared/constants.ts b/system-contracts/test/shared/constants.ts index 1c404a97ef..e3619f94d2 100644 --- a/system-contracts/test/shared/constants.ts +++ b/system-contracts/test/shared/constants.ts @@ -1,5 +1,3 @@ -import { BigNumber } from "ethers"; - export const TEST_BOOTLOADER_FORMAL_ADDRESS = "0x0000000000000000000000000000000000009001"; export const TEST_ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000009002"; export const TEST_NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000009003"; @@ -15,10 +13,12 @@ export const TEST_BOOTLOADER_UTILITIES_ADDRESS = "0x0000000000000000000000000000 export const TEST_COMPRESSOR_CONTRACT_ADDRESS = "0x000000000000000000000000000000000000900e"; export const TEST_COMPLEX_UPGRADER_CONTRACT_ADDRESS = "0x000000000000000000000000000000000000900f"; export const TEST_PUBDATA_CHUNK_PUBLISHER_ADDRESS = "0x0000000000000000000000000000000000009011"; -export const TEST_L2_GENESIS_UPGRADE_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000010001"; export const TEST_EVM_PREDEPLOYS_MANAGER = "0x0000000000000000000000000000000000009014"; export const TEST_EVM_HASHES_STORAGE = "0x0000000000000000000000000000000000009015"; +export const TEST_L2_GENESIS_UPGRADE_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000010001"; +export const TEST_L2_ASSET_ROUTER_ADDRESS = "0x0000000000000000000000000000000000010003"; + // event writer should be on the original address because event logs are filtered by address export const REAL_EVENT_WRITER_CONTRACT_ADDRESS = "0x000000000000000000000000000000000000800d"; export const REAL_DEPLOYER_SYSTEM_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000008006"; @@ -36,10 +36,16 @@ export const REAL_BRIDGEHUB_ADDRESS = "0x000000000000000000000000000000000001000 export const REAL_L2_ASSET_ROUTER_ADDRESS = "0x0000000000000000000000000000000000010003"; export const REAL_L2_NATIVE_TOKEN_VAULT_ADDRESS = "0x0000000000000000000000000000000000010004"; export const REAL_L2_MESSAGE_ROOT_ADDRESS = "0x0000000000000000000000000000000000010005"; +export const REAL_L2_INTEROP_ROOT_STORAGE_ADDRESS = "0x0000000000000000000000000000000000010008"; +export const REAL_L2_MESSAGE_VERIFICATION_ADDRESS = "0x0000000000000000000000000000000000010009"; export const REAL_L2_CHAIN_ASSET_HANDLER_ADDRESS = "0x000000000000000000000000000000000001000a"; +export const REAL_L2_INTEROP_CENTER_ADDRESS = "0x000000000000000000000000000000000001000c"; +export const REAL_L2_INTEROP_HANDLER_ADDRESS = "0x000000000000000000000000000000000001000d"; +export const REAL_L2_ASSET_TRACKER_ADDRESS = "0x000000000000000000000000000000000001000e"; +export const REAL_L2_STANDARD_TRIGGER_ACCOUNT_ADDRESS = "0x000000000000000000000000000000000001000F"; export const EMPTY_STRING_KECCAK = "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; -export const TWO_IN_256 = BigNumber.from(2).pow(256); +export const TWO_IN_256 = 2n ** 256n; export const ONE_BYTES32_HEX = "0x0000000000000000000000000000000000000000000000000000000000000001"; export const ADDRESS_ONE = "0x0000000000000000000000000000000000000001"; @@ -52,3 +58,22 @@ export const EC_PAIRING_ADDRESS = "0x0000000000000000000000000000000000000008"; export const SERVICE_CALL_PSEUDO_CALLER = "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF"; export const PROXY_ADMIN_SLOT = "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103"; + +// export const BRIDGEHUB_L2_CANONICAL_TRANSACTION_ABI = +// "tuple(uint256 txType, uint256 from, uint256 to, uint256 gasLimit, uint256 gasPerPubdataByteLimit, uint256 maxFeePerGas, uint256 maxPriorityFeePerGas, uint256 paymaster, uint256 nonce, uint256 value, uint256[4] reserved, bytes data, bytes signature, uint256[] factoryDeps, bytes paymasterInput, bytes reservedDynamic)"; +// export const BRIDGEHUB_L2_TRANSACTION_REQUEST_ABI = +// "tuple(address sender, address contractL2, uint256 mintValue, uint256 l2Value, bytes l2Calldata, uint256 l2GasLimit, uint256 l2GasPerPubdataByteLimit, bytes[] factoryDeps, address refundRecipient)"; +// export const L2_LOG_STRING = +// "tuple(uint8 l2ShardId,bool isService,uint16 txNumberInBatch,address sender,bytes32 key,bytes32 value)"; +// export const ARTIFACTS_PATH = "../../../contracts/l1-contracts/out/"; +// export const SYSTEM_ARTIFACTS_PATH = "../../../contracts/system-contracts/zkout/"; + +// export const INTEROP_TRIGGER_ABI = +// "tuple(uint256 destinationChainId, address from, address recipient,bytes32 feeBundleHash, bytes32 executionBundleHash, tuple(uint256 gasLimit, uint256 gasPerPubdataByteLimit, address refundRecipient, address paymaster, bytes paymasterInput) gasFields)"; + +// export const INTEROP_CALL_ABI = "tuple(address to, address from, uint256 value, bytes data)"; +export const INTEROP_BUNDLE_ABI = + "tuple(uint256 destinationChainId, tuple(address to, address from, uint256 value, bytes data)[] calls, address executionAddress)"; + +// export const MESSAGE_INCLUSION_PROOF_ABI = +// "tuple(uint256 chainId, uint256 l1BatchNumber, uint256 l2MessageIndex, tuple(uint16 txNumberInBatch, address sender, bytes data) message, bytes32[] proof)"; diff --git a/system-contracts/test/shared/mocks.ts b/system-contracts/test/shared/mocks.ts index 8e38ba278d..40624d1216 100644 --- a/system-contracts/test/shared/mocks.ts +++ b/system-contracts/test/shared/mocks.ts @@ -16,6 +16,10 @@ import { TEST_PUBDATA_CHUNK_PUBLISHER_ADDRESS, REAL_BRIDGEHUB_ADDRESS, REAL_L2_MESSAGE_ROOT_ADDRESS, + REAL_L2_INTEROP_CENTER_ADDRESS, + REAL_L2_INTEROP_HANDLER_ADDRESS, + REAL_L2_NATIVE_TOKEN_VAULT_ADDRESS, + REAL_L2_ASSET_TRACKER_ADDRESS, } from "./constants"; import { deployContractOnAddress, getWallets, loadArtifact } from "./utils"; @@ -46,6 +50,10 @@ const TEST_SYSTEM_CONTRACTS_MOCKS = { IBridgehub: REAL_BRIDGEHUB_ADDRESS, // For similar reasons we mock the L2 message real root only for simplicity IMessageRoot: REAL_L2_MESSAGE_ROOT_ADDRESS, + IInteropCenter: REAL_L2_INTEROP_CENTER_ADDRESS, + IInteropHandler: REAL_L2_INTEROP_HANDLER_ADDRESS, + IL2NativeTokenVault: REAL_L2_NATIVE_TOKEN_VAULT_ADDRESS, + IL2AssetTracker: REAL_L2_ASSET_TRACKER_ADDRESS, }; // Deploys mocks, and cleans previous call results during deployments. diff --git a/system-contracts/test/shared/utils.ts b/system-contracts/test/shared/utils.ts index 56d1ee47e8..82019dc5a4 100644 --- a/system-contracts/test/shared/utils.ts +++ b/system-contracts/test/shared/utils.ts @@ -1,3 +1,5 @@ +import * as fs from "fs"; + import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; import type { ZkSyncArtifact } from "@matterlabs/hardhat-zksync-deploy/dist/types"; import { BigNumber } from "ethers"; @@ -95,6 +97,12 @@ export function loadZasmBytecode(codeName: string, path: string): string { }); } +// Read contract artifacts +export function readContract(path: string, fileName: string, contractName?: string) { + contractName = contractName || fileName; + return JSON.parse(fs.readFileSync(`${path}/${fileName}.sol/${contractName}.json`, { encoding: "utf-8" })); +} + // eslint-disable-next-line @typescript-eslint/no-explicit-any export async function deployContract(name: string, constructorArguments?: any[] | undefined): Promise { const artifact = await loadArtifact(name); @@ -133,10 +141,11 @@ export async function deployContractOnAddress( address: string, name: string, callConstructor: boolean = true, - input = "0x" + input = "0x", + artifact?: ZkSyncArtifact ) { - const artifact = await loadArtifact(name); - await setCode(address, artifact.bytecode, callConstructor, input); + const artifactLoaded = artifact || (await loadArtifact(name)); + await setCode(address, artifactLoaded.bytecode, callConstructor, input); } export async function publishBytecode(bytecode: BytesLike) { @@ -194,8 +203,8 @@ export async function setConstructingCodeHash(address: string, bytecode: string) export interface StateDiff { key: BytesLike; index: number; - initValue: BigNumber; - finalValue: BigNumber; + initValue: bigint; + finalValue: bigint; } export function encodeStateDiffs(stateDiffs: StateDiff[]): string { @@ -224,35 +233,40 @@ export function compressStateDiffs(enumerationIndexSize: number, stateDiffs: Sta const initial = []; const repeated = []; for (const stateDiff of stateDiffs) { - const addition = stateDiff.finalValue.sub(stateDiff.initValue).add(TWO_IN_256).mod(TWO_IN_256); - const subtraction = stateDiff.initValue.sub(stateDiff.finalValue).add(TWO_IN_256).mod(TWO_IN_256); + const addition = (stateDiff.finalValue - stateDiff.initValue + TWO_IN_256) % TWO_IN_256; + const subtraction = (stateDiff.initValue - stateDiff.finalValue + TWO_IN_256) % TWO_IN_256; let op = 3; let min = stateDiff.finalValue; - if (addition.lt(min)) { + if (addition < min) { min = addition; op = 1; } - if (subtraction.lt(min)) { + if (subtraction < min) { min = subtraction; op = 2; } - if (min.gte(BigNumber.from(2).pow(248))) { + if (min >= 2n ** 248n) { min = stateDiff.finalValue; op = 0; } let len = 0; - const minHex = min.eq(0) ? "0x" : min.toHexString(); + const minHex = min === 0n ? "0x00" : "0x" + (min.toString(16).length % 2 === 1 ? "0" : "") + min.toString(16); if (op > 0) { len = (minHex.length - 2) / 2; } const metadata = (len << 3) + op; if (stateDiff.index === 0) { numInitial += 1; - initial.push(ethers.utils.solidityPack(["bytes32", "uint8", "bytes"], [stateDiff.key, metadata, minHex])); + initial.push( + ethers.utils.solidityPack(["bytes32", "uint8", "bytes"], [stateDiff.key, metadata, BigNumber.from(minHex)]) + ); } else { const enumerationIndexType = "uint" + (enumerationIndexSize * 8).toString(); repeated.push( - ethers.utils.solidityPack([enumerationIndexType, "uint8", "bytes"], [stateDiff.index, metadata, minHex]) + ethers.utils.solidityPack( + [enumerationIndexType, "uint8", "bytes"], + [stateDiff.index, metadata, BigNumber.from(minHex)] + ) ); } }