diff --git a/.eslintrc b/.eslintrc index 077931cae..d8474e32a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -11,6 +11,7 @@ "no-console": "off" }, "ignorePatterns": [ - "**/lib/*" + "**/lib/*", + "lib/*" ] } diff --git a/.github/workflows/build-release.yaml b/.github/workflows/build-release.yaml index 2335b74fb..b4292e5e3 100644 --- a/.github/workflows/build-release.yaml +++ b/.github/workflows/build-release.yaml @@ -22,6 +22,15 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ inputs.commit }} + submodules: recursive + + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH - name: Use Node.js uses: actions/setup-node@v3 @@ -35,11 +44,24 @@ jobs: yarn echo "release_tag=${{ inputs.prefix }}-${{ inputs.commit }}" >> $GITHUB_OUTPUT - - name: Build contracts + - name: Build l1 contracts + working-directory: l1-contracts + run: | + forge build + + - name: Build l2 contracts + working-directory: l2-contracts + run: | + forge build --zksync --zk-enable-eravm-extensions + + - name: Build system-contracts + working-directory: system-contracts run: | - yarn l1 build - yarn l2 build - yarn sc build + yarn install + yarn preprocess:system-contracts + forge build --zksync --zk-enable-eravm-extensions + yarn preprocess:bootloader + forge build --zksync --zk-enable-eravm-extensions - name: Prepare artifacts run: | diff --git a/.github/workflows/l1-contracts-ci.yaml b/.github/workflows/l1-contracts-ci.yaml index 2123b47cb..5a27c65f8 100644 --- a/.github/workflows/l1-contracts-ci.yaml +++ b/.github/workflows/l1-contracts-ci.yaml @@ -3,6 +3,11 @@ name: L1 contracts CI on: pull_request: +# We need this permissions for this CI to work with external contributions +permissions: + contents: read + pull-requests: write + jobs: build: runs-on: ubuntu-latest @@ -10,6 +15,16 @@ jobs: steps: - name: Checkout the repository uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH - name: Use Node.js uses: actions/setup-node@v3 @@ -17,26 +32,25 @@ jobs: node-version: 18.18.0 cache: yarn - - name: Install dependencies - run: yarn - - - name: Build artifacts - run: yarn l1 build + - name: Build l1 contracts + working-directory: l1-contracts + run: | + forge build - - name: Build L2 artifacts - run: yarn l2 build + - name: Build l2 contracts + working-directory: l2-contracts + run: | + forge build --zksync --zk-enable-eravm-extensions - name: Create cache uses: actions/cache/save@v3 with: key: artifacts-l1-${{ github.sha }} path: | - l1-contracts/artifacts - l1-contracts/cache - l1-contracts/typechain - l2-contracts/artifacts-zk - l2-contracts/cache-zk - l2-contracts/typechain + l1-contracts/cache-forge + l1-contracts/out + l2-contracts/cache-forge + l2-contracts/zkout lint: runs-on: ubuntu-latest @@ -67,15 +81,19 @@ jobs: with: submodules: recursive - - name: Use Foundry - uses: foundry-rs/foundry-toolchain@v1 - - name: Use Node.js uses: actions/setup-node@v3 with: node-version: 18.18.0 cache: yarn + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH - name: Install dependencies run: yarn @@ -123,7 +141,7 @@ jobs: l2-contracts/typechain - name: Run tests - run: yarn l1 test --no-compile + run: yarn l1 test check-verifier-generator: runs-on: ubuntu-latest @@ -145,3 +163,78 @@ jobs: - name: Compare run: diff tools/data/Verifier.sol l1-contracts/contracts/state-transition/Verifier.sol + + coverage: + defaults: + run: + working-directory: l1-contracts + needs: [build, lint] + runs-on: ubuntu-latest + + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: 18.18.0 + cache: yarn + + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH + + - name: Install dependencies + run: yarn + + - name: Restore artifacts cache + uses: actions/cache/restore@v3 + with: + fail-on-cache-miss: true + key: artifacts-l1-${{ github.sha }} + path: | + l1-contracts/artifacts + l1-contracts/cache + l1-contracts/typechain + + - name: Run coverage + run: FOUNDRY_PROFILE=default yarn test:foundry && FOUNDRY_PROFILE=default yarn coverage:foundry --report summary --report lcov + + # To ignore coverage for certain directories modify the paths in this step as needed. The + # below default ignores coverage results for the test and script directories. Alternatively, + # to include coverage in all directories, comment out this step. Note that because this + # filtering applies to the lcov file, the summary table generated in the previous step will + # still include all files and directories. + # The `--rc lcov_branch_coverage=1` part keeps branch info in the filtered report, since lcov + # defaults to removing branch info. + - name: Filter directories + run: | + sudo apt update && sudo apt install -y lcov + lcov --remove lcov.info 'test/*' 'contracts/dev-contracts/*' '../lib/forge-std/*' '../lib/murky/*' 'lib/*' '../lib/*' 'lib/' --output-file lcov.info --rc lcov_branch_coverage=1 + + # This step posts a detailed coverage report as a comment and deletes previous comments on + # each push. The below step is used to fail coverage if the specified coverage threshold is + # not met. The below step can post a comment (when it's `github-token` is specified) but it's + # not as useful, and this action cannot fail CI based on a minimum coverage threshold, which + # is why we use both in this way. + - name: Post coverage report + if: github.event_name == 'pull_request' # This action fails when ran outside of a pull request. + uses: romeovs/lcov-reporter-action@v0.3.1 + with: + delete-old-comments: true + lcov-file: ./l1-contracts/lcov.info + github-token: ${{ secrets.GITHUB_TOKEN }} # Adds a coverage summary comment to the PR. + + - name: Verify minimum coverage + uses: zgosalvez/github-actions-report-lcov@v2 + with: + coverage-files: ./l1-contracts/lcov.info + working-directory: l1-contracts + minimum-coverage: 85 # Set coverage threshold. diff --git a/.github/workflows/l1-contracts-foundry-ci.yaml b/.github/workflows/l1-contracts-foundry-ci.yaml deleted file mode 100644 index 02c551d63..000000000 --- a/.github/workflows/l1-contracts-foundry-ci.yaml +++ /dev/null @@ -1,117 +0,0 @@ -name: L1 contracts foundry CI - -env: - ANVIL_PRIVATE_KEY: "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" - ANVIL_RPC_URL: "http://127.0.0.1:8545" - -on: - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout the repository - uses: actions/checkout@v4 - with: - submodules: true - - - name: Use Foundry - uses: foundry-rs/foundry-toolchain@v1 - - - name: Use Node.js - uses: actions/setup-node@v4 - with: - node-version: 18.18.0 - cache: yarn - - - name: Install dependencies - run: yarn - - - name: Build artifacts - working-directory: ./l1-contracts - run: forge build - - - name: Build system-contract artifacts - run: yarn sc build - - - name: Create cache - uses: actions/cache/save@v3 - with: - key: artifacts-l1-contracts-foudry-${{ github.sha }} - path: | - l1-contracts/cache - l1-contracts/out - system-contracts/artifacts-zk - system-contracts/bootloader/build - system-contracts/cache-zk - system-contracts/contracts-preprocessed - system-contracts/typechain - - scripts: - runs-on: ubuntu-latest - needs: build - steps: - - name: Checkout the repository - uses: actions/checkout@v4 - with: - submodules: true - - - name: Restore artifacts cache - uses: actions/cache/restore@v3 - with: - fail-on-cache-miss: true - key: artifacts-l1-contracts-foudry-${{ github.sha }} - path: | - l1-contracts/cache - l1-contracts/out - system-contracts/artifacts-zk - system-contracts/bootloader/build - system-contracts/cache-zk - system-contracts/contracts-preprocessed - system-contracts/typechain - - - name: Use Foundry - uses: foundry-rs/foundry-toolchain@v1 - - - name: Copy configs from template - working-directory: ./l1-contracts - run: cp -r deploy-script-config-template script-config - - - name: Run anvil - run: | - anvil --silent & - - ANVIL_READY=0 - for i in {1..10}; do - if curl -s -o /dev/null $ANVIL_RPC_URL -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"eth_chainId","id":1}'; then - echo "Anvil is ready" - ANVIL_READY=1 - break - else - echo "Waiting for Anvil to become ready..." - sleep 1 - fi - done - - if [ $ANVIL_READY -ne 1 ]; then - echo "Anvil failed to become ready after 10 attempts." - exit 1 - fi - - - name: Run DeployL1 script - working-directory: ./l1-contracts - run: forge script ./deploy-scripts/DeployL1.s.sol --ffi --rpc-url $ANVIL_RPC_URL --broadcast --private-key $ANVIL_PRIVATE_KEY - - - name: Run DeployErc20 script - working-directory: ./l1-contracts - run: forge script ./deploy-scripts/DeployErc20.s.sol --ffi --rpc-url $ANVIL_RPC_URL --broadcast --private-key $ANVIL_PRIVATE_KEY -# TODO restore scripts verification -# - name: Run RegisterHyperchain script -# working-directory: ./l1-contracts -# run: | -# cat ./script-out/output-deploy-l1.toml >> ./script-config/register-hyperchain.toml -# forge script ./deploy-scripts/RegisterHyperchain.s.sol --ffi --rpc-url $ANVIL_RPC_URL --broadcast --private-key $ANVIL_PRIVATE_KEY -# - name: Run InitializeL2WethToken script -# working-directory: ./l1-contracts-foundry -# run: forge script ./deploy-scripts/InitializeL2WethToken.s.sol --ffi --rpc-url $ANVIL_RPC_URL --broadcast --private-key $ANVIL_PRIVATE_KEY diff --git a/.github/workflows/l2-contracts-ci.yaml b/.github/workflows/l2-contracts-ci.yaml index 20bb9583f..e19ac376b 100644 --- a/.github/workflows/l2-contracts-ci.yaml +++ b/.github/workflows/l2-contracts-ci.yaml @@ -10,6 +10,16 @@ jobs: steps: - name: Checkout the repository uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH - name: Use Node.js uses: actions/setup-node@v3 @@ -20,23 +30,25 @@ jobs: - name: Install dependencies run: yarn - - name: Build L1 artifacts - run: yarn l1 build + - name: Build l1 contracts + working-directory: l1-contracts + run: | + forge build - - name: Build L2 artifacts - run: yarn l2 build + - name: Build l2 contracts + working-directory: l2-contracts + run: | + forge build --zksync --zk-enable-eravm-extensions - name: Create cache uses: actions/cache/save@v3 with: - key: artifacts-l2-${{ github.sha }} + key: artifacts-l1-${{ github.sha }} path: | - l1-contracts/artifacts - l1-contracts/cache - l1-contracts/typechain - l2-contracts/artifacts-zk - l2-contracts/cache-zk - l2-contracts/typechain + l1-contracts/cache-forge + l1-contracts/out + l2-contracts/cache-forge + l2-contracts/zkout lint: runs-on: ubuntu-latest diff --git a/.github/workflows/slither.yaml b/.github/workflows/slither.yaml index fa253e159..50c9194dc 100644 --- a/.github/workflows/slither.yaml +++ b/.github/workflows/slither.yaml @@ -27,13 +27,18 @@ jobs: with: python-version: 3.8 + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH + - name: Install Slither run: | pip install slither-analyzer - - name: Use Foundry - uses: foundry-rs/foundry-toolchain@v1 - - name: Remove non-compiled files run: | rm -rf ./l1-contracts/contracts/state-transition/utils/ @@ -43,6 +48,6 @@ jobs: rm -rf ./l1-contracts/contracts/dev-contracts/test/VerifierRecursiveTest.sol - name: Run Slither + working-directory: l1-contracts run: | - cd l1-contracts slither --config ./slither.config.json . diff --git a/.github/workflows/system-contracts-ci.yaml b/.github/workflows/system-contracts-ci.yaml index f842214d6..d1338983e 100644 --- a/.github/workflows/system-contracts-ci.yaml +++ b/.github/workflows/system-contracts-ci.yaml @@ -10,6 +10,16 @@ jobs: steps: - name: Checkout the repository uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH - name: Use Node.js uses: actions/setup-node@v3 @@ -17,22 +27,28 @@ jobs: node-version: 18.18.0 cache: yarn - - name: Install dependencies - run: yarn - - name: Build artifacts - run: yarn sc build + working-directory: system-contracts + run: | + yarn install + yarn preprocess:system-contracts + forge build --zksync --zk-enable-eravm-extensions + yarn preprocess:bootloader + forge build --zksync --zk-enable-eravm-extensions + yarn build - name: Create cache uses: actions/cache/save@v3 with: key: artifacts-system-${{ github.sha }} path: | + system-contracts/zkout + system-contracts/cache-forge + system-contracts/bootloader/build system-contracts/artifacts-zk system-contracts/cache-zk system-contracts/typechain system-contracts/contracts-preprocessed - system-contracts/bootloader/build lint: runs-on: ubuntu-latest @@ -72,11 +88,13 @@ jobs: fail-on-cache-miss: true key: artifacts-system-${{ github.sha }} path: | + system-contracts/zkout + system-contracts/cache-forge + system-contracts/bootloader/build system-contracts/artifacts-zk system-contracts/cache-zk system-contracts/typechain system-contracts/contracts-preprocessed - system-contracts/bootloader/build - name: Run bootloader tests run: | @@ -111,11 +129,13 @@ jobs: fail-on-cache-miss: true key: artifacts-system-${{ github.sha }} path: | + system-contracts/zkout + system-contracts/cache-forge + system-contracts/bootloader/build system-contracts/artifacts-zk system-contracts/cache-zk system-contracts/typechain system-contracts/contracts-preprocessed - system-contracts/bootloader/build - name: Run tests run: yarn sc test @@ -123,35 +143,3 @@ jobs: - name: Print output logs of era_test_node if: always() run: cat era_test_node.log - - check-hashes: - needs: [build] - runs-on: ubuntu-latest - - steps: - - name: Checkout the repository - uses: actions/checkout@v4 - - - name: Use Node.js - uses: actions/setup-node@v3 - with: - node-version: 18.18.0 - cache: yarn - - - name: Install dependencies - run: yarn - - - name: Restore artifacts cache - uses: actions/cache/restore@v3 - with: - fail-on-cache-miss: true - key: artifacts-system-${{ github.sha }} - path: | - system-contracts/artifacts-zk - system-contracts/cache-zk - system-contracts/typechain - system-contracts/contracts-preprocessed - system-contracts/bootloader/build - - - name: Check hashes - run: yarn sc calculate-hashes:check diff --git a/.gitignore b/.gitignore index 63f96063b..21c173828 100644 --- a/.gitignore +++ b/.gitignore @@ -24,5 +24,7 @@ l1-contracts/coverage/* l1-contracts/out/* l1-contracts/broadcast/* l1-contracts/script-config/* +!l1-contracts/script-config/artifacts l1-contracts/script-out/* !l1-contracts/script-out/.gitkeep +*.timestamp diff --git a/.gitmodules b/.gitmodules index 5cbc631ba..3451bd884 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,14 +1,14 @@ -[submodule "l1-contracts/lib/forge-std"] - path = l1-contracts/lib/forge-std - url = https://github.com/foundry-rs/forge-std -[submodule "l1-contracts/lib/murky"] - path = l1-contracts/lib/murky +[submodule "lib/murky"] + path = lib/murky url = https://github.com/dmfxyz/murky -[submodule "l1-contracts/lib/openzeppelin-contracts-upgradeable"] - path = l1-contracts/lib/openzeppelin-contracts-upgradeable +[submodule "lib/openzeppelin-contracts-upgradeable-v4"] + path = lib/openzeppelin-contracts-upgradeable-v4 url = https://github.com/Openzeppelin/openzeppelin-contracts-upgradeable branch = release-v4.9 -[submodule "l1-contracts/lib/openzeppelin-contracts"] - path = l1-contracts/lib/openzeppelin-contracts +[submodule "lib/openzeppelin-contracts-v4"] + path = lib/openzeppelin-contracts-v4 url = https://github.com/Openzeppelin/openzeppelin-contracts branch = release-v4.9 +[submodule "lib/forge-std"] + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std diff --git a/.markdownlintignore b/.markdownlintignore index 5abdcbeb3..cffb39f9c 100644 --- a/.markdownlintignore +++ b/.markdownlintignore @@ -2,7 +2,6 @@ node_modules # l1-contracts -l1-contracts/lib l1-contracts/node_modules # l1-contracts-foundry @@ -14,3 +13,8 @@ l2-contracts/node_modules # system-contracts system-contracts/node_modules system-contracts/bootloader/test_infra/target + +l1-contracts/lib +lib/ +l2-contracts/lib +system-contracts/lib diff --git a/.prettierignore b/.prettierignore index 5bc4f9aa7..0c2a4c4dc 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,6 +1,7 @@ tools/data l1-contracts/lib l1-contracts-foundry/lib +lib system-contracts/contracts/openzeppelin system-contracts/contracts/Constants.sol system-contracts/artifacts-zk @@ -10,3 +11,6 @@ l1-contracts/cache l1-contracts/cache-forge l1-contracts/artifacts l1-contracts/artifacts-forge +l1-contracts/zkout +l2-contracts/zkout +system-contracts/zkout diff --git a/.solhint.json b/.solhint.json index 617a892bf..ef3522c45 100644 --- a/.solhint.json +++ b/.solhint.json @@ -1,31 +1,40 @@ { "extends": "solhint:recommended", "rules": { - "state-visibility": "off", - "func-visibility": ["warn", { "ignoreConstructors": true }], - "var-name-mixedcase": "off", - "avoid-call-value": "off", - "no-empty-blocks": "off", - "not-rely-on-time": "off", + "avoid-call-value": "error", "avoid-low-level-calls": "off", - "no-inline-assembly": "off", + "avoid-sha3": "error", + "check-send-result": "error", + "compiler-version": ["error", "^0.8.0"], "const-name-snakecase": "off", - "no-complex-fallback": "off", - "reason-string": "off", + "contract-name-camelcase": "off", + "gas-calldata-parameters": "error", + "gas-custom-errors": "error", + "gas-increment-by-one": "error", + "gas-length-in-loops": "error", + "gas-struct-packing": "error", + "explicit-types": "error", "func-name-mixedcase": "off", - "custom-errors": "off", - "no-unused-vars": "error", + "func-named-parameters": ["error", 4], + "func-visibility": ["error", { "ignoreConstructors": true }], + "imports-on-top": "error", "max-states-count": "off", + "modifier-name-mixedcase": "error", + "named-parameters-mapping": "off", + "no-complex-fallback": "off", + "no-console": "error", + "no-empty-blocks": "off", "no-global-import": "error", + "no-inline-assembly": "off", "no-unused-import": "error", - "explicit-types": "error", - "modifier-name-mixedcase": "error", - "imports-on-top": "error", + "no-unused-vars": "error", + "not-rely-on-time": "off", "quotes": "error", - "use-forbidden-name": "error", - "visibility-modifier-order": "error", + "reason-string": "error", "reentrancy": "error", - "func-named-parameters": ["error", 4], - "compiler-version": ["error", "^0.8.0"] + "state-visibility": "error", + "use-forbidden-name": "error", + "var-name-mixedcase": "off", + "visibility-modifier-order": "error" } } diff --git a/.solhintignore b/.solhintignore index ec8271f7e..abcb64f98 100644 --- a/.solhintignore +++ b/.solhintignore @@ -6,6 +6,8 @@ l1-contracts/cache l1-contracts/cache-forge l1-contracts/lib l1-contracts/node_modules +l1-contracts/contracts/dev-contracts +l1-contracts/test # l1-contracts-foundry l1-contracts-foundry/cache @@ -18,3 +20,12 @@ l2-contracts/node_modules # system-contracts system-contracts/contracts/openzeppelin system-contracts/contracts/Constants.sol +system-contracts/contracts/test-contracts +system-contracts/contracts-preprocessed + +# gas-bound-caller +gas-bound-caller + +lib/* +l2-contracts/lib +system-contracts/lib diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dd3d45842..46bdeebac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,7 +34,7 @@ We aim to make it as easy as possible to contribute to the mission. This is stil and suggestions here too. Some resources to help: 1. [In-repo docs aimed at developers](docs) -2. [zkSync Era docs!](https://era.zksync.io/docs/) +2. [ZKsync Era docs!](https://era.zksync.io/docs/) 3. Company links can be found in the [repo's readme](README.md) ## Code of Conduct diff --git a/README.md b/README.md index 6e3e06aba..cc1425b5b 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -# zkSync Era: Smart Contracts +# ZKsync Era: Smart Contracts [![Logo](eraLogo.svg)](https://zksync.io/) -zkSync Era is a layer 2 rollup that uses zero-knowledge proofs to scale Ethereum without compromising on security or +ZKsync Era is a layer 2 rollup that uses zero-knowledge proofs to scale Ethereum without compromising on security or decentralization. Since it's EVM compatible (Solidity/Vyper), 99% of Ethereum projects can redeploy without refactoring -or re-auditing a single line of code. zkSync Era also uses an LLVM-based compiler that will eventually let developers +or re-auditing a single line of code. ZKsync Era also uses an LLVM-based compiler that will eventually let developers write smart contracts in C++, Rust and other popular languages. -This repository contains both L1 and L2 zkSync smart contracts. For their description see the +This repository contains both L1 and L2 ZKsync smart contracts. For their description see the [system overview](docs/Overview.md). ## Disclaimer @@ -17,7 +17,7 @@ others may not. ## License -zkSync Era contracts are distributed under the terms of the MIT license. +ZKsync Era contracts are distributed under the terms of the MIT license. See [LICENSE-MIT](LICENSE-MIT) for details. @@ -33,7 +33,7 @@ See [LICENSE-MIT](LICENSE-MIT) for details. ## Disclaimer -zkSync Era has been through lots of testing and audits. Although it is live, it is still in alpha state and will go +ZKsync Era has been through lots of testing and audits. Although it is live, it is still in alpha state and will go through more audits and bug bounties programs. We would love to hear our community's thoughts and suggestions about it! It is important to state that forking it now can potentially lead to missing important security updates, critical features, and performance improvements. diff --git a/_typos.toml b/_typos.toml index 54e99fdf1..b2c7c85c8 100644 --- a/_typos.toml +++ b/_typos.toml @@ -5,6 +5,7 @@ extend-exclude = [ "/l1-contracts/out/", "/l1-contracts/node_modules/", "/l1-contracts/artifacts", + "/l1-contracts-foundry/lib/", "/l2-contracts/artifacts-zk", "/l2-contracts/cache-zk", "/l2-contracts/typechain", diff --git a/docs/Overview.md b/docs/Overview.md index 6af3d407d..1db994729 100644 --- a/docs/Overview.md +++ b/docs/Overview.md @@ -1,6 +1,6 @@ # Overview -zkSync Era is a permissionless general-purpose ZK rollup. Similar to many L1 blockchains and sidechains it enables +ZKsync Era is a permissionless general-purpose ZK rollup. Similar to many L1 blockchains and sidechains it enables deployment and interaction with Turing-complete smart contracts. - L2 smart contracts are executed on a zkEVM. @@ -10,7 +10,7 @@ deployment and interaction with Turing-complete smart contracts. - There is no escape hatch mechanism yet, but there will be one. All data that is needed to restore the L2 state are also pushed on-chain. There are two approaches, publishing inputs of -L2 transactions on-chain and publishing the state transition diff. zkSync follows the second option. +L2 transactions on-chain and publishing the state transition diff. ZKsync follows the second option. See the [documentation](https://era.zksync.io/docs/dev/fundamentals/rollups.html) to read more! @@ -25,13 +25,13 @@ See the [documentation](https://era.zksync.io/docs/dev/fundamentals/rollups.html L2 blocks. - **Facet** - implementation contract. The word comes from the EIP-2535. - **Gas** - a unit that measures the amount of computational effort required to execute specific operations on the - zkSync Era network. + ZKsync Era network. ### L1 Smart contracts #### Diamond -Technically, this L1 smart contract acts as a connector between Ethereum (L1) and zkSync (L2). This contract checks the +Technically, this L1 smart contract acts as a connector between Ethereum (L1) and ZKsync (L2). This contract checks the validity proof and data availability, handles L2 <-> L1 communication, finalizes L2 state transition, and more. There are also important contracts deployed on the L2 that can also execute logic called _system contracts_. Using L2 @@ -73,7 +73,7 @@ execution of upgrades in the diamond proxy. This contract manages operations (calls with preconditions) for governance tasks. The contract allows for operations to be scheduled, executed, and canceled with appropriate permissions and delays. It is used for managing and coordinating -upgrades and changes in all zkSync Era governed contracts. +upgrades and changes in all ZKsync Era governed contracts. Each upgrade consists of two steps: @@ -122,8 +122,8 @@ function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Ad ``` For most of the rollups the address aliasing needs to prevent cross-chain exploits that would otherwise be possible if -we simply reused the same L1 addresses as the L2 sender. In zkSync Era address derivation rule is different from the -Ethereum, so cross-chain exploits are already impossible. However, zkSync Era may add full EVM support in the future, so +we simply reused the same L1 addresses as the L2 sender. In ZKsync Era address derivation rule is different from the +Ethereum, so cross-chain exploits are already impossible. However, ZKsync Era may add full EVM support in the future, so applying address aliasing leave room for future EVM compatibility. The L1 -> L2 communication is also used for bridging ether. The user should include a `msg.value` when initiating a @@ -253,8 +253,8 @@ the L1 recipient. #### ValidatorTimelock -An intermediate smart contract between the validator EOA account and the zkSync smart contract. Its primary purpose is -to provide a trustless means of delaying batch execution without modifying the main zkSync contract. zkSync actively +An intermediate smart contract between the validator EOA account and the ZKsync smart contract. Its primary purpose is +to provide a trustless means of delaying batch execution without modifying the main ZKsync contract. ZKsync actively monitors the chain activity and reacts to any suspicious activity by freezing the chain. This allows time for investigation and mitigation before resuming normal operations. @@ -264,12 +264,12 @@ the Alpha stage. This contract consists of four main functions `commitBatches`, `proveBatches`, `executeBatches`, and `revertBatches`, that can be called only by the validator. -When the validator calls `commitBatches`, the same calldata will be propagated to the zkSync contract (`DiamondProxy` +When the validator calls `commitBatches`, the same calldata will be propagated to the ZKsync contract (`DiamondProxy` through `call` where it invokes the `ExecutorFacet` through `delegatecall`), and also a timestamp is assigned to these batches to track the time these batches are committed by the validator to enforce a delay between committing and execution of batches. Then, the validator can prove the already committed batches regardless of the mentioned timestamp, -and again the same calldata (related to the `proveBatches` function) will be propagated to the zkSync contract. After, -the `delay` is elapsed, the validator is allowed to call `executeBatches` to propagate the same calldata to zkSync +and again the same calldata (related to the `proveBatches` function) will be propagated to the ZKsync contract. After, +the `delay` is elapsed, the validator is allowed to call `executeBatches` to propagate the same calldata to ZKsync contract. ### L2 specifics diff --git a/gas-bound-caller/README.md b/gas-bound-caller/README.md index 00f2868df..17b647539 100644 --- a/gas-bound-caller/README.md +++ b/gas-bound-caller/README.md @@ -46,4 +46,4 @@ Since `GasBoundCaller` would be the contract that calls the `_to` contract, the It should be deployed via a built-in CREATE2 factory on each individual chain. -The current address on both sepolia testnet and mainnet for zkSync Era is `0xc706EC7dfA5D4Dc87f29f859094165E8290530f5`. +The current address on both sepolia testnet and mainnet for ZKsync Era is `0xc706EC7dfA5D4Dc87f29f859094165E8290530f5`. diff --git a/gas-bound-caller/contracts/test-contracts/GasBoundCallerTester.sol b/gas-bound-caller/contracts/test-contracts/GasBoundCallerTester.sol index 8c1b790d6..1314bf0c0 100644 --- a/gas-bound-caller/contracts/test-contracts/GasBoundCallerTester.sol +++ b/gas-bound-caller/contracts/test-contracts/GasBoundCallerTester.sol @@ -57,9 +57,9 @@ contract GasBoundCallerTester is GasBoundCaller { } } - function testReturndataOverhead(uint256 len) external { + function testReturndataOverhead(uint256 _len, uint256 _gasForInner) external { uint256 gasbefore = gasleft(); - this.testReturndataOverheadInner(false, len); + this.testReturndataOverheadInner{gas: _gasForInner}(false, _len); lastRecordedGasLeft = gasbefore - gasleft(); } diff --git a/gas-bound-caller/contracts/test-contracts/SystemContractsCaller.sol b/gas-bound-caller/contracts/test-contracts/SystemContractsCaller.sol index ca7c870c7..1f154e270 100644 --- a/gas-bound-caller/contracts/test-contracts/SystemContractsCaller.sol +++ b/gas-bound-caller/contracts/test-contracts/SystemContractsCaller.sol @@ -6,7 +6,7 @@ import {MSG_VALUE_SYSTEM_CONTRACT, MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT} from "@mat import {Utils} from "@matterlabs/zksync-contracts/l2/system-contracts/libraries/Utils.sol"; // Addresses used for the compiler to be replaced with the -// zkSync-specific opcodes during the compilation. +// ZKsync-specific opcodes during the compilation. // IMPORTANT: these are just compile-time constants and are used // only if used in-place by Yul optimizer. address constant TO_L1_CALL_ADDRESS = address((1 << 16) - 1); diff --git a/gas-bound-caller/package.json b/gas-bound-caller/package.json index db6b3d8bf..96593e37a 100644 --- a/gas-bound-caller/package.json +++ b/gas-bound-caller/package.json @@ -13,12 +13,12 @@ "eslint-plugin-prettier": "^5.0.1", "ethers": "^5.7.0", "fast-glob": "^3.3.2", - "hardhat": "^2.18.3", + "hardhat": "=2.22.2", "preprocess": "^3.2.0", "zksync-ethers": "^5.9.0" }, "devDependencies": { - "@matterlabs/hardhat-zksync-chai-matchers": "^0.1.4", + "@matterlabs/hardhat-zksync-chai-matchers": "^0.2.0", "@matterlabs/hardhat-zksync-node": "^0.0.1-beta.7", "@matterlabs/hardhat-zksync-verify": "0.6.1", "@nomicfoundation/hardhat-chai-matchers": "^1.0.3", diff --git a/gas-bound-caller/test/GasBoundCaller.spec.ts b/gas-bound-caller/test/GasBoundCaller.spec.ts index 1a970f0fc..5b92e298f 100644 --- a/gas-bound-caller/test/GasBoundCaller.spec.ts +++ b/gas-bound-caller/test/GasBoundCaller.spec.ts @@ -39,15 +39,16 @@ describe("GasBoundCaller tests", function () { }); it("test returndata overhead", async () => { + // The tests' behavior depends on the amount of gas provided to its inner part, so we always provide 40kk await ( - await tester.testReturndataOverhead(10, { + await tester.testReturndataOverhead(10, 40_000_000, { gasLimit: 80_000_000, }) ).wait(); const smallBytecodeGas = await tester.lastRecordedGasLeft(); await ( - await tester.testReturndataOverhead(100000, { + await tester.testReturndataOverhead(100000, 40_000_000, { gasLimit: 80_000_000, }) ).wait(); diff --git a/l1-contracts/README.md b/l1-contracts/README.md index 30ffc8399..8fb04bb86 100644 --- a/l1-contracts/README.md +++ b/l1-contracts/README.md @@ -1,10 +1,10 @@ -# zkSync Era: L1 Contracts +# ZKsync Era: L1 Contracts [![Logo](../eraLogo.svg)](https://zksync.io/) -zkSync Era is a layer 2 rollup that uses zero-knowledge proofs to scale Ethereum without compromising on security or +ZKsync Era is a layer 2 rollup that uses zero-knowledge proofs to scale Ethereum without compromising on security or decentralization. Since it's EVM compatible (Solidity/Vyper), 99% of Ethereum projects can redeploy without refactoring -or re-auditing a single line of code. zkSync Era also uses an LLVM-based compiler that will eventually let developers +or re-auditing a single line of code. ZKsync Era also uses an LLVM-based compiler that will eventually let developers write smart contracts in C++, Rust and other popular languages. ## L1 Contracts diff --git a/l1-contracts/contracts/bridge/L1ERC20Bridge.sol b/l1-contracts/contracts/bridge/L1ERC20Bridge.sol index da3098969..ccd4a2a88 100644 --- a/l1-contracts/contracts/bridge/L1ERC20Bridge.sol +++ b/l1-contracts/contracts/bridge/L1ERC20Bridge.sol @@ -2,8 +2,8 @@ pragma solidity 0.8.24; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20.sol"; import {IL1ERC20Bridge} from "./interfaces/IL1ERC20Bridge.sol"; import {IL1SharedBridge} from "./interfaces/IL1SharedBridge.sol"; @@ -11,10 +11,12 @@ import {IL1SharedBridge} from "./interfaces/IL1SharedBridge.sol"; import {L2ContractHelper} from "../common/libraries/L2ContractHelper.sol"; import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; +import {Unauthorized, EmptyDeposit, TokensWithFeesNotSupported, WithdrawalAlreadyFinalized} from "../common/L1ContractErrors.sol"; + /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev /// @notice Smart contract that allows depositing ERC20 tokens from Ethereum to hyperchains -/// @dev It is a legacy bridge from zkSync Era, that was deprecated in favour of shared bridge. +/// @dev It is a legacy bridge from ZKsync Era, that was deprecated in favour of shared bridge. /// It is needed for backward compatibility with already integrated projects. contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { using SafeERC20 for IERC20; @@ -23,25 +25,25 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { IL1SharedBridge public immutable override SHARED_BRIDGE; /// @dev A mapping L2 batch number => message number => flag. - /// @dev Used to indicate that L2 -> L1 message was already processed for zkSync Era withdrawals. + /// @dev Used to indicate that L2 -> L1 message was already processed for ZKsync Era withdrawals. // slither-disable-next-line uninitialized-state mapping(uint256 l2BatchNumber => mapping(uint256 l2ToL1MessageNumber => bool isFinalized)) public isWithdrawalFinalized; /// @dev A mapping account => L1 token address => L2 deposit transaction hash => amount. - /// @dev Used for saving the number of deposited funds, to claim them in case the deposit transaction will fail in zkSync Era. + /// @dev Used for saving the number of deposited funds, to claim them in case the deposit transaction will fail in ZKsync Era. mapping(address account => mapping(address l1Token => mapping(bytes32 depositL2TxHash => uint256 amount))) public depositAmount; - /// @dev The address that is used as a L2 bridge counterpart in zkSync Era. + /// @dev The address that is used as a L2 bridge counterpart in ZKsync Era. // slither-disable-next-line uninitialized-state address public l2Bridge; - /// @dev The address that is used as a beacon for L2 tokens in zkSync Era. + /// @dev The address that is used as a beacon for L2 tokens in ZKsync Era. // slither-disable-next-line uninitialized-state address public l2TokenBeacon; - /// @dev Stores the hash of the L2 token proxy contract's bytecode on zkSync Era. + /// @dev Stores the hash of the L2 token proxy contract's bytecode on ZKsync Era. // slither-disable-next-line uninitialized-state bytes32 public l2TokenProxyBytecodeHash; @@ -65,7 +67,9 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { /// @dev transfer token to shared bridge as part of upgrade function transferTokenToSharedBridge(address _token) external { - require(msg.sender == address(SHARED_BRIDGE), "Not shared bridge"); + if (msg.sender != address(SHARED_BRIDGE)) { + revert Unauthorized(msg.sender); + } uint256 amount = IERC20(_token).balanceOf(address(this)); IERC20(_token).safeTransfer(address(SHARED_BRIDGE), amount); } @@ -74,7 +78,7 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { ERA LEGACY GETTERS //////////////////////////////////////////////////////////////*/ - /// @return The L2 token address that would be minted for deposit of the given L1 token on zkSync Era. + /// @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, "")); bytes32 salt = bytes32(uint256(uint160(_l1Token))); @@ -148,9 +152,15 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { uint256 _l2TxGasPerPubdataByte, address _refundRecipient ) public payable nonReentrant returns (bytes32 l2TxHash) { - require(_amount != 0, "0T"); // empty deposit + // empty deposit + if (_amount == 0) { + revert EmptyDeposit(); + } uint256 amount = _depositFundsToSharedBridge(msg.sender, IERC20(_l1Token), _amount); - require(amount == _amount, "3T"); // The token has non-standard transfer logic + // The token has non-standard transfer logic + if (amount != _amount) { + revert TokensWithFeesNotSupported(); + } l2TxHash = SHARED_BRIDGE.depositLegacyErc20Bridge{value: msg.value}({ _msgSender: msg.sender, @@ -162,8 +172,13 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { _refundRecipient: _refundRecipient }); depositAmount[msg.sender][_l1Token][l2TxHash] = _amount; - // solhint-disable-next-line func-named-parameters - emit DepositInitiated(l2TxHash, msg.sender, _l2Receiver, _l1Token, _amount); + emit DepositInitiated({ + l2DepositTxHash: l2TxHash, + from: msg.sender, + to: _l2Receiver, + l1Token: _l1Token, + amount: _amount + }); } /// @dev Transfers tokens from the depositor address to the shared bridge address. @@ -194,7 +209,10 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { bytes32[] calldata _merkleProof ) external nonReentrant { uint256 amount = depositAmount[_depositSender][_l1Token][_l2TxHash]; - require(amount != 0, "2T"); // empty deposit + // empty deposit + if (amount == 0) { + revert EmptyDeposit(); + } delete depositAmount[_depositSender][_l1Token][_l2TxHash]; SHARED_BRIDGE.claimFailedDepositLegacyErc20Bridge({ @@ -223,7 +241,9 @@ contract L1ERC20Bridge is IL1ERC20Bridge, ReentrancyGuard { bytes calldata _message, bytes32[] calldata _merkleProof ) external nonReentrant { - require(!isWithdrawalFinalized[_l2BatchNumber][_l2MessageIndex], "pw"); + if (isWithdrawalFinalized[_l2BatchNumber][_l2MessageIndex]) { + revert WithdrawalAlreadyFinalized(); + } // We don't need to set finalizeWithdrawal here, as we set it in the shared bridge (address l1Receiver, address l1Token, uint256 amount) = SHARED_BRIDGE.finalizeWithdrawalLegacyErc20Bridge({ diff --git a/l1-contracts/contracts/bridge/L1SharedBridge.sol b/l1-contracts/contracts/bridge/L1SharedBridge.sol index 42058fe33..eaddcccc7 100644 --- a/l1-contracts/contracts/bridge/L1SharedBridge.sol +++ b/l1-contracts/contracts/bridge/L1SharedBridge.sol @@ -2,12 +2,12 @@ pragma solidity 0.8.24; -import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; -import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; +import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/security/PausableUpgradeable.sol"; -import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts-v4/token/ERC20/extensions/IERC20Metadata.sol"; +import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20.sol"; import {IL1ERC20Bridge} from "./interfaces/IL1ERC20Bridge.sol"; import {IL1SharedBridge} from "./interfaces/IL1SharedBridge.sol"; @@ -22,6 +22,7 @@ import {ETH_TOKEN_ADDRESS, TWO_BRIDGES_MAGIC_VALUE} from "../common/Config.sol"; import {IBridgehub, L2TransactionRequestTwoBridgesInner, L2TransactionRequestDirect} from "../bridgehub/IBridgehub.sol"; import {IGetters} from "../state-transition/chain-interfaces/IGetters.sol"; import {L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR} from "../common/L2ContractAddresses.sol"; +import {Unauthorized, ZeroAddress, SharedBridgeValueAlreadySet, SharedBridgeKey, NoFundsTransferred, ZeroBalance, ValueMismatch, TokensWithFeesNotSupported, NonEmptyMsgValue, L2BridgeNotSet, TokenNotSupported, DepositIncorrectAmount, EmptyDeposit, DepositExists, AddressAlreadyUsed, InvalidProof, DepositDoesNotExist, InsufficientChainBalance, SharedBridgeValueNotSet, WithdrawalAlreadyFinalized, WithdrawFailed, L2WithdrawalMessageWrongLength, InvalidSelector, SharedBridgeBalanceMismatch, SharedBridgeValueNotSet} from "../common/L1ContractErrors.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -37,22 +38,22 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade IBridgehub public immutable override BRIDGE_HUB; /// @dev Era's chainID - uint256 public immutable ERA_CHAIN_ID; + uint256 internal immutable ERA_CHAIN_ID; - /// @dev The address of zkSync Era diamond proxy contract. - address public immutable ERA_DIAMOND_PROXY; + /// @dev The address of ZKsync Era diamond proxy contract. + address internal immutable ERA_DIAMOND_PROXY; - /// @dev Stores the first batch number on the zkSync Era Diamond Proxy that was settled after Diamond proxy upgrade. + /// @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. uint256 internal eraPostDiamondUpgradeFirstBatch; - /// @dev Stores the first batch number on the zkSync Era Diamond Proxy that was settled after L1ERC20 Bridge upgrade. + /// @dev Stores the first batch number on the ZKsync Era Diamond Proxy that was settled after L1ERC20 Bridge upgrade. /// This variable is used to differentiate between pre-upgrade and post-upgrade ERC20 withdrawals. Withdrawals from batches older /// than this value are considered to have been finalized prior to the upgrade and handled separately. uint256 internal eraPostLegacyBridgeUpgradeFirstBatch; - /// @dev Stores the zkSync Era batch number that processes the last deposit tx initiated by the legacy bridge + /// @dev Stores the ZKsync Era batch number that processes the last deposit tx initiated by the legacy bridge /// This variable (together with eraLegacyBridgeLastDepositTxNumber) is used to differentiate between pre-upgrade and post-upgrade deposits. Deposits processed in older batches /// than this value are considered to have been processed prior to the upgrade and handled separately. /// We use this both for Eth and erc20 token deposits, so we need to update the diamond and bridge simultaneously. @@ -97,28 +98,33 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade /// @notice Checks that the message sender is the bridgehub. modifier onlyBridgehub() { - require(msg.sender == address(BRIDGE_HUB), "ShB not BH"); + if (msg.sender != address(BRIDGE_HUB)) { + revert Unauthorized(msg.sender); + } _; } - /// @notice Checks that the message sender is the bridgehub or zkSync Era Diamond Proxy. + /// @notice Checks that the message sender is the bridgehub or ZKsync Era Diamond Proxy. modifier onlyBridgehubOrEra(uint256 _chainId) { - require( - msg.sender == address(BRIDGE_HUB) || (_chainId == ERA_CHAIN_ID && msg.sender == ERA_DIAMOND_PROXY), - "L1SharedBridge: not bridgehub or era chain" - ); + if (msg.sender != address(BRIDGE_HUB) && (_chainId != ERA_CHAIN_ID || msg.sender != ERA_DIAMOND_PROXY)) { + revert Unauthorized(msg.sender); + } _; } /// @notice Checks that the message sender is the legacy bridge. modifier onlyLegacyBridge() { - require(msg.sender == address(legacyBridge), "ShB not legacy bridge"); + if (msg.sender != address(legacyBridge)) { + revert Unauthorized(msg.sender); + } _; } /// @notice Checks that the message sender is the shared bridge itself. modifier onlySelf() { - require(msg.sender == address(this), "ShB not shared bridge"); + if (msg.sender != address(this)) { + revert Unauthorized(msg.sender); + } _; } @@ -147,7 +153,9 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade /// @param _owner 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 { - require(_owner != address(0), "ShB owner 0"); + if (_owner == address(0)) { + revert ZeroAddress(); + } _transferOwnership(_owner); } @@ -177,39 +185,52 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade } /// @dev This sets the first post diamond upgrade batch for era, used to check old eth withdrawals - /// @param _eraPostDiamondUpgradeFirstBatch The first batch number on the zkSync Era Diamond Proxy that was settled after diamond proxy upgrade. + /// @param _eraPostDiamondUpgradeFirstBatch The first batch number on the ZKsync Era Diamond Proxy that was settled after diamond proxy upgrade. function setEraPostDiamondUpgradeFirstBatch(uint256 _eraPostDiamondUpgradeFirstBatch) external onlyOwner { - require(eraPostDiamondUpgradeFirstBatch == 0, "ShB: eFPUB already set"); + if (eraPostDiamondUpgradeFirstBatch != 0) { + revert SharedBridgeValueAlreadySet(SharedBridgeKey.PostUpgradeFirstBatch); + } eraPostDiamondUpgradeFirstBatch = _eraPostDiamondUpgradeFirstBatch; } /// @dev This sets the first post upgrade batch for era, used to check old token withdrawals - /// @param _eraPostLegacyBridgeUpgradeFirstBatch The first batch number on the zkSync Era Diamond Proxy that was settled after legacy bridge upgrade. + /// @param _eraPostLegacyBridgeUpgradeFirstBatch The first batch number on the ZKsync Era Diamond Proxy that was settled after legacy bridge upgrade. function setEraPostLegacyBridgeUpgradeFirstBatch(uint256 _eraPostLegacyBridgeUpgradeFirstBatch) external onlyOwner { - require(eraPostLegacyBridgeUpgradeFirstBatch == 0, "ShB: eFPUB already set"); + if (eraPostLegacyBridgeUpgradeFirstBatch != 0) { + revert SharedBridgeValueAlreadySet(SharedBridgeKey.LegacyBridgeFirstBatch); + } eraPostLegacyBridgeUpgradeFirstBatch = _eraPostLegacyBridgeUpgradeFirstBatch; } /// @dev This sets the first post upgrade batch for era, used to check old withdrawals - /// @param _eraLegacyBridgeLastDepositBatch The the zkSync Era batch number that processes the last deposit tx initiated by the legacy bridge + /// @param _eraLegacyBridgeLastDepositBatch The the ZKsync Era batch number that processes the last deposit tx initiated by the legacy bridge /// @param _eraLegacyBridgeLastDepositTxNumber The tx number in the _eraLegacyBridgeLastDepositBatch of the last deposit tx initiated by the legacy bridge function setEraLegacyBridgeLastDepositTime( uint256 _eraLegacyBridgeLastDepositBatch, uint256 _eraLegacyBridgeLastDepositTxNumber ) external onlyOwner { - require(eraLegacyBridgeLastDepositBatch == 0, "ShB: eLOBDB already set"); - require(eraLegacyBridgeLastDepositTxNumber == 0, "ShB: eLOBDTN already set"); + if (eraLegacyBridgeLastDepositBatch != 0) { + revert SharedBridgeValueAlreadySet(SharedBridgeKey.LegacyBridgeLastDepositBatch); + } + if (eraLegacyBridgeLastDepositTxNumber != 0) { + revert SharedBridgeValueAlreadySet(SharedBridgeKey.LegacyBridgeLastDepositTxn); + } eraLegacyBridgeLastDepositBatch = _eraLegacyBridgeLastDepositBatch; eraLegacyBridgeLastDepositTxNumber = _eraLegacyBridgeLastDepositTxNumber; } - /// @dev transfer tokens from legacy erc20 bridge or mailbox and set chainBalance as part of migration process + /// @dev Transfer tokens from legacy erc20 bridge or mailbox and set chainBalance as part of migration process. + /// @param _token The address of token to be transferred (address(1) for ether and contract address for ERC20). + /// @param _target The hyperchain or bridge contract address from where to transfer funds. + /// @param _targetChainId The chain ID of the corresponding hyperchain. function transferFundsFromLegacy(address _token, address _target, uint256 _targetChainId) external onlySelf { if (_token == ETH_TOKEN_ADDRESS) { uint256 balanceBefore = address(this).balance; IMailbox(_target).transferEthToSharedBridge(); uint256 balanceAfter = address(this).balance; - require(balanceAfter > balanceBefore, "ShB: 0 eth transferred"); + if (balanceAfter <= balanceBefore) { + revert NoFundsTransferred(); + } chainBalance[_targetChainId][ETH_TOKEN_ADDRESS] = chainBalance[_targetChainId][ETH_TOKEN_ADDRESS] + balanceAfter - @@ -217,10 +238,14 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade } else { uint256 balanceBefore = IERC20(_token).balanceOf(address(this)); uint256 legacyBridgeBalance = IERC20(_token).balanceOf(address(legacyBridge)); - require(legacyBridgeBalance > 0, "ShB: 0 amount to transfer"); + if (legacyBridgeBalance == 0) { + revert ZeroBalance(); + } IL1ERC20Bridge(_target).transferTokenToSharedBridge(_token); uint256 balanceAfter = IERC20(_token).balanceOf(address(this)); - require(balanceAfter - balanceBefore >= legacyBridgeBalance, "ShB: wrong amount transferred"); + if (balanceAfter - balanceBefore < legacyBridgeBalance) { + revert SharedBridgeBalanceMismatch(); + } chainBalance[_targetChainId][_token] = chainBalance[_targetChainId][_token] + legacyBridgeBalance; } } @@ -239,8 +264,12 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade } } + /// @dev Accepts ether only from the hyperchain associated with the specified chain ID. + /// @param _chainId The chain ID corresponding to the hyperchain allowed to send ether. function receiveEth(uint256 _chainId) external payable { - require(BRIDGE_HUB.getHyperchain(_chainId) == msg.sender, "receiveEth not state transition"); + if (BRIDGE_HUB.getHyperchain(_chainId) != msg.sender) { + revert Unauthorized(msg.sender); + } } /// @dev Initializes the l2Bridge address by governance for a specific chain. @@ -264,6 +293,10 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade /// @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 hyperchain to which deposit. + /// @param _prevMsgSender The `msg.sender` address from the external call that initiated current one. + /// @param _l1Token The L1 token address which is deposited. + /// @param _amount The total amount of tokens to be bridged. function bridgehubDepositBaseToken( uint256 _chainId, address _prevMsgSender, @@ -271,13 +304,20 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade uint256 _amount ) external payable virtual onlyBridgehubOrEra(_chainId) whenNotPaused { if (_l1Token == ETH_TOKEN_ADDRESS) { - require(msg.value == _amount, "L1SharedBridge: msg.value not equal to amount"); + if (msg.value != _amount) { + revert ValueMismatch(_amount, msg.value); + } } else { // The Bridgehub also checks this, but we want to be sure - require(msg.value == 0, "ShB m.v > 0 b d.it"); + if (msg.value != 0) { + revert NonEmptyMsgValue(); + } uint256 amount = _depositFunds(_prevMsgSender, IERC20(_l1Token), _amount); // note if _prevMsgSender is this contract, this will return 0. This does not happen. - require(amount == _amount, "3T"); // The token has non-standard transfer logic + // The token has non-standard transfer logic + if (amount != _amount) { + revert TokensWithFeesNotSupported(); + } } if (!hyperbridgingEnabled[_chainId]) { @@ -299,6 +339,10 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade } /// @notice Initiates a deposit transaction within Bridgehub, used by `requestL2TransactionTwoBridges`. + /// @param _chainId The chain ID of the hyperchain to which deposit. + /// @param _prevMsgSender The `msg.sender` address from the external call that initiated current one. + /// @param _l2Value The L2 `msg.value` from the L1 -> L2 deposit transaction. + /// @param _data The calldata for the second bridge deposit. function bridgehubDeposit( uint256 _chainId, address _prevMsgSender, @@ -313,27 +357,43 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade whenNotPaused returns (L2TransactionRequestTwoBridgesInner memory request) { - require(l2BridgeAddress[_chainId] != address(0), "ShB l2 bridge not deployed"); + if (l2BridgeAddress[_chainId] == address(0)) { + revert L2BridgeNotSet(_chainId); + } (address _l1Token, uint256 _depositAmount, address _l2Receiver) = abi.decode( _data, (address, uint256, address) ); - require(_l1Token != L1_WETH_TOKEN, "ShB: WETH deposit not supported"); - require(BRIDGE_HUB.baseToken(_chainId) != _l1Token, "ShB: baseToken deposit not supported"); + if (_l1Token == L1_WETH_TOKEN) { + revert TokenNotSupported(L1_WETH_TOKEN); + } + if (BRIDGE_HUB.baseToken(_chainId) == _l1Token) { + revert TokenNotSupported(_l1Token); + } uint256 amount; if (_l1Token == ETH_TOKEN_ADDRESS) { amount = msg.value; - require(_depositAmount == 0, "ShB wrong withdraw amount"); + if (_depositAmount != 0) { + revert DepositIncorrectAmount(0, _depositAmount); + } } else { - require(msg.value == 0, "ShB m.v > 0 for BH d.it 2"); + if (msg.value != 0) { + revert NonEmptyMsgValue(); + } amount = _depositAmount; - uint256 withdrawAmount = _depositFunds(_prevMsgSender, IERC20(_l1Token), _depositAmount); - require(withdrawAmount == _depositAmount, "5T"); // The token has non-standard transfer logic + uint256 depAmount = _depositFunds(_prevMsgSender, IERC20(_l1Token), _depositAmount); + // The token has non-standard transfer logic + if (depAmount != _depositAmount) { + revert DepositIncorrectAmount(depAmount, _depositAmount); + } + } + // empty deposit amount + if (amount == 0) { + revert EmptyDeposit(); } - require(amount != 0, "6T"); // empty deposit amount bytes32 txDataHash = keccak256(abi.encode(_prevMsgSender, _l1Token, amount)); if (!hyperbridgingEnabled[_chainId]) { @@ -364,20 +424,29 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade /// @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 hyperchain to which confirm the deposit. + /// @param _txDataHash The keccak256 hash of abi.encode(msgSender, l1Token, amount) + /// @param _txHash The hash of the L1->L2 transaction to confirm the deposit. function bridgehubConfirmL2Transaction( uint256 _chainId, bytes32 _txDataHash, bytes32 _txHash ) external override onlyBridgehub whenNotPaused { - require(depositHappened[_chainId][_txHash] == 0x00, "ShB tx hap"); + if (depositHappened[_chainId][_txHash] != 0x00) { + revert DepositExists(); + } depositHappened[_chainId][_txHash] = _txDataHash; emit BridgehubDepositFinalized(_chainId, _txDataHash, _txHash); } /// @dev Sets the L1ERC20Bridge contract address. Should be called only once. function setL1Erc20Bridge(address _legacyBridge) external onlyOwner { - require(address(legacyBridge) == address(0), "ShB: legacy bridge already set"); - require(_legacyBridge != address(0), "ShB: legacy bridge 0"); + if (address(legacyBridge) != address(0)) { + revert AddressAlreadyUsed(address(legacyBridge)); + } + if (_legacyBridge == address(0)) { + revert ZeroAddress(); + } legacyBridge = IL1ERC20Bridge(_legacyBridge); } @@ -395,8 +464,8 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade /// @dev Receives and parses (name, symbol, decimals) from the token contract function _getERC20Getters(address _token) internal view returns (bytes memory) { if (_token == ETH_TOKEN_ADDRESS) { - bytes memory name = bytes("Ether"); - bytes memory symbol = bytes("ETH"); + bytes memory name = abi.encode("Ether"); + bytes memory symbol = abi.encode("ETH"); bytes memory decimals = abi.encode(uint8(18)); return abi.encode(name, symbol, decimals); // when depositing eth to a non-eth based chain it is an ERC20 } @@ -464,9 +533,13 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade _merkleProof: _merkleProof, _status: TxStatus.Failure }); - require(proofValid, "yn"); + if (!proofValid) { + revert InvalidProof(); + } + } + if (_amount == 0) { + revert NoFundsTransferred(); } - require(_amount > 0, "y1"); { bool notCheckedInLegacyBridgeOrWeCanCheckDeposit; @@ -481,14 +554,18 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade if (notCheckedInLegacyBridgeOrWeCanCheckDeposit) { bytes32 dataHash = depositHappened[_chainId][_l2TxHash]; bytes32 txDataHash = keccak256(abi.encode(_depositSender, _l1Token, _amount)); - require(dataHash == txDataHash, "ShB: d.it not hap"); + if (dataHash != txDataHash) { + revert DepositDoesNotExist(); + } delete depositHappened[_chainId][_l2TxHash]; } } if (!hyperbridgingEnabled[_chainId]) { // check that the chain has sufficient balance - require(chainBalance[_chainId][_l1Token] >= _amount, "ShB n funds"); + if (chainBalance[_chainId][_l1Token] < _amount) { + revert InsufficientChainBalance(); + } chainBalance[_chainId][_l1Token] -= _amount; } @@ -499,7 +576,9 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade assembly { callSuccess := call(gas(), _depositSender, _amount, 0, 0, 0, 0) } - require(callSuccess, "ShB: claimFailedDeposit failed"); + if (!callSuccess) { + revert WithdrawFailed(); + } } else { IERC20(_l1Token).safeTransfer(_depositSender, _amount); // Note we don't allow weth deposits anymore, but there might be legacy weth deposits. @@ -509,41 +588,41 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade emit ClaimedFailedDepositSharedBridge(_chainId, _depositSender, _l1Token, _amount); } - /// @dev Determines if an eth withdrawal was initiated on zkSync Era before the upgrade to the Shared Bridge. + /// @dev Determines if an eth withdrawal was initiated on ZKsync Era before the upgrade to the Shared Bridge. /// @param _chainId The chain ID of the transaction to check. /// @param _l2BatchNumber The L2 batch number for the withdrawal. - /// @return Whether withdrawal was initiated on zkSync Era before diamond proxy upgrade. + /// @return Whether withdrawal was initiated on ZKsync Era before diamond proxy upgrade. function _isEraLegacyEthWithdrawal(uint256 _chainId, uint256 _l2BatchNumber) internal view returns (bool) { - require((_chainId != ERA_CHAIN_ID) || eraPostDiamondUpgradeFirstBatch != 0, "ShB: diamondUFB not set for Era"); + if ((_chainId == ERA_CHAIN_ID) && eraPostDiamondUpgradeFirstBatch == 0) { + revert SharedBridgeValueNotSet(SharedBridgeKey.PostUpgradeFirstBatch); + } return (_chainId == ERA_CHAIN_ID) && (_l2BatchNumber < eraPostDiamondUpgradeFirstBatch); } - /// @dev Determines if a token withdrawal was initiated on zkSync Era before the upgrade to the Shared Bridge. + /// @dev Determines if a token withdrawal was initiated on ZKsync Era before the upgrade to the Shared Bridge. /// @param _chainId The chain ID of the transaction to check. /// @param _l2BatchNumber The L2 batch number for the withdrawal. - /// @return Whether withdrawal was initiated on zkSync Era before Legacy Bridge upgrade. + /// @return Whether withdrawal was initiated on ZKsync Era before Legacy Bridge upgrade. function _isEraLegacyTokenWithdrawal(uint256 _chainId, uint256 _l2BatchNumber) internal view returns (bool) { - require( - (_chainId != ERA_CHAIN_ID) || eraPostLegacyBridgeUpgradeFirstBatch != 0, - "ShB: LegacyUFB not set for Era" - ); + if ((_chainId == ERA_CHAIN_ID) && eraPostLegacyBridgeUpgradeFirstBatch == 0) { + revert SharedBridgeValueNotSet(SharedBridgeKey.LegacyBridgeFirstBatch); + } return (_chainId == ERA_CHAIN_ID) && (_l2BatchNumber < eraPostLegacyBridgeUpgradeFirstBatch); } - /// @dev Determines if a deposit was initiated on zkSync Era before the upgrade to the Shared Bridge. + /// @dev Determines if a deposit was initiated on ZKsync Era before the upgrade to the Shared Bridge. /// @param _chainId The chain ID of the transaction to check. /// @param _l2BatchNumber The L2 batch number for the deposit where it was processed. /// @param _l2TxNumberInBatch The L2 transaction number in the batch, in which the deposit was processed. - /// @return Whether deposit was initiated on zkSync Era before Shared Bridge upgrade. + /// @return Whether deposit was initiated on ZKsync Era before Shared Bridge upgrade. function _isEraLegacyDeposit( uint256 _chainId, uint256 _l2BatchNumber, uint256 _l2TxNumberInBatch ) internal view returns (bool) { - require( - (_chainId != ERA_CHAIN_ID) || (eraLegacyBridgeLastDepositBatch != 0), - "ShB: last deposit time not set for Era" - ); + if ((_chainId == ERA_CHAIN_ID) && (eraLegacyBridgeLastDepositBatch == 0)) { + revert SharedBridgeValueNotSet(SharedBridgeKey.LegacyBridgeLastDepositBatch); + } return (_chainId == ERA_CHAIN_ID) && (_l2BatchNumber < eraLegacyBridgeLastDepositBatch || @@ -569,7 +648,9 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade // To avoid rewithdrawing txs that have already happened on the legacy bridge. // Note: new withdraws are all recorded here, so double withdrawing them is not possible. if (_isEraLegacyTokenWithdrawal(_chainId, _l2BatchNumber)) { - require(!legacyBridge.isWithdrawalFinalized(_l2BatchNumber, _l2MessageIndex), "ShB: legacy withdrawal"); + if (legacyBridge.isWithdrawalFinalized(_l2BatchNumber, _l2MessageIndex)) { + revert WithdrawalAlreadyFinalized(); + } } _finalizeWithdrawal({ _chainId: _chainId, @@ -597,17 +678,21 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade bytes calldata _message, bytes32[] calldata _merkleProof ) internal nonReentrant whenNotPaused returns (address l1Receiver, address l1Token, uint256 amount) { - require(!isWithdrawalFinalized[_chainId][_l2BatchNumber][_l2MessageIndex], "Withdrawal is already finalized"); + if (isWithdrawalFinalized[_chainId][_l2BatchNumber][_l2MessageIndex]) { + revert WithdrawalAlreadyFinalized(); + } isWithdrawalFinalized[_chainId][_l2BatchNumber][_l2MessageIndex] = true; - // Handling special case for withdrawal from zkSync Era initiated before Shared Bridge. + // Handling special case for withdrawal from ZKsync Era initiated before Shared Bridge. if (_isEraLegacyEthWithdrawal(_chainId, _l2BatchNumber)) { // Checks that the withdrawal wasn't finalized already. bool alreadyFinalized = IGetters(ERA_DIAMOND_PROXY).isEthWithdrawalFinalized( _l2BatchNumber, _l2MessageIndex ); - require(!alreadyFinalized, "Withdrawal is already finalized 2"); + if (alreadyFinalized) { + revert WithdrawalAlreadyFinalized(); + } } MessageParams memory messageParams = MessageParams({ @@ -619,7 +704,10 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade if (!hyperbridgingEnabled[_chainId]) { // Check that the chain has sufficient balance - require(chainBalance[_chainId][l1Token] >= amount, "ShB not enough funds 2"); // not enough funds + if (chainBalance[_chainId][l1Token] < amount) { + // not enough funds + revert InsufficientChainBalance(); + } chainBalance[_chainId][l1Token] -= amount; } @@ -629,7 +717,9 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade assembly { callSuccess := call(gas(), l1Receiver, amount, 0, 0, 0, 0) } - require(callSuccess, "ShB: withdraw failed"); + if (!callSuccess) { + revert WithdrawFailed(); + } } else { // Withdraw funds IERC20(l1Token).safeTransfer(l1Receiver, amount); @@ -664,7 +754,10 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade _message: l2ToL1Message, _proof: _merkleProof }); - require(success, "ShB withd w proof"); // withdrawal wrong proof + // withdrawal wrong proof + if (!success) { + revert InvalidProof(); + } } function _parseL2WithdrawalMessage( @@ -681,7 +774,10 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade // = 4 + 20 + 32 + 32 + _additionalData.length >= 68 (bytes). // So the data is expected to be at least 56 bytes long. - require(_l2ToL1message.length >= 56, "ShB wrong msg len"); // wrong message length + // wrong message length + if (_l2ToL1message.length < 56) { + revert L2WithdrawalMessageWrongLength(_l2ToL1message.length); + } (uint32 functionSignature, uint256 offset) = UnsafeBytes.readUint32(_l2ToL1message, 0); if (bytes4(functionSignature) == IMailbox.finalizeEthWithdrawal.selector) { @@ -697,12 +793,14 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade // 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, "ShB wrong msg len 2"); + if (_l2ToL1message.length != 76) { + revert L2WithdrawalMessageWrongLength(_l2ToL1message.length); + } (l1Receiver, offset) = UnsafeBytes.readAddress(_l2ToL1message, offset); (l1Token, offset) = UnsafeBytes.readAddress(_l2ToL1message, offset); (amount, offset) = UnsafeBytes.readUint256(_l2ToL1message, offset); } else { - revert("ShB Incorrect message function selector"); + revert InvalidSelector(bytes4(functionSignature)); } } @@ -714,6 +812,7 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade /// 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. + /// @param _prevMsgSender The `msg.sender` address from the external call that initiated current one. /// @param _l2Receiver The account address that should receive funds on L2 /// @param _l1Token The L1 token address which is deposited /// @param _amount The total amount of tokens to be bridged @@ -743,8 +842,12 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade uint256 _l2TxGasPerPubdataByte, address _refundRecipient ) external payable override onlyLegacyBridge nonReentrant whenNotPaused returns (bytes32 l2TxHash) { - require(l2BridgeAddress[ERA_CHAIN_ID] != address(0), "ShB b. n dep"); - require(_l1Token != L1_WETH_TOKEN, "ShB: WETH deposit not supported 2"); + if (l2BridgeAddress[ERA_CHAIN_ID] == address(0)) { + revert L2BridgeNotSet(ERA_CHAIN_ID); + } + if (_l1Token == L1_WETH_TOKEN) { + revert TokenNotSupported(L1_WETH_TOKEN); + } // Note that funds have been transferred to this contract in the legacy ERC20 bridge. if (!hyperbridgingEnabled[ERA_CHAIN_ID]) { @@ -814,7 +917,7 @@ contract L1SharedBridge is IL1SharedBridge, ReentrancyGuard, Ownable2StepUpgrade }); } - /// @notice Withdraw funds from the initiated deposit, that failed when finalizing on zkSync Era chain. + /// @notice Withdraw funds from the initiated deposit, that failed when finalizing on ZKsync Era chain. /// This function is specifically designed for maintaining backward-compatibility with legacy `claimFailedDeposit` /// method in `L1ERC20Bridge`. /// diff --git a/l1-contracts/contracts/bridge/interfaces/IL1ERC20Bridge.sol b/l1-contracts/contracts/bridge/interfaces/IL1ERC20Bridge.sol index f7dd7b07b..722eeedc1 100644 --- a/l1-contracts/contracts/bridge/interfaces/IL1ERC20Bridge.sol +++ b/l1-contracts/contracts/bridge/interfaces/IL1ERC20Bridge.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 {IL1SharedBridge} from "./IL1SharedBridge.sol"; /// @title L1 Bridge contract legacy interface /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev -/// @notice Legacy Bridge interface before hyperchain migration, used for backward compatibility with zkSync Era +/// @notice Legacy Bridge interface before hyperchain migration, used for backward compatibility with ZKsync Era interface IL1ERC20Bridge { event DepositInitiated( bytes32 indexed l2DepositTxHash, diff --git a/l1-contracts/contracts/bridge/interfaces/IL1SharedBridge.sol b/l1-contracts/contracts/bridge/interfaces/IL1SharedBridge.sol index ef7e74165..cc58d160f 100644 --- a/l1-contracts/contracts/bridge/interfaces/IL1SharedBridge.sol +++ b/l1-contracts/contracts/bridge/interfaces/IL1SharedBridge.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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/IBridgehub.sol"; import {IBridgehub} from "../../bridgehub/IBridgehub.sol"; diff --git a/l1-contracts/contracts/bridge/interfaces/IL2Bridge.sol b/l1-contracts/contracts/bridge/interfaces/IL2Bridge.sol index eb21b4f25..39c6b423f 100644 --- a/l1-contracts/contracts/bridge/interfaces/IL2Bridge.sol +++ b/l1-contracts/contracts/bridge/interfaces/IL2Bridge.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 interface IL2Bridge { diff --git a/l1-contracts/contracts/bridge/interfaces/IWETH9.sol b/l1-contracts/contracts/bridge/interfaces/IWETH9.sol index d8e99dc7a..e1536f4fb 100644 --- a/l1-contracts/contracts/bridge/interfaces/IWETH9.sol +++ b/l1-contracts/contracts/bridge/interfaces/IWETH9.sol @@ -1,5 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 -pragma solidity 0.8.24; +// 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; interface IWETH9 { function deposit() external payable; diff --git a/l1-contracts/contracts/bridgehub/Bridgehub.sol b/l1-contracts/contracts/bridgehub/Bridgehub.sol index 7b9ecf43b..89001c2cd 100644 --- a/l1-contracts/contracts/bridgehub/Bridgehub.sol +++ b/l1-contracts/contracts/bridgehub/Bridgehub.sol @@ -2,8 +2,8 @@ pragma solidity 0.8.24; -import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; -import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; +import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/security/PausableUpgradeable.sol"; import {L2TransactionRequestDirect, L2TransactionRequestTwoBridgesOuter, L2TransactionRequestTwoBridgesInner} from "./IBridgehub.sol"; import {IBridgehub, IL1SharedBridge} from "../bridge/interfaces/IL1SharedBridge.sol"; @@ -13,7 +13,13 @@ import {IZkSyncHyperchain} from "../state-transition/chain-interfaces/IZkSyncHyp import {ETH_TOKEN_ADDRESS, TWO_BRIDGES_MAGIC_VALUE, BRIDGEHUB_MIN_SECOND_BRIDGE_ADDRESS} from "../common/Config.sol"; import {BridgehubL2TransactionRequest, L2Message, L2Log, TxStatus} from "../common/Messaging.sol"; import {AddressAliasHelper} from "../vendor/AddressAliasHelper.sol"; +import {Unauthorized, STMAlreadyRegistered, STMNotRegistered, TokenAlreadyRegistered, TokenNotRegistered, ZeroChainId, ChainIdTooBig, SharedBridgeNotSet, BridgeHubAlreadyRegistered, AddressTooLow, MsgValueMismatch, WrongMagicValue, ZeroAddress} from "../common/L1ContractErrors.sol"; +/// @author Matter Labs +/// @custom:security-contact security@matterlabs.dev +/// @dev The Bridgehub contract serves as the primary entry point for L1<->L2 communication, +/// facilitating interactions between end user and bridges. +/// It also manages state transition managers, base tokens, and chain registrations. contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, PausableUpgradeable { /// @notice all the ether is held by the weth bridge IL1SharedBridge public sharedBridge; @@ -44,7 +50,9 @@ contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, Paus } modifier onlyOwnerOrAdmin() { - require(msg.sender == admin || msg.sender == owner(), "Bridgehub: not owner or admin"); + if (msg.sender != admin && msg.sender != owner()) { + revert Unauthorized(msg.sender); + } _; } @@ -52,6 +60,9 @@ contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, Paus /// @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(); + } // Save previous value into the stack to put it into the event later address oldPendingAdmin = pendingAdmin; // Change pending admin @@ -62,7 +73,10 @@ contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, Paus /// @inheritdoc IBridgehub function acceptAdmin() external { address currentPendingAdmin = pendingAdmin; - require(msg.sender == currentPendingAdmin, "n42"); // Only proposed by current admin address can claim the admin rights + // Only proposed by current admin address can claim the admin rights + if (msg.sender != currentPendingAdmin) { + revert Unauthorized(msg.sender); + } address previousAdmin = admin; admin = currentPendingAdmin; @@ -83,32 +97,41 @@ contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, Paus /// @notice State Transition can be any contract with the appropriate interface/functionality function addStateTransitionManager(address _stateTransitionManager) external onlyOwner { - require( - !stateTransitionManagerIsRegistered[_stateTransitionManager], - "Bridgehub: state transition already registered" - ); + if (_stateTransitionManager == address(0)) { + revert ZeroAddress(); + } + if (stateTransitionManagerIsRegistered[_stateTransitionManager]) { + revert STMAlreadyRegistered(); + } stateTransitionManagerIsRegistered[_stateTransitionManager] = true; } /// @notice State Transition can be any contract with the appropriate interface/functionality /// @notice this stops new Chains from using the STF, old chains are not affected function removeStateTransitionManager(address _stateTransitionManager) external onlyOwner { - require( - stateTransitionManagerIsRegistered[_stateTransitionManager], - "Bridgehub: state transition not registered yet" - ); + if (_stateTransitionManager == address(0)) { + revert ZeroAddress(); + } + if (!stateTransitionManagerIsRegistered[_stateTransitionManager]) { + revert STMNotRegistered(); + } stateTransitionManagerIsRegistered[_stateTransitionManager] = false; } /// @notice token can be any contract with the appropriate interface/functionality function addToken(address _token) external onlyOwnerOrAdmin { - require(!tokenIsRegistered[_token], "Bridgehub: token already registered"); + if (tokenIsRegistered[_token]) { + revert TokenAlreadyRegistered(_token); + } tokenIsRegistered[_token] = true; } /// @notice To set shared bridge, only Owner. Not done in initialize, as /// the order of deployment is Bridgehub, Shared bridge, and then we call this function setSharedBridge(address _sharedBridge) external onlyOwner { + if (_sharedBridge == address(0)) { + revert ZeroAddress(); + } sharedBridge = IL1SharedBridge(_sharedBridge); } @@ -123,17 +146,32 @@ contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, Paus address _admin, bytes calldata _initData ) external onlyOwnerOrAdmin nonReentrant whenNotPaused returns (uint256) { - require(_chainId != 0, "Bridgehub: chainId cannot be 0"); - require(_chainId <= type(uint48).max, "Bridgehub: chainId too large"); + if (_chainId == 0) { + revert ZeroChainId(); + } + if (_chainId > type(uint48).max) { + revert ChainIdTooBig(); + } + if (_stateTransitionManager == address(0)) { + revert ZeroAddress(); + } + if (_baseToken == address(0)) { + revert ZeroAddress(); + } - require( - stateTransitionManagerIsRegistered[_stateTransitionManager], - "Bridgehub: state transition not registered" - ); - require(tokenIsRegistered[_baseToken], "Bridgehub: token not registered"); - require(address(sharedBridge) != address(0), "Bridgehub: weth bridge not set"); + if (!stateTransitionManagerIsRegistered[_stateTransitionManager]) { + revert STMNotRegistered(); + } + if (!tokenIsRegistered[_baseToken]) { + revert TokenNotRegistered(_baseToken); + } + if (address(sharedBridge) == address(0)) { + revert SharedBridgeNotSet(); + } - require(stateTransitionManager[_chainId] == address(0), "Bridgehub: chainId already registered"); + if (stateTransitionManager[_chainId] != address(0)) { + revert BridgeHubAlreadyRegistered(); + } stateTransitionManager[_chainId] = _stateTransitionManager; baseToken[_chainId] = _baseToken; @@ -153,6 +191,12 @@ contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, Paus //// Mailbox forwarder /// @notice forwards function call to Mailbox based on ChainId + /// @param _chainId The chain ID of the hyperchain where to prove L2 message inclusion. + /// @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 proveL2MessageInclusion( uint256 _chainId, uint256 _batchNumber, @@ -165,11 +209,17 @@ contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, Paus } /// @notice forwards function call to Mailbox based on ChainId + /// @param _chainId The chain ID of the hyperchain where to prove L2 log inclusion. + /// @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 proveL2LogInclusion( uint256 _chainId, uint256 _batchNumber, uint256 _index, - L2Log memory _log, + L2Log calldata _log, bytes32[] calldata _proof ) external view override returns (bool) { address hyperchain = getHyperchain(_chainId); @@ -177,6 +227,15 @@ contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, Paus } /// @notice forwards function call to Mailbox based on ChainId + /// @param _chainId The chain ID of the hyperchain where to prove L1->L2 tx 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 proveL1ToL2TransactionStatus( uint256 _chainId, bytes32 _l2TxHash, @@ -219,9 +278,13 @@ contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, Paus { address token = baseToken[_request.chainId]; if (token == ETH_TOKEN_ADDRESS) { - require(msg.value == _request.mintValue, "Bridgehub: msg.value mismatch 1"); + if (msg.value != _request.mintValue) { + revert MsgValueMismatch(_request.mintValue, msg.value); + } } else { - require(msg.value == 0, "Bridgehub: non-eth bridge with msg.value"); + if (msg.value != 0) { + revert MsgValueMismatch(0, msg.value); + } } // slither-disable-next-line arbitrary-send-eth @@ -266,13 +329,14 @@ contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, Paus address token = baseToken[_request.chainId]; uint256 baseTokenMsgValue; if (token == ETH_TOKEN_ADDRESS) { - require( - msg.value == _request.mintValue + _request.secondBridgeValue, - "Bridgehub: msg.value mismatch 2" - ); + if (msg.value != _request.mintValue + _request.secondBridgeValue) { + revert MsgValueMismatch(_request.mintValue + _request.secondBridgeValue, msg.value); + } baseTokenMsgValue = _request.mintValue; } else { - require(msg.value == _request.secondBridgeValue, "Bridgehub: msg.value mismatch 3"); + if (msg.value != _request.secondBridgeValue) { + revert MsgValueMismatch(_request.secondBridgeValue, msg.value); + } baseTokenMsgValue = 0; } // slither-disable-next-line arbitrary-send-eth @@ -295,14 +359,16 @@ contract Bridgehub is IBridgehub, ReentrancyGuard, Ownable2StepUpgradeable, Paus _request.secondBridgeCalldata ); - require(outputRequest.magicValue == TWO_BRIDGES_MAGIC_VALUE, "Bridgehub: magic value mismatch"); + if (outputRequest.magicValue != TWO_BRIDGES_MAGIC_VALUE) { + revert WrongMagicValue(uint256(TWO_BRIDGES_MAGIC_VALUE), uint256(outputRequest.magicValue)); + } address refundRecipient = AddressAliasHelper.actualRefundRecipient(_request.refundRecipient, msg.sender); - require( - _request.secondBridgeAddress > BRIDGEHUB_MIN_SECOND_BRIDGE_ADDRESS, - "Bridgehub: second bridge address too low" - ); // to avoid calls to precompiles + if (_request.secondBridgeAddress <= BRIDGEHUB_MIN_SECOND_BRIDGE_ADDRESS) { + revert AddressTooLow(_request.secondBridgeAddress); + } + // to avoid calls to precompiles canonicalTxHash = IZkSyncHyperchain(hyperchain).bridgehubRequestL2Transaction( BridgehubL2TransactionRequest({ sender: _request.secondBridgeAddress, diff --git a/l1-contracts/contracts/bridgehub/IBridgehub.sol b/l1-contracts/contracts/bridgehub/IBridgehub.sol index 1204bc1d4..4216a6840 100644 --- a/l1-contracts/contracts/bridgehub/IBridgehub.sol +++ b/l1-contracts/contracts/bridgehub/IBridgehub.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 {IL1SharedBridge} from "../bridge/interfaces/IL1SharedBridge.sol"; import {L2Message, L2Log, TxStatus} from "../common/Messaging.sol"; diff --git a/l1-contracts/contracts/common/Config.sol b/l1-contracts/contracts/common/Config.sol index 72ca11aa1..c0e05f1fc 100644 --- a/l1-contracts/contracts/common/Config.sol +++ b/l1-contracts/contracts/common/Config.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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; /// @dev `keccak256("")` bytes32 constant EMPTY_STRING_KECCAK = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; @@ -21,10 +21,10 @@ bytes32 constant L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH = 0x72abee45b59e344af8a6e5202 // TODO: change constant to the real root hash of empty Merkle tree (SMA-184) bytes32 constant DEFAULT_L2_LOGS_TREE_ROOT_HASH = bytes32(0); -/// @dev Denotes the type of the zkSync transaction that came from L1. +/// @dev Denotes the type of the ZKsync transaction that came from L1. uint256 constant PRIORITY_OPERATION_L2_TX_TYPE = 255; -/// @dev Denotes the type of the zkSync transaction that is used for system upgrades. +/// @dev Denotes the type of the ZKsync transaction that is used for system upgrades. uint256 constant SYSTEM_UPGRADE_L2_TX_TYPE = 254; /// @dev The maximal allowed difference between protocol minor versions in an upgrade. The 100 gap is needed diff --git a/l1-contracts/contracts/common/Dependencies.sol b/l1-contracts/contracts/common/Dependencies.sol index 6c4d46f2e..fceaa77dd 100644 --- a/l1-contracts/contracts/common/Dependencies.sol +++ b/l1-contracts/contracts/common/Dependencies.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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-next-line no-unused-import */ -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; /* solhint-disable-next-line no-unused-import */ -import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; diff --git a/l1-contracts/contracts/common/L1ContractErrors.sol b/l1-contracts/contracts/common/L1ContractErrors.sol new file mode 100644 index 000000000..73ff72cc9 --- /dev/null +++ b/l1-contracts/contracts/common/L1ContractErrors.sol @@ -0,0 +1,337 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +// 0x1ff9d522 +error AddressAlreadyUsed(address addr); +// 0x86bb51b8 +error AddressHasNoCode(address); +// 0x1eee5481 +error AddressTooLow(address); +// 0x6afd6c20 +error BadReturnData(); +// 0x6ef9a972 +error BaseTokenGasPriceDenominatorNotSet(); +// 0x55ad3fd3 +error BatchHashMismatch(bytes32 expected, bytes32 actual); +// 0x2078a6a0 +error BatchNotExecuted(uint256 batchNumber); +// 0xbd4455ff +error BatchNumberMismatch(uint256 expectedBatchNumber, uint256 providedBatchNumber); +// 0xafd53e2f +error BlobHashCommitmentError(uint256 index, bool blobHashEmpty, bool blobCommitmentEmpty); +// 0x6cf12312 +error BridgeHubAlreadyRegistered(); +// 0xcf102c5a +error CalldataLengthTooBig(); +// 0xe85392f9 +error CanOnlyProcessOneBatch(); +// 0x00c6ead2 +error CantExecuteUnprovenBatches(); +// 0xe18cb383 +error CantRevertExecutedBatch(); +// 0x78d2ed02 +error ChainAlreadyLive(); +// 0x8f620a06 +error ChainIdTooBig(); +// 0xf7a01e4d +error DelegateCallFailed(bytes returnData); +// 0x0a8ed92c +error DenominatorIsZero(); +// 0xc7c9660f +error DepositDoesNotExist(); +// 0xad2fa98e +error DepositExists(); +// 0x79cacff1 +error DepositFailed(); +// 0xae08e4af +error DepositIncorrectAmount(uint256 expectedAmt, uint256 providedAmt); +// 0x0e7ee319 +error DiamondAlreadyFrozen(); +// 0x682dabb4 +error DiamondFreezeIncorrectState(); +// 0xa7151b9a +error DiamondNotFrozen(); +// 0xfc7ab1d3 +error EmptyBlobVersionHash(uint256 index); +// 0x95b66fe9 +error EmptyDeposit(); +// 0xac4a3f98 +error FacetExists(bytes4 selector, address); +// 0x79e12cc3 +error FacetIsFrozen(bytes4 func); +// 0xc91cf3b1 +error GasPerPubdataMismatch(); +// 0x6d4a7df8 +error GenesisBatchCommitmentZero(); +// 0x7940c83f +error GenesisBatchHashZero(); +// 0xb4fc6835 +error GenesisIndexStorageZero(); +// 0x3a1a8589 +error GenesisUpgradeZero(); +// 0xd356e6ba +error HashedLogIsDefault(); +// 0x0b08d5be +error HashMismatch(bytes32 expected, bytes32 actual); +// 0xb615c2b1 +error HyperchainLimitReached(); +// 0x826fb11e +error InsufficientChainBalance(); +// 0x356680b7 +error InsufficientFunds(); +// 0x7a47c9a2 +error InvalidChainId(); +// 0x4fbe5dba +error InvalidDelay(); +// 0x0af806e0 +error InvalidHash(); +// 0xc1780bd6 +error InvalidLogSender(address sender, uint256 logKey); +// 0xd8e9405c +error InvalidNumberOfBlobs(uint256 expected, uint256 numCommitments, uint256 numHashes); +// 0x09bde339 +error InvalidProof(); +// 0x5428eae7 +error InvalidProtocolVersion(); +// 0x53e6d04d +error InvalidPubdataCommitmentsSize(); +// 0x5513177c +error InvalidPubdataHash(bytes32 expectedHash, bytes32 provided); +// 0x9094af7e +error InvalidPubdataLength(); +// 0xc5d09071 +error InvalidPubdataMode(); +// 0x6f1cf752 +error InvalidPubdataPricingMode(); +// 0x12ba286f +error InvalidSelector(bytes4 func); +// 0x5cb29523 +error InvalidTxType(uint256 txType); +// 0x5f1aa154 +error InvalidUpgradeTxn(UpgradeTxVerifyParam); +// 0xaa7feadc +error InvalidValue(); +// 0xa4f62e33 +error L2BridgeNotDeployed(uint256 chainId); +// 0xff8811ff +error L2BridgeNotSet(uint256 chainId); +// 0xcb5e4247 +error L2BytecodeHashMismatch(bytes32 expected, bytes32 provided); +// 0xfb5c22e6 +error L2TimestampTooBig(); +// 0xd2c011d6 +error L2UpgradeNonceNotEqualToNewProtocolVersion(uint256 nonce, uint256 protocolVersion); +// 0x97e1359e +error L2WithdrawalMessageWrongLength(uint256 messageLen); +// 0x32eb8b2f +error LegacyMethodIsSupportedOnlyForEra(); +// 0xe37d2c02 +error LengthIsNotDivisibleBy32(uint256 length); +// 0x1b6825bb +error LogAlreadyProcessed(uint8); +// 0x43e266b0 +error MalformedBytecode(BytecodeError); +// 0x59170bf0 +error MalformedCalldata(); +// 0x16509b9a +error MalformedMessage(); +// 0x9bb54c35 +error MerkleIndexOutOfBounds(); +// 0x8e23ac1a +error MerklePathEmpty(); +// 0x1c500385 +error MerklePathOutOfBounds(); +// 0xfa44b527 +error MissingSystemLogs(uint256 expected, uint256 actual); +// 0x4a094431 +error MsgValueMismatch(uint256 expectedMsgValue, uint256 providedMsgValue); +// 0xb385a3da +error MsgValueTooLow(uint256 required, uint256 provided); +// 0x72ea85ad +error NewProtocolMajorVersionNotZero(); +// 0x79cc2d22 +error NoCallsProvided(); +// 0xa6fef710 +error NoFunctionsForDiamondCut(); +// 0xcab098d8 +error NoFundsTransferred(); +// 0x92290acc +error NonEmptyBlobVersionHash(uint256 index); +// 0xc21b1ab7 +error NonEmptyCalldata(); +// 0x536ec84b +error NonEmptyMsgValue(); +// 0xd018e08e +error NonIncreasingTimestamp(); +// 0x0105f9c0 +error NonSequentialBatch(); +// 0x4ef79e5a +error NonZeroAddress(address); +// 0xdd629f86 +error NotEnoughGas(); +// 0xdd7e3621 +error NotInitializedReentrancyGuard(); +// 0xf3ed9dfa +error OnlyEraSupported(); +// 0x1a21feed +error OperationExists(); +// 0xeda2fbb1 +error OperationMustBePending(); +// 0xe1c1ff37 +error OperationMustBeReady(); +// 0xd7f50a9d +error PatchCantSetUpgradeTxn(); +// 0x962fd7d0 +error PatchUpgradeCantSetBootloader(); +// 0x559cc34e +error PatchUpgradeCantSetDefaultAccount(); +// 0x8d5851de +error PointEvalCallFailed(bytes); +// 0x4daa985d +error PointEvalFailed(bytes); +// 0x9b48e060 +error PreviousOperationNotExecuted(); +// 0x5c598b60 +error PreviousProtocolMajorVersionNotZero(); +// 0xa0f47245 +error PreviousUpgradeNotCleaned(); +// 0x101ba748 +error PreviousUpgradeNotFinalized(bytes32 txHash); +// 0xd5a99014 +error PriorityOperationsRollingHashMismatch(); +// 0x1a4d284a +error PriorityTxPubdataExceedsMaxPubDataPerBatch(); +// 0xa461f651 +error ProtocolIdMismatch(uint256 expectedProtocolVersion, uint256 providedProtocolId); +// 0x64f94ec2 +error ProtocolIdNotGreater(); +// 0xd328c12a +error ProtocolVersionMinorDeltaTooBig(uint256 limit, uint256 proposed); +// 0x88d7b498 +error ProtocolVersionTooSmall(); +// 0x53dee67b +error PubdataCommitmentsEmpty(); +// 0x7734c31a +error PubdataCommitmentsTooBig(); +// 0x959f26fb +error PubdataGreaterThanLimit(uint256 limit, uint256 length); +// 0x2a4a14df +error PubdataPerBatchIsLessThanTxn(); +// 0x63c36549 +error QueueIsEmpty(); +// 0xab143c06 +error Reentrancy(); +// 0x667d17de +error RemoveFunctionFacetAddressNotZero(address facet); +// 0xa2d4b16c +error RemoveFunctionFacetAddressZero(); +// 0x3580370c +error ReplaceFunctionFacetAddressZero(); +// 0xdab52f4b +error RevertedBatchBeforeNewBatch(); +// 0x9a67c1cb +error RevertedBatchNotAfterNewLastBatch(); +// 0xd3b6535b +error SelectorsMustAllHaveSameFreezability(); +// 0x7774d2f9 +error SharedBridgeValueNotSet(SharedBridgeKey); +// 0xc1d9246c +error SharedBridgeBalanceMismatch(); +// 0x856d5b77 +error SharedBridgeNotSet(); +// 0xcac5fc40 +error SharedBridgeValueAlreadySet(SharedBridgeKey); +// 0xdf3a8fdd +error SlotOccupied(); +// 0xd0bc70cf +error STMAlreadyRegistered(); +// 0x09865e10 +error STMNotRegistered(); +// 0xae43b424 +error SystemLogsSizeTooBig(); +// 0x08753982 +error TimeNotReached(uint256 expectedTimestamp, uint256 actualTimestamp); +// 0x2d50c33b +error TimestampError(); +// 0x4f4b634e +error TokenAlreadyRegistered(address token); +// 0xddef98d7 +error TokenNotRegistered(address token); +// 0x06439c6b +error TokenNotSupported(address token); +// 0x23830e28 +error TokensWithFeesNotSupported(); +// 0xf640f0e5 +error TooManyBlobs(); +// 0x76da24b9 +error TooManyFactoryDeps(); +// 0xf0b4e88f +error TooMuchGas(); +// 0x00c5a6a9 +error TransactionNotAllowed(); +// 0x4c991078 +error TxHashMismatch(); +// 0x2e311df8 +error TxnBodyGasLimitNotEnoughGas(); +// 0x8e4a23d6 +error Unauthorized(address caller); +// 0xe52478c7 +error UndefinedDiamondCutAction(); +// 0x07218375 +error UnexpectedNumberOfFactoryDeps(); +// 0x6aa39880 +error UnexpectedSystemLog(uint256 logKey); +// 0xf093c2e5 +error UpgradeBatchNumberIsNotZero(); +// 0x47b3b145 +error ValidateTxnNotEnoughGas(); +// 0x626ade30 +error ValueMismatch(uint256 expected, uint256 actual); +// 0xe1022469 +error VerifiedBatchesExceedsCommittedBatches(); +// 0x2dbdba00 +error VerifyProofCommittedVerifiedMismatch(); +// 0xae899454 +error WithdrawalAlreadyFinalized(); +// 0x27fcd9d1 +error WithdrawalFailed(); +// 0x750b219c +error WithdrawFailed(); +// 0x15e8e429 +error WrongMagicValue(uint256 expectedMagicValue, uint256 providedMagicValue); +// 0xd92e233d +error ZeroAddress(); +// 0x669567ea +error ZeroBalance(); +// 0xc84885d4 +error ZeroChainId(); + +enum SharedBridgeKey { + PostUpgradeFirstBatch, + LegacyBridgeFirstBatch, + LegacyBridgeLastDepositBatch, + LegacyBridgeLastDepositTxn +} + +enum BytecodeError { + Version, + NumberOfWords, + Length, + WordsMustBeOdd +} + +enum UpgradeTxVerifyParam { + From, + To, + Paymaster, + Value, + MaxFeePerGas, + MaxPriorityFeePerGas, + Reserved0, + Reserved1, + Reserved2, + Reserved3, + Signature, + PaymasterInput, + ReservedDynamic +} diff --git a/l1-contracts/contracts/common/L2ContractAddresses.sol b/l1-contracts/contracts/common/L2ContractAddresses.sol index 0becefe72..571ef3d76 100644 --- a/l1-contracts/contracts/common/L2ContractAddresses.sol +++ b/l1-contracts/contracts/common/L2ContractAddresses.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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; /// @dev The formal address of the initial program of the system: the bootloader address constant L2_BOOTLOADER_ADDRESS = address(0x8001); diff --git a/l1-contracts/contracts/common/Messaging.sol b/l1-contracts/contracts/common/Messaging.sol index 3c934ae5f..a7a2db944 100644 --- a/l1-contracts/contracts/common/Messaging.sol +++ b/l1-contracts/contracts/common/Messaging.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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; /// @dev The enum that represents the transaction execution status /// @param Failure The transaction execution failed @@ -122,6 +122,7 @@ struct L2CanonicalTransaction { /// @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; diff --git a/l1-contracts/contracts/common/ReentrancyGuard.sol b/l1-contracts/contracts/common/ReentrancyGuard.sol index a19020b77..b1f8e556a 100644 --- a/l1-contracts/contracts/common/ReentrancyGuard.sol +++ b/l1-contracts/contracts/common/ReentrancyGuard.sol @@ -1,6 +1,8 @@ // 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; -pragma solidity 0.8.24; +import {SlotOccupied, NotInitializedReentrancyGuard, Reentrancy} from "./L1ContractErrors.sol"; /** * @custom:security-contact security@matterlabs.dev @@ -55,7 +57,9 @@ abstract contract ReentrancyGuard { } // Check that storage slot for reentrancy guard is empty to rule out possibility of slot conflict - require(lockSlotOldValue == 0, "1B"); + if (lockSlotOldValue != 0) { + revert SlotOccupied(); + } } /** @@ -71,8 +75,13 @@ abstract contract ReentrancyGuard { _status := sload(LOCK_FLAG_ADDRESS) } - // On the first call to nonReentrant, _notEntered will be true - require(_status == _NOT_ENTERED, "r1"); + if (_status == 0) { + revert NotInitializedReentrancyGuard(); + } + // On the first call to nonReentrant, _NOT_ENTERED will be true + if (_status != _NOT_ENTERED) { + revert Reentrancy(); + } // Any calls to nonReentrant after this point will fail assembly { diff --git a/l1-contracts/contracts/common/interfaces/IL2ContractDeployer.sol b/l1-contracts/contracts/common/interfaces/IL2ContractDeployer.sol index 31d796d45..3d5b597df 100644 --- a/l1-contracts/contracts/common/interfaces/IL2ContractDeployer.sol +++ b/l1-contracts/contracts/common/interfaces/IL2ContractDeployer.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 - * @notice System smart contract that is responsible for deploying other smart contracts on a zkSync hyperchain. + * @notice System smart contract that is responsible for deploying other smart contracts on a ZKsync hyperchain. */ interface IL2ContractDeployer { /// @notice A struct that describes a forced deployment on an address. diff --git a/l1-contracts/contracts/common/libraries/L2ContractHelper.sol b/l1-contracts/contracts/common/libraries/L2ContractHelper.sol index ae1a64250..21199f069 100644 --- a/l1-contracts/contracts/common/libraries/L2ContractHelper.sol +++ b/l1-contracts/contracts/common/libraries/L2ContractHelper.sol @@ -1,6 +1,8 @@ // 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; -pragma solidity 0.8.24; +import {BytecodeError, MalformedBytecode, LengthIsNotDivisibleBy32} from "../L1ContractErrors.sol"; /** * @author Matter Labs @@ -20,11 +22,19 @@ library L2ContractHelper { /// - Bytecode words length is not odd function hashL2Bytecode(bytes memory _bytecode) internal pure returns (bytes32 hashedBytecode) { // Note that the length of the bytecode must be provided in 32-byte words. - require(_bytecode.length % 32 == 0, "pq"); + if (_bytecode.length % 32 != 0) { + revert LengthIsNotDivisibleBy32(_bytecode.length); + } uint256 bytecodeLenInWords = _bytecode.length / 32; - require(bytecodeLenInWords < 2 ** 16, "pp"); // bytecode length must be less than 2^16 words - require(bytecodeLenInWords % 2 == 1, "ps"); // bytecode length in words must be odd + // bytecode length must be less than 2^16 words + if (bytecodeLenInWords >= 2 ** 16) { + revert MalformedBytecode(BytecodeError.NumberOfWords); + } + // bytecode length in words must be odd + if (bytecodeLenInWords % 2 == 0) { + revert MalformedBytecode(BytecodeError.WordsMustBeOdd); + } hashedBytecode = sha256(_bytecode) & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // Setting the version of the hash hashedBytecode = (hashedBytecode | bytes32(uint256(1 << 248))); @@ -38,9 +48,15 @@ library L2ContractHelper { /// @param _bytecodeHash The hash of the bytecode to validate. function validateBytecodeHash(bytes32 _bytecodeHash) internal pure { uint8 version = uint8(_bytecodeHash[0]); - require(version == 1 && _bytecodeHash[1] == bytes1(0), "zf"); // Incorrectly formatted bytecodeHash + // Incorrectly formatted bytecodeHash + if (version != 1 || _bytecodeHash[1] != bytes1(0)) { + revert MalformedBytecode(BytecodeError.Version); + } - require(bytecodeLen(_bytecodeHash) % 2 == 1, "uy"); // Code length in words must be odd + // Code length in words must be odd + if (bytecodeLen(_bytecodeHash) % 2 == 0) { + revert MalformedBytecode(BytecodeError.WordsMustBeOdd); + } } /// @notice Returns the length of the bytecode associated with the given hash. diff --git a/l1-contracts/contracts/common/libraries/SemVer.sol b/l1-contracts/contracts/common/libraries/SemVer.sol index d20f6a1d1..c46051626 100644 --- a/l1-contracts/contracts/common/libraries/SemVer.sol +++ b/l1-contracts/contracts/common/libraries/SemVer.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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; /// @dev The number of bits dedicated to the "patch" portion of the protocol version. /// This also defines the bit starting from which the "minor" part is located. diff --git a/l1-contracts/contracts/common/libraries/UncheckedMath.sol b/l1-contracts/contracts/common/libraries/UncheckedMath.sol index 6adfabf17..a41a9c6ea 100644 --- a/l1-contracts/contracts/common/libraries/UncheckedMath.sol +++ b/l1-contracts/contracts/common/libraries/UncheckedMath.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 diff --git a/l1-contracts/contracts/common/libraries/UnsafeBytes.sol b/l1-contracts/contracts/common/libraries/UnsafeBytes.sol index 5f0647489..d20bcbac8 100644 --- a/l1-contracts/contracts/common/libraries/UnsafeBytes.sol +++ b/l1-contracts/contracts/common/libraries/UnsafeBytes.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 diff --git a/l1-contracts/contracts/dev-contracts/Multicall.sol b/l1-contracts/contracts/dev-contracts/Multicall.sol index e2b1391dd..242c01e24 100644 --- a/l1-contracts/contracts/dev-contracts/Multicall.sol +++ b/l1-contracts/contracts/dev-contracts/Multicall.sol @@ -33,7 +33,8 @@ contract Multicall { function aggregate(Call[] memory calls) public returns (uint256 blockNumber, bytes[] memory returnData) { blockNumber = block.number; returnData = new bytes[](calls.length); - for (uint256 i = 0; i < calls.length; ++i) { + uint256 callsLength = calls.length; + for (uint256 i = 0; i < callsLength; ++i) { (bool success, bytes memory ret) = calls[i].target.call(calls[i].callData); require(success, "multicall 1"); returnData[i] = ret; diff --git a/l1-contracts/contracts/dev-contracts/RevertReceiveAccount.sol b/l1-contracts/contracts/dev-contracts/RevertReceiveAccount.sol index 31575de1b..663afdfdc 100644 --- a/l1-contracts/contracts/dev-contracts/RevertReceiveAccount.sol +++ b/l1-contracts/contracts/dev-contracts/RevertReceiveAccount.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.24; /// @title RevertReceiveAccount - An account which reverts receiving funds depending on the flag -/// @dev Used for testing failed withdrawals from the zkSync smart contract +/// @dev Used for testing failed withdrawals from the ZKsync smart contract contract RevertReceiveAccount { // add this to be excluded from coverage report function test() internal virtual {} diff --git a/l1-contracts/contracts/dev-contracts/RevertTransferERC20.sol b/l1-contracts/contracts/dev-contracts/RevertTransferERC20.sol index bd018276d..dcc1f71f7 100644 --- a/l1-contracts/contracts/dev-contracts/RevertTransferERC20.sol +++ b/l1-contracts/contracts/dev-contracts/RevertTransferERC20.sol @@ -5,7 +5,7 @@ pragma solidity 0.8.24; import {TestnetERC20Token} from "./TestnetERC20Token.sol"; /// @title RevertTransferERC20Token - A ERC20 token contract which can revert transfers depending on a flag -/// @dev Used for testing failed ERC-20 withdrawals from the zkSync smart contract +/// @dev Used for testing failed ERC-20 withdrawals from the ZKsync smart contract contract RevertTransferERC20 is TestnetERC20Token { // add this to be excluded from coverage report function test() internal override {} diff --git a/l1-contracts/contracts/dev-contracts/SingletonFactory.sol b/l1-contracts/contracts/dev-contracts/SingletonFactory.sol index b1bd999cf..3e8b9eec9 100644 --- a/l1-contracts/contracts/dev-contracts/SingletonFactory.sol +++ b/l1-contracts/contracts/dev-contracts/SingletonFactory.sol @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT pragma solidity 0.8.24; /** diff --git a/l1-contracts/contracts/dev-contracts/TestnetERC20Token.sol b/l1-contracts/contracts/dev-contracts/TestnetERC20Token.sol index 4eaddf921..2b189d1c9 100644 --- a/l1-contracts/contracts/dev-contracts/TestnetERC20Token.sol +++ b/l1-contracts/contracts/dev-contracts/TestnetERC20Token.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.24; -import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC20} from "@openzeppelin/contracts-v4/token/ERC20/ERC20.sol"; contract TestnetERC20Token is ERC20 { // add this to be excluded from coverage report diff --git a/l1-contracts/contracts/dev-contracts/test/DummyBridgehub.sol b/l1-contracts/contracts/dev-contracts/test/DummyBridgehub.sol new file mode 100644 index 000000000..79f9dc6e6 --- /dev/null +++ b/l1-contracts/contracts/dev-contracts/test/DummyBridgehub.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import {Bridgehub} from "../../bridgehub/Bridgehub.sol"; + +/// @title DummyBridgehub +/// @notice A test smart contract that allows to set State Transition Manager for a given chain +contract DummyBridgehub is Bridgehub { + // add this to be excluded from coverage report + function test() internal virtual {} + + constructor() Bridgehub() {} + + function setStateTransitionManager(uint256 _chainId, address _stm) external { + stateTransitionManager[_chainId] = _stm; + } +} diff --git a/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol b/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol index b626142a7..11be65a2b 100644 --- a/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol +++ b/l1-contracts/contracts/dev-contracts/test/DummyHyperchain.sol @@ -9,6 +9,10 @@ contract DummyHyperchain is MailboxFacet { s.bridgehub = bridgeHubAddress; } + function getEraChainId() public view returns (uint256) { + return ERA_CHAIN_ID; + } + function setBridgeHubAddress(address bridgeHubAddress) public { s.bridgehub = bridgeHubAddress; } diff --git a/l1-contracts/contracts/dev-contracts/test/DummySharedBridge.sol b/l1-contracts/contracts/dev-contracts/test/DummySharedBridge.sol index 6e61902f0..bebdbe49d 100644 --- a/l1-contracts/contracts/dev-contracts/test/DummySharedBridge.sol +++ b/l1-contracts/contracts/dev-contracts/test/DummySharedBridge.sol @@ -2,12 +2,17 @@ pragma solidity 0.8.24; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {L2TransactionRequestTwoBridgesInner} from "../../bridgehub/IBridgehub.sol"; -import {TWO_BRIDGES_MAGIC_VALUE} from "../../common/Config.sol"; +import {TWO_BRIDGES_MAGIC_VALUE, ETH_TOKEN_ADDRESS} from "../../common/Config.sol"; +import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/security/PausableUpgradeable.sol"; +import {SafeERC20} from "@openzeppelin/contracts-v4/token/ERC20/utils/SafeERC20.sol"; +import {IL2Bridge} from "../../bridge/interfaces/IL2Bridge.sol"; + +contract DummySharedBridge is PausableUpgradeable { + using SafeERC20 for IERC20; -contract DummySharedBridge { event BridgehubDepositBaseTokenInitiated( uint256 indexed chainId, address indexed from, @@ -19,7 +24,7 @@ contract DummySharedBridge { /// @dev Maps token balances for each chain to prevent unauthorized spending across hyperchains. /// This serves as a security measure until hyperbridging is implemented. - mapping(uint256 chainId => mapping(address l1Token => uint256 balance)) internal chainBalance; + mapping(uint256 chainId => mapping(address l1Token => uint256 balance)) public chainBalance; /// @dev Indicates whether the hyperbridging is enabled for a given chain. mapping(uint256 chainId => bool enabled) internal hyperbridgingEnabled; @@ -38,6 +43,8 @@ contract DummySharedBridge { amountReturnInFinalizeWithdrawal = _amount; } + function receiveEth(uint256 _chainId) external payable {} + function depositLegacyErc20Bridge( address, //_msgSender, address, //_l2Receiver, @@ -75,12 +82,51 @@ contract DummySharedBridge { event Debugger(uint256); + function pause() external { + _pause(); + } + + function unpause() external { + _unpause(); + } + + // This function expects abi encoded data + function _parseL2WithdrawalMessage( + bytes memory _l2ToL1message + ) internal view returns (address l1Receiver, address l1Token, uint256 amount) { + (l1Receiver, l1Token, amount) = abi.decode(_l2ToL1message, (address, address, uint256)); + } + + // simple function to just transfer the funds + function finalizeWithdrawal( + uint256 _chainId, + uint256 _l2BatchNumber, + uint256 _l2MessageIndex, + uint16 _l2TxNumberInBatch, + bytes calldata _message, + bytes32[] calldata _merkleProof + ) external { + (address l1Receiver, address l1Token, uint256 amount) = _parseL2WithdrawalMessage(_message); + + if (l1Token == address(1)) { + bool callSuccess; + // Low-level assembly call, to avoid any memory copying (save gas) + assembly { + callSuccess := call(gas(), l1Receiver, amount, 0, 0, 0, 0) + } + require(callSuccess, "ShB: withdraw failed"); + } else { + // Withdraw funds + IERC20(l1Token).safeTransfer(l1Receiver, amount); + } + } + function bridgehubDepositBaseToken( uint256 _chainId, address _prevMsgSender, address _l1Token, uint256 _amount - ) external payable { + ) external payable whenNotPaused { if (_l1Token == address(1)) { require(msg.value == _amount, "L1SharedBridge: msg.value not equal to amount"); } else { @@ -108,14 +154,33 @@ contract DummySharedBridge { } function bridgehubDeposit( - uint256, //_chainId, - address, //_prevMsgSender, - uint256, // l2Value, needed for Weth deposits in the future - bytes calldata //_data + uint256, + address _prevMsgSender, + uint256, + bytes calldata _data ) external payable returns (L2TransactionRequestTwoBridgesInner memory request) { - // Request the finalization of the deposit on the L2 side - bytes memory l2TxCalldata = bytes("0xabcd123"); - bytes32 txDataHash = bytes32("0x1212121212abf"); + (address _l1Token, uint256 _depositAmount, address _l2Receiver) = abi.decode( + _data, + (address, uint256, address) + ); + uint256 amount; + + if (_l1Token == ETH_TOKEN_ADDRESS) { + amount = msg.value; + require(_depositAmount == 0, "ShB wrong withdraw amount"); + } else { + require(msg.value == 0, "ShB m.v > 0 for BH d.it 2"); + amount = _depositAmount; + + uint256 withdrawAmount = _depositFunds(_prevMsgSender, IERC20(_l1Token), _depositAmount); + require(withdrawAmount == _depositAmount, "5T"); // The token has non-standard transfer logic + } + + bytes memory l2TxCalldata = abi.encodeCall( + IL2Bridge.finalizeDeposit, + (_prevMsgSender, _l2Receiver, _l1Token, amount, new bytes(0)) + ); + bytes32 txDataHash = keccak256(abi.encode(_prevMsgSender, _l1Token, amount)); request = L2TransactionRequestTwoBridgesInner({ magicValue: TWO_BRIDGES_MAGIC_VALUE, diff --git a/l1-contracts/contracts/dev-contracts/test/DummyStateTransitionManager.sol b/l1-contracts/contracts/dev-contracts/test/DummyStateTransitionManager.sol index b13050318..fba37465e 100644 --- a/l1-contracts/contracts/dev-contracts/test/DummyStateTransitionManager.sol +++ b/l1-contracts/contracts/dev-contracts/test/DummyStateTransitionManager.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.24; -import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; +import {EnumerableMap} from "@openzeppelin/contracts-v4/utils/structs/EnumerableMap.sol"; import {StateTransitionManager} from "../../state-transition/StateTransitionManager.sol"; diff --git a/l1-contracts/contracts/dev-contracts/test/DummyStateTransitionManagerWithBridgeHubAddress.sol b/l1-contracts/contracts/dev-contracts/test/DummyStateTransitionManagerWithBridgeHubAddress.sol index 883d74ca1..5109f7b77 100644 --- a/l1-contracts/contracts/dev-contracts/test/DummyStateTransitionManagerWithBridgeHubAddress.sol +++ b/l1-contracts/contracts/dev-contracts/test/DummyStateTransitionManagerWithBridgeHubAddress.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.24; -import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; +import {EnumerableMap} from "@openzeppelin/contracts-v4/utils/structs/EnumerableMap.sol"; import {StateTransitionManager} from "../../state-transition/StateTransitionManager.sol"; diff --git a/l1-contracts/contracts/governance/ChainAdmin.sol b/l1-contracts/contracts/governance/ChainAdmin.sol index 874255d38..4d9ff858f 100644 --- a/l1-contracts/contracts/governance/ChainAdmin.sol +++ b/l1-contracts/contracts/governance/ChainAdmin.sol @@ -2,9 +2,10 @@ pragma solidity 0.8.24; -import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {Ownable2Step} from "@openzeppelin/contracts-v4/access/Ownable2Step.sol"; import {IChainAdmin} from "./IChainAdmin.sol"; import {IAdmin} from "../state-transition/chain-interfaces/IAdmin.sol"; +import {NoCallsProvided, Unauthorized, ZeroAddress} from "../common/L1ContractErrors.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -23,7 +24,9 @@ contract ChainAdmin is IChainAdmin, Ownable2Step { address public tokenMultiplierSetter; constructor(address _initialOwner, address _initialTokenMultiplierSetter) { - require(_initialOwner != address(0), "Initial owner should be non zero address"); + if (_initialOwner == address(0)) { + revert ZeroAddress(); + } _transferOwnership(_initialOwner); // Can be zero if no one has this permission. tokenMultiplierSetter = _initialTokenMultiplierSetter; @@ -50,7 +53,10 @@ contract ChainAdmin is IChainAdmin, Ownable2Step { /// @param _requireSuccess If true, reverts transaction on any call failure. /// @dev Intended for batch processing of contract interactions, managing gas efficiency and atomicity of operations. function multicall(Call[] calldata _calls, bool _requireSuccess) external payable onlyOwner { - require(_calls.length > 0, "No calls provided"); + if (_calls.length == 0) { + revert NoCallsProvided(); + } + // solhint-disable-next-line gas-length-in-loops for (uint256 i = 0; i < _calls.length; ++i) { // slither-disable-next-line arbitrary-send-eth (bool success, bytes memory returnData) = _calls[i].target.call{value: _calls[i].value}(_calls[i].data); @@ -69,7 +75,9 @@ contract ChainAdmin is IChainAdmin, Ownable2Step { /// @param _nominator The numerator part of the token multiplier. /// @param _denominator The denominator part of the token multiplier. function setTokenMultiplier(IAdmin _chainContract, uint128 _nominator, uint128 _denominator) external { - require(msg.sender == tokenMultiplierSetter, "Only the token multiplier setter can call this function"); + if (msg.sender != tokenMultiplierSetter) { + revert Unauthorized(msg.sender); + } _chainContract.setTokenMultiplier(_nominator, _denominator); } diff --git a/l1-contracts/contracts/governance/Governance.sol b/l1-contracts/contracts/governance/Governance.sol index 42ac46e02..790b79a26 100644 --- a/l1-contracts/contracts/governance/Governance.sol +++ b/l1-contracts/contracts/governance/Governance.sol @@ -2,8 +2,9 @@ pragma solidity 0.8.24; -import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {Ownable2Step} from "@openzeppelin/contracts-v4/access/Ownable2Step.sol"; import {IGovernance} from "./IGovernance.sol"; +import {ZeroAddress, Unauthorized, OperationMustBeReady, OperationMustBePending, OperationExists, InvalidDelay, PreviousOperationNotExecuted} from "../common/L1ContractErrors.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -11,7 +12,7 @@ import {IGovernance} from "./IGovernance.sol"; /// @notice This contract manages operations (calls with preconditions) for governance tasks. /// The contract allows for operations to be scheduled, executed, and canceled with /// appropriate permissions and delays. It is used for managing and coordinating upgrades -/// and changes in all zkSync hyperchain governed contracts. +/// and changes in all ZKsync hyperchain governed contracts. /// /// Operations can be proposed as either fully transparent upgrades with on-chain data, /// or "shadow" upgrades where upgrade data is not published on-chain before execution. Proposed operations @@ -38,8 +39,11 @@ contract Governance is IGovernance, Ownable2Step { /// @param _admin The address to be assigned as the admin of the contract. /// @param _securityCouncil The address to be assigned as the security council of the contract. /// @param _minDelay The initial minimum delay (in seconds) to be set for operations. + /// @dev We allow for a zero address for _securityCouncil because it can be set later constructor(address _admin, address _securityCouncil, uint256 _minDelay) { - require(_admin != address(0), "Admin should be non zero address"); + if (_admin == address(0)) { + revert ZeroAddress(); + } _transferOwnership(_admin); @@ -56,22 +60,25 @@ contract Governance is IGovernance, Ownable2Step { /// @notice Checks that the message sender is contract itself. modifier onlySelf() { - require(msg.sender == address(this), "Only governance contract itself is allowed to call this function"); + if (msg.sender != address(this)) { + revert Unauthorized(msg.sender); + } _; } /// @notice Checks that the message sender is an active security council. modifier onlySecurityCouncil() { - require(msg.sender == securityCouncil, "Only security council is allowed to call this function"); + if (msg.sender != securityCouncil) { + revert Unauthorized(msg.sender); + } _; } /// @notice Checks that the message sender is an active owner or an active security council. modifier onlyOwnerOrSecurityCouncil() { - require( - msg.sender == owner() || msg.sender == securityCouncil, - "Only the owner and security council are allowed to call this function" - ); + if (msg.sender != owner() && msg.sender != securityCouncil) { + revert Unauthorized(msg.sender); + } _; } @@ -152,7 +159,9 @@ contract Governance is IGovernance, Ownable2Step { /// @dev Only owner can call this function. /// @param _id Proposal id value (see `hashOperation`) function cancel(bytes32 _id) external onlyOwner { - require(isOperationPending(_id), "Operation must be pending"); + if (!isOperationPending(_id)) { + revert OperationMustBePending(); + } delete timestamps[_id]; emit OperationCancelled(_id); } @@ -170,13 +179,17 @@ contract Governance is IGovernance, Ownable2Step { // Check if the predecessor operation is completed. _checkPredecessorDone(_operation.predecessor); // Ensure that the operation is ready to proceed. - require(isOperationReady(id), "Operation must be ready before execution"); + if (!isOperationReady(id)) { + revert OperationMustBeReady(); + } // Execute operation. // slither-disable-next-line reentrancy-eth _execute(_operation.calls); // Reconfirming that the operation is still ready after execution. // This is needed to avoid unexpected reentrancy attacks of re-executing the same operation. - require(isOperationReady(id), "Operation must be ready after execution"); + if (!isOperationReady(id)) { + revert OperationMustBeReady(); + } // Set operation to be done timestamps[id] = EXECUTED_PROPOSAL_TIMESTAMP; emit OperationExecuted(id); @@ -191,13 +204,17 @@ contract Governance is IGovernance, Ownable2Step { // Check if the predecessor operation is completed. _checkPredecessorDone(_operation.predecessor); // Ensure that the operation is in a pending state before proceeding. - require(isOperationPending(id), "Operation must be pending before execution"); + if (!isOperationPending(id)) { + revert OperationMustBePending(); + } // Execute operation. // slither-disable-next-line reentrancy-eth _execute(_operation.calls); // Reconfirming that the operation is still pending before execution. // This is needed to avoid unexpected reentrancy attacks of re-executing the same operation. - require(isOperationPending(id), "Operation must be pending after execution"); + if (!isOperationPending(id)) { + revert OperationMustBePending(); + } // Set operation to be done timestamps[id] = EXECUTED_PROPOSAL_TIMESTAMP; emit OperationExecuted(id); @@ -217,8 +234,12 @@ contract Governance is IGovernance, Ownable2Step { /// @param _id The operation hash (see `hashOperation` function) /// @param _delay The delay time (in seconds) after which the proposed upgrade can be executed by the owner. function _schedule(bytes32 _id, uint256 _delay) internal { - require(!isOperation(_id), "Operation with this proposal id already exists"); - require(_delay >= minDelay, "Proposed delay is less than minimum delay"); + if (isOperation(_id)) { + revert OperationExists(); + } + if (_delay < minDelay) { + revert InvalidDelay(); + } timestamps[_id] = block.timestamp + _delay; } @@ -226,6 +247,8 @@ contract Governance is IGovernance, Ownable2Step { /// @dev Execute an operation's calls. /// @param _calls The array of calls to be executed. function _execute(Call[] calldata _calls) internal { + // We disable this check because calldata array length is cheap. + // solhint-disable-next-line gas-length-in-loops for (uint256 i = 0; i < _calls.length; ++i) { // slither-disable-next-line arbitrary-send-eth (bool success, bytes memory returnData) = _calls[i].target.call{value: _calls[i].value}(_calls[i].data); @@ -242,7 +265,9 @@ contract Governance is IGovernance, Ownable2Step { /// @param _predecessorId The hash of the operation that should be completed. /// @dev Doesn't check the operation to be complete if the input is zero. function _checkPredecessorDone(bytes32 _predecessorId) internal view { - require(_predecessorId == bytes32(0) || isOperationDone(_predecessorId), "Predecessor operation not completed"); + if (_predecessorId != bytes32(0) && !isOperationDone(_predecessorId)) { + revert PreviousOperationNotExecuted(); + } } /*////////////////////////////////////////////////////////////// diff --git a/l1-contracts/contracts/governance/IGovernance.sol b/l1-contracts/contracts/governance/IGovernance.sol index 2b0228203..2b03ed4c9 100644 --- a/l1-contracts/contracts/governance/IGovernance.sol +++ b/l1-contracts/contracts/governance/IGovernance.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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; /// @title Governance contract interface /// @author Matter Labs diff --git a/l1-contracts/contracts/state-transition/IStateTransitionManager.sol b/l1-contracts/contracts/state-transition/IStateTransitionManager.sol index d58f46df5..fec1c31fd 100644 --- a/l1-contracts/contracts/state-transition/IStateTransitionManager.sol +++ b/l1-contracts/contracts/state-transition/IStateTransitionManager.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 {Diamond} from "./libraries/Diamond.sol"; import {L2CanonicalTransaction} from "../common/Messaging.sol"; @@ -26,6 +26,7 @@ struct StateTransitionManagerInitializeData { /// @param genesisIndexRepeatedStorageChanges The serial number of the shortcut storage key for the genesis batch /// @param genesisBatchCommitment The zk-proof commitment for the genesis batch /// @param diamondCut The diamond cut for the first upgrade transaction on the newly deployed chain +// solhint-disable-next-line gas-struct-packing struct ChainCreationParams { address genesisUpgrade; bytes32 genesisBatchHash; @@ -120,7 +121,7 @@ interface IStateTransitionManager { function setNewVersionUpgrade( Diamond.DiamondCutData calldata _cutData, uint256 _oldProtocolVersion, - uint256 _oldprotocolVersionDeadline, + uint256 _oldProtocolVersionDeadline, uint256 _newProtocolVersion ) external; diff --git a/l1-contracts/contracts/state-transition/StateTransitionManager.sol b/l1-contracts/contracts/state-transition/StateTransitionManager.sol index 37929f94c..0dbdd2ad1 100644 --- a/l1-contracts/contracts/state-transition/StateTransitionManager.sol +++ b/l1-contracts/contracts/state-transition/StateTransitionManager.sol @@ -2,8 +2,8 @@ pragma solidity 0.8.24; -import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol"; -import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {EnumerableMap} from "@openzeppelin/contracts-v4/utils/structs/EnumerableMap.sol"; +import {SafeCast} from "@openzeppelin/contracts-v4/utils/math/SafeCast.sol"; import {Diamond} from "./libraries/Diamond.sol"; import {DiamondProxy} from "./chain-deps/DiamondProxy.sol"; @@ -17,11 +17,12 @@ import {IZkSyncHyperchain} from "./chain-interfaces/IZkSyncHyperchain.sol"; import {FeeParams} from "./chain-deps/ZkSyncHyperchainStorage.sol"; import {L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, L2_FORCE_DEPLOYER_ADDR} from "../common/L2ContractAddresses.sol"; import {L2CanonicalTransaction} from "../common/Messaging.sol"; -import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; import {ProposedUpgrade} from "../upgrades/BaseZkSyncUpgrade.sol"; import {ReentrancyGuard} from "../common/ReentrancyGuard.sol"; import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA, L2_TO_L1_LOG_SERIALIZE_SIZE, DEFAULT_L2_LOGS_TREE_ROOT_HASH, EMPTY_STRING_KECCAK, SYSTEM_UPGRADE_L2_TX_TYPE, PRIORITY_TX_MAX_GAS_LIMIT} from "../common/Config.sol"; import {VerifierParams} from "./chain-interfaces/IVerifier.sol"; +import {Unauthorized, ZeroAddress, HashMismatch, HyperchainLimitReached, GenesisUpgradeZero, GenesisBatchHashZero, GenesisIndexStorageZero, GenesisBatchCommitmentZero} from "../common/L1ContractErrors.sol"; import {SemVer} from "../common/libraries/SemVer.sol"; /// @title State Transition Manager contract @@ -80,13 +81,17 @@ contract StateTransitionManager is IStateTransitionManager, ReentrancyGuard, Own /// @notice only the bridgehub can call modifier onlyBridgehub() { - require(msg.sender == BRIDGE_HUB, "STM: only bridgehub"); + if (msg.sender != BRIDGE_HUB) { + revert Unauthorized(msg.sender); + } _; } /// @notice the admin can call, for non-critical updates modifier onlyOwnerOrAdmin() { - require(msg.sender == admin || msg.sender == owner(), "STM: not owner or admin"); + if (msg.sender != admin && msg.sender != owner()) { + revert Unauthorized(msg.sender); + } _; } @@ -100,7 +105,8 @@ contract StateTransitionManager is IStateTransitionManager, ReentrancyGuard, Own function getAllHyperchains() public view override returns (address[] memory chainAddresses) { uint256[] memory keys = hyperchainMap.keys(); chainAddresses = new address[](keys.length); - for (uint256 i = 0; i < keys.length; i++) { + uint256 keysLength = keys.length; + for (uint256 i = 0; i < keysLength; ++i) { chainAddresses[i] = hyperchainMap.get(keys[i]); } } @@ -125,7 +131,9 @@ contract StateTransitionManager is IStateTransitionManager, ReentrancyGuard, Own function initialize( StateTransitionManagerInitializeData calldata _initializeData ) external reentrancyGuardInitializer { - require(_initializeData.owner != address(0), "STM: owner zero"); + if (_initializeData.owner == address(0)) { + revert ZeroAddress(); + } _transferOwnership(_initializeData.owner); protocolVersion = _initializeData.protocolVersion; @@ -138,13 +146,18 @@ contract StateTransitionManager is IStateTransitionManager, ReentrancyGuard, Own /// @notice Updates the parameters with which a new chain is created /// @param _chainCreationParams The new chain creation parameters function _setChainCreationParams(ChainCreationParams calldata _chainCreationParams) internal { - require(_chainCreationParams.genesisUpgrade != address(0), "STM: genesisUpgrade zero"); - require(_chainCreationParams.genesisBatchHash != bytes32(0), "STM: genesisBatchHash zero"); - require( - _chainCreationParams.genesisIndexRepeatedStorageChanges != uint64(0), - "STM: genesisIndexRepeatedStorageChanges zero" - ); - require(_chainCreationParams.genesisBatchCommitment != bytes32(0), "STM: genesisBatchCommitment zero"); + if (_chainCreationParams.genesisUpgrade == address(0)) { + revert GenesisUpgradeZero(); + } + if (_chainCreationParams.genesisBatchHash == bytes32(0)) { + revert GenesisBatchHashZero(); + } + if (_chainCreationParams.genesisIndexRepeatedStorageChanges == uint64(0)) { + revert GenesisIndexStorageZero(); + } + if (_chainCreationParams.genesisBatchCommitment == bytes32(0)) { + revert GenesisBatchCommitmentZero(); + } genesisUpgrade = _chainCreationParams.genesisUpgrade; @@ -194,7 +207,10 @@ contract StateTransitionManager is IStateTransitionManager, ReentrancyGuard, Own /// @notice Accepts transfer of admin rights. Only pending admin can accept the role. function acceptAdmin() external { address currentPendingAdmin = pendingAdmin; - require(msg.sender == currentPendingAdmin, "n42"); // Only proposed by current admin address can claim the admin rights + // Only proposed by current admin address can claim the admin rights + if (msg.sender != currentPendingAdmin) { + revert Unauthorized(msg.sender); + } address previousAdmin = admin; admin = currentPendingAdmin; @@ -367,7 +383,9 @@ contract StateTransitionManager is IStateTransitionManager, ReentrancyGuard, Own /// @param _chainId the chain's id /// @param _hyperchain the chain's contract address function registerAlreadyDeployedHyperchain(uint256 _chainId, address _hyperchain) external onlyOwner { - require(_hyperchain != address(0), "STM: hyperchain zero"); + if (_hyperchain == address(0)) { + revert ZeroAddress(); + } _registerNewHyperchain(_chainId, _hyperchain); } @@ -395,7 +413,9 @@ contract StateTransitionManager is IStateTransitionManager, ReentrancyGuard, Own // check input bytes32 cutHashInput = keccak256(_diamondCut); - require(cutHashInput == initialCutHash, "STM: initial cutHash mismatch"); + if (cutHashInput != initialCutHash) { + revert HashMismatch(initialCutHash, cutHashInput); + } // construct init data bytes memory initData; @@ -406,12 +426,12 @@ contract StateTransitionManager is IStateTransitionManager, ReentrancyGuard, Own bytes32(_chainId), bytes32(uint256(uint160(BRIDGE_HUB))), bytes32(uint256(uint160(address(this)))), - bytes32(uint256(protocolVersion)), + bytes32(protocolVersion), bytes32(uint256(uint160(_admin))), bytes32(uint256(uint160(validatorTimelock))), bytes32(uint256(uint160(_baseToken))), bytes32(uint256(uint160(_sharedBridge))), - bytes32(storedBatchZero), + storedBatchZero, diamondCut.initCalldata ); @@ -432,7 +452,9 @@ contract StateTransitionManager is IStateTransitionManager, ReentrancyGuard, Own function _registerNewHyperchain(uint256 _chainId, address _hyperchain) internal { // slither-disable-next-line unused-return hyperchainMap.set(_chainId, _hyperchain); - require(hyperchainMap.length() <= MAX_NUMBER_OF_HYPERCHAINS, "STM: Hyperchain limit reached"); + if (hyperchainMap.length() > MAX_NUMBER_OF_HYPERCHAINS) { + revert HyperchainLimitReached(); + } emit NewHyperchain(_chainId, _hyperchain); } } diff --git a/l1-contracts/contracts/state-transition/ValidatorTimelock.sol b/l1-contracts/contracts/state-transition/ValidatorTimelock.sol index d793783d6..61576f74c 100644 --- a/l1-contracts/contracts/state-transition/ValidatorTimelock.sol +++ b/l1-contracts/contracts/state-transition/ValidatorTimelock.sol @@ -2,10 +2,11 @@ pragma solidity 0.8.24; -import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {Ownable2Step} from "@openzeppelin/contracts-v4/access/Ownable2Step.sol"; import {LibMap} from "./libraries/LibMap.sol"; import {IExecutor} from "./chain-interfaces/IExecutor.sol"; import {IStateTransitionManager} from "./IStateTransitionManager.sol"; +import {Unauthorized, TimeNotReached, ZeroAddress} from "../common/L1ContractErrors.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -13,7 +14,7 @@ import {IStateTransitionManager} from "./IStateTransitionManager.sol"; /// @dev The primary purpose of this contract is to provide a trustless means of delaying batch execution without /// modifying the main hyperchain diamond contract. As such, even if this contract is compromised, it will not impact the main /// contract. -/// @dev zkSync actively monitors the chain activity and reacts to any suspicious activity by freezing the chain. +/// @dev ZKsync actively monitors the chain activity and reacts to any suspicious activity by freezing the chain. /// This allows time for investigation and mitigation before resuming normal operations. /// @dev The contract overloads all of the 4 methods, that are used in state transition. When the batch is committed, /// the timestamp is stored for it. Later, when the owner calls the batch execution, the contract checks that batch @@ -52,7 +53,7 @@ contract ValidatorTimelock is IExecutor, Ownable2Step { uint32 public executionDelay; /// @dev Era's chainID - uint256 immutable ERA_CHAIN_ID; + uint256 internal immutable ERA_CHAIN_ID; constructor(address _initialOwner, uint32 _executionDelay, uint256 _eraChainId) { _transferOwnership(_initialOwner); @@ -62,18 +63,25 @@ contract ValidatorTimelock is IExecutor, Ownable2Step { /// @notice Checks if the caller is the admin of the chain. modifier onlyChainAdmin(uint256 _chainId) { - require(msg.sender == stateTransitionManager.getChainAdmin(_chainId), "ValidatorTimelock: only chain admin"); + if (msg.sender != stateTransitionManager.getChainAdmin(_chainId)) { + revert Unauthorized(msg.sender); + } _; } /// @notice Checks if the caller is a validator. modifier onlyValidator(uint256 _chainId) { - require(validators[_chainId][msg.sender], "ValidatorTimelock: only validator"); + if (!validators[_chainId][msg.sender]) { + revert Unauthorized(msg.sender); + } _; } /// @dev Sets a new state transition manager. function setStateTransitionManager(IStateTransitionManager _stateTransitionManager) external onlyOwner { + if (address(_stateTransitionManager) == address(0)) { + revert ZeroAddress(); + } stateTransitionManager = _stateTransitionManager; } @@ -130,6 +138,8 @@ contract ValidatorTimelock is IExecutor, Ownable2Step { // This contract is only a temporary solution, that hopefully will be disabled until 2106 year, so... // It is safe to cast. uint32 timestamp = uint32(block.timestamp); + // 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) { committedBatchTimestamp[_chainId].set(_newBatchesData[i].batchNumber, timestamp); } @@ -193,15 +203,19 @@ contract ValidatorTimelock is IExecutor, Ownable2Step { function _executeBatchesInner(uint256 _chainId, StoredBatchInfo[] calldata _newBatchesData) internal { uint256 delay = executionDelay; // uint32 unchecked { + // 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) { uint256 commitBatchTimestamp = committedBatchTimestamp[_chainId].get(_newBatchesData[i].batchNumber); // Note: if the `commitBatchTimestamp` is zero, that means either: // * The batch was committed, but not through this contract. - // * The batch wasn't committed at all, so execution will fail in the zkSync contract. + // * The batch wasn't committed at all, so execution will fail in the ZKsync contract. // We allow executing such batches. - require(block.timestamp >= commitBatchTimestamp + delay, "5c"); // The delay is not passed + if (block.timestamp < commitBatchTimestamp + delay) { + revert TimeNotReached(commitBatchTimestamp + delay, block.timestamp); + } } } _propagateToZkSyncHyperchain(_chainId); diff --git a/l1-contracts/contracts/state-transition/Verifier.sol b/l1-contracts/contracts/state-transition/Verifier.sol index 922f21ca3..a74ecb12c 100644 --- a/l1-contracts/contracts/state-transition/Verifier.sol +++ b/l1-contracts/contracts/state-transition/Verifier.sol @@ -8,13 +8,14 @@ import {IVerifier} from "./chain-interfaces/IVerifier.sol"; /// @author Matter Labs /// @notice Modified version of the Permutations over Lagrange-bases for Oecumenical Noninteractive arguments of /// Knowledge (PLONK) verifier. -/// Modifications have been made to optimize the proof system for zkSync hyperchain circuits. +/// Modifications have been made to optimize the proof system for ZKsync hyperchain circuits. +/// @dev Contract was generated from a verification key with a hash of 0x14f97b81e54b35fe673d8708cc1a19e1ea5b5e348e12d31e39824ed4f42bbca2 /// @dev It uses a custom memory layout inside the inline assembly block. Each reserved memory cell is declared in the /// constants below. /// @dev For a better understanding of the verifier algorithm please refer to the following papers: /// * Original Plonk Article: https://eprint.iacr.org/2019/953.pdf /// * Original LookUp Article: https://eprint.iacr.org/2020/315.pdf -/// * Plonk for zkSync v1.1: https://github.com/matter-labs/solidity_plonk_verifier/raw/recursive/bellman_vk_codegen_recursive/RecursivePlonkUnrolledForEthereum.pdf +/// * Plonk for ZKsync v1.1: https://github.com/matter-labs/solidity_plonk_verifier/raw/recursive/bellman_vk_codegen_recursive/RecursivePlonkUnrolledForEthereum.pdf /// The notation used in the code is the same as in the papers. /* solhint-enable max-line-length */ contract Verifier is IVerifier { diff --git a/l1-contracts/contracts/state-transition/chain-deps/DiamondInit.sol b/l1-contracts/contracts/state-transition/chain-deps/DiamondInit.sol index 424223396..663cf260a 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/DiamondInit.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/DiamondInit.sol @@ -6,6 +6,7 @@ import {Diamond} from "../libraries/Diamond.sol"; import {ZkSyncHyperchainBase} from "./facets/ZkSyncHyperchainBase.sol"; import {L2_TO_L1_LOG_SERIALIZE_SIZE, MAX_GAS_PER_TRANSACTION} from "../../common/Config.sol"; import {InitializeData, IDiamondInit} from "../chain-interfaces/IDiamondInit.sol"; +import {ZeroAddress, TooMuchGas} from "../../common/L1ContractErrors.sol"; /// @author Matter Labs /// @dev The contract is used only once to initialize the diamond proxy. @@ -18,15 +19,33 @@ contract DiamondInit is ZkSyncHyperchainBase, IDiamondInit { /// @return Magic 32 bytes, which indicates that the contract logic is expected to be used as a diamond proxy /// initializer function initialize(InitializeData calldata _initializeData) external reentrancyGuardInitializer returns (bytes32) { - require(address(_initializeData.verifier) != address(0), "vt"); - require(_initializeData.admin != address(0), "vy"); - require(_initializeData.validatorTimelock != address(0), "hc"); - require(_initializeData.priorityTxMaxGasLimit <= MAX_GAS_PER_TRANSACTION, "vu"); - require(_initializeData.bridgehub != address(0), "DiamondInit: b0"); - require(_initializeData.stateTransitionManager != address(0), "DiamondInit: stm0"); - require(_initializeData.baseToken != address(0), "DiamondInit: bt0"); - require(_initializeData.baseTokenBridge != address(0), "DiamondInit: btb0"); - require(_initializeData.blobVersionedHashRetriever != address(0), "DiamondInit: bvhr0"); + if (address(_initializeData.verifier) == address(0)) { + revert ZeroAddress(); + } + if (_initializeData.admin == address(0)) { + revert ZeroAddress(); + } + if (_initializeData.validatorTimelock == address(0)) { + revert ZeroAddress(); + } + if (_initializeData.priorityTxMaxGasLimit > MAX_GAS_PER_TRANSACTION) { + revert TooMuchGas(); + } + if (_initializeData.bridgehub == address(0)) { + revert ZeroAddress(); + } + if (_initializeData.stateTransitionManager == address(0)) { + revert ZeroAddress(); + } + if (_initializeData.baseToken == address(0)) { + revert ZeroAddress(); + } + if (_initializeData.baseTokenBridge == address(0)) { + revert ZeroAddress(); + } + if (_initializeData.blobVersionedHashRetriever == address(0)) { + revert ZeroAddress(); + } s.chainId = _initializeData.chainId; s.bridgehub = _initializeData.bridgehub; diff --git a/l1-contracts/contracts/state-transition/chain-deps/DiamondProxy.sol b/l1-contracts/contracts/state-transition/chain-deps/DiamondProxy.sol index 5cf26ac82..db29da126 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/DiamondProxy.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/DiamondProxy.sol @@ -2,6 +2,8 @@ pragma solidity 0.8.24; +// solhint-disable gas-custom-errors + import {Diamond} from "../libraries/Diamond.sol"; /// @title Diamond Proxy Contract (EIP-2535) diff --git a/l1-contracts/contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol b/l1-contracts/contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol index e76d86f24..a06921fdb 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol @@ -63,6 +63,7 @@ struct FeeParams { /// but NOT to modify already existing variables or change their order. /// NOTE: variables prefixed with '__DEPRECATED_' are deprecated and shouldn't be used. /// Their presence is maintained for compatibility and to prevent storage collision. +// solhint-disable-next-line gas-struct-packing struct ZkSyncHyperchainStorage { /// @dev Storage of variables needed for deprecated diamond cut facet uint256[7] __DEPRECATED_diamondCutStorage; 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 7eb6e7904..9f98c00ec 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/facets/Admin.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/facets/Admin.sol @@ -8,6 +8,7 @@ import {MAX_GAS_PER_TRANSACTION} from "../../../common/Config.sol"; import {FeeParams, PubdataPricingMode} from "../ZkSyncHyperchainStorage.sol"; import {ZkSyncHyperchainBase} from "./ZkSyncHyperchainBase.sol"; import {IStateTransitionManager} from "../../IStateTransitionManager.sol"; +import {Unauthorized, TooMuchGas, PriorityTxPubdataExceedsMaxPubDataPerBatch, InvalidPubdataPricingMode, ProtocolIdMismatch, ChainAlreadyLive, HashMismatch, ProtocolIdNotGreater, DenominatorIsZero, DiamondAlreadyFrozen, DiamondNotFrozen} from "../../../common/L1ContractErrors.sol"; // While formally the following import is not used, it is needed to inherit documentation from it import {IZkSyncHyperchainBase} from "../../chain-interfaces/IZkSyncHyperchainBase.sol"; @@ -31,7 +32,10 @@ contract AdminFacet is ZkSyncHyperchainBase, IAdmin { /// @inheritdoc IAdmin function acceptAdmin() external { address pendingAdmin = s.pendingAdmin; - require(msg.sender == pendingAdmin, "n4"); // Only proposed by current admin address can claim the admin rights + // Only proposed by current admin address can claim the admin rights + if (msg.sender != pendingAdmin) { + revert Unauthorized(msg.sender); + } address previousAdmin = s.admin; s.admin = pendingAdmin; @@ -56,7 +60,9 @@ contract AdminFacet is ZkSyncHyperchainBase, IAdmin { /// @inheritdoc IAdmin function setPriorityTxMaxGasLimit(uint256 _newPriorityTxMaxGasLimit) external onlyStateTransitionManager { - require(_newPriorityTxMaxGasLimit <= MAX_GAS_PER_TRANSACTION, "n5"); + if (_newPriorityTxMaxGasLimit > MAX_GAS_PER_TRANSACTION) { + revert TooMuchGas(); + } uint256 oldPriorityTxMaxGasLimit = s.priorityTxMaxGasLimit; s.priorityTxMaxGasLimit = _newPriorityTxMaxGasLimit; @@ -67,11 +73,16 @@ contract AdminFacet is ZkSyncHyperchainBase, IAdmin { function changeFeeParams(FeeParams calldata _newFeeParams) external onlyAdminOrStateTransitionManager { // Double checking that the new fee params are valid, i.e. // the maximal pubdata per batch is not less than the maximal pubdata per priority transaction. - require(_newFeeParams.maxPubdataPerBatch >= _newFeeParams.priorityTxMaxPubdata, "n6"); + if (_newFeeParams.maxPubdataPerBatch < _newFeeParams.priorityTxMaxPubdata) { + revert PriorityTxPubdataExceedsMaxPubDataPerBatch(); + } FeeParams memory oldFeeParams = s.feeParams; - require(_newFeeParams.pubdataPricingMode == oldFeeParams.pubdataPricingMode, "n7"); // we cannot change pubdata pricing mode + // we cannot change pubdata pricing mode + if (_newFeeParams.pubdataPricingMode != oldFeeParams.pubdataPricingMode) { + revert InvalidPubdataPricingMode(); + } s.feeParams = _newFeeParams; @@ -80,7 +91,9 @@ contract AdminFacet is ZkSyncHyperchainBase, IAdmin { /// @inheritdoc IAdmin function setTokenMultiplier(uint128 _nominator, uint128 _denominator) external onlyAdminOrStateTransitionManager { - require(_denominator != 0, "AF: denominator 0"); + if (_denominator == 0) { + revert DenominatorIsZero(); + } uint128 oldNominator = s.baseTokenGasPriceMultiplierNominator; uint128 oldDenominator = s.baseTokenGasPriceMultiplierDenominator; @@ -92,7 +105,10 @@ contract AdminFacet is ZkSyncHyperchainBase, IAdmin { /// @inheritdoc IAdmin function setPubdataPricingMode(PubdataPricingMode _pricingMode) external onlyAdmin { - require(s.totalBatchesCommitted == 0, "AdminFacet: set validium only after genesis"); // Validium mode can be set only before the first batch is processed + // Validium mode can be set only before the first batch is processed + if (s.totalBatchesCommitted != 0) { + revert ChainAlreadyLive(); + } s.feeParams.pubdataPricingMode = _pricingMode; emit ValidiumModeStatusUpdate(_pricingMode); } @@ -113,15 +129,19 @@ contract AdminFacet is ZkSyncHyperchainBase, IAdmin { Diamond.DiamondCutData calldata _diamondCut ) external onlyAdminOrStateTransitionManager { bytes32 cutHashInput = keccak256(abi.encode(_diamondCut)); - require( - cutHashInput == IStateTransitionManager(s.stateTransitionManager).upgradeCutHash(_oldProtocolVersion), - "AdminFacet: cutHash mismatch" - ); - - require(s.protocolVersion == _oldProtocolVersion, "AdminFacet: protocolVersion mismatch in STC when upgrading"); + bytes32 upgradeCutHash = IStateTransitionManager(s.stateTransitionManager).upgradeCutHash(_oldProtocolVersion); + if (cutHashInput != upgradeCutHash) { + revert HashMismatch(upgradeCutHash, cutHashInput); + } + + if (s.protocolVersion != _oldProtocolVersion) { + revert ProtocolIdMismatch(s.protocolVersion, _oldProtocolVersion); + } Diamond.diamondCut(_diamondCut); emit ExecuteUpgrade(_diamondCut); - require(s.protocolVersion > _oldProtocolVersion, "AdminFacet: protocolVersion mismatch in STC after upgrading"); + if (s.protocolVersion <= _oldProtocolVersion) { + revert ProtocolIdNotGreater(); + } } /// @inheritdoc IAdmin @@ -138,7 +158,10 @@ contract AdminFacet is ZkSyncHyperchainBase, IAdmin { function freezeDiamond() external onlyStateTransitionManager { Diamond.DiamondStorage storage diamondStorage = Diamond.getDiamondStorage(); - require(!diamondStorage.isFrozen, "a9"); // diamond proxy is frozen already + // diamond proxy is frozen already + if (diamondStorage.isFrozen) { + revert DiamondAlreadyFrozen(); + } diamondStorage.isFrozen = true; emit Freeze(); @@ -148,7 +171,10 @@ contract AdminFacet is ZkSyncHyperchainBase, IAdmin { function unfreezeDiamond() external onlyStateTransitionManager { Diamond.DiamondStorage storage diamondStorage = Diamond.getDiamondStorage(); - require(diamondStorage.isFrozen, "a7"); // diamond proxy is not frozen + // diamond proxy is not frozen + if (!diamondStorage.isFrozen) { + revert DiamondNotFrozen(); + } diamondStorage.isFrozen = false; emit Unfreeze(); 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 cb43a5880..07995642b 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/facets/Executor.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/facets/Executor.sol @@ -11,11 +11,12 @@ import {UnsafeBytes} from "../../../common/libraries/UnsafeBytes.sol"; import {L2_BOOTLOADER_ADDRESS, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, L2_PUBDATA_CHUNK_PUBLISHER_ADDR} from "../../../common/L2ContractAddresses.sol"; import {PubdataPricingMode} from "../ZkSyncHyperchainStorage.sol"; import {IStateTransitionManager} from "../../IStateTransitionManager.sol"; +import {BatchNumberMismatch, TimeNotReached, TooManyBlobs, ValueMismatch, InvalidPubdataMode, InvalidPubdataLength, HashMismatch, NonIncreasingTimestamp, TimestampError, InvalidLogSender, TxHashMismatch, UnexpectedSystemLog, MissingSystemLogs, LogAlreadyProcessed, InvalidProtocolVersion, CanOnlyProcessOneBatch, BatchHashMismatch, UpgradeBatchNumberIsNotZero, NonSequentialBatch, CantExecuteUnprovenBatches, SystemLogsSizeTooBig, InvalidNumberOfBlobs, VerifiedBatchesExceedsCommittedBatches, InvalidProof, RevertedBatchNotAfterNewLastBatch, CantRevertExecutedBatch, PointEvalFailed, EmptyBlobVersionHash, NonEmptyBlobVersionHash, BlobHashCommitmentError, CalldataLengthTooBig, InvalidPubdataHash, L2TimestampTooBig, PriorityOperationsRollingHashMismatch, PubdataCommitmentsEmpty, PointEvalCallFailed, PubdataCommitmentsTooBig, InvalidPubdataCommitmentsSize} from "../../../common/L1ContractErrors.sol"; // While formally the following import is not used, it is needed to inherit documentation from it import {IZkSyncHyperchainBase} from "../../chain-interfaces/IZkSyncHyperchainBase.sol"; -/// @title zkSync hyperchain Executor contract capable of processing events emitted in the zkSync hyperchain protocol. +/// @title ZKsync hyperchain Executor contract capable of processing events emitted in the ZKsync hyperchain protocol. /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { @@ -33,16 +34,20 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { CommitBatchInfo calldata _newBatch, bytes32 _expectedSystemContractUpgradeTxHash ) internal view returns (StoredBatchInfo memory) { - require(_newBatch.batchNumber == _previousBatch.batchNumber + 1, "f"); // only commit next batch + // only commit next batch + if (_newBatch.batchNumber != _previousBatch.batchNumber + 1) { + revert BatchNumberMismatch(_previousBatch.batchNumber + 1, _newBatch.batchNumber); + } uint8 pubdataSource = uint8(bytes1(_newBatch.pubdataCommitments[0])); PubdataPricingMode pricingMode = s.feeParams.pubdataPricingMode; - require( - pricingMode == PubdataPricingMode.Validium || - pubdataSource == uint8(PubdataSource.Calldata) || - pubdataSource == uint8(PubdataSource.Blob), - "us" - ); + if ( + pricingMode != PubdataPricingMode.Validium && + pubdataSource != uint8(PubdataSource.Calldata) && + pubdataSource != uint8(PubdataSource.Blob) + ) { + revert InvalidPubdataMode(); + } // Check that batch contain all meta information for L2 logs. // Get the chained hash of priority transaction hashes. @@ -51,8 +56,10 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { bytes32[] memory blobCommitments = new bytes32[](MAX_NUMBER_OF_BLOBS); if (pricingMode == PubdataPricingMode.Validium) { // skipping data validation for validium, we just check that the data is empty - require(_newBatch.pubdataCommitments.length == 1, "EF: v0l"); - for (uint8 i = uint8(SystemLogKey.BLOB_ONE_HASH_KEY); i <= uint8(SystemLogKey.BLOB_SIX_HASH_KEY); i++) { + if (_newBatch.pubdataCommitments.length != 1) { + revert CalldataLengthTooBig(); + } + for (uint8 i = uint8(SystemLogKey.BLOB_ONE_HASH_KEY); i <= uint8(SystemLogKey.BLOB_SIX_HASH_KEY); ++i) { logOutput.blobHashes[i - uint8(SystemLogKey.BLOB_ONE_HASH_KEY)] = bytes32(0); } } else if (pubdataSource == uint8(PubdataSource.Blob)) { @@ -60,12 +67,13 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { blobCommitments = _verifyBlobInformation(_newBatch.pubdataCommitments[1:], logOutput.blobHashes); } else if (pubdataSource == uint8(PubdataSource.Calldata)) { // In this scenario pubdataCommitments is actual pubdata consisting of l2 to l1 logs, l2 to l1 message, compressed smart contract bytecode, and compressed state diffs - require(_newBatch.pubdataCommitments.length <= BLOB_SIZE_BYTES, "cz"); - require( - logOutput.pubdataHash == - keccak256(_newBatch.pubdataCommitments[1:_newBatch.pubdataCommitments.length - 32]), - "wp" - ); + if (_newBatch.pubdataCommitments.length > BLOB_SIZE_BYTES) { + revert InvalidPubdataLength(); + } + bytes32 pubdataHash = keccak256(_newBatch.pubdataCommitments[1:_newBatch.pubdataCommitments.length - 32]); + if (logOutput.pubdataHash != pubdataHash) { + revert InvalidPubdataHash(pubdataHash, logOutput.pubdataHash); + } blobCommitments[0] = bytes32( _newBatch.pubdataCommitments[_newBatch.pubdataCommitments.length - 32:_newBatch .pubdataCommitments @@ -73,11 +81,17 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { ); } - require(_previousBatch.batchHash == logOutput.previousBatchHash, "l"); + if (_previousBatch.batchHash != logOutput.previousBatchHash) { + revert HashMismatch(logOutput.previousBatchHash, _previousBatch.batchHash); + } // Check that the priority operation hash in the L2 logs is as expected - require(logOutput.chainedPriorityTxsHash == _newBatch.priorityOperationsHash, "t"); + if (logOutput.chainedPriorityTxsHash != _newBatch.priorityOperationsHash) { + revert HashMismatch(logOutput.chainedPriorityTxsHash, _newBatch.priorityOperationsHash); + } // Check that the number of processed priority operations is as expected - require(logOutput.numberOfLayer1Txs == _newBatch.numberOfLayer1Txs, "ta"); + if (logOutput.numberOfLayer1Txs != _newBatch.numberOfLayer1Txs) { + revert ValueMismatch(logOutput.numberOfLayer1Txs, _newBatch.numberOfLayer1Txs); + } // Check the timestamp of the new batch _verifyBatchTimestamp(logOutput.packedBatchAndL2BlockTimestamp, _newBatch.timestamp, _previousBatch.timestamp); @@ -114,11 +128,15 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { ) internal view { // Check that the timestamp that came from the system context is expected uint256 batchTimestamp = _packedBatchAndL2BlockTimestamp >> 128; - require(batchTimestamp == _expectedBatchTimestamp, "tb"); + if (batchTimestamp != _expectedBatchTimestamp) { + revert TimestampError(); + } // While the fact that _previousBatchTimestamp < batchTimestamp is already checked on L2, // we double check it here for clarity - require(_previousBatchTimestamp < batchTimestamp, "h3"); + if (_previousBatchTimestamp >= batchTimestamp) { + revert NonIncreasingTimestamp(); + } uint256 lastL2BlockTimestamp = _packedBatchAndL2BlockTimestamp & PACKED_L2_BLOCK_TIMESTAMP_MASK; @@ -126,8 +144,14 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { // So here we need to only double check that: // - The timestamp of the batch is not too small. // - The timestamp of the last L2 block is not too big. - require(block.timestamp - COMMIT_TIMESTAMP_NOT_OLDER <= batchTimestamp, "h1"); // New batch timestamp is too small - require(lastL2BlockTimestamp <= block.timestamp + COMMIT_TIMESTAMP_APPROXIMATION_DELTA, "h2"); // The last L2 block timestamp is too big + // New batch timestamp is too small + if (block.timestamp - COMMIT_TIMESTAMP_NOT_OLDER > batchTimestamp) { + revert TimeNotReached(batchTimestamp, block.timestamp - COMMIT_TIMESTAMP_NOT_OLDER); + } + // The last L2 block timestamp is too big + if (lastL2BlockTimestamp > block.timestamp + COMMIT_TIMESTAMP_APPROXIMATION_DELTA) { + revert L2TimestampTooBig(); + } } /// @dev Check that L2 logs are proper and batch contain all meta information for them @@ -145,10 +169,11 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { // Used as bitmap to set/check log processing happens exactly once. // See SystemLogKey enum in Constants.sol for ordering. - uint256 processedLogs; + uint256 processedLogs = 0; // linear traversal of the logs - for (uint256 i = 0; i < emittedL2Logs.length; i = i.uncheckedAdd(L2_TO_L1_LOG_SERIALIZE_SIZE)) { + uint256 logsLength = emittedL2Logs.length; + for (uint256 i = 0; i < logsLength; i = i.uncheckedAdd(L2_TO_L1_LOG_SERIALIZE_SIZE)) { // Extract the values to be compared to/used such as the log sender, key, and value // slither-disable-next-line unused-return (address logSender, ) = UnsafeBytes.readAddress(emittedL2Logs, i + L2_LOG_ADDRESS_OFFSET); @@ -158,47 +183,69 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { (bytes32 logValue, ) = UnsafeBytes.readBytes32(emittedL2Logs, i + L2_LOG_VALUE_OFFSET); // Ensure that the log hasn't been processed already - require(!_checkBit(processedLogs, uint8(logKey)), "kp"); + if (_checkBit(processedLogs, uint8(logKey))) { + revert LogAlreadyProcessed(uint8(logKey)); + } processedLogs = _setBit(processedLogs, uint8(logKey)); // Need to check that each log was sent by the correct address. if (logKey == uint256(SystemLogKey.L2_TO_L1_LOGS_TREE_ROOT_KEY)) { - require(logSender == L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, "lm"); + if (logSender != L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR) { + revert InvalidLogSender(logSender, logKey); + } logOutput.l2LogsTreeRoot = logValue; } else if (logKey == uint256(SystemLogKey.TOTAL_L2_TO_L1_PUBDATA_KEY)) { - require(logSender == L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, "ln"); + if (logSender != L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR) { + revert InvalidLogSender(logSender, logKey); + } logOutput.pubdataHash = logValue; } else if (logKey == uint256(SystemLogKey.STATE_DIFF_HASH_KEY)) { - require(logSender == L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, "lb"); + if (logSender != L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR) { + revert InvalidLogSender(logSender, logKey); + } logOutput.stateDiffHash = logValue; } else if (logKey == uint256(SystemLogKey.PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY)) { - require(logSender == L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, "sc"); + if (logSender != L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR) { + revert InvalidLogSender(logSender, logKey); + } logOutput.packedBatchAndL2BlockTimestamp = uint256(logValue); } else if (logKey == uint256(SystemLogKey.PREV_BATCH_HASH_KEY)) { - require(logSender == L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR, "sv"); + if (logSender != L2_SYSTEM_CONTEXT_SYSTEM_CONTRACT_ADDR) { + revert InvalidLogSender(logSender, logKey); + } logOutput.previousBatchHash = logValue; } else if (logKey == uint256(SystemLogKey.CHAINED_PRIORITY_TXN_HASH_KEY)) { - require(logSender == L2_BOOTLOADER_ADDRESS, "bl"); + if (logSender != L2_BOOTLOADER_ADDRESS) { + revert InvalidLogSender(logSender, logKey); + } logOutput.chainedPriorityTxsHash = logValue; } else if (logKey == uint256(SystemLogKey.NUMBER_OF_LAYER_1_TXS_KEY)) { - require(logSender == L2_BOOTLOADER_ADDRESS, "bk"); + if (logSender != L2_BOOTLOADER_ADDRESS) { + revert InvalidLogSender(logSender, logKey); + } logOutput.numberOfLayer1Txs = uint256(logValue); } else if ( logKey >= uint256(SystemLogKey.BLOB_ONE_HASH_KEY) && logKey <= uint256(SystemLogKey.BLOB_SIX_HASH_KEY) ) { - require(logSender == L2_PUBDATA_CHUNK_PUBLISHER_ADDR, "pc"); + if (logSender != L2_PUBDATA_CHUNK_PUBLISHER_ADDR) { + revert InvalidLogSender(logSender, logKey); + } uint8 blobNumber = uint8(logKey) - uint8(SystemLogKey.BLOB_ONE_HASH_KEY); - // While the fact that `blobNumber` is a valid blob number is implicitly checked by the fact - // that Solidity provides array overflow protection, we still double check it manually in case - // we accidentally put `unchecked` at the top of the loop and generally for better error messages. - require(blobNumber < MAX_NUMBER_OF_BLOBS, "b6"); + if (blobNumber >= MAX_NUMBER_OF_BLOBS) { + revert TooManyBlobs(); + } + logOutput.blobHashes[blobNumber] = logValue; } else if (logKey == uint256(SystemLogKey.EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY)) { - require(logSender == L2_BOOTLOADER_ADDRESS, "bu"); - require(_expectedSystemContractUpgradeTxHash == logValue, "ut"); + if (logSender != L2_BOOTLOADER_ADDRESS) { + revert InvalidLogSender(logSender, logKey); + } + if (_expectedSystemContractUpgradeTxHash != logValue) { + revert TxHashMismatch(); + } } else if (logKey > uint256(SystemLogKey.EXPECTED_SYSTEM_CONTRACT_UPGRADE_TX_HASH_KEY)) { - revert("ul"); + revert UnexpectedSystemLog(logKey); } } @@ -206,15 +253,19 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { // Without the protocol upgrade we expect 13 logs: 2^13 - 1 = 8191 // With the protocol upgrade we expect 14 logs: 2^14 - 1 = 16383 if (_expectedSystemContractUpgradeTxHash == bytes32(0)) { - require(processedLogs == 8191, "b7"); + if (processedLogs != 8191) { + revert MissingSystemLogs(8191, processedLogs); + } } else { - require(processedLogs == 16383, "b8"); + if (processedLogs != 16383) { + revert MissingSystemLogs(16383, processedLogs); + } } } /// @inheritdoc IExecutor function commitBatches( - StoredBatchInfo memory _lastCommittedBatchData, + StoredBatchInfo calldata _lastCommittedBatchData, CommitBatchInfo[] calldata _newBatchesData ) external nonReentrant onlyValidator { _commitBatches(_lastCommittedBatchData, _newBatchesData); @@ -223,7 +274,7 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { /// @inheritdoc IExecutor function commitBatchesSharedBridge( uint256, // _chainId - StoredBatchInfo memory _lastCommittedBatchData, + StoredBatchInfo calldata _lastCommittedBatchData, CommitBatchInfo[] calldata _newBatchesData ) external nonReentrant onlyValidator { _commitBatches(_lastCommittedBatchData, _newBatchesData); @@ -240,14 +291,21 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { // 2. A chain might become out of sync if it launches while we are in the middle of a protocol upgrade. This would mean they cannot process their genesis upgrade // as their protocolversion would be outdated, and they also cannot process the protocol upgrade tx as they have a pending upgrade. // 3. The protocol upgrade is increased in the BaseZkSyncUpgrade, in the executor only the systemContractsUpgradeTxHash is checked - require( - IStateTransitionManager(s.stateTransitionManager).protocolVersionIsActive(s.protocolVersion), - "Executor facet: wrong protocol version" - ); + if (!IStateTransitionManager(s.stateTransitionManager).protocolVersionIsActive(s.protocolVersion)) { + revert InvalidProtocolVersion(); + } // With the new changes for EIP-4844, namely the restriction on number of blobs per block, we only allow for a single batch to be committed at a time. - require(_newBatchesData.length == 1, "e4"); + if (_newBatchesData.length != 1) { + revert CanOnlyProcessOneBatch(); + } // Check that we commit batches after last committed batch - require(s.storedBatchHashes[s.totalBatchesCommitted] == _hashStoredBatchInfo(_lastCommittedBatchData), "i"); // incorrect previous batch data + if (s.storedBatchHashes[s.totalBatchesCommitted] != _hashStoredBatchInfo(_lastCommittedBatchData)) { + // incorrect previous batch data + revert BatchHashMismatch( + s.storedBatchHashes[s.totalBatchesCommitted], + _hashStoredBatchInfo(_lastCommittedBatchData) + ); + } bytes32 systemContractsUpgradeTxHash = s.l2SystemContractsUpgradeTxHash; // Upgrades are rarely done so we optimize a case with no active system contracts upgrade. @@ -271,6 +329,8 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { StoredBatchInfo memory _lastCommittedBatchData, CommitBatchInfo[] calldata _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)); @@ -297,12 +357,16 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { // 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 encure noticeable gas cost. - require(s.l2SystemContractsUpgradeBatchNumber == 0, "ik"); + // 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); @@ -337,14 +401,17 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { /// @dev _executedBatchIdx is an index in the array of the batches that we want to execute together function _executeOneBatch(StoredBatchInfo memory _storedBatch, uint256 _executedBatchIdx) internal { uint256 currentBatchNumber = _storedBatch.batchNumber; - require(currentBatchNumber == s.totalBatchesExecuted + _executedBatchIdx + 1, "k"); // Execute batches in order - require( - _hashStoredBatchInfo(_storedBatch) == s.storedBatchHashes[currentBatchNumber], - "exe10" // executing batch should be committed - ); + if (currentBatchNumber != s.totalBatchesExecuted + _executedBatchIdx + 1) { + revert NonSequentialBatch(); + } + if (_hashStoredBatchInfo(_storedBatch) != s.storedBatchHashes[currentBatchNumber]) { + revert BatchHashMismatch(s.storedBatchHashes[currentBatchNumber], _hashStoredBatchInfo(_storedBatch)); + } bytes32 priorityOperationsHash = _collectOperationsFromPriorityQueue(_storedBatch.numberOfLayer1Txs); - require(priorityOperationsHash == _storedBatch.priorityOperationsHash, "x"); // priority operations hash does not match to expected + if (priorityOperationsHash != _storedBatch.priorityOperationsHash) { + revert PriorityOperationsRollingHashMismatch(); + } // Save root hash of L2 -> L1 logs tree s.l2LogsRootHashes[currentBatchNumber] = _storedBatch.l2LogsTreeRoot; @@ -372,7 +439,9 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { uint256 newTotalBatchesExecuted = s.totalBatchesExecuted + nBatches; s.totalBatchesExecuted = newTotalBatchesExecuted; - require(newTotalBatchesExecuted <= s.totalBatchesVerified, "n"); // Can't execute batches more than committed and proven currently. + if (newTotalBatchesExecuted > s.totalBatchesVerified) { + revert CantExecuteUnprovenBatches(); + } uint256 batchWhenUpgradeHappened = s.l2SystemContractsUpgradeBatchNumber; if (batchWhenUpgradeHappened != 0 && batchWhenUpgradeHappened <= newTotalBatchesExecuted) { @@ -413,22 +482,31 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { uint256[] memory proofPublicInput = new uint256[](committedBatchesLength); // Check that the batch passed by the validator is indeed the first unverified batch - require(_hashStoredBatchInfo(_prevBatch) == s.storedBatchHashes[currentTotalBatchesVerified], "t1"); + if (_hashStoredBatchInfo(_prevBatch) != s.storedBatchHashes[currentTotalBatchesVerified]) { + revert BatchHashMismatch( + s.storedBatchHashes[currentTotalBatchesVerified], + _hashStoredBatchInfo(_prevBatch) + ); + } bytes32 prevBatchCommitment = _prevBatch.commitment; for (uint256 i = 0; i < committedBatchesLength; i = i.uncheckedInc()) { currentTotalBatchesVerified = currentTotalBatchesVerified.uncheckedInc(); - require( - _hashStoredBatchInfo(_committedBatches[i]) == s.storedBatchHashes[currentTotalBatchesVerified], - "o1" - ); + if (_hashStoredBatchInfo(_committedBatches[i]) != s.storedBatchHashes[currentTotalBatchesVerified]) { + revert BatchHashMismatch( + s.storedBatchHashes[currentTotalBatchesVerified], + _hashStoredBatchInfo(_committedBatches[i]) + ); + } bytes32 currentBatchCommitment = _committedBatches[i].commitment; proofPublicInput[i] = _getBatchProofPublicInput(prevBatchCommitment, currentBatchCommitment); prevBatchCommitment = currentBatchCommitment; } - require(currentTotalBatchesVerified <= s.totalBatchesCommitted, "q"); + if (currentTotalBatchesVerified > s.totalBatchesCommitted) { + revert VerifiedBatchesExceedsCommittedBatches(); + } _verifyProof(proofPublicInput, _proof); @@ -438,14 +516,18 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { function _verifyProof(uint256[] memory proofPublicInput, ProofInput calldata _proof) internal view { // We can only process 1 batch proof at a time. - require(proofPublicInput.length == 1, "t4"); + if (proofPublicInput.length != 1) { + revert CanOnlyProcessOneBatch(); + } bool successVerifyProof = s.verifier.verify( proofPublicInput, _proof.serializedProof, _proof.recursiveAggregationInput ); - require(successVerifyProof, "p"); // Proof verification fail + if (!successVerifyProof) { + revert InvalidProof(); + } } /// @dev Gets zk proof public input @@ -468,8 +550,12 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { } function _revertBatches(uint256 _newLastBatch) internal { - require(s.totalBatchesCommitted > _newLastBatch, "v1"); // The last committed batch is less than new last batch - require(_newLastBatch >= s.totalBatchesExecuted, "v2"); // Already executed batches cannot be reverted + if (s.totalBatchesCommitted <= _newLastBatch) { + revert RevertedBatchNotAfterNewLastBatch(); + } + if (_newLastBatch < s.totalBatchesExecuted) { + revert CantRevertExecutedBatch(); + } if (_newLastBatch < s.totalBatchesVerified) { s.totalBatchesVerified = _newLastBatch; @@ -530,7 +616,9 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { bytes32[] memory _blobCommitments, bytes32[] memory _blobHashes ) internal pure returns (bytes memory) { - require(_batch.systemLogs.length <= MAX_L2_TO_L1_LOGS_COMMITMENT_BYTES, "pu"); + if (_batch.systemLogs.length > MAX_L2_TO_L1_LOGS_COMMITMENT_BYTES) { + revert SystemLogsSizeTooBig(); + } bytes32 l2ToL1LogsHash = keccak256(_batch.systemLogs); @@ -555,8 +643,9 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { ) internal pure returns (bytes32[] memory blobAuxOutputWords) { // These invariants should be checked by the caller of this function, but we double check // just in case. - require(_blobCommitments.length == MAX_NUMBER_OF_BLOBS, "b10"); - require(_blobHashes.length == MAX_NUMBER_OF_BLOBS, "b11"); + if (_blobCommitments.length != MAX_NUMBER_OF_BLOBS || _blobHashes.length != MAX_NUMBER_OF_BLOBS) { + revert InvalidNumberOfBlobs(MAX_NUMBER_OF_BLOBS, _blobCommitments.length, _blobHashes.length); + } // for each blob we have: // linear hash (hash of preimage from system logs) and @@ -568,7 +657,7 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { blobAuxOutputWords = new bytes32[](2 * TOTAL_BLOBS_IN_COMMITMENT); - for (uint256 i = 0; i < MAX_NUMBER_OF_BLOBS; i++) { + for (uint256 i = 0; i < MAX_NUMBER_OF_BLOBS; ++i) { blobAuxOutputWords[i * 2] = _blobHashes[i]; blobAuxOutputWords[i * 2 + 1] = _blobCommitments[i]; } @@ -604,9 +693,13 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { // We verify that the point evaluation precompile call was successful by testing the latter 32 bytes of the // response is equal to BLS_MODULUS as defined in https://eips.ethereum.org/EIPS/eip-4844#point-evaluation-precompile - require(success, "failed to call point evaluation precompile"); + if (!success) { + revert PointEvalCallFailed(precompileInput); + } (, uint256 result) = abi.decode(data, (uint256, uint256)); - require(result == BLS_MODULUS, "precompile unexpected output"); + if (result != BLS_MODULUS) { + revert PointEvalFailed(abi.encode(result)); + } } /// @dev Verifies that the blobs contain the correct data by calling the point evaluation precompile. For the precompile we need: @@ -619,15 +712,25 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { ) internal view returns (bytes32[] memory blobCommitments) { uint256 versionedHashIndex = 0; - require(_pubdataCommitments.length > 0, "pl"); - require(_pubdataCommitments.length <= PUBDATA_COMMITMENT_SIZE * MAX_NUMBER_OF_BLOBS, "bd"); - require(_pubdataCommitments.length % PUBDATA_COMMITMENT_SIZE == 0, "bs"); + if (_pubdataCommitments.length == 0) { + revert PubdataCommitmentsEmpty(); + } + if (_pubdataCommitments.length > PUBDATA_COMMITMENT_SIZE * MAX_NUMBER_OF_BLOBS) { + revert PubdataCommitmentsTooBig(); + } + if (_pubdataCommitments.length % PUBDATA_COMMITMENT_SIZE != 0) { + revert InvalidPubdataCommitmentsSize(); + } blobCommitments = new bytes32[](MAX_NUMBER_OF_BLOBS); + // We disable this check because calldata array length is cheap. + // solhint-disable-next-line gas-length-in-loops for (uint256 i = 0; i < _pubdataCommitments.length; i += PUBDATA_COMMITMENT_SIZE) { bytes32 blobVersionedHash = _getBlobVersionedHash(versionedHashIndex); - require(blobVersionedHash != bytes32(0), "vh"); + if (blobVersionedHash == bytes32(0)) { + revert EmptyBlobVersionHash(versionedHashIndex); + } // First 16 bytes is the opening point. While we get the point as 16 bytes, the point evaluation precompile // requires it to be 32 bytes. The blob commitment must use the opening point as 16 bytes though. @@ -645,22 +748,25 @@ contract ExecutorFacet is ZkSyncHyperchainBase, IExecutor { blobCommitments[versionedHashIndex] = keccak256( abi.encodePacked(blobVersionedHash, _pubdataCommitments[i:i + PUBDATA_COMMITMENT_COMMITMENT_OFFSET]) ); - versionedHashIndex += 1; + ++versionedHashIndex; } // This check is required because we want to ensure that there aren't any extra blobs trying to be published. // Calling the BLOBHASH opcode with an index > # blobs - 1 yields bytes32(0) bytes32 versionedHash = _getBlobVersionedHash(versionedHashIndex); - require(versionedHash == bytes32(0), "lh"); + if (versionedHash != bytes32(0)) { + revert NonEmptyBlobVersionHash(versionedHashIndex); + } // We verify that for each set of blobHash/blobCommitment are either both empty // or there are values for both. - for (uint256 i = 0; i < MAX_NUMBER_OF_BLOBS; i++) { - require( - (_blobHashes[i] == bytes32(0) && blobCommitments[i] == bytes32(0)) || - (_blobHashes[i] != bytes32(0) && blobCommitments[i] != bytes32(0)), - "bh" - ); + for (uint256 i = 0; i < MAX_NUMBER_OF_BLOBS; ++i) { + if ( + (_blobHashes[i] == bytes32(0) && blobCommitments[i] != bytes32(0)) || + (_blobHashes[i] != bytes32(0) && blobCommitments[i] == bytes32(0)) + ) { + revert BlobHashCommitmentError(i, _blobHashes[i] == bytes32(0), blobCommitments[i] == bytes32(0)); + } } } diff --git a/l1-contracts/contracts/state-transition/chain-deps/facets/Getters.sol b/l1-contracts/contracts/state-transition/chain-deps/facets/Getters.sol index ab87d31f0..9cb2a2da8 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/facets/Getters.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/facets/Getters.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.24; -import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {SafeCast} from "@openzeppelin/contracts-v4/utils/math/SafeCast.sol"; import {ZkSyncHyperchainBase} from "./ZkSyncHyperchainBase.sol"; import {PubdataPricingMode} from "../ZkSyncHyperchainStorage.sol"; @@ -12,6 +12,7 @@ import {PriorityQueue, PriorityOperation} from "../../../state-transition/librar import {UncheckedMath} from "../../../common/libraries/UncheckedMath.sol"; import {IGetters} from "../../chain-interfaces/IGetters.sol"; import {ILegacyGetters} from "../../chain-interfaces/ILegacyGetters.sol"; +import {InvalidSelector} from "../../../common/L1ContractErrors.sol"; import {SemVer} from "../../../common/libraries/SemVer.sol"; // While formally the following import is not used, it is needed to inherit documentation from it @@ -189,7 +190,9 @@ contract GettersFacet is ZkSyncHyperchainBase, IGetters, ILegacyGetters { /// @inheritdoc IGetters function isFunctionFreezable(bytes4 _selector) external view returns (bool) { Diamond.DiamondStorage storage ds = Diamond.getDiamondStorage(); - require(ds.selectorToFacet[_selector].facetAddress != address(0), "g2"); + if (ds.selectorToFacet[_selector].facetAddress == address(0)) { + revert InvalidSelector(_selector); + } return ds.selectorToFacet[_selector].isFreezable; } 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 752913b3f..43f6b04e7 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/facets/Mailbox.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/facets/Mailbox.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.24; -import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {Math} from "@openzeppelin/contracts-v4/utils/math/Math.sol"; import {IMailbox} from "../../chain-interfaces/IMailbox.sol"; import {ITransactionFilterer} from "../../chain-interfaces/ITransactionFilterer.sol"; @@ -20,10 +20,12 @@ import {L2_BOOTLOADER_ADDRESS, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from ".. import {IL1SharedBridge} from "../../../bridge/interfaces/IL1SharedBridge.sol"; +import {OnlyEraSupported, BatchNotExecuted, HashedLogIsDefault, BaseTokenGasPriceDenominatorNotSet, TransactionNotAllowed, GasPerPubdataMismatch, TooManyFactoryDeps, MsgValueTooLow} from "../../../common/L1ContractErrors.sol"; + // While formally the following import is not used, it is needed to inherit documentation from it import {IZkSyncHyperchainBase} from "../../chain-interfaces/IZkSyncHyperchainBase.sol"; -/// @title zkSync Mailbox contract providing interfaces for L1 <-> L2 interaction. +/// @title ZKsync Mailbox contract providing interfaces for L1 <-> L2 interaction. /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { @@ -34,7 +36,7 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { string public constant override getName = "MailboxFacet"; /// @dev Era's chainID - uint256 immutable ERA_CHAIN_ID; + uint256 internal immutable ERA_CHAIN_ID; constructor(uint256 _eraChainId) { ERA_CHAIN_ID = _eraChainId; @@ -42,7 +44,9 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { /// @inheritdoc IMailbox function transferEthToSharedBridge() external onlyBaseTokenBridge { - require(s.chainId == ERA_CHAIN_ID, "Mailbox: transferEthToSharedBridge only available for Era on mailbox"); + if (s.chainId != ERA_CHAIN_ID) { + revert OnlyEraSupported(); + } uint256 amount = address(this).balance; address baseTokenBridgeAddress = s.baseTokenBridge; @@ -60,7 +64,7 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { function proveL2MessageInclusion( uint256 _batchNumber, uint256 _index, - L2Message memory _message, + L2Message calldata _message, bytes32[] calldata _proof ) public view returns (bool) { return _proveL2LogInclusion(_batchNumber, _index, _L2MessageToLog(_message), _proof); @@ -70,7 +74,7 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { function proveL2LogInclusion( uint256 _batchNumber, uint256 _index, - L2Log memory _log, + L2Log calldata _log, bytes32[] calldata _proof ) external view returns (bool) { return _proveL2LogInclusion(_batchNumber, _index, _log, _proof); @@ -113,7 +117,9 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { L2Log memory _log, bytes32[] calldata _proof ) internal view returns (bool) { - require(_batchNumber <= s.totalBatchesExecuted, "xx"); + if (_batchNumber > s.totalBatchesExecuted) { + revert BatchNotExecuted(_batchNumber); + } bytes32 hashedLog = keccak256( // solhint-disable-next-line func-named-parameters @@ -121,7 +127,9 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { ); // Check that hashed log is not the default one, // otherwise it means that the value is out of range of sent L2 -> L1 logs - require(hashedLog != L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH, "tw"); + 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 @@ -134,7 +142,7 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { } /// @dev Convert arbitrary-length message to the raw l2 log - function _L2MessageToLog(L2Message memory _message) internal pure returns (L2Log memory) { + function _L2MessageToLog(L2Message calldata _message) internal pure returns (L2Log memory) { return L2Log({ l2ShardId: 0, @@ -162,7 +170,9 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { /// @return The price of L2 gas in the base token function _deriveL2GasPrice(uint256 _l1GasPrice, uint256 _gasPerPubdata) internal view returns (uint256) { FeeParams memory feeParams = s.feeParams; - require(s.baseTokenGasPriceMultiplierDenominator > 0, "Mailbox: baseTokenGasPriceDenominator not set"); + if (s.baseTokenGasPriceMultiplierDenominator == 0) { + revert BaseTokenGasPriceDenominatorNotSet(); + } uint256 l1GasPriceConverted = (_l1GasPrice * s.baseTokenGasPriceMultiplierNominator) / s.baseTokenGasPriceMultiplierDenominator; uint256 pubdataPriceBaseToken; @@ -191,7 +201,9 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { bytes calldata _message, bytes32[] calldata _merkleProof ) external nonReentrant { - require(s.chainId == ERA_CHAIN_ID, "Mailbox: finalizeEthWithdrawal only available for Era on mailbox"); + if (s.chainId != ERA_CHAIN_ID) { + revert OnlyEraSupported(); + } IL1SharedBridge(s.baseTokenBridge).finalizeWithdrawal({ _chainId: ERA_CHAIN_ID, _l2BatchNumber: _l2BatchNumber, @@ -212,7 +224,9 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { bytes[] calldata _factoryDeps, address _refundRecipient ) external payable returns (bytes32 canonicalTxHash) { - require(s.chainId == ERA_CHAIN_ID, "Mailbox: legacy interface only available for Era"); + if (s.chainId != ERA_CHAIN_ID) { + revert OnlyEraSupported(); + } canonicalTxHash = _requestL2TransactionSender( BridgehubL2TransactionRequest({ sender: msg.sender, @@ -239,17 +253,18 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { ) internal nonReentrant returns (bytes32 canonicalTxHash) { // Check that the transaction is allowed by the filterer (if the filterer is set). if (s.transactionFilterer != address(0)) { - require( - ITransactionFilterer(s.transactionFilterer).isTransactionAllowed({ + if ( + !ITransactionFilterer(s.transactionFilterer).isTransactionAllowed({ sender: _request.sender, contractL2: _request.contractL2, mintValue: _request.mintValue, l2Value: _request.l2Value, l2Calldata: _request.l2Calldata, refundRecipient: _request.refundRecipient - }), - "tf" - ); + }) + ) { + revert TransactionNotAllowed(); + } } // Enforcing that `_request.l2GasPerPubdataByteLimit` equals to a certain constant number. This is needed @@ -257,7 +272,9 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { // VERY IMPORTANT: nobody should rely on this constant to be fixed and every contract should give their users the ability to provide the // ability to provide `_request.l2GasPerPubdataByteLimit` for each independent transaction. // CHANGING THIS CONSTANT SHOULD BE A CLIENT-SIDE CHANGE. - require(_request.l2GasPerPubdataByteLimit == REQUIRED_L2_GAS_PRICE_PER_PUBDATA, "qp"); + if (_request.l2GasPerPubdataByteLimit != REQUIRED_L2_GAS_PRICE_PER_PUBDATA) { + revert GasPerPubdataMismatch(); + } WritePriorityOpParams memory params; params.request = _request; @@ -268,21 +285,27 @@ contract MailboxFacet is ZkSyncHyperchainBase, IMailbox { function _requestL2Transaction(WritePriorityOpParams memory _params) internal returns (bytes32 canonicalTxHash) { BridgehubL2TransactionRequest memory request = _params.request; - require(request.factoryDeps.length <= MAX_NEW_FACTORY_DEPS, "uj"); + if (request.factoryDeps.length > MAX_NEW_FACTORY_DEPS) { + revert TooManyFactoryDeps(); + } _params.txId = s.priorityQueue.getTotalPriorityTxs(); // Checking that the user provided enough ether to pay for the transaction. _params.l2GasPrice = _deriveL2GasPrice(tx.gasprice, request.l2GasPerPubdataByteLimit); uint256 baseCost = _params.l2GasPrice * request.l2GasLimit; - require(request.mintValue >= baseCost + request.l2Value, "mv"); // The `msg.value` doesn't cover the transaction cost + if (request.mintValue < baseCost + request.l2Value) { + revert MsgValueTooLow(baseCost + request.l2Value, request.mintValue); + } request.refundRecipient = AddressAliasHelper.actualRefundRecipient(request.refundRecipient, request.sender); // Change the sender address if it is a smart contract to prevent address collision between L1 and L2. - // Please note, currently zkSync address derivation is different from Ethereum one, but it may be changed in the future. + // Please note, currently ZKsync address derivation is different from Ethereum one, but it may be changed in the future. + // solhint-disable avoid-tx-origin // slither-disable-next-line tx-origin if (request.sender != tx.origin) { request.sender = AddressAliasHelper.applyL1ToL2Alias(request.sender); } + // solhint-enable avoid-tx-origin // populate missing fields _params.expirationTimestamp = uint64(block.timestamp + PRIORITY_EXPIRATION); // Safe to cast diff --git a/l1-contracts/contracts/state-transition/chain-deps/facets/ZkSyncHyperchainBase.sol b/l1-contracts/contracts/state-transition/chain-deps/facets/ZkSyncHyperchainBase.sol index 59662d409..0910fcab3 100644 --- a/l1-contracts/contracts/state-transition/chain-deps/facets/ZkSyncHyperchainBase.sol +++ b/l1-contracts/contracts/state-transition/chain-deps/facets/ZkSyncHyperchainBase.sol @@ -5,6 +5,8 @@ pragma solidity 0.8.24; import {ZkSyncHyperchainStorage} from "../ZkSyncHyperchainStorage.sol"; import {ReentrancyGuard} from "../../../common/ReentrancyGuard.sol"; +import {Unauthorized} from "../../../common/L1ContractErrors.sol"; + /// @title Base contract containing functions accessible to the other facets. /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -14,44 +16,52 @@ contract ZkSyncHyperchainBase is ReentrancyGuard { /// @notice Checks that the message sender is an active admin modifier onlyAdmin() { - require(msg.sender == s.admin, "Hyperchain: not admin"); + if (msg.sender != s.admin) { + revert Unauthorized(msg.sender); + } _; } /// @notice Checks if validator is active modifier onlyValidator() { - require(s.validators[msg.sender], "Hyperchain: not validator"); + if (!s.validators[msg.sender]) { + revert Unauthorized(msg.sender); + } _; } modifier onlyStateTransitionManager() { - require(msg.sender == s.stateTransitionManager, "Hyperchain: not state transition manager"); + if (msg.sender != s.stateTransitionManager) { + revert Unauthorized(msg.sender); + } _; } modifier onlyBridgehub() { - require(msg.sender == s.bridgehub, "Hyperchain: not bridgehub"); + if (msg.sender != s.bridgehub) { + revert Unauthorized(msg.sender); + } _; } modifier onlyAdminOrStateTransitionManager() { - require( - msg.sender == s.admin || msg.sender == s.stateTransitionManager, - "Hyperchain: Only by admin or state transition manager" - ); + if (msg.sender != s.admin && msg.sender != s.stateTransitionManager) { + revert Unauthorized(msg.sender); + } _; } modifier onlyValidatorOrStateTransitionManager() { - require( - s.validators[msg.sender] || msg.sender == s.stateTransitionManager, - "Hyperchain: Only by validator or state transition manager" - ); + if (!s.validators[msg.sender] && msg.sender != s.stateTransitionManager) { + revert Unauthorized(msg.sender); + } _; } modifier onlyBaseTokenBridge() { - require(msg.sender == s.baseTokenBridge, "Hyperchain: Only base token bridge can call this function"); + if (msg.sender != s.baseTokenBridge) { + revert Unauthorized(msg.sender); + } _; } } diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IAdmin.sol b/l1-contracts/contracts/state-transition/chain-interfaces/IAdmin.sol index f2252fee6..643c6114d 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IAdmin.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/IAdmin.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 {IZkSyncHyperchainBase} from "../chain-interfaces/IZkSyncHyperchainBase.sol"; diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IDiamondInit.sol b/l1-contracts/contracts/state-transition/chain-interfaces/IDiamondInit.sol index eaa61c3e5..189ae69fa 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IDiamondInit.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/IDiamondInit.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 {IVerifier, VerifierParams} from "./IVerifier.sol"; import {FeeParams} from "../chain-deps/ZkSyncHyperchainStorage.sol"; @@ -21,6 +21,7 @@ import {FeeParams} from "../chain-deps/ZkSyncHyperchainStorage.sol"; /// @param priorityTxMaxGasLimit maximum number of the L2 gas that a user can request for L1 -> L2 transactions /// @param feeParams Fee parameters to be used for L1->L2 transactions /// @param blobVersionedHashRetriever Address of contract used to pull the blob versioned hash for a transaction. +// solhint-disable-next-line gas-struct-packing struct InitializeData { uint256 chainId; address bridgehub; diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IExecutor.sol b/l1-contracts/contracts/state-transition/chain-interfaces/IExecutor.sol index 43a7485c7..d74e4288b 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IExecutor.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/IExecutor.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 {IZkSyncHyperchainBase} from "./IZkSyncHyperchainBase.sol"; @@ -75,7 +75,7 @@ uint256 constant MAX_NUMBER_OF_BLOBS = 6; /// than the maximal number of blobs supported by the contract (`MAX_NUMBER_OF_BLOBS`). uint256 constant TOTAL_BLOBS_IN_COMMITMENT = 16; -/// @title The interface of the zkSync Executor contract capable of processing events emitted in the zkSync protocol. +/// @title The interface of the ZKsync Executor contract capable of processing events emitted in the ZKsync protocol. /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev interface IExecutor is IZkSyncHyperchainBase { @@ -87,7 +87,8 @@ interface IExecutor is IZkSyncHyperchainBase { /// @param priorityOperationsHash Hash of all priority operations from this batch /// @param l2LogsTreeRoot Root hash of tree that contains L2 -> L1 messages from this batch /// @param timestamp Rollup batch timestamp, have the same format as Ethereum batch constant - /// @param commitment Verified input for the zkSync circuit + /// @param commitment Verified input for the ZKsync circuit + // solhint-disable-next-line gas-struct-packing struct StoredBatchInfo { uint64 batchNumber; bytes32 batchHash; @@ -194,7 +195,7 @@ interface IExecutor is IZkSyncHyperchainBase { /// @notice Event emitted when a batch is committed /// @param batchNumber Number of the batch committed /// @param batchHash Hash of the L2 batch - /// @param commitment Calculated input for the zkSync circuit + /// @param commitment Calculated input for the ZKsync circuit /// @dev It has the name "BlockCommit" and not "BatchCommit" due to backward compatibility considerations event BlockCommit(uint256 indexed batchNumber, bytes32 indexed batchHash, bytes32 indexed commitment); @@ -207,7 +208,7 @@ interface IExecutor is IZkSyncHyperchainBase { /// @notice Event emitted when a batch is executed /// @param batchNumber Number of the batch executed /// @param batchHash Hash of the L2 batch - /// @param commitment Verified input for the zkSync circuit + /// @param commitment Verified input for the ZKsync circuit /// @dev It has the name "BlockExecution" and not "BatchExecution" due to backward compatibility considerations event BlockExecution(uint256 indexed batchNumber, bytes32 indexed batchHash, bytes32 indexed commitment); diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IGetters.sol b/l1-contracts/contracts/state-transition/chain-interfaces/IGetters.sol index 9d77efdf3..4d06f9e8e 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IGetters.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/IGetters.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 {PriorityOperation} from "../libraries/PriorityQueue.sol"; import {VerifierParams} from "../chain-interfaces/IVerifier.sol"; diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/ILegacyGetters.sol b/l1-contracts/contracts/state-transition/chain-interfaces/ILegacyGetters.sol index 5d3c36094..cb62f5087 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/ILegacyGetters.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/ILegacyGetters.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 {IZkSyncHyperchainBase} from "./IZkSyncHyperchainBase.sol"; /// @author Matter Labs -/// @dev This interface contains getters for the zkSync contract that should not be used, +/// @dev This interface contains getters for the ZKsync contract that should not be used, /// but still are kept for backward compatibility. /// @custom:security-contact security@matterlabs.dev interface ILegacyGetters is IZkSyncHyperchainBase { diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IMailbox.sol b/l1-contracts/contracts/state-transition/chain-interfaces/IMailbox.sol index b0b535d68..9daffebcf 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IMailbox.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/IMailbox.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 {IZkSyncHyperchainBase} from "./IZkSyncHyperchainBase.sol"; import {L2CanonicalTransaction, L2Log, L2Message, TxStatus, BridgehubL2TransactionRequest} from "../../common/Messaging.sol"; -/// @title The interface of the zkSync Mailbox contract that provides interfaces for L1 <-> L2 interaction. +/// @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 IMailbox is IZkSyncHyperchainBase { diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/ITransactionFilterer.sol b/l1-contracts/contracts/state-transition/chain-interfaces/ITransactionFilterer.sol index 9e1178fc9..a3776cacd 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/ITransactionFilterer.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/ITransactionFilterer.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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; /// @title The interface of the L1 -> L2 transaction filterer. /// @author Matter Labs diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IVerifier.sol b/l1-contracts/contracts/state-transition/chain-interfaces/IVerifier.sol index 0577102b1..97872c370 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IVerifier.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/IVerifier.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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; /// @notice Part of the configuration parameters of ZKP circuits struct VerifierParams { diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IZkSyncHyperchain.sol b/l1-contracts/contracts/state-transition/chain-interfaces/IZkSyncHyperchain.sol index 6641985a8..14aa123b0 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IZkSyncHyperchain.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/IZkSyncHyperchain.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 {IAdmin} from "./IAdmin.sol"; import {IExecutor} from "./IExecutor.sol"; diff --git a/l1-contracts/contracts/state-transition/chain-interfaces/IZkSyncHyperchainBase.sol b/l1-contracts/contracts/state-transition/chain-interfaces/IZkSyncHyperchainBase.sol index 1b6629f7d..3cd646cc9 100644 --- a/l1-contracts/contracts/state-transition/chain-interfaces/IZkSyncHyperchainBase.sol +++ b/l1-contracts/contracts/state-transition/chain-interfaces/IZkSyncHyperchainBase.sol @@ -1,7 +1,8 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.24; +// 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; -/// @title The interface of the zkSync contract, responsible for the main zkSync logic. +/// @title The interface of the ZKsync contract, responsible for the main ZKsync logic. /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev interface IZkSyncHyperchainBase { diff --git a/l1-contracts/contracts/state-transition/l2-deps/ISystemContext.sol b/l1-contracts/contracts/state-transition/l2-deps/ISystemContext.sol index fded0f4d2..d3244b74b 100644 --- a/l1-contracts/contracts/state-transition/l2-deps/ISystemContext.sol +++ b/l1-contracts/contracts/state-transition/l2-deps/ISystemContext.sol @@ -1,5 +1,6 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.0; +// 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; interface ISystemContext { function setChainId(uint256 _newChainId) external; diff --git a/l1-contracts/contracts/state-transition/libraries/Diamond.sol b/l1-contracts/contracts/state-transition/libraries/Diamond.sol index 4e44375da..b43a673c5 100644 --- a/l1-contracts/contracts/state-transition/libraries/Diamond.sol +++ b/l1-contracts/contracts/state-transition/libraries/Diamond.sol @@ -1,9 +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.21; -pragma solidity 0.8.24; - -import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {SafeCast} from "@openzeppelin/contracts-v4/utils/math/SafeCast.sol"; import {UncheckedMath} from "../../common/libraries/UncheckedMath.sol"; +import {NoFunctionsForDiamondCut, UndefinedDiamondCutAction, AddressHasNoCode, FacetExists, RemoveFunctionFacetAddressZero, SelectorsMustAllHaveSameFreezability, NonEmptyCalldata, ReplaceFunctionFacetAddressZero, RemoveFunctionFacetAddressNotZero, DelegateCallFailed} from "../../common/L1ContractErrors.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -59,6 +60,7 @@ library Diamond { /// @param action The action that is made on the facet /// @param isFreezable Denotes whether the facet & all their selectors can be frozen /// @param selectors An array of unique selectors that belongs to the facet address + // solhint-disable-next-line gas-struct-packing struct FacetCut { address facet; Action action; @@ -104,7 +106,9 @@ library Diamond { bool isFacetFreezable = facetCuts[i].isFreezable; bytes4[] memory selectors = facetCuts[i].selectors; - require(selectors.length > 0, "B"); // no functions for diamond cut + if (selectors.length == 0) { + revert NoFunctionsForDiamondCut(); + } if (action == Action.Add) { _addFunctions(facet, selectors, isFacetFreezable); @@ -113,7 +117,7 @@ library Diamond { } else if (action == Action.Remove) { _removeFunctions(facet, selectors); } else { - revert("C"); // undefined diamond cut action + revert UndefinedDiamondCutAction(); } } @@ -129,7 +133,9 @@ library Diamond { // Facet with no code cannot be added. // This check also verifies that the facet does not have zero address, since it is the // address with which 0x00000000 selector is associated. - require(_facet.code.length > 0, "G"); + if (_facet.code.length == 0) { + revert AddressHasNoCode(_facet); + } // Add facet to the list of facets if the facet address is new one _saveFacetIfNew(_facet); @@ -138,7 +144,9 @@ library Diamond { for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) { bytes4 selector = _selectors[i]; SelectorToFacet memory oldFacet = ds.selectorToFacet[selector]; - require(oldFacet.facetAddress == address(0), "J"); // facet for this selector already exists + if (oldFacet.facetAddress != address(0)) { + revert FacetExists(selector, oldFacet.facetAddress); + } _addOneFunction(_facet, selector, _isFacetFreezable); } @@ -152,13 +160,18 @@ library Diamond { // Facet with no code cannot be added. // This check also verifies that the facet does not have zero address, since it is the // address with which 0x00000000 selector is associated. - require(_facet.code.length > 0, "K"); + if (_facet.code.length == 0) { + revert AddressHasNoCode(_facet); + } uint256 selectorsLength = _selectors.length; for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) { bytes4 selector = _selectors[i]; SelectorToFacet memory oldFacet = ds.selectorToFacet[selector]; - require(oldFacet.facetAddress != address(0), "L"); // it is impossible to replace the facet with zero address + // it is impossible to replace the facet with zero address + if (oldFacet.facetAddress == address(0)) { + revert ReplaceFunctionFacetAddressZero(); + } _removeOneFunction(oldFacet.facetAddress, selector); // Add facet to the list of facets if the facet address is a new one @@ -172,13 +185,19 @@ library Diamond { function _removeFunctions(address _facet, bytes4[] memory _selectors) private { DiamondStorage storage ds = getDiamondStorage(); - require(_facet == address(0), "a1"); // facet address must be zero + // facet address must be zero + if (_facet != address(0)) { + revert RemoveFunctionFacetAddressNotZero(_facet); + } uint256 selectorsLength = _selectors.length; for (uint256 i = 0; i < selectorsLength; i = i.uncheckedInc()) { bytes4 selector = _selectors[i]; SelectorToFacet memory oldFacet = ds.selectorToFacet[selector]; - require(oldFacet.facetAddress != address(0), "a2"); // Can't delete a non-existent facet + // Can't delete a non-existent facet + if (oldFacet.facetAddress == address(0)) { + revert RemoveFunctionFacetAddressZero(); + } _removeOneFunction(oldFacet.facetAddress, selector); } @@ -212,7 +231,9 @@ library Diamond { // so all the selectors in a facet will have the same freezability if (selectorPosition != 0) { bytes4 selector0 = ds.facetToSelectors[_facet].selectors[0]; - require(_isSelectorFreezable == ds.selectorToFacet[selector0].isFreezable, "J1"); + if (_isSelectorFreezable != ds.selectorToFacet[selector0].isFreezable) { + revert SelectorsMustAllHaveSameFreezability(); + } } ds.selectorToFacet[_selector] = SelectorToFacet({ @@ -277,14 +298,18 @@ library Diamond { /// @dev Used as a final step of diamond cut to execute the logic of the initialization for changed facets function _initializeDiamondCut(address _init, bytes memory _calldata) private { if (_init == address(0)) { - require(_calldata.length == 0, "H"); // Non-empty calldata for zero address + // Non-empty calldata for zero address + if (_calldata.length != 0) { + revert NonEmptyCalldata(); + } } else { // Do not check whether `_init` is a contract since later we check that it returns data. (bool success, bytes memory data) = _init.delegatecall(_calldata); if (!success) { // If the returndata is too small, we still want to produce some meaningful error - if (data.length <= 4) { - revert("I"); // delegatecall failed + + if (data.length < 4) { + revert DelegateCallFailed(data); } assembly { @@ -294,8 +319,12 @@ library Diamond { // Check that called contract returns magic value to make sure that contract logic // supposed to be used as diamond cut initializer. - require(data.length == 32, "lp"); - require(abi.decode(data, (bytes32)) == DIAMOND_INIT_SUCCESS_RETURN_VALUE, "lp1"); + if (data.length != 32) { + revert DelegateCallFailed(data); + } + if (abi.decode(data, (bytes32)) != DIAMOND_INIT_SUCCESS_RETURN_VALUE) { + revert DelegateCallFailed(data); + } } } } diff --git a/l1-contracts/contracts/state-transition/libraries/LibMap.sol b/l1-contracts/contracts/state-transition/libraries/LibMap.sol index 1ba8a82be..2cbad0b78 100644 --- a/l1-contracts/contracts/state-transition/libraries/LibMap.sol +++ b/l1-contracts/contracts/state-transition/libraries/LibMap.sol @@ -1,5 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.24; +// 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; /// @notice Library for storage of packed unsigned integers. /// @author Matter Labs diff --git a/l1-contracts/contracts/state-transition/libraries/Merkle.sol b/l1-contracts/contracts/state-transition/libraries/Merkle.sol index ec31073aa..57701f338 100644 --- a/l1-contracts/contracts/state-transition/libraries/Merkle.sol +++ b/l1-contracts/contracts/state-transition/libraries/Merkle.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.24; +// 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 {UncheckedMath} from "../../common/libraries/UncheckedMath.sol"; +import {MerklePathEmpty, MerklePathOutOfBounds, MerkleIndexOutOfBounds} from "../../common/L1ContractErrors.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -21,9 +22,15 @@ library Merkle { bytes32 _itemHash ) internal pure returns (bytes32) { uint256 pathLength = _path.length; - require(pathLength > 0, "xc"); - require(pathLength < 256, "bt"); - require(_index < (1 << pathLength), "px"); + if (pathLength == 0) { + revert MerklePathEmpty(); + } + if (pathLength >= 256) { + revert MerklePathOutOfBounds(); + } + if (_index >= (1 << pathLength)) { + revert MerkleIndexOutOfBounds(); + } bytes32 currentHash = _itemHash; for (uint256 i; i < pathLength; i = i.uncheckedInc()) { diff --git a/l1-contracts/contracts/state-transition/libraries/PriorityQueue.sol b/l1-contracts/contracts/state-transition/libraries/PriorityQueue.sol index cb43068df..141cd40c0 100644 --- a/l1-contracts/contracts/state-transition/libraries/PriorityQueue.sol +++ b/l1-contracts/contracts/state-transition/libraries/PriorityQueue.sol @@ -1,6 +1,8 @@ // 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; -pragma solidity 0.8.24; +import {QueueIsEmpty} from "../../common/L1ContractErrors.sol"; /// @notice The structure that contains meta information of the L2 transaction that was requested from L1 /// @dev The weird size of fields was selected specifically to minimize the structure storage size @@ -62,7 +64,10 @@ library PriorityQueue { /// @return The first unprocessed priority operation from the queue function front(Queue storage _queue) internal view returns (PriorityOperation memory) { - require(!_queue.isEmpty(), "D"); // priority queue is empty + // priority queue is empty + if (_queue.isEmpty()) { + revert QueueIsEmpty(); + } return _queue.data[_queue.head]; } @@ -70,7 +75,10 @@ library PriorityQueue { /// @notice Remove the first unprocessed priority operation from the queue /// @return priorityOperation that was popped from the priority queue function popFront(Queue storage _queue) internal returns (PriorityOperation memory priorityOperation) { - require(!_queue.isEmpty(), "s"); // priority queue is empty + // priority queue is empty + if (_queue.isEmpty()) { + revert QueueIsEmpty(); + } // Save value into the stack to avoid double reading from the storage uint256 head = _queue.head; diff --git a/l1-contracts/contracts/state-transition/libraries/TransactionValidator.sol b/l1-contracts/contracts/state-transition/libraries/TransactionValidator.sol index 71ef18a86..f196053f4 100644 --- a/l1-contracts/contracts/state-transition/libraries/TransactionValidator.sol +++ b/l1-contracts/contracts/state-transition/libraries/TransactionValidator.sol @@ -1,13 +1,14 @@ // 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; -pragma solidity 0.8.24; - -import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; +import {Math} from "@openzeppelin/contracts-v4/utils/math/Math.sol"; import {L2CanonicalTransaction} from "../../common/Messaging.sol"; import {TX_SLOT_OVERHEAD_L2_GAS, MEMORY_OVERHEAD_GAS, L1_TX_INTRINSIC_L2_GAS, L1_TX_DELTA_544_ENCODING_BYTES, L1_TX_DELTA_FACTORY_DEPS_L2_GAS, L1_TX_MIN_L2_GAS_BASE, L1_TX_INTRINSIC_PUBDATA, L1_TX_DELTA_FACTORY_DEPS_PUBDATA} from "../../common/Config.sol"; +import {TooMuchGas, InvalidUpgradeTxn, UpgradeTxVerifyParam, PubdataGreaterThanLimit, ValidateTxnNotEnoughGas, TxnBodyGasLimitNotEnoughGas} from "../../common/L1ContractErrors.sol"; -/// @title zkSync Library for validating L1 -> L2 transactions +/// @title ZKsync Library for validating L1 -> L2 transactions /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev library TransactionValidator { @@ -25,39 +26,70 @@ library TransactionValidator { uint256 l2GasForTxBody = getTransactionBodyGasLimit(_transaction.gasLimit, _encoded.length); // Ensuring that the transaction is provable - require(l2GasForTxBody <= _priorityTxMaxGasLimit, "ui"); + if (l2GasForTxBody > _priorityTxMaxGasLimit) { + revert TooMuchGas(); + } // Ensuring that the transaction cannot output more pubdata than is processable - require(l2GasForTxBody / _transaction.gasPerPubdataByteLimit <= _priorityTxMaxPubdata, "uk"); + if (l2GasForTxBody / _transaction.gasPerPubdataByteLimit > _priorityTxMaxPubdata) { + revert PubdataGreaterThanLimit(_priorityTxMaxPubdata, l2GasForTxBody / _transaction.gasPerPubdataByteLimit); + } // Ensuring that the transaction covers the minimal costs for its processing: // hashing its content, publishing the factory dependencies, etc. - require( + if ( getMinimalPriorityTransactionGasLimit( _encoded.length, _transaction.factoryDeps.length, _transaction.gasPerPubdataByteLimit - ) <= l2GasForTxBody, - "up" - ); + ) > l2GasForTxBody + ) { + revert ValidateTxnNotEnoughGas(); + } } /// @dev Used to validate upgrade transactions /// @param _transaction The transaction to validate function validateUpgradeTransaction(L2CanonicalTransaction memory _transaction) internal pure { // Restrict from to be within system contract range (0...2^16 - 1) - require(_transaction.from <= type(uint16).max, "ua"); - require(_transaction.to <= type(uint160).max, "ub"); - require(_transaction.paymaster == 0, "uc"); - require(_transaction.value == 0, "ud"); - require(_transaction.maxFeePerGas == 0, "uq"); - require(_transaction.maxPriorityFeePerGas == 0, "ux"); - require(_transaction.reserved[0] == 0, "ue"); - require(_transaction.reserved[1] <= type(uint160).max, "uf"); - require(_transaction.reserved[2] == 0, "ug"); - require(_transaction.reserved[3] == 0, "uo"); - require(_transaction.signature.length == 0, "uh"); - require(_transaction.paymasterInput.length == 0, "ul1"); - require(_transaction.reservedDynamic.length == 0, "um"); + if (_transaction.from > type(uint16).max) { + revert InvalidUpgradeTxn(UpgradeTxVerifyParam.From); + } + if (_transaction.to > type(uint160).max) { + revert InvalidUpgradeTxn(UpgradeTxVerifyParam.To); + } + if (_transaction.paymaster != 0) { + revert InvalidUpgradeTxn(UpgradeTxVerifyParam.Paymaster); + } + if (_transaction.value != 0) { + revert InvalidUpgradeTxn(UpgradeTxVerifyParam.Value); + } + if (_transaction.maxFeePerGas != 0) { + revert InvalidUpgradeTxn(UpgradeTxVerifyParam.MaxFeePerGas); + } + if (_transaction.maxPriorityFeePerGas != 0) { + revert InvalidUpgradeTxn(UpgradeTxVerifyParam.MaxPriorityFeePerGas); + } + if (_transaction.reserved[0] != 0) { + revert InvalidUpgradeTxn(UpgradeTxVerifyParam.Reserved0); + } + if (_transaction.reserved[1] > type(uint160).max) { + revert InvalidUpgradeTxn(UpgradeTxVerifyParam.Reserved1); + } + if (_transaction.reserved[2] != 0) { + revert InvalidUpgradeTxn(UpgradeTxVerifyParam.Reserved2); + } + if (_transaction.reserved[3] != 0) { + revert InvalidUpgradeTxn(UpgradeTxVerifyParam.Reserved3); + } + if (_transaction.signature.length != 0) { + revert InvalidUpgradeTxn(UpgradeTxVerifyParam.Signature); + } + if (_transaction.paymasterInput.length != 0) { + revert InvalidUpgradeTxn(UpgradeTxVerifyParam.PaymasterInput); + } + if (_transaction.reservedDynamic.length != 0) { + revert InvalidUpgradeTxn(UpgradeTxVerifyParam.ReservedDynamic); + } } /// @dev Calculates the approximate minimum gas limit required for executing a priority transaction. @@ -112,7 +144,10 @@ library TransactionValidator { ) internal pure returns (uint256 txBodyGasLimit) { uint256 overhead = getOverheadForTransaction(_encodingLength); - require(_totalGasLimit >= overhead, "my"); // provided gas limit doesn't cover transaction overhead + // provided gas limit doesn't cover transaction overhead + if (_totalGasLimit < overhead) { + revert TxnBodyGasLimitNotEnoughGas(); + } unchecked { // We enforce the fact that `_totalGasLimit >= overhead` explicitly above. txBodyGasLimit = _totalGasLimit - overhead; @@ -122,7 +157,7 @@ library TransactionValidator { /// @notice Based on the total L2 gas limit and several other parameters of the transaction /// returns the part of the L2 gas that will be spent on the batch's overhead. /// @dev The details of how this function works can be checked in the documentation - /// of the fee model of zkSync. The appropriate comments are also present + /// of the fee model of ZKsync. The appropriate comments are also present /// in the Rust implementation description of function `get_maximal_allowed_overhead`. /// @param _encodingLength The length of the binary encoding of the transaction in bytes function getOverheadForTransaction( diff --git a/l1-contracts/contracts/upgrades/BaseZkSyncUpgrade.sol b/l1-contracts/contracts/upgrades/BaseZkSyncUpgrade.sol index 72c02f277..4534884d5 100644 --- a/l1-contracts/contracts/upgrades/BaseZkSyncUpgrade.sol +++ b/l1-contracts/contracts/upgrades/BaseZkSyncUpgrade.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.24; -import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {SafeCast} from "@openzeppelin/contracts-v4/utils/math/SafeCast.sol"; import {ZkSyncHyperchainBase} from "../state-transition/chain-deps/facets/ZkSyncHyperchainBase.sol"; import {VerifierParams} from "../state-transition/chain-interfaces/IVerifier.sol"; @@ -11,6 +11,7 @@ import {L2ContractHelper} from "../common/libraries/L2ContractHelper.sol"; import {TransactionValidator} from "../state-transition/libraries/TransactionValidator.sol"; import {MAX_NEW_FACTORY_DEPS, SYSTEM_UPGRADE_L2_TX_TYPE, MAX_ALLOWED_MINOR_VERSION_DELTA} from "../common/Config.sol"; import {L2CanonicalTransaction} from "../common/Messaging.sol"; +import {ProtocolVersionMinorDeltaTooBig, TimeNotReached, InvalidTxType, L2UpgradeNonceNotEqualToNewProtocolVersion, TooManyFactoryDeps, UnexpectedNumberOfFactoryDeps, ProtocolVersionTooSmall, PreviousUpgradeNotFinalized, PreviousUpgradeNotCleaned, L2BytecodeHashMismatch, PatchCantSetUpgradeTxn, PreviousProtocolMajorVersionNotZero, NewProtocolMajorVersionNotZero, PatchUpgradeCantSetDefaultAccount, PatchUpgradeCantSetBootloader} from "./ZkSyncUpgradeErrors.sol"; import {SemVer} from "../common/libraries/SemVer.sol"; /// @notice The struct that represents the upgrade proposal. @@ -71,7 +72,9 @@ abstract contract BaseZkSyncUpgrade is ZkSyncHyperchainBase { // 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 // as the permitted delay window is reduced in the future. - require(block.timestamp >= _proposedUpgrade.upgradeTimestamp, "Upgrade is not ready yet"); + if (block.timestamp < _proposedUpgrade.upgradeTimestamp) { + revert TimeNotReached(_proposedUpgrade.upgradeTimestamp, block.timestamp); + } (uint32 newMinorVersion, bool isPatchOnly) = _setNewProtocolVersion(_proposedUpgrade.newProtocolVersion); _upgradeL1Contract(_proposedUpgrade.l1ContractsUpgradeCalldata); @@ -98,7 +101,9 @@ abstract contract BaseZkSyncUpgrade is ZkSyncHyperchainBase { return; } - require(!_patchOnly, "Patch only upgrade can not set new default account"); + if (_patchOnly) { + revert PatchUpgradeCantSetDefaultAccount(); + } L2ContractHelper.validateBytecodeHash(_l2DefaultAccountBytecodeHash); @@ -118,7 +123,9 @@ abstract contract BaseZkSyncUpgrade is ZkSyncHyperchainBase { return; } - require(!_patchOnly, "Patch only upgrade can not set new bootloader"); + if (_patchOnly) { + revert PatchUpgradeCantSetBootloader(); + } L2ContractHelper.validateBytecodeHash(_l2BootloaderBytecodeHash); @@ -202,9 +209,12 @@ abstract contract BaseZkSyncUpgrade is ZkSyncHyperchainBase { return bytes32(0); } - require(!_patchOnly, "Patch only upgrade can not set upgrade transaction"); - - require(_l2ProtocolUpgradeTx.txType == SYSTEM_UPGRADE_L2_TX_TYPE, "L2 system upgrade tx type is wrong"); + if (_l2ProtocolUpgradeTx.txType != SYSTEM_UPGRADE_L2_TX_TYPE) { + revert InvalidTxType(_l2ProtocolUpgradeTx.txType); + } + if (_patchOnly) { + revert PatchCantSetUpgradeTxn(); + } bytes memory encodedTransaction = abi.encode(_l2ProtocolUpgradeTx); @@ -219,10 +229,9 @@ abstract contract BaseZkSyncUpgrade is ZkSyncHyperchainBase { // We want the hashes of l2 system upgrade transactions to be unique. // This is why we require that the `nonce` field is unique to each upgrade. - require( - _l2ProtocolUpgradeTx.nonce == _newMinorProtocolVersion, - "The new protocol version should be included in the L2 system upgrade tx" - ); + if (_l2ProtocolUpgradeTx.nonce != _newMinorProtocolVersion) { + revert L2UpgradeNonceNotEqualToNewProtocolVersion(_l2ProtocolUpgradeTx.nonce, _newMinorProtocolVersion); + } _verifyFactoryDeps(_factoryDeps, _l2ProtocolUpgradeTx.factoryDeps); @@ -237,14 +246,19 @@ abstract contract BaseZkSyncUpgrade is ZkSyncHyperchainBase { /// @param _factoryDeps The list of factory deps /// @param _expectedHashes The list of expected bytecode hashes function _verifyFactoryDeps(bytes[] calldata _factoryDeps, uint256[] calldata _expectedHashes) private pure { - require(_factoryDeps.length == _expectedHashes.length, "Wrong number of factory deps"); - require(_factoryDeps.length <= MAX_NEW_FACTORY_DEPS, "Factory deps can be at most 32"); - - for (uint256 i = 0; i < _factoryDeps.length; ++i) { - require( - L2ContractHelper.hashL2Bytecode(_factoryDeps[i]) == bytes32(_expectedHashes[i]), - "Wrong factory dep hash" - ); + if (_factoryDeps.length != _expectedHashes.length) { + revert UnexpectedNumberOfFactoryDeps(); + } + if (_factoryDeps.length > MAX_NEW_FACTORY_DEPS) { + revert TooManyFactoryDeps(); + } + uint256 length = _factoryDeps.length; + + for (uint256 i = 0; i < length; ++i) { + bytes32 bytecodeHash = L2ContractHelper.hashL2Bytecode(_factoryDeps[i]); + if (bytecodeHash != bytes32(_expectedHashes[i])) { + revert L2BytecodeHashMismatch(bytecodeHash, bytes32(_expectedHashes[i])); + } } } @@ -254,20 +268,23 @@ abstract contract BaseZkSyncUpgrade is ZkSyncHyperchainBase { uint256 _newProtocolVersion ) internal virtual returns (uint32 newMinorVersion, bool patchOnly) { uint256 previousProtocolVersion = s.protocolVersion; - require( - _newProtocolVersion > previousProtocolVersion, - "New protocol version is not greater than the current one" - ); + if (_newProtocolVersion <= previousProtocolVersion) { + revert ProtocolVersionTooSmall(); + } // slither-disable-next-line unused-return (uint32 previousMajorVersion, uint32 previousMinorVersion, ) = SemVer.unpackSemVer( SafeCast.toUint96(previousProtocolVersion) ); - require(previousMajorVersion == 0, "Implementation requires that the major version is 0 at all times"); + if (previousMajorVersion != 0) { + revert PreviousProtocolMajorVersionNotZero(); + } uint32 newMajorVersion; // slither-disable-next-line unused-return (newMajorVersion, newMinorVersion, ) = SemVer.unpackSemVer(SafeCast.toUint96(_newProtocolVersion)); - require(newMajorVersion == 0, "Major must always be 0"); + if (newMajorVersion != 0) { + revert NewProtocolMajorVersionNotZero(); + } // Since `_newProtocolVersion > previousProtocolVersion`, and both old and new major version is 0, // the difference between minor versions is >= 0. @@ -278,19 +295,22 @@ abstract contract BaseZkSyncUpgrade is ZkSyncHyperchainBase { } // While this is implicitly enforced by other checks above, we still double check just in case - require(minorDelta <= MAX_ALLOWED_MINOR_VERSION_DELTA, "Too big protocol version difference"); + if (minorDelta > MAX_ALLOWED_MINOR_VERSION_DELTA) { + revert ProtocolVersionMinorDeltaTooBig(MAX_ALLOWED_MINOR_VERSION_DELTA, minorDelta); + } // If the minor version changes also, we need to ensure that the previous upgrade has been finalized. // In case the minor version does not change, we permit to keep the old upgrade transaction in the system, but it - // must be ensured in the other parts of the upgrade that the is not overridden. + // must be ensured in the other parts of the upgrade that the upgrade transaction is not overridden. if (!patchOnly) { // If the previous upgrade had an L2 system upgrade transaction, we require that it is finalized. // Note it is important to keep this check, as otherwise hyperchains might skip upgrades by overwriting - require(s.l2SystemContractsUpgradeTxHash == bytes32(0), "Previous upgrade has not been finalized"); - require( - s.l2SystemContractsUpgradeBatchNumber == 0, - "The batch number of the previous upgrade has not been cleaned" - ); + if (s.l2SystemContractsUpgradeTxHash != bytes32(0)) { + revert PreviousUpgradeNotFinalized(s.l2SystemContractsUpgradeTxHash); + } + if (s.l2SystemContractsUpgradeBatchNumber != 0) { + revert PreviousUpgradeNotCleaned(); + } } s.protocolVersion = _newProtocolVersion; diff --git a/l1-contracts/contracts/upgrades/BaseZkSyncUpgradeGenesis.sol b/l1-contracts/contracts/upgrades/BaseZkSyncUpgradeGenesis.sol index 7cf9b5ceb..561f25d23 100644 --- a/l1-contracts/contracts/upgrades/BaseZkSyncUpgradeGenesis.sol +++ b/l1-contracts/contracts/upgrades/BaseZkSyncUpgradeGenesis.sol @@ -2,9 +2,10 @@ pragma solidity 0.8.24; -import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import {SafeCast} from "@openzeppelin/contracts-v4/utils/math/SafeCast.sol"; import {BaseZkSyncUpgrade} from "./BaseZkSyncUpgrade.sol"; +import {ProtocolVersionTooSmall, ProtocolVersionDeltaTooLarge, PreviousUpgradeNotFinalized, PreviousUpgradeBatchNotCleared, ProtocolMajorVersionNotZero} from "./ZkSyncUpgradeErrors.sol"; import {MAX_ALLOWED_MINOR_VERSION_DELTA} from "../common/Config.sol"; import {SemVer} from "../common/libraries/SemVer.sol"; @@ -18,21 +19,27 @@ abstract contract BaseZkSyncUpgradeGenesis is BaseZkSyncUpgrade { uint256 _newProtocolVersion ) internal override returns (uint32 newMinorVersion, bool patchOnly) { uint256 previousProtocolVersion = s.protocolVersion; - // IMPORTANT Genesis Upgrade difference: Note this is the only thing change > to >= - require( - _newProtocolVersion >= previousProtocolVersion, - "New protocol version is not greater than the current one" - ); + if ( + // IMPORTANT Genesis Upgrade difference: Note this is the only thing change <= to < + _newProtocolVersion < previousProtocolVersion + ) { + revert ProtocolVersionTooSmall(); + } // slither-disable-next-line unused-return (uint32 previousMajorVersion, uint32 previousMinorVersion, ) = SemVer.unpackSemVer( SafeCast.toUint96(previousProtocolVersion) ); - require(previousMajorVersion == 0, "Implementation requires that the major version is 0 at all times"); + + if (previousMajorVersion != 0) { + revert ProtocolMajorVersionNotZero(); + } uint32 newMajorVersion; // slither-disable-next-line unused-return (newMajorVersion, newMinorVersion, ) = SemVer.unpackSemVer(SafeCast.toUint96(_newProtocolVersion)); - require(newMajorVersion == 0, "Major must always be 0"); + if (newMajorVersion != 0) { + revert ProtocolMajorVersionNotZero(); + } // Since `_newProtocolVersion > previousProtocolVersion`, and both old and new major version is 0, // the difference between minor versions is >= 0. @@ -42,19 +49,22 @@ abstract contract BaseZkSyncUpgradeGenesis is BaseZkSyncUpgrade { patchOnly = false; // While this is implicitly enforced by other checks above, we still double check just in case - require(minorDelta <= MAX_ALLOWED_MINOR_VERSION_DELTA, "Too big protocol version difference"); + if (minorDelta > MAX_ALLOWED_MINOR_VERSION_DELTA) { + revert ProtocolVersionDeltaTooLarge(minorDelta, MAX_ALLOWED_MINOR_VERSION_DELTA); + } // If the minor version changes also, we need to ensure that the previous upgrade has been finalized. // In case the minor version does not change, we permit to keep the old upgrade transaction in the system, but it - // must be ensured in the other parts of the upgrade that the is not overridden. + // must be ensured in the other parts of the upgrade that the upgrade transaction is not overridden. if (!patchOnly) { // If the previous upgrade had an L2 system upgrade transaction, we require that it is finalized. // Note it is important to keep this check, as otherwise hyperchains might skip upgrades by overwriting - require(s.l2SystemContractsUpgradeTxHash == bytes32(0), "Previous upgrade has not been finalized"); - require( - s.l2SystemContractsUpgradeBatchNumber == 0, - "The batch number of the previous upgrade has not been cleaned" - ); + if (s.l2SystemContractsUpgradeTxHash != bytes32(0)) { + revert PreviousUpgradeNotFinalized(s.l2SystemContractsUpgradeTxHash); + } + if (s.l2SystemContractsUpgradeBatchNumber != 0) { + revert PreviousUpgradeBatchNotCleared(); + } } s.protocolVersion = _newProtocolVersion; diff --git a/l1-contracts/contracts/upgrades/ZkSyncUpgradeErrors.sol b/l1-contracts/contracts/upgrades/ZkSyncUpgradeErrors.sol new file mode 100644 index 000000000..b30c882e7 --- /dev/null +++ b/l1-contracts/contracts/upgrades/ZkSyncUpgradeErrors.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.21; + +// 0x7a47c9a2 +error InvalidChainId(); +// 0xd7f8c13e +error PreviousUpgradeBatchNotCleared(); +// 0x3c43ccce +error ProtocolMajorVersionNotZero(); +// 0xd7f50a9d +error PatchCantSetUpgradeTxn(); +// 0xd2c011d6 +error L2UpgradeNonceNotEqualToNewProtocolVersion(uint256 nonce, uint256 protocolVersion); +// 0xcb5e4247 +error L2BytecodeHashMismatch(bytes32 expected, bytes32 provided); +// 0x88d7b498 +error ProtocolVersionTooSmall(); +// 0x56d45b12 +error ProtocolVersionTooBig(); +// 0x5c598b60 +error PreviousProtocolMajorVersionNotZero(); +// 0x72ea85ad +error NewProtocolMajorVersionNotZero(); +// 0xd328c12a +error ProtocolVersionMinorDeltaTooBig(uint256 limit, uint256 proposed); +// 0xe1a9736b +error ProtocolVersionDeltaTooLarge(uint256 _proposedDelta, uint256 _maxDelta); +// 0x6d172ab2 +error ProtocolVersionShouldBeGreater(uint256 _oldProtocolVersion, uint256 _newProtocolVersion); +// 0x559cc34e +error PatchUpgradeCantSetDefaultAccount(); +// 0x962fd7d0 +error PatchUpgradeCantSetBootloader(); +// 0x101ba748 +error PreviousUpgradeNotFinalized(bytes32 txHash); +// 0xa0f47245 +error PreviousUpgradeNotCleaned(); +// 0x07218375 +error UnexpectedNumberOfFactoryDeps(); +// 0x76da24b9 +error TooManyFactoryDeps(); +// 0x5cb29523 +error InvalidTxType(uint256 txType); +// 0x08753982 +error TimeNotReached(uint256 expectedTimestamp, uint256 actualTimestamp); +// 0xd92e233d +error ZeroAddress(); diff --git a/l1-contracts/contracts/vendor/AddressAliasHelper.sol b/l1-contracts/contracts/vendor/AddressAliasHelper.sol index 19f3b2d79..ad80f3483 100644 --- a/l1-contracts/contracts/vendor/AddressAliasHelper.sol +++ b/l1-contracts/contracts/vendor/AddressAliasHelper.sol @@ -15,11 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -pragma solidity 0.8.24; +// 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; library AddressAliasHelper { - uint160 constant offset = uint160(0x1111000000000000000000000000000000001111); + uint160 private constant offset = uint160(0x1111000000000000000000000000000000001111); /// @notice Utility function converts the address that submitted a tx /// to the inbox on L1 to the msg.sender viewed on L2 @@ -51,10 +51,12 @@ library AddressAliasHelper { ) internal view returns (address _recipient) { if (_refundRecipient == address(0)) { // If the `_refundRecipient` is not provided, we use the `_prevMsgSender` as the recipient. + // solhint-disable avoid-tx-origin // slither-disable-next-line tx-origin _recipient = _prevMsgSender == tx.origin ? _prevMsgSender : AddressAliasHelper.applyL1ToL2Alias(_prevMsgSender); + // solhint-enable avoid-tx-origin } else if (_refundRecipient.code.length > 0) { // If the `_refundRecipient` is a smart contract, we apply the L1 to L2 alias to prevent foot guns. _recipient = AddressAliasHelper.applyL1ToL2Alias(_refundRecipient); diff --git a/l1-contracts/deploy-script-config-template/config-prepare-registration-calldata.toml b/l1-contracts/deploy-script-config-template/config-prepare-registration-calldata.toml new file mode 100644 index 000000000..99ff2e7ce --- /dev/null +++ b/l1-contracts/deploy-script-config-template/config-prepare-registration-calldata.toml @@ -0,0 +1,12 @@ +[deployed_addresses] +state_transition_proxy_addr = "0x635853efd1d388f597feb9fe06e666efda397911" +erc20_bridge_proxy_addr = "0x147CDc5DD347bA141545Ad08fce748484Ed7fDbA" + + +[chain] +chain_id = 123 +era_chain_id = 9 +admin = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" +diamond_cut_data = "0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000cf3cd7fa8948f7748d20f7f33e85a0320b6c5d4d0000000000000000000000000000000000000000000000000000000000000c400000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000008800000000000000000000000000000000000000000000000000000000000000a200000000000000000000000003fe9b8f276c1a2e26d2190f2d9fd1897a04eb90a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d0e18b681000000000000000000000000000000000000000000000000000000001733894500000000000000000000000000000000000000000000000000000000fc57565f000000000000000000000000000000000000000000000000000000001cc5d1030000000000000000000000000000000000000000000000000000000021f603d700000000000000000000000000000000000000000000000000000000235d9eb50000000000000000000000000000000000000000000000000000000027ae4c16000000000000000000000000000000000000000000000000000000004623c91d000000000000000000000000000000000000000000000000000000004dd18bf50000000000000000000000000000000000000000000000000000000064bf8d6600000000000000000000000000000000000000000000000000000000a9f6d94100000000000000000000000000000000000000000000000000000000be6f11cf00000000000000000000000000000000000000000000000000000000e76db865000000000000000000000000000000000000000000000000000000000000000000000000000000000e70df06c0938e724ce23e49b3c4f01abed6bbfc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000002906d49e5b00000000000000000000000000000000000000000000000000000000086a56f8000000000000000000000000000000000000000000000000000000000ec6b0b700000000000000000000000000000000000000000000000000000000fe26699e0000000000000000000000000000000000000000000000000000000018e3a941000000000000000000000000000000000000000000000000000000001de72e340000000000000000000000000000000000000000000000000000000029b98c670000000000000000000000000000000000000000000000000000000033ce93fe000000000000000000000000000000000000000000000000000000003591c1a000000000000000000000000000000000000000000000000000000000396073820000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000052ef6b2c000000000000000000000000000000000000000000000000000000005518c73b0000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000006e9960c30000000000000000000000000000000000000000000000000000000074f4d30d0000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000007a0ed627000000000000000000000000000000000000000000000000000000007b30c8da0000000000000000000000000000000000000000000000000000000098acd7a6000000000000000000000000000000000000000000000000000000009cd939e4000000000000000000000000000000000000000000000000000000009d1b5a8100000000000000000000000000000000000000000000000000000000a1954fc500000000000000000000000000000000000000000000000000000000adfca15e00000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000b22dd78e00000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000cdffacc600000000000000000000000000000000000000000000000000000000d046815600000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000e5355c7500000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000ea6c029c00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000f5c1182c00000000000000000000000000000000000000000000000000000000facd743b00000000000000000000000000000000000000000000000000000000fd791f3c000000000000000000000000000000000000000000000000000000000000000000000000000000006e2e077311fb218b80404298c9a227c42b792b610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008042901c70000000000000000000000000000000000000000000000000000000012f43dab00000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000263b7f8e000000000000000000000000000000000000000000000000000000006c0960f900000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000c924de3500000000000000000000000000000000000000000000000000000000e4948f4300000000000000000000000000000000000000000000000000000000000000000000000000000000a226529de193f2153b25d7d9ad774689b78c301e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000080f23da4300000000000000000000000000000000000000000000000000000000c3d93e7c000000000000000000000000000000000000000000000000000000006edd4f12000000000000000000000000000000000000000000000000000000006f497ac600000000000000000000000000000000000000000000000000000000701f58c5000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000c37533bb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000007bd175a72991f0a30ed333eaf1cb215c42e7492c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010008e742608b21bf7eb23c1a9d0602047e3618b464c9b59c0fba3b3d7ab66e01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e3200000000000000000000000000000000000000000000000000000000044aa200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000001d4c00000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000182b8000000000000000000000000000000000000000000000000000000000ee6b280000000000000000000000000baa109e4e90cc08a3c5069a0173aace4e934d57e" +bridgehub_create_new_chain_salt = 0 +base_token_addr = "0x0000000000000000000000000000000000000001" diff --git a/l1-contracts/deploy-scripts/AcceptAdmin.s.sol b/l1-contracts/deploy-scripts/AcceptAdmin.s.sol index be08c5295..3a40b4d78 100644 --- a/l1-contracts/deploy-scripts/AcceptAdmin.s.sol +++ b/l1-contracts/deploy-scripts/AcceptAdmin.s.sol @@ -1,15 +1,33 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.0; +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; -import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import {Ownable2Step} from "@openzeppelin/contracts-v4/access/Ownable2Step.sol"; import {IZkSyncHyperchain} from "contracts/state-transition/chain-interfaces/IZkSyncHyperchain.sol"; import {ChainAdmin} from "contracts/governance/ChainAdmin.sol"; import {IChainAdmin} from "contracts/governance/IChainAdmin.sol"; import {Utils} from "./Utils.sol"; +import {stdToml} from "forge-std/StdToml.sol"; contract AcceptAdmin is Script { + using stdToml for string; + + struct Config { + address admin; + address governor; + } + + Config internal config; + + function initConfig() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/script-config/config-accept-admin.toml"); + string memory toml = vm.readFile(path); + config.admin = toml.readAddress("$.target_addr"); + config.governor = toml.readAddress("$.governor"); + } + // This function should be called by the owner to accept the admin role function governanceAcceptOwner(address governor, address target) public { Ownable2Step adminContract = Ownable2Step(target); diff --git a/l1-contracts/deploy-scripts/DecentralizeGovernanceUpgradeScript.s.sol b/l1-contracts/deploy-scripts/DecentralizeGovernanceUpgradeScript.s.sol index f0fc73617..1e35d3fe4 100644 --- a/l1-contracts/deploy-scripts/DecentralizeGovernanceUpgradeScript.s.sol +++ b/l1-contracts/deploy-scripts/DecentralizeGovernanceUpgradeScript.s.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT +// solhint-disable reason-string, gas-custom-errors pragma solidity 0.8.24; import {Script} from "forge-std/Script.sol"; -import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; +import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {Governance} from "contracts/governance/Governance.sol"; import {IStateTransitionManager} from "contracts/state-transition/IStateTransitionManager.sol"; diff --git a/l1-contracts/deploy-scripts/DeployErc20.s.sol b/l1-contracts/deploy-scripts/DeployErc20.s.sol index 69a8ab649..9a7c9cfa9 100644 --- a/l1-contracts/deploy-scripts/DeployErc20.s.sol +++ b/l1-contracts/deploy-scripts/DeployErc20.s.sol @@ -13,6 +13,7 @@ import {TestnetERC20Token} from "contracts/dev-contracts/TestnetERC20Token.sol"; import {WETH9} from "contracts/dev-contracts/WETH9.sol"; import {Utils} from "./Utils.sol"; +import {MintFailed} from "./ZkSyncScriptErrors.sol"; contract DeployErc20Script is Script { using stdToml for string; @@ -34,7 +35,7 @@ contract DeployErc20Script is Script { uint256 mint; } - Config config; + Config internal config; function run() public { console.log("Deploying ERC20 Tokens"); @@ -66,7 +67,8 @@ contract DeployErc20Script is Script { string[] memory tokens = vm.parseTomlKeys(toml, "$.tokens"); - for (uint256 i = 0; i < tokens.length; i++) { + uint256 tokensLength = tokens.length; + for (uint256 i = 0; i < tokensLength; ++i) { TokenDescription memory token; string memory key = string.concat("$.tokens.", tokens[i]); token.name = toml.readString(string.concat(key, ".name")); @@ -79,7 +81,8 @@ contract DeployErc20Script is Script { } function deployTokens() internal { - for (uint256 i = 0; i < config.tokens.length; i++) { + uint256 tokensLength = config.tokens.length; + for (uint256 i = 0; i < tokensLength; ++i) { TokenDescription storage token = config.tokens[i]; console.log("Deploying token:", token.name); address tokenAddress = deployErc20({ @@ -116,11 +119,14 @@ contract DeployErc20Script is Script { if (mint > 0) { vm.broadcast(); additionalAddressesForMinting.push(config.deployerAddress); - for (uint256 i = 0; i < additionalAddressesForMinting.length; i++) { + uint256 addressMintListLength = additionalAddressesForMinting.length; + for (uint256 i = 0; i < addressMintListLength; ++i) { (bool success, ) = tokenAddress.call( abi.encodeWithSignature("mint(address,uint256)", additionalAddressesForMinting[i], mint) ); - require(success, "Mint failed"); + if (!success) { + revert MintFailed(); + } console.log("Minting to:", additionalAddressesForMinting[i]); } } @@ -130,7 +136,8 @@ contract DeployErc20Script is Script { function saveOutput() internal { string memory tokens = ""; - for (uint256 i = 0; i < config.tokens.length; i++) { + uint256 tokensLength = config.tokens.length; + for (uint256 i = 0; i < tokensLength; ++i) { TokenDescription memory token = config.tokens[i]; vm.serializeString(token.symbol, "name", token.name); vm.serializeString(token.symbol, "symbol", token.symbol); diff --git a/l1-contracts/deploy-scripts/DeployL1.s.sol b/l1-contracts/deploy-scripts/DeployL1.s.sol index f4de831a8..416ffd6a3 100644 --- a/l1-contracts/deploy-scripts/DeployL1.s.sol +++ b/l1-contracts/deploy-scripts/DeployL1.s.sol @@ -5,8 +5,8 @@ pragma solidity 0.8.24; import {Script, console2 as console} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; -import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {Utils} from "./Utils.sol"; import {Multicall3} from "contracts/dev-contracts/Multicall3.sol"; @@ -33,13 +33,15 @@ import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-de import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; import {L1ERC20Bridge} from "contracts/bridge/L1ERC20Bridge.sol"; import {DiamondProxy} from "contracts/state-transition/chain-deps/DiamondProxy.sol"; +import {AddressHasNoCode} from "./ZkSyncScriptErrors.sol"; contract DeployL1Script is Script { using stdToml for string; - address constant ADDRESS_ONE = 0x0000000000000000000000000000000000000001; - address constant DETERMINISTIC_CREATE2_ADDRESS = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + address internal constant ADDRESS_ONE = 0x0000000000000000000000000000000000000001; + address internal constant DETERMINISTIC_CREATE2_ADDRESS = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + // solhint-disable-next-line gas-struct-packing struct DeployedAddresses { BridgehubDeployedAddresses bridgehub; StateTransitionDeployedAddresses stateTransition; @@ -52,11 +54,13 @@ contract DeployL1Script is Script { address create2Factory; } + // solhint-disable-next-line gas-struct-packing struct BridgehubDeployedAddresses { address bridgehubImplementation; address bridgehubProxy; } + // solhint-disable-next-line gas-struct-packing struct StateTransitionDeployedAddresses { address stateTransitionProxy; address stateTransitionImplementation; @@ -71,6 +75,7 @@ contract DeployL1Script is Script { address diamondProxy; } + // solhint-disable-next-line gas-struct-packing struct BridgesDeployedAddresses { address erc20BridgeImplementation; address erc20BridgeProxy; @@ -78,6 +83,7 @@ contract DeployL1Script is Script { address sharedBridgeProxy; } + // solhint-disable-next-line gas-struct-packing struct Config { uint256 l1ChainId; uint256 eraChainId; @@ -88,6 +94,7 @@ contract DeployL1Script is Script { TokensConfig tokens; } + // solhint-disable-next-line gas-struct-packing struct ContractsConfig { bytes32 create2FactorySalt; address create2FactoryAddr; @@ -119,8 +126,8 @@ contract DeployL1Script is Script { address tokenWethAddress; } - Config config; - DeployedAddresses addresses; + Config internal config; + DeployedAddresses internal addresses; function run() public { console.log("Deploying L1 contracts"); @@ -219,7 +226,7 @@ contract DeployL1Script is Script { if (isConfigured) { if (config.contracts.create2FactoryAddr.code.length == 0) { - revert("Create2Factory configured address is empty"); + revert AddressHasNoCode(config.contracts.create2FactoryAddr); } contractAddress = config.contracts.create2FactoryAddr; console.log("Using configured Create2Factory address:", contractAddress); diff --git a/l1-contracts/deploy-scripts/DeployL2Contracts.sol b/l1-contracts/deploy-scripts/DeployL2Contracts.sol index 3525b66b4..4578f1717 100644 --- a/l1-contracts/deploy-scripts/DeployL2Contracts.sol +++ b/l1-contracts/deploy-scripts/DeployL2Contracts.sol @@ -1,4 +1,6 @@ -pragma solidity ^0.8.24; +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; @@ -11,9 +13,10 @@ import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; contract DeployL2Script is Script { using stdToml for string; - Config config; - ContractsBytecodes contracts; + Config internal config; + ContractsBytecodes internal contracts; + // solhint-disable-next-line gas-struct-packing struct Config { address bridgehubAddress; address l1SharedBridgeProxy; @@ -118,43 +121,41 @@ contract DeployL2Script is Script { function loadContracts(bool legacyBridge) internal { //HACK: Meanwhile we are not integrated foundry zksync we use contracts that has been built using hardhat - contracts.l2StandardErc20FactoryBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json" - ); - contracts.beaconProxy = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.json" + contracts.l2StandardErc20FactoryBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/UpgradeableBeacon.sol/UpgradeableBeacon.json" ); - contracts.l2StandardErc20Bytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/bridge/L2StandardERC20.sol/L2StandardERC20.json" + contracts.beaconProxy = Utils.readFoundryBytecode("/../l2-contracts/zkout/BeaconProxy.sol/BeaconProxy.json"); + contracts.l2StandardErc20Bytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/L2StandardERC20.sol/L2StandardERC20.json" ); if (legacyBridge) { - contracts.l2SharedBridgeBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/dev-contracts/DevL2SharedBridge.sol/DevL2SharedBridge.json" + contracts.l2SharedBridgeBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/DevL2SharedBridge.sol/DevL2SharedBridge.json" ); } else { - contracts.l2SharedBridgeBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/bridge/L2SharedBridge.sol/L2SharedBridge.json" + contracts.l2SharedBridgeBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/L2SharedBridge.sol/L2SharedBridge.json" ); } - contracts.l2SharedBridgeProxyBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" + contracts.l2SharedBridgeProxyBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" ); - contracts.consensusRegistryBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/ConsensusRegistry.sol/ConsensusRegistry.json" + contracts.consensusRegistryBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/ConsensusRegistry.sol/ConsensusRegistry.json" ); - contracts.consensusRegistryProxyBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" + contracts.consensusRegistryProxyBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json" ); - contracts.multicall3Bytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/dev-contracts/Multicall3.sol/Multicall3.json" + contracts.multicall3Bytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/Multicall3.sol/Multicall3.json" ); - contracts.forceDeployUpgrader = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/ForceDeployUpgrader.sol/ForceDeployUpgrader.json" + contracts.forceDeployUpgrader = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/ForceDeployUpgrader.sol/ForceDeployUpgrader.json" ); } diff --git a/l1-contracts/deploy-scripts/DeployPaymaster.s.sol b/l1-contracts/deploy-scripts/DeployPaymaster.s.sol index 52b664bc2..eec87fbb0 100644 --- a/l1-contracts/deploy-scripts/DeployPaymaster.s.sol +++ b/l1-contracts/deploy-scripts/DeployPaymaster.s.sol @@ -1,5 +1,6 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.24; +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.21; import {Script} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; @@ -8,8 +9,9 @@ import {Utils} from "./Utils.sol"; contract DeployPaymaster is Script { using stdToml for string; - Config config; + Config internal config; + // solhint-disable-next-line gas-struct-packing struct Config { address bridgehubAddress; address l1SharedBridgeProxy; @@ -42,8 +44,8 @@ contract DeployPaymaster is Script { } function deploy() internal { - bytes memory testnetPaymasterBytecode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/TestnetPaymaster.sol/TestnetPaymaster.json" + bytes memory testnetPaymasterBytecode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/TestnetPaymaster.sol/TestnetPaymaster.json" ); config.paymaster = Utils.deployThroughL1({ diff --git a/l1-contracts/deploy-scripts/InitializeL2WethToken.s.sol b/l1-contracts/deploy-scripts/InitializeL2WethToken.s.sol index 22c427a13..c9b1de8c6 100644 --- a/l1-contracts/deploy-scripts/InitializeL2WethToken.s.sol +++ b/l1-contracts/deploy-scripts/InitializeL2WethToken.s.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; +pragma solidity ^0.8.21; // solhint-disable no-console import {Script, console2 as console} from "forge-std/Script.sol"; import {stdToml} from "forge-std/StdToml.sol"; -import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {Utils} from "./Utils.sol"; import {L2TransactionRequestDirect} from "contracts/bridgehub/IBridgehub.sol"; @@ -14,6 +14,7 @@ import {Bridgehub} from "contracts/bridgehub/Bridgehub.sol"; contract InitializeL2WethTokenScript is Script { using stdToml for string; + // solhint-disable-next-line gas-struct-packing struct Config { address deployerAddress; address create2FactoryAddr; @@ -31,7 +32,7 @@ contract InitializeL2WethTokenScript is Script { uint256 gasMultiplier; } - Config config; + Config internal config; function run() public { initializeConfig(); diff --git a/l1-contracts/deploy-scripts/PrepareZKChainRegistrationCalldata.s.sol b/l1-contracts/deploy-scripts/PrepareZKChainRegistrationCalldata.s.sol new file mode 100644 index 000000000..0a7e20a53 --- /dev/null +++ b/l1-contracts/deploy-scripts/PrepareZKChainRegistrationCalldata.s.sol @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +// solhint-disable no-console, gas-struct-packing, 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 {Bridgehub} from "contracts/bridgehub/Bridgehub.sol"; +import {L2ContractHelper} from "contracts/common/libraries/L2ContractHelper.sol"; +import {AddressAliasHelper} from "contracts/vendor/AddressAliasHelper.sol"; +import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; +import {IStateTransitionManager} from "contracts/state-transition/IStateTransitionManager.sol"; +import {IGovernance} from "contracts/governance/IGovernance.sol"; +import {Utils} from "./Utils.sol"; + +/** + * @title Prepare ZKChain Registration Calldata + * @dev Script to prepare calldata for registering a new ZKChain on the bridgehub + * + * This script prepares calldata for registering a new ZKChain on the bridgehub + * That includes 3 steps: + * 1. Register base token on the bridgehub + * 2. Register the new ZKChain on the bridgehub + * 3. Initialize the L2 bridge on the L1 shared bridge + * + * The script precomputes the address of the L2 bridge to generate the calldata for the third step. + * It assumes that L1 governance is the owner of the L2 bridge and the L2 bridge is deployed by the msg.sender of the script. + * + * The script reads the configuration from a TOML file `script-config/prepare-registration-calldata.toml` + * and writes the output to a TOML file `script-out/output-prepare-registration-calldata.toml`. + * + * The output contains 4 fields: + * - scheduleCalldataStageOne: calldata for scheduling the first stage + * - executeCalldataStageOne: calldata for executing the first stage + * - scheduleCalldataStageTwo: calldata for scheduling the second stage + * - executeCalldataStageTwo: calldata for executing the second stage + * (stage 2 of the execution is the registration of the L2 bridge on the L1 shared bridge) + * + * The separation is required to ensure that there is no period of time where the L2 bridge is registered, so users + * can send their funds there, but they will be burned in case L2 bridge is not initialized by the chain operator. + * It is meant to be executed only after the L2 bridge is deployed. + * + * How to use: + * 1. Create a TOML file `script-config/prepare-registration-calldata.toml`, reference config at `deploy-script-config-template/config-prepare-registration-calldata.toml`. + * 2. Run the script impersonating the address that will deploy the L2 bridge, `forge script --rpc-url $RPC --sender $DEPLOYER PrepareZKChainRegistrationCalldata.s.sol` + * 3. Run the `scheduleCalldataStageOne` and `executeCalldataStageOne` on the L1 chain using governance. + * 4. Deploy the L2 bridge using the address from step 2. This address doesn't need any special permissions, just has to be consistent across all the stages. + * 5. Run the `scheduleCalldataStageTwo` and `executeCalldataStageTwo` on the L1 chain using governance. + * + */ +contract PrepareZKChainRegistrationCalldataScript is Script { + using stdToml for string; + + address internal constant ADDRESS_ONE = 0x0000000000000000000000000000000000000001; + + struct Config { + // Admin of the yet-to-be-registered chain (L1-based address) + address chainAdmin; + // STM proxy address + address stateTransitionProxy; + // Chain ID of the new chain + uint256 chainId; + // Chain ID of the era (required for the L2 bridge deployment) + uint256 eraChainId; + // Salt for createNewChain call, also used as a governance operation salt + uint256 bridgehubCreateNewChainSalt; + // Address of the new chain's base token + address baseToken; + // Diamond cut data is a "configuration" for the Diamond proxy that will be created for a new chain. + // It can only be the one that's allowed by the STM. It can be generated by the other scripts or taken from the + // `etc/env/ecosystems/ENV.yaml` file in `zksync-era` repository + bytes diamondCutData; + // Address of the L1 ERC20 bridge proxy (required for the L2 bridge deployment) + address erc20BridgeProxy; + } + + // Addresses of the contracts in the L1 ecosystem that are fetched from the chain + struct EcosystemContracts { + // Address of the L1 shared bridge proxy + address l1SharedBridgeProxy; + // Bridgehub proxy address + address bridgehub; + // Address of the governance contract for the L1 ecosystem + address governance; + } + + struct ContractsBytecodes { + // Default bytecode of the ERC-20 on L2 (BeaconProxy) + bytes beaconProxy; + // Bytecode of the L2 shared bridge + bytes l2SharedBridgeBytecode; + // Bytecode of the L2 shared bridge proxy (TransparentUpgradeableProxy) + bytes l2SharedBridgeProxyBytecode; + } + + Config internal config; + EcosystemContracts internal ecosystem; + ContractsBytecodes internal bytecodes; + + function run() public { + console.log("Preparing ZK chain registration calldata"); + + initializeConfig(); + + checkBaseTokenAddress(); + + IGovernance.Call[] memory calls; + uint256 cnt = 0; + if (!IBridgehub(ecosystem.bridgehub).tokenIsRegistered(config.baseToken)) { + calls = new IGovernance.Call[](2); + console.log("Adding a call to register base token on the bridgehub"); + IGovernance.Call memory baseTokenRegistrationCall = prepareRegisterBaseTokenCall(); + calls[cnt] = baseTokenRegistrationCall; + ++cnt; + } else { + calls = new IGovernance.Call[](1); + } + + IGovernance.Call memory registerChainCall = prepareRegisterHyperchainCall(); + calls[cnt] = registerChainCall; + ++cnt; + + address l2SharedBridgeProxy = computeL2BridgeAddress(); + IGovernance.Call memory initChainCall = prepareInitializeChainGovernanceCall(l2SharedBridgeProxy); + + scheduleTransparentCalldata(calls, initChainCall); + } + + function initializeConfig() internal { + // Grab config from output of l1 deployment + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/script-config/prepare-registration-calldata.toml"); + console.log("Reading a config from", path); + string memory toml = vm.readFile(path); + + // Config file must be parsed key by key, otherwise values returned + // are parsed alphabetically and not by key. + // https://book.getfoundry.sh/cheatcodes/parse-toml + config.stateTransitionProxy = toml.readAddress("$.deployed_addresses.state_transition_proxy_addr"); + config.erc20BridgeProxy = toml.readAddress("$.deployed_addresses.erc20_bridge_proxy_addr"); + + ecosystem.bridgehub = IStateTransitionManager(config.stateTransitionProxy).BRIDGE_HUB(); + ecosystem.l1SharedBridgeProxy = address(Bridgehub(ecosystem.bridgehub).sharedBridge()); + ecosystem.governance = Bridgehub(ecosystem.bridgehub).owner(); + + config.chainId = toml.readUint("$.chain.chain_id"); + config.eraChainId = toml.readUint("$.chain.era_chain_id"); + config.chainAdmin = toml.readAddress("$.chain.admin"); + config.diamondCutData = toml.readBytes("$.chain.diamond_cut_data"); + config.bridgehubCreateNewChainSalt = toml.readUint("$.chain.bridgehub_create_new_chain_salt"); + config.baseToken = toml.readAddress("$.chain.base_token_addr"); + + bytecodes.l2SharedBridgeBytecode = Utils.readHardhatBytecode("/script-config/artifacts/L2SharedBridge.json"); + bytecodes.beaconProxy = Utils.readHardhatBytecode("/script-config/artifacts/BeaconProxy.json"); + bytecodes.l2SharedBridgeProxyBytecode = Utils.readHardhatBytecode( + "/script-config/artifacts/TransparentUpgradeableProxy.json" + ); + } + + function checkBaseTokenAddress() internal view { + if (config.baseToken == address(0)) { + revert("Base token address is not set"); + } + + // Check if it's ethereum address + if (config.baseToken == ADDRESS_ONE) { + return; + } + + // Does not prevent registering a non-ERC-20 contract as a token + // But calling the ERC-20 methods here on non-ERC-20 will fail without a readable revert message + if (config.baseToken.code.length == 0) { + revert("Token address is an EOA"); + } + + console.log("Using base token address:", config.baseToken); + } + + function prepareRegisterBaseTokenCall() internal view returns (IGovernance.Call memory) { + Bridgehub bridgehub = Bridgehub(ecosystem.bridgehub); + + bytes memory data = abi.encodeCall(bridgehub.addToken, (config.baseToken)); + + return IGovernance.Call({target: ecosystem.bridgehub, value: 0, data: data}); + } + + // @dev Computes the address of the L2 bridge and the L2 bridge proxy + // The variables that are used to compute the address are: + // - Salt + // - L2 bridge impl bytecode hash + // - Era chain ID + // - Beacon proxy bytecode hash + // - L1 governance address(owner of the L2 bridge) + // - L1 ERC20 bridge proxy address + // - Default ERC20 proxy address + // - Deployer's address + function computeL2BridgeAddress() internal view returns (address) { + bytes32 salt = ""; + bytes32 bridgeBytecodeHash = L2ContractHelper.hashL2Bytecode(bytecodes.l2SharedBridgeBytecode); + bytes memory bridgeConstructorData = abi.encode(config.eraChainId); + + address deployer; + address l2GovernanceAddress; + + // ZKsync's protocol design assumes that the addresses of all the smart contracts that are sending L1->L2 + // messages are aliased. We have to check if the sender is an EOA and apply the alias if it is not. + if (isEOA(msg.sender)) { + deployer = msg.sender; + } else { + deployer = AddressAliasHelper.applyL1ToL2Alias(msg.sender); + } + + // If the governance address is an EOA, we use it directly, otherwise we apply the alias. On the Mainnet/Testnet + // the governance address is a smart contract, but in case someone uses the script with different envs, we have + // to check if the address is an EOA. + if (isEOA(ecosystem.governance)) { + l2GovernanceAddress = ecosystem.governance; + } else { + l2GovernanceAddress = AddressAliasHelper.applyL1ToL2Alias(ecosystem.governance); + } + + address implContractAddress = L2ContractHelper.computeCreate2Address( + deployer, + salt, + bridgeBytecodeHash, + keccak256(bridgeConstructorData) + ); + + console.log("Computed L2 bridge impl address:", implContractAddress); + console.log("Bridge bytecode hash:"); + console.logBytes32(bridgeBytecodeHash); + console.log("Bridge constructor data:"); + console.logBytes(bridgeConstructorData); + console.log("Deployer:", deployer); + + bytes32 l2StandardErc20BytecodeHash = L2ContractHelper.hashL2Bytecode(bytecodes.beaconProxy); + + // solhint-disable-next-line func-named-parameters + bytes memory proxyInitializationParams = abi.encodeWithSignature( + "initialize(address,address,bytes32,address)", + ecosystem.l1SharedBridgeProxy, + config.erc20BridgeProxy, + l2StandardErc20BytecodeHash, + l2GovernanceAddress + ); + + bytes memory l2SharedBridgeProxyConstructorData = abi.encode( + implContractAddress, + l2GovernanceAddress, + proxyInitializationParams + ); + + address proxyContractAddress = L2ContractHelper.computeCreate2Address( + deployer, + salt, + L2ContractHelper.hashL2Bytecode(bytecodes.l2SharedBridgeProxyBytecode), + keccak256(l2SharedBridgeProxyConstructorData) + ); + + console.log("Computed L2 bridge proxy address:", proxyContractAddress); + console.log("L1 shared bridge proxy:", ecosystem.l1SharedBridgeProxy); + console.log("L1 ERC20 bridge proxy:", config.erc20BridgeProxy); + console.log("L2 governor addr:", l2GovernanceAddress); + + return proxyContractAddress; + } + + function prepareRegisterHyperchainCall() internal view returns (IGovernance.Call memory) { + Bridgehub bridgehub = Bridgehub(ecosystem.bridgehub); + + bytes memory data = abi.encodeCall( + bridgehub.createNewChain, + ( + config.chainId, + config.stateTransitionProxy, + config.baseToken, + config.bridgehubCreateNewChainSalt, + config.chainAdmin, + config.diamondCutData + ) + ); + + return IGovernance.Call({target: ecosystem.bridgehub, value: 0, data: data}); + } + + function prepareInitializeChainGovernanceCall( + address l2SharedBridgeProxy + ) internal view returns (IGovernance.Call memory) { + L1SharedBridge bridge = L1SharedBridge(ecosystem.l1SharedBridgeProxy); + + bytes memory data = abi.encodeCall(bridge.initializeChainGovernance, (config.chainId, l2SharedBridgeProxy)); + + return IGovernance.Call({target: ecosystem.l1SharedBridgeProxy, value: 0, data: data}); + } + + // @dev Prepares a call to schedule a transparent operation on the governance contract + // `calls` is an array of calls that will be executed in the first stage (add a token to BH, create a new chain) + // `initChainGovCall` is a call that will be executed in the second stage (register the L2 bridge on the L1 shared bridge) + function scheduleTransparentCalldata( + IGovernance.Call[] memory calls, + IGovernance.Call memory initChainGovCall + ) internal { + IGovernance governance = IGovernance(ecosystem.governance); + + IGovernance.Operation memory operation = IGovernance.Operation({ + calls: calls, + predecessor: bytes32(0), + salt: bytes32(config.bridgehubCreateNewChainSalt) + }); + + bytes memory scheduleCalldata = abi.encodeCall(governance.scheduleTransparent, (operation, 0)); + bytes memory executeCalldata = abi.encodeCall(governance.execute, (operation)); + + IGovernance.Call[] memory initChainGovArray = new IGovernance.Call[](1); + initChainGovArray[0] = initChainGovCall; + + IGovernance.Operation memory operation2 = IGovernance.Operation({ + calls: initChainGovArray, + predecessor: bytes32(0), + salt: bytes32(config.bridgehubCreateNewChainSalt) + }); + + bytes memory scheduleCalldata2 = abi.encodeCall(governance.scheduleTransparent, (operation2, 0)); + bytes memory executeCalldata2 = abi.encodeCall(governance.execute, (operation2)); + + saveOutput(scheduleCalldata, executeCalldata, scheduleCalldata2, executeCalldata2); + } + + // Writes the output to a TOML file `script-out/output-prepare-registration-calldata.toml + // For the detailed explanation of the output - look into the contract description + function saveOutput( + bytes memory schedule, + bytes memory execute, + bytes memory schedule2, + bytes memory execute2 + ) internal { + vm.serializeBytes("root", "scheduleCalldataStageOne", schedule); + vm.serializeBytes("root", "executeCalldataStageOne", execute); + vm.serializeBytes("root", "scheduleCalldataStageTwo", schedule2); + string memory toml = vm.serializeBytes("root", "executeCalldataStageTwo", execute2); + + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/script-out/output-prepare-registration-calldata.toml"); + + console.log("Writing the output to", path); + vm.writeToml(toml, path); + } + + function isEOA(address _addr) private view returns (bool) { + uint32 size; + assembly { + size := extcodesize(_addr) + } + + return (size == 0); + } +} + +// Done by the chain admin separately from this script: +// - add validators +// - deploy L2 contracts +// - set pubdata sending mode +// - set base token gas price multiplier diff --git a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol index f5e23cf8d..bbc01226d 100644 --- a/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol +++ b/l1-contracts/deploy-scripts/RegisterHyperchain.s.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.24; -// solhint-disable no-console +// 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"; @@ -18,9 +18,10 @@ import {PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHy contract RegisterHyperchainScript is Script { using stdToml for string; - address constant ADDRESS_ONE = 0x0000000000000000000000000000000000000001; - bytes32 constant STATE_TRANSITION_NEW_CHAIN_HASH = keccak256("NewHyperchain(uint256,address)"); + address internal constant ADDRESS_ONE = 0x0000000000000000000000000000000000000001; + bytes32 internal constant STATE_TRANSITION_NEW_CHAIN_HASH = keccak256("NewHyperchain(uint256,address)"); + // solhint-disable-next-line gas-struct-packing struct Config { address deployerAddress; address ownerAddress; @@ -43,7 +44,7 @@ contract RegisterHyperchainScript is Script { address chainAdmin; } - Config config; + Config internal config; function run() public { console.log("Deploying Hyperchain"); @@ -173,7 +174,8 @@ contract RegisterHyperchainScript is Script { // Get new diamond proxy address from emitted events Vm.Log[] memory logs = vm.getRecordedLogs(); address diamondProxyAddress; - for (uint256 i = 0; i < logs.length; i++) { + uint256 logsLength = logs.length; + for (uint256 i = 0; i < logsLength; ++i) { if (logs[i].topics[0] == STATE_TRANSITION_NEW_CHAIN_HASH) { diamondProxyAddress = address(uint160(uint256(logs[i].topics[2]))); break; diff --git a/l1-contracts/deploy-scripts/Utils.sol b/l1-contracts/deploy-scripts/Utils.sol index 4f5892ef2..5f509b0db 100644 --- a/l1-contracts/deploy-scripts/Utils.sol +++ b/l1-contracts/deploy-scripts/Utils.sol @@ -1,12 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.24; +// solhint-disable gas-custom-errors, reason-string + import {Vm} from "forge-std/Vm.sol"; import {Bridgehub} from "contracts/bridgehub/Bridgehub.sol"; import {L2TransactionRequestDirect} from "contracts/bridgehub/IBridgehub.sol"; import {IGovernance} from "contracts/governance/IGovernance.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol"; import {L2_DEPLOYER_SYSTEM_CONTRACT_ADDR} from "contracts/common/L2ContractAddresses.sol"; import {L2ContractHelper} from "contracts/common/libraries/L2ContractHelper.sol"; @@ -41,8 +43,8 @@ library Utils { bytes internal constant CREATE2_FACTORY_BYTECODE = hex"604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"; - address constant ADDRESS_ONE = 0x0000000000000000000000000000000000000001; - uint256 constant MAX_PRIORITY_TX_GAS = 72000000; + address internal constant ADDRESS_ONE = 0x0000000000000000000000000000000000000001; + uint256 internal constant MAX_PRIORITY_TX_GAS = 72000000; /** * @dev Get all selectors from the bytecode. @@ -61,12 +63,13 @@ library Utils { // Extract selectors from the result string[] memory parts = vm.split(stringResult, "\n"); - bytes4[] memory selectors = new bytes4[](parts.length); - for (uint256 i = 0; i < parts.length; i++) { + uint256 partsLength = parts.length; + bytes4[] memory selectors = new bytes4[](partsLength); + for (uint256 i = 0; i < partsLength; ++i) { bytes memory part = bytes(parts[i]); bytes memory extractedSelector = new bytes(10); // Selector length 10 is 0x + 4 bytes - for (uint256 j = 0; j < 10; j++) { + for (uint256 j = 0; j < 10; ++j) { extractedSelector[j] = part[j]; } bytes4 selector = bytes4(vm.parseBytes(string(extractedSelector))); @@ -75,7 +78,8 @@ library Utils { // Remove `getName()` selector if existing bool hasGetName = false; - for (uint256 i = 0; i < selectors.length; i++) { + uint256 selectorsLength = selectors.length; + for (uint256 i = 0; i < selectorsLength; ++i) { if (selectors[i] == bytes4(keccak256("getName()"))) { selectors[i] = selectors[selectors.length - 1]; hasGetName = true; @@ -83,8 +87,8 @@ library Utils { } } if (hasGetName) { - bytes4[] memory newSelectors = new bytes4[](selectors.length - 1); - for (uint256 i = 0; i < selectors.length - 1; i++) { + bytes4[] memory newSelectors = new bytes4[](selectorsLength - 1); + for (uint256 i = 0; i < selectorsLength - 1; ++i) { newSelectors[i] = selectors[i]; } return newSelectors; @@ -107,10 +111,11 @@ library Utils { */ function bytesToUint256(bytes memory bys) internal pure returns (uint256 value) { // Add left padding to 32 bytes if needed - if (bys.length < 32) { + uint256 bysLength = bys.length; + if (bysLength < 32) { bytes memory padded = new bytes(32); - for (uint256 i = 0; i < bys.length; i++) { - padded[i + 32 - bys.length] = bys[i]; + for (uint256 i = 0; i < bysLength; ++i) { + padded[i + 32 - bysLength] = bys[i]; } bys = padded; } @@ -213,12 +218,14 @@ library Utils { keccak256(constructorargs) ); - bytes[] memory _factoryDeps = new bytes[](factoryDeps.length + 1); + uint256 factoryDepsLength = factoryDeps.length; + + bytes[] memory _factoryDeps = new bytes[](factoryDepsLength + 1); - for (uint256 i = 0; i < factoryDeps.length; i++) { + for (uint256 i = 0; i < factoryDepsLength; ++i) { _factoryDeps[i] = factoryDeps[i]; } - _factoryDeps[factoryDeps.length] = bytecode; + _factoryDeps[factoryDepsLength] = bytecode; runL1L2Transaction({ l2Calldata: deployData, @@ -298,6 +305,17 @@ library Utils { }); } + /** + * @dev Read foundry bytecodes + */ + function readFoundryBytecode(string memory artifactPath) internal view returns (bytes memory) { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, artifactPath); + string memory json = vm.readFile(path); + bytes memory bytecode = vm.parseJsonBytes(json, ".bytecode.object"); + return bytecode; + } + /** * @dev Read hardhat bytecodes */ diff --git a/l1-contracts/deploy-scripts/ZkSyncScriptErrors.sol b/l1-contracts/deploy-scripts/ZkSyncScriptErrors.sol new file mode 100644 index 000000000..76295d633 --- /dev/null +++ b/l1-contracts/deploy-scripts/ZkSyncScriptErrors.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +error FailedToDeploy(ZksyncContract); +error BytecodeNotSet(); +error FailedToDeployViaCreate2(); +error MissingAddress(ZksyncContract); +error AddressHasNoCode(address); +error MintFailed(); + +enum ZksyncContract { + Create2Factory, + DiamondProxy, + BaseToken +} diff --git a/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol b/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol index e178824b1..518005915 100644 --- a/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol +++ b/l1-contracts/deploy-scripts/dev/SetupLegacyBridge.s.sol @@ -6,8 +6,8 @@ import {stdToml} from "forge-std/StdToml.sol"; import {Utils} from "./../Utils.sol"; import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; import {DummyL1ERC20Bridge} from "contracts/dev-contracts/DummyL1ERC20Bridge.sol"; -import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; +import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {L2ContractHelper} from "contracts/common/libraries/L2ContractHelper.sol"; /// This scripts is only for developer @@ -112,8 +112,8 @@ contract SetupLegacyBridge is Script { internal returns (address tokenBeaconAddress, bytes32 tokenBeaconBytecodeHash) { - bytes memory l2StandardTokenCode = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/contracts/bridge/L2StandardERC20.sol/L2StandardERC20.json" + bytes memory l2StandardTokenCode = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/L2StandardERC20.sol/L2StandardERC20.json" ); (address l2StandardToken, ) = calculateL2Create2Address( config.l2SharedBridgeAddress, @@ -122,13 +122,11 @@ contract SetupLegacyBridge is Script { "" ); - bytes memory beaconProxy = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.json" - ); + bytes memory beaconProxy = Utils.readFoundryBytecode("/../l2-contracts/zkout/BeaconProxy.sol/BeaconProxy.json"); tokenBeaconBytecodeHash = L2ContractHelper.hashL2Bytecode(beaconProxy); - bytes memory upgradableBeacon = Utils.readHardhatBytecode( - "/../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json" + bytes memory upgradableBeacon = Utils.readFoundryBytecode( + "/../l2-contracts/zkout/UpgradeableBeacon.sol/UpgradeableBeacon.json" ); (tokenBeaconAddress, ) = calculateL2Create2Address( diff --git a/l1-contracts/foundry.toml b/l1-contracts/foundry.toml index 82910dad0..57dd0744a 100644 --- a/l1-contracts/foundry.toml +++ b/l1-contracts/foundry.toml @@ -1,24 +1,30 @@ [profile.default] -src = 'contracts' -out = 'out' -libs = ['node_modules', 'lib'] -remappings = [ - "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", - "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", - "l2-contracts/=../l2-contracts/contracts/" -] +src = "contracts" +out = "out" +libs = ["lib"] +cache_path = "cache-forge" +test = "test/foundry" +solc_version = "0.8.24" +evm_version = "cancun" allow_paths = ["../l2-contracts/contracts"] fs_permissions = [ { access = "read", path = "../system-contracts/bootloader/build/artifacts" }, { access = "read", path = "../system-contracts/artifacts-zk/contracts-preprocessed" }, { access = "read", path = "../l2-contracts/artifacts-zk/" }, + { access = "read", path = "../l2-contracts/zkout/" }, + { access = "read", path = "../system-contracts/zkout/" }, { access = "read", path = "./script-config" }, { access = "read-write", path = "./script-out" }, { access = "read", path = "./out" } ] -cache_path = 'cache-forge' -test = 'test/foundry' -solc_version = "0.8.24" -evm_version = "cancun" - -# See more config options https://github.com/foundry-rs/foundry/tree/master/crates/config +ignored_error_codes = ["missing-receive-ether", "code-size"] +ignored_warnings_from = ["test", "contracts/dev-contracts"] +remappings = [ + "forge-std/=lib/forge-std/src/", + "murky/=lib/murky/src/", + "foundry-test/=test/foundry/", + "@openzeppelin/contracts-v4/=lib/openzeppelin-contracts-v4/contracts/", + "@openzeppelin/contracts-upgradeable-v4/=lib/openzeppelin-contracts-upgradeable-v4/contracts/", +] +optimizer = true +optimizer_runs = 9999999 diff --git a/l1-contracts/lib/forge-std b/l1-contracts/lib/forge-std deleted file mode 160000 index 52715a217..000000000 --- a/l1-contracts/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 52715a217dc51d0de15877878ab8213f6cbbbab5 diff --git a/l1-contracts/lib/forge-std b/l1-contracts/lib/forge-std new file mode 120000 index 000000000..edce15694 --- /dev/null +++ b/l1-contracts/lib/forge-std @@ -0,0 +1 @@ +../../lib/forge-std \ No newline at end of file diff --git a/l1-contracts/lib/murky b/l1-contracts/lib/murky deleted file mode 160000 index 5feccd125..000000000 --- a/l1-contracts/lib/murky +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5feccd1253d7da820f7cccccdedf64471025455d diff --git a/l1-contracts/lib/murky b/l1-contracts/lib/murky new file mode 120000 index 000000000..a556a15e5 --- /dev/null +++ b/l1-contracts/lib/murky @@ -0,0 +1 @@ +../../lib/murky \ No newline at end of file diff --git a/l1-contracts/lib/openzeppelin-contracts-upgradeable-v4 b/l1-contracts/lib/openzeppelin-contracts-upgradeable-v4 new file mode 120000 index 000000000..0551b6016 --- /dev/null +++ b/l1-contracts/lib/openzeppelin-contracts-upgradeable-v4 @@ -0,0 +1 @@ +../../lib/openzeppelin-contracts-upgradeable-v4 \ No newline at end of file diff --git a/l1-contracts/lib/openzeppelin-contracts-v4 b/l1-contracts/lib/openzeppelin-contracts-v4 new file mode 120000 index 000000000..693e94537 --- /dev/null +++ b/l1-contracts/lib/openzeppelin-contracts-v4 @@ -0,0 +1 @@ +../../lib/openzeppelin-contracts-v4 \ No newline at end of file diff --git a/l1-contracts/package.json b/l1-contracts/package.json index de33649f8..aaceec20c 100644 --- a/l1-contracts/package.json +++ b/l1-contracts/package.json @@ -9,8 +9,8 @@ "@nomiclabs/hardhat-ethers": "^2.0.0", "@nomiclabs/hardhat-etherscan": "^3.1.0", "@nomiclabs/hardhat-waffle": "^2.0.0", - "@openzeppelin/contracts": "4.9.5", - "@openzeppelin/contracts-upgradeable": "4.9.5", + "@openzeppelin/contracts-upgradeable-v4": "npm:@openzeppelin/contracts-upgradeable@4.9.5", + "@openzeppelin/contracts-v4": "npm:@openzeppelin/contracts@4.9.5", "@typechain/ethers-v5": "^2.0.0", "@types/argparse": "^1.0.36", "@types/chai": "^4.2.21", diff --git a/l1-contracts/remappings.txt b/l1-contracts/remappings.txt deleted file mode 100644 index d866a0c22..000000000 --- a/l1-contracts/remappings.txt +++ /dev/null @@ -1,7 +0,0 @@ -@ensdomains/=node_modules/@ensdomains/ -ds-test/=lib/forge-std/lib/ds-test/src/ -eth-gas-reporter/=node_modules/eth-gas-reporter/ -forge-std/=lib/forge-std/src/ -hardhat/=node_modules/hardhat/ -murky/=lib/murky/src/ -foundry-test/=test/foundry/ diff --git a/l1-contracts/script-config/.gitkeep b/l1-contracts/script-config/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/l1-contracts/scripts/display-governance.ts b/l1-contracts/scripts/display-governance.ts index d6b4846f1..0593d580e 100644 --- a/l1-contracts/scripts/display-governance.ts +++ b/l1-contracts/scripts/display-governance.ts @@ -10,7 +10,7 @@ import { applyL1ToL2Alias, getAddressFromEnv } from "../src.ts/utils"; import * as fs from "fs"; import { UpgradeableBeaconFactory } from "../../l2-contracts/typechain/UpgradeableBeaconFactory"; -import { Provider } from "zksync-web3"; +import { Provider } from "zksync-ethers"; const l2SharedBridgeABI = JSON.parse( fs.readFileSync("../zksync/artifacts-zk/contracts/bridge/L2SharedBridge.sol/L2SharedBridge.json").toString() diff --git a/l1-contracts/scripts/initialize-l2-weth-token.ts b/l1-contracts/scripts/initialize-l2-weth-token.ts index f38b1f8f8..4bf9dd933 100644 --- a/l1-contracts/scripts/initialize-l2-weth-token.ts +++ b/l1-contracts/scripts/initialize-l2-weth-token.ts @@ -20,7 +20,7 @@ const contractArtifactsPath = path.join(process.env.ZKSYNC_HOME as string, "cont const l2BridgeArtifactsPath = path.join(contractArtifactsPath, "contracts/bridge/"); const openzeppelinTransparentProxyArtifactsPath = path.join( contractArtifactsPath, - "@openzeppelin/contracts/proxy/transparent/" + "@openzeppelin/contracts-v4/proxy/transparent/" ); function readInterface(path: string, fileName: string, solFileName?: string) { @@ -34,7 +34,7 @@ const L2_WETH_INTERFACE = readInterface(l2BridgeArtifactsPath, "L2WrappedBaseTok const TRANSPARENT_UPGRADEABLE_PROXY = readInterface( openzeppelinTransparentProxyArtifactsPath, "ITransparentUpgradeableProxy", - "TransparentUpgradeableProxy" + "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy" ); function getL2Calldata(l2SharedBridgeAddress: string, l1WethTokenAddress: string, l2WethTokenImplAddress: string) { diff --git a/l1-contracts/scripts/register-hyperchain.ts b/l1-contracts/scripts/register-hyperchain.ts index cee5eac01..1c60ad58d 100644 --- a/l1-contracts/scripts/register-hyperchain.ts +++ b/l1-contracts/scripts/register-hyperchain.ts @@ -59,12 +59,9 @@ async function main() { program .option("--private-key ") - .option("--chain-id ") .option("--gas-price ") .option("--nonce ") .option("--governor-address ") - .option("--create2-salt ") - .option("--diamond-upgrade-init ") .option("--only-verifier") .option("--validium-mode") .option("--base-token-name ") diff --git a/l1-contracts/scripts/setup-legacy-bridge-era.ts b/l1-contracts/scripts/setup-legacy-bridge-era.ts index ffea4ef2d..deaf060fa 100644 --- a/l1-contracts/scripts/setup-legacy-bridge-era.ts +++ b/l1-contracts/scripts/setup-legacy-bridge-era.ts @@ -15,8 +15,8 @@ import { web3Provider, GAS_MULTIPLIER } from "./utils"; import { deployedAddressesFromEnv } from "../src.ts/deploy-utils"; import { ethTestConfig, getAddressFromEnv } from "../src.ts/utils"; import { hashL2Bytecode } from "../../l2-contracts/src/utils"; -import { Provider } from "zksync-web3"; -import beaconProxy = require("../../l2-contracts/artifacts-zk/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.json"); +import { Provider } from "zksync-ethers"; +import beaconProxy = require("../../l2-contracts/artifacts-zk/@openzeppelin/contracts-v4/proxy/beacon/BeaconProxy.sol/BeaconProxy.json"); const provider = web3Provider(); @@ -64,7 +64,9 @@ async function main() { await deployer.deploySharedBridgeImplementation(create2Salt, { nonce }); - const proxyAdminInterface = new Interface(hardhat.artifacts.readArtifactSync("ProxyAdmin").abi); + const proxyAdminInterface = new Interface( + hardhat.artifacts.readArtifactSync("@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol:ProxyAdmin").abi + ); let calldata = proxyAdminInterface.encodeFunctionData("upgrade(address,address)", [ deployer.addresses.Bridges.SharedBridgeProxy, deployer.addresses.Bridges.SharedBridgeImplementation, diff --git a/l1-contracts/scripts/upgrade-consistency-checker.ts b/l1-contracts/scripts/upgrade-consistency-checker.ts index 5da064a04..530d47dc3 100644 --- a/l1-contracts/scripts/upgrade-consistency-checker.ts +++ b/l1-contracts/scripts/upgrade-consistency-checker.ts @@ -112,7 +112,9 @@ async function extractInitCode(data: string) { async function extractProxyInitializationData(contract: ethers.Contract, data: string) { const initCode = await extractInitCode(data); - const artifact = await hardhat.artifacts.readArtifact("TransparentUpgradeableProxy"); + const artifact = await hardhat.artifacts.readArtifact( + "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy" + ); // Deployment tx is a concatenation of the init code and the constructor data // constructor has the following type `constructor(address _logic, address admin_, bytes memory _data)` @@ -449,9 +451,11 @@ async function checkLegacyBridge() { } async function checkProxyAdmin() { - await checkIdenticalBytecode(proxyAdmin, "ProxyAdmin"); + await checkIdenticalBytecode(proxyAdmin, "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol:ProxyAdmin"); - const artifact = await hardhat.artifacts.readArtifact("ProxyAdmin"); + const artifact = await hardhat.artifacts.readArtifact( + "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol:ProxyAdmin" + ); const contract = new ethers.Contract(proxyAdmin, artifact.abi, l1Provider); const currentOwner = await contract.owner(); diff --git a/l1-contracts/src.ts/deploy-process.ts b/l1-contracts/src.ts/deploy-process.ts index 28629fc11..d30762a15 100644 --- a/l1-contracts/src.ts/deploy-process.ts +++ b/l1-contracts/src.ts/deploy-process.ts @@ -96,6 +96,7 @@ export async function registerHyperchain( validiumMode, extraFacets, gasPrice, + false, null, chainId, useGovernance diff --git a/l1-contracts/src.ts/deploy.ts b/l1-contracts/src.ts/deploy.ts index 52ae1d086..3ee3bb07b 100644 --- a/l1-contracts/src.ts/deploy.ts +++ b/l1-contracts/src.ts/deploy.ts @@ -34,10 +34,11 @@ import { L1SharedBridgeFactory } from "../typechain/L1SharedBridgeFactory"; import { SingletonFactoryFactory } from "../typechain/SingletonFactoryFactory"; import { ValidatorTimelockFactory } from "../typechain/ValidatorTimelockFactory"; + import type { FacetCut } from "./diamondCut"; import { getCurrentFacetCutsForAdd } from "./diamondCut"; -import { ChainAdminFactory, ERC20Factory } from "../typechain"; +import { ChainAdminFactory, ERC20Factory, StateTransitionManagerFactory } from "../typechain"; import type { Contract, Overrides } from "@ethersproject/contracts"; let L2_BOOTLOADER_BYTECODE_HASH: string; @@ -81,7 +82,7 @@ export class Deployer { this.chainId = parseInt(process.env.CHAIN_ETH_ZKSYNC_NETWORK_ID!); } - public async initialZkSyncHyperchainDiamondCut(extraFacets?: FacetCut[]) { + public async initialZkSyncHyperchainDiamondCut(extraFacets?: FacetCut[], compareDiamondCutHash: boolean = false) { let facetCuts: FacetCut[] = Object.values( await getCurrentFacetCutsForAdd( this.addresses.StateTransition.AdminFacet, @@ -99,7 +100,7 @@ export class Deployer { }; const priorityTxMaxGasLimit = getNumberFromEnv("CONTRACTS_PRIORITY_TX_MAX_GAS_LIMIT"); - return compileInitialCutHash( + const diamondCut = compileInitialCutHash( facetCuts, verifierParams, L2_BOOTLOADER_BYTECODE_HASH, @@ -110,6 +111,25 @@ export class Deployer { this.addresses.StateTransition.DiamondInit, false ); + + if (compareDiamondCutHash) { + const hash = ethers.utils.keccak256( + ethers.utils.defaultAbiCoder.encode([DIAMOND_CUT_DATA_ABI_STRING], [diamondCut]) + ); + + console.log(`Diamond cut hash: ${hash}`); + const stm = StateTransitionManagerFactory.connect( + this.addresses.StateTransition.StateTransitionProxy, + this.deployWallet + ); + + const hashFromSTM = await stm.initialCutHash(); + if (hash != hashFromSTM) { + throw new Error(`Has from STM ${hashFromSTM} does not match the computed hash ${hash}`); + } + } + + return diamondCut; } public async deployCreate2Factory(ethTxOptions?: ethers.providers.TransactionRequest) { @@ -221,9 +241,12 @@ export class Deployer { console.log("Deploying Proxy Admin"); } // Note: we cannot deploy using Create2, as the owner of the ProxyAdmin is msg.sender - const contractFactory = await hardhat.ethers.getContractFactory("ProxyAdmin", { - signer: this.deployWallet, - }); + const contractFactory = await hardhat.ethers.getContractFactory( + "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol:ProxyAdmin", + { + signer: this.deployWallet, + } + ); const proxyAdmin = await contractFactory.deploy(...[ethTxOptions]); const rec = await proxyAdmin.deployTransaction.wait(); @@ -259,7 +282,7 @@ export class Deployer { const initCalldata = bridgehub.encodeFunctionData("initialize", [this.ownerAddress]); const contractAddress = await this.deployViaCreate2( - "TransparentUpgradeableProxy", + "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy", [this.addresses.Bridgehub.BridgehubImplementation, this.addresses.TransparentProxyAdmin, initCalldata], create2Salt, ethTxOptions @@ -323,7 +346,7 @@ export class Deployer { ]); const contractAddress = await this.deployViaCreate2( - "TransparentUpgradeableProxy", + "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy", [ this.addresses.StateTransition.StateTransitionImplementation, this.addresses.TransparentProxyAdmin, @@ -519,7 +542,7 @@ export class Deployer { "initialize" ); const contractAddress = await this.deployViaCreate2( - "TransparentUpgradeableProxy", + "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy", [this.addresses.Bridges.ERC20BridgeImplementation, this.addresses.TransparentProxyAdmin, initCalldata], create2Salt, ethTxOptions @@ -562,7 +585,7 @@ export class Deployer { [this.addresses.Governance] ); const contractAddress = await this.deployViaCreate2( - "TransparentUpgradeableProxy", + "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy", [this.addresses.Bridges.SharedBridgeImplementation, this.addresses.TransparentProxyAdmin, initCalldata], create2Salt, ethTxOptions @@ -699,6 +722,7 @@ export class Deployer { validiumMode: boolean, extraFacets?: FacetCut[], gasPrice?: BigNumberish, + compareDiamondCutHash: boolean = false, nonce?, predefinedChainId?: string, useGovernance: boolean = false @@ -712,7 +736,7 @@ export class Deployer { const inputChainId = predefinedChainId || getNumberFromEnv("CHAIN_ETH_ZKSYNC_NETWORK_ID"); const admin = process.env.CHAIN_ADMIN_ADDRESS || this.ownerAddress; - const diamondCutData = await this.initialZkSyncHyperchainDiamondCut(extraFacets); + const diamondCutData = await this.initialZkSyncHyperchainDiamondCut(extraFacets, compareDiamondCutHash); const initialDiamondCut = new ethers.utils.AbiCoder().encode([DIAMOND_CUT_DATA_ABI_STRING], [diamondCutData]); const receipt = await this.executeDirectOrGovernance( @@ -765,7 +789,8 @@ export class Deployer { console.log(`CONTRACTS_DIAMOND_PROXY_ADDR=${diamondProxyAddress}`); } } - this.chainId = parseInt(chainId, 16); + const intChainId = parseInt(chainId, 16); + this.chainId = intChainId; const validatorOneAddress = getAddressFromEnv("ETH_SENDER_SENDER_OPERATOR_COMMIT_ETH_ADDR"); const validatorTwoAddress = getAddressFromEnv("ETH_SENDER_SENDER_OPERATOR_BLOBS_ETH_ADDR"); @@ -797,18 +822,25 @@ export class Deployer { } const diamondProxy = this.stateTransitionContract(this.deployWallet); - const tx4 = await diamondProxy.setTokenMultiplier(1, 1); - const receipt4 = await tx4.wait(); - if (this.verbose) { - console.log(`BaseTokenMultiplier set, gas used: ${receipt4.gasUsed.toString()}`); - } - - if (validiumMode) { - const tx5 = await diamondProxy.setPubdataPricingMode(PubdataPricingMode.Validium); - const receipt5 = await tx5.wait(); + // if we are using governance, the deployer will not be the admin, so we can't call the diamond proxy directly + if (admin == this.deployWallet.address) { + const tx4 = await diamondProxy.setTokenMultiplier(1, 1); + const receipt4 = await tx4.wait(); if (this.verbose) { - console.log(`Validium mode set, gas used: ${receipt5.gasUsed.toString()}`); + console.log(`BaseTokenMultiplier set, gas used: ${receipt4.gasUsed.toString()}`); + } + + if (validiumMode) { + const tx5 = await diamondProxy.setPubdataPricingMode(PubdataPricingMode.Validium); + const receipt5 = await tx5.wait(); + if (this.verbose) { + console.log(`Validium mode set, gas used: ${receipt5.gasUsed.toString()}`); + } } + } else { + console.warn( + "BaseTokenMultiplier and Validium mode can't be set through the governance, please set it separately, using the admin account" + ); } } diff --git a/l1-contracts/src.ts/diamondCut.ts b/l1-contracts/src.ts/diamondCut.ts index f9eaadf0e..c2a8e8728 100644 --- a/l1-contracts/src.ts/diamondCut.ts +++ b/l1-contracts/src.ts/diamondCut.ts @@ -6,9 +6,6 @@ import { ethers } from "ethers"; import { IZkSyncHyperchainFactory } from "../typechain/IZkSyncHyperchainFactory"; import { IZkSyncHyperchainBaseFactory } from "../typechain/IZkSyncHyperchainBaseFactory"; -// Some of the facets are to be removed with the upcoming upgrade. -const UNCONDITIONALLY_REMOVED_FACETS = ["DiamondCutFacet", "GovernanceFacet"]; - export enum Action { Add = 0, Replace = 1, @@ -131,10 +128,7 @@ export async function getFacetCutsForUpgrade( namesOfFacetsToBeRemoved?: string[] ) { const newFacetCuts = await getCurrentFacetCutsForAdd(adminAddress, gettersAddress, mailboxAddress, executorAddress); - namesOfFacetsToBeRemoved = namesOfFacetsToBeRemoved || [ - ...UNCONDITIONALLY_REMOVED_FACETS, - ...Object.keys(newFacetCuts), - ]; + namesOfFacetsToBeRemoved = namesOfFacetsToBeRemoved || [...Object.keys(newFacetCuts)]; const oldFacetCuts = await getDeployedFacetCutsForRemove(wallet, zkSyncAddress, namesOfFacetsToBeRemoved); return [...oldFacetCuts, ...Object.values(newFacetCuts)]; } diff --git a/l1-contracts/test/foundry/integration/deploy-scripts/script-out/output-deploy-l1.toml b/l1-contracts/test/foundry/integration/deploy-scripts/script-out/output-deploy-l1.toml new file mode 100644 index 000000000..fa3301825 --- /dev/null +++ b/l1-contracts/test/foundry/integration/deploy-scripts/script-out/output-deploy-l1.toml @@ -0,0 +1,54 @@ +create2_factory_salt = "0x00000000000000000000000000000000000000000000000000000000000000ff" +deployer_addr = "0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496" +era_chain_id = 9 +l1_chain_id = 31337 +multicall3_addr = "0x9735C424DEa176DC4304D1A240C824783D841f20" +owner_address = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" + +[contracts_config] +diamond_cut_data = "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000600000000000000000000000009a5d498f9fdab5d26090b68aec33363ac3706c5e0000000000000000000000000000000000000000000000000000000000000de00000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000009c00000000000000000000000000000000000000000000000000000000000000bc0000000000000000000000000c49e34de76847b6ce4933cae561d6ae7c72b1c2500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000140e18b681000000000000000000000000000000000000000000000000000000001733894500000000000000000000000000000000000000000000000000000000fc57565f000000000000000000000000000000000000000000000000000000001cc5d1030000000000000000000000000000000000000000000000000000000021f603d700000000000000000000000000000000000000000000000000000000235d9eb50000000000000000000000000000000000000000000000000000000027ae4c160000000000000000000000000000000000000000000000000000000043dc2951000000000000000000000000000000000000000000000000000000004623c91d000000000000000000000000000000000000000000000000000000004dd18bf5000000000000000000000000000000000000000000000000000000006223258e0000000000000000000000000000000000000000000000000000000064b554ad0000000000000000000000000000000000000000000000000000000064bf8d660000000000000000000000000000000000000000000000000000000082b57749000000000000000000000000000000000000000000000000000000008c564cc100000000000000000000000000000000000000000000000000000000a37dc1d400000000000000000000000000000000000000000000000000000000a3bd011200000000000000000000000000000000000000000000000000000000a9f6d94100000000000000000000000000000000000000000000000000000000be6f11cf00000000000000000000000000000000000000000000000000000000e76db86500000000000000000000000000000000000000000000000000000000000000000000000000000000ab0aa7c14904459f4bcde7f3b465546f022ec22a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000002c06d49e5b00000000000000000000000000000000000000000000000000000000086a56f8000000000000000000000000000000000000000000000000000000000ec6b0b700000000000000000000000000000000000000000000000000000000fe26699e0000000000000000000000000000000000000000000000000000000018e3a941000000000000000000000000000000000000000000000000000000001de72e340000000000000000000000000000000000000000000000000000000029b98c670000000000000000000000000000000000000000000000000000000033ce93fe000000000000000000000000000000000000000000000000000000003408e470000000000000000000000000000000000000000000000000000000003591c1a000000000000000000000000000000000000000000000000000000000396073820000000000000000000000000000000000000000000000000000000039d7d4aa0000000000000000000000000000000000000000000000000000000046657fe90000000000000000000000000000000000000000000000000000000052ef6b2c000000000000000000000000000000000000000000000000000000005518c73b0000000000000000000000000000000000000000000000000000000056142d7a00000000000000000000000000000000000000000000000000000000631f4bac000000000000000000000000000000000000000000000000000000006e9960c30000000000000000000000000000000000000000000000000000000074f4d30d0000000000000000000000000000000000000000000000000000000079823c9a000000000000000000000000000000000000000000000000000000007a0ed627000000000000000000000000000000000000000000000000000000007b30c8da0000000000000000000000000000000000000000000000000000000098acd7a6000000000000000000000000000000000000000000000000000000009cd939e4000000000000000000000000000000000000000000000000000000009d1b5a8100000000000000000000000000000000000000000000000000000000a1954fc500000000000000000000000000000000000000000000000000000000a7358efb00000000000000000000000000000000000000000000000000000000adfca15e00000000000000000000000000000000000000000000000000000000af6a2dcd00000000000000000000000000000000000000000000000000000000b22dd78e00000000000000000000000000000000000000000000000000000000b8c2f66f00000000000000000000000000000000000000000000000000000000bd7c541200000000000000000000000000000000000000000000000000000000c3bbd2d700000000000000000000000000000000000000000000000000000000cdffacc600000000000000000000000000000000000000000000000000000000d046815600000000000000000000000000000000000000000000000000000000d86970d800000000000000000000000000000000000000000000000000000000db1f0bf900000000000000000000000000000000000000000000000000000000e5355c7500000000000000000000000000000000000000000000000000000000e81e0ba100000000000000000000000000000000000000000000000000000000ea6c029c00000000000000000000000000000000000000000000000000000000ef3f0bae00000000000000000000000000000000000000000000000000000000f5c1182c00000000000000000000000000000000000000000000000000000000facd743b00000000000000000000000000000000000000000000000000000000fd791f3c0000000000000000000000000000000000000000000000000000000000000000000000000000000066825543c5c82b711de855426946f6929573cf55000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000b042901c70000000000000000000000000000000000000000000000000000000008522c300000000000000000000000000000000000000000000000000000000012f43dab00000000000000000000000000000000000000000000000000000000eb67241900000000000000000000000000000000000000000000000000000000263b7f8e000000000000000000000000000000000000000000000000000000006c0960f9000000000000000000000000000000000000000000000000000000007efda2ae00000000000000000000000000000000000000000000000000000000b473318e00000000000000000000000000000000000000000000000000000000d06b26e200000000000000000000000000000000000000000000000000000000dcabb98200000000000000000000000000000000000000000000000000000000e4948f430000000000000000000000000000000000000000000000000000000000000000000000000000000049c0372a531af3cf3fe715c1918c278c07affce5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000800a22e22000000000000000000000000000000000000000000000000000000000f23da4300000000000000000000000000000000000000000000000000000000c37533bb000000000000000000000000000000000000000000000000000000006edd4f1200000000000000000000000000000000000000000000000000000000701f58c5000000000000000000000000000000000000000000000000000000007f61885c0000000000000000000000000000000000000000000000000000000097c09d3400000000000000000000000000000000000000000000000000000000bd6db4990000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000032c101edc4d322abd5da779f1a5376e412e21160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c4b400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f4240000000000000000000000000000000000000000000000000000000000001d4c00000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000182b8000000000000000000000000000000000000000000000000000000000ee6b280000000000000000000000000a4cb26d6933d2c3e76718d30de8547bcdf8dd241" +diamond_init_batch_overhead_l1_gas = 1000000 +diamond_init_max_l2_gas_per_batch = 80000000 +diamond_init_max_pubdata_per_batch = 120000 +diamond_init_minimal_l2_gas_price = 250000000 +diamond_init_priority_tx_max_pubdata = 99000 +diamond_init_pubdata_pricing_mode = 0 +force_deployments_data = "0x00" +priority_tx_max_gas_limit = 80000000 +recursion_circuits_set_vks_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +recursion_leaf_level_vk_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" +recursion_node_level_vk_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" + +[deployed_addresses] +blob_versioned_hash_retriever_addr = "0xA4cB26d6933D2c3E76718D30de8547bCDF8dD241" +governance_addr = "0x6ba327EAE385c52A861b1cacAc60021F03489413" +native_token_vault_addr = "0x153e4040C649Fe562cAa0A71Fd79f79BCA2593aB" +transparent_proxy_admin_addr = "0xDEb1E9a6Be7Baf84208BB6E10aC9F9bbE1D70809" +validator_timelock_addr = "0xDb50CefBF1F40e85951dAbd0194c477D6270Fe5E" + +[deployed_addresses.bridgehub] +bridgehub_implementation_addr = "0xa53970305e11ac9eD420Ec7C7AABb59fC3a64B0e" +bridgehub_proxy_addr = "0xC6585692481e509DDD11Eb2033535c6FF6e89B99" +message_root_implementation_addr = "0x67c321b17102Cbd39068B8bAeC3fF925FEc76C46" +message_root_proxy_addr = "0x88001933Ff48C53181cf1b11935AC2126954cb9e" +stm_deployment_tracker_implementation_addr = "0x205CEF369839dF59C016b02e4ECb45fB706576d0" +stm_deployment_tracker_proxy_addr = "0x8D9731582480f2CB74BC93168D86fB26788986b2" + +[deployed_addresses.bridges] +erc20_bridge_implementation_addr = "0xD23dF92Df88AF35d9f804BCd576B12C212A8BbD9" +erc20_bridge_proxy_addr = "0x6DDEFe6C5B5068347E278D5Be9B2a8a81c9C4F23" +shared_bridge_implementation_addr = "0xA66087143CEBcd6859aEd08420B1228De567Cd88" +shared_bridge_proxy_addr = "0x1e1314a32AaE641325b6BEfC625f499f1d7c7B2a" + +[deployed_addresses.state_transition] +admin_facet_addr = "0xC49E34dE76847b6Ce4933caE561d6aE7C72B1c25" +default_upgrade_addr = "0x7C0213Ecf479fE20b03B9e0d5a62B6D1602fe9a5" +diamond_init_addr = "0x9a5D498f9FdAB5D26090B68AEc33363ac3706C5e" +diamond_proxy_addr = "0x0000000000000000000000000000000000000000" +executor_facet_addr = "0x49C0372A531aF3cF3Fe715c1918c278c07aFfCe5" +genesis_upgrade_addr = "0xAFAb4F3F4B7984A3A93A5eC3B1028aC6e7194602" +getters_facet_addr = "0xab0AA7c14904459F4bCDe7f3B465546f022ec22A" +mailbox_facet_addr = "0x66825543c5c82b711de855426946f6929573cF55" +state_transition_implementation_addr = "0x2051075b03d1F2E0902C9cFd349fbdD4c73bB2d4" +state_transition_proxy_addr = "0x236e89885449f7ef4650743Ba350Fd557060905E" +verifier_addr = "0x32C101EDC4D322AbD5da779f1A5376e412E21160" diff --git a/l1-contracts/test/foundry/unit/concrete/Bridgehub/Initialize.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridgehub/Initialize.t.sol index 38bba5ec2..a31095dea 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridgehub/Initialize.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridgehub/Initialize.t.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; +pragma solidity ^0.8.21; import {BridgehubTest} from "./_Bridgehub_Shared.t.sol"; diff --git a/l1-contracts/test/foundry/unit/concrete/Bridgehub/_Bridgehub_Shared.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridgehub/_Bridgehub_Shared.t.sol index 3d0b445a5..54d264daa 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridgehub/_Bridgehub_Shared.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridgehub/_Bridgehub_Shared.t.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; +pragma solidity ^0.8.21; import {Test} from "forge-std/Test.sol"; diff --git a/l1-contracts/test/foundry/unit/concrete/Bridgehub/experimental_bridge.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridgehub/experimental_bridge.t.sol index ff747ddac..43826e6ac 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridgehub/experimental_bridge.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridgehub/experimental_bridge.t.sol @@ -1,4 +1,4 @@ -//SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT pragma solidity 0.8.24; @@ -11,11 +11,13 @@ import {ChainCreationParams} from "contracts/state-transition/IStateTransitionMa import {L2TransactionRequestDirect, L2TransactionRequestTwoBridgesOuter} from "contracts/bridgehub/IBridgehub.sol"; import {DummyStateTransitionManagerWBH} from "contracts/dev-contracts/test/DummyStateTransitionManagerWithBridgeHubAddress.sol"; import {DummyHyperchain} from "contracts/dev-contracts/test/DummyHyperchain.sol"; -import {DummySharedBridge} from "contracts/dev-contracts/test/DummySharedBridge.sol"; import {IL1SharedBridge} from "contracts/bridge/interfaces/IL1SharedBridge.sol"; - +import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; +import {L2TransactionRequestTwoBridgesInner} from "contracts/bridgehub/IBridgehub.sol"; import {L2Message, L2Log, TxStatus, BridgehubL2TransactionRequest} from "contracts/common/Messaging.sol"; -import {ETH_TOKEN_ADDRESS, REQUIRED_L2_GAS_PRICE_PER_PUBDATA, MAX_NEW_FACTORY_DEPS} from "contracts/common/Config.sol"; +import {ETH_TOKEN_ADDRESS, REQUIRED_L2_GAS_PRICE_PER_PUBDATA, MAX_NEW_FACTORY_DEPS, TWO_BRIDGES_MAGIC_VALUE} from "contracts/common/Config.sol"; +import {L1ERC20Bridge} from "contracts/bridge/L1ERC20Bridge.sol"; +import {ZeroChainId, AddressTooLow, ChainIdTooBig, WrongMagicValue, SharedBridgeNotSet, TokenNotRegistered, BridgeHubAlreadyRegistered, MsgValueMismatch, SlotOccupied, STMAlreadyRegistered, TokenAlreadyRegistered, Unauthorized, NonEmptyMsgValue, STMNotRegistered, InvalidChainId} from "contracts/common/L1ContractErrors.sol"; contract ExperimentalBridgeTest is Test { using stdStorage for StdStorage; @@ -24,27 +26,76 @@ contract ExperimentalBridgeTest is Test { address public bridgeOwner; DummyStateTransitionManagerWBH mockSTM; DummyHyperchain mockChainContract; - DummySharedBridge mockSharedBridge; - DummySharedBridge mockSecondSharedBridge; + L1SharedBridge sharedBridge; + address sharedBridgeAddress; + address secondBridgeAddress; + L1SharedBridge secondBridge; TestnetERC20Token testToken; + TestnetERC20Token testToken6; + TestnetERC20Token testToken8; + TestnetERC20Token testToken18; + + address mockL2Contract; uint256 eraChainId; + event NewChain(uint256 indexed chainId, address stateTransitionManager, address indexed chainGovernance); + + modifier useRandomToken(uint256 randomValue) { + _setRandomToken(randomValue); + + _; + } + + function _setRandomToken(uint256 randomValue) internal { + uint256 tokenIndex = randomValue % 3; + TestnetERC20Token token; + if (tokenIndex == 0) { + testToken = testToken18; + } else if (tokenIndex == 1) { + testToken = testToken6; + } else { + testToken = testToken8; + } + } + function setUp() public { eraChainId = 9; bridgeHub = new Bridgehub(); bridgeOwner = makeAddr("BRIDGE_OWNER"); mockSTM = new DummyStateTransitionManagerWBH(address(bridgeHub)); mockChainContract = new DummyHyperchain(address(bridgeHub), eraChainId); - mockSharedBridge = new DummySharedBridge(keccak256("0xabc")); - mockSecondSharedBridge = new DummySharedBridge(keccak256("0xdef")); - testToken = new TestnetERC20Token("ZKSTT", "ZkSync Test Token", 18); + mockL2Contract = makeAddr("mockL2Contract"); + + // mocks to use in bridges instead of using a dummy one + address mockL1WethAddress = makeAddr("Weth"); + address eraDiamondProxy = makeAddr("eraDiamondProxy"); + + sharedBridge = new L1SharedBridge(mockL1WethAddress, bridgeHub, eraChainId, eraDiamondProxy); + address defaultOwner = sharedBridge.owner(); + vm.prank(defaultOwner); + sharedBridge.transferOwnership(bridgeOwner); + vm.prank(bridgeOwner); + sharedBridge.acceptOwnership(); + + secondBridge = new L1SharedBridge(mockL1WethAddress, bridgeHub, eraChainId, eraDiamondProxy); + defaultOwner = secondBridge.owner(); + vm.prank(defaultOwner); + secondBridge.transferOwnership(bridgeOwner); + vm.prank(bridgeOwner); + secondBridge.acceptOwnership(); + + sharedBridgeAddress = address(sharedBridge); + secondBridgeAddress = address(secondBridge); + testToken18 = new TestnetERC20Token("ZKSTT", "ZkSync Test Token", 18); + 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 - address defaultOwner = bridgeHub.owner(); + defaultOwner = bridgeHub.owner(); // Now, the `reentrancyGuardInitializer` should prevent anyone from calling `initialize` since we have called the constructor of the contract - vm.expectRevert(bytes("1B")); + vm.expectRevert(SlotOccupied.selector); bridgeHub.initialize(bridgeOwner); vm.store( @@ -72,8 +123,44 @@ contract ExperimentalBridgeTest is Test { assertEq(bridgeHub.owner(), bridgeOwner); } + function test_newPendingAdminReplacesPrevious(address randomDeployer, address otherRandomDeployer) public { + vm.assume(randomDeployer != address(0)); + vm.assume(otherRandomDeployer != address(0)); + assertEq(address(0), bridgeHub.admin()); + vm.assume(randomDeployer != otherRandomDeployer); + + vm.prank(bridgeHub.owner()); + bridgeHub.setPendingAdmin(randomDeployer); + + vm.prank(bridgeHub.owner()); + bridgeHub.setPendingAdmin(otherRandomDeployer); + + vm.prank(otherRandomDeployer); + bridgeHub.acceptAdmin(); + + 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()); + vm.assume(randomDeployer != otherRandomDeployer); + + vm.prank(bridgeHub.owner()); + bridgeHub.setPendingAdmin(randomDeployer); + + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, otherRandomDeployer)); + vm.prank(otherRandomDeployer); + bridgeHub.acceptAdmin(); + + assertEq(address(0), bridgeHub.admin()); + } + function test_onlyOwnerCanSetDeployer(address randomDeployer) public { + vm.assume(randomDeployer != address(0)); assertEq(address(0), bridgeHub.admin()); + vm.prank(bridgeHub.owner()); bridgeHub.setPendingAdmin(randomDeployer); vm.prank(randomDeployer); @@ -85,7 +172,7 @@ contract ExperimentalBridgeTest is Test { function test_randomCallerCannotSetDeployer(address randomCaller, address randomDeployer) public { if (randomCaller != bridgeHub.owner() && randomCaller != bridgeHub.admin()) { vm.prank(randomCaller); - vm.expectRevert(bytes("Bridgehub: not owner or admin")); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomCaller)); bridgeHub.setPendingAdmin(randomDeployer); // The deployer shouldn't have changed. @@ -94,6 +181,7 @@ contract ExperimentalBridgeTest is Test { } function test_addStateTransitionManager(address randomAddressWithoutTheCorrectInterface) public { + vm.assume(randomAddressWithoutTheCorrectInterface != address(0)); bool isSTMRegistered = bridgeHub.stateTransitionManagerIsRegistered(randomAddressWithoutTheCorrectInterface); assertTrue(!isSTMRegistered); @@ -105,7 +193,7 @@ contract ExperimentalBridgeTest is Test { // An address that has already been registered, cannot be registered again (at least not before calling `removeStateTransitionManager`). vm.prank(bridgeOwner); - vm.expectRevert(bytes("Bridgehub: state transition already registered")); + vm.expectRevert(STMAlreadyRegistered.selector); bridgeHub.addStateTransitionManager(randomAddressWithoutTheCorrectInterface); isSTMRegistered = bridgeHub.stateTransitionManagerIsRegistered(randomAddressWithoutTheCorrectInterface); @@ -116,6 +204,7 @@ contract ExperimentalBridgeTest is Test { address randomCaller, address randomAddressWithoutTheCorrectInterface ) public { + vm.assume(randomAddressWithoutTheCorrectInterface != address(0)); bool isSTMRegistered = bridgeHub.stateTransitionManagerIsRegistered(randomAddressWithoutTheCorrectInterface); assertTrue(!isSTMRegistered); @@ -134,7 +223,7 @@ contract ExperimentalBridgeTest is Test { // An address that has already been registered, cannot be registered again (at least not before calling `removeStateTransitionManager`). vm.prank(bridgeOwner); - vm.expectRevert(bytes("Bridgehub: state transition already registered")); + vm.expectRevert(STMAlreadyRegistered.selector); bridgeHub.addStateTransitionManager(randomAddressWithoutTheCorrectInterface); // Definitely not by a random caller @@ -149,12 +238,13 @@ contract ExperimentalBridgeTest is Test { } function test_removeStateTransitionManager(address randomAddressWithoutTheCorrectInterface) public { + vm.assume(randomAddressWithoutTheCorrectInterface != address(0)); bool isSTMRegistered = bridgeHub.stateTransitionManagerIsRegistered(randomAddressWithoutTheCorrectInterface); assertTrue(!isSTMRegistered); // A non-existent STM cannot be removed vm.prank(bridgeOwner); - vm.expectRevert(bytes("Bridgehub: state transition not registered yet")); + vm.expectRevert(STMNotRegistered.selector); bridgeHub.removeStateTransitionManager(randomAddressWithoutTheCorrectInterface); // Let's first register our particular stateTransitionManager @@ -173,7 +263,7 @@ contract ExperimentalBridgeTest is Test { // An already removed STM cannot be removed again vm.prank(bridgeOwner); - vm.expectRevert(bytes("Bridgehub: state transition not registered yet")); + vm.expectRevert(STMNotRegistered.selector); bridgeHub.removeStateTransitionManager(randomAddressWithoutTheCorrectInterface); } @@ -181,6 +271,7 @@ contract ExperimentalBridgeTest is Test { address randomAddressWithoutTheCorrectInterface, address randomCaller ) public { + vm.assume(randomAddressWithoutTheCorrectInterface != address(0)); bool isSTMRegistered = bridgeHub.stateTransitionManagerIsRegistered(randomAddressWithoutTheCorrectInterface); assertTrue(!isSTMRegistered); @@ -193,7 +284,7 @@ contract ExperimentalBridgeTest is Test { // A non-existent STM cannot be removed vm.prank(bridgeOwner); - vm.expectRevert(bytes("Bridgehub: state transition not registered yet")); + vm.expectRevert(STMNotRegistered.selector); bridgeHub.removeStateTransitionManager(randomAddressWithoutTheCorrectInterface); // Let's first register our particular stateTransitionManager @@ -212,7 +303,7 @@ contract ExperimentalBridgeTest is Test { // An already removed STM cannot be removed again vm.prank(bridgeOwner); - vm.expectRevert(bytes("Bridgehub: state transition not registered yet")); + vm.expectRevert(STMNotRegistered.selector); bridgeHub.removeStateTransitionManager(randomAddressWithoutTheCorrectInterface); // Not possible by a randomcaller as well @@ -223,7 +314,7 @@ contract ExperimentalBridgeTest is Test { } } - function test_addToken(address, address randomAddress) public { + function test_addToken(address, address randomAddress, uint256 randomValue) public useRandomToken(randomValue) { assertTrue(!bridgeHub.tokenIsRegistered(randomAddress), "This random address is not registered as a token"); vm.prank(bridgeOwner); @@ -244,16 +335,16 @@ contract ExperimentalBridgeTest is Test { // An already registered token cannot be registered again vm.prank(bridgeOwner); - vm.expectRevert("Bridgehub: token already registered"); + vm.expectRevert(abi.encodeWithSelector(TokenAlreadyRegistered.selector, address(randomAddress))); bridgeHub.addToken(randomAddress); } function test_addToken_cannotBeCalledByRandomAddress(address randomAddress, address randomCaller) public { - vm.assume(randomAddress != bridgeOwner); - vm.assume(randomAddress != bridgeHub.admin()); + vm.assume(randomCaller != bridgeOwner); + vm.assume(randomCaller != bridgeHub.admin()); vm.prank(randomCaller); - vm.expectRevert(bytes("Bridgehub: not owner or admin")); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomCaller)); bridgeHub.addToken(randomAddress); assertTrue(!bridgeHub.tokenIsRegistered(randomAddress), "This random address is not registered as a token"); @@ -277,12 +368,13 @@ contract ExperimentalBridgeTest is Test { // An already registered token cannot be registered again by randomCaller if (randomCaller != bridgeOwner) { vm.prank(bridgeOwner); - vm.expectRevert("Bridgehub: token already registered"); + vm.expectRevert(abi.encodeWithSelector(TokenAlreadyRegistered.selector, address(randomAddress))); bridgeHub.addToken(randomAddress); } } function test_setSharedBridge(address randomAddress) public { + vm.assume(randomAddress != address(0)); assertTrue( bridgeHub.sharedBridge() == IL1SharedBridge(address(0)), "This random address is not registered as sharedBridge" @@ -298,6 +390,7 @@ contract ExperimentalBridgeTest is Test { } function test_setSharedBridge_cannotBeCalledByRandomAddress(address randomCaller, address randomAddress) public { + vm.assume(randomAddress != address(0)); if (randomCaller != bridgeOwner) { vm.prank(randomCaller); vm.expectRevert(bytes("Ownable: caller is not the owner")); @@ -321,42 +414,248 @@ contract ExperimentalBridgeTest is Test { uint256 newChainId; address admin; + function test_pause_createNewChain( + uint256 chainId, + uint256 salt, + uint256 randomValue + ) public useRandomToken(randomValue) { + chainId = bound(chainId, 1, type(uint48).max); + address deployerAddress = makeAddr("DEPLOYER_ADDRESS"); + admin = makeAddr("NEW_CHAIN_ADMIN"); + + vm.prank(bridgeOwner); + bridgeHub.pause(); + vm.prank(bridgeOwner); + bridgeHub.setPendingAdmin(deployerAddress); + vm.prank(deployerAddress); + bridgeHub.acceptAdmin(); + + vm.expectRevert("Pausable: paused"); + vm.prank(deployerAddress); + bridgeHub.createNewChain({ + _chainId: chainId, + _stateTransitionManager: address(mockSTM), + _baseToken: address(testToken), + _salt: salt, + _admin: admin, + _initData: bytes("") + }); + + vm.prank(bridgeOwner); + bridgeHub.unpause(); + + vm.expectRevert(STMNotRegistered.selector); + vm.prank(deployerAddress); + bridgeHub.createNewChain({ + _chainId: 1, + _stateTransitionManager: address(mockSTM), + _baseToken: address(testToken), + _salt: uint256(123), + _admin: admin, + _initData: bytes("") + }); + } + + function test_RevertWhen_STMNotRegisteredOnCreate( + uint256 chainId, + uint256 salt, + uint256 randomValue + ) public useRandomToken(randomValue) { + chainId = bound(chainId, 1, type(uint48).max); + address deployerAddress = makeAddr("DEPLOYER_ADDRESS"); + admin = makeAddr("NEW_CHAIN_ADMIN"); + + vm.prank(bridgeOwner); + bridgeHub.setPendingAdmin(deployerAddress); + vm.prank(deployerAddress); + bridgeHub.acceptAdmin(); + + chainId = bound(chainId, 1, type(uint48).max); + vm.expectRevert(STMNotRegistered.selector); + vm.prank(deployerAddress); + bridgeHub.createNewChain({ + _chainId: chainId, + _stateTransitionManager: address(mockSTM), + _baseToken: address(testToken), + _salt: salt, + _admin: admin, + _initData: bytes("") + }); + } + + function test_RevertWhen_wrongChainIdOnCreate( + uint256 chainId, + uint256 salt, + uint256 randomValue + ) public useRandomToken(randomValue) { + chainId = bound(chainId, 1, type(uint48).max); + address deployerAddress = makeAddr("DEPLOYER_ADDRESS"); + admin = makeAddr("NEW_CHAIN_ADMIN"); + + vm.prank(bridgeOwner); + bridgeHub.setPendingAdmin(deployerAddress); + vm.prank(deployerAddress); + bridgeHub.acceptAdmin(); + + chainId = bound(chainId, type(uint48).max + uint256(1), type(uint256).max); + vm.expectRevert(ChainIdTooBig.selector); + vm.prank(deployerAddress); + bridgeHub.createNewChain({ + _chainId: chainId, + _stateTransitionManager: address(mockSTM), + _baseToken: address(testToken), + _salt: salt, + _admin: admin, + _initData: bytes("") + }); + + chainId = 0; + vm.expectRevert(ZeroChainId.selector); + vm.prank(deployerAddress); + bridgeHub.createNewChain({ + _chainId: chainId, + _stateTransitionManager: address(mockSTM), + _baseToken: address(testToken), + _salt: salt, + _admin: admin, + _initData: bytes("") + }); + } + + function test_RevertWhen_tokenNotRegistered( + uint256 chainId, + uint256 salt, + uint256 randomValue + ) public useRandomToken(randomValue) { + chainId = bound(chainId, 1, type(uint48).max); + address deployerAddress = makeAddr("DEPLOYER_ADDRESS"); + admin = makeAddr("NEW_CHAIN_ADMIN"); + + vm.prank(bridgeOwner); + bridgeHub.setPendingAdmin(deployerAddress); + vm.prank(deployerAddress); + bridgeHub.acceptAdmin(); + + vm.startPrank(bridgeOwner); + bridgeHub.addStateTransitionManager(address(mockSTM)); + vm.stopPrank(); + + vm.expectRevert(abi.encodeWithSelector(TokenNotRegistered.selector, address(testToken))); + vm.prank(deployerAddress); + bridgeHub.createNewChain({ + _chainId: chainId, + _stateTransitionManager: address(mockSTM), + _baseToken: address(testToken), + _salt: salt, + _admin: admin, + _initData: bytes("") + }); + } + + function test_RevertWhen_wethBridgeNotSet( + uint256 chainId, + uint256 salt, + uint256 randomValue + ) public useRandomToken(randomValue) { + chainId = bound(chainId, 1, type(uint48).max); + address deployerAddress = makeAddr("DEPLOYER_ADDRESS"); + admin = makeAddr("NEW_CHAIN_ADMIN"); + + vm.prank(bridgeOwner); + bridgeHub.setPendingAdmin(deployerAddress); + vm.prank(deployerAddress); + bridgeHub.acceptAdmin(); + + vm.startPrank(bridgeOwner); + bridgeHub.addStateTransitionManager(address(mockSTM)); + bridgeHub.addToken(address(testToken)); + vm.stopPrank(); + + vm.expectRevert(SharedBridgeNotSet.selector); + vm.prank(deployerAddress); + bridgeHub.createNewChain({ + _chainId: chainId, + _stateTransitionManager: address(mockSTM), + _baseToken: address(testToken), + _salt: salt, + _admin: admin, + _initData: bytes("") + }); + } + + function test_RevertWhen_chainIdAlreadyRegistered( + uint256 chainId, + uint256 salt, + uint256 randomValue + ) public useRandomToken(randomValue) { + address deployerAddress = makeAddr("DEPLOYER_ADDRESS"); + admin = makeAddr("NEW_CHAIN_ADMIN"); + vm.prank(bridgeOwner); + bridgeHub.setPendingAdmin(deployerAddress); + vm.prank(deployerAddress); + bridgeHub.acceptAdmin(); + + vm.startPrank(bridgeOwner); + bridgeHub.addStateTransitionManager(address(mockSTM)); + bridgeHub.addToken(address(testToken)); + bridgeHub.setSharedBridge(sharedBridgeAddress); + vm.stopPrank(); + + chainId = bound(chainId, 1, type(uint48).max); + stdstore.target(address(bridgeHub)).sig("stateTransitionManager(uint256)").with_key(chainId).checked_write( + address(mockSTM) + ); + + vm.expectRevert(BridgeHubAlreadyRegistered.selector); + vm.prank(deployerAddress); + bridgeHub.createNewChain({ + _chainId: chainId, + _stateTransitionManager: address(mockSTM), + _baseToken: address(testToken), + _salt: salt, + _admin: admin, + _initData: bytes("") + }); + } + function test_createNewChain( address randomCaller, uint256 chainId, bool isFreezable, bytes4[] memory mockSelectors, address mockInitAddress, - bytes memory mockInitCalldata - ) public { + bytes memory mockInitCalldata, + uint256 salt, + uint256 randomValue + ) public useRandomToken(randomValue) { address deployerAddress = makeAddr("DEPLOYER_ADDRESS"); admin = makeAddr("NEW_CHAIN_ADMIN"); - // Diamond.DiamondCutData memory dcData; + chainId = bound(chainId, 1, type(uint48).max); vm.prank(bridgeOwner); bridgeHub.setPendingAdmin(deployerAddress); vm.prank(deployerAddress); bridgeHub.acceptAdmin(); + vm.startPrank(bridgeOwner); bridgeHub.addStateTransitionManager(address(mockSTM)); bridgeHub.addToken(address(testToken)); - bridgeHub.setSharedBridge(address(mockSharedBridge)); + bridgeHub.setSharedBridge(sharedBridgeAddress); vm.stopPrank(); if (randomCaller != deployerAddress && randomCaller != bridgeOwner) { vm.prank(randomCaller); - vm.expectRevert(bytes("Bridgehub: not owner or admin")); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomCaller)); bridgeHub.createNewChain({ _chainId: chainId, _stateTransitionManager: address(mockSTM), _baseToken: address(testToken), - _salt: uint256(123), + _salt: salt, _admin: admin, _initData: bytes("") }); } - chainId = bound(chainId, 1, type(uint48).max); vm.prank(mockSTM.owner()); bytes memory _newChainInitData = _createNewChainInitData( isFreezable, @@ -378,13 +677,16 @@ contract ExperimentalBridgeTest is Test { mockSTM.createNewChain.selector, chainId, address(testToken), - address(mockSharedBridge), + sharedBridgeAddress, admin, _newChainInitData ), bytes("") ); + vm.expectEmit(true, true, true, true, address(bridgeHub)); + emit NewChain(chainId, address(mockSTM), admin); + newChainId = bridgeHub.createNewChain({ _chainId: chainId, _stateTransitionManager: address(mockSTM), @@ -587,7 +889,7 @@ contract ExperimentalBridgeTest is Test { vm.clearMockedCalls(); } - function test_requestL2TransactionDirect_ETHCase( + function _prepareETHL2TransactionDirectRequest( uint256 mockChainId, uint256 mockMintValue, address mockL2Contract, @@ -596,14 +898,13 @@ contract ExperimentalBridgeTest is Test { uint256 mockL2GasLimit, uint256 mockL2GasPerPubdataByteLimit, bytes[] memory mockFactoryDeps, - address mockRefundRecipient, - bytes[] memory mockRefundRecipientBH - ) public { + address randomCaller + ) internal returns (L2TransactionRequestDirect memory l2TxnReqDirect) { if (mockFactoryDeps.length > MAX_NEW_FACTORY_DEPS) { mockFactoryDeps = _restrictArraySize(mockFactoryDeps, MAX_NEW_FACTORY_DEPS); } - L2TransactionRequestDirect memory l2TxnReqDirect = _createMockL2TransactionRequestDirect({ + l2TxnReqDirect = _createMockL2TransactionRequestDirect({ mockChainId: mockChainId, mockMintValue: mockMintValue, mockL2Contract: mockL2Contract, @@ -612,24 +913,20 @@ contract ExperimentalBridgeTest is Test { mockL2GasLimit: mockL2GasLimit, mockL2GasPerPubdataByteLimit: mockL2GasPerPubdataByteLimit, mockFactoryDeps: mockFactoryDeps, - mockRefundRecipient: mockRefundRecipient + mockRefundRecipient: address(0) }); l2TxnReqDirect.chainId = _setUpHyperchainForChainId(l2TxnReqDirect.chainId); assertTrue(!(bridgeHub.baseToken(l2TxnReqDirect.chainId) == ETH_TOKEN_ADDRESS)); - _setUpBaseTokenForChainId(l2TxnReqDirect.chainId, true); + _setUpBaseTokenForChainId(l2TxnReqDirect.chainId, true, address(0)); assertTrue(bridgeHub.baseToken(l2TxnReqDirect.chainId) == ETH_TOKEN_ADDRESS); _setUpSharedBridge(); - - address randomCaller = makeAddr("RANDOM_CALLER"); - vm.deal(randomCaller, l2TxnReqDirect.mintValue); + _setUpSharedBridgeL2(mockChainId); assertTrue(bridgeHub.getHyperchain(l2TxnReqDirect.chainId) == address(mockChainContract)); bytes32 canonicalHash = keccak256(abi.encode("CANONICAL_TX_HASH")); - //BridgehubL2TransactionRequest memory bhL2TxnRequest = - _createBhL2TxnRequest(mockRefundRecipientBH); vm.mockCall( address(mockChainContract), @@ -641,10 +938,71 @@ contract ExperimentalBridgeTest is Test { mockChainContract.setBaseTokenGasMultiplierPrice(uint128(1), uint128(1)); mockChainContract.setBridgeHubAddress(address(bridgeHub)); assertTrue(mockChainContract.getBridgeHubAddress() == address(bridgeHub)); + } + + function test_requestL2TransactionDirect_RevertWhen_incorrectETHParams( + uint256 mockChainId, + uint256 mockMintValue, + address mockL2Contract, + uint256 mockL2Value, + uint256 msgValue, + bytes memory mockL2Calldata, + uint256 mockL2GasLimit, + uint256 mockL2GasPerPubdataByteLimit, + bytes[] memory mockFactoryDeps + ) public { + address randomCaller = makeAddr("RANDOM_CALLER"); + vm.assume(msgValue != mockMintValue); - vm.txGasPrice(0.05 ether); + L2TransactionRequestDirect memory l2TxnReqDirect = _prepareETHL2TransactionDirectRequest({ + mockChainId: mockChainId, + mockMintValue: mockMintValue, + mockL2Contract: mockL2Contract, + mockL2Value: mockL2Value, + mockL2Calldata: mockL2Calldata, + mockL2GasLimit: mockL2GasLimit, + mockL2GasPerPubdataByteLimit: mockL2GasPerPubdataByteLimit, + mockFactoryDeps: mockFactoryDeps, + randomCaller: randomCaller + }); + vm.deal(randomCaller, msgValue); + vm.expectRevert(abi.encodeWithSelector(MsgValueMismatch.selector, mockMintValue, msgValue)); vm.prank(randomCaller); + bridgeHub.requestL2TransactionDirect{value: msgValue}(l2TxnReqDirect); + } + + function test_requestL2TransactionDirect_ETHCase( + uint256 mockChainId, + uint256 mockMintValue, + address mockL2Contract, + uint256 mockL2Value, + bytes memory mockL2Calldata, + uint256 mockL2GasLimit, + uint256 mockL2GasPerPubdataByteLimit, + bytes[] memory mockFactoryDeps, + uint256 gasPrice + ) public { + address randomCaller = makeAddr("RANDOM_CALLER"); + mockChainId = bound(mockChainId, 1, type(uint48).max); + + L2TransactionRequestDirect memory l2TxnReqDirect = _prepareETHL2TransactionDirectRequest({ + mockChainId: mockChainId, + mockMintValue: mockMintValue, + mockL2Contract: mockL2Contract, + mockL2Value: mockL2Value, + mockL2Calldata: mockL2Calldata, + mockL2GasLimit: mockL2GasLimit, + mockL2GasPerPubdataByteLimit: mockL2GasPerPubdataByteLimit, + mockFactoryDeps: mockFactoryDeps, + randomCaller: randomCaller + }); + + vm.deal(randomCaller, l2TxnReqDirect.mintValue); + gasPrice = bound(gasPrice, 1_000, 50_000_000); + vm.txGasPrice(gasPrice * 1 gwei); + vm.prank(randomCaller); + bytes32 canonicalHash = keccak256(abi.encode("CANONICAL_TX_HASH")); bytes32 resultantHash = bridgeHub.requestL2TransactionDirect{value: randomCaller.balance}(l2TxnReqDirect); assertTrue(resultantHash == canonicalHash); @@ -659,8 +1017,12 @@ contract ExperimentalBridgeTest is Test { uint256 mockL2GasLimit, uint256 mockL2GasPerPubdataByteLimit, bytes[] memory mockFactoryDeps, - address mockRefundRecipient - ) public { + uint256 gasPrice, + uint256 randomValue + ) public useRandomToken(randomValue) { + address randomCaller = makeAddr("RANDOM_CALLER"); + mockChainId = bound(mockChainId, 1, type(uint48).max); + if (mockFactoryDeps.length > MAX_NEW_FACTORY_DEPS) { mockFactoryDeps = _restrictArraySize(mockFactoryDeps, MAX_NEW_FACTORY_DEPS); } @@ -674,13 +1036,14 @@ contract ExperimentalBridgeTest is Test { mockL2GasLimit: mockL2GasLimit, mockL2GasPerPubdataByteLimit: mockL2GasPerPubdataByteLimit, mockFactoryDeps: mockFactoryDeps, - mockRefundRecipient: mockRefundRecipient + mockRefundRecipient: address(0) }); l2TxnReqDirect.chainId = _setUpHyperchainForChainId(l2TxnReqDirect.chainId); - _setUpBaseTokenForChainId(l2TxnReqDirect.chainId, false); + _setUpBaseTokenForChainId(l2TxnReqDirect.chainId, false, address(testToken)); _setUpSharedBridge(); + _setUpSharedBridgeL2(mockChainId); assertTrue(bridgeHub.getHyperchain(l2TxnReqDirect.chainId) == address(mockChainContract)); bytes32 canonicalHash = keccak256(abi.encode("CANONICAL_TX_HASH")); @@ -696,13 +1059,12 @@ contract ExperimentalBridgeTest is Test { mockChainContract.setBridgeHubAddress(address(bridgeHub)); assertTrue(mockChainContract.getBridgeHubAddress() == address(bridgeHub)); - vm.txGasPrice(0.05 ether); + gasPrice = bound(gasPrice, 1_000, 50_000_000); + vm.txGasPrice(gasPrice * 1 gwei); - address randomCaller = makeAddr("RANDOM_CALLER"); vm.deal(randomCaller, 1 ether); - vm.prank(randomCaller); - vm.expectRevert("Bridgehub: non-eth bridge with msg.value"); + vm.expectRevert(abi.encodeWithSelector(MsgValueMismatch.selector, 0, randomCaller.balance)); bytes32 resultantHash = bridgeHub.requestL2TransactionDirect{value: randomCaller.balance}(l2TxnReqDirect); // Now, let's call the same function with zero msg.value @@ -712,23 +1074,86 @@ contract ExperimentalBridgeTest is Test { vm.prank(randomCaller); testToken.transfer(address(this), l2TxnReqDirect.mintValue); assertEq(testToken.balanceOf(address(this)), l2TxnReqDirect.mintValue); - testToken.approve(address(mockSharedBridge), l2TxnReqDirect.mintValue); + testToken.approve(sharedBridgeAddress, l2TxnReqDirect.mintValue); resultantHash = bridgeHub.requestL2TransactionDirect(l2TxnReqDirect); assertEq(canonicalHash, resultantHash); } - function test_requestL2TransactionTwoBridges_ETHCase( + function test_requestTransactionTwoBridgesChecksMagicValue( + uint256 chainId, + uint256 mintValue, + uint256 l2Value, + uint256 l2GasLimit, + uint256 l2GasPerPubdataByteLimit, + address refundRecipient, + uint256 secondBridgeValue, + bytes memory secondBridgeCalldata, + bytes32 magicValue + ) public { + chainId = bound(chainId, 1, type(uint48).max); + + L2TransactionRequestTwoBridgesOuter memory l2TxnReq2BridgeOut = _createMockL2TransactionRequestTwoBridgesOuter({ + chainId: chainId, + mintValue: mintValue, + l2Value: l2Value, + l2GasLimit: l2GasLimit, + l2GasPerPubdataByteLimit: l2GasPerPubdataByteLimit, + refundRecipient: refundRecipient, + secondBridgeValue: secondBridgeValue, + secondBridgeCalldata: secondBridgeCalldata + }); + + l2TxnReq2BridgeOut.chainId = _setUpHyperchainForChainId(l2TxnReq2BridgeOut.chainId); + + _setUpBaseTokenForChainId(l2TxnReq2BridgeOut.chainId, true, address(0)); + assertTrue(bridgeHub.baseToken(l2TxnReq2BridgeOut.chainId) == ETH_TOKEN_ADDRESS); + + _setUpSharedBridge(); + _setUpSharedBridgeL2(chainId); + + assertTrue(bridgeHub.getHyperchain(l2TxnReq2BridgeOut.chainId) == address(mockChainContract)); + + uint256 callerMsgValue = l2TxnReq2BridgeOut.mintValue + l2TxnReq2BridgeOut.secondBridgeValue; + address randomCaller = makeAddr("RANDOM_CALLER"); + vm.deal(randomCaller, callerMsgValue); + + if (magicValue != TWO_BRIDGES_MAGIC_VALUE) { + L2TransactionRequestTwoBridgesInner memory request = L2TransactionRequestTwoBridgesInner({ + magicValue: magicValue, + l2Contract: makeAddr("L2_CONTRACT"), + l2Calldata: new bytes(0), + factoryDeps: new bytes[](0), + txDataHash: bytes32(0) + }); + + vm.mockCall( + secondBridgeAddress, + abi.encodeWithSelector(IL1SharedBridge.bridgehubDeposit.selector), + abi.encode(request) + ); + + vm.expectRevert(abi.encodeWithSelector(WrongMagicValue.selector, TWO_BRIDGES_MAGIC_VALUE, magicValue)); + vm.prank(randomCaller); + bridgeHub.requestL2TransactionTwoBridges{value: randomCaller.balance}(l2TxnReq2BridgeOut); + } + } + + function test_requestL2TransactionTwoBridgesWrongBridgeAddress( uint256 chainId, uint256 mintValue, + uint256 msgValue, uint256 l2Value, uint256 l2GasLimit, uint256 l2GasPerPubdataByteLimit, address refundRecipient, uint256 secondBridgeValue, + uint160 secondBridgeAddressValue, bytes memory secondBridgeCalldata ) public { + chainId = bound(chainId, 1, type(uint48).max); + L2TransactionRequestTwoBridgesOuter memory l2TxnReq2BridgeOut = _createMockL2TransactionRequestTwoBridgesOuter({ chainId: chainId, mintValue: mintValue, @@ -742,10 +1167,12 @@ contract ExperimentalBridgeTest is Test { l2TxnReq2BridgeOut.chainId = _setUpHyperchainForChainId(l2TxnReq2BridgeOut.chainId); - _setUpBaseTokenForChainId(l2TxnReq2BridgeOut.chainId, true); + _setUpBaseTokenForChainId(l2TxnReq2BridgeOut.chainId, true, address(0)); assertTrue(bridgeHub.baseToken(l2TxnReq2BridgeOut.chainId) == ETH_TOKEN_ADDRESS); _setUpSharedBridge(); + _setUpSharedBridgeL2(chainId); + assertTrue(bridgeHub.getHyperchain(l2TxnReq2BridgeOut.chainId) == address(mockChainContract)); uint256 callerMsgValue = l2TxnReq2BridgeOut.mintValue + l2TxnReq2BridgeOut.secondBridgeValue; @@ -762,11 +1189,174 @@ contract ExperimentalBridgeTest is Test { abi.encode(canonicalHash) ); + L2TransactionRequestTwoBridgesInner memory outputRequest = L2TransactionRequestTwoBridgesInner({ + magicValue: TWO_BRIDGES_MAGIC_VALUE, + l2Contract: address(0), + l2Calldata: abi.encode(""), + factoryDeps: new bytes[](0), + txDataHash: bytes32("") + }); + secondBridgeAddressValue = uint160(bound(uint256(secondBridgeAddressValue), 0, uint256(type(uint16).max))); + address secondBridgeAddress = address(secondBridgeAddressValue); + + vm.mockCall( + address(secondBridgeAddressValue), + l2TxnReq2BridgeOut.secondBridgeValue, + abi.encodeWithSelector( + IL1SharedBridge.bridgehubDeposit.selector, + l2TxnReq2BridgeOut.chainId, + randomCaller, + l2TxnReq2BridgeOut.l2Value, + l2TxnReq2BridgeOut.secondBridgeCalldata + ), + abi.encode(outputRequest) + ); + + l2TxnReq2BridgeOut.secondBridgeAddress = address(secondBridgeAddressValue); + vm.expectRevert(abi.encodeWithSelector(AddressTooLow.selector, secondBridgeAddress)); vm.prank(randomCaller); - //bytes32 resultantHash = bridgeHub.requestL2TransactionTwoBridges{value: randomCaller.balance}(l2TxnReq2BridgeOut); + } + + function test_requestL2TransactionTwoBridges_ERC20ToNonBase( + uint256 chainId, + uint256 mintValue, + uint256 l2Value, + uint256 l2GasLimit, + uint256 l2GasPerPubdataByteLimit, + address l2Receiver, + uint256 randomValue + ) public useRandomToken(randomValue) { + // create another token, to avoid base token + TestnetERC20Token erc20Token = new TestnetERC20Token("ZKESTT", "ZkSync ERC Test Token", 18); + address erc20TokenAddress = address(erc20Token); + l2Value = bound(l2Value, 1, type(uint256).max); + bytes memory secondBridgeCalldata = abi.encode(erc20TokenAddress, l2Value, l2Receiver); + + chainId = _setUpHyperchainForChainId(chainId); + + L2TransactionRequestTwoBridgesOuter memory l2TxnReq2BridgeOut = _createMockL2TransactionRequestTwoBridgesOuter({ + chainId: chainId, + mintValue: mintValue, + l2Value: 0, // not used + l2GasLimit: l2GasLimit, + l2GasPerPubdataByteLimit: l2GasPerPubdataByteLimit, + refundRecipient: address(0), + secondBridgeValue: 0, // not used cause we are using ERC20 + secondBridgeCalldata: secondBridgeCalldata + }); + + address randomCaller = makeAddr("RANDOM_CALLER"); + bytes32 canonicalHash = keccak256(abi.encode("CANONICAL_TX_HASH")); + + _setUpBaseTokenForChainId(l2TxnReq2BridgeOut.chainId, false, address(testToken)); + assertTrue(bridgeHub.baseToken(l2TxnReq2BridgeOut.chainId) == address(testToken)); + _setUpSharedBridge(); + + _setUpSharedBridgeL2(chainId); + assertTrue(bridgeHub.getHyperchain(l2TxnReq2BridgeOut.chainId) == address(mockChainContract)); + mockChainContract.setBridgeHubAddress(address(bridgeHub)); + + vm.mockCall( + address(mockChainContract), + abi.encodeWithSelector(mockChainContract.bridgehubRequestL2Transaction.selector), + abi.encode(canonicalHash) + ); + + testToken.mint(randomCaller, l2TxnReq2BridgeOut.mintValue); + erc20Token.mint(randomCaller, l2Value); - assertTrue(true); + assertEq(testToken.balanceOf(randomCaller), l2TxnReq2BridgeOut.mintValue); + assertEq(erc20Token.balanceOf(randomCaller), l2Value); + + vm.startPrank(randomCaller); + testToken.approve(sharedBridgeAddress, l2TxnReq2BridgeOut.mintValue); + erc20Token.approve(secondBridgeAddress, l2Value); + vm.stopPrank(); + vm.prank(randomCaller); + bytes32 resultHash = bridgeHub.requestL2TransactionTwoBridges(l2TxnReq2BridgeOut); + assertEq(resultHash, canonicalHash); + + assert(erc20Token.balanceOf(randomCaller) == 0); + assert(testToken.balanceOf(randomCaller) == 0); + assert(erc20Token.balanceOf(secondBridgeAddress) == l2Value); + assert(testToken.balanceOf(sharedBridgeAddress) == l2TxnReq2BridgeOut.mintValue); + + l2TxnReq2BridgeOut.secondBridgeValue = 1; + testToken.mint(randomCaller, l2TxnReq2BridgeOut.mintValue); + vm.startPrank(randomCaller); + testToken.approve(sharedBridgeAddress, l2TxnReq2BridgeOut.mintValue); + vm.expectRevert(abi.encodeWithSelector(MsgValueMismatch.selector, l2TxnReq2BridgeOut.secondBridgeValue, 0)); + bridgeHub.requestL2TransactionTwoBridges(l2TxnReq2BridgeOut); + vm.stopPrank(); + } + + function test_requestL2TransactionTwoBridges_ETHToNonBase( + uint256 chainId, + uint256 mintValue, + uint256 msgValue, + uint256 l2Value, + uint256 l2GasLimit, + uint256 l2GasPerPubdataByteLimit, + address refundRecipient, + uint256 secondBridgeValue, + address l2Receiver, + uint256 randomValue + ) public useRandomToken(randomValue) { + secondBridgeValue = bound(secondBridgeValue, 1, type(uint256).max); + bytes memory secondBridgeCalldata = abi.encode(ETH_TOKEN_ADDRESS, 0, l2Receiver); + + chainId = _setUpHyperchainForChainId(chainId); + + L2TransactionRequestTwoBridgesOuter memory l2TxnReq2BridgeOut = _createMockL2TransactionRequestTwoBridgesOuter({ + chainId: chainId, + mintValue: mintValue, + l2Value: l2Value, + l2GasLimit: l2GasLimit, + l2GasPerPubdataByteLimit: l2GasPerPubdataByteLimit, + refundRecipient: refundRecipient, + secondBridgeValue: secondBridgeValue, + secondBridgeCalldata: secondBridgeCalldata + }); + + _setUpBaseTokenForChainId(l2TxnReq2BridgeOut.chainId, false, address(testToken)); + assertTrue(bridgeHub.baseToken(l2TxnReq2BridgeOut.chainId) == address(testToken)); + + _setUpSharedBridge(); + _setUpSharedBridgeL2(chainId); + assertTrue(bridgeHub.getHyperchain(l2TxnReq2BridgeOut.chainId) == address(mockChainContract)); + + address randomCaller = makeAddr("RANDOM_CALLER"); + + mockChainContract.setBridgeHubAddress(address(bridgeHub)); + + { + bytes32 canonicalHash = keccak256(abi.encode("CANONICAL_TX_HASH")); + + vm.mockCall( + address(mockChainContract), + abi.encodeWithSelector(mockChainContract.bridgehubRequestL2Transaction.selector), + abi.encode(canonicalHash) + ); + } + + if (msgValue != secondBridgeValue) { + vm.deal(randomCaller, msgValue); + vm.expectRevert( + abi.encodeWithSelector(MsgValueMismatch.selector, l2TxnReq2BridgeOut.secondBridgeValue, msgValue) + ); + vm.prank(randomCaller); + 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); } ///////////////////////////////////////////////////////// @@ -786,8 +1376,9 @@ contract ExperimentalBridgeTest is Test { L2TransactionRequestTwoBridgesOuter memory l2Req; // Don't let the mintValue + secondBridgeValue go beyond type(uint256).max since that calculation is required to be done by our test: test_requestL2TransactionTwoBridges_ETHCase - mintValue = bound(mintValue, 1, (type(uint256).max) / 2); - secondBridgeValue = bound(secondBridgeValue, 1, (type(uint256).max) / 2); + + mintValue = bound(mintValue, 0, (type(uint256).max) / 2); + secondBridgeValue = bound(secondBridgeValue, 0, (type(uint256).max) / 2); l2Req.chainId = chainId; l2Req.mintValue = mintValue; @@ -795,7 +1386,7 @@ contract ExperimentalBridgeTest is Test { l2Req.l2GasLimit = l2GasLimit; l2Req.l2GasPerPubdataByteLimit = l2GasPerPubdataByteLimit; l2Req.refundRecipient = refundRecipient; - l2Req.secondBridgeAddress = address(mockSecondSharedBridge); + l2Req.secondBridgeAddress = secondBridgeAddress; l2Req.secondBridgeValue = secondBridgeValue; l2Req.secondBridgeCalldata = secondBridgeCalldata; @@ -878,7 +1469,7 @@ contract ExperimentalBridgeTest is Test { } function _setUpHyperchainForChainId(uint256 mockChainId) internal returns (uint256 mockChainIdInRange) { - mockChainId = bound(mockChainId, 2, type(uint48).max); + mockChainId = bound(mockChainId, 1, type(uint48).max); mockChainIdInRange = mockChainId; vm.prank(bridgeOwner); bridgeHub.addStateTransitionManager(address(mockSTM)); @@ -896,15 +1487,29 @@ contract ExperimentalBridgeTest is Test { mockSTM.setHyperchain(mockChainId, address(mockChainContract)); } - function _setUpBaseTokenForChainId(uint256 mockChainId, bool tokenIsETH) internal { - address baseToken = tokenIsETH ? ETH_TOKEN_ADDRESS : address(testToken); + function _setUpBaseTokenForChainId(uint256 mockChainId, bool tokenIsETH, address token) internal { + address baseToken = tokenIsETH ? ETH_TOKEN_ADDRESS : token; stdstore.target(address(bridgeHub)).sig("baseToken(uint256)").with_key(mockChainId).checked_write(baseToken); } function _setUpSharedBridge() internal { vm.prank(bridgeOwner); - bridgeHub.setSharedBridge(address(mockSharedBridge)); + bridgeHub.setSharedBridge(sharedBridgeAddress); + } + + function _setUpSharedBridgeL2(uint256 _chainId) internal { + _chainId = bound(_chainId, 1, type(uint48).max); + + vm.prank(bridgeOwner); + sharedBridge.initializeChainGovernance(_chainId, mockL2Contract); + + assertEq(sharedBridge.l2BridgeAddress(_chainId), mockL2Contract); + + vm.prank(bridgeOwner); + secondBridge.initializeChainGovernance(_chainId, mockL2Contract); + + assertEq(secondBridge.l2BridgeAddress(_chainId), mockL2Contract); } function _createMockL2TransactionRequestDirect( diff --git a/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/ClaimFailedDeposit.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/ClaimFailedDeposit.t.sol index 89a20d90d..e434dd8f4 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/ClaimFailedDeposit.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/ClaimFailedDeposit.t.sol @@ -4,6 +4,8 @@ pragma solidity 0.8.24; import {L1Erc20BridgeTest} from "./_L1Erc20Bridge_Shared.t.sol"; import {StdStorage, stdStorage} from "forge-std/Test.sol"; +import {IL1SharedBridge} from "contracts/bridge/interfaces/IL1SharedBridge.sol"; +import {EmptyDeposit} from "contracts/common/L1ContractErrors.sol"; contract ClaimFailedDepositTest is L1Erc20BridgeTest { using stdStorage for StdStorage; @@ -11,13 +13,13 @@ contract ClaimFailedDepositTest is L1Erc20BridgeTest { event ClaimedFailedDeposit(address indexed to, address indexed l1Token, uint256 amount); function test_RevertWhen_ClaimAmountIsZero() public { - vm.expectRevert(bytes("2T")); + vm.expectRevert(EmptyDeposit.selector); bytes32[] memory merkleProof; bridge.claimFailedDeposit({ _depositSender: randomSigner, _l1Token: address(token), - _l2TxHash: dummyL2DepositTxHash, + _l2TxHash: bytes32(""), _l2BatchNumber: 0, _l2MessageIndex: 0, _l2TxNumberInBatch: 0, @@ -26,37 +28,56 @@ contract ClaimFailedDepositTest is L1Erc20BridgeTest { } function test_claimFailedDepositSuccessfully() public { - uint256 depositedAmountBefore = bridge.depositAmount(alice, address(token), dummyL2DepositTxHash); + uint256 amount = 16; + bytes32 l2DepositTxHash = keccak256("l2tx"); + bytes32[] memory merkleProof; + + uint256 depositedAmountBefore = bridge.depositAmount(alice, address(token), l2DepositTxHash); assertEq(depositedAmountBefore, 0); - uint256 amount = 16; stdstore .target(address(bridge)) .sig("depositAmount(address,address,bytes32)") .with_key(alice) .with_key(address(token)) - .with_key(dummyL2DepositTxHash) + .with_key(l2DepositTxHash) .checked_write(amount); - uint256 depositedAmountAfterDeposit = bridge.depositAmount(alice, address(token), dummyL2DepositTxHash); + uint256 depositedAmountAfterDeposit = bridge.depositAmount(alice, address(token), l2DepositTxHash); assertEq(depositedAmountAfterDeposit, amount); + vm.mockCall( + sharedBridgeAddress, + abi.encodeWithSelector( + IL1SharedBridge.claimFailedDepositLegacyErc20Bridge.selector, + alice, + address(token), + amount, + l2DepositTxHash, + 0, + 0, + 0, + merkleProof + ), + abi.encode("") + ); + vm.prank(alice); // solhint-disable-next-line func-named-parameters vm.expectEmit(true, true, true, true, address(bridge)); emit ClaimedFailedDeposit(alice, address(token), amount); - bytes32[] memory merkleProof; + bridge.claimFailedDeposit({ _depositSender: alice, _l1Token: address(token), - _l2TxHash: dummyL2DepositTxHash, + _l2TxHash: l2DepositTxHash, _l2BatchNumber: 0, _l2MessageIndex: 0, _l2TxNumberInBatch: 0, _merkleProof: merkleProof }); - uint256 depositedAmountAfterWithdrawal = bridge.depositAmount(alice, address(token), dummyL2DepositTxHash); + uint256 depositedAmountAfterWithdrawal = bridge.depositAmount(alice, address(token), l2DepositTxHash); assertEq(depositedAmountAfterWithdrawal, 0); } } diff --git a/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/Deposit.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/Deposit.t.sol index 67f16aab8..ee679d0e1 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/Deposit.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/Deposit.t.sol @@ -3,6 +3,8 @@ pragma solidity 0.8.24; import {L1Erc20BridgeTest} from "./_L1Erc20Bridge_Shared.t.sol"; +import {EmptyDeposit, ValueMismatch, TokensWithFeesNotSupported} from "contracts/common/L1ContractErrors.sol"; +import {IL1SharedBridge} from "contracts/bridge/interfaces/IL1SharedBridge.sol"; contract DepositTest is L1Erc20BridgeTest { event DepositInitiated( @@ -14,7 +16,7 @@ contract DepositTest is L1Erc20BridgeTest { ); function test_RevertWhen_depositAmountIsZero() public { - vm.expectRevert(bytes("0T")); + vm.expectRevert(EmptyDeposit.selector); bridge.deposit({ _l2Receiver: randomSigner, _l1Token: address(token), @@ -26,7 +28,7 @@ contract DepositTest is L1Erc20BridgeTest { } function test_RevertWhen_legacyDepositAmountIsZero() public { - vm.expectRevert(bytes("0T")); + vm.expectRevert(EmptyDeposit.selector); bridge.deposit({ _l2Receiver: randomSigner, _l1Token: address(token), @@ -84,7 +86,7 @@ contract DepositTest is L1Erc20BridgeTest { uint256 amount = 2; vm.prank(alice); feeOnTransferToken.approve(address(bridge), amount); - vm.expectRevert(bytes("3T")); + vm.expectRevert(TokensWithFeesNotSupported.selector); vm.prank(alice); bridge.deposit({ _l2Receiver: randomSigner, @@ -99,7 +101,7 @@ contract DepositTest is L1Erc20BridgeTest { uint256 amount = 4; vm.prank(alice); feeOnTransferToken.approve(address(bridge), amount); - vm.expectRevert(bytes("3T")); + vm.expectRevert(TokensWithFeesNotSupported.selector); vm.prank(alice); bridge.deposit({ _l2Receiver: randomSigner, @@ -112,13 +114,30 @@ contract DepositTest is L1Erc20BridgeTest { function test_depositSuccessfully() public { uint256 amount = 8; + bytes32 l2TxHash = keccak256("txHash"); + + vm.mockCall( + sharedBridgeAddress, + abi.encodeWithSelector( + IL1SharedBridge.depositLegacyErc20Bridge.selector, + alice, + randomSigner, + address(token), + amount, + 0, + 0, + address(0) + ), + abi.encode(l2TxHash) + ); + vm.prank(alice); token.approve(address(bridge), amount); vm.prank(alice); // solhint-disable-next-line func-named-parameters vm.expectEmit(true, true, true, true, address(bridge)); // solhint-disable-next-line func-named-parameters - emit DepositInitiated(dummyL2DepositTxHash, alice, randomSigner, address(token), amount); + emit DepositInitiated(l2TxHash, alice, randomSigner, address(token), amount); bytes32 txHash = bridge.deposit({ _l2Receiver: randomSigner, _l1Token: address(token), @@ -127,24 +146,41 @@ contract DepositTest is L1Erc20BridgeTest { _l2TxGasPerPubdataByte: 0, _refundRecipient: address(0) }); - assertEq(txHash, dummyL2DepositTxHash); + assertEq(txHash, l2TxHash); - uint256 depositedAmount = bridge.depositAmount(alice, address(token), dummyL2DepositTxHash); + uint256 depositedAmount = bridge.depositAmount(alice, address(token), l2TxHash); assertEq(amount, depositedAmount); } function test_legacyDepositSuccessfully() public { - uint256 depositedAmountBefore = bridge.depositAmount(alice, address(token), dummyL2DepositTxHash); + uint256 amount = 8; + bytes32 l2TxHash = keccak256("txHash"); + + uint256 depositedAmountBefore = bridge.depositAmount(alice, address(token), l2TxHash); assertEq(depositedAmountBefore, 0); - uint256 amount = 8; + vm.mockCall( + sharedBridgeAddress, + abi.encodeWithSelector( + IL1SharedBridge.depositLegacyErc20Bridge.selector, + alice, + randomSigner, + address(token), + amount, + 0, + 0, + address(0) + ), + abi.encode(l2TxHash) + ); + vm.prank(alice); token.approve(address(bridge), amount); vm.prank(alice); // solhint-disable-next-line func-named-parameters vm.expectEmit(true, true, true, true, address(bridge)); // solhint-disable-next-line func-named-parameters - emit DepositInitiated(dummyL2DepositTxHash, alice, randomSigner, address(token), amount); + emit DepositInitiated(l2TxHash, alice, randomSigner, address(token), amount); bytes32 txHash = bridge.deposit({ _l2Receiver: randomSigner, _l1Token: address(token), @@ -152,9 +188,9 @@ contract DepositTest is L1Erc20BridgeTest { _l2TxGasLimit: 0, _l2TxGasPerPubdataByte: 0 }); - assertEq(txHash, dummyL2DepositTxHash); + assertEq(txHash, l2TxHash); - uint256 depositedAmount = bridge.depositAmount(alice, address(token), dummyL2DepositTxHash); + uint256 depositedAmount = bridge.depositAmount(alice, address(token), l2TxHash); assertEq(amount, depositedAmount); } } diff --git a/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/FinalizeWithdrawal.sol b/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/FinalizeWithdrawal.sol index 830c77953..59cc80323 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/FinalizeWithdrawal.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/FinalizeWithdrawal.sol @@ -3,7 +3,9 @@ pragma solidity 0.8.24; import {L1Erc20BridgeTest} from "./_L1Erc20Bridge_Shared.t.sol"; +import {IL1SharedBridge} from "contracts/bridge/interfaces/IL1SharedBridge.sol"; import {StdStorage, stdStorage} from "forge-std/Test.sol"; +import {WithdrawalAlreadyFinalized} from "contracts/common/L1ContractErrors.sol"; contract FinalizeWithdrawalTest is L1Erc20BridgeTest { using stdStorage for StdStorage; @@ -22,7 +24,7 @@ contract FinalizeWithdrawalTest is L1Erc20BridgeTest { assertTrue(bridge.isWithdrawalFinalized(l2BatchNumber, l2MessageIndex)); - vm.expectRevert(bytes("pw")); + vm.expectRevert(WithdrawalAlreadyFinalized.selector); bytes32[] memory merkleProof; bridge.finalizeWithdrawal({ _l2BatchNumber: l2BatchNumber, @@ -36,17 +38,30 @@ contract FinalizeWithdrawalTest is L1Erc20BridgeTest { function test_finalizeWithdrawalSuccessfully() public { uint256 l2BatchNumber = 3; uint256 l2MessageIndex = 4; + uint256 txNumberInBatch = 0; + bytes32[] memory merkleProof; uint256 amount = 999; assertFalse(bridge.isWithdrawalFinalized(l2BatchNumber, l2MessageIndex)); - dummySharedBridge.setDataToBeReturnedInFinalizeWithdrawal(alice, address(token), amount); + vm.mockCall( + sharedBridgeAddress, + abi.encodeWithSelector( + IL1SharedBridge.finalizeWithdrawalLegacyErc20Bridge.selector, + l2BatchNumber, + l2MessageIndex, + txNumberInBatch, + "", + merkleProof + ), + abi.encode(alice, address(token), amount) + ); vm.prank(alice); // solhint-disable-next-line func-named-parameters vm.expectEmit(true, true, true, true, address(bridge)); emit WithdrawalFinalized(alice, address(token), amount); - bytes32[] memory merkleProof; + bridge.finalizeWithdrawal({ _l2BatchNumber: l2BatchNumber, _l2MessageIndex: l2MessageIndex, diff --git a/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/Initialization.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/Initialization.t.sol index 281ec169a..d3e5c9357 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/Initialization.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/Initialization.t.sol @@ -3,10 +3,11 @@ pragma solidity 0.8.24; import {L1Erc20BridgeTest} from "./_L1Erc20Bridge_Shared.t.sol"; +import {SlotOccupied} from "contracts/common/L1ContractErrors.sol"; contract InitializationTest is L1Erc20BridgeTest { function test_RevertWhen_DoubleInitialization() public { - vm.expectRevert(bytes("1B")); + vm.expectRevert(SlotOccupied.selector); bridge.initialize(); } } diff --git a/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/Reentrancy.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/Reentrancy.t.sol index 7a6183f93..528239434 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/Reentrancy.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/Reentrancy.t.sol @@ -5,6 +5,7 @@ pragma solidity 0.8.24; import {StdStorage, stdStorage} from "forge-std/Test.sol"; import {L1Erc20BridgeTest} from "./_L1Erc20Bridge_Shared.t.sol"; import {ReenterL1ERC20Bridge} from "contracts/dev-contracts/test/ReenterL1ERC20Bridge.sol"; +import {SlotOccupied, Reentrancy} from "contracts/common/L1ContractErrors.sol"; contract ReentrancyTest is L1Erc20BridgeTest { using stdStorage for StdStorage; @@ -15,7 +16,7 @@ contract ReentrancyTest is L1Erc20BridgeTest { token.approve(address(bridgeReenterItself), amount); vm.prank(alice); - vm.expectRevert(bytes("r1")); + vm.expectRevert(Reentrancy.selector); bridgeReenterItself.deposit({ _l2Receiver: randomSigner, _l1Token: address(token), @@ -32,7 +33,7 @@ contract ReentrancyTest is L1Erc20BridgeTest { token.approve(address(bridgeReenterItself), amount); vm.prank(alice); - vm.expectRevert(bytes("r1")); + vm.expectRevert(Reentrancy.selector); bridgeReenterItself.deposit({ _l2Receiver: randomSigner, _l1Token: address(token), @@ -49,16 +50,16 @@ contract ReentrancyTest is L1Erc20BridgeTest { .sig("depositAmount(address,address,bytes32)") .with_key(alice) .with_key(address(token)) - .with_key(dummyL2DepositTxHash) + .with_key(bytes32("")) .checked_write(amount); vm.prank(alice); bytes32[] memory merkleProof; - vm.expectRevert(bytes("r1")); + vm.expectRevert(Reentrancy.selector); bridgeReenterItself.claimFailedDeposit({ _depositSender: alice, _l1Token: address(token), - _l2TxHash: dummyL2DepositTxHash, + _l2TxHash: bytes32(""), _l2BatchNumber: 0, _l2MessageIndex: 0, _l2TxNumberInBatch: 0, @@ -71,7 +72,7 @@ contract ReentrancyTest is L1Erc20BridgeTest { uint256 l2MessageIndex = 4; vm.prank(alice); - vm.expectRevert(bytes("r1")); + vm.expectRevert(Reentrancy.selector); bytes32[] memory merkleProof; bridgeReenterItself.finalizeWithdrawal({ _l2BatchNumber: l2BatchNumber, diff --git a/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/_L1Erc20Bridge_Shared.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/_L1Erc20Bridge_Shared.t.sol index 6add8395e..25b617d3e 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/_L1Erc20Bridge_Shared.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridges/L1Erc20Bridge/_L1Erc20Bridge_Shared.t.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.17; +pragma solidity ^0.8.21; import {Test} from "forge-std/Test.sol"; @@ -8,13 +8,11 @@ import {L1ERC20Bridge} from "contracts/bridge/L1ERC20Bridge.sol"; import {IL1SharedBridge} from "contracts/bridge/interfaces/IL1SharedBridge.sol"; import {TestnetERC20Token} from "contracts/dev-contracts/TestnetERC20Token.sol"; import {FeeOnTransferToken} from "contracts/dev-contracts/FeeOnTransferToken.sol"; -import {DummySharedBridge} from "contracts/dev-contracts/test/DummySharedBridge.sol"; import {ReenterL1ERC20Bridge} from "contracts/dev-contracts/test/ReenterL1ERC20Bridge.sol"; import {Utils} from "../../Utils/Utils.sol"; contract L1Erc20BridgeTest is Test { L1ERC20Bridge internal bridge; - DummySharedBridge internal dummySharedBridge; ReenterL1ERC20Bridge internal reenterL1ERC20Bridge; L1ERC20Bridge internal bridgeReenterItself; @@ -23,15 +21,14 @@ contract L1Erc20BridgeTest is Test { TestnetERC20Token internal feeOnTransferToken; address internal randomSigner; address internal alice; - bytes32 internal dummyL2DepositTxHash; + address sharedBridgeAddress; constructor() { randomSigner = makeAddr("randomSigner"); - dummyL2DepositTxHash = Utils.randomBytes32("dummyL2DepositTxHash"); alice = makeAddr("alice"); - dummySharedBridge = new DummySharedBridge(dummyL2DepositTxHash); - bridge = new L1ERC20Bridge(IL1SharedBridge(address(dummySharedBridge))); + sharedBridgeAddress = makeAddr("shared bridge"); + bridge = new L1ERC20Bridge(IL1SharedBridge(sharedBridgeAddress)); reenterL1ERC20Bridge = new ReenterL1ERC20Bridge(); bridgeReenterItself = new L1ERC20Bridge(IL1SharedBridge(address(reenterL1ERC20Bridge))); diff --git a/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeFails.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeFails.t.sol index 97bbe2ec2..63eb02aca 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeFails.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/L1SharedBridgeFails.t.sol @@ -3,8 +3,8 @@ pragma solidity 0.8.24; import {L1SharedBridgeTest} from "./_L1SharedBridge_Shared.t.sol"; -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; import {ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; @@ -14,11 +14,12 @@ import {IMailbox} from "contracts/state-transition/chain-interfaces/IMailbox.sol import {IL1ERC20Bridge} from "contracts/bridge/interfaces/IL1ERC20Bridge.sol"; import {L2_BASE_TOKEN_SYSTEM_CONTRACT_ADDR} from "contracts/common/L2ContractAddresses.sol"; import {IGetters} from "contracts/state-transition/chain-interfaces/IGetters.sol"; +import {L2BridgeNotSet, L2WithdrawalMessageWrongLength, InsufficientChainBalance, ZeroAddress, ValueMismatch, NonEmptyMsgValue, DepositExists, ValueMismatch, NonEmptyMsgValue, TokenNotSupported, EmptyDeposit, L2BridgeNotDeployed, DepositIncorrectAmount, InvalidProof, NoFundsTransferred, InsufficientFunds, DepositDoesNotExist, WithdrawalAlreadyFinalized, InsufficientFunds, MalformedMessage, InvalidSelector, TokensWithFeesNotSupported} from "contracts/common/L1ContractErrors.sol"; /// We are testing all the specified revert and require cases. contract L1SharedBridgeFailTest is L1SharedBridgeTest { function test_initialize_wrongOwner() public { - vm.expectRevert("ShB owner 0"); + vm.expectRevert(ZeroAddress.selector); new TransparentUpgradeableProxy( address(sharedBridgeImpl), proxyAdmin, @@ -30,7 +31,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { function test_bridgehubDepositBaseToken_EthwrongMsgValue() public { vm.deal(bridgehubAddress, amount); vm.prank(bridgehubAddress); - vm.expectRevert("L1SharedBridge: msg.value not equal to amount"); + vm.expectRevert(abi.encodeWithSelector(ValueMismatch.selector, amount, uint256(0))); sharedBridge.bridgehubDepositBaseToken(chainId, alice, ETH_TOKEN_ADDRESS, amount); } @@ -40,7 +41,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { vm.prank(alice); token.approve(address(sharedBridge), amount); vm.prank(bridgehubAddress); - vm.expectRevert("ShB m.v > 0 b d.it"); + vm.expectRevert(NonEmptyMsgValue.selector); sharedBridge.bridgehubDepositBaseToken{value: amount}(chainId, alice, address(token), amount); } @@ -51,8 +52,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { vm.mockCall(address(token), abi.encodeWithSelector(IERC20.balanceOf.selector), abi.encode(10)); - bytes memory message = bytes("3T"); - vm.expectRevert(message); + vm.expectRevert(TokensWithFeesNotSupported.selector); vm.prank(bridgehubAddress); sharedBridge.bridgehubDepositBaseToken(chainId, alice, address(token), amount); } @@ -67,14 +67,14 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { abi.encodeWithSelector(IBridgehub.baseToken.selector), abi.encode(address(token)) ); - vm.expectRevert("ShB l2 bridge not deployed"); + vm.expectRevert(abi.encodeWithSelector(L2BridgeNotSet.selector, chainId)); // solhint-disable-next-line func-named-parameters sharedBridge.bridgehubDeposit{value: amount}(chainId, alice, 0, abi.encode(ETH_TOKEN_ADDRESS, 0, bob)); } function test_bridgehubDeposit_Erc_weth() public { vm.prank(bridgehubAddress); - vm.expectRevert("ShB: WETH deposit not supported"); + vm.expectRevert(abi.encodeWithSelector(TokenNotSupported.selector, l1WethAddress)); // solhint-disable-next-line func-named-parameters sharedBridge.bridgehubDeposit(chainId, alice, 0, abi.encode(l1WethAddress, amount, bob)); } @@ -86,7 +86,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { abi.encodeWithSelector(IBridgehub.baseToken.selector), abi.encode(ETH_TOKEN_ADDRESS) ); - vm.expectRevert("ShB: baseToken deposit not supported"); + vm.expectRevert(abi.encodeWithSelector(TokenNotSupported.selector, ETH_TOKEN_ADDRESS)); // solhint-disable-next-line func-named-parameters sharedBridge.bridgehubDeposit(chainId, alice, 0, abi.encode(ETH_TOKEN_ADDRESS, 0, bob)); } @@ -101,7 +101,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { abi.encodeWithSelector(IBridgehub.baseToken.selector), abi.encode(address(token)) ); - vm.expectRevert("ShB wrong withdraw amount"); + vm.expectRevert(abi.encodeWithSelector(DepositIncorrectAmount.selector, 0, amount)); // solhint-disable-next-line func-named-parameters sharedBridge.bridgehubDeposit(chainId, alice, 0, abi.encode(ETH_TOKEN_ADDRESS, amount, bob)); } @@ -117,7 +117,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { abi.encodeWithSelector(IBridgehub.baseToken.selector), abi.encode(ETH_TOKEN_ADDRESS) ); - vm.expectRevert("ShB m.v > 0 for BH d.it 2"); + vm.expectRevert(NonEmptyMsgValue.selector); // solhint-disable-next-line func-named-parameters sharedBridge.bridgehubDeposit{value: amount}(chainId, alice, 0, abi.encode(address(token), amount, bob)); } @@ -133,8 +133,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { abi.encode(ETH_TOKEN_ADDRESS) ); vm.mockCall(address(token), abi.encodeWithSelector(IERC20.balanceOf.selector), abi.encode(10)); - bytes memory message = bytes("5T"); - vm.expectRevert(message); + vm.expectRevert(abi.encodeWithSelector(DepositIncorrectAmount.selector, 0, amount)); // solhint-disable-next-line func-named-parameters sharedBridge.bridgehubDeposit(chainId, alice, 0, abi.encode(address(token), amount, bob)); } @@ -146,8 +145,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { abi.encodeWithSelector(IBridgehub.baseToken.selector), abi.encode(address(token)) ); - bytes memory message = bytes("6T"); - vm.expectRevert(message); + vm.expectRevert(EmptyDeposit.selector); // solhint-disable-next-line func-named-parameters sharedBridge.bridgehubDeposit(chainId, alice, 0, abi.encode(ETH_TOKEN_ADDRESS, 0, bob)); } @@ -156,7 +154,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { bytes32 txDataHash = keccak256(abi.encode(alice, address(token), amount)); _setSharedBridgeDepositHappened(chainId, txHash, txDataHash); vm.prank(bridgehubAddress); - vm.expectRevert("ShB tx hap"); + vm.expectRevert(DepositExists.selector); sharedBridge.bridgehubConfirmL2Transaction(chainId, txDataHash, txHash); } @@ -167,8 +165,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { abi.encode(address(0)) ); vm.prank(bridgehubAddress); - bytes memory message = bytes("yn"); - vm.expectRevert(message); + vm.expectRevert(InvalidProof.selector); sharedBridge.claimFailedDeposit({ _chainId: chainId, _depositSender: alice, @@ -201,8 +198,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { abi.encode(true) ); - bytes memory message = bytes("y1"); - vm.expectRevert(message); + vm.expectRevert(NoFundsTransferred.selector); sharedBridge.claimFailedDeposit({ _chainId: chainId, _depositSender: alice, @@ -235,7 +231,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { abi.encode(true) ); - vm.expectRevert("ShB: d.it not hap"); + vm.expectRevert(DepositDoesNotExist.selector); sharedBridge.claimFailedDeposit({ _chainId: chainId, _depositSender: alice, @@ -272,7 +268,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { abi.encode(true) ); - vm.expectRevert("ShB n funds"); + vm.expectRevert(InsufficientChainBalance.selector); sharedBridge.claimFailedDeposit({ _chainId: chainId, _depositSender: alice, @@ -303,7 +299,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { amount ); - vm.expectRevert("ShB: legacy withdrawal"); + vm.expectRevert(WithdrawalAlreadyFinalized.selector); sharedBridge.finalizeWithdrawal({ _chainId: eraChainId, _l2BatchNumber: legacyBatchNumber, @@ -347,7 +343,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { amount ); - vm.expectRevert("Withdrawal is already finalized"); + vm.expectRevert(WithdrawalAlreadyFinalized.selector); sharedBridge.finalizeWithdrawal({ _chainId: eraChainId, _l2BatchNumber: legacyBatchNumber, @@ -380,8 +376,8 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { address(token), amount ); - vm.expectRevert("Withdrawal is already finalized 2"); + vm.expectRevert(WithdrawalAlreadyFinalized.selector); sharedBridge.finalizeWithdrawal({ _chainId: eraChainId, _l2BatchNumber: legacyBatchNumber, @@ -422,8 +418,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { abi.encode(true) ); - vm.expectRevert("ShB not enough funds 2"); - + vm.expectRevert(InsufficientChainBalance.selector); sharedBridge.finalizeWithdrawal({ _chainId: chainId, _l2BatchNumber: l2BatchNumber, @@ -464,8 +459,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { abi.encode(false) ); - vm.expectRevert("ShB withd w proof"); - + vm.expectRevert(InvalidProof.selector); sharedBridge.finalizeWithdrawal({ _chainId: chainId, _l2BatchNumber: l2BatchNumber, @@ -487,7 +481,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { bytes memory message = abi.encodePacked(IMailbox.finalizeEthWithdrawal.selector); - vm.expectRevert("ShB wrong msg len"); + vm.expectRevert(abi.encodeWithSelector(L2WithdrawalMessageWrongLength.selector, message.length)); sharedBridge.finalizeWithdrawal({ _chainId: chainId, _l2BatchNumber: l2BatchNumber, @@ -510,8 +504,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { bytes memory message = abi.encodePacked(IL1ERC20Bridge.finalizeWithdrawal.selector, alice, amount); // should have more data here - vm.expectRevert("ShB wrong msg len 2"); - + vm.expectRevert(abi.encodeWithSelector(L2WithdrawalMessageWrongLength.selector, message.length)); sharedBridge.finalizeWithdrawal({ _chainId: eraChainId, _l2BatchNumber: l2BatchNumber, @@ -534,7 +527,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { // notice that the selector is wrong bytes memory message = abi.encodePacked(IMailbox.proveL2LogInclusion.selector, alice, amount); - vm.expectRevert("ShB Incorrect message function selector"); + vm.expectRevert(abi.encodeWithSelector(InvalidSelector.selector, IMailbox.proveL2LogInclusion.selector)); sharedBridge.finalizeWithdrawal({ _chainId: eraChainId, _l2BatchNumber: l2BatchNumber, @@ -553,7 +546,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { vm.prank(owner); sharedBridge.reinitializeChainGovernance(eraChainId, address(0)); - vm.expectRevert("ShB b. n dep"); + vm.expectRevert(abi.encodeWithSelector(L2BridgeNotSet.selector, eraChainId)); vm.prank(l1ERC20BridgeAddress); sharedBridge.depositLegacyErc20Bridge({ _prevMsgSender: alice, @@ -571,7 +564,7 @@ contract L1SharedBridgeFailTest is L1SharedBridgeTest { uint256 l2TxGasPerPubdataByte = 100; address refundRecipient = address(0); - vm.expectRevert("ShB: WETH deposit not supported 2"); + vm.expectRevert(abi.encodeWithSelector(TokenNotSupported.selector, l1WethAddress)); vm.prank(l1ERC20BridgeAddress); sharedBridge.depositLegacyErc20Bridge({ _prevMsgSender: alice, diff --git a/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/_L1SharedBridge_Shared.t.sol b/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/_L1SharedBridge_Shared.t.sol index 4554e4a36..1b785ae84 100644 --- a/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/_L1SharedBridge_Shared.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Bridges/L1SharedBridge/_L1SharedBridge_Shared.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.24; import {StdStorage, stdStorage} from "forge-std/Test.sol"; import {Test} from "forge-std/Test.sol"; -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; import {IBridgehub} from "contracts/bridgehub/IBridgehub.sol"; diff --git a/l1-contracts/test/foundry/unit/concrete/DiamondCut/FacetCut.t.sol b/l1-contracts/test/foundry/unit/concrete/DiamondCut/FacetCut.t.sol index adceecddb..0aee58ce7 100644 --- a/l1-contracts/test/foundry/unit/concrete/DiamondCut/FacetCut.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/DiamondCut/FacetCut.t.sol @@ -9,6 +9,7 @@ import {ExecutorFacet} from "contracts/state-transition/chain-deps/facets/Execut 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 {ReplaceFunctionFacetAddressZero, RemoveFunctionFacetAddressNotZero, FacetExists, SelectorsMustAllHaveSameFreezability, AddressHasNoCode, NonZeroAddress, ZeroAddress} from "contracts/common/L1ContractErrors.sol"; contract FacetCutTest is DiamondCutTest { MailboxFacet private mailboxFacet; @@ -88,7 +89,9 @@ contract FacetCutTest is DiamondCutTest { diamondCutTestContract.diamondCut(diamondCutData); - vm.expectRevert(abi.encodePacked("J")); + vm.expectRevert( + abi.encodeWithSelector(FacetExists.selector, Utils.getMailboxSelectors()[0], address(mailboxFacet)) + ); diamondCutTestContract.diamondCut(diamondCutData); } @@ -107,7 +110,7 @@ contract FacetCutTest is DiamondCutTest { initCalldata: bytes("") }); - vm.expectRevert(abi.encodePacked("G")); + vm.expectRevert(abi.encodeWithSelector(AddressHasNoCode.selector, address(0))); diamondCutTestContract.diamondCut(diamondCutData); } @@ -126,7 +129,7 @@ contract FacetCutTest is DiamondCutTest { initCalldata: bytes("") }); - vm.expectRevert(abi.encodePacked("L")); + vm.expectRevert(ReplaceFunctionFacetAddressZero.selector); diamondCutTestContract.diamondCut(diamondCutData); } @@ -145,7 +148,7 @@ contract FacetCutTest is DiamondCutTest { initCalldata: bytes("") }); - vm.expectRevert(abi.encodePacked("a1")); + vm.expectRevert(abi.encodeWithSelector(RemoveFunctionFacetAddressNotZero.selector, address(mailboxFacet))); diamondCutTestContract.diamondCut(diamondCutData); } @@ -288,7 +291,7 @@ contract FacetCutTest is DiamondCutTest { initCalldata: bytes("") }); - vm.expectRevert(abi.encodePacked("G")); + vm.expectRevert(abi.encodeWithSelector(AddressHasNoCode.selector, address(1))); diamondCutTestContract.diamondCut(diamondCutData1); } @@ -310,7 +313,7 @@ contract FacetCutTest is DiamondCutTest { initCalldata: bytes("") }); - vm.expectRevert(abi.encodePacked("K")); + vm.expectRevert(abi.encodeWithSelector(AddressHasNoCode.selector, address(1))); diamondCutTestContract.diamondCut(diamondCutData1); } @@ -341,7 +344,7 @@ contract FacetCutTest is DiamondCutTest { initCalldata: bytes("") }); - vm.expectRevert(abi.encodePacked("J1")); + vm.expectRevert(SelectorsMustAllHaveSameFreezability.selector); diamondCutTestContract.diamondCut(diamondCutData); } @@ -377,7 +380,7 @@ contract FacetCutTest is DiamondCutTest { initCalldata: bytes("") }); - vm.expectRevert(abi.encodePacked("J1")); + vm.expectRevert(SelectorsMustAllHaveSameFreezability.selector); diamondCutTestContract.diamondCut(diamondCutData); } diff --git a/l1-contracts/test/foundry/unit/concrete/DiamondCut/Initialization.t.sol b/l1-contracts/test/foundry/unit/concrete/DiamondCut/Initialization.t.sol index cbcb012a5..94996c5e1 100644 --- a/l1-contracts/test/foundry/unit/concrete/DiamondCut/Initialization.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/DiamondCut/Initialization.t.sol @@ -6,6 +6,7 @@ import {RevertFallback} from "contracts/dev-contracts/RevertFallback.sol"; import {ReturnSomething} from "contracts/dev-contracts/ReturnSomething.sol"; import {DiamondCutTestContract} from "contracts/dev-contracts/test/DiamondCutTestContract.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; +import {DelegateCallFailed, BadReturnData, MalformedCalldata, NonEmptyCalldata} from "contracts/common/L1ContractErrors.sol"; contract InitializationTest is DiamondCutTest { address private revertFallbackAddress; @@ -27,8 +28,8 @@ contract InitializationTest is DiamondCutTest { initAddress: revertFallbackAddress, initCalldata: bytes("") }); - - vm.expectRevert(abi.encodePacked("I")); + bytes memory emptyBytes; + vm.expectRevert(abi.encodeWithSelector(DelegateCallFailed.selector, emptyBytes)); diamondCutTestContract.diamondCut(diamondCutData); } @@ -40,8 +41,8 @@ contract InitializationTest is DiamondCutTest { initAddress: signerAddress, initCalldata: bytes("") }); - - vm.expectRevert(abi.encodePacked("lp")); + bytes memory emptyBytes; + vm.expectRevert(abi.encodeWithSelector(DelegateCallFailed.selector, emptyBytes)); diamondCutTestContract.diamondCut(diamondCutData); } @@ -54,7 +55,7 @@ contract InitializationTest is DiamondCutTest { initCalldata: bytes("0x11") }); - vm.expectRevert(abi.encodePacked("H")); + vm.expectRevert(NonEmptyCalldata.selector); diamondCutTestContract.diamondCut(diamondCutData); } @@ -66,8 +67,8 @@ contract InitializationTest is DiamondCutTest { initAddress: returnSomethingAddress, initCalldata: bytes("") }); - - vm.expectRevert(abi.encodePacked("lp1")); + bytes memory returnData = hex"0000000000000000000000000000000000000000000000000000000000000000"; + vm.expectRevert(abi.encodeWithSelector(DelegateCallFailed.selector, returnData)); diamondCutTestContract.diamondCut(diamondCutData); } } diff --git a/l1-contracts/test/foundry/unit/concrete/DiamondCut/UpgradeLogic.t.sol b/l1-contracts/test/foundry/unit/concrete/DiamondCut/UpgradeLogic.t.sol index 41c07d9a2..7a4badf5f 100644 --- a/l1-contracts/test/foundry/unit/concrete/DiamondCut/UpgradeLogic.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/DiamondCut/UpgradeLogic.t.sol @@ -14,6 +14,7 @@ import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {Utils} from "../Utils/Utils.sol"; import {InitializeData} from "contracts/state-transition/chain-deps/DiamondInit.sol"; import {DummyStateTransitionManager} from "contracts/dev-contracts/test/DummyStateTransitionManager.sol"; +import {DiamondAlreadyFrozen, Unauthorized, DiamondFreezeIncorrectState, DiamondNotFrozen} from "contracts/common/L1ContractErrors.sol"; contract UpgradeLogicTest is DiamondCutTest { DiamondProxy private diamondProxy; @@ -118,8 +119,7 @@ contract UpgradeLogicTest is DiamondCutTest { function test_RevertWhen_EmergencyFreezeWhenUnauthorizedGovernor() public { vm.startPrank(randomSigner); - - vm.expectRevert(abi.encodePacked("Hyperchain: not state transition manager")); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomSigner)); proxyAsAdmin.freezeDiamond(); } @@ -128,14 +128,14 @@ contract UpgradeLogicTest is DiamondCutTest { proxyAsAdmin.freezeDiamond(); - vm.expectRevert(abi.encodePacked("a9")); + vm.expectRevert(DiamondAlreadyFrozen.selector); proxyAsAdmin.freezeDiamond(); } function test_RevertWhen_UnfreezingWhenNotFrozen() public { vm.startPrank(stateTransitionManager); - vm.expectRevert(abi.encodePacked("a7")); + vm.expectRevert(DiamondNotFrozen.selector); proxyAsAdmin.unfreezeDiamond(); } diff --git a/l1-contracts/test/foundry/unit/concrete/Executor/Authorization.t.sol b/l1-contracts/test/foundry/unit/concrete/Executor/Authorization.t.sol index 498fb21a2..8cc19a11d 100644 --- a/l1-contracts/test/foundry/unit/concrete/Executor/Authorization.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Executor/Authorization.t.sol @@ -6,6 +6,7 @@ import {Utils} from "../Utils/Utils.sol"; import {ExecutorTest} from "./_Executor_Shared.t.sol"; import {IExecutor} from "contracts/state-transition/chain-interfaces/IExecutor.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; contract AuthorizationTest is ExecutorTest { IExecutor.StoredBatchInfo private storedBatchInfo; @@ -43,7 +44,7 @@ contract AuthorizationTest is ExecutorTest { vm.prank(randomSigner); - vm.expectRevert(bytes.concat("Hyperchain: not validator")); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomSigner)); executor.commitBatches(storedBatchInfo, commitBatchInfoArray); } @@ -53,7 +54,7 @@ contract AuthorizationTest is ExecutorTest { vm.prank(owner); - vm.expectRevert(bytes.concat("Hyperchain: not validator")); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, owner)); executor.proveBatches(storedBatchInfo, storedBatchInfoArray, proofInput); } @@ -63,7 +64,7 @@ contract AuthorizationTest is ExecutorTest { vm.prank(randomSigner); - vm.expectRevert(bytes.concat("Hyperchain: not validator")); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomSigner)); executor.executeBatches(storedBatchInfoArray); } } diff --git a/l1-contracts/test/foundry/unit/concrete/Executor/Committing.t.sol b/l1-contracts/test/foundry/unit/concrete/Executor/Committing.t.sol index ce3e5947c..eb64051c5 100644 --- a/l1-contracts/test/foundry/unit/concrete/Executor/Committing.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Executor/Committing.t.sol @@ -9,6 +9,7 @@ import {IExecutor, MAX_NUMBER_OF_BLOBS} from "contracts/state-transition/chain-i import {SystemLogKey} from "contracts/state-transition/chain-interfaces/IExecutor.sol"; import {POINT_EVALUATION_PRECOMPILE_ADDR} from "contracts/common/Config.sol"; import {L2_PUBDATA_CHUNK_PUBLISHER_ADDR} from "contracts/common/L2ContractAddresses.sol"; +import {TimeNotReached, BatchNumberMismatch, PubdataCommitmentsTooBig, InvalidPubdataCommitmentsSize, PubdataCommitmentsEmpty, L2TimestampTooBig, EmptyBlobVersionHash, CanOnlyProcessOneBatch, TimestampError, LogAlreadyProcessed, InvalidLogSender, UnexpectedSystemLog, HashMismatch, BatchHashMismatch, ValueMismatch, MissingSystemLogs, InvalidPubdataLength, NonEmptyBlobVersionHash, BlobHashCommitmentError} from "contracts/common/L1ContractErrors.sol"; contract CommittingTest is ExecutorTest { function test_RevertWhen_CommittingWithWrongLastCommittedBatchData() public { @@ -20,7 +21,13 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("i")); + vm.expectRevert( + abi.encodeWithSelector( + BatchHashMismatch.selector, + keccak256(abi.encode(genesisStoredBatchInfo)), + keccak256(abi.encode(wrongGenesisStoredBatchInfo)) + ) + ); executor.commitBatches(wrongGenesisStoredBatchInfo, newCommitBatchInfoArray); } @@ -33,7 +40,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("f")); + vm.expectRevert(abi.encodeWithSelector(BatchNumberMismatch.selector, uint256(1), uint256(2))); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } @@ -56,7 +63,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("tb")); + vm.expectRevert(TimestampError.selector); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } @@ -79,7 +86,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("h1")); + vm.expectRevert(abi.encodeWithSelector(TimeNotReached.selector, 1, 2)); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } @@ -102,7 +109,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("h2")); + vm.expectRevert(abi.encodeWithSelector(L2TimestampTooBig.selector)); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } @@ -124,7 +131,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("l")); + vm.expectRevert(abi.encodeWithSelector(HashMismatch.selector, wrongPreviousBatchHash, bytes32(0))); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } @@ -140,7 +147,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("b7")); + vm.expectRevert(abi.encodeWithSelector(MissingSystemLogs.selector, 8191, 8183)); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } @@ -166,7 +173,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("kp")); + vm.expectRevert(abi.encodeWithSelector(LogAlreadyProcessed.selector, 3)); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } @@ -188,7 +195,13 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("sc")); + vm.expectRevert( + abi.encodeWithSelector( + InvalidLogSender.selector, + address(0), + uint256(SystemLogKey.PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY) + ) + ); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } @@ -210,7 +223,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("t")); + vm.expectRevert(abi.encodeWithSelector(HashMismatch.selector, wrongChainedPriorityHash, keccak256(""))); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } @@ -232,7 +245,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("ta")); + vm.expectRevert(abi.encodeWithSelector(ValueMismatch.selector, uint256(bytes32(bytes1(0x01))), uint256(2))); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } @@ -245,14 +258,14 @@ contract CommittingTest is ExecutorTest { ); IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; - wrongNewCommitBatchInfo.systemLogs = abi.encodePacked(bytes4(0x00000008), wrongL2Logs); + wrongNewCommitBatchInfo.systemLogs = abi.encodePacked(wrongL2Logs); IExecutor.CommitBatchInfo[] memory wrongNewCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); wrongNewCommitBatchInfoArray[0] = wrongNewCommitBatchInfo; vm.prank(validator); - vm.expectRevert(bytes.concat("ul")); + vm.expectRevert(abi.encodeWithSelector(UnexpectedSystemLog.selector, uint256(119))); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } @@ -290,7 +303,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(errors[i]); + vm.expectRevert(abi.encodeWithSelector(InvalidLogSender.selector, wrongAddress, i)); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } } @@ -308,7 +321,8 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("b7")); + uint256 allLogsProcessed = uint256(8191); + vm.expectRevert(abi.encodeWithSelector(MissingSystemLogs.selector, 8191, allLogsProcessed ^ (1 << i))); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } } @@ -506,7 +520,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes("e4")); + vm.expectRevert(abi.encodeWithSelector(CanOnlyProcessOneBatch.selector)); executor.commitBatches(genesisStoredBatchInfo, correctCommitBatchInfoArray); } @@ -530,7 +544,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes("pl")); + vm.expectRevert(PubdataCommitmentsEmpty.selector); executor.commitBatches(genesisStoredBatchInfo, correctCommitBatchInfoArray); } @@ -555,7 +569,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes("bs")); + vm.expectRevert(InvalidPubdataCommitmentsSize.selector); executor.commitBatches(genesisStoredBatchInfo, correctCommitBatchInfoArray); } @@ -580,7 +594,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes("bd")); + vm.expectRevert(PubdataCommitmentsTooBig.selector); executor.commitBatches(genesisStoredBatchInfo, correctCommitBatchInfoArray); } @@ -624,7 +638,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes("lh")); + vm.expectRevert(abi.encodeWithSelector(NonEmptyBlobVersionHash.selector, uint256(1))); executor.commitBatches(genesisStoredBatchInfo, correctCommitBatchInfoArray); vm.clearMockedCalls(); @@ -661,7 +675,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes("vh")); + vm.expectRevert(abi.encodeWithSelector(EmptyBlobVersionHash.selector, 0)); executor.commitBatches(genesisStoredBatchInfo, correctCommitBatchInfoArray); vm.clearMockedCalls(); @@ -706,7 +720,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes("lh")); + vm.expectRevert(abi.encodeWithSelector(NonEmptyBlobVersionHash.selector, uint256(1))); executor.commitBatches(genesisStoredBatchInfo, correctCommitBatchInfoArray); vm.clearMockedCalls(); @@ -769,7 +783,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes("bh")); + vm.expectRevert(abi.encodeWithSelector(BlobHashCommitmentError.selector, uint256(1), true, false)); executor.commitBatches(genesisStoredBatchInfo, correctCommitBatchInfoArray); } @@ -819,7 +833,7 @@ contract CommittingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes("bh")); + vm.expectRevert(abi.encodeWithSelector(BlobHashCommitmentError.selector, uint256(1), false, true)); executor.commitBatches(genesisStoredBatchInfo, correctCommitBatchInfoArray); vm.clearMockedCalls(); diff --git a/l1-contracts/test/foundry/unit/concrete/Executor/Executing.t.sol b/l1-contracts/test/foundry/unit/concrete/Executor/Executing.t.sol index 3360150d5..288febf94 100644 --- a/l1-contracts/test/foundry/unit/concrete/Executor/Executing.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Executor/Executing.t.sol @@ -9,6 +9,7 @@ import {ExecutorTest} from "./_Executor_Shared.t.sol"; import {L2_BOOTLOADER_ADDRESS} from "contracts/common/L2ContractAddresses.sol"; import {COMMIT_TIMESTAMP_NOT_OLDER, REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol"; import {IExecutor, SystemLogKey} from "contracts/state-transition/chain-interfaces/IExecutor.sol"; +import {PriorityOperationsRollingHashMismatch, BatchHashMismatch, NonSequentialBatch, CantExecuteUnprovenBatches, QueueIsEmpty, TxHashMismatch} from "contracts/common/L1ContractErrors.sol"; contract ExecutingTest is ExecutorTest { function setUp() public { @@ -62,7 +63,7 @@ contract ExecutingTest is ExecutorTest { storedBatchInfoArray[0] = wrongNewStoredBatchInfo; vm.prank(validator); - vm.expectRevert(bytes.concat("k")); + vm.expectRevert(NonSequentialBatch.selector); executor.executeBatches(storedBatchInfoArray); } @@ -74,7 +75,13 @@ contract ExecutingTest is ExecutorTest { storedBatchInfoArray[0] = wrongNewStoredBatchInfo; vm.prank(validator); - vm.expectRevert(bytes.concat("exe10")); + vm.expectRevert( + abi.encodeWithSelector( + BatchHashMismatch.selector, + keccak256(abi.encode(newStoredBatchInfo)), + keccak256(abi.encode(wrongNewStoredBatchInfo)) + ) + ); executor.executeBatches(storedBatchInfoArray); } @@ -86,7 +93,7 @@ contract ExecutingTest is ExecutorTest { storedBatchInfoArray[0] = newStoredBatchInfo; vm.prank(validator); - vm.expectRevert(bytes.concat("n")); + vm.expectRevert(CantExecuteUnprovenBatches.selector); executor.executeBatches(storedBatchInfoArray); } @@ -143,7 +150,7 @@ contract ExecutingTest is ExecutorTest { executor.proveBatches(genesisStoredBatchInfo, correctNewStoredBatchInfoArray, proofInput); vm.prank(validator); - vm.expectRevert(bytes.concat("s")); + vm.expectRevert(QueueIsEmpty.selector); executor.executeBatches(correctNewStoredBatchInfoArray); } @@ -220,7 +227,7 @@ contract ExecutingTest is ExecutorTest { }); vm.prank(validator); - vm.expectRevert(bytes.concat("x")); + vm.expectRevert(PriorityOperationsRollingHashMismatch.selector); executor.executeBatches(correctNewStoredBatchInfoArray); } @@ -245,8 +252,12 @@ contract ExecutingTest is ExecutorTest { IExecutor.StoredBatchInfo memory genesisBlock = genesisStoredBatchInfo; genesisBlock.batchHash = wrongPreviousBatchHash; + bytes32 storedBatchHash = getters.storedBlockHash(1); + vm.prank(validator); - vm.expectRevert(bytes.concat("i")); + vm.expectRevert( + abi.encodeWithSelector(BatchHashMismatch.selector, storedBatchHash, keccak256(abi.encode(genesisBlock))) + ); executor.commitBatches(genesisBlock, correctNewCommitBatchInfoArray); } diff --git a/l1-contracts/test/foundry/unit/concrete/Executor/Proving.t.sol b/l1-contracts/test/foundry/unit/concrete/Executor/Proving.t.sol index 184de78e2..92f1878f8 100644 --- a/l1-contracts/test/foundry/unit/concrete/Executor/Proving.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Executor/Proving.t.sol @@ -8,6 +8,7 @@ import {ExecutorTest} from "./_Executor_Shared.t.sol"; import {COMMIT_TIMESTAMP_NOT_OLDER} from "contracts/common/Config.sol"; import {IExecutor, SystemLogKey} from "contracts/state-transition/chain-interfaces/IExecutor.sol"; +import {VerifiedBatchesExceedsCommittedBatches, BatchHashMismatch} from "contracts/common/L1ContractErrors.sol"; contract ProvingTest is ExecutorTest { function setUp() public { @@ -56,7 +57,13 @@ contract ProvingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("t1")); + vm.expectRevert( + abi.encodeWithSelector( + BatchHashMismatch.selector, + keccak256(abi.encode(genesisStoredBatchInfo)), + keccak256(abi.encode(wrongPreviousStoredBatchInfo)) + ) + ); executor.proveBatches(wrongPreviousStoredBatchInfo, storedBatchInfoArray, proofInput); } @@ -69,7 +76,13 @@ contract ProvingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("o1")); + vm.expectRevert( + abi.encodeWithSelector( + BatchHashMismatch.selector, + keccak256(abi.encode(newStoredBatchInfo)), + keccak256(abi.encode(wrongNewStoredBatchInfo)) + ) + ); executor.proveBatches(genesisStoredBatchInfo, storedBatchInfoArray, proofInput); } @@ -82,7 +95,7 @@ contract ProvingTest is ExecutorTest { vm.prank(validator); - vm.expectRevert(bytes.concat("q")); + vm.expectRevert(VerifiedBatchesExceedsCommittedBatches.selector); executor.proveBatches(genesisStoredBatchInfo, storedBatchInfoArray, proofInput); } diff --git a/l1-contracts/test/foundry/unit/concrete/Executor/Reverting.t.sol b/l1-contracts/test/foundry/unit/concrete/Executor/Reverting.t.sol index 9419c9dad..c6e3ea777 100644 --- a/l1-contracts/test/foundry/unit/concrete/Executor/Reverting.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Executor/Reverting.t.sol @@ -8,6 +8,7 @@ import {ExecutorTest} from "./_Executor_Shared.t.sol"; import {COMMIT_TIMESTAMP_NOT_OLDER} from "contracts/common/Config.sol"; import {IExecutor, SystemLogKey} from "contracts/state-transition/chain-interfaces/IExecutor.sol"; +import {RevertedBatchNotAfterNewLastBatch} from "contracts/common/L1ContractErrors.sol"; contract RevertingTest is ExecutorTest { function setUp() public { @@ -55,7 +56,7 @@ contract RevertingTest is ExecutorTest { function test_RevertWhen_RevertingMoreBatchesThanAlreadyCommitted() public { vm.prank(validator); - vm.expectRevert(bytes.concat("v1")); + vm.expectRevert(RevertedBatchNotAfterNewLastBatch.selector); executor.revertBatches(10); } diff --git a/l1-contracts/test/foundry/unit/concrete/Executor/_Executor_Shared.t.sol b/l1-contracts/test/foundry/unit/concrete/Executor/_Executor_Shared.t.sol index b96602f63..d81e9cc30 100644 --- a/l1-contracts/test/foundry/unit/concrete/Executor/_Executor_Shared.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Executor/_Executor_Shared.t.sol @@ -67,7 +67,7 @@ contract ExecutorTest is Test { } function getGettersSelectors() public view returns (bytes4[] memory) { - bytes4[] memory selectors = new bytes4[](28); + bytes4[] memory selectors = new bytes4[](29); selectors[0] = getters.getVerifier.selector; selectors[1] = getters.getAdmin.selector; selectors[2] = getters.getPendingAdmin.selector; @@ -96,6 +96,7 @@ contract ExecutorTest is Test { selectors[25] = getters.getTotalBatchesCommitted.selector; selectors[26] = getters.getTotalBatchesVerified.selector; selectors[27] = getters.getTotalBatchesExecuted.selector; + selectors[28] = getters.storedBlockHash.selector; return selectors; } diff --git a/l1-contracts/test/foundry/unit/concrete/Governance/Authorization.t.sol b/l1-contracts/test/foundry/unit/concrete/Governance/Authorization.t.sol index 540870032..5cc75bf06 100644 --- a/l1-contracts/test/foundry/unit/concrete/Governance/Authorization.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Governance/Authorization.t.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.24; import {GovernanceTest} from "./_Governance_Shared.t.sol"; import {IGovernance} from "contracts/governance/IGovernance.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; contract Authorization is GovernanceTest { function test_RevertWhen_SchedulingByUnauthorisedAddress() public { @@ -33,21 +34,21 @@ contract Authorization is GovernanceTest { function test_RevertWhen_ExecutingByUnauthorisedAddress() public { vm.prank(randomSigner); - vm.expectRevert("Only the owner and security council are allowed to call this function"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomSigner)); IGovernance.Operation memory op = operationWithOneCallZeroSaltAndPredecessor(address(eventOnFallback), 0, ""); governance.execute(op); } function test_RevertWhen_ExecutingInstantByUnauthorisedAddress() public { vm.prank(randomSigner); - vm.expectRevert("Only security council is allowed to call this function"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomSigner)); IGovernance.Operation memory op = operationWithOneCallZeroSaltAndPredecessor(address(eventOnFallback), 0, ""); governance.executeInstant(op); } function test_RevertWhen_ExecutingInstantByOwner() public { vm.prank(owner); - vm.expectRevert("Only security council is allowed to call this function"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, owner)); IGovernance.Operation memory op = operationWithOneCallZeroSaltAndPredecessor(address(eventOnFallback), 0, ""); governance.executeInstant(op); } @@ -60,37 +61,37 @@ contract Authorization is GovernanceTest { function test_RevertWhen_UpdateDelayByUnauthorisedAddress() public { vm.prank(randomSigner); - vm.expectRevert("Only governance contract itself is allowed to call this function"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomSigner)); governance.updateDelay(0); } function test_RevertWhen_UpdateDelayByOwner() public { vm.prank(owner); - vm.expectRevert("Only governance contract itself is allowed to call this function"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, owner)); governance.updateDelay(0); } function test_RevertWhen_UpdateDelayBySecurityCouncil() public { vm.prank(securityCouncil); - vm.expectRevert("Only governance contract itself is allowed to call this function"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, securityCouncil)); governance.updateDelay(0); } function test_RevertWhen_UpdateSecurityCouncilByUnauthorisedAddress() public { vm.prank(randomSigner); - vm.expectRevert("Only governance contract itself is allowed to call this function"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, randomSigner)); governance.updateSecurityCouncil(address(0)); } function test_RevertWhen_UpdateSecurityCouncilByOwner() public { vm.prank(owner); - vm.expectRevert("Only governance contract itself is allowed to call this function"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, owner)); governance.updateSecurityCouncil(address(0)); } function test_RevertWhen_UpdateSecurityCouncilBySecurityCouncil() public { vm.prank(securityCouncil); - vm.expectRevert("Only governance contract itself is allowed to call this function"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, securityCouncil)); governance.updateSecurityCouncil(address(0)); } } diff --git a/l1-contracts/test/foundry/unit/concrete/Governance/Executing.t.sol b/l1-contracts/test/foundry/unit/concrete/Governance/Executing.t.sol index 160cee2f6..9a1e5eeb2 100644 --- a/l1-contracts/test/foundry/unit/concrete/Governance/Executing.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Governance/Executing.t.sol @@ -7,6 +7,7 @@ import {Utils} from "../Utils/Utils.sol"; import {GovernanceTest} from "./_Governance_Shared.t.sol"; import {IGovernance} from "contracts/governance/IGovernance.sol"; +import {OperationMustBeReady, OperationMustBePending, OperationExists, PreviousOperationNotExecuted, InvalidDelay} from "contracts/common/L1ContractErrors.sol"; contract ExecutingTest is GovernanceTest { using stdStorage for StdStorage; @@ -51,7 +52,7 @@ contract ExecutingTest is GovernanceTest { vm.startPrank(owner); IGovernance.Operation memory op = operationWithOneCallZeroSaltAndPredecessor(address(eventOnFallback), 0, ""); governance.scheduleTransparent(op, 10000); - vm.expectRevert("Operation must be ready before execution"); + vm.expectRevert(OperationMustBeReady.selector); governance.execute(op); } @@ -65,7 +66,7 @@ contract ExecutingTest is GovernanceTest { governance.scheduleTransparent(validOp, 0); IGovernance.Operation memory invalidOp = operationWithOneCallZeroSaltAndPredecessor(address(0), 0, ""); - vm.expectRevert("Operation must be ready before execution"); + vm.expectRevert(OperationMustBeReady.selector); governance.execute(invalidOp); } @@ -83,7 +84,7 @@ contract ExecutingTest is GovernanceTest { 1, "" ); - vm.expectRevert("Operation must be ready before execution"); + vm.expectRevert(OperationMustBeReady.selector); governance.execute(invalidOp); } @@ -101,7 +102,7 @@ contract ExecutingTest is GovernanceTest { 0, "00" ); - vm.expectRevert("Operation must be ready before execution"); + vm.expectRevert(OperationMustBeReady.selector); governance.execute(invalidOp); } @@ -133,7 +134,7 @@ contract ExecutingTest is GovernanceTest { invalidOp.predecessor = governance.hashOperation(executedOp); // Failed to execute operation that wasn't scheduled - vm.expectRevert("Operation must be ready before execution"); + vm.expectRevert(OperationMustBeReady.selector); governance.execute(invalidOp); } @@ -152,7 +153,7 @@ contract ExecutingTest is GovernanceTest { "" ); invalidOp.salt = Utils.randomBytes32("wrongSalt"); - vm.expectRevert("Operation must be ready before execution"); + vm.expectRevert(OperationMustBeReady.selector); governance.execute(invalidOp); } @@ -166,7 +167,7 @@ contract ExecutingTest is GovernanceTest { ); invalidOp.predecessor = Utils.randomBytes32("randomPredecessor"); governance.scheduleTransparent(invalidOp, 0); - vm.expectRevert("Predecessor operation not completed"); + vm.expectRevert(PreviousOperationNotExecuted.selector); governance.execute(invalidOp); } @@ -181,7 +182,7 @@ contract ExecutingTest is GovernanceTest { governance.scheduleTransparent(op, 0); executeOpAndCheck(op); - vm.expectRevert("Operation must be ready before execution"); + vm.expectRevert(OperationMustBeReady.selector); governance.execute(op); } @@ -193,7 +194,7 @@ contract ExecutingTest is GovernanceTest { 0, "1122" ); - vm.expectRevert("Operation must be ready before execution"); + vm.expectRevert(OperationMustBeReady.selector); governance.execute(op); } @@ -205,7 +206,7 @@ contract ExecutingTest is GovernanceTest { 0, "1122" ); - vm.expectRevert("Operation must be pending before execution"); + vm.expectRevert(OperationMustBePending.selector); governance.executeInstant(op); } @@ -219,7 +220,7 @@ contract ExecutingTest is GovernanceTest { ); governance.scheduleTransparent(op, 0); governance.cancel(governance.hashOperation(op)); - vm.expectRevert("Operation must be ready before execution"); + vm.expectRevert(OperationMustBeReady.selector); governance.execute(op); } @@ -247,7 +248,7 @@ contract ExecutingTest is GovernanceTest { ); governance.scheduleTransparent(op, 0); executeOpAndCheck(op); - vm.expectRevert("Operation with this proposal id already exists"); + vm.expectRevert(OperationExists.selector); governance.scheduleTransparent(op, 0); } @@ -270,7 +271,7 @@ contract ExecutingTest is GovernanceTest { function test_RevertWhen_CancelNonExistingOperation() public { vm.startPrank(owner); - vm.expectRevert("Operation must be pending"); + vm.expectRevert(OperationMustBePending.selector); governance.cancel(bytes32(0)); } @@ -279,7 +280,7 @@ contract ExecutingTest is GovernanceTest { stdstore.target(address(governance)).sig(governance.minDelay.selector).checked_write(1000); IGovernance.Operation memory op = operationWithOneCallZeroSaltAndPredecessor(address(revertFallback), 0, ""); - vm.expectRevert("Proposed delay is less than minimum delay"); + vm.expectRevert(InvalidDelay.selector); governance.scheduleTransparent(op, 0); } } diff --git a/l1-contracts/test/foundry/unit/concrete/Governance/Reentrancy.t.sol b/l1-contracts/test/foundry/unit/concrete/Governance/Reentrancy.t.sol index 1076d1015..1f6beb10a 100644 --- a/l1-contracts/test/foundry/unit/concrete/Governance/Reentrancy.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Governance/Reentrancy.t.sol @@ -9,6 +9,7 @@ import {GovernanceTest} from "./_Governance_Shared.t.sol"; import {IGovernance} from "contracts/governance/IGovernance.sol"; import {ReenterGovernance} from "contracts/dev-contracts/test/ReenterGovernance.sol"; +import {OperationMustBeReady, OperationMustBePending} from "contracts/common/L1ContractErrors.sol"; contract ReentrancyTest is GovernanceTest { using stdStorage for StdStorage; @@ -88,7 +89,7 @@ contract ReentrancyTest is GovernanceTest { vm.startPrank(address(reenterGovernance)); governance.scheduleTransparent(op, 0); - vm.expectRevert("Operation must be ready after execution"); + vm.expectRevert(OperationMustBeReady.selector); governance.execute(op); } @@ -108,7 +109,7 @@ contract ReentrancyTest is GovernanceTest { vm.startPrank(address(reenterGovernance)); governance.scheduleTransparent(op, 0); - vm.expectRevert("Operation must be pending after execution"); + vm.expectRevert(OperationMustBePending.selector); governance.executeInstant(op); } @@ -125,7 +126,7 @@ contract ReentrancyTest is GovernanceTest { vm.startPrank(address(reenterGovernance)); governance.scheduleTransparent(op, 0); - vm.expectRevert("Operation must be ready after execution"); + vm.expectRevert(OperationMustBeReady.selector); governance.execute(op); } @@ -145,7 +146,7 @@ contract ReentrancyTest is GovernanceTest { vm.startPrank(address(reenterGovernance)); governance.scheduleTransparent(op, 0); - vm.expectRevert("Operation must be pending after execution"); + vm.expectRevert(OperationMustBePending.selector); governance.executeInstant(op); } } diff --git a/l1-contracts/test/foundry/unit/concrete/Utils/Utils.sol b/l1-contracts/test/foundry/unit/concrete/Utils/Utils.sol index b52d1e122..1260334fd 100644 --- a/l1-contracts/test/foundry/unit/concrete/Utils/Utils.sol +++ b/l1-contracts/test/foundry/unit/concrete/Utils/Utils.sol @@ -244,7 +244,7 @@ library Utils { } function getMailboxSelectors() public pure returns (bytes4[] memory) { - bytes4[] memory selectors = new bytes4[](7); + bytes4[] memory selectors = new bytes4[](8); selectors[0] = MailboxFacet.proveL2MessageInclusion.selector; selectors[1] = MailboxFacet.proveL2LogInclusion.selector; selectors[2] = MailboxFacet.proveL1ToL2TransactionStatus.selector; @@ -252,11 +252,12 @@ library Utils { selectors[4] = MailboxFacet.requestL2Transaction.selector; selectors[5] = MailboxFacet.bridgehubRequestL2Transaction.selector; selectors[6] = MailboxFacet.l2TransactionBaseCost.selector; + selectors[7] = MailboxFacet.transferEthToSharedBridge.selector; return selectors; } function getUtilsFacetSelectors() public pure returns (bytes4[] memory) { - bytes4[] memory selectors = new bytes4[](38); + bytes4[] memory selectors = new bytes4[](41); selectors[0] = UtilsFacet.util_setChainId.selector; selectors[1] = UtilsFacet.util_getChainId.selector; selectors[2] = UtilsFacet.util_setBridgehub.selector; @@ -295,6 +296,9 @@ library Utils { selectors[35] = UtilsFacet.util_getIsFrozen.selector; selectors[36] = UtilsFacet.util_setTransactionFilterer.selector; selectors[37] = UtilsFacet.util_setBaseTokenGasPriceMultiplierDenominator.selector; + selectors[38] = UtilsFacet.util_setTotalBatchesExecuted.selector; + selectors[39] = UtilsFacet.util_setL2LogsRootHash.selector; + selectors[40] = UtilsFacet.util_setBaseTokenGasPriceMultiplierNominator.selector; return selectors; } diff --git a/l1-contracts/test/foundry/unit/concrete/Utils/UtilsFacet.sol b/l1-contracts/test/foundry/unit/concrete/Utils/UtilsFacet.sol index 01864697d..ce9e659a0 100644 --- a/l1-contracts/test/foundry/unit/concrete/Utils/UtilsFacet.sol +++ b/l1-contracts/test/foundry/unit/concrete/Utils/UtilsFacet.sol @@ -162,6 +162,18 @@ contract UtilsFacet is ZkSyncHyperchainBase { return s.isFrozen; } + function util_setTotalBatchesExecuted(uint256 _numberOfBatches) external { + s.totalBatchesExecuted = _numberOfBatches; + } + + function util_setL2LogsRootHash(uint256 _batchNumber, bytes32 _newHash) external { + s.l2LogsRootHashes[_batchNumber] = _newHash; + } + + function util_setBaseTokenGasPriceMultiplierNominator(uint128 _nominator) external { + s.baseTokenGasPriceMultiplierNominator = _nominator; + } + // add this to be excluded from coverage report function test() internal virtual {} } diff --git a/l1-contracts/test/foundry/unit/concrete/ValidatorTimelock/ValidatorTimelock.t.sol b/l1-contracts/test/foundry/unit/concrete/ValidatorTimelock/ValidatorTimelock.t.sol index dacc45160..a2217cc13 100644 --- a/l1-contracts/test/foundry/unit/concrete/ValidatorTimelock/ValidatorTimelock.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/ValidatorTimelock/ValidatorTimelock.t.sol @@ -6,6 +6,7 @@ import {Utils} from "../Utils/Utils.sol"; import {ValidatorTimelock, IExecutor} from "contracts/state-transition/ValidatorTimelock.sol"; import {DummyStateTransitionManagerForValidatorTimelock} from "contracts/dev-contracts/test/DummyStateTransitionManagerForValidatorTimelock.sol"; import {IStateTransitionManager} from "contracts/state-transition/IStateTransitionManager.sol"; +import {Unauthorized, TimeNotReached} from "contracts/common/L1ContractErrors.sol"; contract ValidatorTimelockTest is Test { /// @notice A new validator has been added. @@ -270,7 +271,7 @@ contract ValidatorTimelockTest is Test { function test_RevertWhen_addValidatorNotAdmin() public { assert(validator.validators(chainId, bob) == false); - vm.expectRevert("ValidatorTimelock: only chain admin"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, address(this))); validator.addValidator(chainId, bob); assert(validator.validators(chainId, bob) == false); @@ -279,7 +280,7 @@ contract ValidatorTimelockTest is Test { function test_RevertWhen_removeValidatorNotAdmin() public { assert(validator.validators(chainId, alice) == true); - vm.expectRevert("ValidatorTimelock: only chain admin"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, address(this))); validator.removeValidator(chainId, alice); assert(validator.validators(chainId, alice) == true); @@ -309,7 +310,7 @@ contract ValidatorTimelockTest is Test { batchesToCommit[0] = batchToCommit; vm.prank(bob); - vm.expectRevert(bytes("ValidatorTimelock: only validator")); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, bob)); validator.commitBatches(storedBatch, batchesToCommit); } @@ -319,12 +320,12 @@ contract ValidatorTimelockTest is Test { } function test_RevertWhen_revertBatchesNotValidator() public { - vm.expectRevert("ValidatorTimelock: only validator"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, address(this))); validator.revertBatches(lastBatchNumber); } function test_RevertWhen_revertBatchesSharedBridgeNotValidator() public { - vm.expectRevert("ValidatorTimelock: only validator"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, address(this))); validator.revertBatchesSharedBridge(chainId, lastBatchNumber); } @@ -336,7 +337,7 @@ contract ValidatorTimelockTest is Test { IExecutor.StoredBatchInfo[] memory batchesToProve = new IExecutor.StoredBatchInfo[](1); batchesToProve[0] = batchToProve; - vm.expectRevert("ValidatorTimelock: only validator"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, address(this))); validator.proveBatches(prevBatch, batchesToProve, proof); } @@ -349,7 +350,7 @@ contract ValidatorTimelockTest is Test { batchesToProve[0] = batchToProve; vm.prank(bob); - vm.expectRevert("ValidatorTimelock: only validator"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, bob)); validator.proveBatchesSharedBridge(chainId, prevBatch, batchesToProve, proof); } @@ -360,7 +361,7 @@ contract ValidatorTimelockTest is Test { storedBatches[0] = storedBatch; vm.prank(bob); - vm.expectRevert("ValidatorTimelock: only validator"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, bob)); validator.executeBatches(storedBatches); } @@ -371,7 +372,7 @@ contract ValidatorTimelockTest is Test { storedBatches[0] = storedBatch; vm.prank(bob); - vm.expectRevert("ValidatorTimelock: only validator"); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, bob)); validator.executeBatchesSharedBridge(chainId, storedBatches); } @@ -400,7 +401,9 @@ contract ValidatorTimelockTest is Test { vm.prank(dan); vm.warp(timestamp + executionDelay - 1); - vm.expectRevert(bytes("5c")); + vm.expectRevert( + abi.encodeWithSelector(TimeNotReached.selector, timestamp + executionDelay, timestamp + executionDelay - 1) + ); validator.executeBatches(storedBatches); } @@ -429,7 +432,9 @@ contract ValidatorTimelockTest is Test { vm.prank(alice); vm.warp(timestamp + executionDelay - 1); - vm.expectRevert(bytes("5c")); + vm.expectRevert( + abi.encodeWithSelector(TimeNotReached.selector, timestamp + executionDelay, timestamp + executionDelay - 1) + ); validator.executeBatchesSharedBridge(chainId, storedBatches); } } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/CreateNewChain.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/CreateNewChain.t.sol index dc66d38b9..ba69c6bd7 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/CreateNewChain.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/CreateNewChain.t.sol @@ -3,21 +3,27 @@ pragma solidity 0.8.24; import {StateTransitionManagerTest} from "./_StateTransitionManager_Shared.t.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; +import {Unauthorized, HashMismatch} from "contracts/common/L1ContractErrors.sol"; contract createNewChainTest is StateTransitionManagerTest { function test_RevertWhen_InitialDiamondCutHashMismatch() public { Diamond.DiamondCutData memory initialDiamondCutData = getDiamondCutData(sharedBridge); - - vm.expectRevert(bytes("STM: initial cutHash mismatch")); - + Diamond.DiamondCutData memory correctDiamondCutData = getDiamondCutData(address(diamondInit)); + + vm.expectRevert( + abi.encodeWithSelector( + HashMismatch.selector, + keccak256(abi.encode(correctDiamondCutData)), + keccak256(abi.encode(initialDiamondCutData)) + ) + ); createNewChain(initialDiamondCutData); } function test_RevertWhen_CalledNotByBridgehub() public { Diamond.DiamondCutData memory initialDiamondCutData = getDiamondCutData(diamondInit); - vm.expectRevert(bytes("STM: only bridgehub")); - + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, governor)); chainContractAddress.createNewChain({ _chainId: chainId, _baseToken: baseToken, diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/FreezeChain.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/FreezeChain.t.sol index 590d5d4ab..1bf8c8a40 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/FreezeChain.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/FreezeChain.t.sol @@ -3,6 +3,8 @@ pragma solidity 0.8.24; import {StateTransitionManagerTest} from "./_StateTransitionManager_Shared.t.sol"; import {GettersFacet} from "contracts/state-transition/chain-deps/facets/Getters.sol"; +import {IAdmin} from "contracts/state-transition/chain-interfaces/IAdmin.sol"; +import {FacetIsFrozen} from "contracts/common/L1ContractErrors.sol"; contract freezeChainTest is StateTransitionManagerTest { function test_FreezingChain() public { @@ -19,11 +21,11 @@ contract freezeChainTest is StateTransitionManagerTest { chainContractAddress.freezeChain(block.chainid); // Repeated call should revert - vm.expectRevert(bytes.concat("q1")); // storage frozen + vm.expectRevert(bytes("q1")); // storage frozen chainContractAddress.freezeChain(block.chainid); // Call fails as storage is frozen - vm.expectRevert(bytes.concat("q1")); + vm.expectRevert(bytes("q1")); isChainFrozen = gettersFacet.isDiamondStorageFrozen(); } } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/StateTransitionOwnerZero.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/StateTransitionOwnerZero.t.sol index 8fae0aa1e..d8fb6e187 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/StateTransitionOwnerZero.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/StateTransitionOwnerZero.t.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.24; -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {StateTransitionManagerTest} from "./_StateTransitionManager_Shared.t.sol"; import {StateTransitionManager} from "contracts/state-transition/StateTransitionManager.sol"; import {StateTransitionManagerInitializeData, ChainCreationParams} from "contracts/state-transition/IStateTransitionManager.sol"; +import {ZeroAddress} from "contracts/common/L1ContractErrors.sol"; contract initializingSTMOwnerZeroTest is StateTransitionManagerTest { function test_InitializingSTMWithGovernorZeroShouldRevert() public { @@ -23,7 +24,7 @@ contract initializingSTMOwnerZeroTest is StateTransitionManagerTest { protocolVersion: 0 }); - vm.expectRevert(bytes("STM: owner zero")); + vm.expectRevert(ZeroAddress.selector); new TransparentUpgradeableProxy( address(stateTransitionManager), admin, diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/_StateTransitionManager_Shared.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/_StateTransitionManager_Shared.t.sol index 2cdbd8e00..999336642 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/_StateTransitionManager_Shared.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/StateTransitionManager/_StateTransitionManager_Shared.t.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; +pragma solidity ^0.8.21; import {Test} from "forge-std/Test.sol"; -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; import {Utils} from "foundry-test/unit/concrete/Utils/Utils.sol"; import {UtilsFacet} from "foundry-test/unit/concrete/Utils/UtilsFacet.sol"; @@ -18,6 +18,7 @@ import {InitializeDataNewChain} from "contracts/state-transition/chain-interface import {StateTransitionManager} from "contracts/state-transition/StateTransitionManager.sol"; import {StateTransitionManagerInitializeData, ChainCreationParams} from "contracts/state-transition/IStateTransitionManager.sol"; import {TestnetVerifier} from "contracts/state-transition/TestnetVerifier.sol"; +import {ZeroAddress} from "contracts/common/L1ContractErrors.sol"; contract StateTransitionManagerTest is Test { StateTransitionManager internal stateTransitionManager; @@ -93,7 +94,7 @@ contract StateTransitionManagerTest is Test { protocolVersion: 0 }); - vm.expectRevert(bytes.concat("STM: owner zero")); + vm.expectRevert(ZeroAddress.selector); new TransparentUpgradeableProxy( address(stateTransitionManager), admin, @@ -118,7 +119,7 @@ contract StateTransitionManagerTest is Test { vm.startPrank(governor); } - function getDiamondCutData(address _diamondInit) internal returns (Diamond.DiamondCutData memory) { + function getDiamondCutData(address _diamondInit) internal view returns (Diamond.DiamondCutData memory) { InitializeDataNewChain memory initializeData = Utils.makeInitializeDataForNewChain(testnetVerifier); bytes memory initCalldata = abi.encode(initializeData); diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/DiamondInit/Initialize.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/DiamondInit/Initialize.t.sol index 3c2b01dd5..205752a9f 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/DiamondInit/Initialize.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/DiamondInit/Initialize.t.sol @@ -11,6 +11,7 @@ import {DiamondProxy} from "contracts/state-transition/chain-deps/DiamondProxy.s 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 {MalformedCalldata, ZeroAddress, TooMuchGas} from "contracts/common/L1ContractErrors.sol"; contract InitializeTest is DiamondInitTest { function test_revertWhen_verifierIsZeroAddress() public { @@ -23,7 +24,7 @@ contract InitializeTest is DiamondInitTest { initCalldata: abi.encodeWithSelector(DiamondInit.initialize.selector, initializeData) }); - vm.expectRevert(bytes.concat("vt")); + vm.expectRevert(ZeroAddress.selector); new DiamondProxy(block.chainid, diamondCutData); } @@ -37,7 +38,7 @@ contract InitializeTest is DiamondInitTest { initCalldata: abi.encodeWithSelector(DiamondInit.initialize.selector, initializeData) }); - vm.expectRevert(bytes.concat("vy")); + vm.expectRevert(ZeroAddress.selector); new DiamondProxy(block.chainid, diamondCutData); } @@ -51,7 +52,7 @@ contract InitializeTest is DiamondInitTest { initCalldata: abi.encodeWithSelector(DiamondInit.initialize.selector, initializeData) }); - vm.expectRevert(bytes.concat("hc")); + vm.expectRevert(ZeroAddress.selector); new DiamondProxy(block.chainid, diamondCutData); } @@ -65,7 +66,7 @@ contract InitializeTest is DiamondInitTest { initCalldata: abi.encodeWithSelector(DiamondInit.initialize.selector, initializeData) }); - vm.expectRevert(bytes.concat("vu")); + vm.expectRevert(TooMuchGas.selector); new DiamondProxy(block.chainid, diamondCutData); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/DiamondProxy/DiamondProxy.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/DiamondProxy/DiamondProxy.t.sol index ba1ece9db..4637faabd 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/DiamondProxy/DiamondProxy.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/DiamondProxy/DiamondProxy.t.sol @@ -12,6 +12,7 @@ import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {DiamondProxy} from "contracts/state-transition/chain-deps/DiamondProxy.sol"; import {ZkSyncHyperchainBase} from "contracts/state-transition/chain-deps/facets/ZkSyncHyperchainBase.sol"; import {TestnetVerifier} from "contracts/state-transition/TestnetVerifier.sol"; +import {FacetIsFrozen, ValueMismatch, InvalidSelector} from "contracts/common/L1ContractErrors.sol"; contract TestFacet is ZkSyncHyperchainBase { function func() public pure returns (bool) { @@ -59,7 +60,7 @@ contract DiamondProxyTest is Test { initCalldata: abi.encodeWithSelector(DiamondInit.initialize.selector, initializeData) }); - vm.expectRevert(abi.encodePacked("pr")); + vm.expectRevert(bytes("pr")); new DiamondProxy(block.chainid + 1, diamondCutData); } @@ -107,7 +108,7 @@ contract DiamondProxyTest is Test { DiamondProxy diamondProxy = new DiamondProxy(block.chainid, diamondCutData); TestFacet testFacet = TestFacet(address(diamondProxy)); - vm.expectRevert(abi.encodePacked("F")); + vm.expectRevert(bytes("F")); testFacet.func(); } @@ -126,7 +127,7 @@ contract DiamondProxyTest is Test { utilsFacet.util_setIsFrozen(true); - vm.expectRevert(abi.encodePacked("q1")); + vm.expectRevert(bytes("q1")); testFacet.func(); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/AcceptAdmin.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/AcceptAdmin.t.sol index fe8c99db6..ab85ecdb0 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/AcceptAdmin.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/AcceptAdmin.t.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.24; import {AdminTest} from "./_Admin_Shared.t.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; contract AcceptAdminTest is AdminTest { event NewPendingAdmin(address indexed oldPendingAdmin, address indexed newPendingAdmin); @@ -11,9 +12,8 @@ contract AcceptAdminTest is AdminTest { function test_revertWhen_calledByNonPendingAdmin() public { address nonPendingAdmin = makeAddr("nonPendingAdmin"); - vm.expectRevert(bytes.concat("n4")); - vm.startPrank(nonPendingAdmin); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonPendingAdmin)); adminFacet.acceptAdmin(); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/ChangeFeeParams.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/ChangeFeeParams.t.sol index 1575af870..70324aabf 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/ChangeFeeParams.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/ChangeFeeParams.t.sol @@ -3,9 +3,9 @@ pragma solidity 0.8.24; import {AdminTest} from "./_Admin_Shared.t.sol"; -import {ERROR_ONLY_ADMIN_OR_STATE_TRANSITION_MANAGER} from "../Base/_Base_Shared.t.sol"; import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; +import {Unauthorized, PriorityTxPubdataExceedsMaxPubDataPerBatch} from "contracts/common/L1ContractErrors.sol"; contract ChangeFeeParamsTest is AdminTest { event NewFeeParams(FeeParams oldFeeParams, FeeParams newFeeParams); @@ -37,7 +37,7 @@ contract ChangeFeeParamsTest is AdminTest { }); vm.startPrank(nonStateTransitionManager); - vm.expectRevert(ERROR_ONLY_ADMIN_OR_STATE_TRANSITION_MANAGER); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonStateTransitionManager)); adminFacet.changeFeeParams(newFeeParams); } @@ -55,7 +55,7 @@ contract ChangeFeeParamsTest is AdminTest { minimalL2GasPrice: 250_000_000 }); - vm.expectRevert(bytes.concat("n6")); + vm.expectRevert(PriorityTxPubdataExceedsMaxPubDataPerBatch.selector); vm.startPrank(stateTransitionManager); adminFacet.changeFeeParams(newFeeParams); diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/ExecuteUpgrade.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/ExecuteUpgrade.t.sol index 95c6f54af..d09b6f204 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/ExecuteUpgrade.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/ExecuteUpgrade.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.24; import {AdminTest} from "./_Admin_Shared.t.sol"; -import {ERROR_ONLY_STATE_TRANSITION_MANAGER} from "../Base/_Base_Shared.t.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; import {Utils} from "../../../../Utils/Utils.sol"; import {VerifierParams} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; @@ -23,7 +23,7 @@ contract ExecuteUpgradeTest is AdminTest { initCalldata: new bytes(0) }); - vm.expectRevert(ERROR_ONLY_STATE_TRANSITION_MANAGER); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonStateTransitionManager)); vm.startPrank(nonStateTransitionManager); adminFacet.executeUpgrade(diamondCutData); diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/FreezeDiamond.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/FreezeDiamond.t.sol index 8e79f4fc3..77baed0ef 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/FreezeDiamond.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/FreezeDiamond.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.24; import {AdminTest} from "./_Admin_Shared.t.sol"; -import {ERROR_ONLY_STATE_TRANSITION_MANAGER} from "../Base/_Base_Shared.t.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; contract FreezeDiamondTest is AdminTest { event Freeze(); @@ -11,7 +11,7 @@ contract FreezeDiamondTest is AdminTest { function test_revertWhen_calledByNonStateTransitionManager() public { address nonStateTransitionManager = makeAddr("nonStateTransitionManager"); - vm.expectRevert(ERROR_ONLY_STATE_TRANSITION_MANAGER); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonStateTransitionManager)); vm.startPrank(nonStateTransitionManager); adminFacet.freezeDiamond(); diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetPendingGovernor.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetPendingGovernor.t.sol index 8dbc12bbd..359e9ce8c 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetPendingGovernor.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetPendingGovernor.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.24; import {AdminTest} from "./_Admin_Shared.t.sol"; -import {ERROR_ONLY_ADMIN} from "../Base/_Base_Shared.t.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; contract SetPendingAdminTest is AdminTest { event NewPendingAdmin(address indexed oldPendingAdmin, address indexed newPendingAdmin); @@ -12,8 +12,7 @@ contract SetPendingAdminTest is AdminTest { address nonAdmin = makeAddr("nonAdmin"); address newPendingAdmin = makeAddr("newPendingAdmin"); - vm.expectRevert(ERROR_ONLY_ADMIN); - + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonAdmin)); vm.startPrank(nonAdmin); adminFacet.setPendingAdmin(newPendingAdmin); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetPorterAvailability.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetPorterAvailability.t.sol index 94e209a15..ad0708f11 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetPorterAvailability.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetPorterAvailability.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.24; import {AdminTest} from "./_Admin_Shared.t.sol"; -import {ERROR_ONLY_STATE_TRANSITION_MANAGER} from "../Base/_Base_Shared.t.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; contract SetPorterAvailabilityTest is AdminTest { event IsPorterAvailableStatusUpdate(bool isPorterAvailable); @@ -12,9 +12,8 @@ contract SetPorterAvailabilityTest is AdminTest { address nonStateTransitionManager = makeAddr("nonStateTransitionManager"); bool isPorterAvailable = true; - vm.expectRevert(ERROR_ONLY_STATE_TRANSITION_MANAGER); - vm.startPrank(nonStateTransitionManager); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonStateTransitionManager)); adminFacet.setPorterAvailability(isPorterAvailable); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetPriorityTxMaxGasLimit.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetPriorityTxMaxGasLimit.t.sol index 8ce9e4092..5581420fe 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetPriorityTxMaxGasLimit.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetPriorityTxMaxGasLimit.t.sol @@ -3,9 +3,9 @@ pragma solidity 0.8.24; import {AdminTest} from "./_Admin_Shared.t.sol"; -import {ERROR_ONLY_STATE_TRANSITION_MANAGER} from "../Base/_Base_Shared.t.sol"; import {MAX_GAS_PER_TRANSACTION} from "contracts/common/Config.sol"; +import {Unauthorized, TooMuchGas} from "contracts/common/L1ContractErrors.sol"; contract SetPriorityTxMaxGasLimitTest is AdminTest { event NewPriorityTxMaxGasLimit(uint256 oldPriorityTxMaxGasLimit, uint256 newPriorityTxMaxGasLimit); @@ -15,8 +15,7 @@ contract SetPriorityTxMaxGasLimitTest is AdminTest { uint256 newPriorityTxMaxGasLimit = 100; vm.startPrank(nonStateTransitionManager); - vm.expectRevert(ERROR_ONLY_STATE_TRANSITION_MANAGER); - + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonStateTransitionManager)); adminFacet.setPriorityTxMaxGasLimit(newPriorityTxMaxGasLimit); } @@ -24,9 +23,8 @@ contract SetPriorityTxMaxGasLimitTest is AdminTest { address stateTransitionManager = utilsFacet.util_getStateTransitionManager(); uint256 newPriorityTxMaxGasLimit = MAX_GAS_PER_TRANSACTION + 1; - vm.expectRevert(bytes.concat("n5")); - vm.startPrank(stateTransitionManager); + vm.expectRevert(TooMuchGas.selector); adminFacet.setPriorityTxMaxGasLimit(newPriorityTxMaxGasLimit); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetTransactionFilterer.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetTransactionFilterer.t.sol index 5a8ac9a2b..8581ec6c4 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetTransactionFilterer.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetTransactionFilterer.t.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.24; import {AdminTest} from "./_Admin_Shared.t.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; contract SetTransactionFiltererTest is AdminTest { event NewTransactionFilterer(address oldTransactionFilterer, address newTransactionFilterer); @@ -34,10 +35,11 @@ contract SetTransactionFiltererTest is AdminTest { } function test_revertWhen_notAdmin() public { + address nonAdmin = makeAddr("nonAdmin"); address transactionFilterer = makeAddr("transactionFilterer"); - vm.expectRevert("Hyperchain: not admin"); - vm.startPrank(makeAddr("nonAdmin")); + vm.startPrank(nonAdmin); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonAdmin)); adminFacet.setTransactionFilterer(transactionFilterer); } } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetValidator.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetValidator.t.sol index 3452ed132..77990a285 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetValidator.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/SetValidator.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.24; import {AdminTest} from "./_Admin_Shared.t.sol"; -import {ERROR_ONLY_STATE_TRANSITION_MANAGER} from "../Base/_Base_Shared.t.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; contract SetValidatorTest is AdminTest { event ValidatorStatusUpdate(address indexed validatorAddress, bool isActive); @@ -13,9 +13,8 @@ contract SetValidatorTest is AdminTest { address validator = makeAddr("validator"); bool isActive = true; - vm.expectRevert(ERROR_ONLY_STATE_TRANSITION_MANAGER); - vm.startPrank(nonStateTransitionManager); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonStateTransitionManager)); adminFacet.setValidator(validator, isActive); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/UnfreezeDiamond.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/UnfreezeDiamond.t.sol index b7f1fa124..e0da9d6dc 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/UnfreezeDiamond.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/UnfreezeDiamond.t.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.24; import {AdminTest} from "./_Admin_Shared.t.sol"; -import {ERROR_ONLY_STATE_TRANSITION_MANAGER} from "../Base/_Base_Shared.t.sol"; +import {Unauthorized, DiamondFreezeIncorrectState, DiamondNotFrozen} from "contracts/common/L1ContractErrors.sol"; contract UnfreezeDiamondTest is AdminTest { event Unfreeze(); @@ -11,8 +11,7 @@ contract UnfreezeDiamondTest is AdminTest { function test_revertWhen_calledByNonStateTransitionManager() public { address nonStateTransitionManager = makeAddr("nonStateTransitionManager"); - vm.expectRevert(ERROR_ONLY_STATE_TRANSITION_MANAGER); - + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonStateTransitionManager)); vm.startPrank(nonStateTransitionManager); adminFacet.unfreezeDiamond(); } @@ -22,7 +21,7 @@ contract UnfreezeDiamondTest is AdminTest { utilsFacet.util_setIsFrozen(false); - vm.expectRevert(bytes.concat("a7")); + vm.expectRevert(DiamondNotFrozen.selector); vm.startPrank(admin); adminFacet.unfreezeDiamond(); diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/UpgradeChainFromVersion.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/UpgradeChainFromVersion.t.sol index 3e2155995..9e6efc1e5 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/UpgradeChainFromVersion.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Admin/UpgradeChainFromVersion.t.sol @@ -3,10 +3,10 @@ pragma solidity 0.8.24; import {AdminTest} from "./_Admin_Shared.t.sol"; -import {ERROR_ONLY_ADMIN_OR_STATE_TRANSITION_MANAGER} from "../Base/_Base_Shared.t.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {IStateTransitionManager} from "contracts/state-transition/IStateTransitionManager.sol"; +import {ProtocolIdMismatch, ProtocolIdNotGreater, InvalidProtocolVersion, ValueMismatch, Unauthorized, HashMismatch} from "contracts/common/L1ContractErrors.sol"; contract UpgradeChainFromVersionTest is AdminTest { event ExecuteUpgrade(Diamond.DiamondCutData diamondCut); @@ -20,9 +20,8 @@ contract UpgradeChainFromVersionTest is AdminTest { initCalldata: new bytes(0) }); - vm.expectRevert(ERROR_ONLY_ADMIN_OR_STATE_TRANSITION_MANAGER); - vm.startPrank(nonAdminOrStateTransitionManager); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonAdminOrStateTransitionManager)); adminFacet.upgradeChainFromVersion(oldProtocolVersion, diamondCutData); } @@ -46,9 +45,10 @@ contract UpgradeChainFromVersionTest is AdminTest { abi.encode(cutHashInput) ); - vm.expectRevert("AdminFacet: cutHash mismatch"); - vm.startPrank(admin); + vm.expectRevert( + abi.encodeWithSelector(HashMismatch.selector, cutHashInput, keccak256(abi.encode(diamondCutData))) + ); adminFacet.upgradeChainFromVersion(oldProtocolVersion, diamondCutData); } @@ -73,9 +73,8 @@ contract UpgradeChainFromVersionTest is AdminTest { abi.encode(cutHashInput) ); - vm.expectRevert("AdminFacet: protocolVersion mismatch in STC when upgrading"); - vm.startPrank(admin); + vm.expectRevert(abi.encodeWithSelector(ProtocolIdMismatch.selector, uint256(2), oldProtocolVersion)); adminFacet.upgradeChainFromVersion(oldProtocolVersion, diamondCutData); } @@ -100,8 +99,7 @@ contract UpgradeChainFromVersionTest is AdminTest { abi.encode(cutHashInput) ); - vm.expectRevert("AdminFacet: protocolVersion mismatch in STC after upgrading"); - + vm.expectRevert(ProtocolIdNotGreater.selector); // solhint-disable-next-line func-named-parameters vm.expectEmit(true, true, true, true, address(adminFacet)); emit ExecuteUpgrade(diamondCutData); diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyBridgehub.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyBridgehub.t.sol index c484a38bb..af92cde5f 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyBridgehub.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyBridgehub.t.sol @@ -2,14 +2,14 @@ pragma solidity 0.8.24; -import {ZkSyncHyperchainBaseTest, ERROR_ONLY_BRIDGEHUB} from "./_Base_Shared.t.sol"; +import {ZkSyncHyperchainBaseTest} from "./_Base_Shared.t.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; contract OnlyBridgehubTest is ZkSyncHyperchainBaseTest { function test_revertWhen_calledByNonBridgehub() public { address nonBridgehub = makeAddr("nonBridgehub"); - vm.expectRevert(ERROR_ONLY_BRIDGEHUB); - + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonBridgehub)); vm.startPrank(nonBridgehub); testBaseFacet.functionWithOnlyBridgehubModifier(); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyGovernor.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyGovernor.t.sol index ba5199f92..44c397c85 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyGovernor.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyGovernor.t.sol @@ -2,14 +2,14 @@ pragma solidity 0.8.24; -import {ZkSyncHyperchainBaseTest, ERROR_ONLY_ADMIN} from "./_Base_Shared.t.sol"; +import {ZkSyncHyperchainBaseTest} from "./_Base_Shared.t.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; contract OnlyAdminTest is ZkSyncHyperchainBaseTest { function test_revertWhen_calledByNonAdmin() public { address nonAdmin = makeAddr("nonAdmin"); - vm.expectRevert(ERROR_ONLY_ADMIN); - + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonAdmin)); vm.startPrank(nonAdmin); testBaseFacet.functionWithOnlyAdminModifier(); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyGovernorOrStateTransitionManager.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyGovernorOrStateTransitionManager.t.sol index da2d6fccf..2c4062d5b 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyGovernorOrStateTransitionManager.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyGovernorOrStateTransitionManager.t.sol @@ -2,14 +2,14 @@ pragma solidity 0.8.24; -import {ZkSyncHyperchainBaseTest, ERROR_ONLY_ADMIN_OR_STATE_TRANSITION_MANAGER} from "./_Base_Shared.t.sol"; +import {ZkSyncHyperchainBaseTest} from "./_Base_Shared.t.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; contract OnlyAdminOrStateTransitionManagerTest is ZkSyncHyperchainBaseTest { function test_revertWhen_calledByNonAdmin() public { address nonAdmin = makeAddr("nonAdmin"); - vm.expectRevert(ERROR_ONLY_ADMIN_OR_STATE_TRANSITION_MANAGER); - + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonAdmin)); vm.startPrank(nonAdmin); testBaseFacet.functionWithOnlyAdminOrStateTransitionManagerModifier(); } @@ -17,8 +17,7 @@ contract OnlyAdminOrStateTransitionManagerTest is ZkSyncHyperchainBaseTest { function test_revertWhen_calledByNonStateTransitionManager() public { address nonStateTransitionManager = makeAddr("nonStateTransitionManager"); - vm.expectRevert(ERROR_ONLY_ADMIN_OR_STATE_TRANSITION_MANAGER); - + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonStateTransitionManager)); vm.startPrank(nonStateTransitionManager); testBaseFacet.functionWithOnlyAdminOrStateTransitionManagerModifier(); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyStateTransitionManager.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyStateTransitionManager.t.sol index f6aafb661..a93032c90 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyStateTransitionManager.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyStateTransitionManager.t.sol @@ -2,14 +2,14 @@ pragma solidity 0.8.24; -import {ZkSyncHyperchainBaseTest, ERROR_ONLY_STATE_TRANSITION_MANAGER} from "./_Base_Shared.t.sol"; +import {ZkSyncHyperchainBaseTest} from "./_Base_Shared.t.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; contract OnlyStateTransitionManagerTest is ZkSyncHyperchainBaseTest { function test_revertWhen_calledByNonStateTransitionManager() public { address nonStateTransitionManager = makeAddr("nonStateTransitionManager"); - vm.expectRevert(ERROR_ONLY_STATE_TRANSITION_MANAGER); - + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonStateTransitionManager)); vm.startPrank(nonStateTransitionManager); testBaseFacet.functionWithOnlyStateTransitionManagerModifier(); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyValidator.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyValidator.t.sol index c834dd982..c002fec59 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyValidator.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Base/OnlyValidator.t.sol @@ -2,7 +2,8 @@ pragma solidity 0.8.24; -import {ZkSyncHyperchainBaseTest, ERROR_ONLY_VALIDATOR} from "./_Base_Shared.t.sol"; +import {ZkSyncHyperchainBaseTest} from "./_Base_Shared.t.sol"; +import {Unauthorized} from "contracts/common/L1ContractErrors.sol"; contract OnlyValidatorTest is ZkSyncHyperchainBaseTest { function test_revertWhen_calledByNonValidator() public { @@ -10,8 +11,7 @@ contract OnlyValidatorTest is ZkSyncHyperchainBaseTest { utilsFacet.util_setValidator(nonValidator, false); - vm.expectRevert(ERROR_ONLY_VALIDATOR); - + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, nonValidator)); vm.startPrank(nonValidator); testBaseFacet.functionWithOnlyValidatorModifier(); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Getters/IsFunctionFreezable.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Getters/IsFunctionFreezable.t.sol index 0b257db68..4af9875e2 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Getters/IsFunctionFreezable.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Getters/IsFunctionFreezable.t.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.24; import {GettersFacetTest} from "./_Getters_Shared.t.sol"; +import {InvalidSelector} from "contracts/common/L1ContractErrors.sol"; contract IsFunctionFreezableTest is GettersFacetTest { function test_revertWhen_facetAddressIzZero() public { @@ -11,8 +12,7 @@ contract IsFunctionFreezableTest is GettersFacetTest { gettersFacetWrapper.util_setFacetAddress(selector, address(0)); - vm.expectRevert(bytes.concat("g2")); - + vm.expectRevert(abi.encodeWithSelector(InvalidSelector.selector, selector)); gettersFacet.isFunctionFreezable(selector); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Getters/PriorityQueueFrontOperation.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Getters/PriorityQueueFrontOperation.t.sol index d17577afc..ac8ccfeaa 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Getters/PriorityQueueFrontOperation.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Getters/PriorityQueueFrontOperation.t.sol @@ -4,10 +4,11 @@ pragma solidity 0.8.24; import {GettersFacetTest} from "./_Getters_Shared.t.sol"; import {PriorityOperation} from "contracts/state-transition/libraries/PriorityQueue.sol"; +import {QueueIsEmpty} from "contracts/common/L1ContractErrors.sol"; contract GetPriorityQueueFrontOperationTest is GettersFacetTest { function test_revertWhen_queueIsEmpty() public { - vm.expectRevert(bytes.concat("D")); + vm.expectRevert(QueueIsEmpty.selector); gettersFacet.priorityQueueFrontOperation(); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/BaseMailboxTests.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/BaseMailboxTests.t.sol new file mode 100644 index 000000000..54ab2a135 --- /dev/null +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/BaseMailboxTests.t.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import {MailboxTest} from "./_Mailbox_Shared.t.sol"; +import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; +import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol"; +import {DummyHyperchain} from "contracts/dev-contracts/test/DummyHyperchain.sol"; +import {BaseTokenGasPriceDenominatorNotSet} from "contracts/common/L1ContractErrors.sol"; + +contract MailboxBaseTests is MailboxTest { + function setUp() public virtual { + setupDiamondProxy(); + utilsFacet.util_setBaseTokenGasPriceMultiplierDenominator(1); + utilsFacet.util_setBaseTokenGasPriceMultiplierNominator(1); + } + + function test_mailboxConstructor() public { + DummyHyperchain h = new DummyHyperchain(address(0), eraChainId); + assertEq(h.getEraChainId(), eraChainId); + } + + function test_RevertWhen_badDenominatorInL2TransactionBaseCost() public { + utilsFacet.util_setBaseTokenGasPriceMultiplierDenominator(0); + vm.expectRevert(BaseTokenGasPriceDenominatorNotSet.selector); + mailboxFacet.l2TransactionBaseCost(100, 10000, REQUIRED_L2_GAS_PRICE_PER_PUBDATA); + } + + function test_successful_getL2TransactionBaseCostPricingModeValidium() public { + uint256 gasPrice = 10000000; + uint256 l2GasLimit = 1000000; + uint256 l2GasPerPubdataByteLimit = REQUIRED_L2_GAS_PRICE_PER_PUBDATA; + + FeeParams memory feeParams = FeeParams({ + pubdataPricingMode: PubdataPricingMode.Validium, + batchOverheadL1Gas: 1000000, + maxPubdataPerBatch: 120000, + maxL2GasPerBatch: 80000000, + priorityTxMaxPubdata: 99000, + minimalL2GasPrice: 250000000 + }); + + utilsFacet.util_setFeeParams(feeParams); + + // this was get from running the function, but more reasonable would be to + // have some invariants that the calculation should keep for min required gas + // price and also gas limit + uint256 l2TransactionBaseCost = 250125000000000; + + assertEq( + mailboxFacet.l2TransactionBaseCost(gasPrice, l2GasLimit, l2GasPerPubdataByteLimit), + l2TransactionBaseCost + ); + } + + function test_successful_getL2TransactionBaseCostPricingModeRollup() public { + uint256 gasPrice = 10000000; + uint256 l2GasLimit = 1000000; + uint256 l2GasPerPubdataByteLimit = REQUIRED_L2_GAS_PRICE_PER_PUBDATA; + + FeeParams memory feeParams = FeeParams({ + pubdataPricingMode: PubdataPricingMode.Rollup, + batchOverheadL1Gas: 1000000, + maxPubdataPerBatch: 120000, + maxL2GasPerBatch: 80000000, + priorityTxMaxPubdata: 99000, + minimalL2GasPrice: 250000000 + }); + + utilsFacet.util_setFeeParams(feeParams); + + // this was get from running the function, but more reasonable would be to + // have some invariants that the calculation should keep for min required gas + // price and also gas limit + uint256 l2TransactionBaseCost = 250125000000000; + + assertEq( + mailboxFacet.l2TransactionBaseCost(gasPrice, l2GasLimit, l2GasPerPubdataByteLimit), + l2TransactionBaseCost + ); + } +} diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/BridgehubRequestL2Transaction.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/BridgehubRequestL2Transaction.t.sol index d34a6bd7d..580da9a58 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/BridgehubRequestL2Transaction.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/BridgehubRequestL2Transaction.t.sol @@ -4,12 +4,17 @@ pragma solidity 0.8.24; import {MailboxTest} from "./_Mailbox_Shared.t.sol"; import {BridgehubL2TransactionRequest} from "contracts/common/Messaging.sol"; -import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA} from "contracts/common/Config.sol"; +import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA, MAX_NEW_FACTORY_DEPS} from "contracts/common/Config.sol"; import {TransactionFiltererTrue} from "contracts/dev-contracts/test/DummyTransactionFiltererTrue.sol"; import {TransactionFiltererFalse} from "contracts/dev-contracts/test/DummyTransactionFiltererFalse.sol"; +import {TransactionNotAllowed, Unauthorized} from "contracts/common/L1ContractErrors.sol"; -contract BridgehubRequestL2TransactionTest is MailboxTest { - function test_successWithoutFilterer() public { +contract MailboxBridgehubRequestL2TransactionTest is MailboxTest { + function setUp() public virtual { + setupDiamondProxy(); + } + + function test_success_withoutFilterer() public { address bridgehub = makeAddr("bridgehub"); utilsFacet.util_setBridgehub(bridgehub); @@ -24,7 +29,7 @@ contract BridgehubRequestL2TransactionTest is MailboxTest { assertTrue(canonicalTxHash != bytes32(0), "canonicalTxHash should not be 0"); } - function test_successWithFilterer() public { + function test_success_withFilterer() public { address bridgehub = makeAddr("bridgehub"); TransactionFiltererTrue tf = new TransactionFiltererTrue(); @@ -54,7 +59,17 @@ contract BridgehubRequestL2TransactionTest is MailboxTest { vm.deal(bridgehub, 100 ether); vm.prank(address(bridgehub)); - vm.expectRevert(bytes("tf")); + vm.expectRevert(TransactionNotAllowed.selector); + mailboxFacet.bridgehubRequestL2Transaction(req); + } + + function test_revertWhen_notBridgehub() public { + address bridgehub = makeAddr("bridgehub"); + utilsFacet.util_setBridgehub(bridgehub); + BridgehubL2TransactionRequest memory req = getBridgehubRequestL2TransactionRequest(); + vm.deal(bridgehub, 100 ether); + vm.prank(address(sender)); + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, sender)); mailboxFacet.bridgehubRequestL2Transaction(req); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/FinalizeWithdrawal.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/FinalizeWithdrawal.t.sol new file mode 100644 index 000000000..e561f4e3b --- /dev/null +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/FinalizeWithdrawal.t.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import {MailboxTest} from "./_Mailbox_Shared.t.sol"; +import {DummyBridgehub} from "contracts/dev-contracts/test/DummyBridgehub.sol"; +import {L1SharedBridge} from "contracts/bridge/L1SharedBridge.sol"; +import {IBridgehub} from "contracts/bridgehub/IBridgehub.sol"; +import {IL1SharedBridge} from "contracts/bridge/interfaces/IL1SharedBridge.sol"; +import {DummySharedBridge} from "contracts/dev-contracts/test/DummySharedBridge.sol"; +import {OnlyEraSupported} from "contracts/common/L1ContractErrors.sol"; + +contract MailboxFinalizeWithdrawal is MailboxTest { + bytes32[] proof; + bytes message; + DummySharedBridge l1SharedBridge; + address baseTokenBridgeAddress; + + function setUp() public virtual { + setupDiamondProxy(); + + l1SharedBridge = new DummySharedBridge(keccak256("dummyDepositHash")); + baseTokenBridgeAddress = address(l1SharedBridge); + + proof = new bytes32[](0); + message = "message"; + } + + function test_RevertWhen_notEra() public { + utilsFacet.util_setChainId(eraChainId + 1); + + vm.expectRevert(OnlyEraSupported.selector); + mailboxFacet.finalizeEthWithdrawal({ + _l2BatchNumber: 0, + _l2MessageIndex: 0, + _l2TxNumberInBatch: 0, + _message: message, + _merkleProof: proof + }); + } + + function test_success_withdrawal(uint256 amount) public { + address baseTokenBridge = makeAddr("baseTokenBridge"); + utilsFacet.util_setChainId(eraChainId); + utilsFacet.util_setBaseTokenBridge(baseTokenBridgeAddress); + + address l1Receiver = makeAddr("receiver"); + address l1Token = address(1); + vm.deal(baseTokenBridgeAddress, amount); + + bytes memory message = abi.encode(l1Receiver, l1Token, amount); + + mailboxFacet.finalizeEthWithdrawal({ + _l2BatchNumber: 0, + _l2MessageIndex: 0, + _l2TxNumberInBatch: 0, + _message: message, + _merkleProof: proof + }); + + assertEq(l1Receiver.balance, amount); + assertEq(baseTokenBridgeAddress.balance, 0); + } +} diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/ProvingL2LogsInclusion.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/ProvingL2LogsInclusion.t.sol new file mode 100644 index 000000000..b80409234 --- /dev/null +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/ProvingL2LogsInclusion.t.sol @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import {MailboxTest} from "./_Mailbox_Shared.t.sol"; +import {L2Message, L2Log} from "contracts/common/Messaging.sol"; +import "forge-std/Test.sol"; +import {L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH, L1_GAS_PER_PUBDATA_BYTE, L2_TO_L1_LOG_SERIALIZE_SIZE} from "contracts/common/Config.sol"; +import {L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, L2_BOOTLOADER_ADDRESS} from "contracts/common/L2ContractAddresses.sol"; +import {BatchNotExecuted, HashedLogIsDefault} from "contracts/common/L1ContractErrors.sol"; +import {Merkle} from "contracts/state-transition/libraries/Merkle.sol"; +import {MurkyBase} from "murky/common/MurkyBase.sol"; +import {MerkleTest} from "contracts/dev-contracts/test/MerkleTest.sol"; +import {TxStatus} from "contracts/state-transition/chain-deps/facets/Mailbox.sol"; +import {Bridgehub} from "contracts/bridgehub/Bridgehub.sol"; +import {MerkleTreeNoSort} from "test/foundry/unit/concrete/state-transition/libraries/Merkle/MerkleTreeNoSort.sol"; + +contract MailboxL2LogsProve is MailboxTest { + bytes32[] elements; + MerkleTest merkle; + MerkleTreeNoSort merkleTree; + bytes data; + uint256 batchNumber; + bool isService; + uint8 shardId; + + function setUp() public virtual { + setupDiamondProxy(); + + data = abi.encodePacked("test data"); + merkleTree = new MerkleTreeNoSort(); + merkle = new MerkleTest(); + batchNumber = gettersFacet.getTotalBatchesExecuted(); + isService = true; + shardId = 0; + } + + function _addHashedLogToMerkleTree( + uint8 _shardId, + bool _isService, + uint16 _txNumberInBatch, + address _sender, + bytes32 _key, + bytes32 _value + ) internal returns (uint256 index) { + elements.push(keccak256(abi.encodePacked(_shardId, _isService, _txNumberInBatch, _sender, _key, _value))); + + index = elements.length - 1; + } + + function test_RevertWhen_batchNumberGreaterThanBatchesExecuted() public { + L2Message memory message = L2Message({txNumberInBatch: 0, sender: sender, data: data}); + bytes32[] memory proof = new bytes32[](0); + + vm.expectRevert(abi.encodeWithSelector(BatchNotExecuted.selector, batchNumber + 1)); + mailboxFacet.proveL2MessageInclusion({ + _batchNumber: batchNumber + 1, + _index: 0, + _message: message, + _proof: proof + }); + } + + function test_success_proveL2MessageInclusion() public { + uint256 firstLogIndex = _addHashedLogToMerkleTree({ + _shardId: 0, + _isService: true, + _txNumberInBatch: 0, + _sender: L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + _key: bytes32(uint256(uint160(sender))), + _value: keccak256(data) + }); + + uint256 secondLogIndex = _addHashedLogToMerkleTree({ + _shardId: 0, + _isService: true, + _txNumberInBatch: 1, + _sender: L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + _key: bytes32(uint256(uint160(sender))), + _value: keccak256(data) + }); + + // Calculate the Merkle root + bytes32 root = merkleTree.getRoot(elements); + utilsFacet.util_setL2LogsRootHash(batchNumber, root); + + // Create L2 message + L2Message memory message = L2Message({txNumberInBatch: 0, sender: sender, data: data}); + + // Get Merkle proof for the first element + bytes32[] memory firstLogProof = merkleTree.getProof(elements, firstLogIndex); + + { + // Calculate the root using the Merkle proof + bytes32 leaf = elements[firstLogIndex]; + bytes32 calculatedRoot = merkle.calculateRoot(firstLogProof, firstLogIndex, leaf); + + // Assert that the calculated root matches the expected root + assertEq(calculatedRoot, root); + } + + // Prove L2 message inclusion + bool ret = mailboxFacet.proveL2MessageInclusion(batchNumber, firstLogIndex, message, firstLogProof); + + // Assert that the proof was successful + assertEq(ret, true); + + // Prove L2 message inclusion for wrong leaf + ret = mailboxFacet.proveL2MessageInclusion(batchNumber, secondLogIndex, message, firstLogProof); + + // Assert that the proof has failed + assertEq(ret, false); + } + + function test_success_proveL2LogInclusion() public { + uint256 firstLogIndex = _addHashedLogToMerkleTree({ + _shardId: shardId, + _isService: isService, + _txNumberInBatch: 0, + _sender: L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + _key: bytes32(uint256(uint160(sender))), + _value: keccak256(data) + }); + + uint256 secondLogIndex = _addHashedLogToMerkleTree({ + _shardId: shardId, + _isService: isService, + _txNumberInBatch: 1, + _sender: L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + _key: bytes32(uint256(uint160(sender))), + _value: keccak256(data) + }); + + L2Log memory log = L2Log({ + l2ShardId: shardId, + isService: isService, + txNumberInBatch: 1, + sender: L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + key: bytes32(uint256(uint160(sender))), + value: keccak256(data) + }); + + // Calculate the Merkle root + bytes32 root = merkleTree.getRoot(elements); + // Set root hash for current batch + utilsFacet.util_setL2LogsRootHash(batchNumber, root); + + // Get Merkle proof for the first element + bytes32[] memory secondLogProof = merkleTree.getProof(elements, secondLogIndex); + + { + // Calculate the root using the Merkle proof + bytes32 leaf = elements[secondLogIndex]; + + bytes32 calculatedRoot = merkle.calculateRoot(secondLogProof, secondLogIndex, leaf); + // Assert that the calculated root matches the expected root + assertEq(calculatedRoot, root); + } + + // Prove l2 log inclusion with correct proof + bool ret = mailboxFacet.proveL2LogInclusion({ + _batchNumber: batchNumber, + _index: secondLogIndex, + _proof: secondLogProof, + _log: log + }); + + // Assert that the proof was successful + assertEq(ret, true); + + // Prove l2 log inclusion with wrong proof + ret = mailboxFacet.proveL2LogInclusion({ + _batchNumber: batchNumber, + _index: firstLogIndex, + _proof: secondLogProof, + _log: log + }); + + // Assert that the proof was successful + assertEq(ret, false); + } + + // this is not possible in case of message, because some default values + // are set during translation from message to log + function test_RevertWhen_proveL2LogInclusionDefaultLog() public { + L2Log memory log = L2Log({ + l2ShardId: 0, + isService: false, + txNumberInBatch: 0, + sender: address(0), + key: bytes32(0), + value: bytes32(0) + }); + + uint256 firstLogIndex = _addHashedLogToMerkleTree({ + _shardId: 0, + _isService: true, + _txNumberInBatch: 1, + _sender: L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + _key: bytes32(uint256(uint160(sender))), + _value: keccak256(data) + }); + + // Add first element to the Merkle tree + elements.push(keccak256(new bytes(L2_TO_L1_LOG_SERIALIZE_SIZE))); + uint256 secondLogIndex = 1; + + // Calculate the Merkle root + bytes32 root = merkleTree.getRoot(elements); + // Set root hash for current batch + utilsFacet.util_setL2LogsRootHash(batchNumber, root); + + // Get Merkle proof for the first element + bytes32[] memory secondLogProof = merkleTree.getProof(elements, secondLogIndex); + + { + // Calculate the root using the Merkle proof + bytes32 leaf = elements[secondLogIndex]; + bytes32 calculatedRoot = merkle.calculateRoot(secondLogProof, secondLogIndex, leaf); + // Assert that the calculated root matches the expected root + assertEq(calculatedRoot, root); + } + + // Prove log inclusion reverts + vm.expectRevert(HashedLogIsDefault.selector); + mailboxFacet.proveL2LogInclusion({ + _batchNumber: batchNumber, + _index: secondLogIndex, + _proof: secondLogProof, + _log: log + }); + } + + function test_success_proveL1ToL2TransactionStatus() public { + bytes32 firstL2TxHash = keccak256("firstL2Transaction"); + bytes32 secondL2TxHash = keccak256("SecondL2Transaction"); + TxStatus txStatus = TxStatus.Success; + + uint256 firstLogIndex = _addHashedLogToMerkleTree({ + _shardId: shardId, + _isService: isService, + _txNumberInBatch: 0, + _sender: L2_BOOTLOADER_ADDRESS, + _key: firstL2TxHash, + _value: bytes32(uint256(txStatus)) + }); + + uint256 secondLogIndex = _addHashedLogToMerkleTree({ + _shardId: shardId, + _isService: isService, + _txNumberInBatch: 1, + _sender: L2_BOOTLOADER_ADDRESS, + _key: secondL2TxHash, + _value: bytes32(uint256(txStatus)) + }); + + // Calculate the Merkle root + bytes32 root = merkleTree.getRoot(elements); + // Set root hash for current batch + utilsFacet.util_setL2LogsRootHash(batchNumber, root); + + // Get Merkle proof for the first element + bytes32[] memory secondLogProof = merkleTree.getProof(elements, secondLogIndex); + + { + // Calculate the root using the Merkle proof + bytes32 leaf = elements[secondLogIndex]; + bytes32 calculatedRoot = merkle.calculateRoot(secondLogProof, secondLogIndex, leaf); + // Assert that the calculated root matches the expected root + assertEq(calculatedRoot, root); + } + + // Prove L1 to L2 transaction status + bool ret = mailboxFacet.proveL1ToL2TransactionStatus({ + _l2TxHash: secondL2TxHash, + _l2BatchNumber: batchNumber, + _l2MessageIndex: secondLogIndex, + _l2TxNumberInBatch: 1, + _merkleProof: secondLogProof, + _status: txStatus + }); + + // Assert that the proof was successful + assertEq(ret, true); + } +} diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/RequestL2Transaction.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/RequestL2Transaction.t.sol new file mode 100644 index 000000000..76c501013 --- /dev/null +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/RequestL2Transaction.t.sol @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import {MailboxTest} from "./_Mailbox_Shared.t.sol"; +import {BridgehubL2TransactionRequest} from "contracts/common/Messaging.sol"; +import {REQUIRED_L2_GAS_PRICE_PER_PUBDATA, MAX_NEW_FACTORY_DEPS, ETH_TOKEN_ADDRESS} from "contracts/common/Config.sol"; +import {TransactionFiltererTrue} from "contracts/dev-contracts/test/DummyTransactionFiltererTrue.sol"; +import {TransactionFiltererFalse} from "contracts/dev-contracts/test/DummyTransactionFiltererFalse.sol"; +import {FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; +import {IL1SharedBridge} from "contracts/bridge/interfaces/IL1SharedBridge.sol"; +import {DummySharedBridge} from "contracts/dev-contracts/test/DummySharedBridge.sol"; +import {OnlyEraSupported, TooManyFactoryDeps, MsgValueTooLow, GasPerPubdataMismatch} from "contracts/common/L1ContractErrors.sol"; + +contract MailboxRequestL2TransactionTest is MailboxTest { + address tempAddress; + bytes[] tempBytesArr; + bytes tempBytes; + DummySharedBridge l1SharedBridge; + address baseTokenBridgeAddress; + + function setUp() public virtual { + setupDiamondProxy(); + + l1SharedBridge = new DummySharedBridge(keccak256("dummyDepositHash")); + baseTokenBridgeAddress = address(l1SharedBridge); + + tempAddress = makeAddr("temp"); + tempBytesArr = new bytes[](0); + tempBytes = ""; + utilsFacet.util_setChainId(eraChainId); + } + + function test_RevertWhen_NotEra(uint256 randomChainId) public { + vm.assume(eraChainId != randomChainId); + + utilsFacet.util_setChainId(randomChainId); + + vm.expectRevert(OnlyEraSupported.selector); + mailboxFacet.requestL2Transaction({ + _contractL2: tempAddress, + _l2Value: 0, + _calldata: tempBytes, + _l2GasLimit: 0, + _l2GasPerPubdataByteLimit: 0, + _factoryDeps: tempBytesArr, + _refundRecipient: tempAddress + }); + } + + function test_RevertWhen_wrongL2GasPerPubdataByteLimit() public { + vm.expectRevert(GasPerPubdataMismatch.selector); + mailboxFacet.requestL2Transaction({ + _contractL2: tempAddress, + _l2Value: 0, + _calldata: tempBytes, + _l2GasLimit: 0, + _l2GasPerPubdataByteLimit: 0, + _factoryDeps: tempBytesArr, + _refundRecipient: tempAddress + }); + } + + function test_RevertWhen_msgValueDoesntCoverTx() public { + utilsFacet.util_setBaseTokenGasPriceMultiplierDenominator(1); + tempBytesArr = new bytes[](1); + + uint256 baseCost = mailboxFacet.l2TransactionBaseCost(10000000, 1000000, REQUIRED_L2_GAS_PRICE_PER_PUBDATA); + uint256 l2Value = 1 ether; + uint256 mintValue = baseCost + l2Value; + + vm.expectRevert(abi.encodeWithSelector(MsgValueTooLow.selector, mintValue, mintValue - 1)); + mailboxFacet.requestL2Transaction{value: mintValue - 1}({ + _contractL2: tempAddress, + _l2Value: l2Value, + _calldata: tempBytes, + _l2GasLimit: 1000000, + _l2GasPerPubdataByteLimit: REQUIRED_L2_GAS_PRICE_PER_PUBDATA, + _factoryDeps: tempBytesArr, + _refundRecipient: tempAddress + }); + } + + function test_RevertWhen_factoryDepsLengthExceeded() public { + tempBytesArr = new bytes[](MAX_NEW_FACTORY_DEPS + 1); + + vm.expectRevert(TooManyFactoryDeps.selector); + mailboxFacet.requestL2Transaction({ + _contractL2: tempAddress, + _l2Value: 0, + _calldata: tempBytes, + _l2GasLimit: 0, + _l2GasPerPubdataByteLimit: REQUIRED_L2_GAS_PRICE_PER_PUBDATA, + _factoryDeps: tempBytesArr, + _refundRecipient: tempAddress + }); + } + + function _requestL2Transaction( + uint256 amount, + uint256 baseCost, + uint256 l2GasLimit + ) internal returns (bytes32 canonicalTxHash, uint256 mintValue) { + bytes[] memory factoryDeps = new bytes[](1); + factoryDeps[0] = "11111111111111111111111111111111"; + + mintValue = baseCost + amount; + + vm.deal(sender, mintValue); + vm.prank(sender); + canonicalTxHash = mailboxFacet.requestL2Transaction{value: mintValue}({ + _contractL2: tempAddress, + _l2Value: amount, + _calldata: tempBytes, + _l2GasLimit: l2GasLimit, + _l2GasPerPubdataByteLimit: REQUIRED_L2_GAS_PRICE_PER_PUBDATA, + _factoryDeps: factoryDeps, + _refundRecipient: tempAddress + }); + } + + function test_RevertWhen_bridgePaused(uint256 randomValue) public { + utilsFacet.util_setBaseTokenGasPriceMultiplierDenominator(1); + utilsFacet.util_setPriorityTxMaxGasLimit(100000000); + utilsFacet.util_setBaseTokenBridge(baseTokenBridgeAddress); + + uint256 l2GasLimit = 1000000; + uint256 baseCost = mailboxFacet.l2TransactionBaseCost(10000000, l2GasLimit, REQUIRED_L2_GAS_PRICE_PER_PUBDATA); + randomValue = bound(randomValue, 0, type(uint256).max - baseCost); + + l1SharedBridge.pause(); + + vm.expectRevert("Pausable: paused"); + _requestL2Transaction(randomValue, baseCost, l2GasLimit); + } + + function test_success_requestL2Transaction(uint256 randomValue) public { + utilsFacet.util_setBaseTokenGasPriceMultiplierDenominator(1); + utilsFacet.util_setPriorityTxMaxGasLimit(100000000); + utilsFacet.util_setBaseTokenBridge(baseTokenBridgeAddress); + + uint256 l2GasLimit = 1000000; + uint256 baseCost = mailboxFacet.l2TransactionBaseCost(10000000, l2GasLimit, REQUIRED_L2_GAS_PRICE_PER_PUBDATA); + randomValue = bound(randomValue, 0, type(uint256).max - baseCost); + + bytes32 canonicalTxHash; + uint256 mintValue; + + (canonicalTxHash, mintValue) = _requestL2Transaction(randomValue, baseCost, l2GasLimit); + assertTrue(canonicalTxHash != bytes32(0), "canonicalTxHash should not be 0"); + assertEq(baseTokenBridgeAddress.balance, mintValue); + assertEq(l1SharedBridge.chainBalance(eraChainId, ETH_TOKEN_ADDRESS), mintValue); + } +} diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/TransferEthToSharedBridge.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/TransferEthToSharedBridge.t.sol new file mode 100644 index 000000000..2bba6bda1 --- /dev/null +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/TransferEthToSharedBridge.t.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.24; + +import {MailboxTest} from "./_Mailbox_Shared.t.sol"; +import {IL1SharedBridge} from "contracts/bridge/interfaces/IL1SharedBridge.sol"; +import {DummySharedBridge} from "contracts/dev-contracts/test/DummySharedBridge.sol"; +import {OnlyEraSupported, Unauthorized} from "contracts/common/L1ContractErrors.sol"; + +contract MailboxTransferEthToSharedBridge is MailboxTest { + address baseTokenBridgeAddress; + DummySharedBridge l1SharedBridge; + + function setUp() public virtual { + setupDiamondProxy(); + + l1SharedBridge = new DummySharedBridge(keccak256("dummyDepositHash")); + baseTokenBridgeAddress = address(l1SharedBridge); + + utilsFacet.util_setChainId(eraChainId); + utilsFacet.util_setBaseTokenBridge(baseTokenBridgeAddress); + } + + modifier useBaseTokenBridge() { + vm.startPrank(baseTokenBridgeAddress); + _; + vm.stopPrank(); + } + + function test_success_transfer(uint256 randomAmount) public useBaseTokenBridge { + vm.deal(diamondProxy, randomAmount); + + assertEq(address(l1SharedBridge).balance, 0); + assertEq(address(diamondProxy).balance, randomAmount); + mailboxFacet.transferEthToSharedBridge(); + assertEq(address(l1SharedBridge).balance, randomAmount); + assertEq(address(diamondProxy).balance, 0); + } + + function test_RevertWhen_wrongCaller() public { + vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector, sender)); + vm.prank(sender); + mailboxFacet.transferEthToSharedBridge(); + } + + function test_RevertWhen_hyperchainIsNotEra(uint256 randomChainId) public useBaseTokenBridge { + vm.assume(eraChainId != randomChainId); + utilsFacet.util_setChainId(randomChainId); + + vm.expectRevert(OnlyEraSupported.selector); + mailboxFacet.transferEthToSharedBridge(); + } +} diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/_Mailbox_Shared.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/_Mailbox_Shared.t.sol index 03ab74a8d..32a1e9c55 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/_Mailbox_Shared.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/chain-deps/facets/Mailbox/_Mailbox_Shared.t.sol @@ -5,35 +5,32 @@ import {Test} from "forge-std/Test.sol"; import {Utils} from "foundry-test/unit/concrete/Utils/Utils.sol"; import {UtilsFacet} from "foundry-test/unit/concrete/Utils/UtilsFacet.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 {IMailbox} from "contracts/state-transition/chain-interfaces/IMailbox.sol"; +import {IGetters} from "contracts/state-transition/chain-interfaces/IGetters.sol"; import {TestnetVerifier} from "contracts/state-transition/TestnetVerifier.sol"; contract MailboxTest is Test { IMailbox internal mailboxFacet; UtilsFacet internal utilsFacet; + IGetters internal gettersFacet; address sender; - uint256 eraChainId = 9; + uint256 constant eraChainId = 9; address internal testnetVerifier = address(new TestnetVerifier()); + address diamondProxy; - function getMailboxSelectors() public pure returns (bytes4[] memory) { - bytes4[] memory selectors = new bytes4[](1); - selectors[0] = IMailbox.bridgehubRequestL2Transaction.selector; - return selectors; - } - - function setUp() public virtual { + function setupDiamondProxy() public { sender = makeAddr("sender"); vm.deal(sender, 100 ether); - Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](2); + Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](3); facetCuts[0] = Diamond.FacetCut({ facet: address(new MailboxFacet(eraChainId)), action: Diamond.Action.Add, isFreezable: true, - selectors: getMailboxSelectors() + selectors: Utils.getMailboxSelectors() }); facetCuts[1] = Diamond.FacetCut({ facet: address(new UtilsFacet()), @@ -41,10 +38,17 @@ contract MailboxTest is Test { isFreezable: true, selectors: Utils.getUtilsFacetSelectors() }); + facetCuts[2] = Diamond.FacetCut({ + facet: address(new GettersFacet()), + action: Diamond.Action.Add, + isFreezable: true, + selectors: Utils.getGettersSelectors() + }); - address diamondProxy = Utils.makeDiamondProxy(facetCuts, testnetVerifier); + diamondProxy = Utils.makeDiamondProxy(facetCuts, testnetVerifier); mailboxFacet = IMailbox(diamondProxy); utilsFacet = UtilsFacet(diamondProxy); + gettersFacet = IGetters(diamondProxy); } // add this to be excluded from coverage report diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/Merkle/Merkle.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/Merkle/Merkle.t.sol index 492d489c2..89514fc99 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/Merkle/Merkle.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/Merkle/Merkle.t.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.24; import {Test} from "forge-std/Test.sol"; import {MerkleTest} from "contracts/dev-contracts/test/MerkleTest.sol"; import {MerkleTreeNoSort} from "./MerkleTreeNoSort.sol"; +import {MerklePathEmpty, MerkleIndexOutOfBounds, MerklePathOutOfBounds} from "contracts/common/L1ContractErrors.sol"; contract MerkleTestTest is Test { MerkleTreeNoSort merkleTree; @@ -44,7 +45,7 @@ contract MerkleTestTest is Test { bytes32 leaf = elements[0]; bytes32[] memory proof; - vm.expectRevert(bytes("xc")); + vm.expectRevert(MerklePathEmpty.selector); merkleTest.calculateRoot(proof, 0, leaf); } @@ -52,7 +53,7 @@ contract MerkleTestTest is Test { bytes32 leaf = elements[0]; bytes32[] memory proof = merkleTree.getProof(elements, 0); - vm.expectRevert(bytes("px")); + vm.expectRevert(MerkleIndexOutOfBounds.selector); merkleTest.calculateRoot(proof, 2 ** 255, leaf); } @@ -60,7 +61,7 @@ contract MerkleTestTest is Test { bytes32 leaf = elements[0]; bytes32[] memory proof = new bytes32[](256); - vm.expectRevert(bytes("bt")); + vm.expectRevert(MerklePathOutOfBounds.selector); merkleTest.calculateRoot(proof, 0, leaf); } } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/PriorityQueue/OnEmptyQueue.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/PriorityQueue/OnEmptyQueue.sol index 7881409fc..753d5e33c 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/PriorityQueue/OnEmptyQueue.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/PriorityQueue/OnEmptyQueue.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.24; import {PriorityQueueSharedTest} from "./_PriorityQueue_Shared.t.sol"; +import {QueueIsEmpty} from "contracts/common/L1ContractErrors.sol"; contract OnEmptyQueueTest is PriorityQueueSharedTest { function test_gets() public { @@ -13,12 +14,12 @@ contract OnEmptyQueueTest is PriorityQueueSharedTest { } function test_failGetFront() public { - vm.expectRevert(bytes("D")); + vm.expectRevert(QueueIsEmpty.selector); priorityQueue.front(); } function test_failPopFront() public { - vm.expectRevert(bytes("s")); + vm.expectRevert(QueueIsEmpty.selector); priorityQueue.popFront(); } } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/PriorityQueue/PopOperations.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/PriorityQueue/PopOperations.sol index f2f7d73ba..5e43f6284 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/PriorityQueue/PopOperations.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/PriorityQueue/PopOperations.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.24; import {PriorityQueueSharedTest} from "./_PriorityQueue_Shared.t.sol"; import {PriorityOperation} from "contracts/dev-contracts/test/PriorityQueueTest.sol"; +import {QueueIsEmpty} from "contracts/common/L1ContractErrors.sol"; contract PopOperationsTest is PriorityQueueSharedTest { uint256 public constant NUMBER_OPERATIONS = 10; @@ -67,7 +68,7 @@ contract PopOperationsTest is PriorityQueueSharedTest { assertTrue(priorityQueue.isEmpty()); // And now let's go over the limit and fail. - vm.expectRevert(bytes.concat("s")); + vm.expectRevert(QueueIsEmpty.selector); priorityQueue.popFront(); } } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/TransactionValidator/ValidateL1L2Tx.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/TransactionValidator/ValidateL1L2Tx.t.sol index bb78a71b5..dbba8ca2e 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/TransactionValidator/ValidateL1L2Tx.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/TransactionValidator/ValidateL1L2Tx.t.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.24; import {TransactionValidatorSharedTest} from "./_TransactionValidator_Shared.t.sol"; import {L2CanonicalTransaction} from "contracts/common/Messaging.sol"; +import {PubdataGreaterThanLimit, TxnBodyGasLimitNotEnoughGas, ValidateTxnNotEnoughGas, NotEnoughGas, TooMuchGas, InvalidPubdataLength} from "contracts/common/L1ContractErrors.sol"; contract ValidateL1L2TxTest is TransactionValidatorSharedTest { function test_BasicRequestL1L2() public pure { @@ -16,7 +17,7 @@ contract ValidateL1L2TxTest is TransactionValidatorSharedTest { L2CanonicalTransaction memory testTx = createTestTransaction(); // The limit is so low, that it doesn't even cover the overhead testTx.gasLimit = 0; - vm.expectRevert(bytes("my")); + vm.expectRevert(TxnBodyGasLimitNotEnoughGas.selector); validateL1ToL2Transaction(testTx, 500000, 100000); } @@ -27,7 +28,7 @@ contract ValidateL1L2TxTest is TransactionValidatorSharedTest { // before checking that it is below the max gas limit. uint256 priorityTxMaxGasLimit = 500000; testTx.gasLimit = priorityTxMaxGasLimit + 1000000; - vm.expectRevert(bytes("ui")); + vm.expectRevert(TooMuchGas.selector); validateL1ToL2Transaction(testTx, priorityTxMaxGasLimit, 100000); } @@ -41,7 +42,7 @@ contract ValidateL1L2TxTest is TransactionValidatorSharedTest { // So if the pubdata costs per byte is 1 - then this transaction could produce 500k of pubdata. // (hypothetically, assuming all the gas was spent on writing). testTx.gasPerPubdataByteLimit = 1; - vm.expectRevert(bytes("uk")); + vm.expectRevert(abi.encodeWithSelector(PubdataGreaterThanLimit.selector, 100000, 490000)); validateL1ToL2Transaction(testTx, priorityTxMaxGasLimit, 100000); } @@ -49,7 +50,7 @@ contract ValidateL1L2TxTest is TransactionValidatorSharedTest { L2CanonicalTransaction memory testTx = createTestTransaction(); uint256 priorityTxMaxGasLimit = 500000; testTx.gasLimit = 200000; - vm.expectRevert(bytes("up")); + vm.expectRevert(ValidateTxnNotEnoughGas.selector); validateL1ToL2Transaction(testTx, priorityTxMaxGasLimit, 100000); } diff --git a/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/TransactionValidator/ValidateUpgradeTransaction.t.sol b/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/TransactionValidator/ValidateUpgradeTransaction.t.sol index df9a8f7eb..f3ac8238c 100644 --- a/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/TransactionValidator/ValidateUpgradeTransaction.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/state-transition/libraries/TransactionValidator/ValidateUpgradeTransaction.t.sol @@ -5,6 +5,7 @@ import {TransactionValidatorSharedTest} from "./_TransactionValidator_Shared.t.s import {L2CanonicalTransaction} from "contracts/common/Messaging.sol"; import {TransactionValidator} from "contracts/state-transition/libraries/TransactionValidator.sol"; +import {InvalidUpgradeTxn, UpgradeTxVerifyParam} from "contracts/common/L1ContractErrors.sol"; contract ValidateUpgradeTxTest is TransactionValidatorSharedTest { function test_BasicRequest() public pure { @@ -16,7 +17,7 @@ contract ValidateUpgradeTxTest is TransactionValidatorSharedTest { L2CanonicalTransaction memory testTx = createUpgradeTransaction(); // only system contracts (address < 2^16) are allowed to send upgrade transactions. testTx.from = uint256(1000000000); - vm.expectRevert(bytes("ua")); + vm.expectRevert(abi.encodeWithSelector(InvalidUpgradeTxn.selector, UpgradeTxVerifyParam.From)); TransactionValidator.validateUpgradeTransaction(testTx); } @@ -24,7 +25,7 @@ contract ValidateUpgradeTxTest is TransactionValidatorSharedTest { L2CanonicalTransaction memory testTx = createUpgradeTransaction(); // Now the 'to' address it too large. testTx.to = uint256(type(uint160).max) + 100; - vm.expectRevert(bytes("ub")); + vm.expectRevert(abi.encodeWithSelector(InvalidUpgradeTxn.selector, UpgradeTxVerifyParam.To)); TransactionValidator.validateUpgradeTransaction(testTx); } @@ -32,7 +33,7 @@ contract ValidateUpgradeTxTest is TransactionValidatorSharedTest { L2CanonicalTransaction memory testTx = createUpgradeTransaction(); // Paymaster must be 0 - otherwise we revert. testTx.paymaster = 1; - vm.expectRevert(bytes("uc")); + vm.expectRevert(abi.encodeWithSelector(InvalidUpgradeTxn.selector, UpgradeTxVerifyParam.Paymaster)); TransactionValidator.validateUpgradeTransaction(testTx); } @@ -40,7 +41,7 @@ contract ValidateUpgradeTxTest is TransactionValidatorSharedTest { L2CanonicalTransaction memory testTx = createUpgradeTransaction(); // Value must be 0 - otherwise we revert. testTx.value = 1; - vm.expectRevert(bytes("ud")); + vm.expectRevert(abi.encodeWithSelector(InvalidUpgradeTxn.selector, UpgradeTxVerifyParam.Value)); TransactionValidator.validateUpgradeTransaction(testTx); } @@ -48,7 +49,7 @@ contract ValidateUpgradeTxTest is TransactionValidatorSharedTest { L2CanonicalTransaction memory testTx = createUpgradeTransaction(); // reserved 0 must be 0 - otherwise we revert. testTx.reserved[0] = 1; - vm.expectRevert(bytes("ue")); + vm.expectRevert(abi.encodeWithSelector(InvalidUpgradeTxn.selector, UpgradeTxVerifyParam.Reserved0)); TransactionValidator.validateUpgradeTransaction(testTx); } @@ -56,7 +57,7 @@ contract ValidateUpgradeTxTest is TransactionValidatorSharedTest { L2CanonicalTransaction memory testTx = createUpgradeTransaction(); // reserved 1 must be a valid address testTx.reserved[1] = uint256(type(uint160).max) + 100; - vm.expectRevert(bytes("uf")); + vm.expectRevert(abi.encodeWithSelector(InvalidUpgradeTxn.selector, UpgradeTxVerifyParam.Reserved1)); TransactionValidator.validateUpgradeTransaction(testTx); } @@ -64,7 +65,7 @@ contract ValidateUpgradeTxTest is TransactionValidatorSharedTest { L2CanonicalTransaction memory testTx = createUpgradeTransaction(); // reserved 2 must be 0 - otherwise we revert. testTx.reserved[2] = 1; - vm.expectRevert(bytes("ug")); + vm.expectRevert(abi.encodeWithSelector(InvalidUpgradeTxn.selector, UpgradeTxVerifyParam.Reserved2)); TransactionValidator.validateUpgradeTransaction(testTx); } @@ -72,7 +73,7 @@ contract ValidateUpgradeTxTest is TransactionValidatorSharedTest { L2CanonicalTransaction memory testTx = createUpgradeTransaction(); // reserved 3 be 0 - otherwise we revert. testTx.reserved[3] = 1; - vm.expectRevert(bytes("uo")); + vm.expectRevert(abi.encodeWithSelector(InvalidUpgradeTxn.selector, UpgradeTxVerifyParam.Reserved3)); TransactionValidator.validateUpgradeTransaction(testTx); } @@ -80,7 +81,7 @@ contract ValidateUpgradeTxTest is TransactionValidatorSharedTest { L2CanonicalTransaction memory testTx = createUpgradeTransaction(); // Signature must be 0 - otherwise we revert. testTx.signature = bytes("hello"); - vm.expectRevert(bytes("uh")); + vm.expectRevert(abi.encodeWithSelector(InvalidUpgradeTxn.selector, UpgradeTxVerifyParam.Signature)); TransactionValidator.validateUpgradeTransaction(testTx); } @@ -88,7 +89,7 @@ contract ValidateUpgradeTxTest is TransactionValidatorSharedTest { L2CanonicalTransaction memory testTx = createUpgradeTransaction(); // PaymasterInput must be 0 - otherwise we revert. testTx.paymasterInput = bytes("hi"); - vm.expectRevert(bytes("ul1")); + vm.expectRevert(abi.encodeWithSelector(InvalidUpgradeTxn.selector, UpgradeTxVerifyParam.PaymasterInput)); TransactionValidator.validateUpgradeTransaction(testTx); } @@ -96,7 +97,7 @@ contract ValidateUpgradeTxTest is TransactionValidatorSharedTest { L2CanonicalTransaction memory testTx = createUpgradeTransaction(); // ReservedDynamic must be 0 - otherwise we revert. testTx.reservedDynamic = bytes("something"); - vm.expectRevert(bytes("um")); + vm.expectRevert(abi.encodeWithSelector(InvalidUpgradeTxn.selector, UpgradeTxVerifyParam.ReservedDynamic)); TransactionValidator.validateUpgradeTransaction(testTx); } } 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 b0e9733a3..464298482 100644 --- a/l1-contracts/test/unit_tests/custom_base_token.spec.ts +++ b/l1-contracts/test/unit_tests/custom_base_token.spec.ts @@ -97,7 +97,7 @@ describe("Custom base token chain and bridge tests", () => { ) ); - expect(revertReason).equal("ShB not legacy bridge"); + expect(revertReason).contains("Unauthorized"); }); it("Should deposit base token successfully direct via bridgehub", async () => { @@ -147,13 +147,13 @@ describe("Custom base token chain and bridge tests", () => { const revertReason = await getCallRevertReason( l1SharedBridge.connect(randomSigner).finalizeWithdrawal(chainId, 0, 0, 0, "0x", []) ); - expect(revertReason).equal("ShB wrong msg len"); + expect(revertReason).contains("MalformedMessage"); }); it("Should revert on finalizing a withdrawal with wrong function selector", async () => { const revertReason = await getCallRevertReason( l1SharedBridge.connect(randomSigner).finalizeWithdrawal(chainId, 0, 0, 0, ethers.utils.randomBytes(96), []) ); - expect(revertReason).equal("ShB Incorrect message function selector"); + expect(revertReason).contains("InvalidSelector"); }); }); diff --git a/l1-contracts/test/unit_tests/governance_test.spec.ts b/l1-contracts/test/unit_tests/governance_test.spec.ts index 4ab11f266..444e70846 100644 --- a/l1-contracts/test/unit_tests/governance_test.spec.ts +++ b/l1-contracts/test/unit_tests/governance_test.spec.ts @@ -36,7 +36,7 @@ describe("Admin facet tests", function () { const revertReason = await getCallRevertReason( adminFacetTest.connect(randomSigner).setValidator(validatorAddress, true) ); - expect(revertReason).equal("Hyperchain: not state transition manager"); + expect(revertReason).contains("Unauthorized"); }); it("StateTransitionManager successfully set porter availability", async () => { @@ -48,7 +48,7 @@ describe("Admin facet tests", function () { it("random account fails to set porter availability", async () => { const revertReason = await getCallRevertReason(adminFacetTest.connect(randomSigner).setPorterAvailability(false)); - expect(revertReason).equal("Hyperchain: not state transition manager"); + expect(revertReason).contains("Unauthorized"); }); it("StateTransitionManager successfully set priority transaction max gas limit", async () => { @@ -64,7 +64,7 @@ describe("Admin facet tests", function () { const revertReason = await getCallRevertReason( adminFacetTest.connect(randomSigner).setPriorityTxMaxGasLimit(gasLimit) ); - expect(revertReason).equal("Hyperchain: not state transition manager"); + expect(revertReason).contains("Unauthorized"); }); describe("change admin", function () { @@ -92,7 +92,7 @@ describe("Admin facet tests", function () { it("failed to accept admin from not proposed account", async () => { const revertReason = await getCallRevertReason(adminFacetTest.connect(randomSigner).acceptAdmin()); - expect(revertReason).equal("n4"); + expect(revertReason).contains("Unauthorized"); }); it("accept admin from proposed account", async () => { 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 b53b12175..31475e241 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 @@ -98,7 +98,7 @@ describe("Shared Bridge tests", () => { { value: mintValue } ) ); - expect(revertReason).equal("6T"); + expect(revertReason).contains("EmptyDeposit"); }); it("Should deposit successfully", async () => { @@ -129,7 +129,7 @@ describe("Shared Bridge tests", () => { const revertReason = await getCallRevertReason( l1SharedBridge.connect(randomSigner).finalizeWithdrawal(chainId, 0, 0, 0, "0x", [ethers.constants.HashZero]) ); - expect(revertReason).equal("ShB wrong msg len"); + expect(revertReason).contains("MalformedMessage"); }); it("Should revert on finalizing a withdrawal with wrong message length", async () => { @@ -145,14 +145,14 @@ describe("Shared Bridge tests", () => { [ethers.constants.HashZero] ) ); - expect(revertReason).equal("ShB wrong msg len 2"); + expect(revertReason).contains("MalformedMessage"); }); it("Should revert on finalizing a withdrawal with wrong function selector", async () => { const revertReason = await getCallRevertReason( l1SharedBridge.connect(randomSigner).finalizeWithdrawal(chainId, 0, 0, 0, ethers.utils.randomBytes(96), []) ); - expect(revertReason).equal("ShB Incorrect message function selector"); + expect(revertReason).contains("InvalidSelector"); }); it("Should deposit erc20 token successfully", async () => { @@ -183,7 +183,7 @@ describe("Shared Bridge tests", () => { const revertReason = await getCallRevertReason( l1SharedBridge.connect(randomSigner).finalizeWithdrawal(chainId, 0, 0, 0, "0x", [ethers.constants.HashZero]) ); - expect(revertReason).equal("ShB wrong msg len"); + expect(revertReason).contains("MalformedMessage"); }); it("Should revert on finalizing a withdrawal with wrong function signature", async () => { @@ -192,7 +192,7 @@ describe("Shared Bridge tests", () => { .connect(randomSigner) .finalizeWithdrawal(chainId, 0, 0, 0, ethers.utils.randomBytes(76), [ethers.constants.HashZero]) ); - expect(revertReason).equal("ShB Incorrect message function selector"); + expect(revertReason).contains("InvalidSelector"); }); it("Should revert on finalizing a withdrawal with wrong batch number", async () => { @@ -206,7 +206,7 @@ describe("Shared Bridge tests", () => { const revertReason = await getCallRevertReason( l1SharedBridge.connect(randomSigner).finalizeWithdrawal(chainId, 10, 0, 0, l2ToL1message, []) ); - expect(revertReason).equal("xx"); + expect(revertReason).contains("BatchNotExecuted"); }); it("Should revert on finalizing a withdrawal with wrong length of proof", async () => { @@ -220,7 +220,7 @@ describe("Shared Bridge tests", () => { const revertReason = await getCallRevertReason( l1SharedBridge.connect(randomSigner).finalizeWithdrawal(chainId, 0, 0, 0, l2ToL1message, []) ); - expect(revertReason).equal("xc"); + expect(revertReason).contains("MerklePathEmpty"); }); it("Should revert on finalizing a withdrawal with wrong proof", async () => { @@ -236,6 +236,6 @@ describe("Shared Bridge tests", () => { .connect(randomSigner) .finalizeWithdrawal(chainId, 0, 0, 0, l2ToL1message, Array(9).fill(ethers.constants.HashZero)) ); - expect(revertReason).equal("ShB withd w proof"); + expect(revertReason).contains("InvalidProof"); }); }); 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 4ea71d99d..b5d97bf7d 100644 --- a/l1-contracts/test/unit_tests/l2-upgrade.test.spec.ts +++ b/l1-contracts/test/unit_tests/l2-upgrade.test.spec.ts @@ -179,7 +179,7 @@ describe.only("L2 upgrade test", function () { l2ProtocolUpgradeTx: noopUpgradeTransaction, }) ); - expect(bootloaderRevertReason).to.equal("Patch only upgrade can not set new bootloader"); + expect(bootloaderRevertReason).to.contain("PatchUpgradeCantSetBootloader"); const defaultAccountRevertReason = await getCallRevertReason( executeUpgrade(chainId, proxyGetters, stateTransitionManager, proxyAdmin, { @@ -188,7 +188,7 @@ describe.only("L2 upgrade test", function () { l2ProtocolUpgradeTx: noopUpgradeTransaction, }) ); - expect(defaultAccountRevertReason).to.equal("Patch only upgrade can not set new default account"); + expect(defaultAccountRevertReason).to.contain("PatchUpgradeCantSetDefaultAccount"); }); it("Should not allow upgrade transaction during patch upgrade", async () => { @@ -205,7 +205,7 @@ describe.only("L2 upgrade test", function () { l2ProtocolUpgradeTx: someTx, }) ); - expect(bootloaderRevertReason).to.equal("Patch only upgrade can not set upgrade transaction"); + expect(bootloaderRevertReason).to.contain("PatchCantSetUpgradeTxn"); }); it("Should not allow major version change", async () => { @@ -223,7 +223,7 @@ describe.only("L2 upgrade test", function () { l2ProtocolUpgradeTx: someTx, }) ); - expect(bootloaderRevertReason).to.equal("Major must always be 0"); + expect(bootloaderRevertReason).to.contain("NewProtocolMajorVersionNotZero"); }); it("Timestamp should behave correctly", async () => { @@ -241,7 +241,7 @@ describe.only("L2 upgrade test", function () { l2ProtocolUpgradeTx: noopUpgradeTransaction, }) ); - expect(revertReason).to.equal("Upgrade is not ready yet"); + expect(revertReason).contains("TimeNotReached"); }); it("Should require correct tx type for upgrade tx", async () => { @@ -255,7 +255,7 @@ describe.only("L2 upgrade test", function () { }) ); - expect(revertReason).to.equal("L2 system upgrade tx type is wrong"); + expect(revertReason).contains("InvalidTxType"); }); it("Should include the new protocol version as part of nonce", async () => { @@ -271,7 +271,7 @@ describe.only("L2 upgrade test", function () { }) ); - expect(revertReason).to.equal("The new protocol version should be included in the L2 system upgrade tx"); + expect(revertReason).contains("L2UpgradeNonceNotEqualToNewProtocolVersion"); }); it("Should ensure monotonic protocol version", async () => { @@ -287,7 +287,7 @@ describe.only("L2 upgrade test", function () { }) ); - expect(revertReason).to.equal("New protocol version is not greater than the current one"); + expect(revertReason).contains("ProtocolVersionTooSmall"); }); it("Should ensure protocol version not increasing too much", async () => { @@ -303,7 +303,7 @@ describe.only("L2 upgrade test", function () { }) ); - expect(revertReason).to.equal("Too big protocol version difference"); + expect(revertReason).contains("ProtocolVersionMinorDeltaTooBig"); }); it("Should validate upgrade transaction overhead", async () => { @@ -319,7 +319,7 @@ describe.only("L2 upgrade test", function () { }) ); - expect(revertReason).to.equal("my"); + expect(revertReason).contains("NotEnoughGas"); }); it("Should validate upgrade transaction gas max", async () => { @@ -335,7 +335,7 @@ describe.only("L2 upgrade test", function () { }) ); - expect(revertReason).to.equal("ui"); + expect(revertReason).contains("TooMuchGas"); }); it("Should validate upgrade transaction cannot output more pubdata than processable", async () => { @@ -352,7 +352,7 @@ describe.only("L2 upgrade test", function () { }) ); - expect(revertReason).to.equal("uk"); + expect(revertReason).contains("PubdataGreaterThanLimit"); }); it("Should validate factory deps", async () => { @@ -371,7 +371,7 @@ describe.only("L2 upgrade test", function () { }) ); - expect(revertReason).to.equal("Wrong factory dep hash"); + expect(revertReason).contains("L2BytecodeHashMismatch"); }); it("Should validate factory deps length match", async () => { @@ -389,7 +389,7 @@ describe.only("L2 upgrade test", function () { }) ); - expect(revertReason).to.equal("Wrong number of factory deps"); + expect(revertReason).contains("UnexpectedNumberOfFactoryDeps"); }); it("Should validate factory deps length isn't too large", async () => { @@ -409,7 +409,7 @@ describe.only("L2 upgrade test", function () { }) ); - expect(revertReason).to.equal("Factory deps can be at most 32"); + expect(revertReason).contains("TooManyFactoryDeps"); }); let l2UpgradeTxHash: string; @@ -616,7 +616,7 @@ describe.only("L2 upgrade test", function () { stateTransitionManager, upgrade ); - expect(revertReason).to.equal("Previous upgrade has not been finalized"); + expect(revertReason).to.contains("PreviousUpgradeNotFinalized"); }); it("Should require that the next commit batches contains an upgrade tx", async () => { @@ -630,7 +630,7 @@ describe.only("L2 upgrade test", function () { const revertReason = await getCallRevertReason( proxyExecutor.commitBatches(storedBatch2Info, [batch3InfoNoUpgradeTx]) ); - expect(revertReason).to.equal("b8"); + expect(revertReason).to.contains("MissingSystemLogs"); }); it("Should ensure any additional upgrade logs go to the priority ops hash", async () => { @@ -672,7 +672,7 @@ describe.only("L2 upgrade test", function () { const revertReason = await getCallRevertReason( proxyExecutor.commitBatches(storedBatch2Info, [batch3InfoNoUpgradeTx]) ); - expect(revertReason).to.equal("kp"); + expect(revertReason).to.contains("LogAlreadyProcessed"); }); it("Should fail to commit when upgrade tx hash does not match", async () => { @@ -705,7 +705,7 @@ describe.only("L2 upgrade test", function () { const revertReason = await getCallRevertReason( proxyExecutor.commitBatches(storedBatch2Info, [batch3InfoTwoUpgradeTx]) ); - expect(revertReason).to.equal("ut"); + expect(revertReason).to.contains("TxHashMismatch"); }); it("Should commit successfully when the upgrade tx is present", async () => { 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 92a86dc7d..0f4f26bd9 100644 --- a/l1-contracts/test/unit_tests/legacy_era_test.spec.ts +++ b/l1-contracts/test/unit_tests/legacy_era_test.spec.ts @@ -103,7 +103,9 @@ describe("Legacy Era tests", function () { deployer.addresses.StateTransition.DiamondProxy ); - const proxyAdminInterface = new Interface(hardhat.artifacts.readArtifactSync("ProxyAdmin").abi); + const proxyAdminInterface = new Interface( + hardhat.artifacts.readArtifactSync("@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol:ProxyAdmin").abi + ); const calldata = proxyAdminInterface.encodeFunctionData("upgrade(address,address)", [ deployer.addresses.Bridges.SharedBridgeProxy, sharedBridge.address, @@ -142,7 +144,7 @@ describe("Legacy Era tests", function () { "deposit(address,address,uint256,uint256,uint256,address)" ](await randomSigner.getAddress(), erc20TestToken.address, 0, 0, 0, ethers.constants.AddressZero) ); - expect(revertReason).equal("0T"); + expect(revertReason).contains("EmptyDeposit"); }); it("Should deposit successfully", async () => { @@ -162,7 +164,7 @@ describe("Legacy Era tests", function () { const revertReason = await getCallRevertReason( l1ERC20Bridge.connect(randomSigner).finalizeWithdrawal(0, 0, 0, "0x", [ethers.constants.HashZero]) ); - expect(revertReason).equal("ShB wrong msg len"); + expect(revertReason).contains("MalformedMessage"); }); it("Should revert on finalizing a withdrawal with wrong function signature", async () => { @@ -171,7 +173,7 @@ describe("Legacy Era tests", function () { .connect(randomSigner) .finalizeWithdrawal(0, 0, 0, ethers.utils.randomBytes(76), [ethers.constants.HashZero]) ); - expect(revertReason).equal("ShB Incorrect message function selector"); + expect(revertReason).contains("InvalidSelector"); }); it("Should revert on finalizing a withdrawal with wrong batch number", async () => { @@ -185,7 +187,7 @@ describe("Legacy Era tests", function () { const revertReason = await getCallRevertReason( l1ERC20Bridge.connect(randomSigner).finalizeWithdrawal(10, 0, 0, l2ToL1message, []) ); - expect(revertReason).equal("xx"); + expect(revertReason).contains("BatchNotExecuted"); }); it("Should revert on finalizing a withdrawal with wrong length of proof", async () => { @@ -199,7 +201,7 @@ describe("Legacy Era tests", function () { const revertReason = await getCallRevertReason( l1ERC20Bridge.connect(randomSigner).finalizeWithdrawal(0, 0, 0, l2ToL1message, []) ); - expect(revertReason).equal("xc"); + expect(revertReason).contains("MerklePathEmpty"); }); it("Should revert on finalizing a withdrawal with wrong proof", async () => { @@ -215,7 +217,7 @@ describe("Legacy Era tests", function () { .connect(randomSigner) .finalizeWithdrawal(0, 0, 0, l2ToL1message, Array(9).fill(ethers.constants.HashZero)) ); - expect(revertReason).equal("ShB withd w proof"); + expect(revertReason).contains("InvalidProof"); }); /////////// Mailbox. Note we have these two together because we need to fix ERA Diamond proxy Address @@ -237,7 +239,7 @@ describe("Legacy Era tests", function () { ) ); - expect(revertReason).equal("pp"); + expect(revertReason).contains("MalformedBytecode"); }); describe("finalizeEthWithdrawal", function () { @@ -284,7 +286,7 @@ describe("Legacy Era tests", function () { const revertReason = await getCallRevertReason( mailbox.finalizeEthWithdrawal(BLOCK_NUMBER, MESSAGE_INDEX, TX_NUMBER_IN_BLOCK, MESSAGE, invalidProof) ); - expect(revertReason).equal("ShB withd w proof"); + expect(revertReason).contains("InvalidProof"); }); it("Successful deposit", async () => { @@ -316,7 +318,7 @@ describe("Legacy Era tests", function () { const revertReason = await getCallRevertReason( mailbox.finalizeEthWithdrawal(BLOCK_NUMBER, MESSAGE_INDEX, TX_NUMBER_IN_BLOCK, MESSAGE, MERKLE_PROOF) ); - expect(revertReason).equal("Withdrawal is already finalized"); + expect(revertReason).contains("WithdrawalAlreadyFinalized"); }); }); }); diff --git a/l1-contracts/test/unit_tests/mailbox_test.spec.ts b/l1-contracts/test/unit_tests/mailbox_test.spec.ts index 7210ccc44..5bb874381 100644 --- a/l1-contracts/test/unit_tests/mailbox_test.spec.ts +++ b/l1-contracts/test/unit_tests/mailbox_test.spec.ts @@ -105,7 +105,7 @@ describe("Mailbox tests", function () { ) ); - expect(revertReason).equal("pq"); + expect(revertReason).contains("MalformedBytecode"); }); it("Should not accept bytecode of even length in words", async () => { @@ -122,7 +122,7 @@ describe("Mailbox tests", function () { ) ); - expect(revertReason).equal("ps"); + expect(revertReason).contains("MalformedBytecode"); }); describe("finalizeEthWithdrawal", function () { @@ -167,21 +167,21 @@ describe("Mailbox tests", function () { const revertReason = await getCallRevertReason( mailbox.finalizeEthWithdrawal(BLOCK_NUMBER, MESSAGE_INDEX, TX_NUMBER_IN_BLOCK, MESSAGE, invalidProof) ); - expect(revertReason).equal("Mailbox: finalizeEthWithdrawal only available for Era on mailbox"); + expect(revertReason).contains("OnlyEraSupported"); }); it("Successful withdrawal", async () => { const revertReason = await getCallRevertReason( mailbox.finalizeEthWithdrawal(BLOCK_NUMBER, MESSAGE_INDEX, TX_NUMBER_IN_BLOCK, MESSAGE, MERKLE_PROOF) ); - expect(revertReason).equal("Mailbox: finalizeEthWithdrawal only available for Era on mailbox"); + expect(revertReason).contains("OnlyEraSupported"); }); it("Reverts when withdrawal is already finalized", async () => { const revertReason = await getCallRevertReason( mailbox.finalizeEthWithdrawal(BLOCK_NUMBER, MESSAGE_INDEX, TX_NUMBER_IN_BLOCK, MESSAGE, MERKLE_PROOF) ); - expect(revertReason).equal("Mailbox: finalizeEthWithdrawal only available for Era on mailbox"); + expect(revertReason).contains("OnlyEraSupported"); }); }); diff --git a/l1-contracts/test/unit_tests/proxy_test.spec.ts b/l1-contracts/test/unit_tests/proxy_test.spec.ts index 3c3ae6429..e63abe0bb 100644 --- a/l1-contracts/test/unit_tests/proxy_test.spec.ts +++ b/l1-contracts/test/unit_tests/proxy_test.spec.ts @@ -134,14 +134,14 @@ describe("Diamond proxy tests", function () { const proxyAsERC20 = TestnetERC20TokenFactory.connect(proxy.address, proxy.signer); const revertReason = await getCallRevertReason(proxyAsERC20.transfer(proxyAsERC20.address, 0)); - expect(revertReason).equal("F"); + expect(revertReason).contains("InvalidSelector"); }); it("check that proxy reject data with no selector", async () => { const dataWithoutSelector = "0x1122"; const revertReason = await getCallRevertReason(proxy.fallback({ data: dataWithoutSelector })); - expect(revertReason).equal("Ut"); + expect(revertReason).contains("MalformedCalldata"); }); it("should freeze the diamond storage", async () => { @@ -178,7 +178,7 @@ describe("Diamond proxy tests", function () { data: executorFacetSelector3 + "0000000000000000000000000000000000000000000000000000000000000000", }) ); - expect(revertReason).equal("q1"); + expect(revertReason).contains("FacetIsFrozen"); }); it("should be able to call an unfreezable facet when diamondStorage is frozen", async () => { diff --git a/l1-contracts/test/unit_tests/utils.ts b/l1-contracts/test/unit_tests/utils.ts index 2bbf51733..3e21d3c81 100644 --- a/l1-contracts/test/unit_tests/utils.ts +++ b/l1-contracts/test/unit_tests/utils.ts @@ -16,7 +16,7 @@ import { packSemver } from "../../scripts/utils"; export const CONTRACTS_GENESIS_PROTOCOL_VERSION = packSemver(0, 21, 0).toString(); // eslint-disable-next-line @typescript-eslint/no-var-requires -export const IERC20_INTERFACE = require("@openzeppelin/contracts/build/contracts/IERC20"); +export const IERC20_INTERFACE = require("@openzeppelin/contracts-v4/build/contracts/IERC20"); export const DEFAULT_REVERT_REASON = "VM did not revert"; export const DEFAULT_L2_LOGS_TREE_ROOT_HASH = "0x0000000000000000000000000000000000000000000000000000000000000000"; @@ -98,7 +98,21 @@ export async function getCallRevertReason(promise) { } } } catch (_) { - throw e; + try { + if ( + revertReason === "cannot estimate gas; transaction may fail or may require manual gas limit" || + revertReason === DEFAULT_REVERT_REASON + ) { + if (e.error) { + revertReason = + e.error.toString().match(/reverted with custom error '([^']*)'/)[1] || "PLACEHOLDER_STRING"; + } else { + revertReason = e.toString().match(/reverted with custom error '([^']*)'/)[1] || "PLACEHOLDER_STRING"; + } + } + } catch (_) { + throw e; + } } } } diff --git a/l1-contracts/test/unit_tests/validator_timelock_test.spec.ts b/l1-contracts/test/unit_tests/validator_timelock_test.spec.ts index 119cae7cc..af3c951ff 100644 --- a/l1-contracts/test/unit_tests/validator_timelock_test.spec.ts +++ b/l1-contracts/test/unit_tests/validator_timelock_test.spec.ts @@ -90,7 +90,7 @@ describe("ValidatorTimelock tests", function () { validatorTimelock.connect(randomSigner).commitBatches(getMockStoredBatchInfo(0), [getMockCommitBatchInfo(1)]) ); - expect(revertReason).equal("ValidatorTimelock: only validator"); + expect(revertReason).contains("Unauthorized"); }); it("Should revert if non-validator proves batches", async () => { @@ -100,13 +100,13 @@ describe("ValidatorTimelock tests", function () { .proveBatches(getMockStoredBatchInfo(0), [getMockStoredBatchInfo(1)], MOCK_PROOF_INPUT) ); - expect(revertReason).equal("ValidatorTimelock: only validator"); + expect(revertReason).contains("Unauthorized"); }); it("Should revert if non-validator revert batches", async () => { const revertReason = await getCallRevertReason(validatorTimelock.connect(randomSigner).revertBatches(1)); - expect(revertReason).equal("ValidatorTimelock: only validator"); + expect(revertReason).contains("Unauthorized"); }); it("Should revert if non-validator executes batches", async () => { @@ -114,7 +114,7 @@ describe("ValidatorTimelock tests", function () { validatorTimelock.connect(randomSigner).executeBatches([getMockStoredBatchInfo(1)]) ); - expect(revertReason).equal("ValidatorTimelock: only validator"); + expect(revertReason).contains("Unauthorized"); }); it("Should revert if not chain governor sets validator", async () => { @@ -122,7 +122,7 @@ describe("ValidatorTimelock tests", function () { validatorTimelock.connect(randomSigner).addValidator(chainId, await randomSigner.getAddress()) ); - expect(revertReason).equal("ValidatorTimelock: only chain admin"); + expect(revertReason).contains("Unauthorized"); }); it("Should revert if non-owner sets execution delay", async () => { @@ -165,7 +165,7 @@ describe("ValidatorTimelock tests", function () { validatorTimelock.connect(validator).executeBatchesSharedBridge(chainId, [getMockStoredBatchInfo(1)]) ); - expect(revertReason).equal("5c"); + expect(revertReason).contains("TimeNotReached"); }); it("Should successfully revert batches", async () => { diff --git a/l2-contracts/.gitignore b/l2-contracts/.gitignore new file mode 100644 index 000000000..16d545bb0 --- /dev/null +++ b/l2-contracts/.gitignore @@ -0,0 +1,15 @@ +# Compiler files +cache/ +out/ +zkout/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file +.env diff --git a/l2-contracts/contracts/ConsensusRegistry.sol b/l2-contracts/contracts/ConsensusRegistry.sol index 514a4f205..de5af6340 100644 --- a/l2-contracts/contracts/ConsensusRegistry.sol +++ b/l2-contracts/contracts/ConsensusRegistry.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; -import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; -import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/access/Ownable2StepUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable-v4/proxy/utils/Initializable.sol"; import {IConsensusRegistry} from "./interfaces/IConsensusRegistry.sol"; /// @author Matter Labs diff --git a/l2-contracts/contracts/Dependencies.sol b/l2-contracts/contracts/Dependencies.sol index bb8adf1f5..8a606d45a 100644 --- a/l2-contracts/contracts/Dependencies.sol +++ b/l2-contracts/contracts/Dependencies.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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; /* solhint-disable-next-line no-unused-import */ -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol"; /* solhint-disable-next-line no-unused-import */ -import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts-v4/proxy/transparent/ProxyAdmin.sol"; diff --git a/l2-contracts/contracts/ForceDeployUpgrader.sol b/l2-contracts/contracts/ForceDeployUpgrader.sol index 9abb22555..46f9e4fd8 100644 --- a/l2-contracts/contracts/ForceDeployUpgrader.sol +++ b/l2-contracts/contracts/ForceDeployUpgrader.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {IContractDeployer, DEPLOYER_SYSTEM_CONTRACT} from "./L2ContractHelper.sol"; diff --git a/l2-contracts/contracts/L2ContractHelper.sol b/l2-contracts/contracts/L2ContractHelper.sol index 79090a3a9..842d4b4f4 100644 --- a/l2-contracts/contracts/L2ContractHelper.sol +++ b/l2-contracts/contracts/L2ContractHelper.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 @@ -114,7 +114,7 @@ library L2ContractHelper { } } -/// @notice Structure used to represent a zkSync transaction. +/// @notice Structure used to represent a ZKsync transaction. struct Transaction { // The type of the transaction. uint256 txType; diff --git a/l2-contracts/contracts/SystemContractsCaller.sol b/l2-contracts/contracts/SystemContractsCaller.sol index 36153eb6d..ba3136792 100644 --- a/l2-contracts/contracts/SystemContractsCaller.sol +++ b/l2-contracts/contracts/SystemContractsCaller.sol @@ -1,6 +1,8 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +// solhint-disable one-contract-per-file +// 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 {MSG_VALUE_SYSTEM_CONTRACT} from "./L2ContractHelper.sol"; @@ -23,9 +25,14 @@ enum CalldataForwardingMode { UseAuxHeap } +/// @notice Error thrown a cast from uint256 to u32 is not possible. +error U32CastOverflow(); + library Utils { function safeCastToU32(uint256 _x) internal pure returns (uint32) { - require(_x <= type(uint32).max, "Overflow"); + if (_x > type(uint32).max) { + revert U32CastOverflow(); + } return uint32(_x); } @@ -41,7 +48,7 @@ library SystemContractsCaller { assembly { dataStart := add(data, 0x20) } - uint32 dataLength = uint32(Utils.safeCastToU32(data.length)); + uint32 dataLength = Utils.safeCastToU32(data.length); uint256 farCallAbi = getFarCallABI({ dataOffset: 0, diff --git a/l2-contracts/contracts/TestnetPaymaster.sol b/l2-contracts/contracts/TestnetPaymaster.sol index 41ce678c1..54558fe3b 100644 --- a/l2-contracts/contracts/TestnetPaymaster.sol +++ b/l2-contracts/contracts/TestnetPaymaster.sol @@ -1,12 +1,13 @@ // 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; -pragma solidity 0.8.20; - -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC20} from "@openzeppelin/contracts-v4/token/ERC20/IERC20.sol"; import {IPaymaster, ExecutionResult, PAYMASTER_VALIDATION_SUCCESS_MAGIC} from "./interfaces/IPaymaster.sol"; import {IPaymasterFlow} from "./interfaces/IPaymasterFlow.sol"; import {Transaction, BOOTLOADER_ADDRESS} from "./L2ContractHelper.sol"; +import {Unauthorized, InvalidInput, InsufficientAllowance, FailedToTransferTokens, UnsupportedPaymasterFlow} from "./errors/L2ContractErrors.sol"; // This is a dummy paymaster. It expects the paymasterInput to contain its "signature" as well as the needed exchange rate. // It supports only approval-based paymaster flow. @@ -15,12 +16,17 @@ contract TestnetPaymaster is IPaymaster { bytes32, bytes32, Transaction calldata _transaction - ) external payable returns (bytes4 magic, bytes memory context) { + ) external payable returns (bytes4 magic, bytes memory) { // By default we consider the transaction as accepted. magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC; - require(msg.sender == BOOTLOADER_ADDRESS, "Only bootloader can call this contract"); - require(_transaction.paymasterInput.length >= 4, "The standard paymaster input must be at least 4 bytes long"); + if (msg.sender != BOOTLOADER_ADDRESS) { + revert Unauthorized(msg.sender); + } + + if (_transaction.paymasterInput.length < 4) { + revert InvalidInput(); + } bytes4 paymasterInputSelector = bytes4(_transaction.paymasterInput[0:4]); if (paymasterInputSelector == IPaymasterFlow.approvalBased.selector) { @@ -33,7 +39,9 @@ contract TestnetPaymaster is IPaymaster { address thisAddress = address(this); uint256 providedAllowance = IERC20(token).allowance(userAddress, thisAddress); - require(providedAllowance >= amount, "The user did not provide enough allowance"); + if (providedAllowance < amount) { + revert InsufficientAllowance(providedAllowance, amount); + } // The testnet paymaster exchanges X wei of the token to the X wei of ETH. uint256 requiredETH = _transaction.gasLimit * _transaction.maxFeePerGas; @@ -51,7 +59,7 @@ contract TestnetPaymaster is IPaymaster { // If the revert reason is empty or represented by just a function selector, // we replace the error with a more user-friendly message if (revertReason.length <= 4) { - revert("Failed to transferFrom from users' account"); + revert FailedToTransferTokens(token, thisAddress, amount); } else { assembly { revert(add(0x20, revertReason), mload(revertReason)) @@ -61,9 +69,11 @@ contract TestnetPaymaster is IPaymaster { // The bootloader never returns any data, so it can safely be ignored here. (bool success, ) = payable(BOOTLOADER_ADDRESS).call{value: requiredETH}(""); - require(success, "Failed to transfer funds to the bootloader"); + if (!success) { + revert FailedToTransferTokens(address(0), BOOTLOADER_ADDRESS, requiredETH); + } } else { - revert("Unsupported paymaster flow"); + revert UnsupportedPaymasterFlow(); } } diff --git a/l2-contracts/contracts/bridge/L2SharedBridge.sol b/l2-contracts/contracts/bridge/L2SharedBridge.sol index 4c33b4b12..d4e7b7900 100644 --- a/l2-contracts/contracts/bridge/L2SharedBridge.sol +++ b/l2-contracts/contracts/bridge/L2SharedBridge.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; -import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; -import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; -import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; +import {Initializable} from "@openzeppelin/contracts-v4/proxy/utils/Initializable.sol"; +import {BeaconProxy} from "@openzeppelin/contracts-v4/proxy/beacon/BeaconProxy.sol"; +import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol"; import {IL1ERC20Bridge} from "./interfaces/IL1ERC20Bridge.sol"; import {IL2SharedBridge} from "./interfaces/IL2SharedBridge.sol"; @@ -15,6 +15,8 @@ import {AddressAliasHelper} from "../vendor/AddressAliasHelper.sol"; import {L2ContractHelper, DEPLOYER_SYSTEM_CONTRACT, IContractDeployer} from "../L2ContractHelper.sol"; import {SystemContractsCaller} from "../SystemContractsCaller.sol"; +import {ZeroAddress, EmptyBytes32, Unauthorized, AddressMismatch, AmountMustBeGreaterThanZero, DeployFailed} from "../errors/L2ContractErrors.sol"; + /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev /// @notice The "default" bridge implementation for the ERC20 tokens. Note, that it does not @@ -39,7 +41,7 @@ contract L2SharedBridge is IL2SharedBridge, Initializable { /// @dev Contract is expected to be used as proxy implementation. /// @dev Disable the initialization to prevent Parity hack. - uint256 immutable ERA_CHAIN_ID; + uint256 public immutable ERA_CHAIN_ID; constructor(uint256 _eraChainId) { ERA_CHAIN_ID = _eraChainId; @@ -57,9 +59,17 @@ contract L2SharedBridge is IL2SharedBridge, Initializable { bytes32 _l2TokenProxyBytecodeHash, address _aliasedOwner ) external reinitializer(2) { - require(_l1SharedBridge != address(0), "bf"); - require(_l2TokenProxyBytecodeHash != bytes32(0), "df"); - require(_aliasedOwner != address(0), "sf"); + if (_l1SharedBridge == address(0)) { + revert ZeroAddress(); + } + + if (_l2TokenProxyBytecodeHash == bytes32(0)) { + revert EmptyBytes32(); + } + + if (_aliasedOwner == address(0)) { + revert ZeroAddress(); + } l1SharedBridge = _l1SharedBridge; @@ -69,7 +79,9 @@ contract L2SharedBridge is IL2SharedBridge, Initializable { l2TokenProxyBytecodeHash = _l2TokenProxyBytecodeHash; l2TokenBeacon.transferOwnership(_aliasedOwner); } else { - require(_l1Bridge != address(0), "bf2"); + if (_l1Bridge == address(0)) { + revert ZeroAddress(); + } l1Bridge = _l1Bridge; // l2StandardToken and l2TokenBeacon are already deployed on ERA, and stored in the proxy } @@ -89,20 +101,26 @@ contract L2SharedBridge is IL2SharedBridge, Initializable { bytes calldata _data ) external override { // Only the L1 bridge counterpart can initiate and finalize the deposit. - require( - AddressAliasHelper.undoL1ToL2Alias(msg.sender) == l1Bridge || - AddressAliasHelper.undoL1ToL2Alias(msg.sender) == l1SharedBridge, - "mq" - ); + if ( + AddressAliasHelper.undoL1ToL2Alias(msg.sender) != l1Bridge && + AddressAliasHelper.undoL1ToL2Alias(msg.sender) != l1SharedBridge + ) { + revert Unauthorized(msg.sender); + } address expectedL2Token = l2TokenAddress(_l1Token); address currentL1Token = l1TokenAddress[expectedL2Token]; if (currentL1Token == address(0)) { address deployedToken = _deployL2Token(_l1Token, _data); - require(deployedToken == expectedL2Token, "mt"); + if (deployedToken != expectedL2Token) { + revert AddressMismatch(expectedL2Token, deployedToken); + } + l1TokenAddress[expectedL2Token] = _l1Token; } else { - require(currentL1Token == _l1Token, "gg"); // Double check that the expected value equal to real one + if (currentL1Token != _l1Token) { + revert AddressMismatch(_l1Token, currentL1Token); + } } IL2StandardToken(expectedL2Token).bridgeMint(_l2Receiver, _amount); @@ -125,12 +143,16 @@ contract L2SharedBridge is IL2SharedBridge, Initializable { /// @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 { - require(_amount > 0, "Amount cannot be zero"); + if (_amount == 0) { + revert AmountMustBeGreaterThanZero(); + } IL2StandardToken(_l2Token).bridgeBurn(msg.sender, _amount); address l1Token = l1TokenAddress[_l2Token]; - require(l1Token != address(0), "yh"); + if (l1Token == address(0)) { + revert ZeroAddress(); + } bytes memory message = _getL1WithdrawMessage(_l1Receiver, l1Token, _amount); L2ContractHelper.sendMessageToL1(message); @@ -177,7 +199,9 @@ contract L2SharedBridge is IL2SharedBridge, Initializable { ); // The deployment should be successful and return the address of the proxy - require(success, "mk"); + if (!success) { + revert DeployFailed(); + } proxy = BeaconProxy(abi.decode(returndata, (address))); } } diff --git a/l2-contracts/contracts/bridge/L2StandardERC20.sol b/l2-contracts/contracts/bridge/L2StandardERC20.sol index d72608368..90db45814 100644 --- a/l2-contracts/contracts/bridge/L2StandardERC20.sol +++ b/l2-contracts/contracts/bridge/L2StandardERC20.sol @@ -1,12 +1,13 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; -import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol"; -import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; -import {ERC1967Upgrade} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol"; +import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol"; +import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol"; +import {ERC1967Upgrade} from "@openzeppelin/contracts-v4/proxy/ERC1967/ERC1967Upgrade.sol"; import {IL2StandardToken} from "./interfaces/IL2StandardToken.sol"; +import {ZeroAddress, Unauthorized, NonSequentialVersion} from "../errors/L2ContractErrors.sol"; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev @@ -47,8 +48,10 @@ contract L2StandardERC20 is ERC20PermitUpgradeable, IL2StandardToken, ERC1967Upg /// @param _l1Address Address of the L1 token that can be deposited to mint this L2 token /// @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(address _l1Address, bytes memory _data) external initializer { - require(_l1Address != address(0), "in6"); // Should be non-zero address + function bridgeInitialize(address _l1Address, bytes calldata _data) external initializer { + if (_l1Address == address(0)) { + revert ZeroAddress(); + } l1Address = _l1Address; l2Bridge = msg.sender; @@ -110,14 +113,16 @@ contract L2StandardERC20 is ERC20PermitUpgradeable, IL2StandardToken, ERC1967Upg /// to ensure that the governor can not accidentally disable future reinitialization of the token. function reinitializeToken( ERC20Getters calldata _availableGetters, - string memory _newName, - string memory _newSymbol, + string calldata _newName, + string calldata _newSymbol, uint8 _version ) external onlyNextVersion(_version) reinitializer(_version) { // 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(); - require(msg.sender == UpgradeableBeacon(beaconAddress).owner(), "tt"); + if (msg.sender != UpgradeableBeacon(beaconAddress).owner()) { + revert Unauthorized(msg.sender); + } __ERC20_init_unchained(_newName, _newSymbol); __ERC20Permit_init(_newName); @@ -127,14 +132,18 @@ contract L2StandardERC20 is ERC20PermitUpgradeable, IL2StandardToken, ERC1967Upg } modifier onlyBridge() { - require(msg.sender == l2Bridge, "xnt"); // Only L2 bridge can call this method + if (msg.sender != l2Bridge) { + revert 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. - require(_version == _getInitializedVersion() + 1, "v"); + if (_version != _getInitializedVersion() + 1) { + revert NonSequentialVersion(); + } _; } @@ -158,29 +167,32 @@ contract L2StandardERC20 is ERC20PermitUpgradeable, IL2StandardToken, ERC1967Upg 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 if (availableGetters.ignoreName) revert(); return super.name(); } 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 if (availableGetters.ignoreSymbol) revert(); return super.symbol(); } 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 if (availableGetters.ignoreDecimals) revert(); return decimals_; } /// @dev External function to decode a string from bytes. - function decodeString(bytes memory _input) external pure returns (string memory result) { + 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. - function decodeUint8(bytes memory _input) external pure returns (uint8 result) { + function decodeUint8(bytes calldata _input) external pure returns (uint8 result) { (result) = abi.decode(_input, (uint8)); } } diff --git a/l2-contracts/contracts/bridge/L2WrappedBaseToken.sol b/l2-contracts/contracts/bridge/L2WrappedBaseToken.sol index 8cf4d7b5c..8ff9f814e 100644 --- a/l2-contracts/contracts/bridge/L2WrappedBaseToken.sol +++ b/l2-contracts/contracts/bridge/L2WrappedBaseToken.sol @@ -1,12 +1,14 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; -import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol"; +import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol"; import {IL2WrappedBaseToken} from "./interfaces/IL2WrappedBaseToken.sol"; import {IL2StandardToken} from "./interfaces/IL2StandardToken.sol"; +import {ZeroAddress, Unauthorized, UnimplementedMessage, BRIDGE_MINT_NOT_IMPLEMENTED, WithdrawFailed} from "../errors/L2ContractErrors.sol"; + /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev /// @notice The canonical implementation of the WETH token. @@ -42,13 +44,18 @@ contract L2WrappedBaseToken is ERC20PermitUpgradeable, IL2WrappedBaseToken, IL2S /// @param _l1Address Address of the L1 token that can be deposited to mint this L2 WETH. /// Note: The decimals are hardcoded to 18, the same as on Ether. function initializeV2( - string memory name_, - string memory symbol_, + string calldata name_, + string calldata symbol_, address _l2Bridge, address _l1Address ) external reinitializer(2) { - require(_l2Bridge != address(0), "L2 bridge address cannot be zero"); - require(_l1Address != address(0), "L1 WETH token address cannot be zero"); + if (_l2Bridge == address(0)) { + revert ZeroAddress(); + } + + if (_l1Address == address(0)) { + revert ZeroAddress(); + } l2Bridge = _l2Bridge; l1Address = _l1Address; @@ -62,7 +69,9 @@ contract L2WrappedBaseToken is ERC20PermitUpgradeable, IL2WrappedBaseToken, IL2S } modifier onlyBridge() { - require(msg.sender == l2Bridge, "permission denied"); // Only L2 bridge can call this method + if (msg.sender != l2Bridge) { + revert Unauthorized(msg.sender); + } _; } @@ -71,7 +80,7 @@ contract L2WrappedBaseToken is ERC20PermitUpgradeable, IL2WrappedBaseToken, IL2S /// Note: Use `deposit`/`depositTo` methods instead. // solhint-disable-next-line no-unused-vars function bridgeMint(address _to, uint256 _amount) external override onlyBridge { - revert("bridgeMint is not implemented! Use deposit/depositTo methods instead."); + revert UnimplementedMessage(BRIDGE_MINT_NOT_IMPLEMENTED); } /// @dev Burn tokens from a given account and send the same amount of Ether to the bridge. @@ -82,7 +91,9 @@ contract L2WrappedBaseToken is ERC20PermitUpgradeable, IL2WrappedBaseToken, IL2S _burn(_from, _amount); // sends Ether to the bridge (bool success, ) = msg.sender.call{value: _amount}(""); - require(success, "Failed withdrawal"); + if (!success) { + revert WithdrawFailed(); + } emit BridgeBurn(_from, _amount); } @@ -107,7 +118,9 @@ contract L2WrappedBaseToken is ERC20PermitUpgradeable, IL2WrappedBaseToken, IL2S function withdrawTo(address _to, uint256 _amount) public override { _burn(msg.sender, _amount); (bool success, ) = _to.call{value: _amount}(""); - require(success, "Failed withdrawal"); + if (!success) { + revert WithdrawFailed(); + } } /// @dev Fallback function to allow receiving Ether. diff --git a/l2-contracts/contracts/bridge/interfaces/IL1ERC20Bridge.sol b/l2-contracts/contracts/bridge/interfaces/IL1ERC20Bridge.sol index 407669613..84d412245 100644 --- a/l2-contracts/contracts/bridge/interfaces/IL1ERC20Bridge.sol +++ b/l2-contracts/contracts/bridge/interfaces/IL1ERC20Bridge.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 // note we use the IL1ERC20Bridge only to send L1<>L2 messages, diff --git a/l2-contracts/contracts/bridge/interfaces/IL1SharedBridge.sol b/l2-contracts/contracts/bridge/interfaces/IL1SharedBridge.sol index 8ec1ff757..cc468ab87 100644 --- a/l2-contracts/contracts/bridge/interfaces/IL1SharedBridge.sol +++ b/l2-contracts/contracts/bridge/interfaces/IL1SharedBridge.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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; /// @title L1 Bridge contract interface /// @author Matter Labs diff --git a/l2-contracts/contracts/bridge/interfaces/IL2SharedBridge.sol b/l2-contracts/contracts/bridge/interfaces/IL2SharedBridge.sol index c1aa05102..ee31f6691 100644 --- a/l2-contracts/contracts/bridge/interfaces/IL2SharedBridge.sol +++ b/l2-contracts/contracts/bridge/interfaces/IL2SharedBridge.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 interface IL2SharedBridge { diff --git a/l2-contracts/contracts/bridge/interfaces/IL2StandardToken.sol b/l2-contracts/contracts/bridge/interfaces/IL2StandardToken.sol index 6ceb1ae80..6fefafa63 100644 --- a/l2-contracts/contracts/bridge/interfaces/IL2StandardToken.sol +++ b/l2-contracts/contracts/bridge/interfaces/IL2StandardToken.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 IL2StandardToken { event BridgeInitialize(address indexed l1Token, string name, string symbol, uint8 decimals); diff --git a/l2-contracts/contracts/bridge/interfaces/IL2WrappedBaseToken.sol b/l2-contracts/contracts/bridge/interfaces/IL2WrappedBaseToken.sol index 693aa139a..ae7e1a916 100644 --- a/l2-contracts/contracts/bridge/interfaces/IL2WrappedBaseToken.sol +++ b/l2-contracts/contracts/bridge/interfaces/IL2WrappedBaseToken.sol @@ -1,5 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +// 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 IL2WrappedBaseToken { event Initialize(string name, string symbol, uint8 decimals); diff --git a/l2-contracts/contracts/dev-contracts/DevL2SharedBridge.sol b/l2-contracts/contracts/dev-contracts/DevL2SharedBridge.sol index 12a6a187f..fda1c5932 100644 --- a/l2-contracts/contracts/dev-contracts/DevL2SharedBridge.sol +++ b/l2-contracts/contracts/dev-contracts/DevL2SharedBridge.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity ^0.8.20; import {L2SharedBridge} from "../bridge/L2SharedBridge.sol"; import {L2StandardERC20} from "../bridge/L2StandardERC20.sol"; -import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; +import {UpgradeableBeacon} from "@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol"; /// @author Matter Labs /// @notice The implementation of the shared bridge that allows setting legacy bridge. Must only be used in local testing environments. diff --git a/l2-contracts/contracts/dev-contracts/Multicall3.sol b/l2-contracts/contracts/dev-contracts/Multicall3.sol index 9a6c69340..aaa8b8012 100644 --- a/l2-contracts/contracts/dev-contracts/Multicall3.sol +++ b/l2-contracts/contracts/dev-contracts/Multicall3.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; /// @title Multicall3 /// @notice Aggregate results from multiple function calls diff --git a/l2-contracts/contracts/errors/L2ContractErrors.sol b/l2-contracts/contracts/errors/L2ContractErrors.sol new file mode 100644 index 000000000..c5177f3eb --- /dev/null +++ b/l2-contracts/contracts/errors/L2ContractErrors.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; + +// 0x1f73225f +error AddressMismatch(address expected, address supplied); +// 0x5e85ae73 +error AmountMustBeGreaterThanZero(); +// 0xb4f54111 +error DeployFailed(); +// 0x7138356f +error EmptyAddress(); +// 0x1c25715b +error EmptyBytes32(); +// 0x1bdfd505 +error FailedToTransferTokens(address tokenContract, address to, uint256 amount); +// 0x2a1b2dd8 +error InsufficientAllowance(uint256 providedAllowance, uint256 requiredAmount); +// 0xcbd9d2e0 +error InvalidCaller(address); +// 0xb4fa3fb3 +error InvalidInput(); +// 0x0ac76f01 +error NonSequentialVersion(); +// 0x8e4a23d6 +error Unauthorized(address); +// 0x6e128399 +error Unimplemented(); +// 0xa4dde386 +error UnimplementedMessage(string message); +// 0xff15b069 +error UnsupportedPaymasterFlow(); +// 0x750b219c +error WithdrawFailed(); +// 0xd92e233d +error ZeroAddress(); + +string constant BRIDGE_MINT_NOT_IMPLEMENTED = "bridgeMint is not implemented! Use deposit/depositTo methods instead."; diff --git a/l2-contracts/contracts/interfaces/IConsensusRegistry.sol b/l2-contracts/contracts/interfaces/IConsensusRegistry.sol index e3ddd118a..34afc0abe 100644 --- a/l2-contracts/contracts/interfaces/IConsensusRegistry.sol +++ b/l2-contracts/contracts/interfaces/IConsensusRegistry.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; /// @author Matter Labs /// @custom:security-contact security@matterlabs.dev diff --git a/l2-contracts/contracts/interfaces/IPaymaster.sol b/l2-contracts/contracts/interfaces/IPaymaster.sol index 8ba4bc694..ed7e5c50f 100644 --- a/l2-contracts/contracts/interfaces/IPaymaster.sol +++ b/l2-contracts/contracts/interfaces/IPaymaster.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 {Transaction} from "../L2ContractHelper.sol"; diff --git a/l2-contracts/contracts/interfaces/IPaymasterFlow.sol b/l2-contracts/contracts/interfaces/IPaymasterFlow.sol index 2ee4f64f7..207aee24e 100644 --- a/l2-contracts/contracts/interfaces/IPaymasterFlow.sol +++ b/l2-contracts/contracts/interfaces/IPaymasterFlow.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 diff --git a/l2-contracts/contracts/vendor/AddressAliasHelper.sol b/l2-contracts/contracts/vendor/AddressAliasHelper.sol index da0282ed8..6adab1d92 100644 --- a/l2-contracts/contracts/vendor/AddressAliasHelper.sol +++ b/l2-contracts/contracts/vendor/AddressAliasHelper.sol @@ -15,11 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -pragma solidity 0.8.20; +// 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; library AddressAliasHelper { - uint160 constant offset = uint160(0x1111000000000000000000000000000000001111); + uint160 internal constant offset = uint160(0x1111000000000000000000000000000000001111); /// @notice Utility function converts the address that submitted a tx /// to the inbox on L1 to the msg.sender viewed on L2 diff --git a/l2-contracts/foundry.toml b/l2-contracts/foundry.toml new file mode 100644 index 000000000..deb178a12 --- /dev/null +++ b/l2-contracts/foundry.toml @@ -0,0 +1,13 @@ +[profile.default] +src = "contracts" +out = "out" +libs = ["lib"] +cache_path = "cache-forge" +evm_version = "paris" +remappings = [ + "@openzeppelin/contracts-v4/=lib/openzeppelin-contracts-v4/contracts/", + "@openzeppelin/contracts-upgradeable-v4/=lib/openzeppelin-contracts-upgradeable-v4/contracts/", +] + +[profile.default.zksync] +zksolc = "1.5.0" diff --git a/l2-contracts/hardhat.config.ts b/l2-contracts/hardhat.config.ts index c0aaca03e..282ab7b96 100644 --- a/l2-contracts/hardhat.config.ts +++ b/l2-contracts/hardhat.config.ts @@ -12,14 +12,14 @@ if (!process.env.CHAIN_ETH_NETWORK) { export default { zksolc: { - version: "1.3.18", + version: "1.5.0", compilerSource: "binary", settings: { isSystem: true, }, }, solidity: { - version: "0.8.20", + version: "0.8.24", }, defaultNetwork: "localhost", networks: { diff --git a/l2-contracts/lib/forge-std b/l2-contracts/lib/forge-std new file mode 120000 index 000000000..edce15694 --- /dev/null +++ b/l2-contracts/lib/forge-std @@ -0,0 +1 @@ +../../lib/forge-std \ No newline at end of file diff --git a/l2-contracts/lib/openzeppelin-contracts-upgradeable-v4 b/l2-contracts/lib/openzeppelin-contracts-upgradeable-v4 new file mode 120000 index 000000000..0551b6016 --- /dev/null +++ b/l2-contracts/lib/openzeppelin-contracts-upgradeable-v4 @@ -0,0 +1 @@ +../../lib/openzeppelin-contracts-upgradeable-v4 \ No newline at end of file diff --git a/l2-contracts/lib/openzeppelin-contracts-v4 b/l2-contracts/lib/openzeppelin-contracts-v4 new file mode 120000 index 000000000..693e94537 --- /dev/null +++ b/l2-contracts/lib/openzeppelin-contracts-v4 @@ -0,0 +1 @@ +../../lib/openzeppelin-contracts-v4 \ No newline at end of file diff --git a/l2-contracts/package.json b/l2-contracts/package.json index 891b348a3..fdaa06327 100644 --- a/l2-contracts/package.json +++ b/l2-contracts/package.json @@ -3,16 +3,16 @@ "version": "0.1.0", "license": "MIT", "devDependencies": { - "@matterlabs/hardhat-zksync-deploy": "^0.6.5", + "@matterlabs/hardhat-zksync-deploy": "^0.7.0", "@matterlabs/hardhat-zksync-solc": "^0.3.15", - "@matterlabs/hardhat-zksync-verify": "^0.2.0", + "@matterlabs/hardhat-zksync-verify": "^0.4.0", "@nomicfoundation/hardhat-chai-matchers": "^1.0.6", "@nomicfoundation/hardhat-ethers": "^3.0.4", "@nomicfoundation/hardhat-verify": "^1.1.0", "@nomiclabs/hardhat-ethers": "^2.0.0", "@nomiclabs/hardhat-etherscan": "^3.1.7", - "@openzeppelin/contracts": "4.9.5", - "@openzeppelin/contracts-upgradeable": "4.9.5", + "@openzeppelin/contracts-upgradeable-v4": "npm:@openzeppelin/contracts-upgradeable@4.9.5", + "@openzeppelin/contracts-v4": "npm:@openzeppelin/contracts@4.9.5", "@typechain/ethers-v5": "^2.0.0", "@types/chai": "^4.2.21", "@types/chai-as-promised": "^7.1.4", @@ -28,7 +28,7 @@ "ts-node": "^10.1.0", "typechain": "^4.0.0", "typescript": "^5.2.2", - "zksync-web3": "^0.15.4" + "zksync-ethers": "^5.9.0" }, "scripts": { "build": "hardhat compile", diff --git a/l2-contracts/src/deploy-shared-bridge-on-l2-through-l1.ts b/l2-contracts/src/deploy-shared-bridge-on-l2-through-l1.ts index 5bf18af74..613fcaf8c 100644 --- a/l2-contracts/src/deploy-shared-bridge-on-l2-through-l1.ts +++ b/l2-contracts/src/deploy-shared-bridge-on-l2-through-l1.ts @@ -148,7 +148,9 @@ export async function deploySharedBridgeProxyOnL2ThroughL1( ); /// loading TransparentUpgradeableProxy bytecode - const L2_SHARED_BRIDGE_PROXY_BYTECODE = hre.artifacts.readArtifactSync("TransparentUpgradeableProxy").bytecode; + const L2_SHARED_BRIDGE_PROXY_BYTECODE = hre.artifacts.readArtifactSync( + "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy" + ).bytecode; /// compute L2SharedBridgeProxy address const l2SharedBridgeProxyAddress = computeL2Create2Address( diff --git a/l2-contracts/src/update-l2-erc20-metadata.ts b/l2-contracts/src/update-l2-erc20-metadata.ts index b86589df3..24903acd8 100644 --- a/l2-contracts/src/update-l2-erc20-metadata.ts +++ b/l2-contracts/src/update-l2-erc20-metadata.ts @@ -2,7 +2,7 @@ import * as hre from "hardhat"; import "@nomiclabs/hardhat-ethers"; import { Command } from "commander"; import { Wallet, ethers, BigNumber } from "ethers"; -import { Provider } from "zksync-web3"; +import { Provider } from "zksync-ethers"; import { getNumberFromEnv } from "../../l1-contracts/src.ts/utils"; import { web3Provider } from "../../l1-contracts/scripts/utils"; import { Deployer } from "../../l1-contracts/src.ts/deploy"; diff --git a/l2-contracts/src/upgrade-bridge-impl.ts b/l2-contracts/src/upgrade-bridge-impl.ts index 99c7475c7..3d8e77da9 100644 --- a/l2-contracts/src/upgrade-bridge-impl.ts +++ b/l2-contracts/src/upgrade-bridge-impl.ts @@ -6,8 +6,8 @@ import { Command } from "commander"; import { BigNumber, Wallet, ethers } from "ethers"; import * as fs from "fs"; import * as path from "path"; -import { Provider } from "zksync-web3"; -import { REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT } from "zksync-web3/build/src/utils"; +import { Provider } from "zksync-ethers"; +import { REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT } from "zksync-ethers/build/utils"; import { web3Provider } from "../../l1-contracts/scripts/utils"; import { getAddressFromEnv, getNumberFromEnv } from "../../l1-contracts/src.ts/utils"; import { Deployer } from "../../l1-contracts/src.ts/deploy"; @@ -352,7 +352,7 @@ async function main() { REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT ); - console.log(`Base cost for priority tx with max ergs: ${ethers.utils.formatEther(neededValue)} ETH`); + console.log(`Base cost for priority tx with max gas: ${ethers.utils.formatEther(neededValue)} ETH`); }); await program.parseAsync(process.argv); diff --git a/l2-contracts/src/utils.ts b/l2-contracts/src/utils.ts index b4e7d5c1e..0a479a540 100644 --- a/l2-contracts/src/utils.ts +++ b/l2-contracts/src/utils.ts @@ -9,11 +9,11 @@ import { web3Provider } from "../../l1-contracts/scripts/utils"; import type { BigNumber, BytesLike, Wallet } from "ethers"; import { ethers } from "ethers"; -import type { Provider } from "zksync-web3"; -import { REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT, sleep } from "zksync-web3/build/src/utils"; -import { IERC20Factory } from "zksync-web3/build/typechain"; +import type { Provider } from "zksync-ethers"; +import { REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_LIMIT, sleep } from "zksync-ethers/build/utils"; import { ERC20Factory } from "../../l1-contracts/typechain"; +import { IERC20Factory } from "../typechain/IERC20Factory"; export const provider = web3Provider(); diff --git a/l2-contracts/test/erc20.test.ts b/l2-contracts/test/erc20.test.ts index 25dfba652..5f1f21a30 100644 --- a/l2-contracts/test/erc20.test.ts +++ b/l2-contracts/test/erc20.test.ts @@ -2,8 +2,8 @@ import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; import { expect } from "chai"; import { ethers } from "ethers"; import * as hre from "hardhat"; -import { Provider, Wallet } from "zksync-web3"; -import { hashBytecode } from "zksync-web3/build/src/utils"; +import { Provider, Wallet } from "zksync-ethers"; +import { hashBytecode } from "zksync-ethers/build/utils"; import { unapplyL1ToL2Alias } from "./test-utils"; import { L2SharedBridgeFactory, L2StandardERC20Factory } from "../typechain"; import type { L2SharedBridge, L2StandardERC20 } from "../typechain"; @@ -45,12 +45,18 @@ describe("ERC20Bridge", function () { // While we formally don't need to deploy the token and the beacon proxy, it is a neat way to have the bytecode published const l2TokenImplAddress = await deployer.deploy(await deployer.loadArtifact("L2StandardERC20")); - const l2Erc20TokenBeacon = await deployer.deploy(await deployer.loadArtifact("UpgradeableBeacon"), [ - l2TokenImplAddress.address, - ]); - await deployer.deploy(await deployer.loadArtifact("BeaconProxy"), [l2Erc20TokenBeacon.address, "0x"]); - - const beaconProxyBytecodeHash = hashBytecode((await deployer.loadArtifact("BeaconProxy")).bytecode); + const l2Erc20TokenBeacon = await deployer.deploy( + await deployer.loadArtifact("@openzeppelin/contracts-v4/proxy/beacon/UpgradeableBeacon.sol:UpgradeableBeacon"), + [l2TokenImplAddress.address] + ); + await deployer.deploy( + await deployer.loadArtifact("@openzeppelin/contracts-v4/proxy/beacon/BeaconProxy.sol:BeaconProxy"), + [l2Erc20TokenBeacon.address, "0x"] + ); + + const beaconProxyBytecodeHash = hashBytecode( + (await deployer.loadArtifact("@openzeppelin/contracts-v4/proxy/beacon/BeaconProxy.sol:BeaconProxy")).bytecode + ); const erc20BridgeImpl = await deployer.deploy(await deployer.loadArtifact("L2SharedBridge"), [testChainId]); const bridgeInitializeData = erc20BridgeImpl.interface.encodeFunctionData("initialize", [ @@ -60,11 +66,12 @@ describe("ERC20Bridge", function () { governorWallet.address, ]); - const erc20BridgeProxy = await deployer.deploy(await deployer.loadArtifact("TransparentUpgradeableProxy"), [ - erc20BridgeImpl.address, - governorWallet.address, - bridgeInitializeData, - ]); + const erc20BridgeProxy = await deployer.deploy( + await deployer.loadArtifact( + "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy" + ), + [erc20BridgeImpl.address, governorWallet.address, bridgeInitializeData] + ); erc20Bridge = L2SharedBridgeFactory.connect(erc20BridgeProxy.address, deployerWallet); }); diff --git a/l2-contracts/test/weth.test.ts b/l2-contracts/test/weth.test.ts index 00bb921a0..3e8489077 100644 --- a/l2-contracts/test/weth.test.ts +++ b/l2-contracts/test/weth.test.ts @@ -2,7 +2,7 @@ import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; import { expect } from "chai"; import { ethers } from "ethers"; import * as hre from "hardhat"; -import { Provider, Wallet } from "zksync-web3"; +import { Provider, Wallet } from "zksync-ethers"; import type { L2WrappedBaseToken } from "../typechain/L2WrappedBaseToken"; import type { L2SharedBridge } from "../typechain/L2SharedBridge"; import { L2SharedBridgeFactory } from "../typechain/L2SharedBridgeFactory"; @@ -28,16 +28,18 @@ describe("WETH token & WETH bridge", function () { const wethBridgeImpl = await deployer.deploy(await deployer.loadArtifact("L2SharedBridge"), [testChainId]); const randomAddress = ethers.utils.hexlify(ethers.utils.randomBytes(20)); - const wethTokenProxy = await deployer.deploy(await deployer.loadArtifact("TransparentUpgradeableProxy"), [ - wethTokenImpl.address, - randomAddress, - "0x", - ]); - const wethBridgeProxy = await deployer.deploy(await deployer.loadArtifact("TransparentUpgradeableProxy"), [ - wethBridgeImpl.address, - randomAddress, - "0x", - ]); + const wethTokenProxy = await deployer.deploy( + await deployer.loadArtifact( + "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy" + ), + [wethTokenImpl.address, randomAddress, "0x"] + ); + const wethBridgeProxy = await deployer.deploy( + await deployer.loadArtifact( + "@openzeppelin/contracts-v4/proxy/transparent/TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy" + ), + [wethBridgeImpl.address, randomAddress, "0x"] + ); wethToken = L2WrappedBaseTokenFactory.connect(wethTokenProxy.address, wallet); wethBridge = L2SharedBridgeFactory.connect(wethBridgeProxy.address, wallet); diff --git a/lib/forge-std b/lib/forge-std new file mode 160000 index 000000000..bf6606142 --- /dev/null +++ b/lib/forge-std @@ -0,0 +1 @@ +Subproject commit bf6606142994b1e47e2882ce0cd477c020d77623 diff --git a/lib/murky b/lib/murky new file mode 160000 index 000000000..5feccd125 --- /dev/null +++ b/lib/murky @@ -0,0 +1 @@ +Subproject commit 5feccd1253d7da820f7cccccdedf64471025455d diff --git a/l1-contracts/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable-v4 similarity index 100% rename from l1-contracts/lib/openzeppelin-contracts-upgradeable rename to lib/openzeppelin-contracts-upgradeable-v4 diff --git a/l1-contracts/lib/openzeppelin-contracts b/lib/openzeppelin-contracts-v4 similarity index 100% rename from l1-contracts/lib/openzeppelin-contracts rename to lib/openzeppelin-contracts-v4 diff --git a/package.json b/package.json index 466691d3a..5aeef0ff2 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "markdownlint-cli": "^0.33.0", "prettier-plugin-solidity": "^1.1.3", "prettier": "^3.0.3", - "solhint": "^3.6.2" + "solhint": "4.5.4" }, "scripts": { "lint:check": "yarn lint:md && yarn lint:sol && yarn lint:ts && yarn prettier:check", diff --git a/system-contracts/.gitignore b/system-contracts/.gitignore new file mode 100644 index 000000000..16d545bb0 --- /dev/null +++ b/system-contracts/.gitignore @@ -0,0 +1,15 @@ +# Compiler files +cache/ +out/ +zkout/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file +.env diff --git a/system-contracts/README.md b/system-contracts/README.md index 1449c936f..4058a356b 100644 --- a/system-contracts/README.md +++ b/system-contracts/README.md @@ -1,10 +1,10 @@ -# zkSync Era: System Contracts +# ZKsync Era: System Contracts [![Logo](../eraLogo.svg)](https://zksync.io/) -zkSync Era is a layer 2 rollup that uses zero-knowledge proofs to scale Ethereum without compromising on security or +ZKsync Era is a layer 2 rollup that uses zero-knowledge proofs to scale Ethereum without compromising on security or decentralization. Since it's EVM compatible (Solidity/Vyper), 99% of Ethereum projects can redeploy without refactoring -or re-auditing a single line of code. zkSync Era also uses an LLVM-based compiler that will eventually let developers +or re-auditing a single line of code. ZKsync Era also uses an LLVM-based compiler that will eventually let developers write smart contracts in C++, Rust and other popular languages. ## system-contracts @@ -17,7 +17,7 @@ the most commonly used contracts: each deployed contract is known. This contract also defines the derivation address. Whenever a contract is deployed, a ContractDeployed event is emitted. -`L1Messenger` This contract is used to send messages from zkSync to Ethereum. For each message sent, the L1MessageSent +`L1Messenger` This contract is used to send messages from ZKsync to Ethereum. For each message sent, the L1MessageSent event is emitted. `NonceHolder` This contract stores account nonces. The account nonces are stored in a single place for efficiency (the @@ -43,7 +43,7 @@ Update the system contracts hashes: `yarn sc calculate-hashes:fix` ### Run tests -The tests of the system contracts utilize the zkSync test node. In order to run the tests, execute the following commands in the root of the repository: +The tests of the system contracts utilize the ZKsync test node. In order to run the tests, execute the following commands in the root of the repository: ``` yarn test-node @@ -150,7 +150,7 @@ changes. ## License -The zkSync Era system-contracts are distributed under the terms of the MIT license. +The ZKsync Era system-contracts are distributed under the terms of the MIT license. See [LICENSE-MIT](LICENSE-MIT) for details. @@ -166,7 +166,7 @@ See [LICENSE-MIT](LICENSE-MIT) for details. ## Disclaimer -zkSync Era has been through lots of testing and audits. Although it is live, it is still in alpha state and will go +ZKsync Era has been through lots of testing and audits. Although it is live, it is still in alpha state and will go through more audits and bug bounties programs. We would love to hear our community's thoughts and suggestions about it! It is important to state that forking it now can potentially lead to missing important security updates, critical features, and performance improvements. diff --git a/system-contracts/SystemContractsHashes.json b/system-contracts/SystemContractsHashes.json index 7cb1c5b9c..18da55393 100644 --- a/system-contracts/SystemContractsHashes.json +++ b/system-contracts/SystemContractsHashes.json @@ -3,210 +3,210 @@ "contractName": "AccountCodeStorage", "bytecodePath": "artifacts-zk/contracts-preprocessed/AccountCodeStorage.sol/AccountCodeStorage.json", "sourceCodePath": "contracts-preprocessed/AccountCodeStorage.sol", - "bytecodeHash": "0x0100007549287362e4263ea5b204f01fc3c7f2ac09d71e6eb21029698220f01a", - "sourceCodeHash": "0xfbf66e830201c4b7fda14f0ddf28a53beb7fbb48a8406392bcfd0ef7ea9265c8" + "bytecodeHash": "0x0100005d05a277543946914759aa4a6c403604b828f80d00b900c669c3d224e1", + "sourceCodeHash": "0x2e0e09d57a04bd1e722d8bf8c6423fdf3f8bca44e5e8c4f6684f987794be066e" }, { "contractName": "BootloaderUtilities", "bytecodePath": "artifacts-zk/contracts-preprocessed/BootloaderUtilities.sol/BootloaderUtilities.json", "sourceCodePath": "contracts-preprocessed/BootloaderUtilities.sol", - "bytecodeHash": "0x010007d1e53f2dca05f7e27ae5b7062291ed3a1470ca511140b8e786aae7eb77", - "sourceCodeHash": "0x9ff5a2da00acfa145ee4575381ad386587d96b6a0309d05015974f4726881132" + "bytecodeHash": "0x010007c7bb63f64649098bf75f4baa588db20f445b4d20b7cca972d5d8f973ce", + "sourceCodeHash": "0x0f1213c4b95acb71f4ab5d4082cc1aeb2bd5017e1cccd46afc66e53268609d85" }, { "contractName": "ComplexUpgrader", "bytecodePath": "artifacts-zk/contracts-preprocessed/ComplexUpgrader.sol/ComplexUpgrader.json", "sourceCodePath": "contracts-preprocessed/ComplexUpgrader.sol", - "bytecodeHash": "0x01000055c1f27b8316ba61bf07959b11cf3b2a418aa357ccc5531c0914a2da27", - "sourceCodeHash": "0x0aa5d7ed159e783acde47856b13801b7f2268ba39b2fa50807fe3d705c506e96" + "bytecodeHash": "0x0100004da9f3aa5e4febcc53522cb7ee6949369fde25dd79e977752b82b9fd5d", + "sourceCodeHash": "0x796046a914fb676ba2bbd337b2924311ee2177ce54571c18a2c3945755c83614" }, { "contractName": "Compressor", "bytecodePath": "artifacts-zk/contracts-preprocessed/Compressor.sol/Compressor.json", "sourceCodePath": "contracts-preprocessed/Compressor.sol", - "bytecodeHash": "0x01000179842b5aa1c76036f5b90652fe614dacb28438a89649d6ca48131bd402", - "sourceCodeHash": "0xd43ac120a50398e0d6bdcfcf807154bfeece0c231509a0eb2e00bcad744e60cd" + "bytecodeHash": "0x0100014fb4f05ae09288cbcf4fa7a09ca456910f6e69be5ac2c2dfc8d71d1576", + "sourceCodeHash": "0xc6f7cd8b21aae52ed3dd5083c09b438a7af142a4ecda6067c586770e8be745a5" }, { "contractName": "ContractDeployer", "bytecodePath": "artifacts-zk/contracts-preprocessed/ContractDeployer.sol/ContractDeployer.json", "sourceCodePath": "contracts-preprocessed/ContractDeployer.sol", - "bytecodeHash": "0x010005215fda00bfbf95847a13078bd16cdcb1b875534261c1dda9940c7754fe", - "sourceCodeHash": "0x635301b824f927b4d17b3d9974cf6abbf979dda49e610805637db7c677d5f522" + "bytecodeHash": "0x010004e5d52d692822d5c54ac87de3297f39be0e4a6f72f2830ae5ac856684ee", + "sourceCodeHash": "0x82f81fbf5fb007a9cac97462d50907ca5d7a1af62d82d2645e093ed8647a5209" }, { "contractName": "Create2Factory", "bytecodePath": "artifacts-zk/contracts-preprocessed/Create2Factory.sol/Create2Factory.json", "sourceCodePath": "contracts-preprocessed/Create2Factory.sol", - "bytecodeHash": "0x0100004bc85f45ebf0f0bf004752bcbff1bb99792d6cc6494227970ec77fe53b", - "sourceCodeHash": "0x217e65f55c8add77982171da65e0db8cc10141ba75159af582973b332a4e098a" + "bytecodeHash": "0x010000495bd172e90725e6bfafe73e36a288d616d4673f5347eeb819a78bf546", + "sourceCodeHash": "0x114d9322a9ca654989f3e0b3b21f1311dbc4db84f443d054cd414f6414d84de3" }, { "contractName": "DefaultAccount", "bytecodePath": "artifacts-zk/contracts-preprocessed/DefaultAccount.sol/DefaultAccount.json", "sourceCodePath": "contracts-preprocessed/DefaultAccount.sol", - "bytecodeHash": "0x01000563374c277a2c1e34659a2a1e87371bb6d852ce142022d497bfb50b9e32", - "sourceCodeHash": "0xa42423712ddaa8f357d26e46825fda80a9a870d0ac7ff52c98884355f1173ec7" + "bytecodeHash": "0x0100055dba11508480be023137563caec69debc85f826cb3a4b68246a7cabe30", + "sourceCodeHash": "0xebffe840ebbd9329edb1ebff8ca50f6935e7dabcc67194a896fcc2e968d46dfb" }, { "contractName": "EmptyContract", "bytecodePath": "artifacts-zk/contracts-preprocessed/EmptyContract.sol/EmptyContract.json", "sourceCodePath": "contracts-preprocessed/EmptyContract.sol", - "bytecodeHash": "0x0100000781e55a60f3f14fd7dd67e3c8caab896b7b0fca4a662583959299eede", - "sourceCodeHash": "0xc88a4210dda96bc21fc852860fb74a4efeb0cc4101ffe6d928551cab46d15263" + "bytecodeHash": "0x010000078f32964c38fbd138a0369f4723f07ac6f4919c45ef738c18bf874ccd", + "sourceCodeHash": "0xcac36c5afafbcff83601f4fbfdff660aa66d8c80ed97b9322d3011c1926b554d" }, { "contractName": "ImmutableSimulator", "bytecodePath": "artifacts-zk/contracts-preprocessed/ImmutableSimulator.sol/ImmutableSimulator.json", "sourceCodePath": "contracts-preprocessed/ImmutableSimulator.sol", - "bytecodeHash": "0x0100003de00c5ceaa3fdf4566a9822ce94abe676f68b17a6ae11c453e14455fd", - "sourceCodeHash": "0x30df621c72cb35b8820b902b91057f72d0214a0e4a6b7ad4c0847e674e8b9df8" + "bytecodeHash": "0x01000039785a8e0d342a49b6b6c6e156801b816434d93bee85d33f56d56b4f9a", + "sourceCodeHash": "0x9659e69f7db09e8f60a8bb95314b1ed26afcc689851665cf27f5408122f60c98" }, { "contractName": "KnownCodesStorage", "bytecodePath": "artifacts-zk/contracts-preprocessed/KnownCodesStorage.sol/KnownCodesStorage.json", "sourceCodePath": "contracts-preprocessed/KnownCodesStorage.sol", - "bytecodeHash": "0x0100007d82d4a2eb62e539e3c89cc641f507132b247022ba05ef1ddfed2b0073", - "sourceCodeHash": "0x51d388adc58f67ef975a94a7978caa60ed8a0df9d3bd9ac723dfcfc540286c70" + "bytecodeHash": "0x0100006f0f209c9e6d06b1327db1257b15fa7a8b9864ee5ccd12cd3f8bc40ac9", + "sourceCodeHash": "0xb39b5b81168653e0c5062f7b8e1d6d15a4e186df3317f192f0cb2fc3a74f5448" }, { "contractName": "L1Messenger", "bytecodePath": "artifacts-zk/contracts-preprocessed/L1Messenger.sol/L1Messenger.json", "sourceCodePath": "contracts-preprocessed/L1Messenger.sol", - "bytecodeHash": "0x010002b97ebf3c481ead775617590ffca139bee428e443aa49eb38b6a5b83657", - "sourceCodeHash": "0x35c189f3babf5c7a9ce2590bed9eb62b59766e358b7733fdb1bc33f4c232f765" + "bytecodeHash": "0x010002955993e8ff8190e388e94a6bb791fbe9c6388e5011c52cb587a4ebf05e", + "sourceCodeHash": "0xa8768fdaac6d8804782f14e2a51bbe2b6be31dee9103b6d02d149ea8dc46eb6a" }, { "contractName": "L2BaseToken", "bytecodePath": "artifacts-zk/contracts-preprocessed/L2BaseToken.sol/L2BaseToken.json", "sourceCodePath": "contracts-preprocessed/L2BaseToken.sol", - "bytecodeHash": "0x010001039329e4bb55b24531c7e7d27ed40d2c82ad145033fdd5ed5b8ea86cf3", - "sourceCodeHash": "0x76ac95c12820d9a02cd1f177eab59092d99463816f2616e1e0f44637bf791a43" + "bytecodeHash": "0x01000103174a90beadc2cffe3e81bdb7b8a576174e888809c1953175fd3015b4", + "sourceCodeHash": "0x8bdd2b4d0b53dba84c9f0af250bbaa2aad10b3de6747bba957f0bd3721090dfa" }, { "contractName": "MsgValueSimulator", "bytecodePath": "artifacts-zk/contracts-preprocessed/MsgValueSimulator.sol/MsgValueSimulator.json", "sourceCodePath": "contracts-preprocessed/MsgValueSimulator.sol", - "bytecodeHash": "0x010000695a1e821b6d5fcb25e25793b81de0bdca3ff8277e3ac93a38e729e0a1", - "sourceCodeHash": "0x3f9e0af527875bebcdc20ca4ecb6822305877fd6038e4c4c58854d000b9ac115" + "bytecodeHash": "0x0100005da36075675b98f85fe90df11c1d526f6b12925da3a55a8b9c02aaac5f", + "sourceCodeHash": "0x082f3dcbc2fe4d93706c86aae85faa683387097d1b676e7ebd00f71ee0f13b71" }, { "contractName": "NonceHolder", "bytecodePath": "artifacts-zk/contracts-preprocessed/NonceHolder.sol/NonceHolder.json", "sourceCodePath": "contracts-preprocessed/NonceHolder.sol", - "bytecodeHash": "0x010000e563d4ad7b4822cc19d8f74f2c41ee3d3153379be4b02b27d4498d52b6", - "sourceCodeHash": "0x91847512344ac5026e9fd396189c23ad9e253f22cb6e2fe65805c20c915797d4" + "bytecodeHash": "0x010000d97de8c14cd36b1ce06cd7f44a09f6093ec8eb4041629c0fc2116d0c73", + "sourceCodeHash": "0xcd0c0366effebf2c98c58cf96322cc242a2d1c675620ef5514b7ed1f0a869edc" }, { "contractName": "PubdataChunkPublisher", "bytecodePath": "artifacts-zk/contracts-preprocessed/PubdataChunkPublisher.sol/PubdataChunkPublisher.json", "sourceCodePath": "contracts-preprocessed/PubdataChunkPublisher.sol", - "bytecodeHash": "0x01000049eb6d79244e74e5286ed4d3f6eef2b5eb746b67d98691dbc28fa16984", - "sourceCodeHash": "0xbc62d673c2cf9ba2d2148e5e2f99ea577cd357c6fd3ad7d248f670c750050faa" + "bytecodeHash": "0x010000470e396f376539289b7975b6866914a8a0994008a02987edac8be81db7", + "sourceCodeHash": "0xd7161e2c8092cf57b43c6220bc605c0e7e540bddcde1af24e2d90f75633b098e" }, { "contractName": "SystemContext", "bytecodePath": "artifacts-zk/contracts-preprocessed/SystemContext.sol/SystemContext.json", "sourceCodePath": "contracts-preprocessed/SystemContext.sol", - "bytecodeHash": "0x010001b3f2c3a6bdd5ad00ae29a7cbbb32dca3c31fb608b5cd52f8f3056a3847", - "sourceCodeHash": "0xb90284d78f48a958d082c4c877fc91ec292d05f0e388c6c78e6cce6d3b069a63" + "bytecodeHash": "0x010001a5eabf9e28288b7ab7e1db316148021347460cfb4314570956867d5af5", + "sourceCodeHash": "0xf308743981ef5cea2f7a3332b8e51695a5e47e811a63974437fc1cceee475e7a" }, { "contractName": "EventWriter", "bytecodePath": "contracts-preprocessed/artifacts/EventWriter.yul.zbin", "sourceCodePath": "contracts-preprocessed/EventWriter.yul", - "bytecodeHash": "0x010000159a3a08da3ac57cdefec0e9e30da60456bc5643134cf16d6957bcf1ac", - "sourceCodeHash": "0x55cfee65f174350edfd690c949bc0a29458f25da11f1d5f90b57621567df1fc3" + "bytecodeHash": "0x010000159b30cba9e2096353695b63ca5cbf566416a545a6bcb2ff2e4e672f98", + "sourceCodeHash": "0xfcf4828bcc109dea5f88c38f428d9ac5e18d5a2767fa4909277802c7e38c1f93" }, { "contractName": "CodeOracle", "bytecodePath": "contracts-preprocessed/precompiles/artifacts/CodeOracle.yul.zbin", "sourceCodePath": "contracts-preprocessed/precompiles/CodeOracle.yul", - "bytecodeHash": "0x01000023b02bbb21baf1367835e56ae17b82688527dc8f78caf34b12e670ee65", - "sourceCodeHash": "0x55692fab0ef8b5bab3f6fb77aec84f3d1f1cdf97c0640b327d10594ea61218d2" + "bytecodeHash": "0x01000023d652655672eafbb0adc385bd423a4a59f752a28f3dde16e74fa205e3", + "sourceCodeHash": "0x476063e7907f2b7a532c4da6f606fa07186b5a10d77af8fdd83dbea3d9f23f93" }, { "contractName": "EcAdd", "bytecodePath": "contracts-preprocessed/precompiles/artifacts/EcAdd.yul.zbin", "sourceCodePath": "contracts-preprocessed/precompiles/EcAdd.yul", - "bytecodeHash": "0x010000872dd7e2dc1b34416c174086aa84fd80c78acc7b670214da955bd55728", - "sourceCodeHash": "0xc04879ed27207cd276997a856b6507d6d003801a2ee4c4bb4491f0032370895f" + "bytecodeHash": "0x01000087be6181fcb16bebb0567c58b658eec345822aec1d42d471e84f758b85", + "sourceCodeHash": "0xdfec1c5f8c6a93df1c8821f1ac15058a18a640bcbdeb67dc4a017f2153ff1c86" }, { "contractName": "EcMul", "bytecodePath": "contracts-preprocessed/precompiles/artifacts/EcMul.yul.zbin", "sourceCodePath": "contracts-preprocessed/precompiles/EcMul.yul", - "bytecodeHash": "0x010000bd8bd7ab008f76e359dc296ff5fe0e8a95fedce1d570943e90143acdfd", - "sourceCodeHash": "0xb142465167a02139087fda7640ff859489b33081dcc7c2a8089da5b480bcb58c" + "bytecodeHash": "0x010000bd553a916fcda3726f7b6b3ccfc17887166982915ced63abc78ba43b66", + "sourceCodeHash": "0x0e3f320c8a9532425b85809bf0a2136e707046a01bf20491ec03c77887516c43" }, { "contractName": "EcPairing", "bytecodePath": "contracts-preprocessed/precompiles/artifacts/EcPairing.yul.zbin", "sourceCodePath": "contracts-preprocessed/precompiles/EcPairing.yul", - "bytecodeHash": "0x01000f1b3432a32f9fba2115f5dd3b0ee8127e7bf2c609d57d3e231f19119c43", - "sourceCodeHash": "0x149f025b222369ab65b9995a6d61df8b557b23f8b52a05f21dc2164839befb18" + "bytecodeHash": "0x01000f1b5f8dd50a00b502d2663746a49a81a01857b6ee1e1b38c9959142b299", + "sourceCodeHash": "0x5d008cedc44e0e52c2567fd2b877916b2ec5e7c80294cf99b66485e50a6f2c12" }, { "contractName": "Ecrecover", "bytecodePath": "contracts-preprocessed/precompiles/artifacts/Ecrecover.yul.zbin", "sourceCodePath": "contracts-preprocessed/precompiles/Ecrecover.yul", - "bytecodeHash": "0x0100001112e34172b2bc31574d155893a087a1cf4b608cf9895a2201ea7bd6ee", - "sourceCodeHash": "0xe2334f04fa8003d448c7e6bfb345e644f2c851328aa5b49cb30acf45d6e0bbcf" + "bytecodeHash": "0x010000113d6b03e34605f26aa1fc6fb8953561eb55bb5ea192a5a38f7de3053b", + "sourceCodeHash": "0x21e03ab7a5f518a21258669c82506b1d4d1141f8fd4f30bb385f9730580ddd3c" }, { "contractName": "Keccak256", "bytecodePath": "contracts-preprocessed/precompiles/artifacts/Keccak256.yul.zbin", "sourceCodePath": "contracts-preprocessed/precompiles/Keccak256.yul", - "bytecodeHash": "0x0100000f248e111a1b587fef850dc4585c39af2dd505bc8a0d5cc6d3fcc7ed3c", - "sourceCodeHash": "0x3e6b02b36eb6d8cebe19ae258c2aed531f9be6c261ae02d301ba31b2cd388776" + "bytecodeHash": "0x0100000ff991d5847f1e9c10c5969d0f03b34a25411ad86d5cb3e0d9c3931e0b", + "sourceCodeHash": "0xb454e7760732ce1fffc75174c8cf54dca422206cf1e52a29d274b310b574f26d" }, { "contractName": "P256Verify", "bytecodePath": "contracts-preprocessed/precompiles/artifacts/P256Verify.yul.zbin", "sourceCodePath": "contracts-preprocessed/precompiles/P256Verify.yul", - "bytecodeHash": "0x0100001169cd6aa311c1bc9bbe2e7dd085720c96bb197e3223be7e9c66e46ef9", - "sourceCodeHash": "0x4fa14862937a646a2440a8ef5c4358b59e3e53dff5f11a65a1167cd31894b94c" + "bytecodeHash": "0x010000116595cfcc96291f95d47ede2ce630f25ccbd7428f00dc7f8135fb565a", + "sourceCodeHash": "0x976b68d0362307313fd1aaea309eaa2d849187f37da451618c70dd3a6ac3cf3c" }, { "contractName": "SHA256", "bytecodePath": "contracts-preprocessed/precompiles/artifacts/SHA256.yul.zbin", "sourceCodePath": "contracts-preprocessed/precompiles/SHA256.yul", - "bytecodeHash": "0x0100001752dc8a1a374a6346781205017b7b594d97c28812265865f3a45fcb45", - "sourceCodeHash": "0x6de4b57a9cca1cfda7a8edbf6f3e06aafa32c70458a3cc09972b548714ec51d3" + "bytecodeHash": "0x010000171e4e61b14feacd43cb555bffa5f194d38117132957708dcef83ac15a", + "sourceCodeHash": "0xfd4290467e26e992f39db9ca132e78ce99ce042b0254a368f1d7832dc94ddefb" }, { "contractName": "bootloader_test", "bytecodePath": "bootloader/build/artifacts/bootloader_test.yul.zbin", "sourceCodePath": "bootloader/build/bootloader_test.yul", - "bytecodeHash": "0x010003cbf67ee7370dd2e77fb9ad39f718ded9354be174ea3009c6cb4fb8c06d", - "sourceCodeHash": "0x232e09be0ce4a92a3b77558e5724ab67e9deaf68e12e8be682a999655203b066" + "bytecodeHash": "0x010003cbe67434b2848054322cbc311385851bbfbf70d17f92cd5f1f9836b25e", + "sourceCodeHash": "0x006fdf461899dec5fdb34301c23e6819eb93e275907cbfc67d73fccfb47cae68" }, { "contractName": "fee_estimate", "bytecodePath": "bootloader/build/artifacts/fee_estimate.yul.zbin", "sourceCodePath": "bootloader/build/fee_estimate.yul", - "bytecodeHash": "0x01000951968c701c02714779299712d9da6e400e56c78d0d07acd984bfe7242a", - "sourceCodeHash": "0x9b2d51a24186af7ef58f7c8f53d77f6732f3a8d2dbde556fc8c1152957855fa5" + "bytecodeHash": "0x0100092d9b8ae575bca569f68fe60fbef1dc7d4aad6aa02cc4836f56afcf0a38", + "sourceCodeHash": "0x8a858319bac2924a3dee778218a7fe5e23898db0d87b02d7b783f94c5a02d257" }, { "contractName": "gas_test", "bytecodePath": "bootloader/build/artifacts/gas_test.yul.zbin", "sourceCodePath": "bootloader/build/gas_test.yul", - "bytecodeHash": "0x010008d7dffe019f801bf2ee23b93f83afd80ea6d20c8efe82da71fd57cbcb5c", - "sourceCodeHash": "0xf6624fe716eec6bcd5d513f069f33d758271b304009d2bdf5c5b7d0573868a1c" + "bytecodeHash": "0x010008b3e1b8bdd393f2f8d6f5c994c8b9c287df7310dee75d0c52a245fc7cb1", + "sourceCodeHash": "0x89f5ad470f10e755fa57b82507518e571c24409a328bc33aeba26e9518ad1c3e" }, { "contractName": "playground_batch", "bytecodePath": "bootloader/build/artifacts/playground_batch.yul.zbin", "sourceCodePath": "bootloader/build/playground_batch.yul", - "bytecodeHash": "0x01000957420977a293aab097a368f36b123247d87d4695a6cd27ac62598ab171", - "sourceCodeHash": "0x23293faa6627f60f8b4d61657c615cb2327162dd1e33c0968e9ab4d5dd605a20" + "bytecodeHash": "0x01000933061c23d700f3f647c45068e22f5506ff33bb516ac13f11069b163986", + "sourceCodeHash": "0x769448c4fd2b65c43d758ca5f34dd29d9b9dd3000fd0ec89cffcaf8d365a64fd" }, { "contractName": "proved_batch", "bytecodePath": "bootloader/build/artifacts/proved_batch.yul.zbin", "sourceCodePath": "bootloader/build/proved_batch.yul", - "bytecodeHash": "0x010008e742608b21bf7eb23c1a9d0602047e3618b464c9b59c0fba3b3d7ab66e", - "sourceCodeHash": "0x8ac4971296d0546fc6366caa4089489177656cbc33cc21247947d98c28c6dee4" + "bytecodeHash": "0x010008c3be57ae5800e077b6c2056d9d75ad1a7b4f0ce583407961cc6fe0b678", + "sourceCodeHash": "0x908bc6ddb34ef89b125e9637239a1149deacacd91255781d82a65a542a39036e" } ] diff --git a/system-contracts/bootloader/bootloader.yul b/system-contracts/bootloader/bootloader.yul index 85cc33dda..e995e7151 100644 --- a/system-contracts/bootloader/bootloader.yul +++ b/system-contracts/bootloader/bootloader.yul @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: MIT + object "Bootloader" { code { } @@ -11,14 +13,15 @@ object "Bootloader" { // While we definitely cannot control the pubdata price on L1, // we need to check the operator does not provide any absurd numbers there + // These number were chosen to allow for base tokens with low token/eth conversion. function MAX_ALLOWED_FAIR_PUBDATA_PRICE() -> ret { - // 1M gwei - ret := 1000000000000000 + // 2^64 - 1 wei + ret := 18446744073709551615 } function MAX_ALLOWED_FAIR_L2_GAS_PRICE() -> ret { - // 10k gwei - ret := 10000000000000 + // 2^64 - 1 wei + ret := 18446744073709551615 } /// @dev This method ensures that the prices provided by the operator @@ -619,10 +622,10 @@ object "Bootloader" { switch isETHCall case 1 { let gasLimitForTx, reservedGas := getGasLimitForTx( - innerTxDataOffset, - transactionIndex, + innerTxDataOffset, + transactionIndex, gasPerPubdata, - L2_TX_INTRINSIC_GAS(), + L2_TX_INTRINSIC_GAS(), L2_TX_INTRINSIC_PUBDATA() ) @@ -691,63 +694,6 @@ object "Bootloader" { ret := mload(0) } - /// @dev The function that is temporarily needed to upgrade the SystemContext system contract. This function is to be removed - /// once the upgrade is complete. - /// @dev Checks whether the code hash of the SystemContext contract is correct and updates it if needed. - /// @dev The bootloader calls `setPubdataInfo` before each transaction, including the upgrade one. - /// However, the old SystemContext does not have this method. So the bootloader should invoke this function - /// before starting any transaction. - function upgradeSystemContextIfNeeded() { - let expectedCodeHash := {{SYSTEM_CONTEXT_EXPECTED_CODE_HASH}} - - let actualCodeHash := getRawCodeHash(SYSTEM_CONTEXT_ADDR(), true) - if iszero(eq(expectedCodeHash, actualCodeHash)) { - // Now, we need to encode the call to the `ContractDeployer.forceDeployOnAddresses()` function. - - // The `mimicCallOnlyResult` requires that the first word of the data - // contains its length. Here it is 292 bytes. - mstore(0, 292) - mstore(32, {{PADDED_FORCE_DEPLOY_ON_ADDRESSES_SELECTOR}}) - - // The 0x20 offset, for the array of forced deployments - mstore(36, 0x0000000000000000000000000000000000000000000000000000000000000020) - // Only one force deployment - mstore(68, 0x0000000000000000000000000000000000000000000000000000000000000001) - - // Now, starts the description of the forced deployment itself. - // Firstly, the offset. - mstore(100, 0x0000000000000000000000000000000000000000000000000000000000000020) - // The new hash of the SystemContext contract. - mstore(132, expectedCodeHash) - // The address of the system context - mstore(164, SYSTEM_CONTEXT_ADDR()) - // The constructor must be called to reset the `blockGasLimit` variable - mstore(196, 0x0000000000000000000000000000000000000000000000000000000000000001) - // The value should be 0. - mstore(228, 0x0000000000000000000000000000000000000000000000000000000000000000) - // The offset of the input array. - mstore(260, 0x00000000000000000000000000000000000000000000000000000000000000a0) - // No input is provided, the array is empty. - mstore(292, 0x0000000000000000000000000000000000000000000000000000000000000000) - - // We'll use a mimicCall to simulate the correct sender. - let success := mimicCallOnlyResult( - CONTRACT_DEPLOYER_ADDR(), - FORCE_DEPLOYER(), - 0, - 0, - 0, - 0, - 0, - 0 - ) - - if iszero(success) { - assertionError("system context upgrade fail") - } - } - } - /// @dev Calculates the canonical hash of the L1->L2 transaction that will be /// sent to L1 as a message to the L1 contract that a certain operation has been processed. function getCanonicalL1TxHash(txDataOffset) -> ret { @@ -1335,7 +1281,7 @@ object "Bootloader" { /// @param gasLimitForTx The L2 gas limit for the transaction validation & execution. /// @param gasPrice The L2 gas price that should be used by the transaction. /// @param basePubdataSpent The amount of pubdata spent at the beginning of the transaction. - /// @param reservedGas The amount of gas reserved for the pubdata. + /// @param reservedGas The amount of gas reserved for the pubdata. /// @param gasPerPubdata The price of each byte of pubdata in L2 gas. /// @return gasLeft The gas left after the validation step. function l2TxValidation( @@ -1399,7 +1345,7 @@ object "Bootloader" { /// @param txDataOffset The offset to the ABI-encoded Transaction struct. /// @param gasLeft The gas left after the validation step. /// @param basePubdataSpent The amount of pubdata spent at the beginning of the transaction. - /// @param reservedGas The amount of gas reserved for the pubdata. + /// @param reservedGas The amount of gas reserved for the pubdata. /// @param gasPerPubdata The price of each byte of pubdata in L2 gas. /// @return success Whether or not the execution step was successful. /// @return gasSpentOnExecute The gas spent on the transaction execution. @@ -1496,7 +1442,7 @@ object "Bootloader" { /// @param abi The nearCall ABI. It is implicitly used as gasLimit for the call of this function. /// @param txDataOffset The offset to the ABI-encoded Transaction struct. /// @param basePubdataSpent The amount of pubdata spent at the beginning of the transaction. - /// @param reservedGas The amount of gas reserved for the pubdata. + /// @param reservedGas The amount of gas reserved for the pubdata. /// @param gasPerPubdata The price of each byte of pubdata in L2 gas. function ZKSYNC_NEAR_CALL_executeL2Tx( abi, @@ -1539,7 +1485,7 @@ object "Bootloader" { /// @param abi The nearCall ABI. It is implicitly used as gasLimit for the call of this function. /// @param txDataOffset The offset to the ABI-encoded Transaction struct. /// @param basePubdataSpent The amount of pubdata spent at the beginning of the transaction. - /// @param reservedGas The amount of gas reserved for the pubdata. + /// @param reservedGas The amount of gas reserved for the pubdata. /// @param gasPerPubdata The price of each byte of pubdata in L2 gas. function ZKSYNC_NEAR_CALL_markFactoryDepsL2( abi, @@ -1891,7 +1837,7 @@ object "Bootloader" { debugLog("from", from) debugLog("gasPrice", gasPrice) - // We assume that addresses of smart contracts on zkSync and Ethereum + // We assume that addresses of smart contracts on ZKsync and Ethereum // never overlap, so no need to check whether `from` is an EOA here. debugLog("setting tx origin", from) @@ -2324,7 +2270,7 @@ object "Bootloader" { /// @param maxRefundedGas The maximum number of gas the bootloader can be refunded. /// @param basePubdataSpent The amount of pubdata spent at the beginning of the transaction. /// @param gasPerPubdata The price of each byte of pubdata in L2 gas. - /// @param reservedGas The amount of gas reserved for the pubdata. + /// @param reservedGas The amount of gas reserved for the pubdata. /// This is the `maximum` number because it does not take into account the number of gas that /// can be spent by the paymaster itself. function ZKSYNC_NEAR_CALL_callPostOp( @@ -2608,7 +2554,7 @@ object "Bootloader" { } /// - /// zkSync-specific utilities: + /// ZKsync-specific utilities: /// /// @dev Returns an ABI that can be used for low-level @@ -2845,7 +2791,7 @@ object "Bootloader" { let spentErgs := getErgsSpentForPubdata(basePubdataSpent, gasPerPubdata) debugLog("spentErgsPubdata", spentErgs) let allowedGasLimit := add(computeGas, reservedGas) - + ret := lt(allowedGasLimit, spentErgs) } @@ -3635,7 +3581,7 @@ object "Bootloader" { } /// @dev Asks operator for the refund for the transaction. The function provides - /// the operator with the proposed refund gas by the bootloader, + /// the operator with the proposed refund gas by the bootloader, /// total spent gas on the pubdata and gas per 1 byte of pubdata. /// This function is called before the refund stage, because at that point /// only the operator knows how close does a transaction @@ -4018,8 +3964,6 @@ object "Bootloader" { assertionError("baseFee inconsistent") } - upgradeSystemContextIfNeeded() - setNewBatch(PREV_BATCH_HASH, NEW_BATCH_TIMESTAMP, NEW_BATCH_NUMBER, EXPECTED_BASE_FEE) @@ -4028,8 +3972,6 @@ object "Bootloader" { let SHOULD_SET_NEW_BATCH := mload(224) - upgradeSystemContextIfNeeded() - switch SHOULD_SET_NEW_BATCH case 0 { unsafeOverrideBatch(NEW_BATCH_TIMESTAMP, NEW_BATCH_NUMBER, EXPECTED_BASE_FEE) diff --git a/system-contracts/contracts/AccountCodeStorage.sol b/system-contracts/contracts/AccountCodeStorage.sol index 399ea54f5..4c55279c4 100644 --- a/system-contracts/contracts/AccountCodeStorage.sol +++ b/system-contracts/contracts/AccountCodeStorage.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {IAccountCodeStorage} from "./interfaces/IAccountCodeStorage.sol"; import {Utils} from "./libraries/Utils.sol"; import {DEPLOYER_SYSTEM_CONTRACT, NONCE_HOLDER_SYSTEM_CONTRACT, CURRENT_MAX_PRECOMPILE_ADDRESS} from "./Constants.sol"; +import {Unauthorized, InvalidCodeHash, CodeHashReason} from "./SystemContractErrors.sol"; /** * @author Matter Labs @@ -13,17 +14,19 @@ import {DEPLOYER_SYSTEM_CONTRACT, NONCE_HOLDER_SYSTEM_CONTRACT, CURRENT_MAX_PREC * @dev Code hash is not strictly a hash, it's a structure where the first byte denotes the version of the hash, * the second byte denotes whether the contract is constructed, and the next two bytes denote the length in 32-byte words. * And then the next 28 bytes are the truncated hash. - * @dev In this version of zkSync, the first byte of the hash MUST be 1. + * @dev In this version of ZKsync, the first byte of the hash MUST be 1. * @dev The length of each bytecode MUST be odd. It's internal code format requirements, due to padding of SHA256 function. * @dev It is also assumed that all the bytecode hashes are *known*, i.e. the full bytecodes * were published on L1 as calldata. This contract trusts the ContractDeployer and the KnownCodesStorage * system contracts to enforce the invariants mentioned above. */ contract AccountCodeStorage is IAccountCodeStorage { - bytes32 constant EMPTY_STRING_KECCAK = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; + bytes32 private constant EMPTY_STRING_KECCAK = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; modifier onlyDeployer() { - require(msg.sender == address(DEPLOYER_SYSTEM_CONTRACT), "Callable only by the deployer system contract"); + if (msg.sender != address(DEPLOYER_SYSTEM_CONTRACT)) { + revert Unauthorized(msg.sender); + } _; } @@ -34,7 +37,9 @@ contract AccountCodeStorage is IAccountCodeStorage { /// but checks whether the bytecode hash corresponds to the constructing smart contract. function storeAccountConstructingCodeHash(address _address, bytes32 _hash) external override onlyDeployer { // Check that code hash corresponds to the deploying smart contract - require(Utils.isContractConstructing(_hash), "Code hash is not for a contract on constructor"); + if (!Utils.isContractConstructing(_hash)) { + revert InvalidCodeHash(CodeHashReason.NotContractOnConstructor); + } _storeCodeHash(_address, _hash); } @@ -45,7 +50,9 @@ contract AccountCodeStorage is IAccountCodeStorage { /// but checks whether the bytecode hash corresponds to the constructed smart contract. function storeAccountConstructedCodeHash(address _address, bytes32 _hash) external override onlyDeployer { // Check that code hash corresponds to the deploying smart contract - require(Utils.isContractConstructed(_hash), "Code hash is not for a constructed contract"); + if (!Utils.isContractConstructed(_hash)) { + revert InvalidCodeHash(CodeHashReason.NotConstructedContract); + } _storeCodeHash(_address, _hash); } @@ -54,7 +61,9 @@ contract AccountCodeStorage is IAccountCodeStorage { function markAccountCodeHashAsConstructed(address _address) external override onlyDeployer { bytes32 codeHash = getRawCodeHash(_address); - require(Utils.isContractConstructing(codeHash), "Code hash is not for a contract on constructor"); + if (!Utils.isContractConstructing(codeHash)) { + revert InvalidCodeHash(CodeHashReason.NotContractOnConstructor); + } // Get the bytecode hash with "isConstructor" flag equal to false bytes32 constructedBytecodeHash = Utils.constructedBytecodeHash(codeHash); diff --git a/system-contracts/contracts/BootloaderUtilities.sol b/system-contracts/contracts/BootloaderUtilities.sol index 5551764dd..4fd38da74 100644 --- a/system-contracts/contracts/BootloaderUtilities.sol +++ b/system-contracts/contracts/BootloaderUtilities.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {IBootloaderUtilities} from "./interfaces/IBootloaderUtilities.sol"; import {Transaction, TransactionHelper, EIP_712_TX_TYPE, LEGACY_TX_TYPE, EIP_2930_TX_TYPE, EIP_1559_TX_TYPE} from "./libraries/TransactionHelper.sol"; import {RLPEncoder} from "./libraries/RLPEncoder.sol"; import {EfficientCall} from "./libraries/EfficientCall.sol"; +import {UnsupportedTxType, InvalidSig, SigField} from "./SystemContractErrors.sol"; /** * @author Matter Labs @@ -34,7 +35,7 @@ contract BootloaderUtilities is IBootloaderUtilities { } else if (_transaction.txType == EIP_2930_TX_TYPE) { txHash = encodeEIP2930TransactionHash(_transaction); } else { - revert("Unsupported tx type"); + revert UnsupportedTxType(_transaction.txType); } } @@ -89,7 +90,9 @@ contract BootloaderUtilities is IBootloaderUtilities { bytes memory vEncoded; { uint256 vInt = uint256(uint8(_transaction.signature[64])); - require(vInt == 27 || vInt == 28, "Invalid v value"); + if (vInt != 27 && vInt != 28) { + revert InvalidSig(SigField.V, vInt); + } // If the `chainId` is specified in the transaction, then the `v` value is encoded as // `35 + y + 2 * chainId == vInt + 8 + 2 * chainId`, where y - parity bit (see EIP-155). @@ -174,7 +177,7 @@ contract BootloaderUtilities is IBootloaderUtilities { // Otherwise the length is not encoded at all. } - // On zkSync, access lists are always zero length (at least for now). + // On ZKsync, access lists are always zero length (at least for now). bytes memory encodedAccessListLength = RLPEncoder.encodeListLen(0); bytes memory rEncoded; @@ -190,7 +193,9 @@ contract BootloaderUtilities is IBootloaderUtilities { bytes memory vEncoded; { uint256 vInt = uint256(uint8(_transaction.signature[64])); - require(vInt == 27 || vInt == 28, "Invalid v value"); + if (vInt != 27 && vInt != 28) { + revert InvalidSig(SigField.V, vInt); + } vEncoded = RLPEncoder.encodeUint256(vInt - 27); } @@ -271,7 +276,7 @@ contract BootloaderUtilities is IBootloaderUtilities { // Otherwise the length is not encoded at all. } - // On zkSync, access lists are always zero length (at least for now). + // On ZKsync, access lists are always zero length (at least for now). bytes memory encodedAccessListLength = RLPEncoder.encodeListLen(0); bytes memory rEncoded; @@ -287,7 +292,9 @@ contract BootloaderUtilities is IBootloaderUtilities { bytes memory vEncoded; { uint256 vInt = uint256(uint8(_transaction.signature[64])); - require(vInt == 27 || vInt == 28, "Invalid v value"); + if (vInt != 27 && vInt != 28) { + revert InvalidSig(SigField.V, vInt); + } vEncoded = RLPEncoder.encodeUint256(vInt - 27); } diff --git a/system-contracts/contracts/ComplexUpgrader.sol b/system-contracts/contracts/ComplexUpgrader.sol index 2f4d886cd..a69545148 100644 --- a/system-contracts/contracts/ComplexUpgrader.sol +++ b/system-contracts/contracts/ComplexUpgrader.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {IComplexUpgrader} from "./interfaces/IComplexUpgrader.sol"; import {FORCE_DEPLOYER} from "./Constants.sol"; +import {Unauthorized, AddressHasNoCode} from "./SystemContractErrors.sol"; /** * @author Matter Labs @@ -19,9 +20,13 @@ contract ComplexUpgrader is IComplexUpgrader { /// @param _delegateTo the address of the contract to which the calls will be delegated /// @param _calldata the calldata to be delegate called in the `_delegateTo` contract function upgrade(address _delegateTo, bytes calldata _calldata) external payable { - require(msg.sender == FORCE_DEPLOYER, "Can only be called by FORCE_DEPLOYER"); + if (msg.sender != FORCE_DEPLOYER) { + revert Unauthorized(msg.sender); + } - require(_delegateTo.code.length > 0, "Delegatee is an EOA"); + if (_delegateTo.code.length == 0) { + revert AddressHasNoCode(_delegateTo); + } (bool success, bytes memory returnData) = _delegateTo.delegatecall(_calldata); assembly { if iszero(success) { diff --git a/system-contracts/contracts/Compressor.sol b/system-contracts/contracts/Compressor.sol index f52c18ed4..d4c52f989 100644 --- a/system-contracts/contracts/Compressor.sol +++ b/system-contracts/contracts/Compressor.sol @@ -1,13 +1,14 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {ICompressor, OPERATION_BITMASK, LENGTH_BITS_OFFSET, MAX_ENUMERATION_INDEX_SIZE} from "./interfaces/ICompressor.sol"; -import {ISystemContract} from "./interfaces/ISystemContract.sol"; +import {SystemContractBase} from "./abstract/SystemContractBase.sol"; import {Utils} from "./libraries/Utils.sol"; import {UnsafeBytesCalldata} from "./libraries/UnsafeBytesCalldata.sol"; import {EfficientCall} from "./libraries/EfficientCall.sol"; import {L1_MESSENGER_CONTRACT, STATE_DIFF_ENTRY_SIZE, KNOWN_CODE_STORAGE_CONTRACT} from "./Constants.sol"; +import {DerivedKeyNotEqualToCompressedValue, EncodedAndRealBytecodeChunkNotEqual, DictionaryDividedByEightNotGreaterThanEncodedDividedByTwo, EncodedLengthNotFourTimesSmallerThanOriginal, IndexOutOfBounds, IndexSizeError, UnsupportedOperation, CompressorInitialWritesProcessedNotEqual, CompressorEnumIndexNotEqual, StateDiffLengthMismatch, CompressionValueTransformError, CompressionValueAddError, CompressionValueSubError} from "./SystemContractErrors.sol"; /** * @author Matter Labs @@ -19,7 +20,7 @@ import {L1_MESSENGER_CONTRACT, STATE_DIFF_ENTRY_SIZE, KNOWN_CODE_STORAGE_CONTRAC * Or the user may compress the bytecode and publish it instead (fewer data onchain!). At the end of every L1 Batch * we publish pubdata, part of which contains the state diffs that occurred within the batch. */ -contract Compressor is ICompressor, ISystemContract { +contract Compressor is ICompressor, SystemContractBase { using UnsafeBytesCalldata for bytes; /// @notice Verify the compressed bytecode and publish it on the L1. @@ -48,24 +49,28 @@ contract Compressor is ICompressor, ISystemContract { unchecked { (bytes calldata dictionary, bytes calldata encodedData) = _decodeRawBytecode(_rawCompressedData); - require( - encodedData.length * 4 == _bytecode.length, - "Encoded data length should be 4 times shorter than the original bytecode" - ); + if (encodedData.length * 4 != _bytecode.length) { + revert EncodedLengthNotFourTimesSmallerThanOriginal(); + } - require( - dictionary.length / 8 <= encodedData.length / 2, - "Dictionary should have at most the same number of entries as the encoded data" - ); + if (dictionary.length / 8 > encodedData.length / 2) { + revert DictionaryDividedByEightNotGreaterThanEncodedDividedByTwo(); + } + // We disable this check because calldata array length is cheap. + // solhint-disable-next-line gas-length-in-loops for (uint256 encodedDataPointer = 0; encodedDataPointer < encodedData.length; encodedDataPointer += 2) { uint256 indexOfEncodedChunk = uint256(encodedData.readUint16(encodedDataPointer)) * 8; - require(indexOfEncodedChunk < dictionary.length, "Encoded chunk index is out of bounds"); + if (indexOfEncodedChunk > dictionary.length - 1) { + revert IndexOutOfBounds(); + } uint64 encodedChunk = dictionary.readUint64(indexOfEncodedChunk); uint64 realChunk = _bytecode.readUint64(encodedDataPointer * 4); - require(encodedChunk == realChunk, "Encoded chunk does not match the original bytecode"); + if (encodedChunk != realChunk) { + revert EncodedAndRealBytecodeChunkNotEqual(realChunk, encodedChunk); + } } } @@ -116,7 +121,9 @@ contract Compressor is ICompressor, ISystemContract { // We do not enforce the operator to use the optimal, i.e. the minimally possible _enumerationIndexSize. // We do enforce however, that the _enumerationIndexSize is not larger than 8 bytes long, which is the // maximal ever possible size for enumeration index. - require(_enumerationIndexSize <= MAX_ENUMERATION_INDEX_SIZE, "enumeration index size is too large"); + if (_enumerationIndexSize > MAX_ENUMERATION_INDEX_SIZE) { + revert IndexSizeError(); + } uint256 numberOfInitialWrites = uint256(_compressedStateDiffs.readUint16(0)); @@ -132,16 +139,19 @@ contract Compressor is ICompressor, ISystemContract { continue; } - numInitialWritesProcessed++; + ++numInitialWritesProcessed; bytes32 derivedKey = stateDiff.readBytes32(52); uint256 initValue = stateDiff.readUint256(92); uint256 finalValue = stateDiff.readUint256(124); - require(derivedKey == _compressedStateDiffs.readBytes32(stateDiffPtr), "iw: initial key mismatch"); + bytes32 compressedDerivedKey = _compressedStateDiffs.readBytes32(stateDiffPtr); + if (derivedKey != compressedDerivedKey) { + revert DerivedKeyNotEqualToCompressedValue(derivedKey, compressedDerivedKey); + } stateDiffPtr += 32; uint8 metadata = uint8(bytes1(_compressedStateDiffs[stateDiffPtr])); - stateDiffPtr++; + ++stateDiffPtr; uint8 operation = metadata & OPERATION_BITMASK; uint8 len = operation == 0 ? 32 : metadata >> LENGTH_BITS_OFFSET; _verifyValueCompression( @@ -153,7 +163,9 @@ contract Compressor is ICompressor, ISystemContract { stateDiffPtr += len; } - require(numInitialWritesProcessed == numberOfInitialWrites, "Incorrect number of initial storage diffs"); + if (numInitialWritesProcessed != numberOfInitialWrites) { + revert CompressorInitialWritesProcessedNotEqual(numberOfInitialWrites, numInitialWritesProcessed); + } // Process repeated writes for (uint256 i = 0; i < _numberOfStateDiffs * STATE_DIFF_ENTRY_SIZE; i += STATE_DIFF_ENTRY_SIZE) { @@ -168,11 +180,13 @@ contract Compressor is ICompressor, ISystemContract { uint256 compressedEnumIndex = _sliceToUint256( _compressedStateDiffs[stateDiffPtr:stateDiffPtr + _enumerationIndexSize] ); - require(enumIndex == compressedEnumIndex, "rw: enum key mismatch"); + if (enumIndex != compressedEnumIndex) { + revert CompressorEnumIndexNotEqual(enumIndex, compressedEnumIndex); + } stateDiffPtr += _enumerationIndexSize; uint8 metadata = uint8(bytes1(_compressedStateDiffs[stateDiffPtr])); - stateDiffPtr += 1; + ++stateDiffPtr; uint8 operation = metadata & OPERATION_BITMASK; uint8 len = operation == 0 ? 32 : metadata >> LENGTH_BITS_OFFSET; _verifyValueCompression( @@ -184,7 +198,9 @@ contract Compressor is ICompressor, ISystemContract { stateDiffPtr += len; } - require(stateDiffPtr == _compressedStateDiffs.length, "Extra data in _compressedStateDiffs"); + if (stateDiffPtr != _compressedStateDiffs.length) { + revert StateDiffLengthMismatch(); + } stateDiffHash = EfficientCall.keccak(_stateDiffs); } @@ -227,19 +243,19 @@ contract Compressor is ICompressor, ISystemContract { unchecked { if (_operation == 0 || _operation == 3) { - require(convertedValue == _finalValue, "transform or no compression: compressed and final mismatch"); + if (convertedValue != _finalValue) { + revert CompressionValueTransformError(_finalValue, convertedValue); + } } else if (_operation == 1) { - require( - _initialValue + convertedValue == _finalValue, - "add: initial plus converted not equal to final" - ); + if (_initialValue + convertedValue != _finalValue) { + revert CompressionValueAddError(_finalValue, _initialValue + convertedValue); + } } else if (_operation == 2) { - require( - _initialValue - convertedValue == _finalValue, - "sub: initial minus converted not equal to final" - ); + if (_initialValue - convertedValue != _finalValue) { + revert CompressionValueSubError(_finalValue, _initialValue - convertedValue); + } } else { - revert("unsupported operation"); + revert UnsupportedOperation(); } } } diff --git a/system-contracts/contracts/Constants.sol b/system-contracts/contracts/Constants.sol index 0f8e2307f..00145480b 100644 --- a/system-contracts/contracts/Constants.sol +++ b/system-contracts/contracts/Constants.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 {IAccountCodeStorage} from "./interfaces/IAccountCodeStorage.sol"; import {INonceHolder} from "./interfaces/INonceHolder.sol"; @@ -15,7 +15,7 @@ import {IComplexUpgrader} from "./interfaces/IComplexUpgrader.sol"; import {IBootloaderUtilities} from "./interfaces/IBootloaderUtilities.sol"; import {IPubdataChunkPublisher} from "./interfaces/IPubdataChunkPublisher.sol"; -/// @dev All the system contracts introduced by zkSync have their addresses +/// @dev All the system contracts introduced by ZKsync have their addresses /// started from 2^15 in order to avoid collision with Ethereum precompiles. uint160 constant SYSTEM_CONTRACTS_OFFSET = {{SYSTEM_CONTRACTS_OFFSET}}; // 2^15 @@ -35,7 +35,7 @@ address constant ECMUL_SYSTEM_CONTRACT = address(0x07); address constant ECPAIRING_SYSTEM_CONTRACT = address(0x08); -/// @dev The number of ergs that need to be spent for a single byte of pubdata regardless of the pubdata price. +/// @dev The number of gas that need to be spent for a single byte of pubdata regardless of the pubdata price. /// This variable is used to ensure the following: /// - That the long-term storage of the operator is compensated properly. /// - That it is not possible that the pubdata counter grows too high without spending proportional amount of computation. diff --git a/system-contracts/contracts/ContractDeployer.sol b/system-contracts/contracts/ContractDeployer.sol index 01009da19..8e9bda169 100644 --- a/system-contracts/contracts/ContractDeployer.sol +++ b/system-contracts/contracts/ContractDeployer.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {ImmutableData} from "./interfaces/IImmutableSimulator.sol"; import {IContractDeployer} from "./interfaces/IContractDeployer.sol"; @@ -9,24 +9,27 @@ import {CREATE2_PREFIX, CREATE_PREFIX, NONCE_HOLDER_SYSTEM_CONTRACT, ACCOUNT_COD import {Utils} from "./libraries/Utils.sol"; import {EfficientCall} from "./libraries/EfficientCall.sol"; import {SystemContractHelper} from "./libraries/SystemContractHelper.sol"; -import {ISystemContract} from "./interfaces/ISystemContract.sol"; +import {SystemContractBase} from "./abstract/SystemContractBase.sol"; +import {Unauthorized, InvalidNonceOrderingChange, ValueMismatch, EmptyBytes32, NotAllowedToDeployInKernelSpace, HashIsNonZero, NonEmptyAccount, UnknownCodeHash, NonEmptyMsgValue} from "./SystemContractErrors.sol"; /** * @author Matter Labs * @custom:security-contact security@matterlabs.dev - * @notice System smart contract that is responsible for deploying other smart contracts on zkSync. + * @notice System smart contract that is responsible for deploying other smart contracts on ZKsync. * @dev The contract is responsible for generating the address of the deployed smart contract, * incrementing the deployment nonce and making sure that the constructor is never called twice in a contract. * Note, contracts with bytecode that have already been published to L1 once * do not need to be published anymore. */ -contract ContractDeployer is IContractDeployer, ISystemContract { +contract ContractDeployer is IContractDeployer, SystemContractBase { /// @notice Information about an account contract. /// @dev For EOA and simple contracts (i.e. not accounts) this value is 0. mapping(address => AccountInfo) internal accountInfo; modifier onlySelf() { - require(msg.sender == address(this), "Callable only by self"); + if (msg.sender != address(this)) { + revert Unauthorized(msg.sender); + } _; } @@ -74,11 +77,12 @@ contract ContractDeployer is IContractDeployer, ISystemContract { function updateNonceOrdering(AccountNonceOrdering _nonceOrdering) external onlySystemCall { AccountInfo memory currentInfo = accountInfo[msg.sender]; - require( - _nonceOrdering == AccountNonceOrdering.Arbitrary && - currentInfo.nonceOrdering == AccountNonceOrdering.Sequential, - "It is only possible to change from sequential to arbitrary ordering" - ); + if ( + _nonceOrdering != AccountNonceOrdering.Arbitrary || + currentInfo.nonceOrdering != AccountNonceOrdering.Sequential + ) { + revert InvalidNonceOrderingChange(); + } currentInfo.nonceOrdering = _nonceOrdering; _storeAccountInfo(msg.sender, currentInfo); @@ -237,10 +241,9 @@ contract ContractDeployer is IContractDeployer, ISystemContract { /// @dev We do not require `onlySystemCall` here, since the method is accessible only /// by `FORCE_DEPLOYER`. function forceDeployOnAddresses(ForceDeployment[] calldata _deployments) external payable { - require( - msg.sender == FORCE_DEPLOYER || msg.sender == address(COMPLEX_UPGRADER_CONTRACT), - "Can only be called by FORCE_DEPLOYER or COMPLEX_UPGRADER_CONTRACT" - ); + if (msg.sender != FORCE_DEPLOYER && msg.sender != address(COMPLEX_UPGRADER_CONTRACT)) { + revert Unauthorized(msg.sender); + } uint256 deploymentsLength = _deployments.length; // We need to ensure that the `value` provided by the call is enough to provide `value` @@ -249,7 +252,9 @@ contract ContractDeployer is IContractDeployer, ISystemContract { for (uint256 i = 0; i < deploymentsLength; ++i) { sumOfValues += _deployments[i].value; } - require(msg.value == sumOfValues, "`value` provided is not equal to the combined `value`s of deployments"); + if (msg.value != sumOfValues) { + revert ValueMismatch(sumOfValues, msg.value); + } for (uint256 i = 0; i < deploymentsLength; ++i) { this.forceDeployOnAddress{value: _deployments[i].value}(_deployments[i], msg.sender); @@ -262,16 +267,22 @@ contract ContractDeployer is IContractDeployer, ISystemContract { AccountAbstractionVersion _aaVersion, bytes calldata _input ) internal { - require(_bytecodeHash != bytes32(0x0), "BytecodeHash cannot be zero"); - require(uint160(_newAddress) > MAX_SYSTEM_CONTRACT_ADDRESS, "Can not deploy contracts in kernel space"); + if (_bytecodeHash == bytes32(0x0)) { + revert EmptyBytes32(); + } + if (uint160(_newAddress) <= MAX_SYSTEM_CONTRACT_ADDRESS) { + revert NotAllowedToDeployInKernelSpace(); + } // We do not allow deploying twice on the same address. - require( - ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT.getCodeHash(uint256(uint160(_newAddress))) == 0x0, - "Code hash is non-zero" - ); + bytes32 codeHash = ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT.getCodeHash(uint256(uint160(_newAddress))); + if (codeHash != 0x0) { + revert HashIsNonZero(codeHash); + } // Do not allow deploying contracts to default accounts that have already executed transactions. - require(NONCE_HOLDER_SYSTEM_CONTRACT.getRawNonce(_newAddress) == 0x00, "Account is occupied"); + if (NONCE_HOLDER_SYSTEM_CONTRACT.getRawNonce(_newAddress) != 0x00) { + revert NonEmptyAccount(); + } _performDeployOnAddress(_bytecodeHash, _newAddress, _aaVersion, _input); } @@ -308,7 +319,9 @@ contract ContractDeployer is IContractDeployer, ISystemContract { /// @notice Check that bytecode hash is marked as known on the `KnownCodeStorage` system contracts function _ensureBytecodeIsKnown(bytes32 _bytecodeHash) internal view { uint256 knownCodeMarker = KNOWN_CODE_STORAGE_CONTRACT.getMarker(_bytecodeHash); - require(knownCodeMarker > 0, "The code hash is not known"); + if (knownCodeMarker == 0) { + revert UnknownCodeHash(_bytecodeHash); + } } /// @notice Ensures that the _newAddress and assigns a new contract hash to it @@ -362,7 +375,9 @@ contract ContractDeployer is IContractDeployer, ISystemContract { ImmutableData[] memory immutables = abi.decode(returnData, (ImmutableData[])); IMMUTABLE_SIMULATOR_SYSTEM_CONTRACT.setImmutables(_newAddress, immutables); } else { - require(value == 0, "The value must be zero if we do not call the constructor"); + if (value != 0) { + revert NonEmptyMsgValue(); + } // If we do not call the constructor, we need to set the constructed code hash. ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT.storeAccountConstructedCodeHash(_newAddress, _bytecodeHash); } diff --git a/system-contracts/contracts/Create2Factory.sol b/system-contracts/contracts/Create2Factory.sol index 6f68fbb52..868de66fa 100644 --- a/system-contracts/contracts/Create2Factory.sol +++ b/system-contracts/contracts/Create2Factory.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {REAL_DEPLOYER_SYSTEM_CONTRACT} from "./Constants.sol"; import {EfficientCall} from "./libraries/EfficientCall.sol"; diff --git a/system-contracts/contracts/DefaultAccount.sol b/system-contracts/contracts/DefaultAccount.sol index 4c7356dd8..40a38e49b 100644 --- a/system-contracts/contracts/DefaultAccount.sol +++ b/system-contracts/contracts/DefaultAccount.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {IAccount, ACCOUNT_VALIDATION_SUCCESS_MAGIC} from "./interfaces/IAccount.sol"; import {TransactionHelper, Transaction} from "./libraries/TransactionHelper.sol"; @@ -9,6 +9,7 @@ import {SystemContractHelper} from "./libraries/SystemContractHelper.sol"; import {EfficientCall} from "./libraries/EfficientCall.sol"; import {BOOTLOADER_FORMAL_ADDRESS, NONCE_HOLDER_SYSTEM_CONTRACT, DEPLOYER_SYSTEM_CONTRACT, INonceHolder} from "./Constants.sol"; import {Utils} from "./libraries/Utils.sol"; +import {InsufficientFunds, InvalidSig, SigField, FailedToPayOperator} from "./SystemContractErrors.sol"; /** * @author Matter Labs @@ -99,7 +100,9 @@ contract DefaultAccount is IAccount { // should be checked explicitly to prevent user paying for fee for a // transaction that wouldn't be included on Ethereum. uint256 totalRequiredBalance = _transaction.totalRequiredBalance(); - require(totalRequiredBalance <= address(this).balance, "Not enough balance for fee + value"); + if (totalRequiredBalance > address(this).balance) { + revert InsufficientFunds(totalRequiredBalance, address(this).balance); + } if (_isValidSignature(txHash, _transaction.signature)) { magic = ACCOUNT_VALIDATION_SUCCESS_MAGIC; @@ -165,7 +168,9 @@ contract DefaultAccount is IAccount { /// @param _signature The signature of the transaction. /// @return EIP1271_SUCCESS_RETURN_VALUE if the signature is correct. It reverts otherwise. function _isValidSignature(bytes32 _hash, bytes memory _signature) internal view returns (bool) { - require(_signature.length == 65, "Signature length is incorrect"); + if (_signature.length != 65) { + revert InvalidSig(SigField.Length, _signature.length); + } uint8 v; bytes32 r; bytes32 s; @@ -178,7 +183,9 @@ contract DefaultAccount is IAccount { s := mload(add(_signature, 0x40)) v := and(mload(add(_signature, 0x41)), 0xff) } - require(v == 27 || v == 28, "v is neither 27 nor 28"); + if (v != 27 && v != 28) { + revert InvalidSig(SigField.V, v); + } // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines @@ -189,7 +196,9 @@ contract DefaultAccount is IAccount { // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. - require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "Invalid s"); + if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { + revert InvalidSig(SigField.S, uint256(s)); + } address recoveredAddress = ecrecover(_hash, v, r, s); @@ -207,7 +216,9 @@ contract DefaultAccount is IAccount { Transaction calldata _transaction ) external payable ignoreNonBootloader ignoreInDelegateCall { bool success = _transaction.payToTheBootloader(); - require(success, "Failed to pay the fee to the operator"); + if (!success) { + revert FailedToPayOperator(); + } } /// @notice Method, where the user should prepare for the transaction to be diff --git a/system-contracts/contracts/EmptyContract.sol b/system-contracts/contracts/EmptyContract.sol index 3f021964a..15516a7b3 100644 --- a/system-contracts/contracts/EmptyContract.sol +++ b/system-contracts/contracts/EmptyContract.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; /** * @author Matter Labs diff --git a/system-contracts/contracts/EventWriter.yul b/system-contracts/contracts/EventWriter.yul index 4cd4a3814..c85151b90 100644 --- a/system-contracts/contracts/EventWriter.yul +++ b/system-contracts/contracts/EventWriter.yul @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: MIT + /** * @author Matter Labs * @custom:security-contact security@matterlabs.dev diff --git a/system-contracts/contracts/ImmutableSimulator.sol b/system-contracts/contracts/ImmutableSimulator.sol index 2d077316a..93110d782 100644 --- a/system-contracts/contracts/ImmutableSimulator.sol +++ b/system-contracts/contracts/ImmutableSimulator.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {IImmutableSimulator, ImmutableData} from "./interfaces/IImmutableSimulator.sol"; import {DEPLOYER_SYSTEM_CONTRACT} from "./Constants.sol"; +import {Unauthorized} from "./SystemContractErrors.sol"; /** * @author Matter Labs @@ -32,7 +33,9 @@ contract ImmutableSimulator is IImmutableSimulator { /// @param _dest The address which to store the immutables for. /// @param _immutables The list of the immutables. function setImmutables(address _dest, ImmutableData[] calldata _immutables) external override { - require(msg.sender == address(DEPLOYER_SYSTEM_CONTRACT), "Callable only by the deployer system contract"); + if (msg.sender != address(DEPLOYER_SYSTEM_CONTRACT)) { + revert Unauthorized(msg.sender); + } unchecked { uint256 immutablesLength = _immutables.length; for (uint256 i = 0; i < immutablesLength; ++i) { diff --git a/system-contracts/contracts/KnownCodesStorage.sol b/system-contracts/contracts/KnownCodesStorage.sol index 3db07fe31..31fa04734 100644 --- a/system-contracts/contracts/KnownCodesStorage.sol +++ b/system-contracts/contracts/KnownCodesStorage.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {IKnownCodesStorage} from "./interfaces/IKnownCodesStorage.sol"; -import {ISystemContract} from "./interfaces/ISystemContract.sol"; +import {SystemContractBase} from "./abstract/SystemContractBase.sol"; import {Utils} from "./libraries/Utils.sol"; import {COMPRESSOR_CONTRACT, L1_MESSENGER_CONTRACT} from "./Constants.sol"; +import {Unauthorized, MalformedBytecode, BytecodeError} from "./SystemContractErrors.sol"; /** * @author Matter Labs @@ -15,9 +16,11 @@ import {COMPRESSOR_CONTRACT, L1_MESSENGER_CONTRACT} from "./Constants.sol"; * the second byte denotes whether the contract is constructed, and the next two bytes denote the length in 32-byte words. * And then the next 28 bytes is the truncated hash. */ -contract KnownCodesStorage is IKnownCodesStorage, ISystemContract { +contract KnownCodesStorage is IKnownCodesStorage, SystemContractBase { modifier onlyCompressor() { - require(msg.sender == address(COMPRESSOR_CONTRACT), "Callable only by the compressor"); + if (msg.sender != address(COMPRESSOR_CONTRACT)) { + revert Unauthorized(msg.sender); + } _; } @@ -73,8 +76,12 @@ contract KnownCodesStorage is IKnownCodesStorage, ISystemContract { /// That's why we need to validate it function _validateBytecode(bytes32 _bytecodeHash) internal pure { uint8 version = uint8(_bytecodeHash[0]); - require(version == 1 && _bytecodeHash[1] == bytes1(0), "Incorrectly formatted bytecodeHash"); + if (version != 1 || _bytecodeHash[1] != bytes1(0)) { + revert MalformedBytecode(BytecodeError.Version); + } - require(Utils.bytecodeLenInWords(_bytecodeHash) % 2 == 1, "Code length in words must be odd"); + if (Utils.bytecodeLenInWords(_bytecodeHash) % 2 == 0) { + revert MalformedBytecode(BytecodeError.NumberOfWords); + } } } diff --git a/system-contracts/contracts/L1Messenger.sol b/system-contracts/contracts/L1Messenger.sol index 2b584d110..f9578b19b 100644 --- a/system-contracts/contracts/L1Messenger.sol +++ b/system-contracts/contracts/L1Messenger.sol @@ -1,13 +1,14 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {IL1Messenger, L2ToL1Log, L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH, L2_TO_L1_LOG_SERIALIZE_SIZE, STATE_DIFF_COMPRESSION_VERSION_NUMBER} from "./interfaces/IL1Messenger.sol"; -import {ISystemContract} from "./interfaces/ISystemContract.sol"; +import {SystemContractBase} from "./abstract/SystemContractBase.sol"; import {SystemContractHelper} from "./libraries/SystemContractHelper.sol"; import {EfficientCall} from "./libraries/EfficientCall.sol"; import {Utils} from "./libraries/Utils.sol"; import {SystemLogKey, SYSTEM_CONTEXT_CONTRACT, KNOWN_CODE_STORAGE_CONTRACT, COMPRESSOR_CONTRACT, STATE_DIFF_ENTRY_SIZE, L2_TO_L1_LOGS_MERKLE_TREE_LEAVES, PUBDATA_CHUNK_PUBLISHER, COMPUTATIONAL_PRICE_FOR_PUBDATA} from "./Constants.sol"; +import {ReconstructionMismatch, PubdataField} from "./SystemContractErrors.sol"; /** * @author Matter Labs @@ -22,7 +23,7 @@ import {SystemLogKey, SYSTEM_CONTEXT_CONTRACT, KNOWN_CODE_STORAGE_CONTRACT, COMP * - The contract on L1 accepts all sent messages and if the message came from this system contract * it requires that the preimage of `value` be provided. */ -contract L1Messenger is IL1Messenger, ISystemContract { +contract L1Messenger is IL1Messenger, SystemContractBase { /// @notice Sequential hash of logs sent in the current block. /// @dev Will be reset at the end of the block to zero value. bytes32 internal chainedLogsHash; @@ -87,7 +88,7 @@ contract L1Messenger is IL1Messenger, ISystemContract { // - at most 1 time keccakGasCost(64) when building the Merkle tree (as merkle tree can contain // ~2*N nodes, where the first N nodes are leaves the hash of which is calculated on the previous step). uint256 gasToPay = keccakGasCost(L2_TO_L1_LOG_SERIALIZE_SIZE) + 2 * keccakGasCost(64); - SystemContractHelper.burnGas(Utils.safeCastToU32(gasToPay), 0); + SystemContractHelper.burnGas(Utils.safeCastToU32(gasToPay), uint32(L2_TO_L1_LOG_SERIALIZE_SIZE)); } /// @notice Internal function to send L2ToL1Log. @@ -107,7 +108,7 @@ contract L1Messenger is IL1Messenger, ISystemContract { chainedLogsHash = keccak256(abi.encode(chainedLogsHash, hashedLog)); logIdInMerkleTree = numberOfLogsToProcess; - numberOfLogsToProcess++; + ++numberOfLogsToProcess; emit L2ToL1LogSent(_l2ToL1Log); } @@ -198,11 +199,17 @@ contract L1Messenger is IL1Messenger, ISystemContract { /// Check logs uint32 numberOfL2ToL1Logs = uint32(bytes4(_totalL2ToL1PubdataAndStateDiffs[calldataPtr:calldataPtr + 4])); - require(numberOfL2ToL1Logs <= L2_TO_L1_LOGS_MERKLE_TREE_LEAVES, "Too many L2->L1 logs"); + if (numberOfL2ToL1Logs > L2_TO_L1_LOGS_MERKLE_TREE_LEAVES) { + revert ReconstructionMismatch( + PubdataField.NumberOfLogs, + bytes32(L2_TO_L1_LOGS_MERKLE_TREE_LEAVES), + bytes32(uint256(numberOfL2ToL1Logs)) + ); + } calldataPtr += 4; bytes32[] memory l2ToL1LogsTreeArray = new bytes32[](L2_TO_L1_LOGS_MERKLE_TREE_LEAVES); - bytes32 reconstructedChainedLogsHash; + bytes32 reconstructedChainedLogsHash = bytes32(0); for (uint256 i = 0; i < numberOfL2ToL1Logs; ++i) { bytes32 hashedLog = EfficientCall.keccak( _totalL2ToL1PubdataAndStateDiffs[calldataPtr:calldataPtr + L2_TO_L1_LOG_SERIALIZE_SIZE] @@ -211,10 +218,9 @@ contract L1Messenger is IL1Messenger, ISystemContract { l2ToL1LogsTreeArray[i] = hashedLog; reconstructedChainedLogsHash = keccak256(abi.encode(reconstructedChainedLogsHash, hashedLog)); } - require( - reconstructedChainedLogsHash == chainedLogsHash, - "reconstructedChainedLogsHash is not equal to chainedLogsHash" - ); + if (reconstructedChainedLogsHash != chainedLogsHash) { + revert ReconstructionMismatch(PubdataField.LogsHash, chainedLogsHash, reconstructedChainedLogsHash); + } for (uint256 i = numberOfL2ToL1Logs; i < L2_TO_L1_LOGS_MERKLE_TREE_LEAVES; ++i) { l2ToL1LogsTreeArray[i] = L2_L1_LOGS_TREE_DEFAULT_LEAF_HASH; } @@ -232,7 +238,7 @@ contract L1Messenger is IL1Messenger, ISystemContract { /// Check messages uint32 numberOfMessages = uint32(bytes4(_totalL2ToL1PubdataAndStateDiffs[calldataPtr:calldataPtr + 4])); calldataPtr += 4; - bytes32 reconstructedChainedMessagesHash; + bytes32 reconstructedChainedMessagesHash = bytes32(0); for (uint256 i = 0; i < numberOfMessages; ++i) { uint32 currentMessageLength = uint32(bytes4(_totalL2ToL1PubdataAndStateDiffs[calldataPtr:calldataPtr + 4])); calldataPtr += 4; @@ -242,15 +248,14 @@ contract L1Messenger is IL1Messenger, ISystemContract { calldataPtr += currentMessageLength; reconstructedChainedMessagesHash = keccak256(abi.encode(reconstructedChainedMessagesHash, hashedMessage)); } - require( - reconstructedChainedMessagesHash == chainedMessagesHash, - "reconstructedChainedMessagesHash is not equal to chainedMessagesHash" - ); + if (reconstructedChainedMessagesHash != chainedMessagesHash) { + revert ReconstructionMismatch(PubdataField.MsgHash, chainedMessagesHash, reconstructedChainedMessagesHash); + } /// Check bytecodes uint32 numberOfBytecodes = uint32(bytes4(_totalL2ToL1PubdataAndStateDiffs[calldataPtr:calldataPtr + 4])); calldataPtr += 4; - bytes32 reconstructedChainedL1BytecodesRevealDataHash; + bytes32 reconstructedChainedL1BytecodesRevealDataHash = bytes32(0); for (uint256 i = 0; i < numberOfBytecodes; ++i) { uint32 currentBytecodeLength = uint32( bytes4(_totalL2ToL1PubdataAndStateDiffs[calldataPtr:calldataPtr + 4]) @@ -266,28 +271,36 @@ contract L1Messenger is IL1Messenger, ISystemContract { ); calldataPtr += currentBytecodeLength; } - require( - reconstructedChainedL1BytecodesRevealDataHash == chainedL1BytecodesRevealDataHash, - "reconstructedChainedL1BytecodesRevealDataHash is not equal to chainedL1BytecodesRevealDataHash" - ); + if (reconstructedChainedL1BytecodesRevealDataHash != chainedL1BytecodesRevealDataHash) { + revert ReconstructionMismatch( + PubdataField.Bytecode, + chainedL1BytecodesRevealDataHash, + reconstructedChainedL1BytecodesRevealDataHash + ); + } /// Check State Diffs /// encoding is as follows: /// header (1 byte version, 3 bytes total len of compressed, 1 byte enumeration index size) /// body (`compressedStateDiffSize` bytes, 4 bytes number of state diffs, `numberOfStateDiffs` * `STATE_DIFF_ENTRY_SIZE` bytes for the uncompressed state diffs) /// encoded state diffs: [20bytes address][32bytes key][32bytes derived key][8bytes enum index][32bytes initial value][32bytes final value] - require( - uint256(uint8(bytes1(_totalL2ToL1PubdataAndStateDiffs[calldataPtr]))) == - STATE_DIFF_COMPRESSION_VERSION_NUMBER, - "state diff compression version mismatch" - ); - calldataPtr++; + if ( + uint256(uint8(bytes1(_totalL2ToL1PubdataAndStateDiffs[calldataPtr]))) != + STATE_DIFF_COMPRESSION_VERSION_NUMBER + ) { + revert ReconstructionMismatch( + PubdataField.StateDiffCompressionVersion, + bytes32(STATE_DIFF_COMPRESSION_VERSION_NUMBER), + bytes32(uint256(uint8(bytes1(_totalL2ToL1PubdataAndStateDiffs[calldataPtr])))) + ); + } + ++calldataPtr; uint24 compressedStateDiffSize = uint24(bytes3(_totalL2ToL1PubdataAndStateDiffs[calldataPtr:calldataPtr + 3])); calldataPtr += 3; uint8 enumerationIndexSize = uint8(bytes1(_totalL2ToL1PubdataAndStateDiffs[calldataPtr])); - calldataPtr++; + ++calldataPtr; bytes calldata compressedStateDiffs = _totalL2ToL1PubdataAndStateDiffs[calldataPtr:calldataPtr + compressedStateDiffSize]; @@ -310,7 +323,13 @@ contract L1Messenger is IL1Messenger, ISystemContract { ); /// Check for calldata strict format - require(calldataPtr == _totalL2ToL1PubdataAndStateDiffs.length, "Extra data in the totalL2ToL1Pubdata array"); + if (calldataPtr != _totalL2ToL1PubdataAndStateDiffs.length) { + revert ReconstructionMismatch( + PubdataField.ExtraData, + bytes32(calldataPtr), + bytes32(_totalL2ToL1PubdataAndStateDiffs.length) + ); + } PUBDATA_CHUNK_PUBLISHER.chunkAndPublishPubdata(totalL2ToL1Pubdata); diff --git a/system-contracts/contracts/L2BaseToken.sol b/system-contracts/contracts/L2BaseToken.sol index 8101c638b..9f826a80b 100644 --- a/system-contracts/contracts/L2BaseToken.sol +++ b/system-contracts/contracts/L2BaseToken.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {IBaseToken} from "./interfaces/IBaseToken.sol"; -import {ISystemContract} from "./interfaces/ISystemContract.sol"; +import {SystemContractBase} from "./abstract/SystemContractBase.sol"; import {MSG_VALUE_SYSTEM_CONTRACT, DEPLOYER_SYSTEM_CONTRACT, BOOTLOADER_FORMAL_ADDRESS, L1_MESSENGER_CONTRACT} from "./Constants.sol"; import {IMailbox} from "./interfaces/IMailbox.sol"; +import {Unauthorized, InsufficientFunds} from "./SystemContractErrors.sol"; /** * @author Matter Labs @@ -15,7 +16,7 @@ import {IMailbox} from "./interfaces/IMailbox.sol"; * Instead, this contract is used by the bootloader and `MsgValueSimulator`/`ContractDeployer` system contracts * to perform the balance changes while simulating the `msg.value` Ethereum behavior. */ -contract L2BaseToken is IBaseToken, ISystemContract { +contract L2BaseToken is IBaseToken, SystemContractBase { /// @notice The balances of the users. mapping(address account => uint256 balance) internal balance; @@ -30,15 +31,18 @@ contract L2BaseToken is IBaseToken, ISystemContract { /// @dev This function also emits "Transfer" event, which might be removed /// later on. function transferFromTo(address _from, address _to, uint256 _amount) external override { - require( - msg.sender == MSG_VALUE_SYSTEM_CONTRACT || - msg.sender == address(DEPLOYER_SYSTEM_CONTRACT) || - msg.sender == BOOTLOADER_FORMAL_ADDRESS, - "Only system contracts with special access can call this method" - ); + if ( + msg.sender != MSG_VALUE_SYSTEM_CONTRACT && + msg.sender != address(DEPLOYER_SYSTEM_CONTRACT) && + msg.sender != BOOTLOADER_FORMAL_ADDRESS + ) { + revert Unauthorized(msg.sender); + } uint256 fromBalance = balance[_from]; - require(fromBalance >= _amount, "Transfer amount exceeds balance"); + if (fromBalance < _amount) { + revert InsufficientFunds(_amount, fromBalance); + } unchecked { balance[_from] = fromBalance - _amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by @@ -82,7 +86,7 @@ contract L2BaseToken is IBaseToken, ISystemContract { /// @notice Initiate the withdrawal of the base token, with the sent message. The funds will be available to claim on L1 `finalizeEthWithdrawal` method. /// @param _l1Receiver The address on L1 to receive the funds. /// @param _additionalData Additional data to be sent to L1 with the withdrawal. - function withdrawWithMessage(address _l1Receiver, bytes memory _additionalData) external payable override { + function withdrawWithMessage(address _l1Receiver, bytes calldata _additionalData) external payable override { uint256 amount = _burnMsgValue(); // Send the L2 log, a user could use it as proof of the withdrawal diff --git a/system-contracts/contracts/MsgValueSimulator.sol b/system-contracts/contracts/MsgValueSimulator.sol index c1dcde694..5fcd0f2d9 100644 --- a/system-contracts/contracts/MsgValueSimulator.sol +++ b/system-contracts/contracts/MsgValueSimulator.sol @@ -1,12 +1,13 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {Utils} from "./libraries/Utils.sol"; import {EfficientCall} from "./libraries/EfficientCall.sol"; -import {ISystemContract} from "./interfaces/ISystemContract.sol"; +import {SystemContractBase} from "./abstract/SystemContractBase.sol"; import {SystemContractHelper} from "./libraries/SystemContractHelper.sol"; import {MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT, REAL_BASE_TOKEN_SYSTEM_CONTRACT} from "./Constants.sol"; +import {InvalidCall} from "./SystemContractErrors.sol"; /** * @author Matter Labs @@ -16,7 +17,7 @@ import {MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT, REAL_BASE_TOKEN_SYSTEM_CONTRACT} from * the address to call in the second extraAbi param, transfers the funds and uses `mimicCall` to continue the * call with the same msg.sender. */ -contract MsgValueSimulator is ISystemContract { +contract MsgValueSimulator is SystemContractBase { /// @notice Extract value, isSystemCall and to from the extraAbi params. /// @dev The contract accepts value, the callee and whether the call should be a system one via its ABI params. /// @dev The first ABI param contains the value in the [0..127] bits. The 128th contains @@ -33,17 +34,18 @@ contract MsgValueSimulator is ISystemContract { } /// @notice The maximal number of gas out of the stipend that should be passed to the callee. - uint256 constant GAS_TO_PASS = 2300; + uint256 private constant GAS_TO_PASS = 2300; /// @notice The amount of gas that is passed to the MsgValueSimulator as a stipend. /// This number servers to pay for the ETH transfer as well as to provide gas for the `GAS_TO_PASS` gas. /// It is equal to the following constant: https://github.com/matter-labs/era-zkevm_opcode_defs/blob/7bf8016f5bb13a73289f321ad6ea8f614540ece9/src/system_params.rs#L96. - uint256 constant MSG_VALUE_SIMULATOR_STIPEND_GAS = 27000; + uint256 private constant MSG_VALUE_SIMULATOR_STIPEND_GAS = 27000; /// @notice The fallback function that is the main entry point for the MsgValueSimulator. /// @dev The contract accepts value, the callee and whether the call should be a system one via its ABI params. /// @param _data The calldata to be passed to the callee. /// @return The return data from the callee. + // solhint-disable-next-line payable-fallback fallback(bytes calldata _data) external onlySystemCall returns (bytes memory) { // Firstly we calculate how much gas has been actually provided by the user to the inner call. // For that, we need to get the total gas available in this context and subtract the stipend from it. @@ -57,7 +59,9 @@ contract MsgValueSimulator is ISystemContract { (uint256 value, bool isSystemCall, address to) = _getAbiParams(); // Prevent mimic call to the MsgValueSimulator to prevent an unexpected change of callee. - require(to != address(this), "MsgValueSimulator calls itself"); + if (to == address(this)) { + revert InvalidCall(); + } if (value != 0) { (bool success, ) = address(REAL_BASE_TOKEN_SYSTEM_CONTRACT).call( diff --git a/system-contracts/contracts/NonceHolder.sol b/system-contracts/contracts/NonceHolder.sol index 12abda8bd..cca07b1b4 100644 --- a/system-contracts/contracts/NonceHolder.sol +++ b/system-contracts/contracts/NonceHolder.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {INonceHolder} from "./interfaces/INonceHolder.sol"; import {IContractDeployer} from "./interfaces/IContractDeployer.sol"; -import {ISystemContract} from "./interfaces/ISystemContract.sol"; +import {SystemContractBase} from "./abstract/SystemContractBase.sol"; import {DEPLOYER_SYSTEM_CONTRACT} from "./Constants.sol"; +import {NonceIncreaseError, ZeroNonceError, NonceJumpError, ValueMismatch, NonceAlreadyUsed, NonceNotUsed, Unauthorized} from "./SystemContractErrors.sol"; /** * @author Matter Labs @@ -24,7 +25,7 @@ import {DEPLOYER_SYSTEM_CONTRACT} from "./Constants.sol"; * @dev The behavior of some of the methods depends on the nonce ordering of the account. Nonce ordering is a mere suggestion and all the checks that are present * here serve more as a help to users to prevent from doing mistakes, rather than any invariants. */ -contract NonceHolder is INonceHolder, ISystemContract { +contract NonceHolder is INonceHolder, SystemContractBase { uint256 private constant DEPLOY_NONCE_MULTIPLIER = 2 ** 128; /// The minNonce can be increased by 2^32 at a time to prevent it from /// overflowing beyond 2**128. @@ -63,7 +64,9 @@ contract NonceHolder is INonceHolder, ISystemContract { /// @param _value The number by which to increase the minimal nonce for msg.sender. /// @return oldMinNonce The value of the minimal nonce for msg.sender before the increase. function increaseMinNonce(uint256 _value) public onlySystemCall returns (uint256 oldMinNonce) { - require(_value <= MAXIMAL_MIN_NONCE_INCREMENT, "The value for incrementing the nonce is too high"); + if (_value > MAXIMAL_MIN_NONCE_INCREMENT) { + revert NonceIncreaseError(MAXIMAL_MIN_NONCE_INCREMENT, _value); + } uint256 addressAsKey = uint256(uint160(msg.sender)); uint256 oldRawNonce = rawNonces[addressAsKey]; @@ -82,11 +85,15 @@ contract NonceHolder is INonceHolder, ISystemContract { function setValueUnderNonce(uint256 _key, uint256 _value) public onlySystemCall { IContractDeployer.AccountInfo memory accountInfo = DEPLOYER_SYSTEM_CONTRACT.getAccountInfo(msg.sender); - require(_value != 0, "Nonce value cannot be set to 0"); + if (_value == 0) { + revert ZeroNonceError(); + } // If an account has sequential nonce ordering, we enforce that the previous // nonce has already been used. if (accountInfo.nonceOrdering == IContractDeployer.AccountNonceOrdering.Sequential && _key != 0) { - require(isNonceUsed(msg.sender, _key - 1), "Previous nonce has not been used"); + if (!isNonceUsed(msg.sender, _key - 1)) { + revert NonceJumpError(); + } } uint256 addressAsKey = uint256(uint160(msg.sender)); @@ -112,7 +119,9 @@ contract NonceHolder is INonceHolder, ISystemContract { uint256 oldRawNonce = rawNonces[addressAsKey]; (, uint256 oldMinNonce) = _splitRawNonce(oldRawNonce); - require(oldMinNonce == _expectedNonce, "Incorrect nonce"); + if (oldMinNonce != _expectedNonce) { + revert ValueMismatch(_expectedNonce, oldMinNonce); + } unchecked { rawNonces[addressAsKey] = oldRawNonce + 1; @@ -133,10 +142,9 @@ contract NonceHolder is INonceHolder, ISystemContract { /// @param _address The address of the account which to return the deploy nonce for. /// @return prevDeploymentNonce The deployment nonce at the time this function is called. function incrementDeploymentNonce(address _address) external returns (uint256 prevDeploymentNonce) { - require( - msg.sender == address(DEPLOYER_SYSTEM_CONTRACT), - "Only the contract deployer can increment the deployment nonce" - ); + if (msg.sender != address(DEPLOYER_SYSTEM_CONTRACT)) { + revert Unauthorized(msg.sender); + } uint256 addressAsKey = uint256(uint160(_address)); uint256 oldRawNonce = rawNonces[addressAsKey]; @@ -167,9 +175,9 @@ contract NonceHolder is INonceHolder, ISystemContract { bool isUsed = isNonceUsed(_address, _key); if (isUsed && !_shouldBeUsed) { - revert("Reusing the same nonce twice"); + revert NonceAlreadyUsed(_address, _key); } else if (!isUsed && _shouldBeUsed) { - revert("The nonce was not set as used"); + revert NonceNotUsed(_address, _key); } } diff --git a/system-contracts/contracts/PubdataChunkPublisher.sol b/system-contracts/contracts/PubdataChunkPublisher.sol index 53c265e9b..9402f05a6 100644 --- a/system-contracts/contracts/PubdataChunkPublisher.sol +++ b/system-contracts/contracts/PubdataChunkPublisher.sol @@ -1,23 +1,26 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {IPubdataChunkPublisher} from "./interfaces/IPubdataChunkPublisher.sol"; -import {ISystemContract} from "./interfaces/ISystemContract.sol"; +import {SystemContractBase} from "./abstract/SystemContractBase.sol"; import {L1_MESSENGER_CONTRACT, BLOB_SIZE_BYTES, MAX_NUMBER_OF_BLOBS, SystemLogKey} from "./Constants.sol"; import {SystemContractHelper} from "./libraries/SystemContractHelper.sol"; +import {TooMuchPubdata} from "./SystemContractErrors.sol"; /** * @author Matter Labs * @custom:security-contact security@matterlabs.dev * @notice Smart contract for chunking pubdata into the appropriate size for EIP-4844 blobs. */ -contract PubdataChunkPublisher is IPubdataChunkPublisher, ISystemContract { +contract PubdataChunkPublisher is IPubdataChunkPublisher, SystemContractBase { /// @notice Chunks pubdata into pieces that can fit into blobs. /// @param _pubdata The total l2 to l1 pubdata that will be sent via L1 blobs. /// @dev Note: This is an early implementation, in the future we plan to support up to 16 blobs per l1 batch. /// @dev We always publish 6 system logs even if our pubdata fits into a single blob. This makes processing logs on L1 easier. function chunkAndPublishPubdata(bytes calldata _pubdata) external onlyCallFrom(address(L1_MESSENGER_CONTRACT)) { - require(_pubdata.length <= BLOB_SIZE_BYTES * MAX_NUMBER_OF_BLOBS, "pubdata should fit in 6 blobs"); + if (_pubdata.length > BLOB_SIZE_BYTES * MAX_NUMBER_OF_BLOBS) { + revert TooMuchPubdata(BLOB_SIZE_BYTES * MAX_NUMBER_OF_BLOBS, _pubdata.length); + } bytes32[] memory blobHashes = new bytes32[](MAX_NUMBER_OF_BLOBS); @@ -31,7 +34,7 @@ contract PubdataChunkPublisher is IPubdataChunkPublisher, ISystemContract { calldatacopy(ptr, _pubdata.offset, _pubdata.length) } - for (uint256 i = 0; i < MAX_NUMBER_OF_BLOBS; i++) { + for (uint256 i = 0; i < MAX_NUMBER_OF_BLOBS; ++i) { uint256 start = BLOB_SIZE_BYTES * i; // We break if the pubdata isn't enough to cover all 6 blobs. On L1 it is expected that the hash @@ -50,7 +53,7 @@ contract PubdataChunkPublisher is IPubdataChunkPublisher, ISystemContract { blobHashes[i] = blobHash; } - for (uint8 i = 0; i < MAX_NUMBER_OF_BLOBS; i++) { + for (uint8 i = 0; i < MAX_NUMBER_OF_BLOBS; ++i) { SystemContractHelper.toL1( true, bytes32(uint256(SystemLogKey(i + uint256(SystemLogKey.BLOB_ONE_HASH_KEY)))), diff --git a/system-contracts/contracts/SystemContext.sol b/system-contracts/contracts/SystemContext.sol index 51b9633d9..4763b4153 100644 --- a/system-contracts/contracts/SystemContext.sol +++ b/system-contracts/contracts/SystemContext.sol @@ -1,9 +1,11 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +// solhint-disable reason-string, gas-custom-errors + +pragma solidity 0.8.24; import {ISystemContext} from "./interfaces/ISystemContext.sol"; -import {ISystemContract} from "./interfaces/ISystemContract.sol"; +import {SystemContractBase} from "./abstract/SystemContractBase.sol"; import {ISystemContextDeprecated} from "./interfaces/ISystemContextDeprecated.sol"; import {SystemContractHelper} from "./libraries/SystemContractHelper.sol"; import {BOOTLOADER_FORMAL_ADDRESS, SystemLogKey} from "./Constants.sol"; @@ -14,7 +16,7 @@ import {BOOTLOADER_FORMAL_ADDRESS, SystemLogKey} from "./Constants.sol"; * @notice Contract that stores some of the context variables, that may be either * block-scoped, tx-scoped or system-wide. */ -contract SystemContext is ISystemContext, ISystemContextDeprecated, ISystemContract { +contract SystemContext is ISystemContext, ISystemContextDeprecated, SystemContractBase { /// @notice The number of latest L2 blocks to store. /// @dev EVM requires us to be able to query the hashes of previous 256 blocks. /// We could either: @@ -289,6 +291,7 @@ contract SystemContext is ISystemContext, ISystemContextDeprecated, ISystemContr virtualBlockUpgradeInfo.virtualBlockStartBatch = currentBatchNumber; require(_maxVirtualBlocksToCreate > 0, "Can't initialize the first virtual block"); + // solhint-disable-next-line gas-increment-by-one _maxVirtualBlocksToCreate -= 1; } else if (_maxVirtualBlocksToCreate == 0) { // The virtual blocks have been already initialized, but the operator didn't ask to create @@ -484,7 +487,7 @@ contract SystemContext is ISystemContext, ISystemContextDeprecated, ISystemContr } function incrementTxNumberInBatch() external onlyCallFromBootloader { - txNumberInBlock += 1; + ++txNumberInBlock; } function resetTxNumberInBatch() external onlyCallFromBootloader { diff --git a/system-contracts/contracts/SystemContractErrors.sol b/system-contracts/contracts/SystemContractErrors.sol new file mode 100644 index 000000000..b5dfc8276 --- /dev/null +++ b/system-contracts/contracts/SystemContractErrors.sol @@ -0,0 +1,142 @@ +// 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; + +// 0x86bb51b8 +error AddressHasNoCode(address); +// 0xefce78c7 +error CallerMustBeBootloader(); +// 0xb7549616 +error CallerMustBeForceDeployer(); +// 0x9eedbd2b +error CallerMustBeSystemContract(); +// 0x4f951510 +error CompressionValueAddError(uint256 expected, uint256 actual); +// 0x1e6aff87 +error CompressionValueTransformError(uint256 expected, uint256 actual); +// 0xc2ea251e +error CompressionValueSubError(uint256 expected, uint256 actual); +// 0x849acb7f +error CompressorInitialWritesProcessedNotEqual(uint256 expected, uint256 actual); +// 0x61a6a4b3 +error CompressorEnumIndexNotEqual(uint256 expected, uint256 actual); +// 0x9be48d8d +error DerivedKeyNotEqualToCompressedValue(bytes32 expected, bytes32 provided); +// 0xe223db5e +error DictionaryDividedByEightNotGreaterThanEncodedDividedByTwo(); +// 0x1c25715b +error EmptyBytes32(); +// 0x92bf3cf8 +error EmptyVirtualBlocks(); +// 0xc06d5cb2 +error EncodedAndRealBytecodeChunkNotEqual(uint64 expected, uint64 provided); +// 0x2bfbfc11 +error EncodedLengthNotFourTimesSmallerThanOriginal(); +// 0xe95a1fbe +error FailedToChargeGas(); +// 0x1f70c58f +error FailedToPayOperator(); +// 0x9d5da395 +error FirstL2BlockInitializationError(); +// 0x9e4a3c8a +error HashIsNonZero(bytes32); +// 0x86302004 +error HashMismatch(bytes32 expected, uint256 actual); +// 0x4e23d035 +error IndexOutOfBounds(); +// 0x122e73e9 +error IndexSizeError(); +// 0x03eb8b54 +error InsufficientFunds(uint256 required, uint256 actual); +// 0x1c26714c +error InsufficientGas(); +// 0xae962d4e +error InvalidCall(); +// 0x6a84bc39 +error InvalidCodeHash(CodeHashReason); +// 0xb4fa3fb3 +error InvalidInput(); +// 0x60b85677 +error InvalidNonceOrderingChange(); +// 0x90f049c9 +error InvalidSig(SigField, uint256); +// 0xf4a271b5 +error Keccak256InvalidReturnData(); +// 0xd2906dd9 +error L2BlockMustBeGreaterThanZero(); +// 0x43e266b0 +error MalformedBytecode(BytecodeError); +// 0xe90aded4 +error NonceAlreadyUsed(address account, uint256 nonce); +// 0x45ac24a6 +error NonceIncreaseError(uint256 max, uint256 proposed); +// 0x13595475 +error NonceJumpError(); +// 0x1f2f8478 +error NonceNotUsed(address account, uint256 nonce); +// 0x760a1568 +error NonEmptyAccount(); +// 0x536ec84b +error NonEmptyMsgValue(); +// 0xd018e08e +error NonIncreasingTimestamp(); +// 0x50df6bc3 +error NotAllowedToDeployInKernelSpace(); +// 0x35278d12 +error Overflow(); +// 0x7f7b0cf7 +error ReconstructionMismatch(PubdataField, bytes32 expected, bytes32 actual); +// 0x3adb5f1d +error ShaInvalidReturnData(); +// 0xbd8665e2 +error StateDiffLengthMismatch(); +// 0x71c3da01 +error SystemCallFlagRequired(); +// 0xe0456dfe +error TooMuchPubdata(uint256 limit, uint256 supplied); +// 0x8e4a23d6 +error Unauthorized(address); +// 0x3e5efef9 +error UnknownCodeHash(bytes32); +// 0x9ba6061b +error UnsupportedOperation(); +// 0xff15b069 +error UnsupportedPaymasterFlow(); +// 0x17a84415 +error UnsupportedTxType(uint256); +// 0x5708aead +error UpgradeMustBeFirstTxn(); +// 0x626ade30 +error ValueMismatch(uint256 expected, uint256 actual); +// 0x460b9939 +error ValuesNotEqual(uint256 expected, uint256 actual); +// 0x6818f3f9 +error ZeroNonceError(); + +enum CodeHashReason { + NotContractOnConstructor, + NotConstructedContract +} + +enum SigField { + Length, + V, + S +} + +enum PubdataField { + NumberOfLogs, + LogsHash, + MsgHash, + Bytecode, + StateDiffCompressionVersion, + ExtraData +} + +enum BytecodeError { + Version, + NumberOfWords, + Length, + WordsMustBeOdd, + DictionaryLength +} diff --git a/system-contracts/contracts/interfaces/ISystemContract.sol b/system-contracts/contracts/abstract/SystemContractBase.sol similarity index 60% rename from system-contracts/contracts/interfaces/ISystemContract.sol rename to system-contracts/contracts/abstract/SystemContractBase.sol index 01ff9d95f..89966a576 100644 --- a/system-contracts/contracts/interfaces/ISystemContract.sol +++ b/system-contracts/contracts/abstract/SystemContractBase.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 {SystemContractHelper} from "../libraries/SystemContractHelper.sol"; import {BOOTLOADER_FORMAL_ADDRESS, FORCE_DEPLOYER} from "../Constants.sol"; +import {SystemCallFlagRequired, Unauthorized, CallerMustBeSystemContract, CallerMustBeBootloader, CallerMustBeForceDeployer} from "../SystemContractErrors.sol"; /** * @author Matter Labs @@ -14,45 +15,49 @@ import {BOOTLOADER_FORMAL_ADDRESS, FORCE_DEPLOYER} from "../Constants.sol"; * @dev Never add storage variables into this contract as some * system contracts rely on this abstract contract as on interface! */ -abstract contract ISystemContract { +abstract contract SystemContractBase { /// @notice Modifier that makes sure that the method /// can only be called via a system call. modifier onlySystemCall() { - require( - SystemContractHelper.isSystemCall() || SystemContractHelper.isSystemContract(msg.sender), - "This method require system call flag" - ); + if (!SystemContractHelper.isSystemCall() && !SystemContractHelper.isSystemContract(msg.sender)) { + revert SystemCallFlagRequired(); + } _; } /// @notice Modifier that makes sure that the method /// can only be called from a system contract. modifier onlyCallFromSystemContract() { - require( - SystemContractHelper.isSystemContract(msg.sender), - "This method require the caller to be system contract" - ); + if (!SystemContractHelper.isSystemContract(msg.sender)) { + revert CallerMustBeSystemContract(); + } _; } /// @notice Modifier that makes sure that the method /// can only be called from a special given address. modifier onlyCallFrom(address caller) { - require(msg.sender == caller, "Inappropriate caller"); + if (msg.sender != caller) { + revert Unauthorized(msg.sender); + } _; } /// @notice Modifier that makes sure that the method /// can only be called from the bootloader. modifier onlyCallFromBootloader() { - require(msg.sender == BOOTLOADER_FORMAL_ADDRESS, "Callable only by the bootloader"); + if (msg.sender != BOOTLOADER_FORMAL_ADDRESS) { + revert CallerMustBeBootloader(); + } _; } /// @notice Modifier that makes sure that the method /// can only be called from the L1 force deployer. modifier onlyCallFromForceDeployer() { - require(msg.sender == FORCE_DEPLOYER); + if (msg.sender != FORCE_DEPLOYER) { + revert CallerMustBeForceDeployer(); + } _; } } diff --git a/system-contracts/contracts/interfaces/IAccount.sol b/system-contracts/contracts/interfaces/IAccount.sol index c32b35767..cebe91d17 100644 --- a/system-contracts/contracts/interfaces/IAccount.sol +++ b/system-contracts/contracts/interfaces/IAccount.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 {Transaction} from "../libraries/TransactionHelper.sol"; diff --git a/system-contracts/contracts/interfaces/IAccountCodeStorage.sol b/system-contracts/contracts/interfaces/IAccountCodeStorage.sol index c266774ea..5183e77f6 100644 --- a/system-contracts/contracts/interfaces/IAccountCodeStorage.sol +++ b/system-contracts/contracts/interfaces/IAccountCodeStorage.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 IAccountCodeStorage { function storeAccountConstructingCodeHash(address _address, bytes32 _hash) external; diff --git a/system-contracts/contracts/interfaces/IBaseToken.sol b/system-contracts/contracts/interfaces/IBaseToken.sol index d15f2f123..fc32c7b83 100644 --- a/system-contracts/contracts/interfaces/IBaseToken.sol +++ b/system-contracts/contracts/interfaces/IBaseToken.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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); diff --git a/system-contracts/contracts/interfaces/IBootloaderUtilities.sol b/system-contracts/contracts/interfaces/IBootloaderUtilities.sol index 31413320a..e900bfb5e 100644 --- a/system-contracts/contracts/interfaces/IBootloaderUtilities.sol +++ b/system-contracts/contracts/interfaces/IBootloaderUtilities.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 {Transaction} from "../libraries/TransactionHelper.sol"; diff --git a/system-contracts/contracts/interfaces/IComplexUpgrader.sol b/system-contracts/contracts/interfaces/IComplexUpgrader.sol index 1b5e15182..3b1468417 100644 --- a/system-contracts/contracts/interfaces/IComplexUpgrader.sol +++ b/system-contracts/contracts/interfaces/IComplexUpgrader.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 diff --git a/system-contracts/contracts/interfaces/ICompressor.sol b/system-contracts/contracts/interfaces/ICompressor.sol index 3062ea4f7..854aa7904 100644 --- a/system-contracts/contracts/interfaces/ICompressor.sol +++ b/system-contracts/contracts/interfaces/ICompressor.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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; // The bitmask by applying which to the compressed state diff metadata we retrieve its operation. uint8 constant OPERATION_BITMASK = 7; diff --git a/system-contracts/contracts/interfaces/IContractDeployer.sol b/system-contracts/contracts/interfaces/IContractDeployer.sol index 3f84672d7..6e0bac3dc 100644 --- a/system-contracts/contracts/interfaces/IContractDeployer.sol +++ b/system-contracts/contracts/interfaces/IContractDeployer.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 IContractDeployer { /// @notice Defines the version of the account abstraction protocol diff --git a/system-contracts/contracts/interfaces/IImmutableSimulator.sol b/system-contracts/contracts/interfaces/IImmutableSimulator.sol index d30ac9b96..840053849 100644 --- a/system-contracts/contracts/interfaces/IImmutableSimulator.sol +++ b/system-contracts/contracts/interfaces/IImmutableSimulator.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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; struct ImmutableData { uint256 index; diff --git a/system-contracts/contracts/interfaces/IKnownCodesStorage.sol b/system-contracts/contracts/interfaces/IKnownCodesStorage.sol index 98a1277d0..551cfb0d8 100644 --- a/system-contracts/contracts/interfaces/IKnownCodesStorage.sol +++ b/system-contracts/contracts/interfaces/IKnownCodesStorage.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 diff --git a/system-contracts/contracts/interfaces/IL1Messenger.sol b/system-contracts/contracts/interfaces/IL1Messenger.sol index cd0cc90f7..88e2c81d8 100644 --- a/system-contracts/contracts/interfaces/IL1Messenger.sol +++ b/system-contracts/contracts/interfaces/IL1Messenger.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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; /// @dev The log passed from L2 /// @param l2ShardId The shard identifier, 0 - rollup, 1 - porter. All other values are not used but are reserved for the future diff --git a/system-contracts/contracts/interfaces/IL2StandardToken.sol b/system-contracts/contracts/interfaces/IL2StandardToken.sol index 3d75c8ede..d67a3ea1f 100644 --- a/system-contracts/contracts/interfaces/IL2StandardToken.sol +++ b/system-contracts/contracts/interfaces/IL2StandardToken.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 IL2StandardToken { event BridgeMint(address indexed _account, uint256 _amount); diff --git a/system-contracts/contracts/interfaces/IMailbox.sol b/system-contracts/contracts/interfaces/IMailbox.sol index ba673058c..a9dcdad05 100644 --- a/system-contracts/contracts/interfaces/IMailbox.sol +++ b/system-contracts/contracts/interfaces/IMailbox.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 IMailbox { function finalizeEthWithdrawal( diff --git a/system-contracts/contracts/interfaces/INonceHolder.sol b/system-contracts/contracts/interfaces/INonceHolder.sol index 1213fbea4..ce3b0279d 100644 --- a/system-contracts/contracts/interfaces/INonceHolder.sol +++ b/system-contracts/contracts/interfaces/INonceHolder.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 diff --git a/system-contracts/contracts/interfaces/IPaymaster.sol b/system-contracts/contracts/interfaces/IPaymaster.sol index 7b06d86ee..1c8af5b28 100644 --- a/system-contracts/contracts/interfaces/IPaymaster.sol +++ b/system-contracts/contracts/interfaces/IPaymaster.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 {Transaction} from "../libraries/TransactionHelper.sol"; diff --git a/system-contracts/contracts/interfaces/IPaymasterFlow.sol b/system-contracts/contracts/interfaces/IPaymasterFlow.sol index 38866073e..4c9683fd4 100644 --- a/system-contracts/contracts/interfaces/IPaymasterFlow.sol +++ b/system-contracts/contracts/interfaces/IPaymasterFlow.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 diff --git a/system-contracts/contracts/interfaces/IPubdataChunkPublisher.sol b/system-contracts/contracts/interfaces/IPubdataChunkPublisher.sol index 83c1893fd..47893abdb 100644 --- a/system-contracts/contracts/interfaces/IPubdataChunkPublisher.sol +++ b/system-contracts/contracts/interfaces/IPubdataChunkPublisher.sol @@ -1,5 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +// 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 diff --git a/system-contracts/contracts/interfaces/ISystemContext.sol b/system-contracts/contracts/interfaces/ISystemContext.sol index a122a04f5..6b9a37fce 100644 --- a/system-contracts/contracts/interfaces/ISystemContext.sol +++ b/system-contracts/contracts/interfaces/ISystemContext.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 diff --git a/system-contracts/contracts/interfaces/ISystemContextDeprecated.sol b/system-contracts/contracts/interfaces/ISystemContextDeprecated.sol index a44b61b23..ac5153270 100644 --- a/system-contracts/contracts/interfaces/ISystemContextDeprecated.sol +++ b/system-contracts/contracts/interfaces/ISystemContextDeprecated.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 diff --git a/system-contracts/contracts/libraries/EfficientCall.sol b/system-contracts/contracts/libraries/EfficientCall.sol index 8f9939f08..27fea6396 100644 --- a/system-contracts/contracts/libraries/EfficientCall.sol +++ b/system-contracts/contracts/libraries/EfficientCall.sol @@ -1,11 +1,12 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 {SystemContractHelper, ADDRESS_MASK} from "./SystemContractHelper.sol"; import {SystemContractsCaller, CalldataForwardingMode, RAW_FAR_CALL_BY_REF_CALL_ADDRESS, SYSTEM_CALL_BY_REF_CALL_ADDRESS, MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT, MIMIC_CALL_BY_REF_CALL_ADDRESS} from "./SystemContractsCaller.sol"; import {Utils} from "./Utils.sol"; import {SHA256_SYSTEM_CONTRACT, KECCAK256_SYSTEM_CONTRACT, MSG_VALUE_SYSTEM_CONTRACT} from "../Constants.sol"; +import {Keccak256InvalidReturnData, ShaInvalidReturnData} from "../SystemContractErrors.sol"; /** * @author Matter Labs @@ -36,7 +37,9 @@ library EfficientCall { /// @return The `keccak256` hash. function keccak(bytes calldata _data) internal view returns (bytes32) { bytes memory returnData = staticCall(gasleft(), KECCAK256_SYSTEM_CONTRACT, _data); - require(returnData.length == 32, "keccak256 returned invalid data"); + if (returnData.length != 32) { + revert Keccak256InvalidReturnData(); + } return bytes32(returnData); } @@ -45,7 +48,9 @@ library EfficientCall { /// @return The `sha256` hash. function sha(bytes calldata _data) internal view returns (bytes32) { bytes memory returnData = staticCall(gasleft(), SHA256_SYSTEM_CONTRACT, _data); - require(returnData.length == 32, "sha returned invalid data"); + if (returnData.length != 32) { + revert ShaInvalidReturnData(); + } return bytes32(returnData); } diff --git a/system-contracts/contracts/libraries/RLPEncoder.sol b/system-contracts/contracts/libraries/RLPEncoder.sol index 8e32ea9ba..16eaa4053 100644 --- a/system-contracts/contracts/libraries/RLPEncoder.sol +++ b/system-contracts/contracts/libraries/RLPEncoder.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 @@ -100,7 +100,7 @@ library RLPEncoder { hbs += 2; } if (_number > type(uint8).max) { - hbs += 1; + ++hbs; } } } diff --git a/system-contracts/contracts/libraries/SystemContractHelper.sol b/system-contracts/contracts/libraries/SystemContractHelper.sol index 7ae75b520..e8469e308 100644 --- a/system-contracts/contracts/libraries/SystemContractHelper.sol +++ b/system-contracts/contracts/libraries/SystemContractHelper.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 {MAX_SYSTEM_CONTRACT_ADDRESS} from "../Constants.sol"; import {CALLFLAGS_CALL_ADDRESS, CODE_ADDRESS_CALL_ADDRESS, EVENT_WRITE_ADDRESS, EVENT_INITIALIZE_ADDRESS, GET_EXTRA_ABI_DATA_ADDRESS, LOAD_CALLDATA_INTO_ACTIVE_PTR_CALL_ADDRESS, META_CODE_SHARD_ID_OFFSET, META_CALLER_SHARD_ID_OFFSET, META_SHARD_ID_OFFSET, META_AUX_HEAP_SIZE_OFFSET, META_HEAP_SIZE_OFFSET, META_PUBDATA_PUBLISHED_OFFSET, META_CALL_ADDRESS, PTR_CALLDATA_CALL_ADDRESS, PTR_ADD_INTO_ACTIVE_CALL_ADDRESS, PTR_SHRINK_INTO_ACTIVE_CALL_ADDRESS, PTR_PACK_INTO_ACTIVE_CALL_ADDRESS, PRECOMPILE_CALL_ADDRESS, SET_CONTEXT_VALUE_CALL_ADDRESS, TO_L1_CALL_ADDRESS} from "./SystemContractsCaller.sol"; +import {IndexOutOfBounds, FailedToChargeGas} from "../SystemContractErrors.sol"; uint256 constant UINT32_MASK = type(uint32).max; uint256 constant UINT64_MASK = type(uint64).max; @@ -318,7 +319,10 @@ library SystemContractHelper { /// @dev It is equal to the value of the (N+2)-th register /// at the start of the call. function getExtraAbiData(uint256 index) internal view returns (uint256 extraAbiData) { - require(index < 10, "There are only 10 accessible registers"); + // Note that there are only 10 accessible registers (indices 0-9 inclusively) + if (index > 9) { + revert IndexOutOfBounds(); + } address callAddr = GET_EXTRA_ABI_DATA_ADDRESS; assembly { @@ -350,6 +354,8 @@ library SystemContractHelper { _gasToPay, _pubdataToSpend ); - require(precompileCallSuccess, "Failed to charge gas"); + if (!precompileCallSuccess) { + revert FailedToChargeGas(); + } } } diff --git a/system-contracts/contracts/libraries/SystemContractsCaller.sol b/system-contracts/contracts/libraries/SystemContractsCaller.sol index d964fbbe7..9497b0c52 100644 --- a/system-contracts/contracts/libraries/SystemContractsCaller.sol +++ b/system-contracts/contracts/libraries/SystemContractsCaller.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 {MSG_VALUE_SYSTEM_CONTRACT, MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT} from "../Constants.sol"; import {Utils} from "./Utils.sol"; // Addresses used for the compiler to be replaced with the -// zkSync-specific opcodes during the compilation. +// ZKsync-specific opcodes during the compilation. // IMPORTANT: these are just compile-time constants and are used // only if used in-place by Yul optimizer. address constant TO_L1_CALL_ADDRESS = address((1 << 16) - 1); @@ -80,7 +80,7 @@ library SystemContractsCaller { assembly { dataStart := add(data, 0x20) } - uint32 dataLength = uint32(Utils.safeCastToU32(data.length)); + uint32 dataLength = Utils.safeCastToU32(data.length); uint256 farCallAbi = SystemContractsCaller.getFarCallABI({ dataOffset: 0, diff --git a/system-contracts/contracts/libraries/TransactionHelper.sol b/system-contracts/contracts/libraries/TransactionHelper.sol index 9a2921010..467eb57f9 100644 --- a/system-contracts/contracts/libraries/TransactionHelper.sol +++ b/system-contracts/contracts/libraries/TransactionHelper.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 {IERC20} from "../openzeppelin/token/ERC20/IERC20.sol"; import {SafeERC20} from "../openzeppelin/token/ERC20/utils/SafeERC20.sol"; @@ -9,8 +9,9 @@ import {IPaymasterFlow} from "../interfaces/IPaymasterFlow.sol"; import {BASE_TOKEN_SYSTEM_CONTRACT, BOOTLOADER_FORMAL_ADDRESS} from "../Constants.sol"; import {RLPEncoder} from "./RLPEncoder.sol"; import {EfficientCall} from "./EfficientCall.sol"; +import {UnsupportedTxType, InvalidInput, UnsupportedPaymasterFlow} from "../SystemContractErrors.sol"; -/// @dev The type id of zkSync's EIP-712-signed transaction. +/// @dev The type id of ZKsync's EIP-712-signed transaction. uint8 constant EIP_712_TX_TYPE = 0x71; /// @dev The type id of legacy transactions. @@ -20,7 +21,7 @@ uint8 constant EIP_2930_TX_TYPE = 0x01; /// @dev The type id of EIP1559 transactions. uint8 constant EIP_1559_TX_TYPE = 0x02; -/// @notice Structure used to represent a zkSync transaction. +/// @notice Structure used to represent a ZKsync transaction. struct Transaction { // The type of the transaction. uint256 txType; @@ -78,9 +79,10 @@ library TransactionHelper { using SafeERC20 for IERC20; /// @notice The EIP-712 typehash for the contract's domain - bytes32 constant EIP712_DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,string version,uint256 chainId)"); + bytes32 internal constant EIP712_DOMAIN_TYPEHASH = + keccak256("EIP712Domain(string name,string version,uint256 chainId)"); - bytes32 constant EIP712_TRANSACTION_TYPE_HASH = + bytes32 internal constant EIP712_TRANSACTION_TYPE_HASH = keccak256( "Transaction(uint256 txType,uint256 from,uint256 to,uint256 gasLimit,uint256 gasPerPubdataByteLimit,uint256 maxFeePerGas,uint256 maxPriorityFeePerGas,uint256 paymaster,uint256 nonce,uint256 value,bytes data,bytes32[] factoryDeps,bytes paymasterInput)" ); @@ -108,11 +110,11 @@ library TransactionHelper { } else { // Currently no other transaction types are supported. // Any new transaction types will be processed in a similar manner. - revert("Encoding unsupported tx"); + revert UnsupportedTxType(_transaction.txType); } } - /// @notice Encode hash of the zkSync native transaction type. + /// @notice Encode hash of the ZKsync native transaction type. /// @return keccak256 hash of the EIP-712 encoded representation of transaction function _encodeHashEIP712Transaction(Transaction calldata _transaction) private view returns (bytes32) { bytes32 structHash = keccak256( @@ -221,7 +223,7 @@ library TransactionHelper { // Hash of EIP2930 transactions is encoded the following way: // H(0x01 || RLP(chain_id, nonce, gas_price, gas_limit, destination, amount, data, access_list)) // - // Note, that on zkSync access lists are not supported and should always be empty. + // Note, that on ZKsync access lists are not supported and should always be empty. // Encode all fixed-length params to avoid "stack too deep error" bytes memory encodedFixedLengthParams; @@ -259,7 +261,7 @@ library TransactionHelper { // Otherwise the length is not encoded at all. } - // On zkSync, access lists are always zero length (at least for now). + // On ZKsync, access lists are always zero length (at least for now). bytes memory encodedAccessListLength = RLPEncoder.encodeListLen(0); bytes memory encodedListLength; @@ -293,7 +295,7 @@ library TransactionHelper { // Hash of EIP1559 transactions is encoded the following way: // H(0x02 || RLP(chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list)) // - // Note, that on zkSync access lists are not supported and should always be empty. + // Note, that on ZKsync access lists are not supported and should always be empty. // Encode all fixed-length params to avoid "stack too deep error" bytes memory encodedFixedLengthParams; @@ -333,7 +335,7 @@ library TransactionHelper { // Otherwise the length is not encoded at all. } - // On zkSync, access lists are always zero length (at least for now). + // On ZKsync, access lists are always zero length (at least for now). bytes memory encodedAccessListLength = RLPEncoder.encodeListLen(0); bytes memory encodedListLength; @@ -365,14 +367,15 @@ library TransactionHelper { /// for tokens, etc. For more information on the expected behavior, check out /// the "Paymaster flows" section in the documentation. function processPaymasterInput(Transaction calldata _transaction) internal { - require(_transaction.paymasterInput.length >= 4, "The standard paymaster input must be at least 4 bytes long"); + if (_transaction.paymasterInput.length < 4) { + revert InvalidInput(); + } bytes4 paymasterInputSelector = bytes4(_transaction.paymasterInput[0:4]); if (paymasterInputSelector == IPaymasterFlow.approvalBased.selector) { - require( - _transaction.paymasterInput.length >= 68, - "The approvalBased paymaster input must be at least 68 bytes long" - ); + if (_transaction.paymasterInput.length < 68) { + revert InvalidInput(); + } // While the actual data consists of address, uint256 and bytes data, // the data is needed only for the paymaster, so we ignore it here for the sake of optimization @@ -390,7 +393,7 @@ library TransactionHelper { } else if (paymasterInputSelector == IPaymasterFlow.general.selector) { // Do nothing. general(bytes) paymaster flow means that the paymaster must interpret these bytes on his own. } else { - revert("Unsupported paymaster flow"); + revert UnsupportedPaymasterFlow(); } } diff --git a/system-contracts/contracts/libraries/UnsafeBytesCalldata.sol b/system-contracts/contracts/libraries/UnsafeBytesCalldata.sol index 4ce65f5fb..82b4c5c1d 100644 --- a/system-contracts/contracts/libraries/UnsafeBytesCalldata.sol +++ b/system-contracts/contracts/libraries/UnsafeBytesCalldata.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT - -pragma solidity 0.8.20; +// 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 diff --git a/system-contracts/contracts/libraries/Utils.sol b/system-contracts/contracts/libraries/Utils.sol index 5fa7eec6f..fc23de94b 100644 --- a/system-contracts/contracts/libraries/Utils.sol +++ b/system-contracts/contracts/libraries/Utils.sol @@ -1,36 +1,44 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +// 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 {EfficientCall} from "./EfficientCall.sol"; +import {MalformedBytecode, BytecodeError, Overflow} from "../SystemContractErrors.sol"; /** * @author Matter Labs * @custom:security-contact security@matterlabs.dev - * @dev Common utilities used in zkSync system contracts + * @dev Common utilities used in ZKsync system contracts */ library Utils { /// @dev Bit mask of bytecode hash "isConstructor" marker - bytes32 constant IS_CONSTRUCTOR_BYTECODE_HASH_BIT_MASK = + bytes32 internal constant IS_CONSTRUCTOR_BYTECODE_HASH_BIT_MASK = 0x00ff000000000000000000000000000000000000000000000000000000000000; /// @dev Bit mask to set the "isConstructor" marker in the bytecode hash - bytes32 constant SET_IS_CONSTRUCTOR_MARKER_BIT_MASK = + bytes32 internal constant SET_IS_CONSTRUCTOR_MARKER_BIT_MASK = 0x0001000000000000000000000000000000000000000000000000000000000000; function safeCastToU128(uint256 _x) internal pure returns (uint128) { - require(_x <= type(uint128).max, "Overflow"); + if (_x > type(uint128).max) { + revert Overflow(); + } return uint128(_x); } function safeCastToU32(uint256 _x) internal pure returns (uint32) { - require(_x <= type(uint32).max, "Overflow"); + if (_x > type(uint32).max) { + revert Overflow(); + } return uint32(_x); } function safeCastToU24(uint256 _x) internal pure returns (uint24) { - require(_x <= type(uint24).max, "Overflow"); + if (_x > type(uint24).max) { + revert Overflow(); + } return uint24(_x); } @@ -81,11 +89,19 @@ library Utils { /// - Bytecode words length is not odd function hashL2Bytecode(bytes calldata _bytecode) internal view returns (bytes32 hashedBytecode) { // Note that the length of the bytecode must be provided in 32-byte words. - require(_bytecode.length % 32 == 0, "po"); + if (_bytecode.length % 32 != 0) { + revert MalformedBytecode(BytecodeError.Length); + } uint256 lengthInWords = _bytecode.length / 32; - require(lengthInWords < 2 ** 16, "pp"); // bytecode length must be less than 2^16 words - require(lengthInWords % 2 == 1, "pr"); // bytecode length in words must be odd + // bytecode length must be less than 2^16 words + if (lengthInWords >= 2 ** 16) { + revert MalformedBytecode(BytecodeError.NumberOfWords); + } + // bytecode length in words must be odd + if (lengthInWords % 2 == 0) { + revert MalformedBytecode(BytecodeError.WordsMustBeOdd); + } hashedBytecode = EfficientCall.sha(_bytecode) & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; diff --git a/system-contracts/contracts/openzeppelin/token/ERC20/IERC20.sol b/system-contracts/contracts/openzeppelin/token/ERC20/IERC20.sol index b816bfed0..18b39a7a9 100644 --- a/system-contracts/contracts/openzeppelin/token/ERC20/IERC20.sol +++ b/system-contracts/contracts/openzeppelin/token/ERC20/IERC20.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) - +// 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.0; /** diff --git a/system-contracts/contracts/openzeppelin/token/ERC20/extensions/IERC20Permit.sol b/system-contracts/contracts/openzeppelin/token/ERC20/extensions/IERC20Permit.sol index bb43e53b6..5e0875438 100644 --- a/system-contracts/contracts/openzeppelin/token/ERC20/extensions/IERC20Permit.sol +++ b/system-contracts/contracts/openzeppelin/token/ERC20/extensions/IERC20Permit.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol) - +// 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.0; /** diff --git a/system-contracts/contracts/openzeppelin/token/ERC20/utils/SafeERC20.sol b/system-contracts/contracts/openzeppelin/token/ERC20/utils/SafeERC20.sol index 2ae0c4b0e..a23e6d1f7 100644 --- a/system-contracts/contracts/openzeppelin/token/ERC20/utils/SafeERC20.sol +++ b/system-contracts/contracts/openzeppelin/token/ERC20/utils/SafeERC20.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) - +// 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.0; import {IERC20} from "../IERC20.sol"; diff --git a/system-contracts/contracts/openzeppelin/utils/Address.sol b/system-contracts/contracts/openzeppelin/utils/Address.sol index 7a7d2d5d3..5d6de78c4 100644 --- a/system-contracts/contracts/openzeppelin/utils/Address.sol +++ b/system-contracts/contracts/openzeppelin/utils/Address.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) - +// 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.1; /** diff --git a/system-contracts/contracts/precompiles/CodeOracle.yul b/system-contracts/contracts/precompiles/CodeOracle.yul index 820b8df70..63b386788 100644 --- a/system-contracts/contracts/precompiles/CodeOracle.yul +++ b/system-contracts/contracts/precompiles/CodeOracle.yul @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: MIT + /** * @author Matter Labs * @custom:security-contact security@matterlabs.dev diff --git a/system-contracts/contracts/precompiles/EcAdd.yul b/system-contracts/contracts/precompiles/EcAdd.yul index 5771df8f9..8b7f25618 100644 --- a/system-contracts/contracts/precompiles/EcAdd.yul +++ b/system-contracts/contracts/precompiles/EcAdd.yul @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: MIT + object "EcAdd" { code { return(0, 0) diff --git a/system-contracts/contracts/precompiles/EcMul.yul b/system-contracts/contracts/precompiles/EcMul.yul index 84838ec2a..63fd0bc42 100644 --- a/system-contracts/contracts/precompiles/EcMul.yul +++ b/system-contracts/contracts/precompiles/EcMul.yul @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: MIT + object "EcMul" { code { return(0, 0) diff --git a/system-contracts/contracts/precompiles/EcPairing.yul b/system-contracts/contracts/precompiles/EcPairing.yul index 6ea6e92de..5e8011bcc 100644 --- a/system-contracts/contracts/precompiles/EcPairing.yul +++ b/system-contracts/contracts/precompiles/EcPairing.yul @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: MIT + object "EcPairing" { code { return(0, 0) diff --git a/system-contracts/contracts/precompiles/Ecrecover.yul b/system-contracts/contracts/precompiles/Ecrecover.yul index cbb8fcc0f..9c64d509f 100644 --- a/system-contracts/contracts/precompiles/Ecrecover.yul +++ b/system-contracts/contracts/precompiles/Ecrecover.yul @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: MIT + /** * @author Matter Labs * @custom:security-contact security@matterlabs.dev diff --git a/system-contracts/contracts/precompiles/Keccak256.yul b/system-contracts/contracts/precompiles/Keccak256.yul index 8eaa53671..397ee89bb 100644 --- a/system-contracts/contracts/precompiles/Keccak256.yul +++ b/system-contracts/contracts/precompiles/Keccak256.yul @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: MIT + /** * @author Matter Labs * @custom:security-contact security@matterlabs.dev diff --git a/system-contracts/contracts/precompiles/P256Verify.yul b/system-contracts/contracts/precompiles/P256Verify.yul index 8cd14beb2..80b782209 100644 --- a/system-contracts/contracts/precompiles/P256Verify.yul +++ b/system-contracts/contracts/precompiles/P256Verify.yul @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: MIT + /** * @author Matter Labs * @custom:security-contact security@matterlabs.dev diff --git a/system-contracts/contracts/precompiles/SHA256.yul b/system-contracts/contracts/precompiles/SHA256.yul index ff52632cd..8173502ef 100644 --- a/system-contracts/contracts/precompiles/SHA256.yul +++ b/system-contracts/contracts/precompiles/SHA256.yul @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: MIT + /** * @author Matter Labs * @custom:security-contact security@matterlabs.dev diff --git a/system-contracts/contracts/precompiles/test-contracts/Keccak256Mock.yul b/system-contracts/contracts/precompiles/test-contracts/Keccak256Mock.yul index b37eb69ca..e3cb9ac1e 100644 --- a/system-contracts/contracts/precompiles/test-contracts/Keccak256Mock.yul +++ b/system-contracts/contracts/precompiles/test-contracts/Keccak256Mock.yul @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: MIT + /** * @author Matter Labs * @notice The contract used to emulate EVM's keccak256 opcode. diff --git a/system-contracts/contracts/test-contracts/AlwaysRevert.sol b/system-contracts/contracts/test-contracts/AlwaysRevert.sol index 902117487..3c9d469ce 100644 --- a/system-contracts/contracts/test-contracts/AlwaysRevert.sol +++ b/system-contracts/contracts/test-contracts/AlwaysRevert.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.20; contract AlwaysRevert { fallback() external { diff --git a/system-contracts/contracts/test-contracts/CodeOracleTest.sol b/system-contracts/contracts/test-contracts/CodeOracleTest.sol index 4db306fb6..31de9d366 100644 --- a/system-contracts/contracts/test-contracts/CodeOracleTest.sol +++ b/system-contracts/contracts/test-contracts/CodeOracleTest.sol @@ -1,6 +1,6 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.20; address constant REAL_CODE_ORACLE_ADDR = 0x0000000000000000000000000000000000008011; diff --git a/system-contracts/contracts/test-contracts/DelegateCaller.sol b/system-contracts/contracts/test-contracts/DelegateCaller.sol index caa5aae6b..a28cc0167 100644 --- a/system-contracts/contracts/test-contracts/DelegateCaller.sol +++ b/system-contracts/contracts/test-contracts/DelegateCaller.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.20; contract DelegateCaller { function delegateCall(address _to) external payable { diff --git a/system-contracts/contracts/test-contracts/Deployable.sol b/system-contracts/contracts/test-contracts/Deployable.sol index be35861a4..8178eadb4 100644 --- a/system-contracts/contracts/test-contracts/Deployable.sol +++ b/system-contracts/contracts/test-contracts/Deployable.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; contract Deployable { event Deployed(uint256 value, bytes data); diff --git a/system-contracts/contracts/test-contracts/KeccakTest.sol b/system-contracts/contracts/test-contracts/KeccakTest.sol index 19ce77ea1..79581afc4 100644 --- a/system-contracts/contracts/test-contracts/KeccakTest.sol +++ b/system-contracts/contracts/test-contracts/KeccakTest.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.20; pragma abicoder v2; import {LOAD_LATEST_RETURNDATA_INTO_ACTIVE_PTR_CALL_ADDRESS, PTR_PACK_INTO_ACTIVE_CALL_ADDRESS, SystemContractsCaller, CalldataForwardingMode, RAW_FAR_CALL_BY_REF_CALL_ADDRESS} from "../libraries/SystemContractsCaller.sol"; diff --git a/system-contracts/contracts/test-contracts/MockContract.sol b/system-contracts/contracts/test-contracts/MockContract.sol index 1505be34c..b7d9bcb55 100644 --- a/system-contracts/contracts/test-contracts/MockContract.sol +++ b/system-contracts/contracts/test-contracts/MockContract.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; contract MockContract { event Called(uint256 value, bytes data); diff --git a/system-contracts/contracts/test-contracts/SystemCaller.sol b/system-contracts/contracts/test-contracts/SystemCaller.sol index a377174ae..b51caec0b 100644 --- a/system-contracts/contracts/test-contracts/SystemCaller.sol +++ b/system-contracts/contracts/test-contracts/SystemCaller.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.20; +pragma solidity 0.8.24; import {SYSTEM_CALL_CALL_ADDRESS, MSG_VALUE_SIMULATOR_IS_SYSTEM_BIT, SystemContractsCaller, CalldataForwardingMode} from "../libraries/SystemContractsCaller.sol"; import {Utils} from "../libraries/Utils.sol"; diff --git a/system-contracts/contracts/test-contracts/TransferTest.sol b/system-contracts/contracts/test-contracts/TransferTest.sol index 1342c5a6d..ca76a9932 100644 --- a/system-contracts/contracts/test-contracts/TransferTest.sol +++ b/system-contracts/contracts/test-contracts/TransferTest.sol @@ -1,6 +1,6 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.20; contract TransferTest { function transfer(address payable to, uint256 amount, bool warmUpRecipient) public payable { diff --git a/system-contracts/foundry.toml b/system-contracts/foundry.toml new file mode 100644 index 000000000..06485883a --- /dev/null +++ b/system-contracts/foundry.toml @@ -0,0 +1,14 @@ +[profile.default] +src = "contracts-preprocessed" +out = "out" +libs = ["lib"] +cache_path = "cache-forge" +evm_version = "paris" +remappings = [ + "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", + "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", +] + +[profile.default.zksync] +zksolc = "1.5.0" +enable_eravm_extensions = true diff --git a/system-contracts/hardhat.config.ts b/system-contracts/hardhat.config.ts index 68550e6c3..7ad59a41f 100644 --- a/system-contracts/hardhat.config.ts +++ b/system-contracts/hardhat.config.ts @@ -34,8 +34,9 @@ export default { ethNetwork: "http://localhost:8545", }, solidity: { - version: "0.8.20", + version: "0.8.24", settings: { + evmVersion: "cancun", optimizer: { enabled: true, runs: 9999999, diff --git a/system-contracts/lib/forge-std b/system-contracts/lib/forge-std new file mode 120000 index 000000000..edce15694 --- /dev/null +++ b/system-contracts/lib/forge-std @@ -0,0 +1 @@ +../../lib/forge-std \ No newline at end of file diff --git a/system-contracts/lib/openzeppelin-contracts b/system-contracts/lib/openzeppelin-contracts new file mode 120000 index 000000000..99aa45507 --- /dev/null +++ b/system-contracts/lib/openzeppelin-contracts @@ -0,0 +1 @@ +../../lib/openzeppelin-contracts \ No newline at end of file diff --git a/system-contracts/lib/openzeppelin-contracts-upgradeable b/system-contracts/lib/openzeppelin-contracts-upgradeable new file mode 120000 index 000000000..f1fc7a76a --- /dev/null +++ b/system-contracts/lib/openzeppelin-contracts-upgradeable @@ -0,0 +1 @@ +../../lib/openzeppelin-contracts-upgradeable \ No newline at end of file diff --git a/system-contracts/package.json b/system-contracts/package.json index 95900f654..ef53db110 100644 --- a/system-contracts/package.json +++ b/system-contracts/package.json @@ -4,7 +4,7 @@ "repository": "git@github.com:matter-labs/system-contracts.git", "license": "MIT", "dependencies": { - "@matterlabs/hardhat-zksync-deploy": "^0.6.5", + "@matterlabs/hardhat-zksync-deploy": "^0.7.0", "@matterlabs/hardhat-zksync-solc": "^1.1.4", "@matterlabs/hardhat-zksync-verify": "^1.4.3", "commander": "^9.4.1", @@ -18,7 +18,7 @@ "zksync-ethers": "^5.9.0" }, "devDependencies": { - "@matterlabs/hardhat-zksync-chai-matchers": "^0.1.4", + "@matterlabs/hardhat-zksync-chai-matchers": "^0.2.0", "@matterlabs/hardhat-zksync-node": "^0.0.1-beta.7", "@nomicfoundation/hardhat-chai-matchers": "^1.0.3", "@nomiclabs/hardhat-ethers": "^2.0.0", diff --git a/system-contracts/scripts/calculate-hashes.ts b/system-contracts/scripts/calculate-hashes.ts index 1fe368d75..1b9f355a5 100644 --- a/system-contracts/scripts/calculate-hashes.ts +++ b/system-contracts/scripts/calculate-hashes.ts @@ -3,7 +3,7 @@ import * as fs from "fs"; import _ from "lodash"; import os from "os"; import { join } from "path"; -import { hashBytecode } from "zksync-web3/build/src/utils"; +import { hashBytecode } from "zksync-ethers/build/utils"; type ContractDetails = { contractName: string; @@ -42,10 +42,10 @@ const findFilesEndingWith = (path: string, endingWith: string): string[] => { } }; -const SOLIDITY_ARTIFACTS_DIR = "artifacts-zk"; +const SOLIDITY_ARTIFACTS_DIR = "zkout"; const getSolidityContractDetails = (dir: string, contractName: string): ContractDetails => { - const bytecodePath = join(SOLIDITY_ARTIFACTS_DIR, dir, contractName + ".sol", contractName + ".json"); + const bytecodePath = join(SOLIDITY_ARTIFACTS_DIR, contractName + ".sol", contractName + ".json"); const sourceCodePath = join(dir, contractName + ".sol"); return { contractName, @@ -55,7 +55,7 @@ const getSolidityContractDetails = (dir: string, contractName: string): Contract }; const getSolidityContractsDetails = (dir: string): ContractDetails[] => { - const bytecodesDir = join(SOLIDITY_ARTIFACTS_DIR, dir); + const bytecodesDir = SOLIDITY_ARTIFACTS_DIR; const dirsEndingWithSol = findDirsEndingWith(bytecodesDir, ".sol"); const contractNames = dirsEndingWithSol.map((d) => d.replace(".sol", "")); const solidityContractsDetails = contractNames.map((c) => getSolidityContractDetails(dir, c)); @@ -100,7 +100,7 @@ const readBytecode = (details: ContractDetails): string => { try { if (details.bytecodePath.endsWith(".json")) { const jsonFile = fs.readFileSync(absolutePath, "utf8"); - return ethers.utils.hexlify(JSON.parse(jsonFile).bytecode); + return ethers.utils.hexlify("0x" + JSON.parse(jsonFile).bytecode.object); } else { return ethers.utils.hexlify(fs.readFileSync(absolutePath)); } diff --git a/system-contracts/scripts/compile-yul.ts b/system-contracts/scripts/compile-yul.ts index 5b972ef92..67b468987 100644 --- a/system-contracts/scripts/compile-yul.ts +++ b/system-contracts/scripts/compile-yul.ts @@ -1,11 +1,23 @@ // hardhat import should be the first import in the file import type { CompilerPaths } from "./utils"; -import { spawn, compilerLocation, prepareCompilerPaths, getSolcLocation } from "./utils"; +import { + spawn, + compilerLocation, + prepareCompilerPaths, + getSolcLocation, + needsRecompilation, + setCompilationTime, +} from "./utils"; import * as fs from "fs"; import { Command } from "commander"; +import * as _path from "path"; const COMPILER_VERSION = "1.3.18"; const IS_COMPILER_PRE_RELEASE = true; +const CONTRACTS_DIR = "contracts-preprocessed"; +const BOOTLOADER_DIR = "bootloader"; +const TIMESTAMP_FILE_YUL = "last_compilation_yul.timestamp"; +const TIMESTAMP_FILE_BOOTLOADER = "last_compilation_bootloader.timestamp"; export async function compileYul(paths: CompilerPaths, file: string) { const solcCompilerPath = await getSolcLocation(); @@ -32,14 +44,34 @@ async function main() { program.version("0.1.0").name("compile yul").description("publish preimages for the L2 contracts"); program.command("compile-bootloader").action(async () => { - await compileYulFolder("bootloader/build"); - await compileYulFolder("bootloader/tests"); + const timestampFilePath = _path.join(process.cwd(), TIMESTAMP_FILE_BOOTLOADER); + const folderToCheck = _path.join(process.cwd(), BOOTLOADER_DIR); + + if (needsRecompilation(folderToCheck, timestampFilePath)) { + console.log("Compilation needed."); + await compileYulFolder("bootloader/build"); + await compileYulFolder("bootloader/tests"); + setCompilationTime(timestampFilePath); + } else { + console.log("Compilation not needed."); + return; + } }); program.command("compile-precompiles").action(async () => { - await compileYulFolder("contracts-preprocessed"); - await compileYulFolder("contracts-preprocessed/precompiles"); - await compileYulFolder("contracts-preprocessed/precompiles/test-contracts"); + const timestampFilePath = _path.join(process.cwd(), TIMESTAMP_FILE_YUL); + const folderToCheck = _path.join(process.cwd(), CONTRACTS_DIR); + + if (needsRecompilation(folderToCheck, timestampFilePath)) { + console.log("Compilation needed."); + await compileYulFolder("contracts-preprocessed"); + await compileYulFolder("contracts-preprocessed/precompiles"); + await compileYulFolder("contracts-preprocessed/precompiles/test-contracts"); + setCompilationTime(timestampFilePath); + } else { + console.log("Compilation not needed."); + return; + } }); await program.parseAsync(process.argv); diff --git a/system-contracts/scripts/constants.ts b/system-contracts/scripts/constants.ts index 406b4cb6e..b354c36ab 100644 --- a/system-contracts/scripts/constants.ts +++ b/system-contracts/scripts/constants.ts @@ -184,7 +184,7 @@ export const EIP712_DOMAIN = { name: "zkSync", version: "2", chainId: CHAIN_ID, - // zkSync contract doesn't verify EIP712 signatures. + // ZKsync contract doesn't verify EIP712 signatures. }; export interface TransactionData { diff --git a/system-contracts/scripts/deploy-preimages.ts b/system-contracts/scripts/deploy-preimages.ts index 6803f9a53..0029f56a0 100644 --- a/system-contracts/scripts/deploy-preimages.ts +++ b/system-contracts/scripts/deploy-preimages.ts @@ -8,9 +8,9 @@ import { ethers } from "ethers"; import { formatUnits, parseUnits } from "ethers/lib/utils"; import * as fs from "fs"; import * as path from "path"; -import type { types } from "zksync-web3"; -import { Provider, Wallet } from "zksync-web3"; -import { hashBytecode } from "zksync-web3/build/src/utils"; +import type { types } from "zksync-ethers"; +import { Provider, Wallet } from "zksync-ethers"; +import { hashBytecode } from "zksync-ethers/build/utils"; import { Language, SYSTEM_CONTRACTS } from "./constants"; import type { Dependency, DeployedDependency } from "./utils"; import { checkMarkers, filterPublishedFactoryDeps, getBytecodes, publishFactoryDeps, readYulBytecode } from "./utils"; @@ -103,7 +103,7 @@ class ZkSyncDeployer { this.nonce += 1; } - // Returns the current default account bytecode on zkSync + // Returns the current default account bytecode on ZKsync async currentDefaultAccountBytecode(): Promise { const zkSync = await this.deployer.zkWallet.getMainContract(); return await zkSync.getL2DefaultAccountBytecodeHash(); @@ -114,7 +114,7 @@ class ZkSyncDeployer { const bytecodeHash = ethers.utils.hexlify(hashBytecode(defaultAccountBytecode)); const currentDefaultAccountBytecode = ethers.utils.hexlify(await this.currentDefaultAccountBytecode()); - // If the bytecode is not the same as the one deployed on zkSync, we need to add it to the deployment + // If the bytecode is not the same as the one deployed on ZKsync, we need to add it to the deployment if (bytecodeHash.toLowerCase() !== currentDefaultAccountBytecode) { this.defaultAccountToUpgrade = { name: DEFAULT_ACCOUNT_CONTRACT_NAME, @@ -161,7 +161,7 @@ class ZkSyncDeployer { const bytecodeHash = ethers.utils.hexlify(hashBytecode(bootloaderCode)); const currentBootloaderBytecode = ethers.utils.hexlify(await this.currentBootloaderBytecode()); - // If the bytecode is not the same as the one deployed on zkSync, we need to add it to the deployment + // If the bytecode is not the same as the one deployed on ZKsync, we need to add it to the deployment if (bytecodeHash.toLowerCase() !== currentBootloaderBytecode) { this.bootloaderToUpgrade = { name: BOOTLOADER_CONTRACT_NAME, diff --git a/system-contracts/scripts/preprocess-bootloader.ts b/system-contracts/scripts/preprocess-bootloader.ts index 4dbf145da..e3dc18aaf 100644 --- a/system-contracts/scripts/preprocess-bootloader.ts +++ b/system-contracts/scripts/preprocess-bootloader.ts @@ -6,20 +6,29 @@ import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs"; import { render, renderFile } from "template-file"; import { utils } from "zksync-ethers"; import { getRevertSelector, getTransactionUtils } from "./constants"; +import * as fs from "node:fs"; /* eslint-disable @typescript-eslint/no-var-requires */ const preprocess = require("preprocess"); const SYSTEM_PARAMS = require("../../SystemConfig.json"); /* eslint-enable@typescript-eslint/no-var-requires */ -const OUTPUT_DIR = "bootloader/build"; +const OUTPUT_DIR_1 = "contracts-preprocessed/bootloader"; +const OUTPUT_DIR_2 = "bootloader/build"; const PREPROCCESING_MODES = ["proved_batch", "playground_batch"]; function getSelector(contractName: string, method: string): string { - const artifact = hre.artifacts.readArtifactSync(contractName); - const contractInterface = new ethers.utils.Interface(artifact.abi); - + let contractInterface; + try { + const artifact = hre.artifacts.readArtifactSync(contractName); + contractInterface = new ethers.utils.Interface(artifact.abi); + } catch (e) { + const artifact = JSON.parse( + fs.readFileSync(`zkout/${contractName}.sol/${contractName}.json`, { encoding: "utf-8" }) + ); + contractInterface = new ethers.utils.Interface(artifact.abi); + } return contractInterface.getSighash(method); } @@ -33,6 +42,7 @@ function padZeroRight(hexData: string, length: number): string { } const PADDED_SELECTOR_LENGTH = 32 * 2 + 2; + function getPaddedSelector(contractName: string, method: string): string { const result = getSelector(contractName, method); @@ -40,7 +50,13 @@ function getPaddedSelector(contractName: string, method: string): string { } function getSystemContextCodeHash() { - const bytecode = hre.artifacts.readArtifactSync("SystemContext").bytecode; + let bytecode; + try { + const artifact = JSON.parse(fs.readFileSync("zkout/SystemContext.sol/SystemContext.json", { encoding: "utf-8" })); + bytecode = "0x" + artifact.bytecode.object; + } catch (e) { + bytecode = hre.artifacts.readArtifactSync("SystemContext").bytecode; + } return ethers.utils.hexlify(utils.hashBytecode(bytecode)); } @@ -209,15 +225,32 @@ async function main() { }); const provedBootloaderWithTests = preprocess.preprocess(bootloaderWithTests, { BOOTLOADER_TYPE: "proved_batch" }); - if (!existsSync(OUTPUT_DIR)) { - mkdirSync(OUTPUT_DIR); + if (!existsSync(OUTPUT_DIR_1)) { + mkdirSync(OUTPUT_DIR_1); + } + + if (!existsSync(OUTPUT_DIR_2)) { + mkdirSync(OUTPUT_DIR_2); } - writeFileSync(`${OUTPUT_DIR}/bootloader_test.yul`, provedBootloaderWithTests); - writeFileSync(`${OUTPUT_DIR}/proved_batch.yul`, provedBatchBootloader); - writeFileSync(`${OUTPUT_DIR}/playground_batch.yul`, playgroundBatchBootloader); - writeFileSync(`${OUTPUT_DIR}/gas_test.yul`, gasTestBootloader); - writeFileSync(`${OUTPUT_DIR}/fee_estimate.yul`, feeEstimationBootloader); + const transferTest = readFileSync("bootloader/tests/transfer_test.yul").toString(); + const dummy = readFileSync("bootloader/tests/dummy.yul").toString(); + + writeFileSync(`${OUTPUT_DIR_1}/bootloader_test.yul`, provedBootloaderWithTests); + writeFileSync(`${OUTPUT_DIR_1}/proved_batch.yul`, provedBatchBootloader); + writeFileSync(`${OUTPUT_DIR_1}/playground_batch.yul`, playgroundBatchBootloader); + writeFileSync(`${OUTPUT_DIR_1}/gas_test.yul`, gasTestBootloader); + writeFileSync(`${OUTPUT_DIR_1}/fee_estimate.yul`, feeEstimationBootloader); + writeFileSync(`${OUTPUT_DIR_1}/dummy.yul`, dummy); + writeFileSync(`${OUTPUT_DIR_1}/transfer_test.yul`, transferTest); + + writeFileSync(`${OUTPUT_DIR_2}/bootloader_test.yul`, provedBootloaderWithTests); + writeFileSync(`${OUTPUT_DIR_2}/proved_batch.yul`, provedBatchBootloader); + writeFileSync(`${OUTPUT_DIR_2}/playground_batch.yul`, playgroundBatchBootloader); + writeFileSync(`${OUTPUT_DIR_2}/gas_test.yul`, gasTestBootloader); + writeFileSync(`${OUTPUT_DIR_2}/fee_estimate.yul`, feeEstimationBootloader); + writeFileSync(`${OUTPUT_DIR_2}/dummy.yul`, dummy); + writeFileSync(`${OUTPUT_DIR_2}/transfer_test.yul`, transferTest); console.log("Bootloader preprocessing done!"); } diff --git a/system-contracts/scripts/preprocess-system-contracts.ts b/system-contracts/scripts/preprocess-system-contracts.ts index acecee1ac..0b3690a9e 100644 --- a/system-contracts/scripts/preprocess-system-contracts.ts +++ b/system-contracts/scripts/preprocess-system-contracts.ts @@ -3,9 +3,11 @@ import path from "path"; import { renderFile } from "template-file"; import { glob } from "fast-glob"; import { Command } from "commander"; +import { needsRecompilation, deleteDir, setCompilationTime, isFolderEmpty } from "./utils"; const CONTRACTS_DIR = "contracts"; const OUTPUT_DIR = "contracts-preprocessed"; +const TIMESTAMP_FILE = "last_compilation_preprocessing.timestamp"; // File to store the last compilation time const params = { SYSTEM_CONTRACTS_OFFSET: "0x8000", @@ -17,6 +19,18 @@ async function preprocess(testMode: boolean) { params.SYSTEM_CONTRACTS_OFFSET = "0x9000"; } + const timestampFilePath = path.join(process.cwd(), TIMESTAMP_FILE); + const folderToCheck = path.join(process.cwd(), CONTRACTS_DIR); + + if ((await isFolderEmpty(OUTPUT_DIR)) || needsRecompilation(folderToCheck, timestampFilePath) || testMode) { + console.log("Preprocessing needed."); + deleteDir(OUTPUT_DIR); + setCompilationTime(timestampFilePath); + } else { + console.log("Preprocessing not needed."); + return; + } + const contracts = await glob( [`${CONTRACTS_DIR}/**/*.sol`, `${CONTRACTS_DIR}/**/*.yul`, `${CONTRACTS_DIR}/**/*.zasm`], { onlyFiles: true } diff --git a/system-contracts/scripts/utils.ts b/system-contracts/scripts/utils.ts index 2deba9ce0..4c1060ee2 100644 --- a/system-contracts/scripts/utils.ts +++ b/system-contracts/scripts/utils.ts @@ -7,7 +7,8 @@ import type { Deployer } from "@matterlabs/hardhat-zksync-deploy"; import type { BigNumberish, BytesLike } from "ethers"; import { BigNumber, ethers } from "ethers"; import * as fs from "fs"; -import { hashBytecode } from "zksync-web3/build/src/utils"; +import * as fsPr from "fs/promises"; +import { hashBytecode } from "zksync-ethers/build/utils"; import type { YulContractDescription, ZasmContractDescription } from "./constants"; import { Language, SYSTEM_CONTRACTS } from "./constants"; import { getCompilersDir } from "hardhat/internal/util/global-dir"; @@ -83,7 +84,7 @@ export async function outputSystemContracts(): Promise { return await Promise.all(upgradeParamsPromises); } -// Script that publishes preimages for all the system contracts on zkSync +// Script that publishes preimages for all the system contracts on ZKsync // and outputs the JSON that can be used for performing the necessary upgrade const DEFAULT_L2_TX_GAS_LIMIT = 2097152; @@ -257,6 +258,77 @@ export function prepareCompilerPaths(path: string): CompilerPaths { return new CompilerPaths(absolutePathSources, absolutePathArtifacts); } +// Get the latest file modification time in the watched folder +function getLatestModificationTime(folder: string): Date | null { + const files = fs.readdirSync(folder); + let latestTime: Date | null = null; // Initialize to null to avoid uninitialized variable + + files.forEach((file) => { + const filePath = path.join(folder, file); + const stats = fs.statSync(filePath); + if (stats.isDirectory()) { + const dirLatestTime = getLatestModificationTime(filePath); + if (dirLatestTime && (!latestTime || dirLatestTime > latestTime)) { + latestTime = dirLatestTime; + } + } else if (stats.isFile()) { + if (!latestTime || stats.mtime > latestTime) { + latestTime = stats.mtime; + } + } + }); + + return latestTime; +} + +// Read the last compilation timestamp from the file +export function getLastCompilationTime(timestampFile: string): Date | null { + try { + if (fs.existsSync(timestampFile)) { + const timestamp = fs.readFileSync(timestampFile, "utf-8"); + return new Date(parseInt(timestamp, 10)); + } + } catch (error) { + const err = error as Error; // Cast `error` to `Error` + console.error(`Error reading timestamp: ${err.message}`); + } + return null; +} + +// Write the current time to the timestamp file +export function setCompilationTime(timestampFile: string) { + fs.writeFileSync(timestampFile, Date.now().toString()); +} + +// Determine if recompilation is needed +export function needsRecompilation(folder: string, timestampFile: string): boolean { + const lastCompilationTime = getLastCompilationTime(timestampFile); + const latestModificationTime = getLatestModificationTime(folder); + if (!lastCompilationTime) { + return true; // If there's no history, always recompile + } + + return latestModificationTime! > lastCompilationTime; +} + +export function deleteDir(path: string): void { + try { + fs.rmSync(path, { recursive: true, force: true }); // 'recursive: true' deletes all contents, 'force: true' prevents errors if the directory doesn't exist + console.log(`Directory '${path}' deleted successfully.`); + } catch (error) { + console.error(`Error deleting directory '${path}':`, error); + } +} + +export async function isFolderEmpty(folderPath: string): Promise { + try { + const files = await fsPr.readdir(folderPath); // Get a list of files in the folder + return files.length === 0; // If there are no files, the folder is empty + } catch (error) { + console.error("No target folder with artifacts."); + return true; // Return true if an error, as folder doesn't exist. + } +} /** * Performs an API call to the Contract verification API. * diff --git a/system-contracts/test/AccountCodeStorage.spec.ts b/system-contracts/test/AccountCodeStorage.spec.ts index 994cfacc8..dca782e01 100644 --- a/system-contracts/test/AccountCodeStorage.spec.ts +++ b/system-contracts/test/AccountCodeStorage.spec.ts @@ -44,7 +44,7 @@ describe("AccountCodeStorage tests", function () { it("non-deployer failed to call", async () => { await expect( accountCodeStorage.storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH) - ).to.be.revertedWith("Callable only by the deployer system contract"); + ).to.be.revertedWithCustomError(accountCodeStorage, "Unauthorized"); }); it("failed to set with constructed bytecode", async () => { @@ -52,7 +52,7 @@ describe("AccountCodeStorage tests", function () { accountCodeStorage .connect(deployerAccount) .storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTED_BYTECODE_HASH) - ).to.be.revertedWith("Code hash is not for a contract on constructor"); + ).to.be.revertedWithCustomError(accountCodeStorage, "InvalidCodeHash"); }); it("successfully stored", async () => { @@ -72,7 +72,7 @@ describe("AccountCodeStorage tests", function () { it("non-deployer failed to call", async () => { await expect( accountCodeStorage.storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH) - ).to.be.revertedWith("Callable only by the deployer system contract"); + ).to.be.revertedWithCustomError(accountCodeStorage, "Unauthorized"); }); it("failed to set with constructing bytecode", async () => { @@ -80,7 +80,7 @@ describe("AccountCodeStorage tests", function () { accountCodeStorage .connect(deployerAccount) .storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH) - ).to.be.revertedWith("Code hash is not for a constructed contract"); + ).to.be.revertedWithCustomError(accountCodeStorage, "InvalidCodeHash"); }); it("successfully stored", async () => { @@ -96,8 +96,9 @@ describe("AccountCodeStorage tests", function () { describe("markAccountCodeHashAsConstructed", function () { it("non-deployer failed to call", async () => { - await expect(accountCodeStorage.markAccountCodeHashAsConstructed(RANDOM_ADDRESS)).to.be.revertedWith( - "Callable only by the deployer system contract" + await expect(accountCodeStorage.markAccountCodeHashAsConstructed(RANDOM_ADDRESS)).to.be.revertedWithCustomError( + accountCodeStorage, + "Unauthorized" ); }); @@ -108,7 +109,7 @@ describe("AccountCodeStorage tests", function () { await expect( accountCodeStorage.connect(deployerAccount).markAccountCodeHashAsConstructed(RANDOM_ADDRESS) - ).to.be.revertedWith("Code hash is not for a contract on constructor"); + ).to.be.revertedWithCustomError(accountCodeStorage, "InvalidCodeHash"); await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); }); diff --git a/system-contracts/test/BootloaderUtilities.spec.ts b/system-contracts/test/BootloaderUtilities.spec.ts index 998b98e8b..7c3c8ed69 100644 --- a/system-contracts/test/BootloaderUtilities.spec.ts +++ b/system-contracts/test/BootloaderUtilities.spec.ts @@ -84,7 +84,10 @@ describe("BootloaderUtilities tests", function () { signature[64] = 29; txData.signature = signature; - await expect(bootloaderUtilities.getTransactionHashes(txData)).to.be.revertedWith("Invalid v value"); + await expect(bootloaderUtilities.getTransactionHashes(txData)).to.be.revertedWithCustomError( + bootloaderUtilities, + "InvalidSig" + ); }); }); @@ -130,7 +133,10 @@ describe("BootloaderUtilities tests", function () { signature[64] = 0; EIP1559TxData.signature = signature; - await expect(bootloaderUtilities.getTransactionHashes(EIP1559TxData)).to.be.revertedWith("Invalid v value"); + await expect(bootloaderUtilities.getTransactionHashes(EIP1559TxData)).to.be.revertedWithCustomError( + bootloaderUtilities, + "InvalidSig" + ); }); }); @@ -176,7 +182,10 @@ describe("BootloaderUtilities tests", function () { signature[64] = 100; EIP2930TxData.signature = signature; - await expect(bootloaderUtilities.getTransactionHashes(EIP2930TxData)).to.be.revertedWith("Invalid v value"); + await expect(bootloaderUtilities.getTransactionHashes(EIP2930TxData)).to.be.revertedWithCustomError( + bootloaderUtilities, + "InvalidSig" + ); }); }); }); diff --git a/system-contracts/test/CodeOracle.spec.ts b/system-contracts/test/CodeOracle.spec.ts index b4df2ceaf..d9b0c3781 100644 --- a/system-contracts/test/CodeOracle.spec.ts +++ b/system-contracts/test/CodeOracle.spec.ts @@ -1,4 +1,4 @@ -import { hashBytecode } from "zksync-web3/build/src/utils"; +import { hashBytecode } from "zksync-ethers/build/utils"; import type { CodeOracleTest } from "../typechain"; import { REAL_CODE_ORACLE_CONTRACT_ADDRESS } from "./shared/constants"; import { publishBytecode, setCode, getCode, deployContract } from "./shared/utils"; diff --git a/system-contracts/test/ComplexUpgrader.spec.ts b/system-contracts/test/ComplexUpgrader.spec.ts index 63b4a61eb..e9104e010 100644 --- a/system-contracts/test/ComplexUpgrader.spec.ts +++ b/system-contracts/test/ComplexUpgrader.spec.ts @@ -18,8 +18,9 @@ describe("ComplexUpgrader tests", function () { describe("upgrade", function () { it("non force deployer failed to call", async () => { - await expect(complexUpgrader.upgrade(dummyUpgrade.address, "0xdeadbeef")).to.be.revertedWith( - "Can only be called by FORCE_DEPLOYER" + await expect(complexUpgrader.upgrade(dummyUpgrade.address, "0xdeadbeef")).to.be.revertedWithCustomError( + complexUpgrader, + "Unauthorized" ); }); diff --git a/system-contracts/test/Compressor.spec.ts b/system-contracts/test/Compressor.spec.ts index 094eddd99..615ab9211 100644 --- a/system-contracts/test/Compressor.spec.ts +++ b/system-contracts/test/Compressor.spec.ts @@ -46,8 +46,9 @@ describe("Compressor tests", function () { describe("publishCompressedBytecode", function () { it("should revert when it's a non-bootloader call", async () => { - await expect(compressor.publishCompressedBytecode("0x", "0x0000")).to.be.revertedWith( - "Callable only by the bootloader" + await expect(compressor.publishCompressedBytecode("0x", "0x0000")).to.be.revertedWithCustomError( + compressor, + "CallerMustBeBootloader" ); }); @@ -57,7 +58,7 @@ describe("Compressor tests", function () { const COMPRESSED_BYTECODE = "0x0002" + "deadbeefdeadbeef" + "0000" + "0000" + "0000" + "0000"; await expect( compressor.connect(bootloaderAccount).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) - ).to.be.revertedWith("Encoded data length should be 4 times shorter than the original bytecode"); + ).to.be.revertedWithCustomError(compressor, "EncodedLengthNotFourTimesSmallerThanOriginal"); }); it("should revert when there is no encoded data", async () => { @@ -66,7 +67,7 @@ describe("Compressor tests", function () { const COMPRESSED_BYTECODE = "0x0002" + "deadbeefdeadbeef" + "deadbeefdeadbeef"; await expect( compressor.connect(bootloaderAccount).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) - ).to.be.revertedWith("Encoded data length should be 4 times shorter than the original bytecode"); + ).to.be.revertedWithCustomError(compressor, "EncodedLengthNotFourTimesSmallerThanOriginal"); }); it("should revert when the encoded data length is invalid", async () => { @@ -80,7 +81,7 @@ describe("Compressor tests", function () { // The length of the encodedData should be 32 / 4 = 8 bytes await expect( compressor.connect(bootloaderAccount).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) - ).to.be.revertedWith("Encoded data length should be 4 times shorter than the original bytecode"); + ).to.be.revertedWithCustomError(compressor, "EncodedLengthNotFourTimesSmallerThanOriginal"); }); it("should revert when the dictionary has too many entries", async () => { @@ -101,7 +102,7 @@ describe("Compressor tests", function () { // The dictionary should have at most encode data length entries await expect( compressor.connect(bootloaderAccount).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) - ).to.be.revertedWith("Dictionary should have at most the same number of entries as the encoded data"); + ).to.be.revertedWithCustomError(compressor, "DictionaryDividedByEightNotGreaterThanEncodedDividedByTwo"); }); it("should revert when the encoded data has chunks where index is out of bounds", async () => { @@ -112,7 +113,7 @@ describe("Compressor tests", function () { // The dictionary has only 1 entry, so at the last entry of the encoded data the chunk index is out of bounds await expect( compressor.connect(bootloaderAccount).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) - ).to.be.revertedWith("Encoded chunk index is out of bounds"); + ).to.be.revertedWithCustomError(compressor, "IndexOutOfBounds"); }); it("should revert when the encoded data has chunks that does not match the original bytecode", async () => { @@ -122,7 +123,7 @@ describe("Compressor tests", function () { "0x0002" + "deadbeefdeadbeef" + "1111111111111111" + "0001" + "0000" + "0000" + "0001"; await expect( compressor.connect(bootloaderAccount).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) - ).to.be.revertedWith("Encoded chunk does not match the original bytecode"); + ).to.be.revertedWithCustomError(compressor, "EncodedAndRealBytecodeChunkNotEqual"); }); it("should revert when the bytecode length in bytes is invalid", async () => { @@ -131,7 +132,7 @@ describe("Compressor tests", function () { const COMPRESSED_BYTECODE = "0x0001" + "deadbeefdeadbeef" + "0000" + "0000" + "0000"; await expect( compressor.connect(bootloaderAccount).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) - ).to.be.revertedWith("po"); + ).to.be.revertedWithCustomError(compressor, "MalformedBytecode"); }); it("should revert when the bytecode length in words is odd", async () => { @@ -140,7 +141,7 @@ describe("Compressor tests", function () { const COMPRESSED_BYTECODE = "0x0001" + "deadbeefdeadbeef" + "0000".repeat(4 * 2); await expect( compressor.connect(bootloaderAccount).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) - ).to.be.revertedWith("pr"); + ).to.be.revertedWithCustomError(compressor, "MalformedBytecode"); }); // Test case with too big bytecode is unrealistic because API cannot accept so much data. @@ -183,8 +184,9 @@ describe("Compressor tests", function () { describe("verifyCompressedStateDiffs", function () { it("non l1 messenger failed to call", async () => { - await expect(compressor.verifyCompressedStateDiffs(0, 8, "0x", "0x0000")).to.be.revertedWith( - "Inappropriate caller" + await expect(compressor.verifyCompressedStateDiffs(0, 8, "0x", "0x0000")).to.be.revertedWithCustomError( + compressor, + "Unauthorized" ); }); @@ -202,7 +204,7 @@ describe("Compressor tests", function () { const compressedStateDiffs = compressStateDiffs(9, stateDiffs); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(1, 9, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith("enumeration index size is too large"); + ).to.be.revertedWithCustomError(compressor, "IndexSizeError"); }); it("initial write key mismatch", async () => { @@ -219,7 +221,7 @@ describe("Compressor tests", function () { const compressedStateDiffs = compressStateDiffs(4, stateDiffs); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(1, 4, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith("iw: initial key mismatch"); + ).to.be.revertedWithCustomError(compressor, "DerivedKeyNotEqualToCompressedValue"); }); it("repeated write key mismatch", async () => { @@ -236,7 +238,7 @@ describe("Compressor tests", function () { const compressedStateDiffs = compressStateDiffs(8, stateDiffs); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(1, 8, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith("rw: enum key mismatch"); + ).to.be.revertedWithCustomError(compressor, "CompressorEnumIndexNotEqual"); }); it("no compression value mismatch", async () => { @@ -259,7 +261,7 @@ describe("Compressor tests", function () { const compressedStateDiffs = compressStateDiffs(3, stateDiffs); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(2, 3, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith("transform or no compression: compressed and final mismatch"); + ).to.be.revertedWithCustomError(compressor, "CompressionValueTransformError"); }); it("transform value mismatch", async () => { @@ -282,7 +284,7 @@ describe("Compressor tests", function () { const compressedStateDiffs = compressStateDiffs(1, stateDiffs); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(2, 1, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith("transform or no compression: compressed and final mismatch"); + ).to.be.revertedWithCustomError(compressor, "CompressionValueTransformError"); }); it("add value mismatch", async () => { @@ -299,7 +301,7 @@ describe("Compressor tests", function () { const compressedStateDiffs = compressStateDiffs(1, stateDiffs); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(1, 1, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith("add: initial plus converted not equal to final"); + ).to.be.revertedWithCustomError(compressor, "CompressionValueAddError"); }); it("sub value mismatch", async () => { @@ -316,7 +318,7 @@ describe("Compressor tests", function () { const compressedStateDiffs = compressStateDiffs(1, stateDiffs); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(1, 1, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith("sub: initial minus converted not equal to final"); + ).to.be.revertedWithCustomError(compressor, "CompressionValueSubError"); }); it("invalid operation", async () => { @@ -335,7 +337,7 @@ describe("Compressor tests", function () { compressedStateDiffs = compressedStateDiffsCharArray.join(""); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(1, 1, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith("unsupported operation"); + ).to.be.revertedWithCustomError(compressor, "UnsupportedOperation"); }); it("Incorrect number of initial storage diffs", async () => { @@ -363,7 +365,7 @@ describe("Compressor tests", function () { const compressedStateDiffs = compressStateDiffs(1, stateDiffs); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(2, 1, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith("Incorrect number of initial storage diffs"); + ).to.be.revertedWithCustomError(compressor, "CompressorInitialWritesProcessedNotEqual"); }); it("Extra data in compressed state diffs", async () => { @@ -391,7 +393,7 @@ describe("Compressor tests", function () { const compressedStateDiffs = compressStateDiffs(1, stateDiffs); await expect( compressor.connect(l1MessengerAccount).verifyCompressedStateDiffs(2, 1, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith("Extra data in _compressedStateDiffs"); + ).to.be.revertedWithCustomError(compressor, "StateDiffLengthMismatch"); }); it("successfully verified", async () => { diff --git a/system-contracts/test/ContractDeployer.spec.ts b/system-contracts/test/ContractDeployer.spec.ts index 6f8984eae..bcae882c0 100644 --- a/system-contracts/test/ContractDeployer.spec.ts +++ b/system-contracts/test/ContractDeployer.spec.ts @@ -68,8 +68,9 @@ describe("ContractDeployer tests", function () { describe("updateAccountVersion", function () { it("non system call failed", async () => { - await expect(contractDeployer.updateAccountVersion(AA_VERSION_NONE)).to.be.revertedWith( - "This method require system call flag" + await expect(contractDeployer.updateAccountVersion(AA_VERSION_NONE)).to.be.revertedWithCustomError( + contractDeployer, + "SystemCallFlagRequired" ); }); @@ -96,8 +97,9 @@ describe("ContractDeployer tests", function () { describe("updateNonceOrdering", function () { it("non system call failed", async () => { - await expect(contractDeployer.updateNonceOrdering(NONCE_ORDERING_SEQUENTIAL)).to.be.revertedWith( - "This method require system call flag" + await expect(contractDeployer.updateNonceOrdering(NONCE_ORDERING_SEQUENTIAL)).to.be.revertedWithCustomError( + contractDeployer, + "SystemCallFlagRequired" ); }); @@ -115,9 +117,9 @@ describe("ContractDeployer tests", function () { expect((await contractDeployer.getAccountInfo(contractDeployerSystemCall.address)).nonceOrdering).to.be.eq( NONCE_ORDERING_ARBITRARY ); - await expect(contractDeployerSystemCall.updateNonceOrdering(NONCE_ORDERING_SEQUENTIAL)).to.be.revertedWith( - "It is only possible to change from sequential to arbitrary ordering" - ); + await expect( + contractDeployerSystemCall.updateNonceOrdering(NONCE_ORDERING_SEQUENTIAL) + ).to.be.revertedWithCustomError(contractDeployer, "InvalidNonceOrderingChange"); }); }); @@ -233,7 +235,7 @@ describe("ContractDeployer tests", function () { "0x", AA_VERSION_NONE ) - ).to.be.revertedWith("This method require system call flag"); + ).to.be.revertedWithCustomError(contractDeployer, "SystemCallFlagRequired"); }); it("zero bytecode hash failed", async () => { @@ -244,7 +246,7 @@ describe("ContractDeployer tests", function () { "0x", AA_VERSION_NONE ) - ).to.be.revertedWith("BytecodeHash cannot be zero"); + ).to.be.revertedWithCustomError(contractDeployer, "EmptyBytes32"); }); it("not known bytecode hash failed", async () => { @@ -261,7 +263,7 @@ describe("ContractDeployer tests", function () { "0x", AA_VERSION_NONE ) - ).to.be.revertedWith("The code hash is not known"); + ).to.be.revertedWithCustomError(contractDeployer, "UnknownCodeHash"); }); // TODO: other mock events can be checked as well @@ -344,7 +346,7 @@ describe("ContractDeployer tests", function () { "0xdeadbeef", AA_VERSION_NONE ) - ).to.be.revertedWith("This method require system call flag"); + ).to.be.revertedWithCustomError(contractDeployer, "SystemCallFlagRequired"); }); it("zero bytecode hash failed", async () => { @@ -355,7 +357,7 @@ describe("ContractDeployer tests", function () { "0x", AA_VERSION_NONE ) - ).to.be.revertedWith("BytecodeHash cannot be zero"); + ).to.be.revertedWithCustomError(contractDeployerSystemCall, "EmptyBytes32"); }); it("not known bytecode hash failed", async () => { @@ -386,7 +388,7 @@ describe("ContractDeployer tests", function () { "0x", AA_VERSION_NONE ) - ).to.be.revertedWith("The code hash is not known"); + ).to.be.revertedWithCustomError(contractDeployerSystemCall, "UnknownCodeHash"); }); it("successfully deployed", async () => { @@ -419,7 +421,7 @@ describe("ContractDeployer tests", function () { "0xdeadbeef", AA_VERSION_NONE ) - ).to.be.revertedWith("Code hash is non-zero"); + ).to.be.revertedWithCustomError(contractDeployerSystemCall, "HashIsNonZero"); await setResult("AccountCodeStorage", "getCodeHash", [expectedAddress], { failure: false, returnData: ethers.constants.HashZero, @@ -477,7 +479,7 @@ describe("ContractDeployer tests", function () { it("non system call failed", async () => { await expect( contractDeployer.create(ethers.constants.HashZero, utils.hashBytecode(deployableArtifact.bytecode), "0x") - ).to.be.revertedWith("This method require system call flag"); + ).to.be.revertedWithCustomError(contractDeployer, "SystemCallFlagRequired"); }); it("successfully deployed", async () => { @@ -534,7 +536,7 @@ describe("ContractDeployer tests", function () { it("non system call failed", async () => { await expect( contractDeployer.create2(ethers.constants.HashZero, utils.hashBytecode(deployableArtifact.bytecode), "0xabcd") - ).to.be.revertedWith("This method require system call flag"); + ).to.be.revertedWithCustomError(contractDeployer, "SystemCallFlagRequired"); }); it("successfully deployed", async () => { @@ -564,8 +566,9 @@ describe("ContractDeployer tests", function () { value: 0, input: "0x", }; - await expect(contractDeployer.forceDeployOnAddress(deploymentData, wallet.address)).to.be.revertedWith( - "Callable only by self" + await expect(contractDeployer.forceDeployOnAddress(deploymentData, wallet.address)).to.be.revertedWithCustomError( + contractDeployer, + "Unauthorized" ); }); @@ -585,7 +588,7 @@ describe("ContractDeployer tests", function () { }; await expect( contractDeployer.connect(deployerAccount).forceDeployOnAddress(deploymentData, wallet.address) - ).to.be.revertedWith("The code hash is not known"); + ).to.be.revertedWithCustomError(contractDeployerSystemCall, "UnknownCodeHash"); }); it("successfully deployed", async () => { @@ -628,8 +631,9 @@ describe("ContractDeployer tests", function () { input: "0xab", }, ]; - await expect(contractDeployer.forceDeployOnAddresses(deploymentData)).to.be.revertedWith( - "Can only be called by FORCE_DEPLOYER or COMPLEX_UPGRADER_CONTRACT" + await expect(contractDeployer.forceDeployOnAddresses(deploymentData)).to.be.revertedWithCustomError( + contractDeployer, + "Unauthorized" ); }); diff --git a/system-contracts/test/DefaultAccount.spec.ts b/system-contracts/test/DefaultAccount.spec.ts index 77dafa1ed..9f3d380d3 100644 --- a/system-contracts/test/DefaultAccount.spec.ts +++ b/system-contracts/test/DefaultAccount.spec.ts @@ -2,7 +2,7 @@ import { expect } from "chai"; import { ethers, network } from "hardhat"; import type { Wallet } from "zksync-ethers"; import * as zksync from "zksync-ethers"; -import { serialize } from "zksync-web3/build/src/utils"; +import { serialize } from "zksync-ethers/build/utils"; import type { DefaultAccount, DelegateCaller, MockContract } from "../typechain"; import { DefaultAccountFactory } from "../typechain"; import { TEST_BOOTLOADER_FORMAL_ADDRESS } from "./shared/constants"; diff --git a/system-contracts/test/EventWriter.spec.ts b/system-contracts/test/EventWriter.spec.ts index 072f8e35b..35c5d66f7 100644 --- a/system-contracts/test/EventWriter.spec.ts +++ b/system-contracts/test/EventWriter.spec.ts @@ -2,7 +2,7 @@ import { expect } from "chai"; import { ethers } from "hardhat"; import type { Wallet } from "zksync-ethers"; import { Contract } from "zksync-ethers"; -import type { TransactionResponse } from "zksync-web3/build/src/types"; +import type { TransactionResponse } from "zksync-ethers/build/types"; import { ONE_BYTES32_HEX, REAL_EVENT_WRITER_CONTRACT_ADDRESS } from "./shared/constants"; import { EXTRA_ABI_CALLER_ADDRESS, encodeExtraAbiCallerCalldata } from "./shared/extraAbiCaller"; import { getCode, getWallets, loadYulBytecode, loadZasmBytecode, setCode } from "./shared/utils"; diff --git a/system-contracts/test/ImmutableSimulator.spec.ts b/system-contracts/test/ImmutableSimulator.spec.ts index 530fa370c..0adce4c2e 100644 --- a/system-contracts/test/ImmutableSimulator.spec.ts +++ b/system-contracts/test/ImmutableSimulator.spec.ts @@ -31,8 +31,9 @@ describe("ImmutableSimulator tests", function () { describe("setImmutables", function () { it("non-deployer failed to call", async () => { - await expect(immutableSimulator.setImmutables(RANDOM_ADDRESS, IMMUTABLES_DATA)).to.be.revertedWith( - "Callable only by the deployer system contract" + await expect(immutableSimulator.setImmutables(RANDOM_ADDRESS, IMMUTABLES_DATA)).to.be.revertedWithCustomError( + immutableSimulator, + "Unauthorized" ); }); diff --git a/system-contracts/test/KnownCodesStorage.spec.ts b/system-contracts/test/KnownCodesStorage.spec.ts index 9558f85dc..36a034cb7 100644 --- a/system-contracts/test/KnownCodesStorage.spec.ts +++ b/system-contracts/test/KnownCodesStorage.spec.ts @@ -50,21 +50,22 @@ describe("KnownCodesStorage tests", function () { describe("markBytecodeAsPublished", function () { it("non-compressor failed to call", async () => { - await expect(knownCodesStorage.markBytecodeAsPublished(BYTECODE_HASH_1)).to.be.revertedWith( - "Callable only by the compressor" + await expect(knownCodesStorage.markBytecodeAsPublished(BYTECODE_HASH_1)).to.be.revertedWithCustomError( + knownCodesStorage, + "Unauthorized" ); }); it("incorrectly formatted bytecode hash failed to call", async () => { await expect( knownCodesStorage.connect(compressorAccount).markBytecodeAsPublished(INCORRECTLY_FORMATTED_HASH) - ).to.be.revertedWith("Incorrectly formatted bytecodeHash"); + ).to.be.revertedWithCustomError(knownCodesStorage, "MalformedBytecode"); }); it("invalid length bytecode hash failed to call", async () => { await expect( knownCodesStorage.connect(compressorAccount).markBytecodeAsPublished(INVALID_LENGTH_HASH) - ).to.be.revertedWith("Code length in words must be odd"); + ).to.be.revertedWithCustomError(knownCodesStorage, "MalformedBytecode"); }); it("successfully marked", async () => { @@ -85,9 +86,9 @@ describe("KnownCodesStorage tests", function () { describe("markFactoryDeps", function () { it("non-bootloader failed to call", async () => { - await expect(knownCodesStorage.markFactoryDeps(false, [BYTECODE_HASH_2, BYTECODE_HASH_3])).to.be.revertedWith( - "Callable only by the bootloader" - ); + await expect( + knownCodesStorage.markFactoryDeps(false, [BYTECODE_HASH_2, BYTECODE_HASH_3]) + ).to.be.revertedWithCustomError(knownCodesStorage, "CallerMustBeBootloader"); }); it("incorrectly formatted bytecode hash failed to call", async () => { @@ -95,13 +96,13 @@ describe("KnownCodesStorage tests", function () { knownCodesStorage .connect(bootloaderAccount) .markFactoryDeps(true, [BYTECODE_HASH_2, INCORRECTLY_FORMATTED_HASH]) - ).to.be.revertedWith("Incorrectly formatted bytecodeHash"); + ).to.be.revertedWithCustomError(knownCodesStorage, "MalformedBytecode"); }); it("invalid length bytecode hash failed to call", async () => { await expect( knownCodesStorage.connect(bootloaderAccount).markFactoryDeps(false, [INVALID_LENGTH_HASH, BYTECODE_HASH_3]) - ).to.be.revertedWith("Code length in words must be odd"); + ).to.be.revertedWithCustomError(knownCodesStorage, "MalformedBytecode"); }); it("successfully marked", async () => { diff --git a/system-contracts/test/L1Messenger.spec.ts b/system-contracts/test/L1Messenger.spec.ts index 74f16fc10..678da92a9 100644 --- a/system-contracts/test/L1Messenger.spec.ts +++ b/system-contracts/test/L1Messenger.spec.ts @@ -4,8 +4,8 @@ import { L1MessengerFactory } from "../typechain"; import { prepareEnvironment, setResult } from "./shared/mocks"; import type { StateDiff } from "./shared/utils"; import { compressStateDiffs, deployContractOnAddress, encodeStateDiffs, getCode, getWallets } from "./shared/utils"; -import { utils } from "zksync-web3"; -import type { Wallet } from "zksync-web3"; +import { utils } from "zksync-ethers"; +import type { Wallet } from "zksync-ethers"; import { TEST_KNOWN_CODE_STORAGE_CONTRACT_ADDRESS, TEST_L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, @@ -99,7 +99,7 @@ describe("L1Messenger tests", () => { l1Messenger .connect(bootloaderAccount) .publishPubdataAndClearState(emulator.buildTotalL2ToL1PubdataAndStateDiffs({ numberOfLogs: 0x4002 })) - ).to.be.rejectedWith("Too many L2->L1 logs"); + ).to.be.revertedWithCustomError(l1Messenger, "ReconstructionMismatch"); }); it("should revert logshashes mismatch", async () => { @@ -121,7 +121,7 @@ describe("L1Messenger tests", () => { l1Messenger .connect(bootloaderAccount) .publishPubdataAndClearState(emulator.buildTotalL2ToL1PubdataAndStateDiffs(overrideData)) - ).to.be.rejectedWith("reconstructedChainedLogsHash is not equal to chainedLogsHash"); + ).to.be.revertedWithCustomError(l1Messenger, "ReconstructionMismatch"); }); it("should revert chainedMessageHash mismatch", async () => { @@ -133,7 +133,7 @@ describe("L1Messenger tests", () => { l1Messenger .connect(bootloaderAccount) .publishPubdataAndClearState(emulator.buildTotalL2ToL1PubdataAndStateDiffs(overrideData)) - ).to.be.rejectedWith("reconstructedChainedMessagesHash is not equal to chainedMessagesHash"); + ).to.be.revertedWithCustomError(l1Messenger, "ReconstructionMismatch"); }); it("should revert state diff compression version mismatch", async () => { @@ -151,7 +151,7 @@ describe("L1Messenger tests", () => { version: ethers.utils.hexZeroPad(ethers.utils.hexlify(66), 1), }) ) - ).to.be.rejectedWith("state diff compression version mismatch"); + ).to.be.revertedWithCustomError(l1Messenger, "ReconstructionMismatch"); }); it("should revert extra data", async () => { @@ -162,14 +162,15 @@ describe("L1Messenger tests", () => { .publishPubdataAndClearState( ethers.utils.concat([emulator.buildTotalL2ToL1PubdataAndStateDiffs(), Buffer.alloc(1, 64)]) ) - ).to.be.rejectedWith("Extra data in the totalL2ToL1Pubdata array"); + ).to.be.revertedWithCustomError(l1Messenger, "ReconstructionMismatch"); }); }); describe("sendL2ToL1Log", async () => { it("should revert when not called by the system contract", async () => { - await expect(l1Messenger.sendL2ToL1Log(true, logData.key, logData.value)).to.be.rejectedWith( - "This method require the caller to be system contract" + await expect(l1Messenger.sendL2ToL1Log(true, logData.key, logData.value)).to.be.revertedWithCustomError( + l1Messenger, + "CallerMustBeSystemContract" ); }); @@ -244,7 +245,10 @@ describe("L1Messenger tests", () => { describe("requestBytecodeL1Publication", async () => { it("should revert when not called by known code storage contract", async () => { const byteCodeHash = ethers.utils.hexlify(randomBytes(32)); - await expect(l1Messenger.requestBytecodeL1Publication(byteCodeHash)).to.be.rejectedWith("Inappropriate caller"); + await expect(l1Messenger.requestBytecodeL1Publication(byteCodeHash)).to.be.revertedWithCustomError( + l1Messenger, + "Unauthorized" + ); }); it("should emit event, called by known code system contract", async () => { diff --git a/system-contracts/test/L2BaseToken.spec.ts b/system-contracts/test/L2BaseToken.spec.ts index 3ef04d590..d73f0444d 100644 --- a/system-contracts/test/L2BaseToken.spec.ts +++ b/system-contracts/test/L2BaseToken.spec.ts @@ -1,6 +1,6 @@ import { expect } from "chai"; import { ethers, network } from "hardhat"; -import type { Wallet } from "zksync-web3"; +import type { Wallet } from "zksync-ethers"; import type { L2BaseToken } from "../typechain"; import { L2BaseTokenFactory } from "../typechain"; import { deployContractOnAddress, getWallets, loadArtifact, provider } from "./shared/utils"; @@ -53,9 +53,9 @@ describe("L2BaseToken tests", () => { it("not called by bootloader", async () => { const amountToMint: BigNumber = ethers.utils.parseEther("10.0"); - await expect(L2BaseToken.connect(wallets[0]).mint(wallets[0].address, amountToMint)).to.be.rejectedWith( - "Callable only by the bootloader" - ); + await expect( + L2BaseToken.connect(wallets[0]).mint(wallets[0].address, amountToMint) + ).to.be.revertedWithCustomError(L2BaseToken, "CallerMustBeBootloader"); }); }); @@ -90,7 +90,7 @@ describe("L2BaseToken tests", () => { await expect( L2BaseToken.connect(bootloaderAccount).transferFromTo(wallets[0].address, wallets[1].address, amountToTransfer) - ).to.be.rejectedWith("Transfer amount exceeds balance"); + ).to.be.revertedWithCustomError(L2BaseToken, "InsufficientFunds"); }); it("no transfer - require special access", async () => { @@ -107,7 +107,7 @@ describe("L2BaseToken tests", () => { wallets[1].address, amountToTransfer ) - ).to.be.rejectedWith("Only system contracts with special access can call this method"); + ).to.be.revertedWithCustomError(L2BaseToken, "Unauthorized"); }); }); diff --git a/system-contracts/test/NonceHolder.spec.ts b/system-contracts/test/NonceHolder.spec.ts new file mode 100644 index 000000000..cbab36d21 --- /dev/null +++ b/system-contracts/test/NonceHolder.spec.ts @@ -0,0 +1,267 @@ +import { expect } from "chai"; +import type { NonceHolder } from "../typechain"; +import { NonceHolderFactory } from "../typechain"; +import { + TEST_DEPLOYER_SYSTEM_CONTRACT_ADDRESS, + TEST_NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS, + TEST_SYSTEM_CONTEXT_CONTRACT_ADDRESS, +} from "./shared/constants"; +import { prepareEnvironment, setResult } from "./shared/mocks"; +import { deployContractOnAddress, getWallets } from "./shared/utils"; +import { ethers, network } from "hardhat"; +import { BigNumber } from "ethers"; + +describe("NonceHolder tests", () => { + const wallet = getWallets()[0]; + let nonceHolder: NonceHolder; + let systemAccount: ethers.Signer; + let deployerAccount: ethers.Signer; + + before(async () => { + await prepareEnvironment(); + await deployContractOnAddress(TEST_NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS, "NonceHolder"); + nonceHolder = NonceHolderFactory.connect(TEST_NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS, wallet); + + // Using a system account to satisfy the `onlySystemCall` modifier. + systemAccount = await ethers.getImpersonatedSigner(TEST_SYSTEM_CONTEXT_CONTRACT_ADDRESS); + deployerAccount = await ethers.getImpersonatedSigner(TEST_DEPLOYER_SYSTEM_CONTRACT_ADDRESS); + }); + + after(async () => { + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [TEST_SYSTEM_CONTEXT_CONTRACT_ADDRESS], + }); + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [TEST_DEPLOYER_SYSTEM_CONTRACT_ADDRESS], + }); + }); + + describe("increaseMinNonce and getters", () => { + it("should increase account minNonce by 1", async () => { + const nonceBefore = await nonceHolder.getMinNonce(systemAccount.address); + const rawNonceBefore = await nonceHolder.getRawNonce(systemAccount.address); + await nonceHolder.connect(systemAccount).increaseMinNonce(1); + const nonceAfter = await nonceHolder.getMinNonce(systemAccount.address); + const rawNonceAfter = await nonceHolder.getRawNonce(systemAccount.address); + + expect(nonceAfter).to.equal(nonceBefore.add(1)); + expect(rawNonceAfter).to.equal(rawNonceBefore.add(1)); + }); + + it("should stay the same", async () => { + const nonceBefore = await nonceHolder.getMinNonce(systemAccount.address); + const rawNonceBefore = await nonceHolder.getRawNonce(systemAccount.address); + await nonceHolder.connect(systemAccount).increaseMinNonce(0); + const nonceAfter = await nonceHolder.getMinNonce(systemAccount.address); + const rawNonceAfter = await nonceHolder.getRawNonce(systemAccount.address); + + expect(nonceBefore).to.equal(nonceAfter); + expect(rawNonceBefore).to.equal(rawNonceAfter); + }); + + it("should increase account minNonce by many", async () => { + const nonceBefore = await nonceHolder.getMinNonce(systemAccount.address); + const rawNonceBefore = await nonceHolder.getRawNonce(systemAccount.address); + await nonceHolder.connect(systemAccount).increaseMinNonce(2 ** 4); + const nonceAfter = await nonceHolder.getMinNonce(systemAccount.address); + const rawNonceAfter = await nonceHolder.getRawNonce(systemAccount.address); + + expect(nonceAfter).to.equal(nonceBefore.add(2 ** 4)); + expect(rawNonceAfter).to.equal(rawNonceBefore.add(2 ** 4)); + }); + + it("should fail with too high", async () => { + const nonceBefore = await nonceHolder.getMinNonce(systemAccount.address); + const rawNonceBefore = await nonceHolder.getRawNonce(systemAccount.address); + + await expect( + nonceHolder.connect(systemAccount).increaseMinNonce(BigNumber.from(2).pow(32).add(1)) + ).to.be.revertedWithCustomError(nonceHolder, "NonceIncreaseError"); + + const nonceAfter = await nonceHolder.getMinNonce(systemAccount.address); + const rawNonceAfter = await nonceHolder.getRawNonce(systemAccount.address); + + expect(nonceAfter).to.equal(nonceBefore); + expect(rawNonceAfter).to.equal(rawNonceBefore); + }); + + it("should revert This method require system call flag", async () => { + await expect(nonceHolder.increaseMinNonce(123)).to.be.revertedWithCustomError( + nonceHolder, + "SystemCallFlagRequired" + ); + }); + }); + + describe("incrementMinNonceIfEquals", async () => { + it("should revert This method require system call flag", async () => { + const expectedNonce = await nonceHolder.getMinNonce(systemAccount.address); + await expect(nonceHolder.incrementMinNonceIfEquals(expectedNonce)).to.be.revertedWithCustomError( + nonceHolder, + "SystemCallFlagRequired" + ); + }); + + it("should revert Incorrect nonce", async () => { + await expect(nonceHolder.connect(systemAccount).incrementMinNonceIfEquals(2222222)).to.be.revertedWithCustomError( + nonceHolder, + "ValueMismatch" + ); + }); + + it("should increment minNonce if equals to expected", async () => { + const expectedNonce = await nonceHolder.getMinNonce(systemAccount.address); + await nonceHolder.connect(systemAccount).incrementMinNonceIfEquals(expectedNonce); + const result = await nonceHolder.getMinNonce(systemAccount.address); + expect(result).to.equal(expectedNonce.add(1)); + }); + }); + + describe("incrementDeploymentNonce", async () => { + it("should revert Only the contract deployer can increment the deployment nonce", async () => { + await expect(nonceHolder.incrementDeploymentNonce(deployerAccount.address)).to.be.revertedWithCustomError( + nonceHolder, + "Unauthorized" + ); + }); + + it("should increment deployment nonce", async () => { + const nonceBefore = await nonceHolder.getDeploymentNonce(wallet.address); + const rawNonceBefore = await nonceHolder.getRawNonce(wallet.address); + await nonceHolder.connect(deployerAccount).incrementDeploymentNonce(wallet.address); + const nonceAfter = await nonceHolder.getDeploymentNonce(wallet.address); + const rawNonceAfter = await nonceHolder.getRawNonce(wallet.address); + + expect(nonceAfter).to.equal(nonceBefore.add(BigNumber.from(1))); + expect(rawNonceAfter).to.equal(rawNonceBefore.add(BigNumber.from(2).pow(128))); + }); + }); + + describe("setValueUnderNonce and getValueUnderNonce", async () => { + it("should revert Nonce value cannot be set to 0", async () => { + const accountInfo = [1, 0]; + const encodedAccountInfo = ethers.utils.defaultAbiCoder.encode(["tuple(uint8, uint8)"], [accountInfo]); + await setResult("ContractDeployer", "getAccountInfo", [systemAccount.address], { + failure: false, + returnData: encodedAccountInfo, + }); + await expect(nonceHolder.connect(systemAccount).setValueUnderNonce(124, 0)).to.be.revertedWithCustomError( + nonceHolder, + "ZeroNonceError" + ); + }); + + it("should revert Previous nonce has not been used", async () => { + const accountInfo = [1, 0]; + const encodedAccountInfo = ethers.utils.defaultAbiCoder.encode(["tuple(uint8, uint8)"], [accountInfo]); + await setResult("ContractDeployer", "getAccountInfo", [systemAccount.address], { + failure: false, + returnData: encodedAccountInfo, + }); + await expect(nonceHolder.connect(systemAccount).setValueUnderNonce(443, 111)).to.be.revertedWithCustomError( + nonceHolder, + "NonceJumpError" + ); + }); + + it("should emit ValueSetUnderNonce event", async () => { + const currentNonce = await nonceHolder.getMinNonce(systemAccount.address); + const valueBefore = await nonceHolder.connect(systemAccount).getValueUnderNonce(currentNonce); + const value = valueBefore.add(42); + + const accountInfo = [1, 0]; + const encodedAccountInfo = ethers.utils.defaultAbiCoder.encode(["tuple(uint8, uint8)"], [accountInfo]); + await setResult("ContractDeployer", "getAccountInfo", [systemAccount.address], { + failure: false, + returnData: encodedAccountInfo, + }); + await expect(nonceHolder.connect(systemAccount).setValueUnderNonce(currentNonce, value)) + .to.emit(nonceHolder, "ValueSetUnderNonce") + .withArgs(systemAccount.address, currentNonce, value); + + const valueAfter = await nonceHolder.connect(systemAccount).getValueUnderNonce(currentNonce); + expect(valueAfter).to.equal(value); + }); + + it("should emit ValueSetUnderNonce event arbitrary ordering", async () => { + const currentNonce = await nonceHolder.getMinNonce(systemAccount.address); + const encodedAccountInfo = ethers.utils.defaultAbiCoder.encode(["tuple(uint8, uint8)"], [[1, 1]]); + await setResult("ContractDeployer", "getAccountInfo", [systemAccount.address], { + failure: false, + returnData: encodedAccountInfo, + }); + + const firstValue = (await nonceHolder.connect(systemAccount).getValueUnderNonce(currentNonce)).add(111); + await expect(nonceHolder.connect(systemAccount).setValueUnderNonce(currentNonce, firstValue)) + .to.emit(nonceHolder, "ValueSetUnderNonce") + .withArgs(systemAccount.address, currentNonce, firstValue); + + const secondValue = (await nonceHolder.connect(systemAccount).getValueUnderNonce(currentNonce.add(2))).add(333); + await expect(nonceHolder.connect(systemAccount).setValueUnderNonce(currentNonce.add(2), secondValue)) + .to.emit(nonceHolder, "ValueSetUnderNonce") + .withArgs(systemAccount.address, currentNonce.add(2), secondValue); + + const thirdValue = (await nonceHolder.connect(systemAccount).getValueUnderNonce(currentNonce.add(1))).add(222); + await expect(nonceHolder.connect(systemAccount).setValueUnderNonce(currentNonce.add(1), thirdValue)) + .to.emit(nonceHolder, "ValueSetUnderNonce") + .withArgs(systemAccount.address, currentNonce.add(1), thirdValue); + + const storedValue = await nonceHolder.connect(systemAccount).getValueUnderNonce(currentNonce); + expect(storedValue).to.equal(firstValue); + const storedValueNext = await nonceHolder.connect(systemAccount).getValueUnderNonce(currentNonce.add(1)); + expect(storedValueNext).to.equal(thirdValue); + const storedAfterNext = await nonceHolder.connect(systemAccount).getValueUnderNonce(currentNonce.add(2)); + expect(storedAfterNext).to.equal(secondValue); + }); + }); + + describe("isNonceUsed", () => { + it("used nonce because it too small", async () => { + const isUsed = await nonceHolder.isNonceUsed(systemAccount.address, 1); + expect(isUsed).to.equal(true); + }); + + it("used nonce because set", async () => { + const currentNonce = await nonceHolder.getMinNonce(systemAccount.address); + const checkedNonce = currentNonce.add(1); + await nonceHolder.connect(systemAccount).setValueUnderNonce(checkedNonce, 5); + + const isUsed = await nonceHolder.isNonceUsed(systemAccount.address, checkedNonce); + expect(isUsed).to.equal(true); + }); + + it("not used nonce", async () => { + const currentNonce = await nonceHolder.getMinNonce(systemAccount.address); + const checkedNonce = currentNonce.add(2137 * 2 ** 10); + + const isUsed = await nonceHolder.isNonceUsed(systemAccount.address, checkedNonce); + expect(isUsed).to.be.false; + }); + }); + + describe("validateNonceUsage", () => { + it("used nonce & should not be used", async () => { + await expect(nonceHolder.validateNonceUsage(systemAccount.address, 1, false)).to.be.revertedWithCustomError( + nonceHolder, + "NonceAlreadyUsed" + ); + }); + + it("used nonce & should be used", async () => { + await nonceHolder.validateNonceUsage(systemAccount.address, 1, true); + }); + + it("not used nonce & should be used", async () => { + await expect(nonceHolder.validateNonceUsage(systemAccount.address, 2 ** 16, true)).to.be.revertedWithCustomError( + nonceHolder, + "NonceNotUsed" + ); + }); + + it("not used nonce & should not be used", async () => { + await nonceHolder.validateNonceUsage(systemAccount.address, 2 ** 16, false); + }); + }); +}); diff --git a/system-contracts/test/PubdataChunkPublisher.spec.ts b/system-contracts/test/PubdataChunkPublisher.spec.ts index 49dd5b05f..8dfbfebf9 100644 --- a/system-contracts/test/PubdataChunkPublisher.spec.ts +++ b/system-contracts/test/PubdataChunkPublisher.spec.ts @@ -1,6 +1,6 @@ import { expect } from "chai"; import { ethers, network } from "hardhat"; -import type { Wallet } from "zksync-web3"; +import type { Wallet } from "zksync-ethers"; import type { PubdataChunkPublisher } from "../typechain"; import { PubdataChunkPublisherFactory } from "../typechain"; import { TEST_L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, TEST_PUBDATA_CHUNK_PUBLISHER_ADDRESS } from "./shared/constants"; @@ -37,14 +37,17 @@ describe("PubdataChunkPublisher tests", () => { describe("chunkAndPublishPubdata", () => { it("non-L1Messenger failed to call", async () => { - await expect(pubdataChunkPublisher.chunkAndPublishPubdata("0x1337")).to.be.revertedWith("Inappropriate caller"); + await expect(pubdataChunkPublisher.chunkAndPublishPubdata("0x1337")).to.be.revertedWithCustomError( + pubdataChunkPublisher, + "Unauthorized" + ); }); it("Too Much Pubdata", async () => { const pubdata = genRandHex(blobSizeInBytes * maxNumberBlobs + 1); await expect( pubdataChunkPublisher.connect(l1MessengerAccount).chunkAndPublishPubdata(pubdata) - ).to.be.revertedWith("pubdata should fit in 6 blobs"); + ).to.be.revertedWithCustomError(pubdataChunkPublisher, "TooMuchPubdata"); }); it("Publish 1 Blob", async () => { diff --git a/system-contracts/test/SystemContext.spec.ts b/system-contracts/test/SystemContext.spec.ts index dd23acaf2..2117c59da 100644 --- a/system-contracts/test/SystemContext.spec.ts +++ b/system-contracts/test/SystemContext.spec.ts @@ -28,7 +28,10 @@ describe("SystemContext tests", () => { describe("setTxOrigin", async () => { it("should revert not called by bootlader", async () => { const txOriginExpected = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; - await expect(systemContext.setTxOrigin(txOriginExpected)).to.be.rejectedWith("Callable only by the bootloader"); + await expect(systemContext.setTxOrigin(txOriginExpected)).to.be.revertedWithCustomError( + systemContext, + "CallerMustBeBootloader" + ); }); it("should set tx.origin", async () => { @@ -44,7 +47,10 @@ describe("SystemContext tests", () => { describe("setGasPrice", async () => { it("should revert not called by bootlader", async () => { const newGasPrice = 4294967295; - await expect(systemContext.setGasPrice(newGasPrice)).to.be.rejectedWith("Callable only by the bootloader"); + await expect(systemContext.setGasPrice(newGasPrice)).to.be.revertedWithCustomError( + systemContext, + "CallerMustBeBootloader" + ); }); it("should set tx.gasprice", async () => { @@ -92,7 +98,7 @@ describe("SystemContext tests", () => { const batchHash = await systemContext.getBatchHash(batchData.batchNumber); await expect( systemContext.setNewBatch(batchHash, batchData.batchTimestamp.add(1), batchData.batchNumber.add(1), 1) - ).to.be.rejectedWith("Callable only by the bootloader"); + ).to.be.revertedWithCustomError(systemContext, "CallerMustBeBootloader"); }); it("should revert timestamp should be incremental", async () => { @@ -159,7 +165,7 @@ describe("SystemContext tests", () => { true, 1 ) - ).to.be.rejectedWith("Callable only by the bootloader"); + ).to.be.revertedWithCustomError(systemContext, "CallerMustBeBootloader"); }); it("should revert The timestamp of the L2 block must be greater than or equal to the timestamp of the current batch", async () => { diff --git a/system-contracts/test/shared/mocks.ts b/system-contracts/test/shared/mocks.ts index 2b8c35654..4dd51671e 100644 --- a/system-contracts/test/shared/mocks.ts +++ b/system-contracts/test/shared/mocks.ts @@ -2,6 +2,7 @@ import { ethers } from "hardhat"; import type { MockContract } from "../../typechain"; import { MockContractFactory } from "../../typechain"; import { + TEST_DEPLOYER_SYSTEM_CONTRACT_ADDRESS, TEST_ACCOUNT_CODE_STORAGE_SYSTEM_CONTRACT_ADDRESS, TEST_BOOTLOADER_FORMAL_ADDRESS, TEST_BASE_TOKEN_SYSTEM_CONTRACT_ADDRESS, @@ -26,6 +27,7 @@ type CallResult = { const TEST_SYSTEM_CONTRACTS_MOCKS = { Compressor: TEST_COMPRESSOR_CONTRACT_ADDRESS, SystemContext: TEST_SYSTEM_CONTEXT_CONTRACT_ADDRESS, + ContractDeployer: TEST_DEPLOYER_SYSTEM_CONTRACT_ADDRESS, NonceHolder: TEST_NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS, L1Messenger: TEST_L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, KnownCodesStorage: TEST_KNOWN_CODE_STORAGE_CONTRACT_ADDRESS, diff --git a/tools/Cargo.lock b/tools/Cargo.lock index 90d7c01b3..da25711f1 100644 --- a/tools/Cargo.lock +++ b/tools/Cargo.lock @@ -3,455 +3,6803 @@ version = 3 [[package]] -name = "ansi_term" -version = "0.12.1" +name = "Inflector" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" dependencies = [ - "winapi", + "lazy_static", + "regex", ] [[package]] -name = "atty" -version = "0.2.14" +name = "addchain" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570" dependencies = [ - "hermit-abi", - "libc", - "winapi", + "num-bigint 0.3.3", + "num-integer", + "num-traits", ] [[package]] -name = "bitflags" -version = "1.3.2" +name = "addr2line" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] [[package]] -name = "block-buffer" -version = "0.10.4" +name = "adler" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] -name = "cfg-if" -version = "1.0.0" +name = "aes" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if 1.0.0", + "cipher", + "cpufeatures", +] [[package]] -name = "clap" -version = "2.34.0" +name = "aho-corasick" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", + "memchr", ] [[package]] -name = "cpufeatures" -version = "0.2.9" +name = "android-tzdata" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] -name = "crypto-common" -version = "0.1.6" +name = "ansi_term" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ - "generic-array", - "typenum", + "winapi", ] [[package]] -name = "digest" -version = "0.10.7" +name = "anstream" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ - "block-buffer", - "crypto-common", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", ] [[package]] -name = "generic-array" -version = "0.14.7" +name = "anstyle" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ - "typenum", - "version_check", + "utf8parse", ] [[package]] -name = "handlebars" -version = "4.4.0" +name = "anstyle-query" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c39b3bc2a8f715298032cf5087e58573809374b08160aa7d750582bdb82d2683" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ - "log", - "pest", - "pest_derive", - "serde", - "serde_json", - "thiserror", + "windows-sys 0.52.0", ] [[package]] -name = "heck" -version = "0.3.3" +name = "anstyle-wincon" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ - "unicode-segmentation", + "anstyle", + "windows-sys 0.52.0", ] [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "anyhow" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" + +[[package]] +name = "arr_macro" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a105bfda48707cf19220129e78fca01e9639433ffaef4163546ed8fb04120a5" dependencies = [ - "libc", + "arr_macro_impl", + "proc-macro-hack", ] [[package]] -name = "itoa" -version = "1.0.9" +name = "arr_macro_impl" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "0609c78bd572f4edc74310dfb63a01f5609d53fa8b4dd7c4d98aef3b3e8d72d1" +dependencies = [ + "proc-macro-hack", + "quote 1.0.33", + "syn 1.0.109", +] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "arrayref" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] -name = "libc" -version = "0.2.148" +name = "arrayvec" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +dependencies = [ + "nodrop", +] [[package]] -name = "log" -version = "0.4.20" +name = "arrayvec" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] -name = "memchr" -version = "2.6.3" +name = "arrayvec" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] -name = "once_cell" -version = "1.18.0" +name = "ascii-canvas" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] [[package]] -name = "pest" -version = "2.7.3" +name = "async-trait" +version = "0.1.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a4d085fd991ac8d5b05a147b437791b4260b76326baf0fc60cf7c9c27ecd33" +checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514" dependencies = [ - "memchr", - "thiserror", - "ucd-trie", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", ] [[package]] -name = "pest_derive" -version = "2.7.3" +name = "async_io_stream" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bee7be22ce7918f641a33f08e3f43388c7656772244e2bbb2477f44cc9021a" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" dependencies = [ - "pest", - "pest_generator", + "futures", + "pharos", + "rustc_version", ] [[package]] -name = "pest_generator" -version = "2.7.3" +name = "atty" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1511785c5e98d79a05e8a6bc34b4ac2168a0e3e92161862030ad84daa223141" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.33", + "hermit-abi 0.1.19", + "libc", + "winapi", ] [[package]] -name = "pest_meta" -version = "2.7.3" +name = "auto_impl" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42f0394d3123e33353ca5e1e89092e533d2cc490389f2bd6131c43c634ebc5f" +checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" dependencies = [ - "once_cell", - "pest", - "sha2", + "proc-macro-error", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 1.0.109", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "auto_impl" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "autocfg" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" dependencies = [ - "proc-macro2", - "quote", - "version_check", + "async-trait", + "axum-core", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", ] [[package]] -name = "proc-macro2" -version = "1.0.67" +name = "axum-core" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" dependencies = [ - "unicode-ident", + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", + "rustversion", + "tower-layer", + "tower-service", ] [[package]] -name = "quote" -version = "1.0.33" +name = "backtrace" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ - "proc-macro2", + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", ] [[package]] -name = "ryu" -version = "1.0.15" +name = "base16ct" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" [[package]] -name = "serde" -version = "1.0.188" +name = "base16ct" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" -dependencies = [ - "serde_derive", -] +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] -name = "serde_derive" -version = "1.0.188" +name = "base58" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.33", -] +checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" [[package]] -name = "serde_json" -version = "1.0.107" +name = "base58check" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "2ee2fe4c9a0c84515f136aaae2466744a721af6d63339c18689d9e995d74d99b" dependencies = [ - "itoa", - "ryu", - "serde", + "base58", + "sha2 0.8.2", ] [[package]] -name = "sha2" -version = "0.10.7" +name = "base64" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" [[package]] -name = "strsim" -version = "0.8.0" +name = "base64" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] -name = "structopt" -version = "0.3.26" +name = "base64" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" -dependencies = [ - "clap", - "lazy_static", - "structopt-derive", -] +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] -name = "structopt-derive" -version = "0.4.18" +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "syn" -version = "1.0.109" +name = "base64ct" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] -name = "syn" -version = "2.0.33" +name = "bech32" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9caece70c63bfba29ec2fed841a09851b14a235c60010fa4de58089b6c025668" +checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" + +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" + +[[package]] +name = "bellman_ce" +version = "0.3.2" +source = "git+https://github.com/matter-labs/bellman?branch=snark-wrapper#e01e5fa08a97a113e76ec8a69d06fe6cc2c82d17" dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "arrayvec 0.7.4", + "bit-vec", + "blake2s_const", + "blake2s_simd", + "byteorder", + "cfg-if 1.0.0", + "crossbeam 0.7.3", + "futures", + "hex", + "lazy_static", + "num_cpus", + "pairing_ce 0.28.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6", + "serde", + "smallvec", + "tiny-keccak 1.5.0", ] [[package]] -name = "textwrap" -version = "0.11.0" +name = "bigdecimal" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +checksum = "a6773ddc0eafc0e509fb60e48dff7f450f8e674a0686ae8605e8d9901bd5eefa" dependencies = [ - "unicode-width", + "num-bigint 0.4.5", + "num-integer", + "num-traits", ] [[package]] -name = "thiserror" -version = "1.0.48" +name = "bincode" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "thiserror-impl", + "serde", ] [[package]] -name = "thiserror-impl" -version = "1.0.48" +name = "bit-set" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.33", + "bit-vec", ] [[package]] -name = "typenum" -version = "1.16.0" +name = "bit-vec" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +dependencies = [ + "serde", +] [[package]] -name = "ucd-trie" -version = "0.1.6" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "unicode-ident" -version = "1.0.12" +name = "bitflags" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] -name = "unicode-segmentation" -version = "1.10.1" +name = "bitvec" +version = "0.17.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +dependencies = [ + "either", + "radium 0.3.0", +] [[package]] -name = "unicode-width" -version = "0.1.10" +name = "bitvec" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium 0.7.0", + "tap", + "wyz", +] [[package]] -name = "vec_map" -version = "0.8.2" +name = "blake2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" +dependencies = [ + "crypto-mac", + "digest 0.9.0", + "opaque-debug 0.3.1", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "git+https://github.com/RustCrypto/hashes.git?rev=1f727ce37ff40fa0cce84eb8543a45bdd3ca4a4e#1f727ce37ff40fa0cce84eb8543a45bdd3ca4a4e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "blake2-rfc_bellman_edition" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc60350286c7c3db13b98e91dbe5c8b6830a6821bc20af5b0c310ce94d74915" +dependencies = [ + "arrayvec 0.4.12", + "byteorder", + "constant_time_eq", +] + +[[package]] +name = "blake2s_const" +version = "0.6.0" +source = "git+https://github.com/matter-labs/bellman?branch=snark-wrapper#e01e5fa08a97a113e76ec8a69d06fe6cc2c82d17" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "constant_time_eq", +] + +[[package]] +name = "blake2s_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding 0.1.5", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding 0.2.1", + "generic-array 0.14.7", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "boojum" +version = "0.2.0" +source = "git+https://github.com/matter-labs/era-boojum.git?branch=main#19988079852ea22576da6b09e39365e6cdc1368f" +dependencies = [ + "arrayvec 0.7.4", + "bincode", + "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", + "const_format", + "convert_case 0.6.0", + "crossbeam 0.8.4", + "crypto-bigint 0.5.5", + "cs_derive", + "derivative", + "ethereum-types", + "firestorm", + "itertools 0.10.5", + "lazy_static", + "num-modular", + "num_cpus", + "packed_simd", + "pairing_ce 0.28.5 (git+https://github.com/matter-labs/pairing.git)", + "rand 0.8.5", + "rayon", + "serde", + "sha2 0.10.8", + "sha3 0.10.6", + "smallvec", + "unroll", +] + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +dependencies = [ + "serde", +] + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.5", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "circuit_definitions" +version = "0.1.0" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#39665dffd576cff5007c80dd0e1b5334e230bd3b" +dependencies = [ + "circuit_encodings 0.1.40", + "crossbeam 0.8.4", + "derivative", + "seq-macro", + "serde", + "snark_wrapper", + "zk_evm 1.4.0", + "zkevm_circuits 1.4.0", +] + +[[package]] +name = "circuit_definitions" +version = "1.5.0" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.5.0#394e1c7d1aec06d2f3abd63bdc2ddf0efef5ac49" +dependencies = [ + "circuit_encodings 0.1.50", + "crossbeam 0.8.4", + "derivative", + "seq-macro", + "serde", + "snark_wrapper", +] + +[[package]] +name = "circuit_encodings" +version = "0.1.40" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#39665dffd576cff5007c80dd0e1b5334e230bd3b" +dependencies = [ + "derivative", + "serde", + "zk_evm 1.4.0", + "zkevm_circuits 1.4.0", +] + +[[package]] +name = "circuit_encodings" +version = "0.1.50" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.5.0#394e1c7d1aec06d2f3abd63bdc2ddf0efef5ac49" +dependencies = [ + "derivative", + "serde", + "zk_evm 1.5.0", + "zkevm_circuits 1.5.0", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim 0.8.0", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.1", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck 0.5.0", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "codegen" +version = "0.1.0" +source = "git+https://github.com/matter-labs/solidity_plonk_verifier.git?branch=snark_wrapper#5fb698f5118990bf53648bfd7027363bc4b03ff2" +dependencies = [ + "ethereum-types", + "franklin-crypto", + "handlebars", + "hex", + "paste", + "rescue_poseidon", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "coins-bip32" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634c509653de24b439672164bbf56f5f582a2ab0e313d3b0f6af0b7345cf2560" +dependencies = [ + "bincode", + "bs58", + "coins-core", + "digest 0.10.7", + "getrandom", + "hmac", + "k256 0.11.6", + "lazy_static", + "serde", + "sha2 0.10.8", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a11892bcac83b4c6e95ab84b5b06c76d9d70ad73548dd07418269c5c7977171" +dependencies = [ + "bitvec 0.17.4", + "coins-bip32", + "getrandom", + "hex", + "hmac", + "pbkdf2", + "rand 0.8.5", + "sha2 0.10.8", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94090a6663f224feae66ab01e41a2555a8296ee07b5f20dab8888bdefc9f617" +dependencies = [ + "base58check", + "base64 0.12.3", + "bech32", + "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.10.7", + "generic-array 0.14.7", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2 0.10.8", + "sha3 0.10.8", + "thiserror", +] + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + +[[package]] +name = "compile-fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bed69047ed42e52c7e38d6421eeb8ceefb4f2a2b52eed59137f7bad7908f6800" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const_format" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "unicode-xid 0.2.4", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "crossbeam" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" +dependencies = [ + "cfg-if 0.1.10", + "crossbeam-channel 0.4.4", + "crossbeam-deque 0.7.4", + "crossbeam-epoch 0.8.2", + "crossbeam-queue 0.2.3", + "crossbeam-utils 0.7.2", +] + +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel 0.5.12", + "crossbeam-deque 0.8.5", + "crossbeam-epoch 0.9.18", + "crossbeam-queue 0.3.11", + "crossbeam-utils 0.8.19", +] + +[[package]] +name = "crossbeam-channel" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" +dependencies = [ + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +dependencies = [ + "crossbeam-utils 0.8.19", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" +dependencies = [ + "crossbeam-epoch 0.8.2", + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch 0.9.18", + "crossbeam-utils 0.8.19", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +dependencies = [ + "autocfg", + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils 0.8.19", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +dependencies = [ + "cfg-if 0.1.10", + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils 0.8.19", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if 0.1.10", + "lazy_static", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto" +version = "0.1.0" +source = "git+https://github.com/matter-labs/era-boojum-validator-cli?branch=main#1661eef7b235fc10e92208fb738c9e261f58c653" +dependencies = [ + "anyhow", + "bincode", + "circuit_definitions 0.1.0", + "clap 4.5.4", + "codegen", + "colored", + "ethers", + "hex", + "once_cell", + "primitive-types", + "reqwest", + "serde", + "serde_json", + "sha3 0.9.1", + "tokio", + "zksync_types", +] + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array 0.14.7", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array 0.14.7", + "subtle", +] + +[[package]] +name = "cs_derive" +version = "0.1.0" +source = "git+https://github.com/matter-labs/era-boojum.git?branch=main#19988079852ea22576da6b09e39365e6cdc1368f" +dependencies = [ + "proc-macro-error", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "serde", + "uuid 1.8.0", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2 1.0.82", + "quote 1.0.33", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "1.0.0-beta.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7abbfc297053be59290e3152f8cbcd52c8642e0728b69ee187d991d4c1af08d" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0-beta.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bba3e9872d7c58ce7ef0fcf1844fcc3e23ef2a58377b50df35dd98e42a5726e" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", + "unicode-xid 0.2.4", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der 0.6.1", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", + "signature 1.6.4", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der 0.7.9", + "digest 0.10.7", + "elliptic-curve 0.13.8", + "rfc6979 0.4.0", + "signature 2.2.0", + "spki 0.7.3", +] + +[[package]] +name = "either" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct 0.1.1", + "crypto-bigint 0.4.9", + "der 0.6.1", + "digest 0.10.7", + "ff 0.12.1", + "generic-array 0.14.7", + "group 0.12.1", + "pkcs8 0.9.0", + "rand_core 0.6.4", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.5", + "digest 0.10.7", + "ff 0.13.0", + "generic-array 0.14.7", + "group 0.13.0", + "pem-rfc7468", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "sec1 0.7.3", + "subtle", + "zeroize", +] + +[[package]] +name = "elsa" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98e71ae4df57d214182a2e5cb90230c0192c6ddfcaa05c36453d46a54713e10" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "ena" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" +dependencies = [ + "log", +] + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "envy" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f47e0157f2cb54f5ae1bd371b30a2ae4311e1c028f575cd4e81de7353215965" +dependencies = [ + "serde", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac", + "pbkdf2", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "thiserror", + "uuid 0.8.2", +] + +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3 0.10.8", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak 2.0.2", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types", + "scale-info", + "uint", +] + +[[package]] +name = "ethers" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f26f9d8d80da18ca72aca51804c65eb2153093af3bec74fd5ce32aa0c1f665" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-middleware", + "ethers-providers", + "ethers-signers", + "ethers-solc", +] + +[[package]] +name = "ethers-addressbook" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4be54dd2260945d784e06ccdeb5ad573e8f1541838cee13a1ab885485eaa0b" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c3c3e119a89f0a9a1e539e7faecea815f74ddcf7c90d0b00d1f524db2fdc9c" +dependencies = [ + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "hex", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4e5ad46aede34901f71afdb7bb555710ed9613d88d644245c657dc371aa228" +dependencies = [ + "Inflector", + "cfg-if 1.0.0", + "dunce", + "ethers-core", + "eyre", + "getrandom", + "hex", + "proc-macro2 1.0.82", + "quote 1.0.33", + "regex", + "reqwest", + "serde", + "serde_json", + "syn 1.0.109", + "toml", + "url", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f192e8e4cf2b038318aae01e94e7644e0659a76219e94bcd3203df744341d61f" +dependencies = [ + "ethers-contract-abigen", + "ethers-core", + "hex", + "proc-macro2 1.0.82", + "quote 1.0.33", + "serde_json", + "syn 1.0.109", +] + +[[package]] +name = "ethers-core" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade3e9c97727343984e1ceada4fdab11142d2ee3472d2c67027d56b1251d4f15" +dependencies = [ + "arrayvec 0.7.4", + "bytes", + "cargo_metadata", + "chrono", + "convert_case 0.6.0", + "elliptic-curve 0.12.3", + "ethabi", + "generic-array 0.14.7", + "hex", + "k256 0.11.6", + "once_cell", + "open-fastrlp", + "proc-macro2 1.0.82", + "rand 0.8.5", + "rlp", + "rlp-derive", + "serde", + "serde_json", + "strum", + "syn 1.0.109", + "thiserror", + "tiny-keccak 2.0.2", + "unicode-xid 0.2.4", +] + +[[package]] +name = "ethers-etherscan" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9713f525348e5dde025d09b0a4217429f8074e8ff22c886263cc191e87d8216" +dependencies = [ + "ethers-core", + "getrandom", + "reqwest", + "semver", + "serde", + "serde-aux", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-middleware" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e71df7391b0a9a51208ffb5c7f2d068900e99d6b3128d3a4849d138f194778b7" +dependencies = [ + "async-trait", + "auto_impl 0.5.0", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-providers", + "ethers-signers", + "futures-locks", + "futures-util", + "instant", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a9e0597aa6b2fdc810ff58bc95e4eeaa2c219b3e615ed025106ecb027407d8" +dependencies = [ + "async-trait", + "auto_impl 1.2.0", + "base64 0.13.1", + "ethers-core", + "futures-channel", + "futures-core", + "futures-timer", + "futures-util", + "getrandom", + "hashers", + "hex", + "http", + "once_cell", + "parking_lot 0.11.2", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-tungstenite", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-timer", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f41ced186867f64773db2e55ffdd92959e094072a1d09a5e5e831d443204f98" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "elliptic-curve 0.12.3", + "eth-keystore", + "ethers-core", + "hex", + "rand 0.8.5", + "sha2 0.10.8", + "thiserror", +] + +[[package]] +name = "ethers-solc" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbe9c0a6d296c57191e5f8a613a3b5e816812c28f4a28d6178a17c21db903d77" +dependencies = [ + "cfg-if 1.0.0", + "dunce", + "ethers-core", + "getrandom", + "glob", + "hex", + "home", + "md-5", + "num_cpus", + "once_cell", + "path-slash", + "rayon", + "regex", + "semver", + "serde", + "serde_json", + "solang-parser", + "svm-rs", + "thiserror", + "tiny-keccak 2.0.2", + "tokio", + "tracing", + "walkdir", + "yansi", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "ff_ce" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b538e4231443a5b9c507caee3356f016d832cf7393d2d90f03ea3180d4e3fbc" +dependencies = [ + "byteorder", + "ff_derive_ce", + "hex", + "rand 0.4.6", + "serde", +] + +[[package]] +name = "ff_derive_ce" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b96fbccd88dbb1fac4ee4a07c2fcc4ca719a74ffbd9d2b9d41d8c8eb073d8b20" +dependencies = [ + "num-bigint 0.4.5", + "num-integer", + "num-traits", + "proc-macro2 1.0.82", + "quote 1.0.33", + "serde", + "syn 1.0.109", +] + +[[package]] +name = "findshlibs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" +dependencies = [ + "cc", + "lazy_static", + "libc", + "winapi", +] + +[[package]] +name = "firestorm" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c5f6c2c942da57e2aaaa84b8a521489486f14e75e7fa91dab70aba913975f98" + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "franklin-crypto" +version = "0.0.5" +source = "git+https://github.com/matter-labs/franklin-crypto?branch=snark_wrapper#2546c63b91b59bdb0ad342d26f03fb57477550b2" +dependencies = [ + "arr_macro", + "bellman_ce", + "bit-vec", + "blake2 0.9.2", + "blake2-rfc_bellman_edition", + "blake2s_simd", + "boojum", + "byteorder", + "derivative", + "digest 0.9.0", + "hex", + "indexmap 1.9.3", + "itertools 0.10.5", + "lazy_static", + "num-bigint 0.4.5", + "num-derive", + "num-integer", + "num-traits", + "rand 0.4.6", + "serde", + "sha2 0.9.9", + "sha3 0.9.1", + "smallvec", + "splitmut", + "tiny-keccak 1.5.0", +] + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff 0.12.1", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.2.6", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "handlebars" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39b3bc2a8f715298032cf5087e58573809374b08160aa7d750582bdb82d2683" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64 0.21.7", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonrpc-core" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" +dependencies = [ + "futures", + "futures-executor", + "futures-util", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "k256" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.8", + "sha3 0.10.8", +] + +[[package]] +name = "k256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "once_cell", + "sha2 0.10.8", + "signature 2.2.0", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lalrpop" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a1cbf952127589f2851ab2046af368fd20645491bb4b376f04b7f94d7a9837b" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools 0.10.5", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax 0.6.29", + "string_cache", + "term", + "tiny-keccak 2.0.2", + "unicode-xid 0.2.4", +] + +[[package]] +name = "lalrpop-util" +version = "0.19.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3c48237b9604c5a4702de6b824e02006c3214327564636aef27c1028a8fa0ed" +dependencies = [ + "regex", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.5.0", + "libc", +] + +[[package]] +name = "linkme" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3ae8aae8e1d516e0a3ceee1219eded7f73741607e4227bf11ef2c3e31580427" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad083d767be37e709a232ae2a244445ed032bb9c6bf7d9442dd416ba5a7b7264" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "logos" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1" +dependencies = [ + "logos-derive", +] + +[[package]] +name = "logos-codegen" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" +dependencies = [ + "beef", + "fnv", + "proc-macro2 1.0.82", + "quote 1.0.33", + "regex-syntax 0.6.29", + "syn 2.0.33", +] + +[[package]] +name = "logos-derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e" +dependencies = [ + "logos-codegen", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if 1.0.0", + "digest 0.10.7", +] + +[[package]] +name = "memchr" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" + +[[package]] +name = "memoffset" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miette" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" +dependencies = [ + "miette-derive", + "once_cell", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3135b08af27d103b0a51f2ae0f8632117b7b185ccf931445affa8df530576a41" +dependencies = [ + "num-bigint 0.4.5", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6f7833f2cbf2360a6cfd58cd41a53aa7a90bd4c202f5b1c7dd2ed73c57b2c3" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +dependencies = [ + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-complex" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +dependencies = [ + "num-traits", + "serde", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-modular" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint 0.4.5", + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive 0.6.1", +] + +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive 0.7.2", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec 0.7.4", + "auto_impl 1.2.0", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "openssl" +version = "0.10.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +dependencies = [ + "bitflags 2.5.0", + "cfg-if 1.0.0", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "opentelemetry" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9591d937bc0e6d2feb6f71a559540ab300ea49955229c347a517a28d27784c54" +dependencies = [ + "opentelemetry_api", + "opentelemetry_sdk", +] + +[[package]] +name = "opentelemetry-http" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7594ec0e11d8e33faf03530a4c49af7064ebba81c1480e01be67d90b356508b" +dependencies = [ + "async-trait", + "bytes", + "http", + "opentelemetry_api", + "reqwest", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e5e5a5c4135864099f3faafbe939eb4d7f9b80ebf68a8448da961b32a7c1275" +dependencies = [ + "async-trait", + "futures-core", + "http", + "opentelemetry-http", + "opentelemetry-proto", + "opentelemetry-semantic-conventions", + "opentelemetry_api", + "opentelemetry_sdk", + "prost 0.11.9", + "reqwest", + "thiserror", + "tokio", + "tonic", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e3f814aa9f8c905d0ee4bde026afd3b2577a97c10e1699912e3e44f0c4cbeb" +dependencies = [ + "opentelemetry_api", + "opentelemetry_sdk", + "prost 0.11.9", + "tonic", +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73c9f9340ad135068800e7f1b24e9e09ed9e7143f5bf8518ded3d3ec69789269" +dependencies = [ + "opentelemetry", +] + +[[package]] +name = "opentelemetry_api" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a81f725323db1b1206ca3da8bb19874bbd3f57c3bcd59471bfb04525b265b9b" +dependencies = [ + "futures-channel", + "futures-util", + "indexmap 1.9.3", + "js-sys", + "once_cell", + "pin-project-lite", + "thiserror", + "urlencoding", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa8e705a0612d48139799fcbaba0d4a90f06277153e43dd2bdc16c6f0edd8026" +dependencies = [ + "async-trait", + "crossbeam-channel 0.5.12", + "futures-channel", + "futures-executor", + "futures-util", + "once_cell", + "opentelemetry_api", + "ordered-float 3.9.2", + "percent-encoding", + "rand 0.8.5", + "regex", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", +] + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ordered-float" +version = "3.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc" +dependencies = [ + "num-traits", +] + +[[package]] +name = "os_info" +version = "3.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" +dependencies = [ + "log", + "serde", + "windows-sys 0.52.0", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder", + "sha2 0.10.8", +] + +[[package]] +name = "packed_simd" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f9f08af0c877571712e2e3e686ad79efad9657dbf0f7c3c8ba943ff6c38932d" +dependencies = [ + "cfg-if 1.0.0", + "num-traits", +] + +[[package]] +name = "pairing_ce" +version = "0.28.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db007b21259660d025918e653508f03050bf23fb96a88601f9936329faadc597" +dependencies = [ + "byteorder", + "cfg-if 1.0.0", + "ff_ce", + "rand 0.4.6", + "serde", +] + +[[package]] +name = "pairing_ce" +version = "0.28.5" +source = "git+https://github.com/matter-labs/pairing.git#d24f2c5871089c4cd4f54c0ca266bb9fef6115eb" +dependencies = [ + "byteorder", + "cfg-if 1.0.0", + "ff_ce", + "rand 0.4.6", + "serde", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe" +dependencies = [ + "arrayvec 0.7.4", + "bitvec 1.0.1", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b" +dependencies = [ + "proc-macro-crate 2.0.0", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall 0.5.1", + "smallvec", + "windows-targets 0.52.5", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", + "hmac", + "password-hash", + "sha2 0.10.8", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a4d085fd991ac8d5b05a147b437791b4260b76326baf0fc60cf7c9c27ecd33" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bee7be22ce7918f641a33f08e3f43388c7656772244e2bbb2477f44cc9021a" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1511785c5e98d79a05e8a6bc34b4ac2168a0e3e92161862030ad84daa223141" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "pest_meta" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42f0394d3123e33353ca5e1e89092e533d2cc490389f2bd6131c43c634ebc5f" +dependencies = [ + "once_cell", + "pest", + "sha2 0.10.8", +] + +[[package]] +name = "petgraph" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" +dependencies = [ + "fixedbitset", + "indexmap 2.2.6", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_macros", + "phf_shared", + "proc-macro-hack", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro-hack", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der 0.6.1", + "spki 0.6.0", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der 0.7.9", + "spki 0.7.3", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "prettyplease" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +dependencies = [ + "proc-macro2 1.0.82", + "syn 2.0.33", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve 0.13.8", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", +] + +[[package]] +name = "proc-macro2" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prometheus-client" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ca959da22a332509f2a73ae9e5f23f9dcfc31fd3a54d71f159495bd5909baa" +dependencies = [ + "dtoa", + "itoa", + "parking_lot 0.12.2", + "prometheus-client-derive-encode", +] + +[[package]] +name = "prometheus-client-derive-encode" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "prost" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +dependencies = [ + "bytes", + "prost-derive 0.11.9", +] + +[[package]] +name = "prost" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f5d036824e4761737860779c906171497f6d55681139d8312388f8fe398922" +dependencies = [ + "bytes", + "prost-derive 0.12.4", +] + +[[package]] +name = "prost-build" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" +dependencies = [ + "bytes", + "heck 0.4.1", + "itertools 0.12.1", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost 0.12.4", + "prost-types", + "regex", + "syn 2.0.33", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "prost-derive" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19de2de2a00075bf566bee3bd4db014b11587e84184d3f7a791bc17f1a8e9e48" +dependencies = [ + "anyhow", + "itertools 0.12.1", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "prost-reflect" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057237efdb71cf4b3f9396302a3d6599a92fa94063ba537b66130980ea9909f3" +dependencies = [ + "base64 0.21.7", + "logos", + "miette", + "once_cell", + "prost 0.12.4", + "prost-types", + "serde", + "serde-value", +] + +[[package]] +name = "prost-types" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" +dependencies = [ + "prost 0.12.4", +] + +[[package]] +name = "protox" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00bb76c5f6221de491fe2c8f39b106330bbd9762c6511119c07940e10eb9ff11" +dependencies = [ + "bytes", + "miette", + "prost 0.12.4", + "prost-reflect", + "prost-types", + "protox-parse", + "thiserror", +] + +[[package]] +name = "protox-parse" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4581f441c58863525a3e6bec7b8de98188cf75239a56c725a3e7288450a33f" +dependencies = [ + "logos", + "miette", + "prost-types", + "thiserror", +] + +[[package]] +name = "quick-protobuf" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" +dependencies = [ + "byteorder", +] + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2 1.0.82", +] + +[[package]] +name = "radium" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque 0.8.5", + "crossbeam-utils 0.8.19", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.6", + "regex-syntax 0.8.3", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.3", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.12", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-rustls 0.24.1", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.25.4", + "winreg", +] + +[[package]] +name = "rescue_poseidon" +version = "0.4.1" +source = "git+https://github.com/matter-labs/rescue-poseidon?branch=poseidon2#126937ef0e7a281f1ff9f512ac41a746a691a342" +dependencies = [ + "addchain", + "arrayvec 0.7.4", + "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "derivative", + "franklin-crypto", + "lazy_static", + "log", + "num-bigint 0.3.3", + "num-integer", + "num-iter", + "num-traits", + "rand 0.4.6", + "serde", + "sha3 0.9.1", + "smallvec", + "typemap_rev", +] + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint 0.4.9", + "hmac", + "zeroize", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if 1.0.0", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.5.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" +dependencies = [ + "log", + "ring 0.16.20", + "sct", + "webpki", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring 0.17.8", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + +[[package]] +name = "rustversion" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scale-info" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c453e59a955f81fb62ee5d596b450383d699f152d350e9d23a0db2adb78e4c0" +dependencies = [ + "cfg-if 1.0.0", + "derive_more 0.99.17", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18cf6c6447f813ef19eb450e985bcce6705f9ce7660db221b59093d15c79c4b7" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2", + "salsa20", + "sha2 0.10.8", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct 0.1.1", + "der 0.6.1", + "generic-array 0.14.7", + "pkcs8 0.9.0", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.9", + "generic-array 0.14.7", + "pkcs8 0.10.2", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags 2.5.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +dependencies = [ + "serde", +] + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "sentry" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce4b57f1b521f674df7a1d200be8ff5d74e3712020ee25b553146657b5377d5" +dependencies = [ + "httpdate", + "native-tls", + "reqwest", + "sentry-backtrace", + "sentry-contexts", + "sentry-core", + "sentry-debug-images", + "sentry-panic", + "sentry-tracing", + "tokio", + "ureq", +] + +[[package]] +name = "sentry-backtrace" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58cc8d4e04a73de8f718dc703943666d03f25d3e9e4d0fb271ca0b8c76dfa00e" +dependencies = [ + "backtrace", + "once_cell", + "regex", + "sentry-core", +] + +[[package]] +name = "sentry-contexts" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6436c1bad22cdeb02179ea8ef116ffc217797c028927def303bc593d9320c0d1" +dependencies = [ + "hostname", + "libc", + "os_info", + "rustc_version", + "sentry-core", + "uname", +] + +[[package]] +name = "sentry-core" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901f761681f97db3db836ef9e094acdd8756c40215326c194201941947164ef1" +dependencies = [ + "once_cell", + "rand 0.8.5", + "sentry-types", + "serde", + "serde_json", +] + +[[package]] +name = "sentry-debug-images" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afdb263e73d22f39946f6022ed455b7561b22ff5553aca9be3c6a047fa39c328" +dependencies = [ + "findshlibs", + "once_cell", + "sentry-core", +] + +[[package]] +name = "sentry-panic" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74fbf1c163f8b6a9d05912e1b272afa27c652e8b47ea60cb9a57ad5e481eea99" +dependencies = [ + "sentry-backtrace", + "sentry-core", +] + +[[package]] +name = "sentry-tracing" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82eabcab0a047040befd44599a1da73d3adb228ff53b5ed9795ae04535577704" +dependencies = [ + "sentry-backtrace", + "sentry-core", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "sentry-types" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da956cca56e0101998c8688bc65ce1a96f00673a0e58e663664023d4c7911e82" +dependencies = [ + "debugid", + "hex", + "rand 0.8.5", + "serde", + "serde_json", + "thiserror", + "time", + "url", + "uuid 1.8.0", +] + +[[package]] +name = "seq-macro" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-aux" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d2e8bfba469d06512e11e3311d4d051a4a387a5b42d010404fecf3200321c95" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float 2.10.1", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "serde_json" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15e0ef66bf939a7c890a0bf6d5a733c70202225f9888a89ed5c62298b019129" +dependencies = [ + "indexmap 2.2.6", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.1", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.1", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "git+https://github.com/RustCrypto/hashes.git?rev=1731ced4a116d61ba9dc6ee6d0f38fb8102e357a#1731ced4a116d61ba9dc6ee6d0f38fb8102e357a" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug 0.3.1", +] + +[[package]] +name = "sha3" +version = "0.10.6" +source = "git+https://github.com/RustCrypto/hashes.git?rev=7a187e934c1f6c68e4b4e5cf37541b7a0d64d303#7a187e934c1f6c68e4b4e5cf37541b7a0d64d303" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] + +[[package]] +name = "snark_wrapper" +version = "0.1.0" +source = "git+https://github.com/matter-labs/snark-wrapper.git?branch=main#76959cadabeec344b9fa1458728400d60340e496" +dependencies = [ + "derivative", + "rand 0.4.6", + "rescue_poseidon", +] + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "soketto" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" +dependencies = [ + "base64 0.13.1", + "bytes", + "futures", + "httparse", + "log", + "rand 0.8.5", + "sha-1 0.9.8", +] + +[[package]] +name = "solang-parser" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac8ac4bfef383f368bd9bb045107a501cd9cd0b64ad1983e1b7e839d6a44ecad" +dependencies = [ + "itertools 0.10.5", + "lalrpop", + "lalrpop-util", + "phf", + "unicode-xid 0.2.4", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der 0.6.1", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der 0.7.9", +] + +[[package]] +name = "splitmut" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85070f382340e8b23a75808e83573ddf65f9ad9143df9573ca37c1ed2ee956a" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot 0.12.2", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "structopt" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +dependencies = [ + "clap 2.34.0", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck 0.3.3", + "proc-macro-error", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2 1.0.82", + "quote 1.0.33", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "svm-rs" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a04fc4f5cd35c700153b233f5575ccb3237e0f941fa5049d9e98254d10bf2fe" +dependencies = [ + "fs2", + "hex", + "home", + "once_cell", + "reqwest", + "semver", + "serde", + "serde_json", + "sha2 0.10.8", + "thiserror", + "url", + "zip", +] + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9caece70c63bfba29ec2fed841a09851b14a235c60010fa4de58089b6c025668" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if 1.0.0", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e3de26b0965292219b4287ff031fcba86837900fe9cd2b34ea8ad893c0953d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8a021c69bb74a44ccedb824a046447e2c84a01df9e5c20779750acb38e11b2" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot 0.12.2", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls 0.20.9", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" +dependencies = [ + "futures-util", + "log", + "rustls 0.20.9", + "tokio", + "tokio-rustls 0.23.4", + "tungstenite", + "webpki", + "webpki-roots 0.22.6", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tonic" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" +dependencies = [ + "async-trait", + "axum", + "base64 0.21.7", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost 0.11.9", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "tracing-log" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-opentelemetry" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75327c6b667828ddc28f5e3f169036cb793c3f588d83bf0f262a7f062ffed3c8" +dependencies = [ + "once_cell", + "opentelemetry", + "opentelemetry_sdk", + "smallvec", + "tracing", + "tracing-core", + "tracing-log 0.1.4", + "tracing-subscriber", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "time", + "tracing", + "tracing-core", + "tracing-log 0.2.0", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" +dependencies = [ + "base64 0.13.1", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "rand 0.8.5", + "rustls 0.20.9", + "sha-1 0.10.1", + "thiserror", + "url", + "utf-8", + "webpki", +] + +[[package]] +name = "typemap_rev" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74b08b0c1257381af16a5c3605254d529d3e7e109f3c62befc5d168968192998" + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "uname" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8" +dependencies = [ + "libc", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "unroll" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad948c1cb799b1a70f836077721a92a35ac177d4daddf4c20a633786d4cf618" +dependencies = [ + "quote 1.0.33", + "syn 1.0.109", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd" +dependencies = [ + "base64 0.22.1", + "log", + "native-tls", + "once_cell", + "url", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna 0.5.0", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "uuid" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +dependencies = [ + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vise" +version = "0.1.0" +source = "git+https://github.com/matter-labs/vise.git?rev=a5bb80c9ce7168663114ee30e794d6dc32159ee4#a5bb80c9ce7168663114ee30e794d6dc32159ee4" +dependencies = [ + "compile-fmt", + "elsa", + "linkme", + "once_cell", + "prometheus-client", + "vise-macros", +] + +[[package]] +name = "vise-macros" +version = "0.1.0" +source = "git+https://github.com/matter-labs/vise.git?rev=a5bb80c9ce7168663114ee30e794d6dc32159ee4#a5bb80c9ce7168663114ee30e794d6dc32159ee4" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "vlog" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zksync-era.git?branch=main#29a4ffc6b9420590f32a9e1d1585ebffb95eeb6c" +dependencies = [ + "chrono", + "opentelemetry", + "opentelemetry-otlp", + "opentelemetry-semantic-conventions", + "sentry", + "serde_json", + "tracing", + "tracing-opentelemetry", + "tracing-subscriber", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote 1.0.33", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2 1.0.82", + "quote 1.0.33", + "syn 2.0.33", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web3" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5388522c899d1e1c96a4c307e3797e0f697ba7c77dd8e0e625ecba9dd0342937" +dependencies = [ + "arrayvec 0.7.4", + "base64 0.21.7", + "bytes", + "derive_more 0.99.17", + "ethabi", + "ethereum-types", + "futures", + "futures-timer", + "headers", + "hex", + "idna 0.4.0", + "jsonrpc-core", + "log", + "once_cell", + "parking_lot 0.12.2", + "pin-project", + "reqwest", + "rlp", + "secp256k1", + "serde", + "serde_json", + "soketto", + "tiny-keccak 2.0.2", + "tokio", + "tokio-stream", + "tokio-util", + "url", + "web3-async-native-tls", +] + +[[package]] +name = "web3-async-native-tls" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f6d8d1636b2627fe63518d5a9b38a569405d9c9bc665c43c9c341de57227ebb" +dependencies = [ + "native-tls", + "thiserror", + "tokio", + "url", +] + +[[package]] +name = "webpki" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] [[package]] -name = "winapi" -version = "0.3.9" +name = "windows-targets" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "windows_aarch64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows_aarch64_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if 1.0.0", + "windows-sys 0.48.0", +] + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version", + "send_wrapper", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils 0.8.19", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zk_evm" +version = "1.3.3" +source = "git+https://github.com/matter-labs/era-zk_evm.git?tag=v1.3.3-rc2#fbee20f5bac7d6ca3e22ae69b2077c510a07de4e" +dependencies = [ + "anyhow", + "lazy_static", + "num", + "serde", + "serde_json", + "static_assertions", + "zk_evm_abstractions 0.1.0", + "zkevm_opcode_defs 1.3.2", +] + +[[package]] +name = "zk_evm" +version = "1.4.0" +source = "git+https://github.com/matter-labs/era-zk_evm.git?branch=v1.4.0#dd76fc5badf2c05278a21b38015a7798fe2fe358" +dependencies = [ + "anyhow", + "lazy_static", + "num", + "serde", + "serde_json", + "static_assertions", + "zk_evm_abstractions 0.1.0", + "zkevm_opcode_defs 1.3.2", +] + +[[package]] +name = "zk_evm" +version = "1.5.0" +source = "git+https://github.com/matter-labs/era-zk_evm.git?branch=v1.5.0#6119ce908ab714f2f99804794e725b97298a6b11" +dependencies = [ + "anyhow", + "lazy_static", + "num", + "serde", + "serde_json", + "static_assertions", + "zk_evm_abstractions 1.5.0", +] + +[[package]] +name = "zk_evm_abstractions" +version = "0.1.0" +source = "git+https://github.com/matter-labs/era-zk_evm_abstractions.git#32dd320953841aa78579d9da08abbc70bcaed175" +dependencies = [ + "anyhow", + "num_enum 0.6.1", + "serde", + "static_assertions", + "zkevm_opcode_defs 1.3.2", +] + +[[package]] +name = "zk_evm_abstractions" +version = "1.5.0" +source = "git+https://github.com/matter-labs/era-zk_evm_abstractions.git?branch=v1.5.0#e464b2cf2b146d883be80e7d690c752bf670ff05" +dependencies = [ + "anyhow", + "num_enum 0.6.1", + "serde", + "static_assertions", + "zkevm_opcode_defs 1.5.0", +] + +[[package]] +name = "zkevm_circuits" +version = "1.4.0" +source = "git+https://github.com/matter-labs/era-zkevm_circuits.git?branch=v1.4.0#fb3e2574b5c890342518fc930c145443f039a105" +dependencies = [ + "arrayvec 0.7.4", + "bincode", + "boojum", + "cs_derive", + "derivative", + "hex", + "itertools 0.10.5", + "rand 0.4.6", + "rand 0.8.5", + "seq-macro", + "serde", + "serde_json", + "smallvec", + "zkevm_opcode_defs 1.3.2", +] + +[[package]] +name = "zkevm_circuits" +version = "1.5.0" +source = "git+https://github.com/matter-labs/era-zkevm_circuits.git?branch=v1.5.0#861f81029bf3a916dae55afa5bd7f82b2eaca98b" +dependencies = [ + "arrayvec 0.7.4", + "boojum", + "cs_derive", + "derivative", + "hex", + "itertools 0.10.5", + "rand 0.4.6", + "rand 0.8.5", + "seq-macro", + "serde", + "smallvec", + "zkevm_opcode_defs 1.5.0", +] + +[[package]] +name = "zkevm_opcode_defs" +version = "1.3.2" +source = "git+https://github.com/matter-labs/era-zkevm_opcode_defs.git?branch=v1.3.2#dffacadeccdfdbff4bc124d44c595c4a6eae5013" +dependencies = [ + "bitflags 2.5.0", + "blake2 0.10.6 (git+https://github.com/RustCrypto/hashes.git?rev=1f727ce37ff40fa0cce84eb8543a45bdd3ca4a4e)", + "ethereum-types", + "k256 0.11.6", + "lazy_static", + "sha2 0.10.6", + "sha3 0.10.6", +] + +[[package]] +name = "zkevm_opcode_defs" +version = "1.5.0" +source = "git+https://github.com/matter-labs/era-zkevm_opcode_defs.git?branch=v1.5.0#109d9f734804a8b9dc0531c0b576e2a0f55a40de" +dependencies = [ + "bitflags 2.5.0", + "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types", + "k256 0.13.2", + "lazy_static", + "p256", + "serde", + "sha2 0.10.8", + "sha3 0.10.8", +] + +[[package]] +name = "zksync_basic_types" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zksync-era.git?branch=main#29a4ffc6b9420590f32a9e1d1585ebffb95eeb6c" +dependencies = [ + "anyhow", + "chrono", + "num_enum 0.7.2", + "serde", + "serde_json", + "strum", + "url", + "web3", +] + +[[package]] +name = "zksync_concurrency" +version = "0.1.0" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=92ecb2d5d65e3bc4a883dacd18d0640e86576c8c#92ecb2d5d65e3bc4a883dacd18d0640e86576c8c" +dependencies = [ + "anyhow", + "once_cell", + "pin-project", + "rand 0.8.5", + "sha3 0.10.8", + "thiserror", + "time", + "tokio", + "tracing", + "tracing-subscriber", + "vise", +] + +[[package]] +name = "zksync_config" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zksync-era.git?branch=main#29a4ffc6b9420590f32a9e1d1585ebffb95eeb6c" +dependencies = [ + "anyhow", + "rand 0.8.5", + "serde", + "url", + "zksync_basic_types", + "zksync_consensus_utils", + "zksync_crypto_primitives", +] + +[[package]] +name = "zksync_consensus_utils" +version = "0.1.0" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=92ecb2d5d65e3bc4a883dacd18d0640e86576c8c#92ecb2d5d65e3bc4a883dacd18d0640e86576c8c" +dependencies = [ + "rand 0.8.5", + "thiserror", + "zksync_concurrency", +] + +[[package]] +name = "zksync_contracts" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zksync-era.git?branch=main#29a4ffc6b9420590f32a9e1d1585ebffb95eeb6c" +dependencies = [ + "envy", + "ethabi", + "hex", + "once_cell", + "serde", + "serde_json", + "zksync_utils", +] + +[[package]] +name = "zksync_crypto" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zksync-era.git?branch=main#29a4ffc6b9420590f32a9e1d1585ebffb95eeb6c" +dependencies = [ + "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", + "hex", + "once_cell", + "serde", + "sha2 0.10.8", + "thiserror", + "zksync_basic_types", +] + +[[package]] +name = "zksync_crypto_primitives" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zksync-era.git?branch=main#29a4ffc6b9420590f32a9e1d1585ebffb95eeb6c" +dependencies = [ + "anyhow", + "hex", + "rand 0.8.5", + "secp256k1", + "serde", + "serde_json", + "thiserror", + "web3", + "zksync_basic_types", + "zksync_utils", +] + +[[package]] +name = "zksync_mini_merkle_tree" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zksync-era.git?branch=main#29a4ffc6b9420590f32a9e1d1585ebffb95eeb6c" +dependencies = [ + "once_cell", + "zksync_basic_types", + "zksync_crypto", +] + +[[package]] +name = "zksync_protobuf" +version = "0.1.0" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=92ecb2d5d65e3bc4a883dacd18d0640e86576c8c#92ecb2d5d65e3bc4a883dacd18d0640e86576c8c" +dependencies = [ + "anyhow", + "bit-vec", + "once_cell", + "prost 0.12.4", + "prost-reflect", + "quick-protobuf", + "rand 0.8.5", + "serde", + "serde_json", + "serde_yaml", + "zksync_concurrency", + "zksync_consensus_utils", + "zksync_protobuf_build", +] + +[[package]] +name = "zksync_protobuf_build" +version = "0.1.0" +source = "git+https://github.com/matter-labs/era-consensus.git?rev=92ecb2d5d65e3bc4a883dacd18d0640e86576c8c#92ecb2d5d65e3bc4a883dacd18d0640e86576c8c" +dependencies = [ + "anyhow", + "heck 0.5.0", + "prettyplease", + "proc-macro2 1.0.82", + "prost-build", + "prost-reflect", + "protox", + "quote 1.0.33", + "syn 2.0.33", +] + +[[package]] +name = "zksync_system_constants" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zksync-era.git?branch=main#29a4ffc6b9420590f32a9e1d1585ebffb95eeb6c" +dependencies = [ + "once_cell", + "zksync_basic_types", + "zksync_utils", +] + +[[package]] +name = "zksync_types" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zksync-era.git?branch=main#29a4ffc6b9420590f32a9e1d1585ebffb95eeb6c" +dependencies = [ + "anyhow", + "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono", + "derive_more 1.0.0-beta.6", + "hex", + "itertools 0.10.5", + "num", + "num_enum 0.7.2", + "once_cell", + "prost 0.12.4", + "rlp", + "secp256k1", + "serde", + "serde_json", + "strum", + "thiserror", + "zksync_basic_types", + "zksync_config", + "zksync_contracts", + "zksync_crypto_primitives", + "zksync_mini_merkle_tree", + "zksync_protobuf", + "zksync_protobuf_build", + "zksync_system_constants", + "zksync_utils", +] + +[[package]] +name = "zksync_utils" +version = "0.1.0" +source = "git+https://github.com/matter-labs/zksync-era.git?branch=main#29a4ffc6b9420590f32a9e1d1585ebffb95eeb6c" +dependencies = [ + "anyhow", + "bigdecimal", + "futures", + "hex", + "itertools 0.10.5", + "num", + "reqwest", + "serde", + "thiserror", + "tokio", + "tracing", + "vlog", + "zk_evm 1.3.3", + "zksync_basic_types", +] [[package]] name = "zksync_verifier_contract_generator" version = "0.1.0" dependencies = [ + "circuit_definitions 1.5.0", + "crypto", "handlebars", + "hex", "lazy_static", "serde_derive", "serde_json", + "sha3 0.10.8", "structopt", ] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.10+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/tools/Cargo.toml b/tools/Cargo.toml index 204440623..b32b52bdb 100644 --- a/tools/Cargo.toml +++ b/tools/Cargo.toml @@ -4,10 +4,15 @@ version = "0.1.0" edition = "2021" [dependencies] +zksync_crypto = { git = "https://github.com/matter-labs/era-boojum-validator-cli", branch = "main", package = "crypto" } +circuit_definitions = {git = "https://github.com/matter-labs/era-zkevm_test_harness.git", branch="v1.5.0"} + serde_derive = "1.0" serde_json = "1.0" lazy_static = "1.4" structopt = "0.3.26" handlebars = "4.4.0" +sha3 = "0.10.8" +hex = "0.4.3" [workspace] diff --git a/tools/data/verifier_contract_template.txt b/tools/data/verifier_contract_template.txt index bef14e662..5ef32b2c5 100644 --- a/tools/data/verifier_contract_template.txt +++ b/tools/data/verifier_contract_template.txt @@ -8,13 +8,14 @@ import {IVerifier} from "./chain-interfaces/IVerifier.sol"; /// @author Matter Labs /// @notice Modified version of the Permutations over Lagrange-bases for Oecumenical Noninteractive arguments of /// Knowledge (PLONK) verifier. -/// Modifications have been made to optimize the proof system for zkSync hyperchain circuits. +/// Modifications have been made to optimize the proof system for ZKsync hyperchain circuits. +/// @dev Contract was generated from a verification key with a hash of 0x{{vk_hash}} /// @dev It uses a custom memory layout inside the inline assembly block. Each reserved memory cell is declared in the /// constants below. /// @dev For a better understanding of the verifier algorithm please refer to the following papers: /// * Original Plonk Article: https://eprint.iacr.org/2019/953.pdf /// * Original LookUp Article: https://eprint.iacr.org/2020/315.pdf -/// * Plonk for zkSync v1.1: https://github.com/matter-labs/solidity_plonk_verifier/raw/recursive/bellman_vk_codegen_recursive/RecursivePlonkUnrolledForEthereum.pdf +/// * Plonk for ZKsync v1.1: https://github.com/matter-labs/solidity_plonk_verifier/raw/recursive/bellman_vk_codegen_recursive/RecursivePlonkUnrolledForEthereum.pdf /// The notation used in the code is the same as in the papers. /* solhint-enable max-line-length */ contract Verifier is IVerifier { diff --git a/tools/rust-toolchain b/tools/rust-toolchain deleted file mode 100644 index 0834888f5..000000000 --- a/tools/rust-toolchain +++ /dev/null @@ -1 +0,0 @@ -1.72.0 diff --git a/tools/rust-toolchain.toml b/tools/rust-toolchain.toml new file mode 100644 index 000000000..1388c20ff --- /dev/null +++ b/tools/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly-2024-02-04" diff --git a/tools/src/main.rs b/tools/src/main.rs index 3ac8c3ff1..746373fe4 100644 --- a/tools/src/main.rs +++ b/tools/src/main.rs @@ -1,5 +1,9 @@ +use circuit_definitions::snark_wrapper::franklin_crypto::bellman::plonk::better_better_cs::setup::VerificationKey; +use circuit_definitions::snark_wrapper::franklin_crypto::bellman::pairing::bn256::Bn256; +use circuit_definitions::circuit_definitions::aux_layer::ZkSyncSnarkWrapperCircuit; use handlebars::Handlebars; use serde_json::json; +use zksync_crypto::calculate_verification_key_hash; use std::collections::HashMap; use std::error::Error; use std::fs; @@ -122,8 +126,16 @@ fn main() -> Result<(), Box> { let verifier_contract_template = fs::read_to_string("data/verifier_contract_template.txt")?; + let verification_key = fs::read_to_string(&opt.input_path) + .expect(&format!("Unable to read from {}", &opt.input_path)); + + let verification_key: VerificationKey = + serde_json::from_str(&verification_key).unwrap(); + + let vk_hash = hex::encode(calculate_verification_key_hash(verification_key).to_fixed_bytes()); + let verifier_contract_template = - insert_residue_elements_and_commitments(&verifier_contract_template, &vk)?; + insert_residue_elements_and_commitments(&verifier_contract_template, &vk, &vk_hash)?; let mut file = File::create(opt.output_path)?; @@ -134,6 +146,7 @@ fn main() -> Result<(), Box> { fn insert_residue_elements_and_commitments( template: &str, vk: &HashMap, + vk_hash: &str, ) -> Result> { let reg = Handlebars::new(); let residue_g2_elements = generate_residue_g2_elements(vk); @@ -145,7 +158,8 @@ fn insert_residue_elements_and_commitments( Ok(reg.render_template( &verifier_contract_template, &json!({"residue_g2_elements": residue_g2_elements, - "commitments": commitments}), + "commitments": commitments, + "vk_hash": vk_hash}), )?) } diff --git a/yarn.lock b/yarn.lock index f83d0f620..66cd67b1a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -679,10 +679,20 @@ resolved "https://registry.yarnpkg.com/@matterlabs/eslint-config-typescript/-/eslint-config-typescript-1.1.2.tgz#a9be4e56aedf298800f247c5049fc412f8b301a7" integrity sha512-AhiWJQr+MSE3RVfgp5XwGoMK7kNSKh6a18+T7hkNJtyycP0306I6IGmuFA5ZVbcakGb+K32fQWzepSkrNCTAGg== -"@matterlabs/hardhat-zksync-chai-matchers@^0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-chai-matchers/-/hardhat-zksync-chai-matchers-0.1.4.tgz#105cb0ec1367c8fcd3ce7e3773f747c71fff675b" - integrity sha512-eGQWiImg51fmayoQ7smIK/T6QZkSu38PK7xjp1RIrewGzw2ZgqFWGp40jb5oomkf8yOQPk52Hu4TwE3Ntp8CtA== +"@matterlabs/hardhat-zksync-chai-matchers@^0.2.0": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-chai-matchers/-/hardhat-zksync-chai-matchers-0.2.1.tgz#d05136d6cf9a53c30f5e7ee9bae95abb72c1000d" + integrity sha512-LXm5r53DLTQC/KXRXzSRmVp5mEJ4tsoKAKyGck2YLHQ9CBdPoC0paVjbyB2MaEuK/k8o4lZu4uaYKgWQNUXeyQ== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@matterlabs/hardhat-zksync-deploy" "^0.7.0" + "@matterlabs/hardhat-zksync-solc" "1.0.6" + chai "^4.3.7" + chai-as-promised "^7.1.1" + ethers "~5.7.2" + hardhat "^2.14.0" + ordinal "1.0.3" + zksync-ethers "^5.0.0" "@matterlabs/hardhat-zksync-deploy@^0.6.5": version "0.6.6" @@ -693,6 +703,15 @@ chalk "4.1.2" ts-morph "^19.0.0" +"@matterlabs/hardhat-zksync-deploy@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-deploy/-/hardhat-zksync-deploy-0.7.0.tgz#e56b73d8f8fbd0f809a779d0028418ea7d914017" + integrity sha512-PGZcuhKsVzZ2IWPt931pK2gA+HDxnCtye+7CwvoOnM6diHeO9tB1QHFX/ywR9ErOW9wpezhPYkVDx9myFrdoqQ== + dependencies: + "@matterlabs/hardhat-zksync-solc" "^1.0.5" + chalk "4.1.2" + ts-morph "^19.0.0" + "@matterlabs/hardhat-zksync-node@^0.0.1-beta.7": version "0.0.1" resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-node/-/hardhat-zksync-node-0.0.1.tgz#d44bda3c0069b149e2a67c9697eb81166b169ea6" @@ -703,25 +722,26 @@ chalk "4.1.2" fs-extra "^11.1.1" -"@matterlabs/hardhat-zksync-solc@0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-0.4.1.tgz#e8e67d947098d7bb8925f968544d34e522af5a9c" - integrity sha512-fdlGf/2yZR5ihVNc2ubea1R/nNFXRONL29Fgz5FwB3azB13rPb76fkQgcFIg9zSufHsEy6zUUT029NkxLNA9Sw== +"@matterlabs/hardhat-zksync-solc@0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-0.4.2.tgz#64121082e88c5ab22eb4e9594d120e504f6af499" + integrity sha512-6NFWPSZiOAoo7wNuhMg4ztj7mMEH+tLrx09WuCbcURrHPijj/KxYNsJD6Uw5lapKr7G8H7SQISGid1/MTXVmXQ== dependencies: "@nomiclabs/hardhat-docker" "^2.0.0" chalk "4.1.2" dockerode "^3.3.4" fs-extra "^11.1.1" + proper-lockfile "^4.1.2" semver "^7.5.1" -"@matterlabs/hardhat-zksync-solc@0.4.2": - version "0.4.2" - resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-0.4.2.tgz#64121082e88c5ab22eb4e9594d120e504f6af499" - integrity sha512-6NFWPSZiOAoo7wNuhMg4ztj7mMEH+tLrx09WuCbcURrHPijj/KxYNsJD6Uw5lapKr7G8H7SQISGid1/MTXVmXQ== +"@matterlabs/hardhat-zksync-solc@1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-1.0.6.tgz#7ef8438e6bb15244691600e2afa77aaff7dff9f0" + integrity sha512-0icYSufXba/Bbb7v2iXuZJ+IbYsiNpR4Wy6UizHnGuFw3OMHgh+saebQphuaN9yyRL2UPGZbPkQFHWBLZj5/xQ== dependencies: "@nomiclabs/hardhat-docker" "^2.0.0" chalk "4.1.2" - dockerode "^3.3.4" + dockerode "^4.0.0" fs-extra "^11.1.1" proper-lockfile "^4.1.2" semver "^7.5.1" @@ -772,16 +792,17 @@ sinon-chai "^3.7.0" zksync-ethers "^5.0.0" -"@matterlabs/hardhat-zksync-verify@^0.2.0": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-verify/-/hardhat-zksync-verify-0.2.2.tgz#daa34bc4404096ed0f44461ee366c1cb0e5a4f2f" - integrity sha512-WgcItoZGY702oJ708uCP5uLvmwzDLBfhMqq2D0Kh1U/3fCTlPza9zMGUFHxKMQYsITKTeQ5zKOjKoi8MXOeUdQ== +"@matterlabs/hardhat-zksync-verify@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@matterlabs/hardhat-zksync-verify/-/hardhat-zksync-verify-0.4.0.tgz#f812c19950022fc36728f3796f6bdae5633e2fcd" + integrity sha512-GPZmAumFl3ZMPKbECX7Qw8CriwZKWd1DlCRhoG/6YYc6mFy4+MXkF1XsHLMs5r34N+GDOfbVZVMeftIlJC96Kg== dependencies: - "@matterlabs/hardhat-zksync-solc" "0.4.1" + "@matterlabs/hardhat-zksync-solc" "^1.0.5" "@nomicfoundation/hardhat-verify" "^1.0.2" axios "^1.4.0" chalk "4.1.2" dockerode "^3.3.4" + zksync-ethers "^5.0.0" "@matterlabs/hardhat-zksync-verify@^1.4.3": version "1.4.3" @@ -881,10 +902,10 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.4.0.tgz#bbb43f0e01f40839b0bd38c2c443cb6910ae955f" integrity sha512-7+rraFk9tCqvfemv9Ita5vTlSBAeO/S5aDKOgGRgYt0JEKZlrX161nDW6UfzMPxWl9GOLEDUzCEaYuNmXseUlg== -"@nomicfoundation/edr-darwin-arm64@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.5.0.tgz#08b7302c7ce00e3c4dc43e7cfc9065997463c470" - integrity sha512-G6OX/PESdfU4ZOyJ4MDh4eevW0wt2mduuxA+thXtTcStOiQTtPuV205h4kLOR5wRB1Zz6Zy0LedTMax7TzOtGw== +"@nomicfoundation/edr-darwin-arm64@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.5.2.tgz#72f7a826c9f0f2c91308edca562de3b9484ac079" + integrity sha512-Gm4wOPKhbDjGTIRyFA2QUAPfCXA1AHxYOKt3yLSGJkQkdy9a5WW+qtqKeEKHc/+4wpJSLtsGQfpzyIzggFfo/A== "@nomicfoundation/edr-darwin-x64@0.3.7": version "0.3.7" @@ -896,10 +917,10 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.4.0.tgz#b1ffcd9142418fd8498de34a7336b3f977907c86" integrity sha512-+Hrc0mP9L6vhICJSfyGo/2taOToy1AIzVZawO3lU8Lf7oDQXfhQ4UkZnkWAs9SVu1eUwHUGGGE0qB8644piYgg== -"@nomicfoundation/edr-darwin-x64@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.5.0.tgz#4a30a8584721bffd1ad6d7cc7fb70f2b2034e3b5" - integrity sha512-fI7uHfHqPtdPZjkFUTpotc/F5gGv41ws+jSZy9+2AR9RDMOAIXMEArOx9rGLBcevWu8SFnyH/l/77kG/5FXbDw== +"@nomicfoundation/edr-darwin-x64@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.5.2.tgz#6d0fedb219d664631c6feddc596ab8c3bbc36fa8" + integrity sha512-ClyABq2dFCsrYEED3/UIO0c7p4H1/4vvlswFlqUyBpOkJccr75qIYvahOSJRM62WgUFRhbSS0OJXFRwc/PwmVg== "@nomicfoundation/edr-linux-arm64-gnu@0.3.7": version "0.3.7" @@ -911,10 +932,10 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.4.0.tgz#8173d16d4f6f2b3e82ba7096d2a1ea3619d8bfa7" integrity sha512-4HUDMchNClQrVRfVTqBeSX92hM/3khCgpZkXP52qrnJPqgbdCxosOehlQYZ65wu0b/kaaZSyvACgvCLSQ5oSzQ== -"@nomicfoundation/edr-linux-arm64-gnu@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.5.0.tgz#f4a0e9a5ac8157dc4e241f751c8e8b09f446aa8d" - integrity sha512-eMC3sWPkBZILg2/YB4Xv6IR0nggCLt5hS8K8jjHeGEeUs9pf8poBF2Oy+G4lSu0YLLjexGzHypz9/P+pIuxZHw== +"@nomicfoundation/edr-linux-arm64-gnu@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.5.2.tgz#60e4d52d963141bc2bb4a02639dc590a7fbdda2f" + integrity sha512-HWMTVk1iOabfvU2RvrKLDgtFjJZTC42CpHiw2h6rfpsgRqMahvIlx2jdjWYzFNy1jZKPTN1AStQ/91MRrg5KnA== "@nomicfoundation/edr-linux-arm64-musl@0.3.7": version "0.3.7" @@ -926,10 +947,10 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.4.0.tgz#b1ce293a7c3e0d9f70391e1aef1a82b83b997567" integrity sha512-D4J935ZRL8xfnP3zIFlCI9jXInJ0loDUkCTLeCEbOf2uuDumWDghKNQlF1itUS+EHaR1pFVBbuwqq8hVK0dASg== -"@nomicfoundation/edr-linux-arm64-musl@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.5.0.tgz#34e240a02ebb8d6e0e262642058370f24d555386" - integrity sha512-yPK0tKjYRxe5ktggFr8aBHH0DCI9uafuaD8QuzyrQAfSf/m/ebTdgthROdbYp6eRk5mJyfAQT/45fM3tnlYsWw== +"@nomicfoundation/edr-linux-arm64-musl@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.5.2.tgz#6676a09eab57c435a16ffc144658c896acca9baa" + integrity sha512-CwsQ10xFx/QAD5y3/g5alm9+jFVuhc7uYMhrZAu9UVF+KtVjeCvafj0PaVsZ8qyijjqVuVsJ8hD1x5ob7SMcGg== "@nomicfoundation/edr-linux-x64-gnu@0.3.7": version "0.3.7" @@ -941,10 +962,10 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.4.0.tgz#4c12c4e4bfd3d837f5663ad7cbf7cb6d5634ef83" integrity sha512-6x7HPy+uN5Cb9N77e2XMmT6+QSJ+7mRbHnhkGJ8jm4cZvWuj2Io7npOaeHQ3YHK+TiQpTnlbkjoOIpEwpY3XZA== -"@nomicfoundation/edr-linux-x64-gnu@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.5.0.tgz#c118f26567eba994133c7fda11a022dee46c5e13" - integrity sha512-Hds8CRYi4DEyuErjcwUNSvNpMzmOYUihW4qYCoKgSBUVS5saX1PyPYvFYuYpeU5J8/T2iMk6yAPVLCxtKbgnKg== +"@nomicfoundation/edr-linux-x64-gnu@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.5.2.tgz#f558d9697ce961410e7a7468f9ab8c8a601b9df6" + integrity sha512-CWVCEdhWJ3fmUpzWHCRnC0/VLBDbqtqTGTR6yyY1Ep3S3BOrHEAvt7h5gx85r2vLcztisu2vlDq51auie4IU1A== "@nomicfoundation/edr-linux-x64-musl@0.3.7": version "0.3.7" @@ -956,10 +977,10 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.4.0.tgz#8842004aa1a47c504f10863687da28b65dca7baa" integrity sha512-3HFIJSXgyubOiaN4MWGXx2xhTnhwlJk0PiSYNf9+L/fjBtcRkb2nM910ZJHTvqCb6OT98cUnaKuAYdXIW2amgw== -"@nomicfoundation/edr-linux-x64-musl@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.5.0.tgz#b437a652ead59186b566fc2c7a45278018d85806" - integrity sha512-1hXMDSzdyh5ojwO3ZSRbt7t5KKYycGUlFdC3lgJRZ7gStB8xjb7RA3hZn2csn9OydS950Ne4nh+puNq91iXApw== +"@nomicfoundation/edr-linux-x64-musl@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.5.2.tgz#c9c9cbb2997499f75c1d022be724b0551d44569f" + integrity sha512-+aJDfwhkddy2pP5u1ISg3IZVAm0dO836tRlDTFWtvvSMQ5hRGqPcWwlsbobhDQsIxhPJyT7phL0orCg5W3WMeA== "@nomicfoundation/edr-win32-x64-msvc@0.3.7": version "0.3.7" @@ -971,10 +992,10 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.4.0.tgz#29d8bbb2edf9912a95f5453855cf17cdcb269957" integrity sha512-CP4GsllEfXEz+lidcGYxKe5rDJ60TM5/blB5z/04ELVvw6/CK9eLcYeku7HV0jvV7VE6dADYKSdQyUkvd0El+A== -"@nomicfoundation/edr-win32-x64-msvc@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.5.0.tgz#0dd0eb9c0d6c2f47403393b9712dd8577bd06041" - integrity sha512-CFagD423400xXkRmACIR13FoocN48qi4ogRnuFQIvBDtEE3aMEajfFj4bycmQQDqnqChsZy/jwD4OxbX6oaNJw== +"@nomicfoundation/edr-win32-x64-msvc@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.5.2.tgz#f16db88bf4fe09a996af0a25096e09deecb72bfa" + integrity sha512-CcvvuA3sAv7liFNPsIR/68YlH6rrybKzYttLlMr80d4GKJjwJ5OKb3YgE6FdZZnOfP19HEHhsLcE0DPLtY3r0w== "@nomicfoundation/edr@^0.3.1": version "0.3.7" @@ -1003,17 +1024,17 @@ "@nomicfoundation/edr-win32-x64-msvc" "0.4.0" "@nomicfoundation/edr@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.5.0.tgz#febcce36898ae3e01f04f2013a24b8bec0c2ca24" - integrity sha512-nAUyjGhxntXje/1AkDX9POfH+pqUxdi4XHzIhaf/dJYs7fgAFxL3STBK1OYcA3LR7vtiylLHMz7wxjqLzlLGKg== - dependencies: - "@nomicfoundation/edr-darwin-arm64" "0.5.0" - "@nomicfoundation/edr-darwin-x64" "0.5.0" - "@nomicfoundation/edr-linux-arm64-gnu" "0.5.0" - "@nomicfoundation/edr-linux-arm64-musl" "0.5.0" - "@nomicfoundation/edr-linux-x64-gnu" "0.5.0" - "@nomicfoundation/edr-linux-x64-musl" "0.5.0" - "@nomicfoundation/edr-win32-x64-msvc" "0.5.0" + version "0.5.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/edr/-/edr-0.5.2.tgz#e8c7b3d3dd4a312432ab3930dec60f76dc5c4926" + integrity sha512-hW/iLvUQZNTVjFyX/I40rtKvvDOqUEyIi96T28YaLfmPL+3LW2lxmYLUXEJ6MI14HzqxDqrLyhf6IbjAa2r3Dw== + dependencies: + "@nomicfoundation/edr-darwin-arm64" "0.5.2" + "@nomicfoundation/edr-darwin-x64" "0.5.2" + "@nomicfoundation/edr-linux-arm64-gnu" "0.5.2" + "@nomicfoundation/edr-linux-arm64-musl" "0.5.2" + "@nomicfoundation/edr-linux-x64-gnu" "0.5.2" + "@nomicfoundation/edr-linux-x64-musl" "0.5.2" + "@nomicfoundation/edr-win32-x64-msvc" "0.5.2" "@nomicfoundation/ethereumjs-common@4.0.4": version "4.0.4" @@ -1195,12 +1216,12 @@ resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.6.tgz#d11cb063a5f61a77806053e54009c40ddee49a54" integrity sha512-+Wz0hwmJGSI17B+BhU/qFRZ1l6/xMW82QGXE/Gi+WTmwgJrQefuBs1lIf7hzQ1hLk6hpkvb/zwcNkpVKRYTQYg== -"@openzeppelin/contracts-upgradeable@4.9.5": +"@openzeppelin/contracts-upgradeable-v4@npm:@openzeppelin/contracts-upgradeable@4.9.5": version "4.9.5" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-4.9.5.tgz#572b5da102fc9be1d73f34968e0ca56765969812" integrity sha512-f7L1//4sLlflAN7fVzJLoRedrf5Na3Oal5PZfIq55NFcVZ90EpV1q5xOvL4lFvg3MNICSDr2hH0JUBxwlxcoPg== -"@openzeppelin/contracts@4.9.5": +"@openzeppelin/contracts-v4@npm:@openzeppelin/contracts@4.9.5": version "4.9.5" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.5.tgz#1eed23d4844c861a1835b5d33507c1017fa98de8" integrity sha512-ZK+W5mVhRppff9BE6YdR8CC52C8zAvsVAiWhEtQ5+oNxFE6h1WdeWo+FJSF8KKvtxxVYZ7MTP/5KoVpAU3aSWg== @@ -1215,6 +1236,27 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== +"@pnpm/config.env-replace@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz#ab29da53df41e8948a00f2433f085f54de8b3a4c" + integrity sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w== + +"@pnpm/network.ca-file@^1.0.1": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz#2ab05e09c1af0cdf2fcf5035bea1484e222f7983" + integrity sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA== + dependencies: + graceful-fs "4.2.10" + +"@pnpm/npm-conf@^2.1.0": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz#0058baf1c26cbb63a828f0193795401684ac86f0" + integrity sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA== + dependencies: + "@pnpm/config.env-replace" "^1.1.0" + "@pnpm/network.ca-file" "^1.0.1" + config-chain "^1.1.11" + "@resolver-engine/core@^0.3.3": version "0.3.3" resolved "https://registry.yarnpkg.com/@resolver-engine/core/-/core-0.3.3.tgz#590f77d85d45bc7ecc4e06c654f41345db6ca967" @@ -1359,6 +1401,11 @@ "@sentry/types" "5.30.0" tslib "^1.9.3" +"@sindresorhus/is@^5.2.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-5.6.0.tgz#41dd6093d34652cddb5d5bdeee04eafc33826668" + integrity sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g== + "@sinonjs/commons@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" @@ -1418,6 +1465,13 @@ resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.18.0.tgz#8e77a02a09ecce957255a2f48c9a7178ec191908" integrity sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA== +"@szmarczak/http-timer@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-5.0.1.tgz#c7c1bf1141cdd4751b0399c8fc7b8b664cd5be3a" + integrity sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw== + dependencies: + defer-to-connect "^2.0.1" + "@trufflesuite/bigint-buffer@1.1.10": version "1.1.10" resolved "https://registry.yarnpkg.com/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.10.tgz#a1d9ca22d3cad1a138b78baaf15543637a3e1692" @@ -1542,6 +1596,11 @@ "@types/minimatch" "*" "@types/node" "*" +"@types/http-cache-semantics@^4.0.2": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" + integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== + "@types/json-schema@^7.0.12": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" @@ -1935,6 +1994,11 @@ antlr4@^4.11.0: resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.13.1.tgz#1e0a1830a08faeb86217cb2e6c34716004e4253d" integrity sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA== +antlr4@^4.13.1-patch-1: + version "4.13.1-patch-1" + resolved "https://registry.yarnpkg.com/antlr4/-/antlr4-4.13.1-patch-1.tgz#946176f863f890964a050c4f18c47fd6f7e57602" + integrity sha512-OjFLWWLzDMV9rdFhpvroCWR4ooktNg9/nvVYSA5z28wuVpU36QUNuioR1XLnQtcjVlf8npjyz593PxnU/f/Cow== + antlr4ts@^0.5.0-alpha.4: version "0.5.0-alpha.4" resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" @@ -2409,6 +2473,24 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +cacheable-lookup@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz#3476a8215d046e5a3202a9209dd13fec1f933a27" + integrity sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w== + +cacheable-request@^10.2.8: + version "10.2.14" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-10.2.14.tgz#eb915b665fda41b79652782df3f553449c406b9d" + integrity sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ== + dependencies: + "@types/http-cache-semantics" "^4.0.2" + get-stream "^6.0.1" + http-cache-semantics "^4.1.1" + keyv "^4.5.3" + mimic-response "^4.0.0" + normalize-url "^8.0.0" + responselike "^3.0.0" + call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" @@ -2454,7 +2536,7 @@ chai-as-promised@^7.1.1: dependencies: check-error "^1.0.2" -chai@^4.3.10, chai@^4.3.6: +chai@^4.3.10, chai@^4.3.6, chai@^4.3.7: version "4.4.1" resolved "https://registry.yarnpkg.com/chai/-/chai-4.4.1.tgz#3603fa6eba35425b0f2ac91a009fe924106e50d1" integrity sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g== @@ -2709,6 +2791,14 @@ concat-stream@^1.6.0, concat-stream@^1.6.2, concat-stream@~1.6.2: readable-stream "^2.2.2" typedarray "^0.0.6" +config-chain@^1.1.11: + version "1.1.13" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + cookie@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" @@ -2876,6 +2966,13 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + deep-eql@^4.0.1, deep-eql@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" @@ -2893,6 +2990,11 @@ deep-is@^0.1.3, deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +defer-to-connect@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + deferred-leveldown@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-5.3.0.tgz#27a997ad95408b61161aa69bd489b86c71b78058" @@ -3006,7 +3108,7 @@ dockerode@^3.3.4: docker-modem "^3.0.0" tar-fs "~2.0.1" -dockerode@^4.0.2: +dockerode@^4.0.0, dockerode@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/dockerode/-/dockerode-4.0.2.tgz#dedc8529a1db3ac46d186f5912389899bc309f7d" integrity sha512-9wM1BVpVMFr2Pw3eJNXrYYt6DT9k0xMcsSCjtPvyQ+xa1iPg/Mo3T/gUcwI0B2cczqCeCYRPF8yFYDwtFXT0+w== @@ -3552,7 +3654,7 @@ ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.3, ethereumjs-util@^7.1.4, ethereum ethereum-cryptography "^0.1.3" rlp "^2.2.4" -ethers@^5.0.2, ethers@^5.7.0, ethers@^5.7.2, ethers@~5.7.0: +ethers@^5.0.2, ethers@^5.7.0, ethers@^5.7.2, ethers@~5.7.0, ethers@~5.7.2: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -3844,6 +3946,11 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== +form-data-encoder@^2.1.2: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5" + integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw== + form-data@^2.2.0: version "2.5.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" @@ -4017,6 +4124,11 @@ get-stdin@~9.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575" integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA== +get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" @@ -4195,6 +4307,28 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +got@^12.1.0: + version "12.6.1" + resolved "https://registry.yarnpkg.com/got/-/got-12.6.1.tgz#8869560d1383353204b5a9435f782df9c091f549" + integrity sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ== + dependencies: + "@sindresorhus/is" "^5.2.0" + "@szmarczak/http-timer" "^5.0.1" + cacheable-lookup "^7.0.0" + cacheable-request "^10.2.8" + decompress-response "^6.0.0" + form-data-encoder "^2.1.2" + get-stream "^6.0.1" + http2-wrapper "^2.1.10" + lowercase-keys "^3.0.0" + p-cancelable "^3.0.0" + responselike "^3.0.0" + +graceful-fs@4.2.10: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -4356,7 +4490,7 @@ hardhat@^2.14.0: uuid "^8.3.2" ws "^7.4.6" -hardhat@^2.18.3, hardhat@^2.19.4: +hardhat@^2.19.4: version "2.22.5" resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.5.tgz#7e1a4311fa9e34a1cfe337784eae06706f6469a5" integrity sha512-9Zq+HonbXCSy6/a13GY1cgHglQRfh4qkzmj1tpPlhxJDwNVnhxlReV6K7hCWFKlOrV13EQwsdcD0rjcaQKWRZw== @@ -4507,6 +4641,11 @@ http-basic@^8.1.1: http-response-object "^3.0.1" parse-cache-control "^1.0.1" +http-cache-semantics@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + http-errors@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -4534,6 +4673,14 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +http2-wrapper@^2.1.10: + version "2.2.1" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-2.2.1.tgz#310968153dcdedb160d8b72114363ef5fce1f64a" + integrity sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.2.0" + https-proxy-agent@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -4615,7 +4762,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== -ini@^1.3.5: +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== @@ -5069,6 +5216,13 @@ klaw@^1.0.0: optionalDependencies: graceful-fs "^4.1.9" +latest-version@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-7.0.0.tgz#843201591ea81a4d404932eeb61240fe04e9e5da" + integrity sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg== + dependencies: + package-json "^8.1.0" + level-codec@^9.0.0: version "9.0.2" resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-9.0.2.tgz#fd60df8c64786a80d44e63423096ffead63d8cbc" @@ -5289,6 +5443,11 @@ loupe@^2.3.6: dependencies: get-func-name "^2.0.1" +lowercase-keys@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" + integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -5453,6 +5612,16 @@ mime-types@^2.1.12, mime-types@~2.1.19: dependencies: mime-db "1.52.0" +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +mimic-response@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" + integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -5697,6 +5866,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +normalize-url@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.1.tgz#9b7d96af9836577c58f5883e939365fa15623a4a" + integrity sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w== + number-to-bn@1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" @@ -5799,7 +5973,7 @@ optionator@^0.9.3: type-check "^0.4.0" word-wrap "^1.2.5" -ordinal@^1.0.3: +ordinal@1.0.3, ordinal@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/ordinal/-/ordinal-1.0.3.tgz#1a3c7726a61728112f50944ad7c35c06ae3a0d4d" integrity sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ== @@ -5809,6 +5983,11 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== +p-cancelable@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" + integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== + p-limit@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -5856,6 +6035,16 @@ p-try@^1.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== +package-json@^8.1.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-8.1.1.tgz#3e9948e43df40d1e8e78a85485f1070bf8f03dc8" + integrity sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA== + dependencies: + got "^12.1.0" + registry-auth-token "^5.0.1" + registry-url "^6.0.0" + semver "^7.3.7" + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -6054,6 +6243,11 @@ proper-lockfile@^4.1.2: retry "^0.12.0" signal-exit "^3.0.2" +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -6117,6 +6311,11 @@ queue-microtask@^1.2.2, queue-microtask@^1.2.3: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + randombytes@^2.0.1, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -6134,6 +6333,16 @@ raw-body@^2.4.1: iconv-lite "0.4.24" unpipe "1.0.0" +rc@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.5: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" @@ -6207,6 +6416,20 @@ regexp.prototype.flags@^1.5.2: es-errors "^1.3.0" set-function-name "^2.0.1" +registry-auth-token@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-5.0.2.tgz#8b026cc507c8552ebbe06724136267e63302f756" + integrity sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ== + dependencies: + "@pnpm/npm-conf" "^2.1.0" + +registry-url@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-6.0.1.tgz#056d9343680f2f64400032b1e199faa692286c58" + integrity sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q== + dependencies: + rc "1.2.8" + req-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/req-cwd/-/req-cwd-2.0.0.tgz#d4082b4d44598036640fb73ddea01ed53db49ebc" @@ -6257,6 +6480,11 @@ require-from-string@^2.0.0, require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== +resolve-alpn@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== + resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" @@ -6293,6 +6521,13 @@ resolve@^1.1.6, resolve@^1.22.4, resolve@^1.8.1: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +responselike@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-3.0.0.tgz#20decb6c298aff0dbee1c355ca95461d42823626" + integrity sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg== + dependencies: + lowercase-keys "^3.0.0" + retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -6456,6 +6691,11 @@ semver@^7.3.4, semver@^7.5.1, semver@^7.5.2, semver@^7.5.4: dependencies: lru-cache "^6.0.0" +semver@^7.3.7: + version "7.6.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.1.tgz#60bfe090bf907a25aa8119a72b9f90ef7ca281b2" + integrity sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA== + serialize-javascript@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" @@ -6644,6 +6884,32 @@ solhint-plugin-prettier@^0.0.5: dependencies: prettier-linter-helpers "^1.0.0" +solhint@4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/solhint/-/solhint-4.5.4.tgz#171cf33f46c36b8499efe60c0e425f6883a54e50" + integrity sha512-Cu1XiJXub2q1eCr9kkJ9VPv1sGcmj3V7Zb76B0CoezDOB9bu3DxKIFFH7ggCl9fWpEPD6xBmRLfZrYijkVmujQ== + dependencies: + "@solidity-parser/parser" "^0.18.0" + ajv "^6.12.6" + antlr4 "^4.13.1-patch-1" + ast-parents "^0.0.1" + chalk "^4.1.2" + commander "^10.0.0" + cosmiconfig "^8.0.0" + fast-diff "^1.2.0" + glob "^8.0.3" + ignore "^5.2.4" + js-yaml "^4.1.0" + latest-version "^7.0.0" + lodash "^4.17.21" + pluralize "^8.0.0" + semver "^7.5.2" + strip-ansi "^6.0.1" + table "^6.8.1" + text-table "^0.2.0" + optionalDependencies: + prettier "^2.8.3" + solhint@^3.6.2: version "3.6.2" resolved "https://registry.yarnpkg.com/solhint/-/solhint-3.6.2.tgz#2b2acbec8fdc37b2c68206a71ba89c7f519943fe" @@ -6867,6 +7133,11 @@ strip-json-comments@3.1.1, strip-json-comments@^3.1.1, strip-json-comments@~3.1. resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + supports-color@8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"