diff --git a/.eslintrc b/.eslintrc index 8efdd5f0684..e287b9a7fdc 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,6 +1,11 @@ { - "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], - "root": true -} + "extends": ["@matterlabs/eslint-config-typescript"], + "rules": { + "no-multiple-empty-lines": ["error", { "max": 1 }], + "@typescript-eslint/no-namespace": "off", + "import/no-named-as-default-member": "off", + "import/namespace": "off", + "import/no-unresolved": "off", + "import/order": "off" + } +} \ No newline at end of file diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 00000000000..76dfb3f2dc4 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,16 @@ +#!/bin/sh + +CYAN='\033[0;36m' +NC='\033[0m' # No Color +RED='\033[0;31m' + +# Check that the code is formatted in the given directory provided in the first argument +function check_prettier { + if ! yarn prettier:check; then + echo "${RED}Commit error! Cannot commit unformatted code!${NC}" + echo "Prettier errors found. Please format the code via ${CYAN}yarn prettier:fix${NC}!" + exit 1 + fi +} + +check_prettier diff --git a/.githooks/pre-push b/.githooks/pre-push new file mode 100755 index 00000000000..214d2f64118 --- /dev/null +++ b/.githooks/pre-push @@ -0,0 +1,16 @@ +#!/bin/sh + +CYAN='\033[0;36m' +NC='\033[0m' # No Color +RED='\033[0;31m' + +# Checking that the code is linted and formatted in the given directory provided in the first argument +function check_lint { + if ! yarn lint:check; then + echo "${RED}Push error! Cannot push unlinted code!${NC}" + echo "Lint errors found. Please lint the code via ${CYAN}yarn lint:fix${NC} and/or fix the errors manually!" + exit 1 + fi +} + +check_lint diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 3c160c5ef5e..79ab40e61f4 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,9 +1,9 @@ --- name: Scripts-Related Bug Report about: Use this template for reporting script related bugs. For contract bugs, see our security policy. -title: '' +title: "" labels: bug -assignees: '' +assignees: "" --- ### 🐛 Script Bug Report diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index d921e066ccc..f04164903d5 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,9 +1,9 @@ --- name: Feature request about: Use this template for requesting features -title: '' +title: "" labels: feat -assignees: '' +assignees: "" --- ### 🌟 Feature Request diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 9346d073df6..54b41935374 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -17,4 +17,3 @@ - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. -- [ ] Code has been formatted via `yarn prettier:write` and `yarn lint:fix`. diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 9cad58e0deb..1ffa5d8d55e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -56,7 +56,7 @@ jobs: run: yarn - name: Run lint - run: yarn lint + run: yarn lint:check check_hashes: needs: [build] @@ -89,7 +89,7 @@ jobs: bootloader/build - name: Check hashes - run: yarn calculate-hashes --check-only + run: yarn calculate-hashes:check test: needs: [build, lint] diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 4c7b1e9d975..00000000000 --- a/.prettierrc +++ /dev/null @@ -1,63 +0,0 @@ -{ - "plugins": ["prettier-plugin-solidity"], - "overrides": [ - { - "files": "*.js", - "options": { - "tabWidth": 4, - "printWidth": 120, - "singleQuote": true, - "trailingComma": "none", - "bracketSpacing": true - } - }, - { - "files": "*.json", - "options": { - "tabWidth": 2, - "printWidth": 120, - "bracketSpacing": true - } - }, - { - "files": "*.md", - "options": { - "tabWidth": 2, - "printWidth": 120, - "parser": "markdown", - "singleQuote": true, - "trailingComma": "none", - "bracketSpacing": true, - "proseWrap": "always" - } - }, - { - "files": "*.sol", - "options": { - "printWidth": 120, - "tabWidth": 4, - "useTabs": false, - "singleQuote": false, - "bracketSpacing": false - } - }, - { - "files": "*.ts", - "options": { - "tabWidth": 4, - "printWidth": 120, - "parser": "typescript", - "singleQuote": true, - "trailingComma": "none", - "bracketSpacing": true - } - }, - { - "files": "*.yaml", - "options": { - "tabWidth": 2, - "printWidth": 120 - } - } - ] -} diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 00000000000..02098299827 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,16 @@ +module.exports = { + ...require("@matterlabs/prettier-config"), + plugins: ["prettier-plugin-solidity"], + overrides: [ + { + files: "*.sol", + options: { + bracketSpacing: false, + printWidth: 120, + singleQuote: false, + tabWidth: 4, + useTabs: false, + }, + }, + ], +}; diff --git a/README.md b/README.md index 6306d9c74fd..3a795a2f407 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,9 @@ This repository is used as a submodule of the [zksync-2-dev](https://github.com/ Compile the solidity and yul contracts: `yarn build` -Check the system contracts hashes: `yarn calculate-hashes --check-only` +Check the system contracts hashes: `yarn calculate-hashes:check` -Update the system contracts hashes: `yarn calculate-hashes` +Update the system contracts hashes: `yarn calculate-hashes:fix` ## Update Process diff --git a/hardhat.config.ts b/hardhat.config.ts index 962b8acd40f..6374c4e30e9 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,51 +1,51 @@ -import '@matterlabs/hardhat-zksync-chai-matchers'; -import '@matterlabs/hardhat-zksync-solc'; -import '@nomiclabs/hardhat-ethers'; -import '@nomiclabs/hardhat-solpp'; -import '@typechain/hardhat'; +import "@matterlabs/hardhat-zksync-chai-matchers"; +import "@matterlabs/hardhat-zksync-solc"; +import "@nomiclabs/hardhat-ethers"; +import "@nomiclabs/hardhat-solpp"; +import "@typechain/hardhat"; // eslint-disable-next-line @typescript-eslint/no-var-requires -const systemConfig = require('./SystemConfig.json'); +const systemConfig = require("./SystemConfig.json"); export default { - zksolc: { - version: '1.3.14', - compilerSource: 'binary', - settings: { - isSystem: true - } + zksolc: { + version: "1.3.14", + compilerSource: "binary", + settings: { + isSystem: true, }, - zkSyncDeploy: { - zkSyncNetwork: 'http://localhost:3050', - ethNetwork: 'http://localhost:8545' + }, + zkSyncDeploy: { + zkSyncNetwork: "http://localhost:3050", + ethNetwork: "http://localhost:8545", + }, + solidity: { + version: "0.8.17", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + viaIR: true, }, - solidity: { - version: '0.8.17', - settings: { - optimizer: { - enabled: true, - runs: 200 - }, - viaIR: true - } + }, + solpp: { + defs: (() => { + return { + ECRECOVER_COST_GAS: systemConfig.ECRECOVER_COST_GAS, + KECCAK_ROUND_COST_GAS: systemConfig.KECCAK_ROUND_COST_GAS, + SHA256_ROUND_COST_GAS: systemConfig.SHA256_ROUND_COST_GAS, + }; + })(), + }, + networks: { + hardhat: { + zksync: true, }, - solpp: { - defs: (() => { - return { - ECRECOVER_COST_GAS: systemConfig.ECRECOVER_COST_GAS, - KECCAK_ROUND_COST_GAS: systemConfig.KECCAK_ROUND_COST_GAS, - SHA256_ROUND_COST_GAS: systemConfig.SHA256_ROUND_COST_GAS - }; - })() + zkSyncTestNode: { + url: "http://127.0.0.1:8011", + ethNetwork: "", + zksync: true, }, - networks: { - hardhat: { - zksync: true - }, - zkSyncTestNode: { - url: 'http://127.0.0.1:8011', - ethNetwork: '', - zksync: true - } - } + }, }; diff --git a/package.json b/package.json index 9272f11a332..ad977d73f7b 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,10 @@ "zksync-web3": "^0.14.3" }, "devDependencies": { + "@matterlabs/eslint-config-typescript": "^1.1.2", "@matterlabs/hardhat-zksync-chai-matchers": "^0.1.4", "@matterlabs/hardhat-zksync-solc": "^0.4.2", + "@matterlabs/prettier-config": "^1.0.3", "@nomicfoundation/hardhat-chai-matchers": "^1.0.3", "@nomiclabs/hardhat-ethers": "^2.0.6", "@typechain/ethers-v5": "^10.0.0", @@ -26,8 +28,11 @@ "@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/parser": "^6.7.4", "chai": "^4.3.6", - "lodash": "^4.17.21", "eslint": "^8.51.0", + "eslint-import-resolver-typescript": "^3.6.1", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-prettier": "^5.0.1", + "lodash": "^4.17.21", "markdownlint-cli": "^0.33.0", "mocha": "^10.0.0", "prettier": "^3.0.3", @@ -52,20 +57,21 @@ "build": "yarn build:sol && yarn build:yul", "build:sol": "hardhat compile", "build:yul": "yarn preprocess:yul && yarn compile-yul", - "calculate-hashes": "ts-node scripts/calculate-hashes.ts", + "calculate-hashes:check": "ts-node scripts/calculate-hashes.ts --check-only", + "calculate-hashes:fix": "ts-node scripts/calculate-hashes.ts", "clean": "yarn clean:sol && yarn clean:yul", "clean:sol": "hardhat clean", "clean:yul": "rm -rf ./bootloader/build ./bootloader/tests/artifacts ./contracts/artifacts ./contracts/precompiles/artifacts", "compile-yul": "ts-node scripts/compile-yul.ts", "deploy-preimages": "ts-node scripts/deploy-preimages.ts", - "lint": "yarn lint:md && yarn lint:sol && yarn lint:ts && yarn prettier:check", - "lint:fix": "yarn lint:md --fix && yarn lint:sol --fix && yarn lint:ts --fix && yarn prettier:write", - "lint:md": "markdownlint **/*.md", + "lint:check": "yarn lint:md && yarn lint:sol && yarn lint:ts && yarn prettier:check", + "lint:fix": "yarn lint:md --fix && yarn lint:sol --fix && yarn lint:ts --fix && yarn prettier:fix", + "lint:md": "markdownlint \"**/*.md\"", "lint:sol": "solhint \"contracts/**/*.sol\"", "lint:ts": "eslint .", "preprocess:yul": "rm -rf ./bootloader/build && yarn ts-node scripts/process.ts", "prettier:check": "prettier --check \"**/*.{js,json,md,sol,ts,yaml}\"", - "prettier:write": "prettier --write \"**/*.{js,json,md,sol,ts,yaml}\"", + "prettier:fix": "prettier --write \"**/*.{js,json,md,sol,ts,yaml}\"", "test": "hardhat test --network zkSyncTestNode", "test:bootloader": "cd bootloader/test_infra && cargo run" } diff --git a/scripts/calculate-hashes.ts b/scripts/calculate-hashes.ts index 1ff4165a197..bc7fb007f1d 100644 --- a/scripts/calculate-hashes.ts +++ b/scripts/calculate-hashes.ts @@ -1,232 +1,230 @@ -import { ethers } from 'ethers'; -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 { ethers } from "ethers"; +import * as fs from "fs"; +import _ from "lodash"; +import os from "os"; +import { join } from "path"; +import { hashBytecode } from "zksync-web3/build/src/utils"; type ContractDetails = { - contractName: string; - bytecodePath: string; - sourceCodePath: string; + contractName: string; + bytecodePath: string; + sourceCodePath: string; }; type Hashes = { - bytecodeHash: string; - sourceCodeHash: string; + bytecodeHash: string; + sourceCodeHash: string; }; type SystemContractHashes = ContractDetails & Hashes; const findDirsEndingWith = - (endingWith: string) => - (path: string): string[] => { - const absolutePath = makePathAbsolute(path); - try { - const dirs = fs.readdirSync(absolutePath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()); - const dirsEndingWithSol = dirs.filter((dirent) => dirent.name.endsWith(endingWith)); - return dirsEndingWithSol.map((dirent) => dirent.name); - } catch (err) { - const msg = err instanceof Error ? err.message : 'Unknown error'; - throw new Error(`Failed to read directory: ${absolutePath} Error: ${msg}`); - } - }; + (endingWith: string) => + (path: string): string[] => { + const absolutePath = makePathAbsolute(path); + try { + const dirs = fs.readdirSync(absolutePath, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()); + const dirsEndingWithSol = dirs.filter((dirent) => dirent.name.endsWith(endingWith)); + return dirsEndingWithSol.map((dirent) => dirent.name); + } catch (err) { + const msg = err instanceof Error ? err.message : "Unknown error"; + throw new Error(`Failed to read directory: ${absolutePath} Error: ${msg}`); + } + }; -const SOLIDITY_ARTIFACTS_DIR = 'artifacts-zk'; +const SOLIDITY_ARTIFACTS_DIR = "artifacts-zk"; const getSolidityContractDetails = (dir: string, contractName: string): ContractDetails => { - const bytecodePath = join(SOLIDITY_ARTIFACTS_DIR, dir, contractName + '.sol', contractName + '.json'); - const sourceCodePath = join(dir, contractName + '.sol'); - return { - contractName, - bytecodePath, - sourceCodePath - }; + const bytecodePath = join(SOLIDITY_ARTIFACTS_DIR, dir, contractName + ".sol", contractName + ".json"); + const sourceCodePath = join(dir, contractName + ".sol"); + return { + contractName, + bytecodePath, + sourceCodePath, + }; }; const getSolidityContractsDetails = (dir: string): ContractDetails[] => { - const bytecodesDir = join(SOLIDITY_ARTIFACTS_DIR, dir); - const dirsEndingWithSol = findDirsEndingWith('.sol')(bytecodesDir); - const contractNames = dirsEndingWithSol.map((d) => d.replace('.sol', '')); - const solidityContractsDetails = contractNames.map((c) => getSolidityContractDetails(dir, c)); - return solidityContractsDetails; + const bytecodesDir = join(SOLIDITY_ARTIFACTS_DIR, dir); + const dirsEndingWithSol = findDirsEndingWith(".sol")(bytecodesDir); + const contractNames = dirsEndingWithSol.map((d) => d.replace(".sol", "")); + const solidityContractsDetails = contractNames.map((c) => getSolidityContractDetails(dir, c)); + return solidityContractsDetails; }; -const YUL_ARTIFACTS_DIR = 'artifacts'; +const YUL_ARTIFACTS_DIR = "artifacts"; const getYulContractDetails = (dir: string, contractName: string): ContractDetails => { - const bytecodePath = join(dir, YUL_ARTIFACTS_DIR, contractName + '.yul', contractName + '.yul.zbin'); - const sourceCodePath = join(dir, contractName + '.yul'); - return { - contractName, - bytecodePath, - sourceCodePath - }; + const bytecodePath = join(dir, YUL_ARTIFACTS_DIR, contractName + ".yul", contractName + ".yul.zbin"); + const sourceCodePath = join(dir, contractName + ".yul"); + return { + contractName, + bytecodePath, + sourceCodePath, + }; }; const getYulContractsDetails = (dir: string): ContractDetails[] => { - const bytecodesDir = join(dir, YUL_ARTIFACTS_DIR); - const dirsEndingWithYul = findDirsEndingWith('.yul')(bytecodesDir); - const contractNames = dirsEndingWithYul.map((d) => d.replace('.yul', '')); - const yulContractsDetails = contractNames.map((c) => getYulContractDetails(dir, c)); - return yulContractsDetails; + const bytecodesDir = join(dir, YUL_ARTIFACTS_DIR); + const dirsEndingWithYul = findDirsEndingWith(".yul")(bytecodesDir); + const contractNames = dirsEndingWithYul.map((d) => d.replace(".yul", "")); + const yulContractsDetails = contractNames.map((c) => getYulContractDetails(dir, c)); + return yulContractsDetails; }; const makePathAbsolute = (path: string): string => { - return join(__dirname, '..', path); + return join(__dirname, "..", path); }; const readSourceCode = (details: ContractDetails): string => { - const absolutePath = makePathAbsolute(details.sourceCodePath); - try { - return ethers.utils.hexlify(fs.readFileSync(absolutePath)); - } catch (err) { - const msg = err instanceof Error ? err.message : 'Unknown error'; - throw new Error(`Failed to read source code for ${details.contractName}: ${absolutePath} Error: ${msg}`); - } + const absolutePath = makePathAbsolute(details.sourceCodePath); + try { + return ethers.utils.hexlify(fs.readFileSync(absolutePath)); + } catch (err) { + const msg = err instanceof Error ? err.message : "Unknown error"; + throw new Error(`Failed to read source code for ${details.contractName}: ${absolutePath} Error: ${msg}`); + } }; const readBytecode = (details: ContractDetails): string => { - const absolutePath = makePathAbsolute(details.bytecodePath); - try { - if (details.bytecodePath.endsWith('.json')) { - const jsonFile = fs.readFileSync(absolutePath, 'utf8'); - return ethers.utils.hexlify(JSON.parse(jsonFile).bytecode); - } else { - return ethers.utils.hexlify(fs.readFileSync(absolutePath)); - } - } catch (err) { - const msg = err instanceof Error ? err.message : 'Unknown error'; - throw new Error(`Failed to read bytecode for ${details.contractName}: ${details.bytecodePath} Error: ${msg}`); + const absolutePath = makePathAbsolute(details.bytecodePath); + try { + if (details.bytecodePath.endsWith(".json")) { + const jsonFile = fs.readFileSync(absolutePath, "utf8"); + return ethers.utils.hexlify(JSON.parse(jsonFile).bytecode); + } else { + return ethers.utils.hexlify(fs.readFileSync(absolutePath)); } + } catch (err) { + const msg = err instanceof Error ? err.message : "Unknown error"; + throw new Error(`Failed to read bytecode for ${details.contractName}: ${details.bytecodePath} Error: ${msg}`); + } }; const getHashes = (contractName: string, sourceCode: string, bytecode: string): Hashes => { - try { - return { - bytecodeHash: ethers.utils.hexlify(hashBytecode(bytecode)), - // The extra checks performed by the hashBytecode function are not needed for the source code, therefore - // sha256 is used for simplicity - sourceCodeHash: ethers.utils.sha256(sourceCode) - }; - } catch (err) { - const msg = err instanceof Error ? err.message : 'Unknown error'; - throw new Error(`Failed to calculate hashes for ${contractName} Error: ${msg}`); - } + try { + return { + bytecodeHash: ethers.utils.hexlify(hashBytecode(bytecode)), + // The extra checks performed by the hashBytecode function are not needed for the source code, therefore + // sha256 is used for simplicity + sourceCodeHash: ethers.utils.sha256(sourceCode), + }; + } catch (err) { + const msg = err instanceof Error ? err.message : "Unknown error"; + throw new Error(`Failed to calculate hashes for ${contractName} Error: ${msg}`); + } }; const getSystemContractsHashes = (systemContractsDetails: ContractDetails[]): SystemContractHashes[] => - systemContractsDetails.map((contractDetails) => { - const sourceCode = readSourceCode(contractDetails); - const bytecode = readBytecode(contractDetails); - const hashes = getHashes(contractDetails.contractName, sourceCode, bytecode); - - const systemContractHashes: SystemContractHashes = { - ...contractDetails, - ...hashes - }; + systemContractsDetails.map((contractDetails) => { + const sourceCode = readSourceCode(contractDetails); + const bytecode = readBytecode(contractDetails); + const hashes = getHashes(contractDetails.contractName, sourceCode, bytecode); + + const systemContractHashes: SystemContractHashes = { + ...contractDetails, + ...hashes, + }; - return systemContractHashes; - }); + return systemContractHashes; + }); const readSystemContractsHashesFile = (path: string): SystemContractHashes[] => { - const absolutePath = makePathAbsolute(path); - try { - const file = fs.readFileSync(absolutePath, 'utf8'); - const parsedFile = JSON.parse(file); - return parsedFile; - } catch (err) { - const msg = err instanceof Error ? err.message : 'Unknown error'; - throw new Error(`Failed to read file: ${absolutePath} Error: ${msg}`); - } + const absolutePath = makePathAbsolute(path); + try { + const file = fs.readFileSync(absolutePath, "utf8"); + const parsedFile = JSON.parse(file); + return parsedFile; + } catch (err) { + const msg = err instanceof Error ? err.message : "Unknown error"; + throw new Error(`Failed to read file: ${absolutePath} Error: ${msg}`); + } }; const saveSystemContractsHashesFile = (path: string, systemContractsHashes: SystemContractHashes[]) => { - const absolutePath = makePathAbsolute(path); - try { - fs.writeFileSync(absolutePath, JSON.stringify(systemContractsHashes, null, 2) + os.EOL); - } catch (err) { - const msg = err instanceof Error ? err.message : 'Unknown error'; - throw new Error(`Failed to save file: ${absolutePath} Error: ${msg}`); - } + const absolutePath = makePathAbsolute(path); + try { + fs.writeFileSync(absolutePath, JSON.stringify(systemContractsHashes, null, 2) + os.EOL); + } catch (err) { + const msg = err instanceof Error ? err.message : "Unknown error"; + throw new Error(`Failed to save file: ${absolutePath} Error: ${msg}`); + } }; const findDifferences = (newHashes: SystemContractHashes[], oldHashes: SystemContractHashes[]) => { - const differentElements = _.xorWith(newHashes, oldHashes, _.isEqual); + const differentElements = _.xorWith(newHashes, oldHashes, _.isEqual); - const differentUniqueElements = _.uniqWith(differentElements, (a, b) => a.contractName === b.contractName); + const differentUniqueElements = _.uniqWith(differentElements, (a, b) => a.contractName === b.contractName); - const differencesList = differentUniqueElements.map((diffElem) => { - const newHashesElem = newHashes.find((elem) => elem.contractName === diffElem.contractName); + const differencesList = differentUniqueElements.map((diffElem) => { + const newHashesElem = newHashes.find((elem) => elem.contractName === diffElem.contractName); - const oldHashesElem = oldHashes.find((elem) => elem.contractName === diffElem.contractName); + const oldHashesElem = oldHashes.find((elem) => elem.contractName === diffElem.contractName); - const differingFields = _.xorWith( - Object.entries(newHashesElem || {}), - Object.entries(oldHashesElem || {}), - _.isEqual - ); + const differingFields = _.xorWith( + Object.entries(newHashesElem || {}), + Object.entries(oldHashesElem || {}), + _.isEqual + ); - const differingFieldsUniqueKeys = _.uniq(differingFields.map(([key]) => key)); + const differingFieldsUniqueKeys = _.uniq(differingFields.map(([key]) => key)); - return { - contract: diffElem.contractName, - differingFields: differingFieldsUniqueKeys, - old: oldHashesElem || {}, - new: newHashesElem || {} - }; - }); + return { + contract: diffElem.contractName, + differingFields: differingFieldsUniqueKeys, + old: oldHashesElem || {}, + new: newHashesElem || {}, + }; + }); - return differencesList; + return differencesList; }; -const SOLIDITY_SOURCE_CODE_PATHS = ['cache-zk/solpp-generated-contracts']; -const YUL_SOURCE_CODE_PATHS = ['contracts', 'contracts/precompiles', 'bootloader/build']; -const OUTPUT_FILE_PATH = 'SystemContractsHashes.json'; +const SOLIDITY_SOURCE_CODE_PATHS = ["cache-zk/solpp-generated-contracts"]; +const YUL_SOURCE_CODE_PATHS = ["contracts", "contracts/precompiles", "bootloader/build"]; +const OUTPUT_FILE_PATH = "SystemContractsHashes.json"; const main = async () => { - const args = process.argv; - if (args.length > 3 || (args.length == 3 && !args.includes('--check-only'))) { - console.log( - 'This command can be used with no arguments or with the --check-only flag. Use the --check-only flag to check the hashes without updating the SystemContractsHashes.json file.' - ); - process.exit(1); - } - const checkOnly = args.includes('--check-only'); - - const solidityContractsDetails = _.flatten(SOLIDITY_SOURCE_CODE_PATHS.map(getSolidityContractsDetails)); - const yulContractsDetails = _.flatten(YUL_SOURCE_CODE_PATHS.map(getYulContractsDetails)); - const systemContractsDetails = [...solidityContractsDetails, ...yulContractsDetails]; - - const newSystemContractsHashes = getSystemContractsHashes(systemContractsDetails); - const oldSystemContractsHashes = readSystemContractsHashesFile(OUTPUT_FILE_PATH); - if (_.isEqual(newSystemContractsHashes, oldSystemContractsHashes)) { - console.log('Calculated hashes match the hashes in the SystemContractsHashes.json file.'); - console.log('Exiting...'); - return; - } - const differences = findDifferences(newSystemContractsHashes, oldSystemContractsHashes); - console.log('Calculated hashes differ from the hashes in the SystemContractsHashes.json file. Differences:'); - console.log(differences); - if (checkOnly) { - console.log('You can use the `yarn calculate-hashes` command to update the SystemContractsHashes.json file.'); - console.log('Exiting...'); - process.exit(1); - } else { - console.log('Updating...'); - saveSystemContractsHashesFile(OUTPUT_FILE_PATH, newSystemContractsHashes); - console.log('Update finished'); - console.log('Exiting...'); - return; - } + const args = process.argv; + if (args.length > 3 || (args.length == 3 && !args.includes("--check-only"))) { + console.log( + "This command can be used with no arguments or with the --check-only flag. Use the --check-only flag to check the hashes without updating the SystemContractsHashes.json file." + ); + process.exit(1); + } + const checkOnly = args.includes("--check-only"); + + const solidityContractsDetails = _.flatten(SOLIDITY_SOURCE_CODE_PATHS.map(getSolidityContractsDetails)); + const yulContractsDetails = _.flatten(YUL_SOURCE_CODE_PATHS.map(getYulContractsDetails)); + const systemContractsDetails = [...solidityContractsDetails, ...yulContractsDetails]; + + const newSystemContractsHashes = getSystemContractsHashes(systemContractsDetails); + const oldSystemContractsHashes = readSystemContractsHashesFile(OUTPUT_FILE_PATH); + if (_.isEqual(newSystemContractsHashes, oldSystemContractsHashes)) { + console.log("Calculated hashes match the hashes in the SystemContractsHashes.json file."); + console.log("Exiting..."); + return; + } + const differences = findDifferences(newSystemContractsHashes, oldSystemContractsHashes); + console.log("Calculated hashes differ from the hashes in the SystemContractsHashes.json file. Differences:"); + console.log(differences); + if (checkOnly) { + console.log("You can use the `yarn calculate-hashes:fix` command to update the SystemContractsHashes.json file."); + console.log("Exiting..."); + process.exit(1); + } else { + console.log("Updating..."); + saveSystemContractsHashesFile(OUTPUT_FILE_PATH, newSystemContractsHashes); + console.log("Update finished"); + console.log("Exiting..."); + return; + } }; main() - .then(() => process.exit(0)) - .catch((err) => { - console.error('Error:', err.message || err); - console.log( - 'Please make sure to run `yarn build && yarn preprocess && yarn compile-yul` before running this script.' - ); - process.exit(1); - }); + .then(() => process.exit(0)) + .catch((err) => { + console.error("Error:", err.message || err); + console.log("Please make sure to run `yarn build` before running this script."); + process.exit(1); + }); diff --git a/scripts/compile-yul.ts b/scripts/compile-yul.ts index 5fe84278f5c..51b91977ae8 100644 --- a/scripts/compile-yul.ts +++ b/scripts/compile-yul.ts @@ -1,100 +1,100 @@ -import * as hre from 'hardhat'; +import * as hre from "hardhat"; -import { getZksolcUrl, saltFromUrl } from '@matterlabs/hardhat-zksync-solc'; -import { spawn as _spawn } from 'child_process'; -import * as fs from 'fs'; -import { getCompilersDir } from 'hardhat/internal/util/global-dir'; -import path from 'path'; +import { getZksolcUrl, saltFromUrl } from "@matterlabs/hardhat-zksync-solc"; +import { spawn as _spawn } from "child_process"; +import * as fs from "fs"; +import { getCompilersDir } from "hardhat/internal/util/global-dir"; +import path from "path"; -const COMPILER_VERSION = '1.3.14'; +const COMPILER_VERSION = "1.3.14"; const IS_COMPILER_PRE_RELEASE = false; async function compilerLocation(): Promise { - const compilersCache = await getCompilersDir(); + const compilersCache = await getCompilersDir(); - let salt = ''; + let salt = ""; - if (IS_COMPILER_PRE_RELEASE) { - const url = getZksolcUrl('https://github.com/matter-labs/zksolc-prerelease', hre.config.zksolc.version); - salt = saltFromUrl(url); - } + if (IS_COMPILER_PRE_RELEASE) { + const url = getZksolcUrl("https://github.com/matter-labs/zksolc-prerelease", hre.config.zksolc.version); + salt = saltFromUrl(url); + } - return path.join(compilersCache, 'zksolc', `zksolc-v${COMPILER_VERSION}${salt ? '-' : ''}${salt}`); + return path.join(compilersCache, "zksolc", `zksolc-v${COMPILER_VERSION}${salt ? "-" : ""}${salt}`); } // executes a command in a new shell // but pipes data to parent's stdout/stderr export function spawn(command: string) { - command = command.replace(/\n/g, ' '); - const child = _spawn(command, { stdio: 'inherit', shell: true }); - return new Promise((resolve, reject) => { - child.on('error', reject); - child.on('close', (code) => { - code == 0 ? resolve(code) : reject(`Child process exited with code ${code}`); - }); + command = command.replace(/\n/g, " "); + const child = _spawn(command, { stdio: "inherit", shell: true }); + return new Promise((resolve, reject) => { + child.on("error", reject); + child.on("close", (code) => { + code == 0 ? resolve(code) : reject(`Child process exited with code ${code}`); }); + }); } export async function compileYul(path: string, files: string[], outputDirName: string | null) { - if (!files.length) { - console.log(`No test files provided in folder ${path}.`); - return; - } - const paths = preparePaths(path, files, outputDirName); - - const zksolcLocation = await compilerLocation(); - await spawn( - `${zksolcLocation} ${paths.absolutePathSources}/${paths.outputDir} --optimization 3 --system-mode --yul --bin --overwrite -o ${paths.absolutePathArtifacts}/${paths.outputDir}` - ); + if (!files.length) { + console.log(`No test files provided in folder ${path}.`); + return; + } + const paths = preparePaths(path, files, outputDirName); + + const zksolcLocation = await compilerLocation(); + await spawn( + `${zksolcLocation} ${paths.absolutePathSources}/${paths.outputDir} --optimization 3 --system-mode --yul --bin --overwrite -o ${paths.absolutePathArtifacts}/${paths.outputDir}` + ); } export async function compileYulFolder(path: string) { - const files: string[] = (await fs.promises.readdir(path)).filter((fn) => fn.endsWith('.yul')); - for (const file of files) { - await compileYul(path, [file], `${file}`); - } + const files: string[] = (await fs.promises.readdir(path)).filter((fn) => fn.endsWith(".yul")); + for (const file of files) { + await compileYul(path, [file], `${file}`); + } } function preparePaths(path: string, files: string[], outputDirName: string | null): CompilerPaths { - const filePaths = files - .map((val) => { - return `sources/${val}`; - }) - .join(' '); - const currentWorkingDirectory = process.cwd(); - console.log(`Yarn project directory: ${currentWorkingDirectory}`); - - const outputDir = outputDirName || files[0]; - // This script is located in `system-contracts/scripts`, so we get one directory back. - const absolutePathSources = `${__dirname}/../${path}`; - const absolutePathArtifacts = `${__dirname}/../${path}/artifacts`; - - return new CompilerPaths(filePaths, outputDir, absolutePathSources, absolutePathArtifacts); + const filePaths = files + .map((val) => { + return `sources/${val}`; + }) + .join(" "); + const currentWorkingDirectory = process.cwd(); + console.log(`Yarn project directory: ${currentWorkingDirectory}`); + + const outputDir = outputDirName || files[0]; + // This script is located in `system-contracts/scripts`, so we get one directory back. + const absolutePathSources = `${__dirname}/../${path}`; + const absolutePathArtifacts = `${__dirname}/../${path}/artifacts`; + + return new CompilerPaths(filePaths, outputDir, absolutePathSources, absolutePathArtifacts); } class CompilerPaths { - public filePath: string; - public outputDir: string; - public absolutePathSources: string; - public absolutePathArtifacts: string; - constructor(filePath: string, outputDir: string, absolutePathSources: string, absolutePathArtifacts: string) { - this.filePath = filePath; - this.outputDir = outputDir; - this.absolutePathSources = absolutePathSources; - this.absolutePathArtifacts = absolutePathArtifacts; - } + public filePath: string; + public outputDir: string; + public absolutePathSources: string; + public absolutePathArtifacts: string; + constructor(filePath: string, outputDir: string, absolutePathSources: string, absolutePathArtifacts: string) { + this.filePath = filePath; + this.outputDir = outputDir; + this.absolutePathSources = absolutePathSources; + this.absolutePathArtifacts = absolutePathArtifacts; + } } async function main() { - await compileYulFolder('contracts'); - await compileYulFolder('contracts/precompiles'); - await compileYulFolder('bootloader/build'); - await compileYulFolder('bootloader/tests'); + await compileYulFolder("contracts"); + await compileYulFolder("contracts/precompiles"); + await compileYulFolder("bootloader/build"); + await compileYulFolder("bootloader/tests"); } main() - .then(() => process.exit(0)) - .catch((err) => { - console.error('Error:', err.message || err); - process.exit(1); - }); + .then(() => process.exit(0)) + .catch((err) => { + console.error("Error:", err.message || err); + process.exit(1); + }); diff --git a/scripts/constants.ts b/scripts/constants.ts index 4bb1a5b5d50..dd089d97cb3 100644 --- a/scripts/constants.ts +++ b/scripts/constants.ts @@ -1,128 +1,129 @@ -import { BigNumberish, BytesLike, constants, ethers } from 'ethers'; +import type { BigNumberish, BytesLike } from "ethers"; +import { constants, ethers } from "ethers"; -export const BOOTLOADER_FORMAL_ADDRESS = '0x0000000000000000000000000000000000008001'; +export const BOOTLOADER_FORMAL_ADDRESS = "0x0000000000000000000000000000000000008001"; export const ETH_ADDRESS = constants.AddressZero; export enum Language { - Solidity = 'solidity', - Yul = 'yul' + Solidity = "solidity", + Yul = "yul", } export interface SystemContractDescription { - address: string; - codeName: string; + address: string; + codeName: string; } export interface YulContractDescrption extends SystemContractDescription { - lang: Language.Yul; - path: string; + lang: Language.Yul; + path: string; } export interface SolidityContractDescription extends SystemContractDescription { - lang: Language.Solidity; + lang: Language.Solidity; } interface ISystemContracts { - [key: string]: YulContractDescrption | SolidityContractDescription; + [key: string]: YulContractDescrption | SolidityContractDescription; } export const SYSTEM_CONTRACTS: ISystemContracts = { - zeroAddress: { - // zero address has EmptyContract code - address: '0x0000000000000000000000000000000000000000', - codeName: 'EmptyContract', - lang: Language.Solidity - }, - ecrecover: { - address: '0x0000000000000000000000000000000000000001', - codeName: 'Ecrecover', - lang: Language.Yul, - path: 'precompiles' - }, - sha256: { - address: '0x0000000000000000000000000000000000000002', - codeName: 'SHA256', - lang: Language.Yul, - path: 'precompiles' - }, - bootloader: { - // Bootloader has EmptyContract code - address: '0x0000000000000000000000000000000000008001', - codeName: 'EmptyContract', - lang: Language.Solidity - }, - accountCodeStorage: { - address: '0x0000000000000000000000000000000000008002', - codeName: 'AccountCodeStorage', - lang: Language.Solidity - }, - nonceHolder: { - address: '0x0000000000000000000000000000000000008003', - codeName: 'NonceHolder', - lang: Language.Solidity - }, - knownCodesStorage: { - address: '0x0000000000000000000000000000000000008004', - codeName: 'KnownCodesStorage', - lang: Language.Solidity - }, - immutableSimulator: { - address: '0x0000000000000000000000000000000000008005', - codeName: 'ImmutableSimulator', - lang: Language.Solidity - }, - contractDeployer: { - address: '0x0000000000000000000000000000000000008006', - codeName: 'ContractDeployer', - lang: Language.Solidity - }, - l1Messenger: { - address: '0x0000000000000000000000000000000000008008', - codeName: 'L1Messenger', - lang: Language.Solidity - }, - msgValueSimulator: { - address: '0x0000000000000000000000000000000000008009', - codeName: 'MsgValueSimulator', - lang: Language.Solidity - }, - l2EthToken: { - address: '0x000000000000000000000000000000000000800a', - codeName: 'L2EthToken', - lang: Language.Solidity - }, - systemContext: { - address: '0x000000000000000000000000000000000000800b', - codeName: 'SystemContext', - lang: Language.Solidity - }, - bootloaderUtilities: { - address: '0x000000000000000000000000000000000000800c', - codeName: 'BootloaderUtilities', - lang: Language.Solidity - }, - eventWriter: { - address: '0x000000000000000000000000000000000000800d', - codeName: 'EventWriter', - lang: Language.Yul, - path: '' - }, - compressor: { - address: '0x000000000000000000000000000000000000800e', - codeName: 'Compressor', - lang: Language.Solidity - }, - complexUpgrader: { - address: '0x000000000000000000000000000000000000800f', - codeName: 'ComplexUpgrader', - lang: Language.Solidity - }, - keccak256: { - address: '0x0000000000000000000000000000000000008010', - codeName: 'Keccak256', - lang: Language.Yul, - path: 'precompiles' - } + zeroAddress: { + // zero address has EmptyContract code + address: "0x0000000000000000000000000000000000000000", + codeName: "EmptyContract", + lang: Language.Solidity, + }, + ecrecover: { + address: "0x0000000000000000000000000000000000000001", + codeName: "Ecrecover", + lang: Language.Yul, + path: "precompiles", + }, + sha256: { + address: "0x0000000000000000000000000000000000000002", + codeName: "SHA256", + lang: Language.Yul, + path: "precompiles", + }, + bootloader: { + // Bootloader has EmptyContract code + address: "0x0000000000000000000000000000000000008001", + codeName: "EmptyContract", + lang: Language.Solidity, + }, + accountCodeStorage: { + address: "0x0000000000000000000000000000000000008002", + codeName: "AccountCodeStorage", + lang: Language.Solidity, + }, + nonceHolder: { + address: "0x0000000000000000000000000000000000008003", + codeName: "NonceHolder", + lang: Language.Solidity, + }, + knownCodesStorage: { + address: "0x0000000000000000000000000000000000008004", + codeName: "KnownCodesStorage", + lang: Language.Solidity, + }, + immutableSimulator: { + address: "0x0000000000000000000000000000000000008005", + codeName: "ImmutableSimulator", + lang: Language.Solidity, + }, + contractDeployer: { + address: "0x0000000000000000000000000000000000008006", + codeName: "ContractDeployer", + lang: Language.Solidity, + }, + l1Messenger: { + address: "0x0000000000000000000000000000000000008008", + codeName: "L1Messenger", + lang: Language.Solidity, + }, + msgValueSimulator: { + address: "0x0000000000000000000000000000000000008009", + codeName: "MsgValueSimulator", + lang: Language.Solidity, + }, + l2EthToken: { + address: "0x000000000000000000000000000000000000800a", + codeName: "L2EthToken", + lang: Language.Solidity, + }, + systemContext: { + address: "0x000000000000000000000000000000000000800b", + codeName: "SystemContext", + lang: Language.Solidity, + }, + bootloaderUtilities: { + address: "0x000000000000000000000000000000000000800c", + codeName: "BootloaderUtilities", + lang: Language.Solidity, + }, + eventWriter: { + address: "0x000000000000000000000000000000000000800d", + codeName: "EventWriter", + lang: Language.Yul, + path: "", + }, + compressor: { + address: "0x000000000000000000000000000000000000800e", + codeName: "Compressor", + lang: Language.Solidity, + }, + complexUpgrader: { + address: "0x000000000000000000000000000000000000800f", + codeName: "ComplexUpgrader", + lang: Language.Solidity, + }, + keccak256: { + address: "0x0000000000000000000000000000000000008010", + codeName: "Keccak256", + lang: Language.Yul, + path: "precompiles", + }, } as const; export const EIP712_TX_ID = 113; @@ -130,125 +131,125 @@ export const CHAIN_ID = 270; // For now, these types are hardcoded, but maybe it will make sense export const EIP712_DOMAIN = { - name: 'zkSync', - version: '2', - chainId: CHAIN_ID - // zkSync contract doesn't verify EIP712 signatures. + name: "zkSync", + version: "2", + chainId: CHAIN_ID, + // zkSync contract doesn't verify EIP712 signatures. }; export interface TransactionData { - txType: BigNumberish; - from: BigNumberish; - to: BigNumberish; - gasLimit: BigNumberish; - gasPerPubdataByteLimit: BigNumberish; - gasPrice: BigNumberish; - // In the future, we might want to add some - // new fields to the struct. The `txData` struct - // is to be passed to account and any changes to its structure - // would mean a breaking change to these accounts. In order to prevent this, - // we should keep some fields as "reserved". - // It is also recommended that their length is fixed, since - // it would allow easier proof integration (in case we will need - // some special circuit for preprocessing transactions). - reserved: BigNumberish[]; - data: BytesLike; - signature: BytesLike; - // Reserved dynamic type for the future use-case. Using it should be avoided, - // But it is still here, just in case we want to enable some additional functionality. - reservedDynamic: BytesLike; + txType: BigNumberish; + from: BigNumberish; + to: BigNumberish; + gasLimit: BigNumberish; + gasPerPubdataByteLimit: BigNumberish; + gasPrice: BigNumberish; + // In the future, we might want to add some + // new fields to the struct. The `txData` struct + // is to be passed to account and any changes to its structure + // would mean a breaking change to these accounts. In order to prevent this, + // we should keep some fields as "reserved". + // It is also recommended that their length is fixed, since + // it would allow easier proof integration (in case we will need + // some special circuit for preprocessing transactions). + reserved: BigNumberish[]; + data: BytesLike; + signature: BytesLike; + // Reserved dynamic type for the future use-case. Using it should be avoided, + // But it is still here, just in case we want to enable some additional functionality. + reservedDynamic: BytesLike; } export interface EIP712Tx { - txType: BigNumberish; - from: BigNumberish; - to: BigNumberish; - value: BigNumberish; - gasLimit: BigNumberish; - gasPerPubdataByteLimit: BigNumberish; - gasPrice: BigNumberish; - nonce: BigNumberish; - data: BytesLike; - signature: BytesLike; + txType: BigNumberish; + from: BigNumberish; + to: BigNumberish; + value: BigNumberish; + gasLimit: BigNumberish; + gasPerPubdataByteLimit: BigNumberish; + gasPrice: BigNumberish; + nonce: BigNumberish; + data: BytesLike; + signature: BytesLike; } export type Address = string; export const EIP712_TX_TYPE = { - Transaction: [ - { name: 'txType', type: 'uint8' }, - { name: 'to', type: 'uint256' }, - { name: 'value', type: 'uint256' }, - { name: 'data', type: 'bytes' }, - { name: 'gasLimit', type: 'uint256' }, - { name: 'gasPerPubdataByteLimit', type: 'uint256' }, - { name: 'gasPrice', type: 'uint256' }, - { name: 'nonce', type: 'uint256' } - ] + Transaction: [ + { name: "txType", type: "uint8" }, + { name: "to", type: "uint256" }, + { name: "value", type: "uint256" }, + { name: "data", type: "bytes" }, + { name: "gasLimit", type: "uint256" }, + { name: "gasPerPubdataByteLimit", type: "uint256" }, + { name: "gasPrice", type: "uint256" }, + { name: "nonce", type: "uint256" }, + ], }; -export type DynamicType = 'bytes' | 'bytes32[]'; -export type FixedType = 'address' | 'uint256' | 'uint128' | 'uint32'; +export type DynamicType = "bytes" | "bytes32[]"; +export type FixedType = "address" | "uint256" | "uint128" | "uint32"; export type FieldType = FixedType | DynamicType; function isDynamicType(x: FieldType): x is DynamicType { - return x == 'bytes' || x == 'bytes32[]'; + return x == "bytes" || x == "bytes32[]"; } function isFixedType(x: FieldType): x is FixedType { - return !isDynamicType(x); + return !isDynamicType(x); } export const TransactionFields: Record = { - txType: 'uint256', - from: 'address', - to: 'address', - gasLimit: 'uint32', - gasPerPubdataByteLimit: 'uint32', - maxFeePerGas: 'uint256', - maxPriorityFeePerGas: 'uint256', - paymaster: 'address', - // In the future, we might want to add some - // new fields to the struct. The `txData` struct - // is to be passed to account and any changes to its structure - // would mean a breaking change to these accounts. In order to prevent this, - // we should keep some fields as "reserved". - // It is also recommended that their length is fixed, since - // it would allow easier proof integration (in case we will need - // some special circuit for preprocessing transactions). - reserved: Array(6).fill('uint256'), - data: 'bytes', - signature: 'bytes', - factoryDeps: 'bytes32[]', - paymasterInput: 'bytes', - // Reserved dynamic type for the future use-case. Using it should be avoided, - // But it is still here, just in case we want to enable some additional functionality. - reservedDynamic: 'bytes' + txType: "uint256", + from: "address", + to: "address", + gasLimit: "uint32", + gasPerPubdataByteLimit: "uint32", + maxFeePerGas: "uint256", + maxPriorityFeePerGas: "uint256", + paymaster: "address", + // In the future, we might want to add some + // new fields to the struct. The `txData` struct + // is to be passed to account and any changes to its structure + // would mean a breaking change to these accounts. In order to prevent this, + // we should keep some fields as "reserved". + // It is also recommended that their length is fixed, since + // it would allow easier proof integration (in case we will need + // some special circuit for preprocessing transactions). + reserved: Array(6).fill("uint256"), + data: "bytes", + signature: "bytes", + factoryDeps: "bytes32[]", + paymasterInput: "bytes", + // Reserved dynamic type for the future use-case. Using it should be avoided, + // But it is still here, just in case we want to enable some additional functionality. + reservedDynamic: "bytes", }; function capitalize(s: string) { - if (!s.length) { - return s; - } - return `${s[0].toUpperCase()}${s.substring(1)}`; + if (!s.length) { + return s; + } + return `${s[0].toUpperCase()}${s.substring(1)}`; } function memPosFromOffset(offset: number) { - return offset === 0 ? 'innerTxDataOffset' : `add(innerTxDataOffset, ${offset})`; + return offset === 0 ? "innerTxDataOffset" : `add(innerTxDataOffset, ${offset})`; } function getGetterName(fieldName: string) { - return `get${capitalize(fieldName)}`; + return `get${capitalize(fieldName)}`; } function getPtrGetterName(fieldName: string) { - return `get${capitalize(fieldName)}Ptr`; + return `get${capitalize(fieldName)}Ptr`; } function getGetter(fieldName: string, offset: number) { - const getterName = getGetterName(fieldName); - const memPos = memPosFromOffset(offset); - return ` + const getterName = getGetterName(fieldName); + const memPos = memPosFromOffset(offset); + return ` function ${getterName}(innerTxDataOffset) -> ret { ret := mload(${memPos}) } @@ -256,9 +257,9 @@ function getGetter(fieldName: string, offset: number) { } function getPtrGetter(fieldName: string, offset: number) { - const getterName = getPtrGetterName(fieldName); - const memPos = memPosFromOffset(offset); - return ` + const getterName = getPtrGetterName(fieldName); + const memPos = memPosFromOffset(offset); + return ` function ${getterName}(innerTxDataOffset) -> ret { ret := mload(${memPos}) ret := add(innerTxDataOffset, ret) @@ -267,29 +268,29 @@ function getPtrGetter(fieldName: string, offset: number) { } function getTypeValidationMethodName(type: FieldType) { - if (type == 'bytes32[]') { - return 'validateBytes32Array'; - } else { - return `validate${capitalize(type)}`; - } + if (type == "bytes32[]") { + return "validateBytes32Array"; + } else { + return `validate${capitalize(type)}`; + } } function getBytesLengthGetterName(fieldName: string): string { - return `get${capitalize(fieldName)}BytesLength`; + return `get${capitalize(fieldName)}BytesLength`; } function getBytesLengthGetter(fieldName: string, type: DynamicType) { - let lengthToBytes: string; - if (type == 'bytes') { - lengthToBytes = `lengthToWords(mload(ptr))`; - } else if (type == 'bytes32[]') { - lengthToBytes = `mul(mload(ptr),32)`; - } else { - throw new Error(`Type ${type} is not supported`); - } - - const getterName = getBytesLengthGetterName(fieldName); - return ` + let lengthToBytes: string; + if (type == "bytes") { + lengthToBytes = "lengthToWords(mload(ptr))"; + } else if (type == "bytes32[]") { + lengthToBytes = "mul(mload(ptr),32)"; + } else { + throw new Error(`Type ${type} is not supported`); + } + + const getterName = getBytesLengthGetterName(fieldName); + return ` function ${getterName}(innerTxDataOffset) -> ret { let ptr := ${getPtrGetterName(fieldName)}(innerTxDataOffset) ret := ${lengthToBytes} @@ -298,14 +299,14 @@ function getBytesLengthGetter(fieldName: string, type: DynamicType) { } function getDataLength(baseLength: number, dynamicFields: [string, DynamicType][]) { - const ptrAdders = dynamicFields - .map(([fieldName]) => { - return ` + const ptrAdders = dynamicFields + .map(([fieldName]) => { + return ` ret := add(ret, ${getBytesLengthGetterName(fieldName)}(innerTxDataOffset))`; - }) - .join(''); + }) + .join(""); - return ` + return ` function getDataLength(innerTxDataOffset) -> ret { // To get the length of the txData in bytes, we can simply // get the number of fields * 32 + the length of the dynamic types @@ -318,13 +319,13 @@ function getDataLength(baseLength: number, dynamicFields: [string, DynamicType][ } function validateFixedSizeField(fieldName: string, type: FixedType): string { - if (type == 'uint256') { - // There is no validation for uint256 - return ``; - } - const assertionErrorStr = getEncodingError(fieldName); - const fieldValue = `${fieldName}Value`; - return ` + if (type == "uint256") { + // There is no validation for uint256 + return ""; + } + const assertionErrorStr = getEncodingError(fieldName); + const fieldValue = `${fieldName}Value`; + return ` let ${fieldValue} := ${getGetterName(fieldName)}(innerTxDataOffset) if iszero(${getTypeValidationMethodName(type)}(${fieldValue})) { assertionError("${assertionErrorStr}") @@ -333,39 +334,39 @@ function validateFixedSizeField(fieldName: string, type: FixedType): string { } function getEncodingError(fieldName: string) { - // Unfortunately we have to keep this not-so-readable name - // because the maximum length is 32. - const assertionError = `Encoding ${fieldName}`; + // Unfortunately we have to keep this not-so-readable name + // because the maximum length is 32. + const assertionError = `Encoding ${fieldName}`; - if (assertionError.length > 32) { - throw new Error(`Assertion str too long: ${assertionError}`); - } + if (assertionError.length > 32) { + throw new Error(`Assertion str too long: ${assertionError}`); + } - return assertionError; + return assertionError; } function getValidateTxStructure( - fixedFieldsChecks: string, - fixedLenPart: number, - dynamicFields: [string, DynamicType][] + fixedFieldsChecks: string, + fixedLenPart: number, + dynamicFields: [string, DynamicType][] ): string { - const dynamicChecks = dynamicFields - .map(([fieldName, type]) => { - const lengthPos = `${fieldName}LengthPos`; - const assertionError = getEncodingError(fieldName); - const validationMethod = getTypeValidationMethodName(type); + const dynamicChecks = dynamicFields + .map(([fieldName, type]) => { + const lengthPos = `${fieldName}LengthPos`; + const assertionError = getEncodingError(fieldName); + const validationMethod = getTypeValidationMethodName(type); - return ` + return ` let ${lengthPos} := ${getPtrGetterName(fieldName)}(innerTxDataOffset) if iszero(eq(${lengthPos}, expectedDynamicLenPtr)) { assertionError("${assertionError}") } expectedDynamicLenPtr := ${validationMethod}(${lengthPos}) `; - }) - .join('\n'); + }) + .join("\n"); - return ` + return ` /// This method checks that the transaction's structure is correct /// and tightly packed function validateAbiEncoding(innerTxDataOffset) -> ret { @@ -377,42 +378,42 @@ function getValidateTxStructure( } export function getTransactionUtils(): string { - let result = `/// + let result = `/// /// TransactionData utilities ///\n`; - let innerOffsetBytes = 0; - let checksStr = ``; - - const dynamicFields: [string, DynamicType][] = []; - for (const [key, value] of Object.entries(TransactionFields)) { - if (Array.isArray(value)) { - // We assume that the - for (let i = 0; i < value.length; i++) { - const keyName = `${key}${i}`; - result += getGetter(keyName, innerOffsetBytes); - checksStr += validateFixedSizeField(keyName, value[i]); - innerOffsetBytes += 32; - } - } else if (isFixedType(value)) { - result += getGetter(key, innerOffsetBytes); - checksStr += validateFixedSizeField(key, value); - innerOffsetBytes += 32; - } else { - result += getPtrGetter(key, innerOffsetBytes); - result += getBytesLengthGetter(key, value); - dynamicFields.push([key, value]); - innerOffsetBytes += 32; - } + let innerOffsetBytes = 0; + let checksStr = ""; + + const dynamicFields: [string, DynamicType][] = []; + for (const [key, value] of Object.entries(TransactionFields)) { + if (Array.isArray(value)) { + // We assume that the + for (let i = 0; i < value.length; i++) { + const keyName = `${key}${i}`; + result += getGetter(keyName, innerOffsetBytes); + checksStr += validateFixedSizeField(keyName, value[i]); + innerOffsetBytes += 32; + } + } else if (isFixedType(value)) { + result += getGetter(key, innerOffsetBytes); + checksStr += validateFixedSizeField(key, value); + innerOffsetBytes += 32; + } else { + result += getPtrGetter(key, innerOffsetBytes); + result += getBytesLengthGetter(key, value); + dynamicFields.push([key, value]); + innerOffsetBytes += 32; } + } - result += getValidateTxStructure(checksStr, innerOffsetBytes, dynamicFields); + result += getValidateTxStructure(checksStr, innerOffsetBytes, dynamicFields); - result += getDataLength(innerOffsetBytes, dynamicFields); + result += getDataLength(innerOffsetBytes, dynamicFields); - return result; + return result; } export function getRevertSelector(): string { - return ethers.utils.keccak256(ethers.utils.toUtf8Bytes('Error(string)')).substring(0, 10); + return ethers.utils.keccak256(ethers.utils.toUtf8Bytes("Error(string)")).substring(0, 10); } diff --git a/scripts/deploy-preimages.ts b/scripts/deploy-preimages.ts index 103f7d73530..716533c7dbc 100644 --- a/scripts/deploy-preimages.ts +++ b/scripts/deploy-preimages.ts @@ -1,312 +1,302 @@ -import * as hre from 'hardhat'; - -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; -import { Command } from 'commander'; -import { BigNumber, ethers } from 'ethers'; -import { formatUnits, parseUnits } from 'ethers/lib/utils'; -import * as fs from 'fs'; -import * as path from 'path'; -import { Provider, Wallet } from 'zksync-web3'; -import { hashBytecode } from 'zksync-web3/build/src/utils'; -import { Language, SYSTEM_CONTRACTS } from './constants'; -import { - Dependency, - DeployedDependency, - filterPublishedFactoryDeps, - publishFactoryDeps, - readYulBytecode -} from './utils'; - -const testConfigPath = path.join(process.env.ZKSYNC_HOME as string, `etc/test_config/constant`); -const ethTestConfig = JSON.parse(fs.readFileSync(`${testConfigPath}/eth.json`, { encoding: 'utf-8' })); +import * as hre from "hardhat"; + +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { Command } from "commander"; +import type { BigNumber } from "ethers"; +import { ethers } from "ethers"; +import { formatUnits, parseUnits } from "ethers/lib/utils"; +import * as fs from "fs"; +import * as path from "path"; +import { Provider, Wallet } from "zksync-web3"; +import { hashBytecode } from "zksync-web3/build/src/utils"; +import { Language, SYSTEM_CONTRACTS } from "./constants"; +import type { Dependency, DeployedDependency } from "./utils"; +import { filterPublishedFactoryDeps, publishFactoryDeps, readYulBytecode } from "./utils"; + +const testConfigPath = path.join(process.env.ZKSYNC_HOME as string, "etc/test_config/constant"); +const ethTestConfig = JSON.parse(fs.readFileSync(`${testConfigPath}/eth.json`, { encoding: "utf-8" })); // Maximum length of the combined length of dependencies const MAX_COMBINED_LENGTH = 90000; -const DEFAULT_ACCOUNT_CONTRACT_NAME = 'DefaultAccount'; -const BOOTLOADER_CONTRACT_NAME = 'Bootloader'; +const DEFAULT_ACCOUNT_CONTRACT_NAME = "DefaultAccount"; +const BOOTLOADER_CONTRACT_NAME = "Bootloader"; class ZkSyncDeployer { - deployer: Deployer; - gasPrice: BigNumber; - nonce: number; - dependenciesToUpgrade: DeployedDependency[]; - defaultAccountToUpgrade?: DeployedDependency; - bootloaderToUpgrade?: DeployedDependency; - constructor(deployer: Deployer, gasPrice: BigNumber, nonce: number) { - this.deployer = deployer; - this.gasPrice = gasPrice; - this.nonce = nonce; - this.dependenciesToUpgrade = []; + deployer: Deployer; + gasPrice: BigNumber; + nonce: number; + dependenciesToUpgrade: DeployedDependency[]; + defaultAccountToUpgrade?: DeployedDependency; + bootloaderToUpgrade?: DeployedDependency; + constructor(deployer: Deployer, gasPrice: BigNumber, nonce: number) { + this.deployer = deployer; + this.gasPrice = gasPrice; + this.nonce = nonce; + this.dependenciesToUpgrade = []; + } + + async publishFactoryDeps(dependencies: Dependency[]) { + await publishFactoryDeps(dependencies, this.deployer, this.nonce, this.gasPrice); + this.nonce += 1; + } + + // Returns the current default account bytecode on zkSync + async currentDefaultAccountBytecode(): Promise { + const zkSync = await this.deployer.zkWallet.getMainContract(); + return await zkSync.getL2DefaultAccountBytecodeHash(); + } + + // If needed, appends the default account bytecode to the upgrade + async checkShouldUpgradeDefaultAA(defaultAccountBytecode: string) { + 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 (bytecodeHash.toLowerCase() !== currentDefaultAccountBytecode) { + this.defaultAccountToUpgrade = { + name: DEFAULT_ACCOUNT_CONTRACT_NAME, + bytecodeHashes: [bytecodeHash], + }; } - - async publishFactoryDeps(dependencies: Dependency[]) { - await publishFactoryDeps(dependencies, this.deployer, this.nonce, this.gasPrice); - this.nonce += 1; - } - - // Returns the current default account bytecode on zkSync - async currentDefaultAccountBytecode(): Promise { - const zkSync = await this.deployer.zkWallet.getMainContract(); - return await zkSync.getL2DefaultAccountBytecodeHash(); - } - - // If needed, appends the default account bytecode to the upgrade - async checkShouldUpgradeDefaultAA(defaultAccountBytecode: string) { - 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 (bytecodeHash.toLowerCase() !== currentDefaultAccountBytecode) { - this.defaultAccountToUpgrade = { - name: DEFAULT_ACCOUNT_CONTRACT_NAME, - bytecodeHashes: [bytecodeHash] - }; - } - } - - // Publish default account bytecode - async publishDefaultAA(defaultAccountBytecode: string) { - const [defaultAccountBytecodes] = await filterPublishedFactoryDeps( - DEFAULT_ACCOUNT_CONTRACT_NAME, - [defaultAccountBytecode], - this.deployer - ); - - if (defaultAccountBytecodes.length == 0) { - console.log('Default account bytecode is already published, skipping'); - return; - } - - await this.publishFactoryDeps([ - { - name: DEFAULT_ACCOUNT_CONTRACT_NAME, - bytecodes: defaultAccountBytecodes - } - ]); - this.nonce += 1; - } - - // Publishes the bytecode of default AA and appends it to the deployed bytecodes if needed. - async processDefaultAA() { - const defaultAccountBytecode = (await this.deployer.loadArtifact(DEFAULT_ACCOUNT_CONTRACT_NAME)).bytecode; - - await this.publishDefaultAA(defaultAccountBytecode); - await this.checkShouldUpgradeDefaultAA(defaultAccountBytecode); - } - - async currentBootloaderBytecode(): Promise { - const zkSync = await this.deployer.zkWallet.getMainContract(); - return await zkSync.getL2BootloaderBytecodeHash(); + } + + // Publish default account bytecode + async publishDefaultAA(defaultAccountBytecode: string) { + const [defaultAccountBytecodes] = await filterPublishedFactoryDeps( + DEFAULT_ACCOUNT_CONTRACT_NAME, + [defaultAccountBytecode], + this.deployer + ); + + if (defaultAccountBytecodes.length == 0) { + console.log("Default account bytecode is already published, skipping"); + return; } - async checkShouldUpgradeBootloader(bootloaderCode: string) { - 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 (bytecodeHash.toLowerCase() !== currentBootloaderBytecode) { - this.bootloaderToUpgrade = { - name: BOOTLOADER_CONTRACT_NAME, - bytecodeHashes: [bytecodeHash] - }; - } + await this.publishFactoryDeps([ + { + name: DEFAULT_ACCOUNT_CONTRACT_NAME, + bytecodes: defaultAccountBytecodes, + }, + ]); + this.nonce += 1; + } + + // Publishes the bytecode of default AA and appends it to the deployed bytecodes if needed. + async processDefaultAA() { + const defaultAccountBytecode = (await this.deployer.loadArtifact(DEFAULT_ACCOUNT_CONTRACT_NAME)).bytecode; + + await this.publishDefaultAA(defaultAccountBytecode); + await this.checkShouldUpgradeDefaultAA(defaultAccountBytecode); + } + + async currentBootloaderBytecode(): Promise { + const zkSync = await this.deployer.zkWallet.getMainContract(); + return await zkSync.getL2BootloaderBytecodeHash(); + } + + async checkShouldUpgradeBootloader(bootloaderCode: string) { + 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 (bytecodeHash.toLowerCase() !== currentBootloaderBytecode) { + this.bootloaderToUpgrade = { + name: BOOTLOADER_CONTRACT_NAME, + bytecodeHashes: [bytecodeHash], + }; } + } - async publishBootloader(bootloaderCode: string) { - console.log('\nPublishing bootloader bytecode:'); + async publishBootloader(bootloaderCode: string) { + console.log("\nPublishing bootloader bytecode:"); - const [deps] = await filterPublishedFactoryDeps(BOOTLOADER_CONTRACT_NAME, [bootloaderCode], this.deployer); + const [deps] = await filterPublishedFactoryDeps(BOOTLOADER_CONTRACT_NAME, [bootloaderCode], this.deployer); - if (deps.length == 0) { - console.log('Default bootloader bytecode is already published, skipping'); - return; - } - - await this.publishFactoryDeps([ - { - name: BOOTLOADER_CONTRACT_NAME, - bytecodes: deps - } - ]); - } - - async processBootloader() { - const bootloaderCode = ethers.utils.hexlify( - fs.readFileSync('./bootloader/build/artifacts/proved_batch.yul/proved_batch.yul.zbin') - ); - - await this.publishBootloader(bootloaderCode); - await this.checkShouldUpgradeBootloader(bootloaderCode); - } - - async shouldUpgradeSystemContract(contractAddress: string, expectedBytecodeHash: string): Promise { - // We could have also used the `getCode` method of the JSON-RPC, but in the context - // of system upgrades looking into account code storage is more robust - const currentBytecodeHash = await this.deployer.zkWallet.provider.getStorageAt( - SYSTEM_CONTRACTS.accountCodeStorage.address, - contractAddress - ); - - return expectedBytecodeHash.toLowerCase() !== currentBytecodeHash.toLowerCase(); + if (deps.length == 0) { + console.log("Default bootloader bytecode is already published, skipping"); + return; } - // Returns the contracts to be published. - async prepareContractsForPublishing(): Promise { - const dependenciesToPublish: Dependency[] = []; - for (const contract of Object.values(SYSTEM_CONTRACTS)) { - const contractName = contract.codeName; - let factoryDeps: string[] = []; - if (contract.lang == Language.Solidity) { - const artifact = await this.deployer.loadArtifact(contractName); - factoryDeps = [...(await this.deployer.extractFactoryDeps(artifact)), artifact.bytecode]; - } else { - // Yul files have only one dependency - factoryDeps = [readYulBytecode(contract)]; - } - - const contractBytecodeHash = ethers.utils.hexlify(hashBytecode(factoryDeps[factoryDeps.length - 1])); - if (await this.shouldUpgradeSystemContract(contract.address, contractBytecodeHash)) { - this.dependenciesToUpgrade.push({ - name: contractName, - bytecodeHashes: [contractBytecodeHash], - address: contract.address - }); - } - - const [bytecodesToPublish, currentLength] = await filterPublishedFactoryDeps( - contractName, - factoryDeps, - this.deployer - ); - if (bytecodesToPublish.length == 0) { - console.log(`All bytecodes for ${contractName} are already published, skipping`); - continue; - } - if (currentLength > MAX_COMBINED_LENGTH) { - throw new Error(`Can not publish dependencies of contract ${contractName}`); - } - - dependenciesToPublish.push({ - name: contractName, - bytecodes: bytecodesToPublish, - address: contract.address - }); - } - - return dependenciesToPublish; + await this.publishFactoryDeps([ + { + name: BOOTLOADER_CONTRACT_NAME, + bytecodes: deps, + }, + ]); + } + + async processBootloader() { + const bootloaderCode = ethers.utils.hexlify( + fs.readFileSync("./bootloader/build/artifacts/proved_batch.yul/proved_batch.yul.zbin") + ); + + await this.publishBootloader(bootloaderCode); + await this.checkShouldUpgradeBootloader(bootloaderCode); + } + + async shouldUpgradeSystemContract(contractAddress: string, expectedBytecodeHash: string): Promise { + // We could have also used the `getCode` method of the JSON-RPC, but in the context + // of system upgrades looking into account code storage is more robust + const currentBytecodeHash = await this.deployer.zkWallet.provider.getStorageAt( + SYSTEM_CONTRACTS.accountCodeStorage.address, + contractAddress + ); + + return expectedBytecodeHash.toLowerCase() !== currentBytecodeHash.toLowerCase(); + } + + // Returns the contracts to be published. + async prepareContractsForPublishing(): Promise { + const dependenciesToPublish: Dependency[] = []; + for (const contract of Object.values(SYSTEM_CONTRACTS)) { + const contractName = contract.codeName; + let factoryDeps: string[] = []; + if (contract.lang == Language.Solidity) { + const artifact = await this.deployer.loadArtifact(contractName); + factoryDeps = [...(await this.deployer.extractFactoryDeps(artifact)), artifact.bytecode]; + } else { + // Yul files have only one dependency + factoryDeps = [readYulBytecode(contract)]; + } + + const contractBytecodeHash = ethers.utils.hexlify(hashBytecode(factoryDeps[factoryDeps.length - 1])); + if (await this.shouldUpgradeSystemContract(contract.address, contractBytecodeHash)) { + this.dependenciesToUpgrade.push({ + name: contractName, + bytecodeHashes: [contractBytecodeHash], + address: contract.address, + }); + } + + const [bytecodesToPublish, currentLength] = await filterPublishedFactoryDeps( + contractName, + factoryDeps, + this.deployer + ); + if (bytecodesToPublish.length == 0) { + console.log(`All bytecodes for ${contractName} are already published, skipping`); + continue; + } + if (currentLength > MAX_COMBINED_LENGTH) { + throw new Error(`Can not publish dependencies of contract ${contractName}`); + } + + dependenciesToPublish.push({ + name: contractName, + bytecodes: bytecodesToPublish, + address: contract.address, + }); } - async publishDependencies(dependenciesToPublish: Dependency[]) { - let currentLength = 0; - let currentDependencies: Dependency[] = []; - // We iterate over dependencies and try to batch the publishing of those in order to save up on gas as well as time. - for (const dependency of dependenciesToPublish) { - const dependencyLength = dependency.bytecodes.reduce( - (prev, dep) => prev + ethers.utils.arrayify(dep).length, - 0 - ); - if (currentLength + dependencyLength > MAX_COMBINED_LENGTH) { - await this.publishFactoryDeps(currentDependencies); - currentLength = dependencyLength; - currentDependencies = [dependency]; - } else { - currentLength += dependencyLength; - currentDependencies.push(dependency); - } - } - if (currentDependencies.length > 0) { - await this.publishFactoryDeps(currentDependencies); - } + return dependenciesToPublish; + } + + async publishDependencies(dependenciesToPublish: Dependency[]) { + let currentLength = 0; + let currentDependencies: Dependency[] = []; + // We iterate over dependencies and try to batch the publishing of those in order to save up on gas as well as time. + for (const dependency of dependenciesToPublish) { + const dependencyLength = dependency.bytecodes.reduce((prev, dep) => prev + ethers.utils.arrayify(dep).length, 0); + if (currentLength + dependencyLength > MAX_COMBINED_LENGTH) { + await this.publishFactoryDeps(currentDependencies); + currentLength = dependencyLength; + currentDependencies = [dependency]; + } else { + currentLength += dependencyLength; + currentDependencies.push(dependency); + } } - - returnResult() { - return { - systemContracts: this.dependenciesToUpgrade, - defaultAA: this.defaultAccountToUpgrade, - bootloader: this.bootloaderToUpgrade - }; + if (currentDependencies.length > 0) { + await this.publishFactoryDeps(currentDependencies); } + } + + returnResult() { + return { + systemContracts: this.dependenciesToUpgrade, + defaultAA: this.defaultAccountToUpgrade, + bootloader: this.bootloaderToUpgrade, + }; + } } export function l1RpcUrl() { - return process.env.ETH_CLIENT_WEB3_URL as string; + return process.env.ETH_CLIENT_WEB3_URL as string; } export function l2RpcUrl() { - return process.env.API_WEB3_JSON_RPC_HTTP_URL as string; + return process.env.API_WEB3_JSON_RPC_HTTP_URL as string; } async function main() { - const program = new Command(); - - program.version('0.1.0').name('publish preimages').description('publish preimages for the L2 contracts'); - - program - .option('--private-key ') - .option('--gas-price ') - .option('--nonce ') - .option('--l1Rpc ') - .option('--l2Rpc ') - .option('--bootloader') - .option('--default-aa') - .option('--system-contracts') - .option('--file ') - .action(async (cmd) => { - const l1Rpc = cmd.l1Rpc ? cmd.l1Rpc : l1RpcUrl(); - const l2Rpc = cmd.l2Rpc ? cmd.l2Rpc : l2RpcUrl(); - const providerL1 = new ethers.providers.JsonRpcProvider(l1Rpc); - const providerL2 = new Provider(l2Rpc); - const wallet = cmd.privateKey - ? new Wallet(cmd.privateKey) - : Wallet.fromMnemonic( - process.env.MNEMONIC ? process.env.MNEMONIC : ethTestConfig.mnemonic, - "m/44'/60'/0'/0/1" - ); - wallet.connect(providerL2); - wallet.connectToL1(providerL1); - - const deployer = new Deployer(hre, wallet); - deployer.zkWallet = deployer.zkWallet.connect(providerL2).connectToL1(providerL1); - deployer.ethWallet = deployer.ethWallet.connect(providerL1); - const ethWallet = deployer.ethWallet; - - console.log(`Using deployer wallet: ${ethWallet.address}`); - - const gasPrice = cmd.gasPrice ? parseUnits(cmd.gasPrice, 'gwei') : await providerL1.getGasPrice(); - console.log(`Using gas price: ${formatUnits(gasPrice, 'gwei')} gwei`); - - const nonce = cmd.nonce ? parseInt(cmd.nonce) : await ethWallet.getTransactionCount(); - console.log(`Using nonce: ${nonce}`); - - const zkSyncDeployer = new ZkSyncDeployer(deployer, gasPrice, nonce); - if (cmd.bootloader) { - await zkSyncDeployer.processBootloader(); - } - - if (cmd.defaultAa) { - await zkSyncDeployer.processDefaultAA(); - } - - if (cmd.systemContracts) { - const dependenciesToPublish = await zkSyncDeployer.prepareContractsForPublishing(); - await zkSyncDeployer.publishDependencies(dependenciesToPublish); - } - - const result = zkSyncDeployer.returnResult(); - console.log(JSON.stringify(result, null, 2)); - if (cmd.file) { - fs.writeFileSync(cmd.file, JSON.stringify(result, null, 2)); - } - console.log('\nPublishing factory dependencies complete!'); - }); + const program = new Command(); + + program.version("0.1.0").name("publish preimages").description("publish preimages for the L2 contracts"); + + program + .option("--private-key ") + .option("--gas-price ") + .option("--nonce ") + .option("--l1Rpc ") + .option("--l2Rpc ") + .option("--bootloader") + .option("--default-aa") + .option("--system-contracts") + .option("--file ") + .action(async (cmd) => { + const l1Rpc = cmd.l1Rpc ? cmd.l1Rpc : l1RpcUrl(); + const l2Rpc = cmd.l2Rpc ? cmd.l2Rpc : l2RpcUrl(); + const providerL1 = new ethers.providers.JsonRpcProvider(l1Rpc); + const providerL2 = new Provider(l2Rpc); + const wallet = cmd.privateKey + ? new Wallet(cmd.privateKey) + : Wallet.fromMnemonic(process.env.MNEMONIC ? process.env.MNEMONIC : ethTestConfig.mnemonic, "m/44'/60'/0'/0/1"); + wallet.connect(providerL2); + wallet.connectToL1(providerL1); + + const deployer = new Deployer(hre, wallet); + deployer.zkWallet = deployer.zkWallet.connect(providerL2).connectToL1(providerL1); + deployer.ethWallet = deployer.ethWallet.connect(providerL1); + const ethWallet = deployer.ethWallet; + + console.log(`Using deployer wallet: ${ethWallet.address}`); + + const gasPrice = cmd.gasPrice ? parseUnits(cmd.gasPrice, "gwei") : await providerL1.getGasPrice(); + console.log(`Using gas price: ${formatUnits(gasPrice, "gwei")} gwei`); + + const nonce = cmd.nonce ? parseInt(cmd.nonce) : await ethWallet.getTransactionCount(); + console.log(`Using nonce: ${nonce}`); + + const zkSyncDeployer = new ZkSyncDeployer(deployer, gasPrice, nonce); + if (cmd.bootloader) { + await zkSyncDeployer.processBootloader(); + } + + if (cmd.defaultAa) { + await zkSyncDeployer.processDefaultAA(); + } + + if (cmd.systemContracts) { + const dependenciesToPublish = await zkSyncDeployer.prepareContractsForPublishing(); + await zkSyncDeployer.publishDependencies(dependenciesToPublish); + } + + const result = zkSyncDeployer.returnResult(); + console.log(JSON.stringify(result, null, 2)); + if (cmd.file) { + fs.writeFileSync(cmd.file, JSON.stringify(result, null, 2)); + } + console.log("\nPublishing factory dependencies complete!"); + }); - await program.parseAsync(process.argv); + await program.parseAsync(process.argv); } main() - .then(() => process.exit(0)) - .catch((err) => { - console.error('Error:', err); - process.exit(1); - }); + .then(() => process.exit(0)) + .catch((err) => { + console.error("Error:", err); + process.exit(1); + }); diff --git a/scripts/process.ts b/scripts/process.ts index 67151b851f0..261b3005c5b 100644 --- a/scripts/process.ts +++ b/scripts/process.ts @@ -1,172 +1,169 @@ -import * as hre from 'hardhat'; +import * as hre from "hardhat"; -import { ethers } from 'ethers'; -import { existsSync, mkdirSync, writeFileSync } from 'fs'; -import { renderFile } from 'template-file'; -import { utils } from 'zksync-web3'; -import { SYSTEM_CONTRACTS, getRevertSelector, getTransactionUtils } from './constants'; -import { ForceDeployment } from './utils'; +import { ethers } from "ethers"; +import { existsSync, mkdirSync, writeFileSync } from "fs"; +import { renderFile } from "template-file"; +import { utils } from "zksync-web3"; +import { SYSTEM_CONTRACTS, getRevertSelector, getTransactionUtils } from "./constants"; +import type { ForceDeployment } from "./utils"; /* eslint-disable @typescript-eslint/no-var-requires */ -const preprocess = require('preprocess'); -const SYSTEM_PARAMS = require('../SystemConfig.json'); +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 = "bootloader/build"; function getSelector(contractName: string, method: string): string { - const artifact = hre.artifacts.readArtifactSync(contractName); - const contractInterface = new ethers.utils.Interface(artifact.abi); + const artifact = hre.artifacts.readArtifactSync(contractName); + const contractInterface = new ethers.utils.Interface(artifact.abi); - return contractInterface.getSighash(method); + return contractInterface.getSighash(method); } // Methods from ethers do zero pad from left, but we need to pad from the right function padZeroRight(hexData: string, length: number): string { - while (hexData.length < length) { - hexData += '0'; - } + while (hexData.length < length) { + hexData += "0"; + } - return hexData; + return hexData; } const PADDED_SELECTOR_LENGTH = 32 * 2 + 2; function getPaddedSelector(contractName: string, method: string): string { - const result = getSelector(contractName, method); + const result = getSelector(contractName, method); - return padZeroRight(result, PADDED_SELECTOR_LENGTH); + return padZeroRight(result, PADDED_SELECTOR_LENGTH); } function getSystemContextExpectedHash() { - const artifact = hre.artifacts.readArtifactSync('SystemContext'); - return ethers.utils.hexlify(utils.hashBytecode(artifact.bytecode)); + const artifact = hre.artifacts.readArtifactSync("SystemContext"); + return ethers.utils.hexlify(utils.hashBytecode(artifact.bytecode)); } function upgradeSystemContextCalldata() { - // Here we need to encode the force deployment for the system context contract as well as transform - // it into writing of the calldata into the bootloader memory. - - const newHash = getSystemContextExpectedHash(); - const artifact = new ethers.utils.Interface(hre.artifacts.readArtifactSync('ContractDeployer').abi); - - const forceDeplyment: ForceDeployment = { - bytecodeHash: newHash, - newAddress: SYSTEM_CONTRACTS.systemContext.address, - callConstructor: false, - value: 0, - input: '0x' - }; - - let calldata = artifact.encodeFunctionData('forceDeployOnAddresses', [[forceDeplyment]]); - const originalLength = (calldata.length - 2) / 2; - - // Padding calldata from the right. We really need to do it, since Yul would "implicitly" pad it from the left and it - // it is not what we want. - while ((calldata.length - 2) % 64 != 0) { - calldata += '0'; - } + // Here we need to encode the force deployment for the system context contract as well as transform + // it into writing of the calldata into the bootloader memory. - // We will apply tabulation to make the compiled bootloader code more readable - const TABULATION = '\t\t\t\t\t'; - // In the first slot we need to store the calldata's length - let data = `mstore(0x00, ${originalLength})\n`; + const newHash = getSystemContextExpectedHash(); + const artifact = new ethers.utils.Interface(hre.artifacts.readArtifactSync("ContractDeployer").abi); - const slices = (calldata.length - 2) / 64; + const forceDeplyment: ForceDeployment = { + bytecodeHash: newHash, + newAddress: SYSTEM_CONTRACTS.systemContext.address, + callConstructor: false, + value: 0, + input: "0x", + }; - for (let slice = 0; slice < slices; slice++) { - const offset = slice * 32; - const sliceHex = calldata.slice(2 + offset * 2, 2 + offset * 2 + 64); + let calldata = artifact.encodeFunctionData("forceDeployOnAddresses", [[forceDeplyment]]); + const originalLength = (calldata.length - 2) / 2; - data += `${TABULATION}mstore(${offset + 32}, 0x${sliceHex})\n`; - } + // Padding calldata from the right. We really need to do it, since Yul would "implicitly" pad it from the left and it + // it is not what we want. + while ((calldata.length - 2) % 64 != 0) { + calldata += "0"; + } + + // We will apply tabulation to make the compiled bootloader code more readable + const TABULATION = "\t\t\t\t\t"; + // In the first slot we need to store the calldata's length + let data = `mstore(0x00, ${originalLength})\n`; + + const slices = (calldata.length - 2) / 64; + + for (let slice = 0; slice < slices; slice++) { + const offset = slice * 32; + const sliceHex = calldata.slice(2 + offset * 2, 2 + offset * 2 + 64); + + data += `${TABULATION}mstore(${offset + 32}, 0x${sliceHex})\n`; + } - return data; + return data; } // Maybe in the future some of these params will be passed // in a JSON file. For now, a simple object is ok here. const params = { - MARK_BATCH_AS_REPUBLISHED_SELECTOR: getSelector('KnownCodesStorage', 'markFactoryDeps'), - VALIDATE_TX_SELECTOR: getSelector('IAccount', 'validateTransaction'), - EXECUTE_TX_SELECTOR: getSelector('DefaultAccount', 'executeTransaction'), - RIGHT_PADDED_GET_ACCOUNT_VERSION_SELECTOR: getPaddedSelector('ContractDeployer', 'extendedAccountVersion'), - RIGHT_PADDED_GET_RAW_CODE_HASH_SELECTOR: getPaddedSelector('AccountCodeStorage', 'getRawCodeHash'), - PAY_FOR_TX_SELECTOR: getSelector('DefaultAccount', 'payForTransaction'), - PRE_PAYMASTER_SELECTOR: getSelector('DefaultAccount', 'prepareForPaymaster'), - VALIDATE_AND_PAY_PAYMASTER: getSelector('IPaymaster', 'validateAndPayForPaymasterTransaction'), - // It doesn't used directly now but is important to keep the way to regenerate it when needed - TX_UTILITIES: getTransactionUtils(), - RIGHT_PADDED_POST_TRANSACTION_SELECTOR: getPaddedSelector('IPaymaster', 'postTransaction'), - RIGHT_PADDED_SET_TX_ORIGIN: getPaddedSelector('SystemContext', 'setTxOrigin'), - RIGHT_PADDED_SET_GAS_PRICE: getPaddedSelector('SystemContext', 'setGasPrice'), - RIGHT_PADDED_INCREMENT_TX_NUMBER_IN_BLOCK_SELECTOR: getPaddedSelector('SystemContext', 'incrementTxNumberInBatch'), - RIGHT_PADDED_RESET_TX_NUMBER_IN_BLOCK_SELECTOR: getPaddedSelector('SystemContext', 'resetTxNumberInBatch'), - RIGHT_PADDED_SEND_L2_TO_L1_LOG_SELECTOR: getPaddedSelector('L1Messenger', 'sendL2ToL1Log'), - PUBLISH_PUBDATA_SELECTOR: getSelector('L1Messenger', 'publishPubdataAndClearState'), - RIGHT_PADDED_SET_NEW_BATCH_SELECTOR: getPaddedSelector('SystemContext', 'setNewBatch'), - RIGHT_PADDED_OVERRIDE_BATCH_SELECTOR: getPaddedSelector('SystemContext', 'unsafeOverrideBatch'), - // Error - REVERT_ERROR_SELECTOR: padZeroRight(getRevertSelector(), PADDED_SELECTOR_LENGTH), - RIGHT_PADDED_VALIDATE_NONCE_USAGE_SELECTOR: getPaddedSelector('INonceHolder', 'validateNonceUsage'), - RIGHT_PADDED_MINT_ETHER_SELECTOR: getPaddedSelector('L2EthToken', 'mint'), - GET_TX_HASHES_SELECTOR: getSelector('BootloaderUtilities', 'getTransactionHashes'), - CREATE_SELECTOR: getSelector('ContractDeployer', 'create'), - CREATE2_SELECTOR: getSelector('ContractDeployer', 'create2'), - CREATE_ACCOUNT_SELECTOR: getSelector('ContractDeployer', 'createAccount'), - CREATE2_ACCOUNT_SELECTOR: getSelector('ContractDeployer', 'create2Account'), - PADDED_TRANSFER_FROM_TO_SELECTOR: getPaddedSelector('L2EthToken', 'transferFromTo'), - SUCCESSFUL_ACCOUNT_VALIDATION_MAGIC_VALUE: getPaddedSelector('IAccount', 'validateTransaction'), - SUCCESSFUL_PAYMASTER_VALIDATION_MAGIC_VALUE: getPaddedSelector( - 'IPaymaster', - 'validateAndPayForPaymasterTransaction' - ), - PUBLISH_COMPRESSED_BYTECODE_SELECTOR: getSelector('Compressor', 'publishCompressedBytecode'), - GET_MARKER_PADDED_SELECTOR: getPaddedSelector('KnownCodesStorage', 'getMarker'), - RIGHT_PADDED_SET_L2_BLOCK_SELECTOR: getPaddedSelector('SystemContext', 'setL2Block'), - RIGHT_PADDED_APPEND_TRANSACTION_TO_L2_BLOCK_SELECTOR: getPaddedSelector( - 'SystemContext', - 'appendTransactionToCurrentL2Block' - ), - RIGHT_PADDED_PUBLISH_TIMESTAMP_DATA_TO_L1_SELECTOR: getPaddedSelector('SystemContext', 'publishTimestampDataToL1'), - COMPRESSED_BYTECODES_SLOTS: 32768, - ENSURE_RETURNED_MAGIC: 1, - FORBID_ZERO_GAS_PER_PUBDATA: 1, - SYSTEM_CONTEXT_EXPECTED_CODE_HASH: getSystemContextExpectedHash(), - UPGRADE_SYSTEM_CONTEXT_CALLDATA: upgradeSystemContextCalldata(), - // One of "worst case" scenarios for the number of state diffs in a batch is when 120kb of pubdata is spent - // on repeated writes, that are all zeroed out. In this case, the number of diffs is 120k / 5 = 24k. This means that they will have - // accoomdate 6528000 bytes of calldata for the uncompressed state diffs. Adding 120k on top leaves us with - // roughly 6650000 bytes needed for calldata. 207813 slots are needed to accomodate this amount of data. - // We round up to 208000 slots just in case. - // - // In theory though much more calldata could be used (if for instance 1 byte is used for enum index). It is the responsibility of the - // operator to ensure that it can form the correct calldata for the L1Messenger. - OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_SLOTS: 208000, - ...SYSTEM_PARAMS + MARK_BATCH_AS_REPUBLISHED_SELECTOR: getSelector("KnownCodesStorage", "markFactoryDeps"), + VALIDATE_TX_SELECTOR: getSelector("IAccount", "validateTransaction"), + EXECUTE_TX_SELECTOR: getSelector("DefaultAccount", "executeTransaction"), + RIGHT_PADDED_GET_ACCOUNT_VERSION_SELECTOR: getPaddedSelector("ContractDeployer", "extendedAccountVersion"), + RIGHT_PADDED_GET_RAW_CODE_HASH_SELECTOR: getPaddedSelector("AccountCodeStorage", "getRawCodeHash"), + PAY_FOR_TX_SELECTOR: getSelector("DefaultAccount", "payForTransaction"), + PRE_PAYMASTER_SELECTOR: getSelector("DefaultAccount", "prepareForPaymaster"), + VALIDATE_AND_PAY_PAYMASTER: getSelector("IPaymaster", "validateAndPayForPaymasterTransaction"), + // It doesn't used directly now but is important to keep the way to regenerate it when needed + TX_UTILITIES: getTransactionUtils(), + RIGHT_PADDED_POST_TRANSACTION_SELECTOR: getPaddedSelector("IPaymaster", "postTransaction"), + RIGHT_PADDED_SET_TX_ORIGIN: getPaddedSelector("SystemContext", "setTxOrigin"), + RIGHT_PADDED_SET_GAS_PRICE: getPaddedSelector("SystemContext", "setGasPrice"), + RIGHT_PADDED_INCREMENT_TX_NUMBER_IN_BLOCK_SELECTOR: getPaddedSelector("SystemContext", "incrementTxNumberInBatch"), + RIGHT_PADDED_RESET_TX_NUMBER_IN_BLOCK_SELECTOR: getPaddedSelector("SystemContext", "resetTxNumberInBatch"), + RIGHT_PADDED_SEND_L2_TO_L1_LOG_SELECTOR: getPaddedSelector("L1Messenger", "sendL2ToL1Log"), + PUBLISH_PUBDATA_SELECTOR: getSelector("L1Messenger", "publishPubdataAndClearState"), + RIGHT_PADDED_SET_NEW_BATCH_SELECTOR: getPaddedSelector("SystemContext", "setNewBatch"), + RIGHT_PADDED_OVERRIDE_BATCH_SELECTOR: getPaddedSelector("SystemContext", "unsafeOverrideBatch"), + // Error + REVERT_ERROR_SELECTOR: padZeroRight(getRevertSelector(), PADDED_SELECTOR_LENGTH), + RIGHT_PADDED_VALIDATE_NONCE_USAGE_SELECTOR: getPaddedSelector("INonceHolder", "validateNonceUsage"), + RIGHT_PADDED_MINT_ETHER_SELECTOR: getPaddedSelector("L2EthToken", "mint"), + GET_TX_HASHES_SELECTOR: getSelector("BootloaderUtilities", "getTransactionHashes"), + CREATE_SELECTOR: getSelector("ContractDeployer", "create"), + CREATE2_SELECTOR: getSelector("ContractDeployer", "create2"), + CREATE_ACCOUNT_SELECTOR: getSelector("ContractDeployer", "createAccount"), + CREATE2_ACCOUNT_SELECTOR: getSelector("ContractDeployer", "create2Account"), + PADDED_TRANSFER_FROM_TO_SELECTOR: getPaddedSelector("L2EthToken", "transferFromTo"), + SUCCESSFUL_ACCOUNT_VALIDATION_MAGIC_VALUE: getPaddedSelector("IAccount", "validateTransaction"), + SUCCESSFUL_PAYMASTER_VALIDATION_MAGIC_VALUE: getPaddedSelector("IPaymaster", "validateAndPayForPaymasterTransaction"), + PUBLISH_COMPRESSED_BYTECODE_SELECTOR: getSelector("Compressor", "publishCompressedBytecode"), + GET_MARKER_PADDED_SELECTOR: getPaddedSelector("KnownCodesStorage", "getMarker"), + RIGHT_PADDED_SET_L2_BLOCK_SELECTOR: getPaddedSelector("SystemContext", "setL2Block"), + RIGHT_PADDED_APPEND_TRANSACTION_TO_L2_BLOCK_SELECTOR: getPaddedSelector( + "SystemContext", + "appendTransactionToCurrentL2Block" + ), + RIGHT_PADDED_PUBLISH_TIMESTAMP_DATA_TO_L1_SELECTOR: getPaddedSelector("SystemContext", "publishTimestampDataToL1"), + COMPRESSED_BYTECODES_SLOTS: 32768, + ENSURE_RETURNED_MAGIC: 1, + FORBID_ZERO_GAS_PER_PUBDATA: 1, + SYSTEM_CONTEXT_EXPECTED_CODE_HASH: getSystemContextExpectedHash(), + UPGRADE_SYSTEM_CONTEXT_CALLDATA: upgradeSystemContextCalldata(), + // One of "worst case" scenarios for the number of state diffs in a batch is when 120kb of pubdata is spent + // on repeated writes, that are all zeroed out. In this case, the number of diffs is 120k / 5 = 24k. This means that they will have + // accoomdate 6528000 bytes of calldata for the uncompressed state diffs. Adding 120k on top leaves us with + // roughly 6650000 bytes needed for calldata. 207813 slots are needed to accomodate this amount of data. + // We round up to 208000 slots just in case. + // + // In theory though much more calldata could be used (if for instance 1 byte is used for enum index). It is the responsibility of the + // operator to ensure that it can form the correct calldata for the L1Messenger. + OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_SLOTS: 208000, + ...SYSTEM_PARAMS, }; function extractTestFunctionNames(sourceCode: string): string[] { - // Remove single-line comments - sourceCode = sourceCode.replace(/\/\/[^\n]*/g, ''); + // Remove single-line comments + sourceCode = sourceCode.replace(/\/\/[^\n]*/g, ""); - // Remove multi-line comments - sourceCode = sourceCode.replace(/\/\*[\s\S]*?\*\//g, ''); + // Remove multi-line comments + sourceCode = sourceCode.replace(/\/\*[\s\S]*?\*\//g, ""); - const regexPatterns = [/function\s+(TEST\w+)/g]; + const regexPatterns = [/function\s+(TEST\w+)/g]; - const results: string[] = []; - for (const pattern of regexPatterns) { - let match; - while ((match = pattern.exec(sourceCode)) !== null) { - results.push(match[1]); - } + const results: string[] = []; + for (const pattern of regexPatterns) { + let match; + while ((match = pattern.exec(sourceCode)) !== null) { + results.push(match[1]); } + } - return [...new Set(results)]; // Remove duplicates + return [...new Set(results)]; // Remove duplicates } function createTestFramework(tests: string[]): string { - let testFramework = ` + let testFramework = ` let test_id:= mload(0) switch test_id @@ -175,80 +172,80 @@ function createTestFramework(tests: string[]): string { } `; - tests.forEach((value, index) => { - testFramework += ` + tests.forEach((value, index) => { + testFramework += ` case ${index + 1} { testing_start("${value}") ${value}() } `; - }); + }); - testFramework += ` + testFramework += ` default { } return (0, 0) `; - return testFramework; + return testFramework; } async function main() { - const bootloader = await renderFile('bootloader/bootloader.yul', params); - // The overhead is unknown for gas tests and so it should be zero to calculate it - const gasTestBootloaderTemplate = await renderFile('bootloader/bootloader.yul', { - ...params, - L2_TX_INTRINSIC_GAS: 0, - L2_TX_INTRINSIC_PUBDATA: 0, - L1_TX_INTRINSIC_L2_GAS: 0, - L1_TX_INTRINSIC_PUBDATA: 0, - FORBID_ZERO_GAS_PER_PUBDATA: 0 - }); - - const feeEstimationBootloaderTemplate = await renderFile('bootloader/bootloader.yul', { - ...params, - ENSURE_RETURNED_MAGIC: 0 - }); - - console.log('Preprocessing production bootloader'); - const provedBatchBootloader = preprocess.preprocess(bootloader, { BOOTLOADER_TYPE: 'proved_batch' }); - console.log('Preprocessing playground block bootloader'); - const playgroundBatchBootloader = preprocess.preprocess(bootloader, { BOOTLOADER_TYPE: 'playground_batch' }); - console.log('Preprocessing gas test bootloader'); - const gasTestBootloader = preprocess.preprocess(gasTestBootloaderTemplate, { BOOTLOADER_TYPE: 'proved_batch' }); - console.log('Preprocessing fee estimation bootloader'); - const feeEstimationBootloader = preprocess.preprocess(feeEstimationBootloaderTemplate, { - BOOTLOADER_TYPE: 'playground_batch' - }); - - console.log('Preprocessing bootloader tests'); - const bootloaderTests = await renderFile('bootloader/tests/bootloader/bootloader_test.yul', {}); - - const testMethods = extractTestFunctionNames(bootloaderTests); - - console.log('Found tests: ' + testMethods); - - const testFramework = createTestFramework(testMethods); - - const bootloaderTestUtils = await renderFile('bootloader/tests/utils/test_utils.yul', {}); - - const bootloaderWithTests = await renderFile('bootloader/bootloader.yul', { - ...params, - CODE_START_PLACEHOLDER: '\n' + bootloaderTestUtils + '\n' + bootloaderTests + '\n' + testFramework - }); - const provedBootloaderWithTests = preprocess.preprocess(bootloaderWithTests, { BOOTLOADER_TYPE: 'proved_batch' }); - - if (!existsSync(OUTPUT_DIR)) { - mkdirSync(OUTPUT_DIR); - } - - 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); - - console.log('Preprocessing done!'); + const bootloader = await renderFile("bootloader/bootloader.yul", params); + // The overhead is unknown for gas tests and so it should be zero to calculate it + const gasTestBootloaderTemplate = await renderFile("bootloader/bootloader.yul", { + ...params, + L2_TX_INTRINSIC_GAS: 0, + L2_TX_INTRINSIC_PUBDATA: 0, + L1_TX_INTRINSIC_L2_GAS: 0, + L1_TX_INTRINSIC_PUBDATA: 0, + FORBID_ZERO_GAS_PER_PUBDATA: 0, + }); + + const feeEstimationBootloaderTemplate = await renderFile("bootloader/bootloader.yul", { + ...params, + ENSURE_RETURNED_MAGIC: 0, + }); + + console.log("Preprocessing production bootloader"); + const provedBatchBootloader = preprocess.preprocess(bootloader, { BOOTLOADER_TYPE: "proved_batch" }); + console.log("Preprocessing playground block bootloader"); + const playgroundBatchBootloader = preprocess.preprocess(bootloader, { BOOTLOADER_TYPE: "playground_batch" }); + console.log("Preprocessing gas test bootloader"); + const gasTestBootloader = preprocess.preprocess(gasTestBootloaderTemplate, { BOOTLOADER_TYPE: "proved_batch" }); + console.log("Preprocessing fee estimation bootloader"); + const feeEstimationBootloader = preprocess.preprocess(feeEstimationBootloaderTemplate, { + BOOTLOADER_TYPE: "playground_batch", + }); + + console.log("Preprocessing bootloader tests"); + const bootloaderTests = await renderFile("bootloader/tests/bootloader/bootloader_test.yul", {}); + + const testMethods = extractTestFunctionNames(bootloaderTests); + + console.log("Found tests: " + testMethods); + + const testFramework = createTestFramework(testMethods); + + const bootloaderTestUtils = await renderFile("bootloader/tests/utils/test_utils.yul", {}); + + const bootloaderWithTests = await renderFile("bootloader/bootloader.yul", { + ...params, + CODE_START_PLACEHOLDER: "\n" + bootloaderTestUtils + "\n" + bootloaderTests + "\n" + testFramework, + }); + const provedBootloaderWithTests = preprocess.preprocess(bootloaderWithTests, { BOOTLOADER_TYPE: "proved_batch" }); + + if (!existsSync(OUTPUT_DIR)) { + mkdirSync(OUTPUT_DIR); + } + + 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); + + console.log("Preprocessing done!"); } main(); diff --git a/scripts/utils.ts b/scripts/utils.ts index 7d8fcaeb65e..81e855e0dca 100644 --- a/scripts/utils.ts +++ b/scripts/utils.ts @@ -1,67 +1,69 @@ -import * as hre from 'hardhat'; +import * as hre from "hardhat"; -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; -import { BigNumber, BigNumberish, BytesLike, ethers } from 'ethers'; -import * as fs from 'fs'; -import { hashBytecode } from 'zksync-web3/build/src/utils'; -import { Language, SYSTEM_CONTRACTS, YulContractDescrption } from './constants'; +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 type { YulContractDescrption } from "./constants"; +import { Language, SYSTEM_CONTRACTS } from "./constants"; export interface Dependency { - name: string; - bytecodes: BytesLike[]; - address?: string; + name: string; + bytecodes: BytesLike[]; + address?: string; } export interface DeployedDependency { - name: string; - bytecodeHashes: string[]; - address?: string; + name: string; + bytecodeHashes: string[]; + address?: string; } export function readYulBytecode(description: YulContractDescrption) { - const contractName = description.codeName; - const path = `contracts/${description.path}/artifacts/${contractName}.yul/${contractName}.yul.zbin`; - return ethers.utils.hexlify(fs.readFileSync(path)); + const contractName = description.codeName; + const path = `contracts/${description.path}/artifacts/${contractName}.yul/${contractName}.yul.zbin`; + return ethers.utils.hexlify(fs.readFileSync(path)); } // The struct used to represent the parameters of a forced deployment -- a deployment during upgrade // which sets a bytecode onto an address. Typically used for updating system contracts. export interface ForceDeployment { - // The bytecode hash to put on an address - bytecodeHash: BytesLike; - // The address on which to deploy the bytecodehash to - newAddress: string; - // Whether to call the constructor - callConstructor: boolean; - // The value with which to initialize a contract - value: BigNumberish; - // The constructor calldata - input: BytesLike; + // The bytecode hash to put on an address + bytecodeHash: BytesLike; + // The address on which to deploy the bytecodehash to + newAddress: string; + // Whether to call the constructor + callConstructor: boolean; + // The value with which to initialize a contract + value: BigNumberish; + // The constructor calldata + input: BytesLike; } export async function outputSystemContracts(): Promise { - const upgradeParamsPromises: Promise[] = Object.values(SYSTEM_CONTRACTS).map( - async (systemContractInfo) => { - let bytecode: string; - - if (systemContractInfo.lang === Language.Yul) { - bytecode = readYulBytecode(systemContractInfo); - } else { - bytecode = (await hre.artifacts.readArtifact(systemContractInfo.codeName)).bytecode; - } - const bytecodeHash = hashBytecode(bytecode); - - return { - bytecodeHash: ethers.utils.hexlify(bytecodeHash), - newAddress: systemContractInfo.address, - value: '0', - input: '0x', - callConstructor: false - }; - } - ); - - return await Promise.all(upgradeParamsPromises); + const upgradeParamsPromises: Promise[] = Object.values(SYSTEM_CONTRACTS).map( + async (systemContractInfo) => { + let bytecode: string; + + if (systemContractInfo.lang === Language.Yul) { + bytecode = readYulBytecode(systemContractInfo); + } else { + bytecode = (await hre.artifacts.readArtifact(systemContractInfo.codeName)).bytecode; + } + const bytecodeHash = hashBytecode(bytecode); + + return { + bytecodeHash: ethers.utils.hexlify(bytecodeHash), + newAddress: systemContractInfo.address, + value: "0", + input: "0x", + callConstructor: false, + }; + } + ); + + return await Promise.all(upgradeParamsPromises); } // Script that publishes preimages for all the system contracts on zkSync @@ -72,110 +74,110 @@ const DEFAULT_L2_TX_GAS_LIMIT = 2097152; // for each dependency the bytecodeHash is its versioned hash and marker is whether // the hash has been published before. export async function getMarkers(dependencies: BytesLike[], deployer: Deployer): Promise<[string, boolean][]> { - const contract = new ethers.Contract( - SYSTEM_CONTRACTS.knownCodesStorage.address, - (await hre.artifacts.readArtifact('KnownCodesStorage')).abi, - deployer.zkWallet - ); + const contract = new ethers.Contract( + SYSTEM_CONTRACTS.knownCodesStorage.address, + (await hre.artifacts.readArtifact("KnownCodesStorage")).abi, + deployer.zkWallet + ); - const promises = dependencies.map(async (dep) => { - const hash = ethers.utils.hexlify(hashBytecode(dep)); - const marker = BigNumber.from(await contract.getMarker(hash)); + const promises = dependencies.map(async (dep) => { + const hash = ethers.utils.hexlify(hashBytecode(dep)); + const marker = BigNumber.from(await contract.getMarker(hash)); - return [hash, marker.eq(1)] as [string, boolean]; - }); + return [hash, marker.eq(1)] as [string, boolean]; + }); - return await Promise.all(promises); + return await Promise.all(promises); } // Checks whether the marker has been set correctly in the KnownCodesStorage // system contract export async function checkMarkers(dependencies: BytesLike[], deployer: Deployer) { - const markers = await getMarkers(dependencies, deployer); + const markers = await getMarkers(dependencies, deployer); - for (const [bytecodeHash, marker] of markers) { - if (!marker) { - throw new Error(`Failed to mark ${bytecodeHash}`); - } + for (const [bytecodeHash, marker] of markers) { + if (!marker) { + throw new Error(`Failed to mark ${bytecodeHash}`); } + } } export function totalBytesLength(dependencies: BytesLike[]): number { - return dependencies.reduce((prev, curr) => prev + ethers.utils.arrayify(curr).length, 0); + return dependencies.reduce((prev, curr) => prev + ethers.utils.arrayify(curr).length, 0); } export function getBytecodes(dependencies: Dependency[]): BytesLike[] { - return dependencies.map((dep) => dep.bytecodes).flat(); + return dependencies.map((dep) => dep.bytecodes).flat(); } export async function publishFactoryDeps( - dependencies: Dependency[], - deployer: Deployer, - nonce: number, - gasPrice: BigNumber + dependencies: Dependency[], + deployer: Deployer, + nonce: number, + gasPrice: BigNumber ) { - if (dependencies.length == 0) { - return []; - } - const bytecodes = getBytecodes(dependencies); - const combinedLength = totalBytesLength(bytecodes); - - console.log( - `\nPublishing dependencies for contracts ${dependencies - .map((dep) => { - return dep.name; - }) - .join(', ')}` - ); - console.log(`Combined length ${combinedLength}`); - - const txHandle = await deployer.zkWallet.requestExecute({ - contractAddress: ethers.constants.AddressZero, - calldata: '0x', - l2GasLimit: DEFAULT_L2_TX_GAS_LIMIT, - factoryDeps: bytecodes, - overrides: { - nonce, - gasPrice, - gasLimit: 3000000 - } - }); - console.log(`Transaction hash: ${txHandle.hash}`); - - // Waiting for the transaction to be processed by the server - await txHandle.wait(); - - console.log('Transaction complete! Checking markers on L2...'); - - // Double checking that indeed the dependencies have been marked as known - await checkMarkers(bytecodes, deployer); + if (dependencies.length == 0) { + return []; + } + const bytecodes = getBytecodes(dependencies); + const combinedLength = totalBytesLength(bytecodes); + + console.log( + `\nPublishing dependencies for contracts ${dependencies + .map((dep) => { + return dep.name; + }) + .join(", ")}` + ); + console.log(`Combined length ${combinedLength}`); + + const txHandle = await deployer.zkWallet.requestExecute({ + contractAddress: ethers.constants.AddressZero, + calldata: "0x", + l2GasLimit: DEFAULT_L2_TX_GAS_LIMIT, + factoryDeps: bytecodes, + overrides: { + nonce, + gasPrice, + gasLimit: 3000000, + }, + }); + console.log(`Transaction hash: ${txHandle.hash}`); + + // Waiting for the transaction to be processed by the server + await txHandle.wait(); + + console.log("Transaction complete! Checking markers on L2..."); + + // Double checking that indeed the dependencies have been marked as known + await checkMarkers(bytecodes, deployer); } // Returns an array of bytecodes that should be published along with their total length in bytes export async function filterPublishedFactoryDeps( - contractName: string, - factoryDeps: string[], - deployer: Deployer + contractName: string, + factoryDeps: string[], + deployer: Deployer ): Promise<[string[], number]> { - console.log(`\nFactory dependencies for contract ${contractName}:`); - let currentLength = 0; + console.log(`\nFactory dependencies for contract ${contractName}:`); + let currentLength = 0; - const bytecodesToDeploy: string[] = []; + const bytecodesToDeploy: string[] = []; - const hashesAndMarkers = await getMarkers(factoryDeps, deployer); + const hashesAndMarkers = await getMarkers(factoryDeps, deployer); - for (let i = 0; i < factoryDeps.length; i++) { - const depLength = ethers.utils.arrayify(factoryDeps[i]).length; - const [hash, marker] = hashesAndMarkers[i]; - console.log(`${hash} (length: ${depLength} bytes) (deployed: ${marker})`); + for (let i = 0; i < factoryDeps.length; i++) { + const depLength = ethers.utils.arrayify(factoryDeps[i]).length; + const [hash, marker] = hashesAndMarkers[i]; + console.log(`${hash} (length: ${depLength} bytes) (deployed: ${marker})`); - if (!marker) { - currentLength += depLength; - bytecodesToDeploy.push(factoryDeps[i]); - } + if (!marker) { + currentLength += depLength; + bytecodesToDeploy.push(factoryDeps[i]); } + } - console.log(`Combined length to deploy: ${currentLength}`); + console.log(`Combined length to deploy: ${currentLength}`); - return [bytecodesToDeploy, currentLength]; + return [bytecodesToDeploy, currentLength]; } diff --git a/test/AccountCodeStorage.spec.ts b/test/AccountCodeStorage.spec.ts index 9bed917b87e..e7d6e8d3262 100644 --- a/test/AccountCodeStorage.spec.ts +++ b/test/AccountCodeStorage.spec.ts @@ -1,225 +1,215 @@ -import { expect } from 'chai'; -import { ethers, network } from 'hardhat'; -import { Wallet } from 'zksync-web3'; -import { AccountCodeStorage } from '../typechain-types'; -import { DEPLOYER_SYSTEM_CONTRACT_ADDRESS, EMPTY_STRING_KECCAK } from './shared/constants'; -import { deployContract, getWallets } from './shared/utils'; - -describe('AccountCodeStorage tests', function () { - let wallet: Wallet; - let accountCodeStorage: AccountCodeStorage; - let deployerAccount: ethers.Signer; - - const CONSTRUCTING_BYTECODE_HASH = '0x0101FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF'; - const CONSTRUCTED_BYTECODE_HASH = '0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF'; - const RANDOM_ADDRESS = '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'; - - before(async () => { - wallet = getWallets()[0]; - accountCodeStorage = (await deployContract('AccountCodeStorage')) as AccountCodeStorage; - - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS] - }); - deployerAccount = await ethers.getSigner(DEPLOYER_SYSTEM_CONTRACT_ADDRESS); - }); - - after(async () => { - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS] - }); - }); - - describe('storeAccountConstructingCodeHash', 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'); - }); - - it('failed to set with constructed bytecode', async () => { - await expect( - accountCodeStorage - .connect(deployerAccount) - .storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTED_BYTECODE_HASH) - ).to.be.revertedWith('Code hash is not for a contract on constructor'); - }); - - it('successfully stored', async () => { - await accountCodeStorage - .connect(deployerAccount) - .storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH); - - expect(await accountCodeStorage.getRawCodeHash(RANDOM_ADDRESS)).to.be.eq( - CONSTRUCTING_BYTECODE_HASH.toLowerCase() - ); - - await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); - }); - }); - - describe('storeAccountConstructedCodeHash', 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'); - }); - - it('failed to set with constructing bytecode', async () => { - await expect( - accountCodeStorage - .connect(deployerAccount) - .storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH) - ).to.be.revertedWith('Code hash is not for a constructed contract'); - }); - - it('successfully stored', async () => { - await accountCodeStorage - .connect(deployerAccount) - .storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTED_BYTECODE_HASH); - - expect(await accountCodeStorage.getRawCodeHash(RANDOM_ADDRESS)).to.be.eq( - CONSTRUCTED_BYTECODE_HASH.toLowerCase() - ); - - await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); - }); - }); - - 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' - ); - }); - - it('failed to mark already constructed bytecode', async () => { - await accountCodeStorage - .connect(deployerAccount) - .storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTED_BYTECODE_HASH); - - await expect( - accountCodeStorage.connect(deployerAccount).markAccountCodeHashAsConstructed(RANDOM_ADDRESS) - ).to.be.revertedWith('Code hash is not for a contract on constructor'); +import { expect } from "chai"; +import { ethers, network } from "hardhat"; +import type { Wallet } from "zksync-web3"; +import type { AccountCodeStorage } from "../typechain-types"; +import { DEPLOYER_SYSTEM_CONTRACT_ADDRESS, EMPTY_STRING_KECCAK } from "./shared/constants"; +import { deployContract, getWallets } from "./shared/utils"; + +describe("AccountCodeStorage tests", function () { + let wallet: Wallet; + let accountCodeStorage: AccountCodeStorage; + let deployerAccount: ethers.Signer; + + const CONSTRUCTING_BYTECODE_HASH = "0x0101FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"; + const CONSTRUCTED_BYTECODE_HASH = "0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"; + const RANDOM_ADDRESS = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; + + before(async () => { + wallet = getWallets()[0]; + accountCodeStorage = (await deployContract("AccountCodeStorage")) as AccountCodeStorage; + + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS], + }); + deployerAccount = await ethers.getSigner(DEPLOYER_SYSTEM_CONTRACT_ADDRESS); + }); + + after(async () => { + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS], + }); + }); - await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); - }); + describe("storeAccountConstructingCodeHash", 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"); + }); - it('successfully marked', async () => { - await accountCodeStorage - .connect(deployerAccount) - .storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH); + it("failed to set with constructed bytecode", async () => { + await expect( + accountCodeStorage + .connect(deployerAccount) + .storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTED_BYTECODE_HASH) + ).to.be.revertedWith("Code hash is not for a contract on constructor"); + }); - await accountCodeStorage.connect(deployerAccount).markAccountCodeHashAsConstructed(RANDOM_ADDRESS); + it("successfully stored", async () => { + await accountCodeStorage + .connect(deployerAccount) + .storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH); - expect(await accountCodeStorage.getRawCodeHash(RANDOM_ADDRESS)).to.be.eq( - CONSTRUCTED_BYTECODE_HASH.toLowerCase() - ); + expect(await accountCodeStorage.getRawCodeHash(RANDOM_ADDRESS)).to.be.eq( + CONSTRUCTING_BYTECODE_HASH.toLowerCase() + ); - await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); - }); + await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); }); + }); - describe('getRawCodeHash', function () { - it('zero', async () => { - expect(await accountCodeStorage.getRawCodeHash(RANDOM_ADDRESS)).to.be.eq(ethers.constants.HashZero); - }); + describe("storeAccountConstructedCodeHash", 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"); + }); - it('non-zero', async () => { - await accountCodeStorage - .connect(deployerAccount) - .storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTED_BYTECODE_HASH); + it("failed to set with constructing bytecode", async () => { + await expect( + accountCodeStorage + .connect(deployerAccount) + .storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH) + ).to.be.revertedWith("Code hash is not for a constructed contract"); + }); - expect(await accountCodeStorage.getRawCodeHash(RANDOM_ADDRESS)).to.be.eq( - CONSTRUCTED_BYTECODE_HASH.toLowerCase() - ); + it("successfully stored", async () => { + await accountCodeStorage + .connect(deployerAccount) + .storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTED_BYTECODE_HASH); - await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); - }); + expect(await accountCodeStorage.getRawCodeHash(RANDOM_ADDRESS)).to.be.eq(CONSTRUCTED_BYTECODE_HASH.toLowerCase()); + + await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); }); + }); - describe('getCodeHash', function () { - it('precompile', async () => { - expect(await accountCodeStorage.getCodeHash('0x0000000000000000000000000000000000000001')).to.be.eq( - EMPTY_STRING_KECCAK - ); - }); + 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" + ); + }); - it('EOA with non-zero nonce', async () => { - // This address at least deployed this contract - expect(await accountCodeStorage.getCodeHash(wallet.address)).to.be.eq(EMPTY_STRING_KECCAK); - }); + it("failed to mark already constructed bytecode", async () => { + await accountCodeStorage + .connect(deployerAccount) + .storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTED_BYTECODE_HASH); - it('address in the constructor', async () => { - await accountCodeStorage - .connect(deployerAccount) - .storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH); + await expect( + accountCodeStorage.connect(deployerAccount).markAccountCodeHashAsConstructed(RANDOM_ADDRESS) + ).to.be.revertedWith("Code hash is not for a contract on constructor"); - expect(await accountCodeStorage.getCodeHash(RANDOM_ADDRESS)).to.be.eq(EMPTY_STRING_KECCAK); + await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); + }); - await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); - }); + it("successfully marked", async () => { + await accountCodeStorage + .connect(deployerAccount) + .storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH); - it('constructed code hash', async () => { - await accountCodeStorage - .connect(deployerAccount) - .storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTED_BYTECODE_HASH); + await accountCodeStorage.connect(deployerAccount).markAccountCodeHashAsConstructed(RANDOM_ADDRESS); - expect(await accountCodeStorage.getCodeHash(RANDOM_ADDRESS)).to.be.eq( - CONSTRUCTED_BYTECODE_HASH.toLowerCase() - ); + expect(await accountCodeStorage.getRawCodeHash(RANDOM_ADDRESS)).to.be.eq(CONSTRUCTED_BYTECODE_HASH.toLowerCase()); - await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); - }); + await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); + }); + }); - it('zero', async () => { - expect(await accountCodeStorage.getCodeHash(RANDOM_ADDRESS)).to.be.eq(ethers.constants.HashZero); - }); + describe("getRawCodeHash", function () { + it("zero", async () => { + expect(await accountCodeStorage.getRawCodeHash(RANDOM_ADDRESS)).to.be.eq(ethers.constants.HashZero); }); - describe('getCodeSize', function () { - it('zero address', async () => { - expect(await accountCodeStorage.getCodeSize(ethers.constants.AddressZero)).to.be.eq(0); - }); + it("non-zero", async () => { + await accountCodeStorage + .connect(deployerAccount) + .storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTED_BYTECODE_HASH); - it('precompile', async () => { - expect(await accountCodeStorage.getCodeSize('0x0000000000000000000000000000000000000001')).to.be.eq(0); - }); + expect(await accountCodeStorage.getRawCodeHash(RANDOM_ADDRESS)).to.be.eq(CONSTRUCTED_BYTECODE_HASH.toLowerCase()); - it('address in the constructor', async () => { - await accountCodeStorage - .connect(deployerAccount) - .storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH); + await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); + }); + }); - expect(await accountCodeStorage.getCodeSize(RANDOM_ADDRESS)).to.be.eq(0); + describe("getCodeHash", function () { + it("precompile", async () => { + expect(await accountCodeStorage.getCodeHash("0x0000000000000000000000000000000000000001")).to.be.eq( + EMPTY_STRING_KECCAK + ); + }); - await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); - }); + it("EOA with non-zero nonce", async () => { + // This address at least deployed this contract + expect(await accountCodeStorage.getCodeHash(wallet.address)).to.be.eq(EMPTY_STRING_KECCAK); + }); - it('non-zero size', async () => { - await accountCodeStorage - .connect(deployerAccount) - .storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTED_BYTECODE_HASH); + it("address in the constructor", async () => { + await accountCodeStorage + .connect(deployerAccount) + .storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH); - expect(await accountCodeStorage.getCodeSize(RANDOM_ADDRESS)).to.be.eq(65535 * 32); + expect(await accountCodeStorage.getCodeHash(RANDOM_ADDRESS)).to.be.eq(EMPTY_STRING_KECCAK); - await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); - }); + await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); + }); - it('zero', async () => { - expect(await accountCodeStorage.getCodeSize(RANDOM_ADDRESS)).to.be.eq(0); - }); + it("constructed code hash", async () => { + await accountCodeStorage + .connect(deployerAccount) + .storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTED_BYTECODE_HASH); + + expect(await accountCodeStorage.getCodeHash(RANDOM_ADDRESS)).to.be.eq(CONSTRUCTED_BYTECODE_HASH.toLowerCase()); + + await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); + }); + + it("zero", async () => { + expect(await accountCodeStorage.getCodeHash(RANDOM_ADDRESS)).to.be.eq(ethers.constants.HashZero); + }); + }); + + describe("getCodeSize", function () { + it("zero address", async () => { + expect(await accountCodeStorage.getCodeSize(ethers.constants.AddressZero)).to.be.eq(0); }); + + it("precompile", async () => { + expect(await accountCodeStorage.getCodeSize("0x0000000000000000000000000000000000000001")).to.be.eq(0); + }); + + it("address in the constructor", async () => { + await accountCodeStorage + .connect(deployerAccount) + .storeAccountConstructingCodeHash(RANDOM_ADDRESS, CONSTRUCTING_BYTECODE_HASH); + + expect(await accountCodeStorage.getCodeSize(RANDOM_ADDRESS)).to.be.eq(0); + + await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); + }); + + it("non-zero size", async () => { + await accountCodeStorage + .connect(deployerAccount) + .storeAccountConstructedCodeHash(RANDOM_ADDRESS, CONSTRUCTED_BYTECODE_HASH); + + expect(await accountCodeStorage.getCodeSize(RANDOM_ADDRESS)).to.be.eq(65535 * 32); + + await unsetCodeHash(accountCodeStorage, RANDOM_ADDRESS); + }); + + it("zero", async () => { + expect(await accountCodeStorage.getCodeSize(RANDOM_ADDRESS)).to.be.eq(0); + }); + }); }); // Utility function to unset code hash for the specified address. // Deployer system contract should be impersonated async function unsetCodeHash(accountCodeStorage: AccountCodeStorage, address: string) { - const deployerAccount = await ethers.getImpersonatedSigner(DEPLOYER_SYSTEM_CONTRACT_ADDRESS); + const deployerAccount = await ethers.getImpersonatedSigner(DEPLOYER_SYSTEM_CONTRACT_ADDRESS); - await accountCodeStorage - .connect(deployerAccount) - .storeAccountConstructedCodeHash(address, ethers.constants.HashZero); + await accountCodeStorage.connect(deployerAccount).storeAccountConstructedCodeHash(address, ethers.constants.HashZero); } diff --git a/test/BootloaderUtilities.spec.ts b/test/BootloaderUtilities.spec.ts index 70e63781f79..b191497855f 100644 --- a/test/BootloaderUtilities.spec.ts +++ b/test/BootloaderUtilities.spec.ts @@ -1,182 +1,182 @@ -import { expect } from 'chai'; -import { ethers } from 'hardhat'; -import * as zksync from 'zksync-web3'; -import { Wallet } from 'zksync-web3'; -import { serialize } from 'zksync-web3/build/src/utils'; -import { BootloaderUtilities } from '../typechain-types'; -import { signedTxToTransactionData } from './shared/transactions'; -import { deployContract, getWallets } from './shared/utils'; - -describe('BootloaderUtilities tests', function () { - let wallet: Wallet; - let bootloaderUtilities: BootloaderUtilities; - - before(async () => { - wallet = getWallets()[0]; - bootloaderUtilities = (await deployContract('BootloaderUtilities')) as BootloaderUtilities; +import { expect } from "chai"; +import { ethers } from "hardhat"; +import * as zksync from "zksync-web3"; +import type { Wallet } from "zksync-web3"; +import { serialize } from "zksync-web3/build/src/utils"; +import type { BootloaderUtilities } from "../typechain-types"; +import { signedTxToTransactionData } from "./shared/transactions"; +import { deployContract, getWallets } from "./shared/utils"; + +describe("BootloaderUtilities tests", function () { + let wallet: Wallet; + let bootloaderUtilities: BootloaderUtilities; + + before(async () => { + wallet = getWallets()[0]; + bootloaderUtilities = (await deployContract("BootloaderUtilities")) as BootloaderUtilities; + }); + + describe("EIP-712 transaction", function () { + it("check hashes", async () => { + const eip712Tx = await wallet.populateTransaction({ + type: 113, + to: wallet.address, + from: wallet.address, + data: "0x", + value: 0, + maxFeePerGas: 12000, + maxPriorityFeePerGas: 100, + customData: { + gasPerPubdata: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, + }, + }); + const signedEip712Tx = await wallet.signTransaction(eip712Tx); + const parsedEIP712tx = zksync.utils.parseTransaction(signedEip712Tx); + + const eip712TxData = signedTxToTransactionData(parsedEIP712tx)!; + const expectedEIP712TxHash = parsedEIP712tx.hash; + const expectedEIP712SignedHash = zksync.EIP712Signer.getSignedDigest(eip712Tx); + + const proposedEIP712Hashes = await bootloaderUtilities.getTransactionHashes(eip712TxData); + + expect(proposedEIP712Hashes.txHash).to.be.eq(expectedEIP712TxHash); + expect(proposedEIP712Hashes.signedTxHash).to.be.eq(expectedEIP712SignedHash); }); - - describe('EIP-712 transaction', function () { - it('check hashes', async () => { - const eip712Tx = await wallet.populateTransaction({ - type: 113, - to: wallet.address, - from: wallet.address, - data: '0x', - value: 0, - maxFeePerGas: 12000, - maxPriorityFeePerGas: 100, - customData: { - gasPerPubdata: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT - } - }); - const signedEip712Tx = await wallet.signTransaction(eip712Tx); - const parsedEIP712tx = zksync.utils.parseTransaction(signedEip712Tx); - - const eip712TxData = signedTxToTransactionData(parsedEIP712tx)!; - const expectedEIP712TxHash = parsedEIP712tx.hash; - const expectedEIP712SignedHash = zksync.EIP712Signer.getSignedDigest(eip712Tx); - - const proposedEIP712Hashes = await bootloaderUtilities.getTransactionHashes(eip712TxData); - - expect(proposedEIP712Hashes.txHash).to.be.eq(expectedEIP712TxHash); - expect(proposedEIP712Hashes.signedTxHash).to.be.eq(expectedEIP712SignedHash); - }); + }); + + describe("legacy transaction", function () { + it("check hashes", async () => { + const legacyTx = await wallet.populateTransaction({ + type: 0, + to: wallet.address, + from: wallet.address, + data: "0x", + value: 0, + gasLimit: 50000, + }); + const txBytes = await wallet.signTransaction(legacyTx); + const parsedTx = zksync.utils.parseTransaction(txBytes); + const txData = signedTxToTransactionData(parsedTx)!; + + const expectedTxHash = parsedTx.hash; + delete legacyTx.from; + const expectedSignedHash = ethers.utils.keccak256(serialize(legacyTx)); + + const proposedHashes = await bootloaderUtilities.getTransactionHashes(txData); + expect(proposedHashes.txHash).to.be.eq(expectedTxHash); + expect(proposedHashes.signedTxHash).to.be.eq(expectedSignedHash); }); - describe('legacy transaction', function () { - it('check hashes', async () => { - const legacyTx = await wallet.populateTransaction({ - type: 0, - to: wallet.address, - from: wallet.address, - data: '0x', - value: 0, - gasLimit: 50000 - }); - const txBytes = await wallet.signTransaction(legacyTx); - const parsedTx = zksync.utils.parseTransaction(txBytes); - const txData = signedTxToTransactionData(parsedTx)!; - - const expectedTxHash = parsedTx.hash; - delete legacyTx.from; - const expectedSignedHash = ethers.utils.keccak256(serialize(legacyTx)); - - const proposedHashes = await bootloaderUtilities.getTransactionHashes(txData); - expect(proposedHashes.txHash).to.be.eq(expectedTxHash); - expect(proposedHashes.signedTxHash).to.be.eq(expectedSignedHash); - }); - - it('invalid v signature value', async () => { - const legacyTx = await wallet.populateTransaction({ - type: 0, - to: wallet.address, - from: wallet.address, - data: '0x', - value: 0, - gasLimit: 50000 - }); - const txBytes = await wallet.signTransaction(legacyTx); - const parsedTx = zksync.utils.parseTransaction(txBytes); - const txData = signedTxToTransactionData(parsedTx)!; - - const signature = ethers.utils.arrayify(txData.signature); - signature[64] = 29; - txData.signature = signature; - - await expect(bootloaderUtilities.getTransactionHashes(txData)).to.be.revertedWith('Invalid v value'); - }); + it("invalid v signature value", async () => { + const legacyTx = await wallet.populateTransaction({ + type: 0, + to: wallet.address, + from: wallet.address, + data: "0x", + value: 0, + gasLimit: 50000, + }); + const txBytes = await wallet.signTransaction(legacyTx); + const parsedTx = zksync.utils.parseTransaction(txBytes); + const txData = signedTxToTransactionData(parsedTx)!; + + const signature = ethers.utils.arrayify(txData.signature); + signature[64] = 29; + txData.signature = signature; + + await expect(bootloaderUtilities.getTransactionHashes(txData)).to.be.revertedWith("Invalid v value"); + }); + }); + + describe("EIP-1559 transaction", function () { + it("check hashes", async () => { + const eip1559Tx = await wallet.populateTransaction({ + type: 2, + to: wallet.address, + from: wallet.address, + data: "0x", + value: 0, + maxFeePerGas: 12000, + maxPriorityFeePerGas: 100, + }); + const signedEip1559Tx = await wallet.signTransaction(eip1559Tx); + const parsedEIP1559tx = zksync.utils.parseTransaction(signedEip1559Tx); + + const EIP1559TxData = signedTxToTransactionData(parsedEIP1559tx)!; + delete eip1559Tx.from; + const expectedEIP1559TxHash = parsedEIP1559tx.hash; + const expectedEIP1559SignedHash = ethers.utils.keccak256(serialize(eip1559Tx)); + + const proposedEIP1559Hashes = await bootloaderUtilities.getTransactionHashes(EIP1559TxData); + expect(proposedEIP1559Hashes.txHash).to.be.eq(expectedEIP1559TxHash); + expect(proposedEIP1559Hashes.signedTxHash).to.be.eq(expectedEIP1559SignedHash); }); - describe('EIP-1559 transaction', function () { - it('check hashes', async () => { - const eip1559Tx = await wallet.populateTransaction({ - type: 2, - to: wallet.address, - from: wallet.address, - data: '0x', - value: 0, - maxFeePerGas: 12000, - maxPriorityFeePerGas: 100 - }); - const signedEip1559Tx = await wallet.signTransaction(eip1559Tx); - const parsedEIP1559tx = zksync.utils.parseTransaction(signedEip1559Tx); - - const EIP1559TxData = signedTxToTransactionData(parsedEIP1559tx)!; - delete eip1559Tx.from; - const expectedEIP1559TxHash = parsedEIP1559tx.hash; - const expectedEIP1559SignedHash = ethers.utils.keccak256(serialize(eip1559Tx)); - - const proposedEIP1559Hashes = await bootloaderUtilities.getTransactionHashes(EIP1559TxData); - expect(proposedEIP1559Hashes.txHash).to.be.eq(expectedEIP1559TxHash); - expect(proposedEIP1559Hashes.signedTxHash).to.be.eq(expectedEIP1559SignedHash); - }); - - it('invalid v signature value', async () => { - const eip1559Tx = await wallet.populateTransaction({ - type: 2, - to: wallet.address, - from: wallet.address, - data: '0x', - value: 0, - maxFeePerGas: 12000, - maxPriorityFeePerGas: 100 - }); - const signedEip1559Tx = await wallet.signTransaction(eip1559Tx); - const parsedEIP1559tx = zksync.utils.parseTransaction(signedEip1559Tx); - - const EIP1559TxData = signedTxToTransactionData(parsedEIP1559tx)!; - const signature = ethers.utils.arrayify(EIP1559TxData.signature); - signature[64] = 0; - EIP1559TxData.signature = signature; - - await expect(bootloaderUtilities.getTransactionHashes(EIP1559TxData)).to.be.revertedWith('Invalid v value'); - }); + it("invalid v signature value", async () => { + const eip1559Tx = await wallet.populateTransaction({ + type: 2, + to: wallet.address, + from: wallet.address, + data: "0x", + value: 0, + maxFeePerGas: 12000, + maxPriorityFeePerGas: 100, + }); + const signedEip1559Tx = await wallet.signTransaction(eip1559Tx); + const parsedEIP1559tx = zksync.utils.parseTransaction(signedEip1559Tx); + + const EIP1559TxData = signedTxToTransactionData(parsedEIP1559tx)!; + const signature = ethers.utils.arrayify(EIP1559TxData.signature); + signature[64] = 0; + EIP1559TxData.signature = signature; + + await expect(bootloaderUtilities.getTransactionHashes(EIP1559TxData)).to.be.revertedWith("Invalid v value"); + }); + }); + + describe("EIP-1559 transaction", function () { + it("check hashes", async () => { + const eip2930Tx = await wallet.populateTransaction({ + type: 1, + to: wallet.address, + from: wallet.address, + data: "0x", + value: 0, + gasLimit: 50000, + gasPrice: 55000, + }); + const signedEip2930Tx = await wallet.signTransaction(eip2930Tx); + const parsedEIP2930tx = zksync.utils.parseTransaction(signedEip2930Tx); + + const EIP2930TxData = signedTxToTransactionData(parsedEIP2930tx)!; + delete eip2930Tx.from; + const expectedEIP2930TxHash = parsedEIP2930tx.hash; + const expectedEIP2930SignedHash = ethers.utils.keccak256(serialize(eip2930Tx)); + + const proposedEIP2930Hashes = await bootloaderUtilities.getTransactionHashes(EIP2930TxData); + expect(proposedEIP2930Hashes.txHash).to.be.eq(expectedEIP2930TxHash); + expect(proposedEIP2930Hashes.signedTxHash).to.be.eq(expectedEIP2930SignedHash); }); - describe('EIP-1559 transaction', function () { - it('check hashes', async () => { - const eip2930Tx = await wallet.populateTransaction({ - type: 1, - to: wallet.address, - from: wallet.address, - data: '0x', - value: 0, - gasLimit: 50000, - gasPrice: 55000 - }); - const signedEip2930Tx = await wallet.signTransaction(eip2930Tx); - const parsedEIP2930tx = zksync.utils.parseTransaction(signedEip2930Tx); - - const EIP2930TxData = signedTxToTransactionData(parsedEIP2930tx)!; - delete eip2930Tx.from; - const expectedEIP2930TxHash = parsedEIP2930tx.hash; - const expectedEIP2930SignedHash = ethers.utils.keccak256(serialize(eip2930Tx)); - - const proposedEIP2930Hashes = await bootloaderUtilities.getTransactionHashes(EIP2930TxData); - expect(proposedEIP2930Hashes.txHash).to.be.eq(expectedEIP2930TxHash); - expect(proposedEIP2930Hashes.signedTxHash).to.be.eq(expectedEIP2930SignedHash); - }); - - it('invalid v signature value', async () => { - const eip2930Tx = await wallet.populateTransaction({ - type: 1, - to: wallet.address, - from: wallet.address, - data: '0x', - value: 0, - gasLimit: 50000, - gasPrice: 55000 - }); - const signedEip2930Tx = await wallet.signTransaction(eip2930Tx); - const parsedEIP2930tx = zksync.utils.parseTransaction(signedEip2930Tx); - - const EIP2930TxData = signedTxToTransactionData(parsedEIP2930tx)!; - const signature = ethers.utils.arrayify(EIP2930TxData.signature); - signature[64] = 100; - EIP2930TxData.signature = signature; - - await expect(bootloaderUtilities.getTransactionHashes(EIP2930TxData)).to.be.revertedWith('Invalid v value'); - }); + it("invalid v signature value", async () => { + const eip2930Tx = await wallet.populateTransaction({ + type: 1, + to: wallet.address, + from: wallet.address, + data: "0x", + value: 0, + gasLimit: 50000, + gasPrice: 55000, + }); + const signedEip2930Tx = await wallet.signTransaction(eip2930Tx); + const parsedEIP2930tx = zksync.utils.parseTransaction(signedEip2930Tx); + + const EIP2930TxData = signedTxToTransactionData(parsedEIP2930tx)!; + const signature = ethers.utils.arrayify(EIP2930TxData.signature); + signature[64] = 100; + EIP2930TxData.signature = signature; + + await expect(bootloaderUtilities.getTransactionHashes(EIP2930TxData)).to.be.revertedWith("Invalid v value"); }); + }); }); diff --git a/test/ComplexUpgrader.spec.ts b/test/ComplexUpgrader.spec.ts index ea92b57a3d3..20a341f493b 100644 --- a/test/ComplexUpgrader.spec.ts +++ b/test/ComplexUpgrader.spec.ts @@ -1,46 +1,43 @@ -import { expect } from 'chai'; -import { ethers, network } from 'hardhat'; -import { ComplexUpgrader, DummyUpgrade } from '../typechain-types'; -import { FORCE_DEPLOYER_ADDRESS } from './shared/constants'; -import { deployContract } from './shared/utils'; +import { expect } from "chai"; +import { ethers, network } from "hardhat"; +import type { ComplexUpgrader, DummyUpgrade } from "../typechain-types"; +import { FORCE_DEPLOYER_ADDRESS } from "./shared/constants"; +import { deployContract } from "./shared/utils"; -describe('ComplexUpgrader tests', function () { - let complexUpgrader: ComplexUpgrader; - let dummyUpgrade: DummyUpgrade; +describe("ComplexUpgrader tests", function () { + let complexUpgrader: ComplexUpgrader; + let dummyUpgrade: DummyUpgrade; - before(async () => { - complexUpgrader = (await deployContract('ComplexUpgrader')) as ComplexUpgrader; - dummyUpgrade = (await deployContract('DummyUpgrade')) as DummyUpgrade; - }); + before(async () => { + complexUpgrader = (await deployContract("ComplexUpgrader")) as ComplexUpgrader; + dummyUpgrade = (await deployContract("DummyUpgrade")) as DummyUpgrade; + }); - describe('upgrade', function () { - it('non force deployer failed to call', async () => { - await expect( - complexUpgrader.upgrade( - dummyUpgrade.address, - dummyUpgrade.interface.encodeFunctionData('performUpgrade') - ) - ).to.be.revertedWith('Can only be called by FORCE_DEPLOYER'); - }); + describe("upgrade", function () { + it("non force deployer failed to call", async () => { + await expect( + complexUpgrader.upgrade(dummyUpgrade.address, dummyUpgrade.interface.encodeFunctionData("performUpgrade")) + ).to.be.revertedWith("Can only be called by FORCE_DEPLOYER"); + }); - it('successfully upgraded', async () => { - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [FORCE_DEPLOYER_ADDRESS] - }); + it("successfully upgraded", async () => { + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [FORCE_DEPLOYER_ADDRESS], + }); - const force_deployer = await ethers.getSigner(FORCE_DEPLOYER_ADDRESS); + const force_deployer = await ethers.getSigner(FORCE_DEPLOYER_ADDRESS); - await expect( - complexUpgrader - .connect(force_deployer) - .upgrade(dummyUpgrade.address, dummyUpgrade.interface.encodeFunctionData('performUpgrade')) - ).to.emit(dummyUpgrade.attach(complexUpgrader.address), 'Upgraded'); + await expect( + complexUpgrader + .connect(force_deployer) + .upgrade(dummyUpgrade.address, dummyUpgrade.interface.encodeFunctionData("performUpgrade")) + ).to.emit(dummyUpgrade.attach(complexUpgrader.address), "Upgraded"); - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [FORCE_DEPLOYER_ADDRESS] - }); - }); + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [FORCE_DEPLOYER_ADDRESS], + }); }); + }); }); diff --git a/test/Compressor.spec.ts b/test/Compressor.spec.ts index 0e1ba314922..90621c8e4be 100644 --- a/test/Compressor.spec.ts +++ b/test/Compressor.spec.ts @@ -1,531 +1,513 @@ -import { expect } from 'chai'; -import { BigNumber, BytesLike } from 'ethers'; -import { ethers, network } from 'hardhat'; -import * as zksync from 'zksync-web3'; -import { Wallet } from 'zksync-web3'; -import { Compressor, MockKnownCodesStorage__factory } from '../typechain-types'; +import { expect } from "chai"; +import type { BytesLike } from "ethers"; +import { BigNumber } from "ethers"; +import { ethers, network } from "hardhat"; +import * as zksync from "zksync-web3"; +import type { Wallet } from "zksync-web3"; +import type { Compressor } from "../typechain-types"; +import { MockKnownCodesStorage__factory } from "../typechain-types"; import { - BOOTLOADER_FORMAL_ADDRESS, - KNOWN_CODE_STORAGE_CONTRACT_ADDRESS, - L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, - TWO_IN_256 -} from './shared/constants'; -import { deployContract, getCode, getWallets, loadArtifact, setCode } from './shared/utils'; - -describe('Compressor tests', function () { - let wallet: Wallet; - let compressor: Compressor; - let bootloader: ethers.Signer; - let l1Messenger: ethers.Signer; - - let _knownCodesStorageCode: string; - - before(async () => { - wallet = getWallets()[0]; - compressor = (await deployContract('Compressor')) as Compressor; - _knownCodesStorageCode = await getCode(KNOWN_CODE_STORAGE_CONTRACT_ADDRESS); - const mockKnownCodesStorageArtifact = await loadArtifact('MockKnownCodesStorage'); - await setCode(KNOWN_CODE_STORAGE_CONTRACT_ADDRESS, mockKnownCodesStorageArtifact.bytecode); - - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); - - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS] - }); - l1Messenger = await ethers.getSigner(L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS); + BOOTLOADER_FORMAL_ADDRESS, + KNOWN_CODE_STORAGE_CONTRACT_ADDRESS, + L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, + TWO_IN_256, +} from "./shared/constants"; +import { deployContract, getCode, getWallets, loadArtifact, setCode } from "./shared/utils"; + +describe("Compressor tests", function () { + let wallet: Wallet; + let compressor: Compressor; + let bootloader: ethers.Signer; + let l1Messenger: ethers.Signer; + + let _knownCodesStorageCode: string; + + before(async () => { + wallet = getWallets()[0]; + compressor = (await deployContract("Compressor")) as Compressor; + _knownCodesStorageCode = await getCode(KNOWN_CODE_STORAGE_CONTRACT_ADDRESS); + const mockKnownCodesStorageArtifact = await loadArtifact("MockKnownCodesStorage"); + await setCode(KNOWN_CODE_STORAGE_CONTRACT_ADDRESS, mockKnownCodesStorageArtifact.bytecode); + + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], }); + bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); - after(async function () { - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS], + }); + l1Messenger = await ethers.getSigner(L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS); + }); + + after(async function () { + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], + }); - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS] - }); + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS], + }); + + await setCode(KNOWN_CODE_STORAGE_CONTRACT_ADDRESS, _knownCodesStorageCode); + }); + + describe("publishCompressedBytecode", function () { + it("non-bootloader failed to call", async () => { + await expect(compressor.publishCompressedBytecode("0x", "0x0000")).to.be.revertedWith( + "Callable only by the bootloader" + ); + }); - await setCode(KNOWN_CODE_STORAGE_CONTRACT_ADDRESS, _knownCodesStorageCode); + it("invalid encoded length", async () => { + const BYTECODE = "0xdeadbeefdeadbeef"; + const COMPRESSED_BYTECODE = "0x0001deadbeefdeadbeef00000000"; + await expect( + compressor.connect(bootloader).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) + ).to.be.revertedWith("Encoded data length should be 4 times shorter than the original bytecode"); }); - describe('publishCompressedBytecode', function () { - it('non-bootloader failed to call', async () => { - await expect(compressor.publishCompressedBytecode('0x', '0x0000')).to.be.revertedWith( - 'Callable only by the bootloader' - ); - }); - - it('invalid encoded length', async () => { - const BYTECODE = '0xdeadbeefdeadbeef'; - const COMPRESSED_BYTECODE = '0x0001deadbeefdeadbeef00000000'; - await expect( - compressor.connect(bootloader).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) - ).to.be.revertedWith('Encoded data length should be 4 times shorter than the original bytecode'); - }); - - it('chunk index is out of bounds', async () => { - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - - const bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); - - const BYTECODE = '0xdeadbeefdeadbeef'; - const COMPRESSED_BYTECODE = '0x0001deadbeefdeadbeef0001'; - await expect( - compressor.connect(bootloader).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) - ).to.be.revertedWith('Encoded chunk index is out of bounds'); - - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - }); - - it('chunk does not match the original bytecode', async () => { - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - - const bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); - - const BYTECODE = '0xdeadbeefdeadbeef1111111111111111'; - const COMPRESSED_BYTECODE = '0x0002deadbeefdeadbeef111111111111111100000000'; - await expect( - compressor.connect(bootloader).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) - ).to.be.revertedWith('Encoded chunk does not match the original bytecode'); - - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - }); - - it('invalid bytecode length in bytes', async () => { - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - - const bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); - - const BYTECODE = '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'; - const COMPRESSED_BYTECODE = '0x0001deadbeefdeadbeef000000000000'; - await expect( - compressor.connect(bootloader).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) - ).to.be.revertedWith('po'); - - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - }); - - // Test case with too big bytecode is unrealistic because API cannot accept so much data. - it('invalid bytecode length in words', async () => { - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - - const bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); - - const BYTECODE = '0x' + 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'.repeat(2); - const COMPRESSED_BYTECODE = '0x0001deadbeefdeadbeef' + '0000'.repeat(4 * 2); - await expect( - compressor.connect(bootloader).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) - ).to.be.revertedWith('pr'); - - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - }); - - it('successfully published', async () => { - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - - const bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); - - const BYTECODE = - '0x000200000000000200010000000103550000006001100270000000150010019d0000000101200190000000080000c13d0000000001000019004e00160000040f0000000101000039004e00160000040f0000001504000041000000150510009c000000000104801900000040011002100000000001310019000000150320009c0000000002048019000000600220021000000000012100190000004f0001042e000000000100001900000050000104300000008002000039000000400020043f0000000002000416000000000110004c000000240000613d000000000120004c0000004d0000c13d000000200100003900000100001004430000012000000443000001000100003900000040020000390000001d03000041004e000a0000040f000000000120004c0000004d0000c13d0000000001000031000000030110008c0000004d0000a13d0000000101000367000000000101043b0000001601100197000000170110009c0000004d0000c13d0000000101000039000000000101041a0000000202000039000000000202041a000000400300043d00000040043000390000001805200197000000000600041a0000000000540435000000180110019700000020043000390000000000140435000000a0012002700000001901100197000000600430003900000000001404350000001a012001980000001b010000410000000001006019000000b8022002700000001c02200197000000000121019f0000008002300039000000000012043500000018016001970000000000130435000000400100043d0000000002130049000000a0022000390000000003000019004e000a0000040f004e00140000040f0000004e000004320000004f0001042e000000500001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff000000000000000000000000000000000000000000000000000000008903573000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000ffffff0000000000008000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000007fffff00000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; - const COMPRESSED_BYTECODE = - '0x00510000000000000000ffffffffffffffff0000004d0000c13d00000000ffffffff0000000000140435004e000a0000040f000000000120004c00000050000104300000004f0001042e0000000101000039004e00160000040f0000000001000019000000020000000000000000007fffffffffffffff80000000000000000080000000000000ffffff8903573000000000ffffffff000000000000004e00000432004e00140000040f0000000003000019000000a0022000390000000002130049000000400100043d0000000000130435000000180160019700000000001204350000008002300039000000000121019f0000001c02200197000000b80220027000000000010060190000001b010000410000001a0120019800000060043000390000001901100197000000a001200270000000200430003900000018011001970000000000540435000000000600041a00000018052001970000004004300039000000400300043d000000000202041a0000000202000039000000000101041a000000170110009c0000001601100197000000000101043b00000001010003670000004d0000a13d000000030110008c00000000010000310000001d0300004100000040020000390000010001000039000001200000044300000100001004430000002001000039000000240000613d000000000110004c0000000002000416000000400020043f0000008002000039000000000121001900000060022002100000000002048019000000150320009c000000000131001900000040011002100000000001048019000000150510009c0000001504000041000000080000c13d0000000101200190000000150010019d0000006001100270000100000001035500020000000000020050004f004e004d004c004b000b000a0009000a004a004900480047004600450044004300420008000b000700410040003f003e003d00060002003c003b003a003900380037000500060002003600350034003300320031003000020009002f002e002d002c002b002a002900280027002600040025002400230004002200210020001f001e001d001c001b001a001900180017001600150005001400130008000700000000000000000000000000030012000000000000001100000000000000000003000100010000000000000010000f000000000000000100010001000e000000000000000d000c0000000000000000000000000000'; - await expect(compressor.connect(bootloader).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE)) - .to.emit( - MockKnownCodesStorage__factory.connect(KNOWN_CODE_STORAGE_CONTRACT_ADDRESS, wallet), - 'MockBytecodePublished' - ) - .withArgs(zksync.utils.hashBytecode(BYTECODE)); - - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - }); + it("chunk index is out of bounds", async () => { + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], + }); + + const bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); + + const BYTECODE = "0xdeadbeefdeadbeef"; + const COMPRESSED_BYTECODE = "0x0001deadbeefdeadbeef0001"; + await expect( + compressor.connect(bootloader).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) + ).to.be.revertedWith("Encoded chunk index is out of bounds"); + + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], + }); }); - describe('verifyCompressedStateDiffs', function () { - it('non l1 messenger failed to call', async () => { - await expect(compressor.verifyCompressedStateDiffs(0, 8, '0x', '0x0000')).to.be.revertedWith( - 'Inappropriate caller' - ); - }); - - it('enumeration index size is too large', async () => { - const stateDiffs = [ - { - key: '0x1234567890123456789012345678901234567890123456789012345678901234', - index: 0, - initValue: BigNumber.from(0), - finalValue: BigNumber.from('0x1234567890123456789012345678901234567890123456789012345678901234') - } - ]; - const encodedStateDiffs = encodeStateDiffs(stateDiffs); - stateDiffs[0].key = '0x1234567890123456789012345678901234567890123456789012345678901233'; - const compressedStateDiffs = compressStateDiffs(9, stateDiffs); - await expect( - compressor - .connect(l1Messenger) - .verifyCompressedStateDiffs(1, 9, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith('enumeration index size is too large'); - }); - - it('initial write key mismatch', async () => { - const stateDiffs = [ - { - key: '0x1234567890123456789012345678901234567890123456789012345678901234', - index: 0, - initValue: BigNumber.from(1), - finalValue: BigNumber.from(0) - } - ]; - const encodedStateDiffs = encodeStateDiffs(stateDiffs); - stateDiffs[0].key = '0x1234567890123456789012345678901234567890123456789012345678901233'; - const compressedStateDiffs = compressStateDiffs(4, stateDiffs); - await expect( - compressor - .connect(l1Messenger) - .verifyCompressedStateDiffs(1, 4, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith('iw: initial key mismatch'); - }); - - it('repeated write key mismatch', async () => { - const stateDiffs = [ - { - key: '0x1234567890123456789012345678901234567890123456789012345678901234', - index: 1, - initValue: BigNumber.from(1), - finalValue: BigNumber.from(0) - } - ]; - const encodedStateDiffs = encodeStateDiffs(stateDiffs); - stateDiffs[0].index = 2; - const compressedStateDiffs = compressStateDiffs(8, stateDiffs); - await expect( - compressor - .connect(l1Messenger) - .verifyCompressedStateDiffs(1, 8, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith('rw: enum key mismatch'); - }); - - it('no compression value mismatch', async () => { - const stateDiffs = [ - { - key: '0x1234567890123456789012345678901234567890123456789012345678901234', - index: 1, - initValue: BigNumber.from(1), - finalValue: BigNumber.from(0) - }, - { - key: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef', - index: 0, - initValue: TWO_IN_256.div(2), - finalValue: TWO_IN_256.sub(2) - } - ]; - const encodedStateDiffs = encodeStateDiffs(stateDiffs); - stateDiffs[1].finalValue = TWO_IN_256.sub(1); - const compressedStateDiffs = compressStateDiffs(3, stateDiffs); - await expect( - compressor - .connect(l1Messenger) - .verifyCompressedStateDiffs(2, 3, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith('transform or no compression: compressed and final mismatch'); - }); - - it('transform value mismatch', async () => { - const stateDiffs = [ - { - key: '0x1234567890123456789012345678901234567890123456789012345678901234', - index: 255, - initValue: BigNumber.from(1), - finalValue: BigNumber.from(0) - }, - { - key: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef', - index: 0, - initValue: TWO_IN_256.div(2), - finalValue: BigNumber.from(1) - } - ]; - const encodedStateDiffs = encodeStateDiffs(stateDiffs); - stateDiffs[1].finalValue = BigNumber.from(0); - const compressedStateDiffs = compressStateDiffs(1, stateDiffs); - await expect( - compressor - .connect(l1Messenger) - .verifyCompressedStateDiffs(2, 1, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith('transform or no compression: compressed and final mismatch'); - }); - - it('add value mismatch', async () => { - const stateDiffs = [ - { - key: '0x1234567890123456789012345678901234567890123456789012345678901235', - index: 255, - initValue: TWO_IN_256.div(2).sub(2), - finalValue: TWO_IN_256.div(2).sub(1) - } - ]; - const encodedStateDiffs = encodeStateDiffs(stateDiffs); - stateDiffs[0].finalValue = TWO_IN_256.div(2); - const compressedStateDiffs = compressStateDiffs(1, stateDiffs); - await expect( - compressor - .connect(l1Messenger) - .verifyCompressedStateDiffs(1, 1, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith('add: initial plus converted not equal to final'); - }); - - it('sub value mismatch', async () => { - const stateDiffs = [ - { - key: '0x1234567890123456789012345678901234567890123456789012345678901236', - index: 0, - initValue: TWO_IN_256.div(4), - finalValue: TWO_IN_256.div(4).sub(5) - } - ]; - const encodedStateDiffs = encodeStateDiffs(stateDiffs); - stateDiffs[0].finalValue = TWO_IN_256.div(4).sub(1); - const compressedStateDiffs = compressStateDiffs(1, stateDiffs); - await expect( - compressor - .connect(l1Messenger) - .verifyCompressedStateDiffs(1, 1, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith('sub: initial minus converted not equal to final'); - }); - - it('invalid operation', async () => { - const stateDiffs = [ - { - key: '0x1234567890123456789012345678901234567890123456789012345678901236', - index: 0, - initValue: TWO_IN_256.div(4), - finalValue: TWO_IN_256.div(4).sub(5) - } - ]; - const encodedStateDiffs = encodeStateDiffs(stateDiffs); - let compressedStateDiffs = compressStateDiffs(1, stateDiffs); - const compressedStateDiffsCharArray = compressedStateDiffs.split(''); - compressedStateDiffsCharArray[2 + 4 + 64 + 1] = 'f'; - compressedStateDiffs = compressedStateDiffsCharArray.join(''); - await expect( - compressor - .connect(l1Messenger) - .verifyCompressedStateDiffs(1, 1, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith('unsupported operation'); - }); - - it('Incorrect number of initial storage diffs', async () => { - const stateDiffs = [ - { - key: '0x1234567890123456789012345678901234567890123456789012345678901236', - index: 0, - initValue: TWO_IN_256.div(4), - finalValue: TWO_IN_256.div(4).sub(5) - }, - { - key: '0x1234567890123456789012345678901234567890123456789012345678901239', - index: 121, - initValue: TWO_IN_256.sub(1), - finalValue: BigNumber.from(0) - } - ]; - const encodedStateDiffs = encodeStateDiffs(stateDiffs); - stateDiffs.push({ - key: '0x0234567890123456789012345678901234567890123456789012345678901231', - index: 0, - initValue: BigNumber.from(0), - finalValue: BigNumber.from(1) - }); - const compressedStateDiffs = compressStateDiffs(1, stateDiffs); - await expect( - compressor - .connect(l1Messenger) - .verifyCompressedStateDiffs(2, 1, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith('Incorrect number of initial storage diffs'); - }); - - it('Extra data in compressed state diffs', async () => { - const stateDiffs = [ - { - key: '0x1234567890123456789012345678901234567890123456789012345678901236', - index: 0, - initValue: TWO_IN_256.div(4), - finalValue: TWO_IN_256.div(4).sub(5) - }, - { - key: '0x1234567890123456789012345678901234567890123456789012345678901239', - index: 121, - initValue: TWO_IN_256.sub(1), - finalValue: BigNumber.from(0) - } - ]; - const encodedStateDiffs = encodeStateDiffs(stateDiffs); - stateDiffs.push({ - key: '0x0234567890123456789012345678901234567890123456789012345678901231', - index: 1, - initValue: BigNumber.from(0), - finalValue: BigNumber.from(1) - }); - const compressedStateDiffs = compressStateDiffs(1, stateDiffs); - await expect( - compressor - .connect(l1Messenger) - .verifyCompressedStateDiffs(2, 1, encodedStateDiffs, compressedStateDiffs) - ).to.be.revertedWith('Extra data in _compressedStateDiffs'); - }); - - it('successfully verified', async () => { - const stateDiffs = [ - { - key: '0x1234567890123456789012345678901234567890123456789012345678901230', - index: 0, - initValue: BigNumber.from('0x1234567890123456789012345678901234567890123456789012345678901231'), - finalValue: BigNumber.from('0x1234567890123456789012345678901234567890123456789012345678901230') - }, - { - key: '0x1234567890123456789012345678901234567890123456789012345678901232', - index: 1, - initValue: TWO_IN_256.sub(1), - finalValue: BigNumber.from(1) - }, - { - key: '0x1234567890123456789012345678901234567890123456789012345678901234', - index: 0, - initValue: TWO_IN_256.div(2), - finalValue: BigNumber.from(1) - }, - { - key: '0x1234567890123456789012345678901234567890123456789012345678901236', - index: 2323, - initValue: BigNumber.from('0x1234567890123456789012345678901234567890123456789012345678901237'), - finalValue: BigNumber.from('0x0239329298382323782378478237842378478237847237237872373272373272') - }, - { - key: '0x1234567890123456789012345678901234567890123456789012345678901238', - index: 2, - initValue: BigNumber.from(0), - finalValue: BigNumber.from(1) - } - ]; - const encodedStateDiffs = encodeStateDiffs(stateDiffs); - const compressedStateDiffs = compressStateDiffs(4, stateDiffs); - const tx = { - from: L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, - to: compressor.address, - data: compressor.interface.encodeFunctionData('verifyCompressedStateDiffs', [ - 5, - 4, - encodedStateDiffs, - compressedStateDiffs - ]) - }; - // eth_call to get return data - expect(await ethers.provider.call(tx)).to.be.eq(ethers.utils.keccak256(encodedStateDiffs)); - }); + it("chunk does not match the original bytecode", async () => { + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], + }); + + const bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); + + const BYTECODE = "0xdeadbeefdeadbeef1111111111111111"; + const COMPRESSED_BYTECODE = "0x0002deadbeefdeadbeef111111111111111100000000"; + await expect( + compressor.connect(bootloader).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) + ).to.be.revertedWith("Encoded chunk does not match the original bytecode"); + + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], + }); }); + + it("invalid bytecode length in bytes", async () => { + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], + }); + + const bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); + + const BYTECODE = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; + const COMPRESSED_BYTECODE = "0x0001deadbeefdeadbeef000000000000"; + await expect( + compressor.connect(bootloader).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) + ).to.be.revertedWith("po"); + + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], + }); + }); + + // Test case with too big bytecode is unrealistic because API cannot accept so much data. + it("invalid bytecode length in words", async () => { + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], + }); + + const bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); + + const BYTECODE = "0x" + "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef".repeat(2); + const COMPRESSED_BYTECODE = "0x0001deadbeefdeadbeef" + "0000".repeat(4 * 2); + await expect( + compressor.connect(bootloader).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE) + ).to.be.revertedWith("pr"); + + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], + }); + }); + + it("successfully published", async () => { + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], + }); + + const bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); + + const BYTECODE = + "0x000200000000000200010000000103550000006001100270000000150010019d0000000101200190000000080000c13d0000000001000019004e00160000040f0000000101000039004e00160000040f0000001504000041000000150510009c000000000104801900000040011002100000000001310019000000150320009c0000000002048019000000600220021000000000012100190000004f0001042e000000000100001900000050000104300000008002000039000000400020043f0000000002000416000000000110004c000000240000613d000000000120004c0000004d0000c13d000000200100003900000100001004430000012000000443000001000100003900000040020000390000001d03000041004e000a0000040f000000000120004c0000004d0000c13d0000000001000031000000030110008c0000004d0000a13d0000000101000367000000000101043b0000001601100197000000170110009c0000004d0000c13d0000000101000039000000000101041a0000000202000039000000000202041a000000400300043d00000040043000390000001805200197000000000600041a0000000000540435000000180110019700000020043000390000000000140435000000a0012002700000001901100197000000600430003900000000001404350000001a012001980000001b010000410000000001006019000000b8022002700000001c02200197000000000121019f0000008002300039000000000012043500000018016001970000000000130435000000400100043d0000000002130049000000a0022000390000000003000019004e000a0000040f004e00140000040f0000004e000004320000004f0001042e000000500001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff000000000000000000000000000000000000000000000000000000008903573000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000ffffff0000000000008000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000000000007fffff00000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + const COMPRESSED_BYTECODE = + "0x00510000000000000000ffffffffffffffff0000004d0000c13d00000000ffffffff0000000000140435004e000a0000040f000000000120004c00000050000104300000004f0001042e0000000101000039004e00160000040f0000000001000019000000020000000000000000007fffffffffffffff80000000000000000080000000000000ffffff8903573000000000ffffffff000000000000004e00000432004e00140000040f0000000003000019000000a0022000390000000002130049000000400100043d0000000000130435000000180160019700000000001204350000008002300039000000000121019f0000001c02200197000000b80220027000000000010060190000001b010000410000001a0120019800000060043000390000001901100197000000a001200270000000200430003900000018011001970000000000540435000000000600041a00000018052001970000004004300039000000400300043d000000000202041a0000000202000039000000000101041a000000170110009c0000001601100197000000000101043b00000001010003670000004d0000a13d000000030110008c00000000010000310000001d0300004100000040020000390000010001000039000001200000044300000100001004430000002001000039000000240000613d000000000110004c0000000002000416000000400020043f0000008002000039000000000121001900000060022002100000000002048019000000150320009c000000000131001900000040011002100000000001048019000000150510009c0000001504000041000000080000c13d0000000101200190000000150010019d0000006001100270000100000001035500020000000000020050004f004e004d004c004b000b000a0009000a004a004900480047004600450044004300420008000b000700410040003f003e003d00060002003c003b003a003900380037000500060002003600350034003300320031003000020009002f002e002d002c002b002a002900280027002600040025002400230004002200210020001f001e001d001c001b001a001900180017001600150005001400130008000700000000000000000000000000030012000000000000001100000000000000000003000100010000000000000010000f000000000000000100010001000e000000000000000d000c0000000000000000000000000000"; + await expect(compressor.connect(bootloader).publishCompressedBytecode(BYTECODE, COMPRESSED_BYTECODE)) + .to.emit( + MockKnownCodesStorage__factory.connect(KNOWN_CODE_STORAGE_CONTRACT_ADDRESS, wallet), + "MockBytecodePublished" + ) + .withArgs(zksync.utils.hashBytecode(BYTECODE)); + + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], + }); + }); + }); + + describe("verifyCompressedStateDiffs", function () { + it("non l1 messenger failed to call", async () => { + await expect(compressor.verifyCompressedStateDiffs(0, 8, "0x", "0x0000")).to.be.revertedWith( + "Inappropriate caller" + ); + }); + + it("enumeration index size is too large", async () => { + const stateDiffs = [ + { + key: "0x1234567890123456789012345678901234567890123456789012345678901234", + index: 0, + initValue: BigNumber.from(0), + finalValue: BigNumber.from("0x1234567890123456789012345678901234567890123456789012345678901234"), + }, + ]; + const encodedStateDiffs = encodeStateDiffs(stateDiffs); + stateDiffs[0].key = "0x1234567890123456789012345678901234567890123456789012345678901233"; + const compressedStateDiffs = compressStateDiffs(9, stateDiffs); + await expect( + compressor.connect(l1Messenger).verifyCompressedStateDiffs(1, 9, encodedStateDiffs, compressedStateDiffs) + ).to.be.revertedWith("enumeration index size is too large"); + }); + + it("initial write key mismatch", async () => { + const stateDiffs = [ + { + key: "0x1234567890123456789012345678901234567890123456789012345678901234", + index: 0, + initValue: BigNumber.from(1), + finalValue: BigNumber.from(0), + }, + ]; + const encodedStateDiffs = encodeStateDiffs(stateDiffs); + stateDiffs[0].key = "0x1234567890123456789012345678901234567890123456789012345678901233"; + const compressedStateDiffs = compressStateDiffs(4, stateDiffs); + await expect( + compressor.connect(l1Messenger).verifyCompressedStateDiffs(1, 4, encodedStateDiffs, compressedStateDiffs) + ).to.be.revertedWith("iw: initial key mismatch"); + }); + + it("repeated write key mismatch", async () => { + const stateDiffs = [ + { + key: "0x1234567890123456789012345678901234567890123456789012345678901234", + index: 1, + initValue: BigNumber.from(1), + finalValue: BigNumber.from(0), + }, + ]; + const encodedStateDiffs = encodeStateDiffs(stateDiffs); + stateDiffs[0].index = 2; + const compressedStateDiffs = compressStateDiffs(8, stateDiffs); + await expect( + compressor.connect(l1Messenger).verifyCompressedStateDiffs(1, 8, encodedStateDiffs, compressedStateDiffs) + ).to.be.revertedWith("rw: enum key mismatch"); + }); + + it("no compression value mismatch", async () => { + const stateDiffs = [ + { + key: "0x1234567890123456789012345678901234567890123456789012345678901234", + index: 1, + initValue: BigNumber.from(1), + finalValue: BigNumber.from(0), + }, + { + key: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", + index: 0, + initValue: TWO_IN_256.div(2), + finalValue: TWO_IN_256.sub(2), + }, + ]; + const encodedStateDiffs = encodeStateDiffs(stateDiffs); + stateDiffs[1].finalValue = TWO_IN_256.sub(1); + const compressedStateDiffs = compressStateDiffs(3, stateDiffs); + await expect( + compressor.connect(l1Messenger).verifyCompressedStateDiffs(2, 3, encodedStateDiffs, compressedStateDiffs) + ).to.be.revertedWith("transform or no compression: compressed and final mismatch"); + }); + + it("transform value mismatch", async () => { + const stateDiffs = [ + { + key: "0x1234567890123456789012345678901234567890123456789012345678901234", + index: 255, + initValue: BigNumber.from(1), + finalValue: BigNumber.from(0), + }, + { + key: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", + index: 0, + initValue: TWO_IN_256.div(2), + finalValue: BigNumber.from(1), + }, + ]; + const encodedStateDiffs = encodeStateDiffs(stateDiffs); + stateDiffs[1].finalValue = BigNumber.from(0); + const compressedStateDiffs = compressStateDiffs(1, stateDiffs); + await expect( + compressor.connect(l1Messenger).verifyCompressedStateDiffs(2, 1, encodedStateDiffs, compressedStateDiffs) + ).to.be.revertedWith("transform or no compression: compressed and final mismatch"); + }); + + it("add value mismatch", async () => { + const stateDiffs = [ + { + key: "0x1234567890123456789012345678901234567890123456789012345678901235", + index: 255, + initValue: TWO_IN_256.div(2).sub(2), + finalValue: TWO_IN_256.div(2).sub(1), + }, + ]; + const encodedStateDiffs = encodeStateDiffs(stateDiffs); + stateDiffs[0].finalValue = TWO_IN_256.div(2); + const compressedStateDiffs = compressStateDiffs(1, stateDiffs); + await expect( + compressor.connect(l1Messenger).verifyCompressedStateDiffs(1, 1, encodedStateDiffs, compressedStateDiffs) + ).to.be.revertedWith("add: initial plus converted not equal to final"); + }); + + it("sub value mismatch", async () => { + const stateDiffs = [ + { + key: "0x1234567890123456789012345678901234567890123456789012345678901236", + index: 0, + initValue: TWO_IN_256.div(4), + finalValue: TWO_IN_256.div(4).sub(5), + }, + ]; + const encodedStateDiffs = encodeStateDiffs(stateDiffs); + stateDiffs[0].finalValue = TWO_IN_256.div(4).sub(1); + const compressedStateDiffs = compressStateDiffs(1, stateDiffs); + await expect( + compressor.connect(l1Messenger).verifyCompressedStateDiffs(1, 1, encodedStateDiffs, compressedStateDiffs) + ).to.be.revertedWith("sub: initial minus converted not equal to final"); + }); + + it("invalid operation", async () => { + const stateDiffs = [ + { + key: "0x1234567890123456789012345678901234567890123456789012345678901236", + index: 0, + initValue: TWO_IN_256.div(4), + finalValue: TWO_IN_256.div(4).sub(5), + }, + ]; + const encodedStateDiffs = encodeStateDiffs(stateDiffs); + let compressedStateDiffs = compressStateDiffs(1, stateDiffs); + const compressedStateDiffsCharArray = compressedStateDiffs.split(""); + compressedStateDiffsCharArray[2 + 4 + 64 + 1] = "f"; + compressedStateDiffs = compressedStateDiffsCharArray.join(""); + await expect( + compressor.connect(l1Messenger).verifyCompressedStateDiffs(1, 1, encodedStateDiffs, compressedStateDiffs) + ).to.be.revertedWith("unsupported operation"); + }); + + it("Incorrect number of initial storage diffs", async () => { + const stateDiffs = [ + { + key: "0x1234567890123456789012345678901234567890123456789012345678901236", + index: 0, + initValue: TWO_IN_256.div(4), + finalValue: TWO_IN_256.div(4).sub(5), + }, + { + key: "0x1234567890123456789012345678901234567890123456789012345678901239", + index: 121, + initValue: TWO_IN_256.sub(1), + finalValue: BigNumber.from(0), + }, + ]; + const encodedStateDiffs = encodeStateDiffs(stateDiffs); + stateDiffs.push({ + key: "0x0234567890123456789012345678901234567890123456789012345678901231", + index: 0, + initValue: BigNumber.from(0), + finalValue: BigNumber.from(1), + }); + const compressedStateDiffs = compressStateDiffs(1, stateDiffs); + await expect( + compressor.connect(l1Messenger).verifyCompressedStateDiffs(2, 1, encodedStateDiffs, compressedStateDiffs) + ).to.be.revertedWith("Incorrect number of initial storage diffs"); + }); + + it("Extra data in compressed state diffs", async () => { + const stateDiffs = [ + { + key: "0x1234567890123456789012345678901234567890123456789012345678901236", + index: 0, + initValue: TWO_IN_256.div(4), + finalValue: TWO_IN_256.div(4).sub(5), + }, + { + key: "0x1234567890123456789012345678901234567890123456789012345678901239", + index: 121, + initValue: TWO_IN_256.sub(1), + finalValue: BigNumber.from(0), + }, + ]; + const encodedStateDiffs = encodeStateDiffs(stateDiffs); + stateDiffs.push({ + key: "0x0234567890123456789012345678901234567890123456789012345678901231", + index: 1, + initValue: BigNumber.from(0), + finalValue: BigNumber.from(1), + }); + const compressedStateDiffs = compressStateDiffs(1, stateDiffs); + await expect( + compressor.connect(l1Messenger).verifyCompressedStateDiffs(2, 1, encodedStateDiffs, compressedStateDiffs) + ).to.be.revertedWith("Extra data in _compressedStateDiffs"); + }); + + it("successfully verified", async () => { + const stateDiffs = [ + { + key: "0x1234567890123456789012345678901234567890123456789012345678901230", + index: 0, + initValue: BigNumber.from("0x1234567890123456789012345678901234567890123456789012345678901231"), + finalValue: BigNumber.from("0x1234567890123456789012345678901234567890123456789012345678901230"), + }, + { + key: "0x1234567890123456789012345678901234567890123456789012345678901232", + index: 1, + initValue: TWO_IN_256.sub(1), + finalValue: BigNumber.from(1), + }, + { + key: "0x1234567890123456789012345678901234567890123456789012345678901234", + index: 0, + initValue: TWO_IN_256.div(2), + finalValue: BigNumber.from(1), + }, + { + key: "0x1234567890123456789012345678901234567890123456789012345678901236", + index: 2323, + initValue: BigNumber.from("0x1234567890123456789012345678901234567890123456789012345678901237"), + finalValue: BigNumber.from("0x0239329298382323782378478237842378478237847237237872373272373272"), + }, + { + key: "0x1234567890123456789012345678901234567890123456789012345678901238", + index: 2, + initValue: BigNumber.from(0), + finalValue: BigNumber.from(1), + }, + ]; + const encodedStateDiffs = encodeStateDiffs(stateDiffs); + const compressedStateDiffs = compressStateDiffs(4, stateDiffs); + const tx = { + from: L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, + to: compressor.address, + data: compressor.interface.encodeFunctionData("verifyCompressedStateDiffs", [ + 5, + 4, + encodedStateDiffs, + compressedStateDiffs, + ]), + }; + // eth_call to get return data + expect(await ethers.provider.call(tx)).to.be.eq(ethers.utils.keccak256(encodedStateDiffs)); + }); + }); }); interface StateDiff { - key: BytesLike; - index: number; - initValue: BigNumber; - finalValue: BigNumber; + key: BytesLike; + index: number; + initValue: BigNumber; + finalValue: BigNumber; } function encodeStateDiffs(stateDiffs: StateDiff[]): string { - const rawStateDiffs = []; - for (const stateDiff of stateDiffs) { - rawStateDiffs.push( - ethers.utils.solidityPack( - ['address', 'bytes32', 'bytes32', 'uint64', 'uint256', 'uint256', 'bytes'], - [ - ethers.constants.AddressZero, - ethers.constants.HashZero, - stateDiff.key, - stateDiff.index, - stateDiff.initValue, - stateDiff.finalValue, - '0x' + '00'.repeat(116) - ] - ) - ); - } - return ethers.utils.hexlify(ethers.utils.concat(rawStateDiffs)); + const rawStateDiffs = []; + for (const stateDiff of stateDiffs) { + rawStateDiffs.push( + ethers.utils.solidityPack( + ["address", "bytes32", "bytes32", "uint64", "uint256", "uint256", "bytes"], + [ + ethers.constants.AddressZero, + ethers.constants.HashZero, + stateDiff.key, + stateDiff.index, + stateDiff.initValue, + stateDiff.finalValue, + "0x" + "00".repeat(116), + ] + ) + ); + } + return ethers.utils.hexlify(ethers.utils.concat(rawStateDiffs)); } function compressStateDiffs(enumerationIndexSize: number, stateDiffs: StateDiff[]): string { - let num_initial = 0; - const initial = []; - const repeated = []; - for (const stateDiff of stateDiffs) { - const addition = stateDiff.finalValue.sub(stateDiff.initValue).add(TWO_IN_256).mod(TWO_IN_256); - const subtraction = stateDiff.initValue.sub(stateDiff.finalValue).add(TWO_IN_256).mod(TWO_IN_256); - let op = 3; - let min = stateDiff.finalValue; - if (addition.lt(min)) { - min = addition; - op = 1; - } - if (subtraction.lt(min)) { - min = subtraction; - op = 2; - } - if (min.gte(BigNumber.from(2).pow(248))) { - min = stateDiff.finalValue; - op = 0; - } - let len = 0; - const minHex = min.eq(0) ? '0x' : min.toHexString(); - if (op > 0) { - len = (minHex.length - 2) / 2; - } - const metadata = (len << 3) + op; - const enumerationIndexType = 'uint' + (enumerationIndexSize * 8).toString(); - if (stateDiff.index === 0) { - num_initial += 1; - initial.push(ethers.utils.solidityPack(['bytes32', 'uint8', 'bytes'], [stateDiff.key, metadata, minHex])); - } else { - repeated.push( - ethers.utils.solidityPack([enumerationIndexType, 'uint8', 'bytes'], [stateDiff.index, metadata, minHex]) - ); - } + let num_initial = 0; + const initial = []; + const repeated = []; + for (const stateDiff of stateDiffs) { + const addition = stateDiff.finalValue.sub(stateDiff.initValue).add(TWO_IN_256).mod(TWO_IN_256); + const subtraction = stateDiff.initValue.sub(stateDiff.finalValue).add(TWO_IN_256).mod(TWO_IN_256); + let op = 3; + let min = stateDiff.finalValue; + if (addition.lt(min)) { + min = addition; + op = 1; } - return ethers.utils.hexlify( - ethers.utils.concat([ethers.utils.solidityPack(['uint16'], [num_initial]), ...initial, ...repeated]) - ); + if (subtraction.lt(min)) { + min = subtraction; + op = 2; + } + if (min.gte(BigNumber.from(2).pow(248))) { + min = stateDiff.finalValue; + op = 0; + } + let len = 0; + const minHex = min.eq(0) ? "0x" : min.toHexString(); + if (op > 0) { + len = (minHex.length - 2) / 2; + } + const metadata = (len << 3) + op; + const enumerationIndexType = "uint" + (enumerationIndexSize * 8).toString(); + if (stateDiff.index === 0) { + num_initial += 1; + initial.push(ethers.utils.solidityPack(["bytes32", "uint8", "bytes"], [stateDiff.key, metadata, minHex])); + } else { + repeated.push( + ethers.utils.solidityPack([enumerationIndexType, "uint8", "bytes"], [stateDiff.index, metadata, minHex]) + ); + } + } + return ethers.utils.hexlify( + ethers.utils.concat([ethers.utils.solidityPack(["uint16"], [num_initial]), ...initial, ...repeated]) + ); } diff --git a/test/ContractDeployer.spec.ts b/test/ContractDeployer.spec.ts index d7ec83b5bd2..f87d2ab3a38 100644 --- a/test/ContractDeployer.spec.ts +++ b/test/ContractDeployer.spec.ts @@ -1,550 +1,538 @@ -import { ZkSyncArtifact } from '@matterlabs/hardhat-zksync-deploy/dist/types'; -import { expect } from 'chai'; -import { ethers, network } from 'hardhat'; -import { Contract, Wallet, utils } from 'zksync-web3'; +import type { ZkSyncArtifact } from "@matterlabs/hardhat-zksync-deploy/dist/types"; +import { expect } from "chai"; +import { ethers, network } from "hardhat"; +import type { Wallet } from "zksync-web3"; +import { Contract, utils } from "zksync-web3"; +import type { ContractDeployer, NonceHolder } from "../typechain-types"; +import { ContractDeployer__factory, Deployable__factory, NonceHolder__factory } from "../typechain-types"; import { - ContractDeployer, - ContractDeployer__factory, - Deployable__factory, - NonceHolder, - NonceHolder__factory -} from '../typechain-types'; -import { - DEPLOYER_SYSTEM_CONTRACT_ADDRESS, - FORCE_DEPLOYER_ADDRESS, - NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS -} from './shared/constants'; -import { deployContract, getCode, getWallets, loadArtifact, publishBytecode, setCode } from './shared/utils'; - -describe('ContractDeployer tests', function () { - let wallet: Wallet; - let contractDeployer: ContractDeployer; - let contractDeployerSystemCall: ContractDeployer; - let contractDeployerNotSystemCall: ContractDeployer; - let nonceHolder: NonceHolder; - let deployableArtifact: ZkSyncArtifact; - let deployerAccount: ethers.Signer; - let forceDeployer: ethers.Signer; - - const EOA = ethers.utils.getAddress('0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'); - const RANDOM_ADDRESS = ethers.utils.getAddress('0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbee1'); - const RANDOM_ADDRESS_2 = ethers.utils.getAddress('0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbee2'); - const RANDOM_ADDRESS_3 = ethers.utils.getAddress('0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbee3'); - const AA_VERSION_NONE = 0; - const AA_VERSION_1 = 1; - const NONCE_ORDERING_SEQUENTIAL = 0; - const NONCE_ORDERING_ARBITRARY = 1; - - let _contractDeployerCode: string; - - before(async () => { - wallet = getWallets()[0]; - - _contractDeployerCode = await getCode(DEPLOYER_SYSTEM_CONTRACT_ADDRESS); - const contractDeployerArtifact = await loadArtifact('ContractDeployer'); - await setCode(DEPLOYER_SYSTEM_CONTRACT_ADDRESS, contractDeployerArtifact.bytecode); - contractDeployer = ContractDeployer__factory.connect(DEPLOYER_SYSTEM_CONTRACT_ADDRESS, wallet); - - nonceHolder = NonceHolder__factory.connect(NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS, wallet); - - const contractDeployerSystemCallContract = await deployContract('SystemCaller', [contractDeployer.address]); - contractDeployerSystemCall = new Contract( - contractDeployerSystemCallContract.address, - contractDeployerArtifact.abi, - wallet - ) as ContractDeployer; - - const contractDeployerNotSystemCallContract = await deployContract('NotSystemCaller', [ - contractDeployer.address - ]); - contractDeployerNotSystemCall = new Contract( - contractDeployerNotSystemCallContract.address, - contractDeployerArtifact.abi, - wallet - ) as ContractDeployer; - - deployableArtifact = await loadArtifact('Deployable'); - await publishBytecode(deployableArtifact.bytecode); - - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS] - }); - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [FORCE_DEPLOYER_ADDRESS] - }); - deployerAccount = await ethers.getSigner(DEPLOYER_SYSTEM_CONTRACT_ADDRESS); - forceDeployer = await ethers.getSigner(FORCE_DEPLOYER_ADDRESS); - }); - - after(async () => { - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS] - }); - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [FORCE_DEPLOYER_ADDRESS] - }); - await setCode(DEPLOYER_SYSTEM_CONTRACT_ADDRESS, _contractDeployerCode); - }); - - 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' - ); - }); - - it('from none to version1', async () => { - expect( - (await contractDeployer.getAccountInfo(contractDeployerSystemCall.address)).supportedAAVersion - ).to.be.eq(AA_VERSION_NONE); - await contractDeployerSystemCall.updateAccountVersion(AA_VERSION_1); - expect( - (await contractDeployer.getAccountInfo(contractDeployerSystemCall.address)).supportedAAVersion - ).to.be.eq(AA_VERSION_1); - }); - - it('from version1 to none', async () => { - expect( - (await contractDeployer.getAccountInfo(contractDeployerSystemCall.address)).supportedAAVersion - ).to.be.eq(AA_VERSION_1); - await contractDeployerSystemCall.updateAccountVersion(AA_VERSION_NONE); - expect( - (await contractDeployer.getAccountInfo(contractDeployerSystemCall.address)).supportedAAVersion - ).to.be.eq(AA_VERSION_NONE); - }); - }); - - 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' - ); - }); - - it('success from sequential to arbitrary', async () => { - expect((await contractDeployer.getAccountInfo(contractDeployerSystemCall.address)).nonceOrdering).to.be.eq( - NONCE_ORDERING_SEQUENTIAL - ); - await contractDeployerSystemCall.updateNonceOrdering(NONCE_ORDERING_ARBITRARY); - expect((await contractDeployer.getAccountInfo(contractDeployerSystemCall.address)).nonceOrdering).to.be.eq( - NONCE_ORDERING_ARBITRARY - ); - }); - - it('failed from arbitrary to sequential', async () => { - 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' - ); - }); - }); - - describe('getAccountInfo', function () { - it('success', async () => { - const accountInfo = await contractDeployer.getAccountInfo(RANDOM_ADDRESS); - expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); - expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); - }); - }); - - describe('extendedAccountVersion', function () { - it('account abstraction contract', async () => { - await contractDeployerSystemCall.updateAccountVersion(AA_VERSION_1); - expect(await contractDeployer.extendedAccountVersion(contractDeployerSystemCall.address)).to.be.eq( - AA_VERSION_1 - ); - await contractDeployerSystemCall.updateAccountVersion(AA_VERSION_NONE); - }); - - it('EOA', async () => { - expect(await contractDeployer.extendedAccountVersion(EOA)).to.be.eq(AA_VERSION_1); - }); - - it('not AA', async () => { - expect(await contractDeployer.extendedAccountVersion(contractDeployerSystemCall.address)).to.be.eq( - AA_VERSION_NONE - ); - }); - }); - - describe('getNewAddressCreate2', function () { - it('success', async () => { - expect( - await contractDeployer.getNewAddressCreate2( - RANDOM_ADDRESS, - '0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF', - '0x0000000022000000000123812381283812831823812838912389128938912893', - '0x' - ) - ).to.be.eq( - utils.create2Address( - RANDOM_ADDRESS, - '0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF', - '0x0000000022000000000123812381283812831823812838912389128938912893', - '0x' - ) - ); - }); - }); - - describe('getNewAddressCreate', function () { - it('success', async () => { - expect(await contractDeployer.getNewAddressCreate(RANDOM_ADDRESS, 3223233)).to.be.eq( - utils.createAddress(RANDOM_ADDRESS, 3223233) - ); - }); - }); - - // TODO: some other things can be tested: - // - check other contracts (like known codes storage) - // - cases with the kernel space address (not possible in production) - // - twice on the same address for create (not possible in production) - // - constructor behavior (failed, invalid immutables array) - // - more cases for force deployments - describe('createAccount', function () { - it('non system call failed', async () => { - await expect( - contractDeployerNotSystemCall.createAccount( - ethers.constants.HashZero, - utils.hashBytecode(deployableArtifact.bytecode), - '0x', - AA_VERSION_NONE - ) - ).to.be.revertedWith('This method require system call flag'); - }); - - it('zero bytecode hash failed', async () => { - await expect( - contractDeployerSystemCall.createAccount( - ethers.constants.HashZero, - ethers.constants.HashZero, - '0x', - AA_VERSION_NONE - ) - ).to.be.revertedWith('BytecodeHash cannot be zero'); - }); - - it('not known bytecode hash failed', async () => { - await expect( - contractDeployerSystemCall.createAccount( - ethers.constants.HashZero, - '0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF', - '0x', - AA_VERSION_NONE - ) - ).to.be.revertedWith('The code hash is not known'); - }); - - it('successfully deployed', async () => { - const nonce = await nonceHolder.getDeploymentNonce(wallet.address); - const expectedAddress = utils.createAddress(wallet.address, nonce); - await expect( - contractDeployer.createAccount( - ethers.constants.HashZero, - utils.hashBytecode(deployableArtifact.bytecode), - '0xdeadbeef', - AA_VERSION_NONE - ) - ) - .to.emit(contractDeployer, 'ContractDeployed') - .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), expectedAddress) - .to.emit(Deployable__factory.connect(expectedAddress, wallet), 'Deployed') - .withArgs(0, '0xdeadbeef'); - const accountInfo = await contractDeployer.getAccountInfo(expectedAddress); - expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); - expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); - }); - - it('non-zero value deployed', async () => { - const nonce = await nonceHolder.getDeploymentNonce(wallet.address); - const expectedAddress = utils.createAddress(wallet.address, nonce); - await expect( - contractDeployer.createAccount( - ethers.constants.HashZero, - utils.hashBytecode(deployableArtifact.bytecode), - '0x', - AA_VERSION_NONE, - { value: 11111111 } - ) - ) - .to.emit(contractDeployer, 'ContractDeployed') - .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), expectedAddress) - .to.emit(Deployable__factory.connect(expectedAddress, wallet), 'Deployed') - .withArgs(11111111, '0x'); - const accountInfo = await contractDeployer.getAccountInfo(expectedAddress); - expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); - expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); - }); - }); - - describe('create2Account', function () { - it('non system call failed', async () => { - await expect( - contractDeployerNotSystemCall.create2Account( - '0x1234567891234567891234512222122167891123456789123456787654323456', - utils.hashBytecode(deployableArtifact.bytecode), - '0x', - AA_VERSION_NONE - ) - ).to.be.revertedWith('This method require system call flag'); - }); - - it('zero bytecode hash failed', async () => { - await expect( - contractDeployerSystemCall.create2Account( - '0x1234567891234567891234512222122167891123456789123456787654323456', - ethers.constants.HashZero, - '0x', - AA_VERSION_NONE - ) - ).to.be.revertedWith('BytecodeHash cannot be zero'); - }); - - it('not known bytecode hash failed', async () => { - await expect( - contractDeployerSystemCall.create2Account( - '0x1234567891234567891234512222122167891123456789123456787654323456', - '0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF', - '0x', - AA_VERSION_NONE - ) - ).to.be.revertedWith('The code hash is not known'); - }); - - it('successfully deployed', async () => { - const expectedAddress = utils.create2Address( - wallet.address, - utils.hashBytecode(deployableArtifact.bytecode), - '0x1234567891234567891234512222122167891123456789123456787654323456', - '0xdeadbeef' - ); - await expect( - contractDeployer.create2Account( - '0x1234567891234567891234512222122167891123456789123456787654323456', - utils.hashBytecode(deployableArtifact.bytecode), - '0xdeadbeef', - AA_VERSION_NONE - ) - ) - .to.emit(contractDeployer, 'ContractDeployed') - .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), expectedAddress) - .to.emit(Deployable__factory.connect(expectedAddress, wallet), 'Deployed') - .withArgs(0, '0xdeadbeef'); - const accountInfo = await contractDeployer.getAccountInfo(expectedAddress); - expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); - expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); - }); - - it('already deployed failed', async () => { - await expect( - contractDeployer.create2Account( - '0x1234567891234567891234512222122167891123456789123456787654323456', - utils.hashBytecode(deployableArtifact.bytecode), - '0xdeadbeef', - AA_VERSION_NONE - ) - ).to.be.revertedWith('Code hash is non-zero'); - }); - - it('non-zero value deployed', async () => { - const expectedAddress = utils.create2Address( - wallet.address, - utils.hashBytecode(deployableArtifact.bytecode), - ethers.constants.HashZero, - '0x' - ); - await expect( - contractDeployer.create2Account( - ethers.constants.HashZero, - utils.hashBytecode(deployableArtifact.bytecode), - '0x', - AA_VERSION_NONE, - { value: 5555 } - ) - ) - .to.emit(contractDeployer, 'ContractDeployed') - .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), expectedAddress) - .to.emit(Deployable__factory.connect(expectedAddress, wallet), 'Deployed') - .withArgs(5555, '0x'); - const accountInfo = await contractDeployer.getAccountInfo(expectedAddress); - expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); - expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); - }); - }); - - describe('create', function () { - it('non system call failed', async () => { - await expect( - contractDeployerNotSystemCall.create( - ethers.constants.HashZero, - utils.hashBytecode(deployableArtifact.bytecode), - '0x' - ) - ).to.be.revertedWith('This method require system call flag'); - }); - - it('successfully deployed', async () => { - const nonce = await nonceHolder.getDeploymentNonce(wallet.address); - const expectedAddress = utils.createAddress(wallet.address, nonce); - await expect( - contractDeployer.create( - ethers.constants.HashZero, - utils.hashBytecode(deployableArtifact.bytecode), - '0x12' - ) - ) - .to.emit(contractDeployer, 'ContractDeployed') - .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), expectedAddress) - .to.emit(Deployable__factory.connect(expectedAddress, wallet), 'Deployed') - .withArgs(0, '0x12'); - const accountInfo = await contractDeployer.getAccountInfo(expectedAddress); - expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); - expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); - }); - }); - - describe('create2', function () { - it('non system call failed', async () => { - await expect( - contractDeployerNotSystemCall.create2( - ethers.constants.HashZero, - utils.hashBytecode(deployableArtifact.bytecode), - '0x' - ) - ).to.be.revertedWith('This method require system call flag'); - }); - - it('successfully deployed', async () => { - const expectedAddress = utils.create2Address( - wallet.address, - utils.hashBytecode(deployableArtifact.bytecode), - '0x1234567891234567891234512222122167891123456789123456787654323456', - '0xab' - ); - await expect( - contractDeployer.create2( - '0x1234567891234567891234512222122167891123456789123456787654323456', - utils.hashBytecode(deployableArtifact.bytecode), - '0xab' - ) - ) - .to.emit(contractDeployer, 'ContractDeployed') - .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), expectedAddress) - .to.emit(Deployable__factory.connect(expectedAddress, wallet), 'Deployed') - .withArgs(0, '0xab'); - const accountInfo = await contractDeployer.getAccountInfo(expectedAddress); - expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); - expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); - }); - }); - - describe('forceDeployOnAddress', function () { - it('not from self call failed', async () => { - const deploymentData = { - bytecodeHash: utils.hashBytecode(deployableArtifact.bytecode), - newAddress: RANDOM_ADDRESS, - callConstructor: false, - value: 0, - input: '0x' - }; - await expect(contractDeployer.forceDeployOnAddress(deploymentData, wallet.address)).to.be.revertedWith( - 'Callable only by self' - ); - }); - - it('not known bytecode hash failed', async () => { - const deploymentData = { - bytecodeHash: '0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF', - newAddress: RANDOM_ADDRESS, - callConstructor: false, - value: 0, - input: '0x' - }; - await expect( - contractDeployer.connect(deployerAccount).forceDeployOnAddress(deploymentData, wallet.address) - ).to.be.revertedWith('The code hash is not known'); - }); - - it('successfully deployed', async () => { - const deploymentData = { - bytecodeHash: utils.hashBytecode(deployableArtifact.bytecode), - newAddress: RANDOM_ADDRESS, - callConstructor: false, - value: 0, - input: '0x' - }; - await expect(contractDeployer.connect(deployerAccount).forceDeployOnAddress(deploymentData, wallet.address)) - .to.emit(contractDeployer, 'ContractDeployed') - .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), RANDOM_ADDRESS) - .to.not.emit(Deployable__factory.connect(RANDOM_ADDRESS, wallet), 'Deployed'); - const accountInfo = await contractDeployer.getAccountInfo(RANDOM_ADDRESS); - expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); - expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); - }); - }); - - describe('forceDeployOnAddresses', function () { - it('not allowed to call', async () => { - const deploymentData = [ - { - bytecodeHash: utils.hashBytecode(deployableArtifact.bytecode), - newAddress: RANDOM_ADDRESS_2, - callConstructor: true, - value: 0, - input: '0x' - }, - { - bytecodeHash: utils.hashBytecode(deployableArtifact.bytecode), - newAddress: RANDOM_ADDRESS_3, - callConstructor: false, - value: 0, - input: '0xab' - } - ]; - await expect(contractDeployer.forceDeployOnAddresses(deploymentData)).to.be.revertedWith( - 'Can only be called by FORCE_DEPLOYER or COMPLEX_UPGRADER_CONTRACT' - ); - }); - - it('successfully deployed', async () => { - const deploymentData = [ - { - bytecodeHash: utils.hashBytecode(deployableArtifact.bytecode), - newAddress: RANDOM_ADDRESS_2, - callConstructor: true, - value: 0, - input: '0x' - }, - { - bytecodeHash: utils.hashBytecode(deployableArtifact.bytecode), - newAddress: RANDOM_ADDRESS_3, - callConstructor: false, - value: 0, - input: '0xab' - } - ]; - await expect(contractDeployer.connect(forceDeployer).forceDeployOnAddresses(deploymentData)) - .to.emit(contractDeployer, 'ContractDeployed') - .withArgs(forceDeployer.address, utils.hashBytecode(deployableArtifact.bytecode), RANDOM_ADDRESS_2) - .to.emit(contractDeployer, 'ContractDeployed') - .withArgs(forceDeployer.address, utils.hashBytecode(deployableArtifact.bytecode), RANDOM_ADDRESS_3) - .to.emit(Deployable__factory.connect(RANDOM_ADDRESS_2, wallet), 'Deployed') - .withArgs(0, '0x') - .to.not.emit(Deployable__factory.connect(RANDOM_ADDRESS_3, wallet), 'Deployed'); - - const accountInfo1 = await contractDeployer.getAccountInfo(RANDOM_ADDRESS_2); - expect(accountInfo1.supportedAAVersion).to.be.eq(AA_VERSION_NONE); - expect(accountInfo1.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); - - const accountInfo2 = await contractDeployer.getAccountInfo(RANDOM_ADDRESS_3); - expect(accountInfo2.supportedAAVersion).to.be.eq(AA_VERSION_NONE); - expect(accountInfo2.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); - }); + DEPLOYER_SYSTEM_CONTRACT_ADDRESS, + FORCE_DEPLOYER_ADDRESS, + NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS, +} from "./shared/constants"; +import { deployContract, getCode, getWallets, loadArtifact, publishBytecode, setCode } from "./shared/utils"; + +describe("ContractDeployer tests", function () { + let wallet: Wallet; + let contractDeployer: ContractDeployer; + let contractDeployerSystemCall: ContractDeployer; + let contractDeployerNotSystemCall: ContractDeployer; + let nonceHolder: NonceHolder; + let deployableArtifact: ZkSyncArtifact; + let deployerAccount: ethers.Signer; + let forceDeployer: ethers.Signer; + + const EOA = ethers.utils.getAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); + const RANDOM_ADDRESS = ethers.utils.getAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbee1"); + const RANDOM_ADDRESS_2 = ethers.utils.getAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbee2"); + const RANDOM_ADDRESS_3 = ethers.utils.getAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbee3"); + const AA_VERSION_NONE = 0; + const AA_VERSION_1 = 1; + const NONCE_ORDERING_SEQUENTIAL = 0; + const NONCE_ORDERING_ARBITRARY = 1; + + let _contractDeployerCode: string; + + before(async () => { + wallet = getWallets()[0]; + + _contractDeployerCode = await getCode(DEPLOYER_SYSTEM_CONTRACT_ADDRESS); + const contractDeployerArtifact = await loadArtifact("ContractDeployer"); + await setCode(DEPLOYER_SYSTEM_CONTRACT_ADDRESS, contractDeployerArtifact.bytecode); + contractDeployer = ContractDeployer__factory.connect(DEPLOYER_SYSTEM_CONTRACT_ADDRESS, wallet); + + nonceHolder = NonceHolder__factory.connect(NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS, wallet); + + const contractDeployerSystemCallContract = await deployContract("SystemCaller", [contractDeployer.address]); + contractDeployerSystemCall = new Contract( + contractDeployerSystemCallContract.address, + contractDeployerArtifact.abi, + wallet + ) as ContractDeployer; + + const contractDeployerNotSystemCallContract = await deployContract("NotSystemCaller", [contractDeployer.address]); + contractDeployerNotSystemCall = new Contract( + contractDeployerNotSystemCallContract.address, + contractDeployerArtifact.abi, + wallet + ) as ContractDeployer; + + deployableArtifact = await loadArtifact("Deployable"); + await publishBytecode(deployableArtifact.bytecode); + + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS], + }); + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [FORCE_DEPLOYER_ADDRESS], + }); + deployerAccount = await ethers.getSigner(DEPLOYER_SYSTEM_CONTRACT_ADDRESS); + forceDeployer = await ethers.getSigner(FORCE_DEPLOYER_ADDRESS); + }); + + after(async () => { + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS], + }); + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [FORCE_DEPLOYER_ADDRESS], + }); + await setCode(DEPLOYER_SYSTEM_CONTRACT_ADDRESS, _contractDeployerCode); + }); + + 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" + ); + }); + + it("from none to version1", async () => { + expect((await contractDeployer.getAccountInfo(contractDeployerSystemCall.address)).supportedAAVersion).to.be.eq( + AA_VERSION_NONE + ); + await contractDeployerSystemCall.updateAccountVersion(AA_VERSION_1); + expect((await contractDeployer.getAccountInfo(contractDeployerSystemCall.address)).supportedAAVersion).to.be.eq( + AA_VERSION_1 + ); + }); + + it("from version1 to none", async () => { + expect((await contractDeployer.getAccountInfo(contractDeployerSystemCall.address)).supportedAAVersion).to.be.eq( + AA_VERSION_1 + ); + await contractDeployerSystemCall.updateAccountVersion(AA_VERSION_NONE); + expect((await contractDeployer.getAccountInfo(contractDeployerSystemCall.address)).supportedAAVersion).to.be.eq( + AA_VERSION_NONE + ); + }); + }); + + 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" + ); + }); + + it("success from sequential to arbitrary", async () => { + expect((await contractDeployer.getAccountInfo(contractDeployerSystemCall.address)).nonceOrdering).to.be.eq( + NONCE_ORDERING_SEQUENTIAL + ); + await contractDeployerSystemCall.updateNonceOrdering(NONCE_ORDERING_ARBITRARY); + expect((await contractDeployer.getAccountInfo(contractDeployerSystemCall.address)).nonceOrdering).to.be.eq( + NONCE_ORDERING_ARBITRARY + ); + }); + + it("failed from arbitrary to sequential", async () => { + 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" + ); + }); + }); + + describe("getAccountInfo", function () { + it("success", async () => { + const accountInfo = await contractDeployer.getAccountInfo(RANDOM_ADDRESS); + expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); + expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); + }); + }); + + describe("extendedAccountVersion", function () { + it("account abstraction contract", async () => { + await contractDeployerSystemCall.updateAccountVersion(AA_VERSION_1); + expect(await contractDeployer.extendedAccountVersion(contractDeployerSystemCall.address)).to.be.eq(AA_VERSION_1); + await contractDeployerSystemCall.updateAccountVersion(AA_VERSION_NONE); + }); + + it("EOA", async () => { + expect(await contractDeployer.extendedAccountVersion(EOA)).to.be.eq(AA_VERSION_1); + }); + + it("not AA", async () => { + expect(await contractDeployer.extendedAccountVersion(contractDeployerSystemCall.address)).to.be.eq( + AA_VERSION_NONE + ); + }); + }); + + describe("getNewAddressCreate2", function () { + it("success", async () => { + expect( + await contractDeployer.getNewAddressCreate2( + RANDOM_ADDRESS, + "0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", + "0x0000000022000000000123812381283812831823812838912389128938912893", + "0x" + ) + ).to.be.eq( + utils.create2Address( + RANDOM_ADDRESS, + "0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", + "0x0000000022000000000123812381283812831823812838912389128938912893", + "0x" + ) + ); + }); + }); + + describe("getNewAddressCreate", function () { + it("success", async () => { + expect(await contractDeployer.getNewAddressCreate(RANDOM_ADDRESS, 3223233)).to.be.eq( + utils.createAddress(RANDOM_ADDRESS, 3223233) + ); + }); + }); + + // TODO: some other things can be tested: + // - check other contracts (like known codes storage) + // - cases with the kernel space address (not possible in production) + // - twice on the same address for create (not possible in production) + // - constructor behavior (failed, invalid immutables array) + // - more cases for force deployments + describe("createAccount", function () { + it("non system call failed", async () => { + await expect( + contractDeployerNotSystemCall.createAccount( + ethers.constants.HashZero, + utils.hashBytecode(deployableArtifact.bytecode), + "0x", + AA_VERSION_NONE + ) + ).to.be.revertedWith("This method require system call flag"); + }); + + it("zero bytecode hash failed", async () => { + await expect( + contractDeployerSystemCall.createAccount( + ethers.constants.HashZero, + ethers.constants.HashZero, + "0x", + AA_VERSION_NONE + ) + ).to.be.revertedWith("BytecodeHash cannot be zero"); + }); + + it("not known bytecode hash failed", async () => { + await expect( + contractDeployerSystemCall.createAccount( + ethers.constants.HashZero, + "0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", + "0x", + AA_VERSION_NONE + ) + ).to.be.revertedWith("The code hash is not known"); + }); + + it("successfully deployed", async () => { + const nonce = await nonceHolder.getDeploymentNonce(wallet.address); + const expectedAddress = utils.createAddress(wallet.address, nonce); + await expect( + contractDeployer.createAccount( + ethers.constants.HashZero, + utils.hashBytecode(deployableArtifact.bytecode), + "0xdeadbeef", + AA_VERSION_NONE + ) + ) + .to.emit(contractDeployer, "ContractDeployed") + .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), expectedAddress) + .to.emit(Deployable__factory.connect(expectedAddress, wallet), "Deployed") + .withArgs(0, "0xdeadbeef"); + const accountInfo = await contractDeployer.getAccountInfo(expectedAddress); + expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); + expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); + }); + + it("non-zero value deployed", async () => { + const nonce = await nonceHolder.getDeploymentNonce(wallet.address); + const expectedAddress = utils.createAddress(wallet.address, nonce); + await expect( + contractDeployer.createAccount( + ethers.constants.HashZero, + utils.hashBytecode(deployableArtifact.bytecode), + "0x", + AA_VERSION_NONE, + { value: 11111111 } + ) + ) + .to.emit(contractDeployer, "ContractDeployed") + .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), expectedAddress) + .to.emit(Deployable__factory.connect(expectedAddress, wallet), "Deployed") + .withArgs(11111111, "0x"); + const accountInfo = await contractDeployer.getAccountInfo(expectedAddress); + expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); + expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); + }); + }); + + describe("create2Account", function () { + it("non system call failed", async () => { + await expect( + contractDeployerNotSystemCall.create2Account( + "0x1234567891234567891234512222122167891123456789123456787654323456", + utils.hashBytecode(deployableArtifact.bytecode), + "0x", + AA_VERSION_NONE + ) + ).to.be.revertedWith("This method require system call flag"); + }); + + it("zero bytecode hash failed", async () => { + await expect( + contractDeployerSystemCall.create2Account( + "0x1234567891234567891234512222122167891123456789123456787654323456", + ethers.constants.HashZero, + "0x", + AA_VERSION_NONE + ) + ).to.be.revertedWith("BytecodeHash cannot be zero"); + }); + + it("not known bytecode hash failed", async () => { + await expect( + contractDeployerSystemCall.create2Account( + "0x1234567891234567891234512222122167891123456789123456787654323456", + "0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", + "0x", + AA_VERSION_NONE + ) + ).to.be.revertedWith("The code hash is not known"); + }); + + it("successfully deployed", async () => { + const expectedAddress = utils.create2Address( + wallet.address, + utils.hashBytecode(deployableArtifact.bytecode), + "0x1234567891234567891234512222122167891123456789123456787654323456", + "0xdeadbeef" + ); + await expect( + contractDeployer.create2Account( + "0x1234567891234567891234512222122167891123456789123456787654323456", + utils.hashBytecode(deployableArtifact.bytecode), + "0xdeadbeef", + AA_VERSION_NONE + ) + ) + .to.emit(contractDeployer, "ContractDeployed") + .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), expectedAddress) + .to.emit(Deployable__factory.connect(expectedAddress, wallet), "Deployed") + .withArgs(0, "0xdeadbeef"); + const accountInfo = await contractDeployer.getAccountInfo(expectedAddress); + expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); + expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); + }); + + it("already deployed failed", async () => { + await expect( + contractDeployer.create2Account( + "0x1234567891234567891234512222122167891123456789123456787654323456", + utils.hashBytecode(deployableArtifact.bytecode), + "0xdeadbeef", + AA_VERSION_NONE + ) + ).to.be.revertedWith("Code hash is non-zero"); + }); + + it("non-zero value deployed", async () => { + const expectedAddress = utils.create2Address( + wallet.address, + utils.hashBytecode(deployableArtifact.bytecode), + ethers.constants.HashZero, + "0x" + ); + await expect( + contractDeployer.create2Account( + ethers.constants.HashZero, + utils.hashBytecode(deployableArtifact.bytecode), + "0x", + AA_VERSION_NONE, + { value: 5555 } + ) + ) + .to.emit(contractDeployer, "ContractDeployed") + .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), expectedAddress) + .to.emit(Deployable__factory.connect(expectedAddress, wallet), "Deployed") + .withArgs(5555, "0x"); + const accountInfo = await contractDeployer.getAccountInfo(expectedAddress); + expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); + expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); + }); + }); + + describe("create", function () { + it("non system call failed", async () => { + await expect( + contractDeployerNotSystemCall.create( + ethers.constants.HashZero, + utils.hashBytecode(deployableArtifact.bytecode), + "0x" + ) + ).to.be.revertedWith("This method require system call flag"); + }); + + it("successfully deployed", async () => { + const nonce = await nonceHolder.getDeploymentNonce(wallet.address); + const expectedAddress = utils.createAddress(wallet.address, nonce); + await expect( + contractDeployer.create(ethers.constants.HashZero, utils.hashBytecode(deployableArtifact.bytecode), "0x12") + ) + .to.emit(contractDeployer, "ContractDeployed") + .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), expectedAddress) + .to.emit(Deployable__factory.connect(expectedAddress, wallet), "Deployed") + .withArgs(0, "0x12"); + const accountInfo = await contractDeployer.getAccountInfo(expectedAddress); + expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); + expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); + }); + }); + + describe("create2", function () { + it("non system call failed", async () => { + await expect( + contractDeployerNotSystemCall.create2( + ethers.constants.HashZero, + utils.hashBytecode(deployableArtifact.bytecode), + "0x" + ) + ).to.be.revertedWith("This method require system call flag"); + }); + + it("successfully deployed", async () => { + const expectedAddress = utils.create2Address( + wallet.address, + utils.hashBytecode(deployableArtifact.bytecode), + "0x1234567891234567891234512222122167891123456789123456787654323456", + "0xab" + ); + await expect( + contractDeployer.create2( + "0x1234567891234567891234512222122167891123456789123456787654323456", + utils.hashBytecode(deployableArtifact.bytecode), + "0xab" + ) + ) + .to.emit(contractDeployer, "ContractDeployed") + .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), expectedAddress) + .to.emit(Deployable__factory.connect(expectedAddress, wallet), "Deployed") + .withArgs(0, "0xab"); + const accountInfo = await contractDeployer.getAccountInfo(expectedAddress); + expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); + expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); + }); + }); + + describe("forceDeployOnAddress", function () { + it("not from self call failed", async () => { + const deploymentData = { + bytecodeHash: utils.hashBytecode(deployableArtifact.bytecode), + newAddress: RANDOM_ADDRESS, + callConstructor: false, + value: 0, + input: "0x", + }; + await expect(contractDeployer.forceDeployOnAddress(deploymentData, wallet.address)).to.be.revertedWith( + "Callable only by self" + ); + }); + + it("not known bytecode hash failed", async () => { + const deploymentData = { + bytecodeHash: "0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF", + newAddress: RANDOM_ADDRESS, + callConstructor: false, + value: 0, + input: "0x", + }; + await expect( + contractDeployer.connect(deployerAccount).forceDeployOnAddress(deploymentData, wallet.address) + ).to.be.revertedWith("The code hash is not known"); + }); + + it("successfully deployed", async () => { + const deploymentData = { + bytecodeHash: utils.hashBytecode(deployableArtifact.bytecode), + newAddress: RANDOM_ADDRESS, + callConstructor: false, + value: 0, + input: "0x", + }; + await expect(contractDeployer.connect(deployerAccount).forceDeployOnAddress(deploymentData, wallet.address)) + .to.emit(contractDeployer, "ContractDeployed") + .withArgs(wallet.address, utils.hashBytecode(deployableArtifact.bytecode), RANDOM_ADDRESS) + .to.not.emit(Deployable__factory.connect(RANDOM_ADDRESS, wallet), "Deployed"); + const accountInfo = await contractDeployer.getAccountInfo(RANDOM_ADDRESS); + expect(accountInfo.supportedAAVersion).to.be.eq(AA_VERSION_NONE); + expect(accountInfo.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); + }); + }); + + describe("forceDeployOnAddresses", function () { + it("not allowed to call", async () => { + const deploymentData = [ + { + bytecodeHash: utils.hashBytecode(deployableArtifact.bytecode), + newAddress: RANDOM_ADDRESS_2, + callConstructor: true, + value: 0, + input: "0x", + }, + { + bytecodeHash: utils.hashBytecode(deployableArtifact.bytecode), + newAddress: RANDOM_ADDRESS_3, + callConstructor: false, + value: 0, + input: "0xab", + }, + ]; + await expect(contractDeployer.forceDeployOnAddresses(deploymentData)).to.be.revertedWith( + "Can only be called by FORCE_DEPLOYER or COMPLEX_UPGRADER_CONTRACT" + ); + }); + + it("successfully deployed", async () => { + const deploymentData = [ + { + bytecodeHash: utils.hashBytecode(deployableArtifact.bytecode), + newAddress: RANDOM_ADDRESS_2, + callConstructor: true, + value: 0, + input: "0x", + }, + { + bytecodeHash: utils.hashBytecode(deployableArtifact.bytecode), + newAddress: RANDOM_ADDRESS_3, + callConstructor: false, + value: 0, + input: "0xab", + }, + ]; + await expect(contractDeployer.connect(forceDeployer).forceDeployOnAddresses(deploymentData)) + .to.emit(contractDeployer, "ContractDeployed") + .withArgs(forceDeployer.address, utils.hashBytecode(deployableArtifact.bytecode), RANDOM_ADDRESS_2) + .to.emit(contractDeployer, "ContractDeployed") + .withArgs(forceDeployer.address, utils.hashBytecode(deployableArtifact.bytecode), RANDOM_ADDRESS_3) + .to.emit(Deployable__factory.connect(RANDOM_ADDRESS_2, wallet), "Deployed") + .withArgs(0, "0x") + .to.not.emit(Deployable__factory.connect(RANDOM_ADDRESS_3, wallet), "Deployed"); + + const accountInfo1 = await contractDeployer.getAccountInfo(RANDOM_ADDRESS_2); + expect(accountInfo1.supportedAAVersion).to.be.eq(AA_VERSION_NONE); + expect(accountInfo1.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); + + const accountInfo2 = await contractDeployer.getAccountInfo(RANDOM_ADDRESS_3); + expect(accountInfo2.supportedAAVersion).to.be.eq(AA_VERSION_NONE); + expect(accountInfo2.nonceOrdering).to.be.eq(NONCE_ORDERING_SEQUENTIAL); }); + }); }); diff --git a/test/DefaultAccount.spec.ts b/test/DefaultAccount.spec.ts index a2460581846..25f5b86ca56 100644 --- a/test/DefaultAccount.spec.ts +++ b/test/DefaultAccount.spec.ts @@ -1,375 +1,363 @@ -import { expect } from 'chai'; -import { ethers, network } from 'hardhat'; -import * as zksync from 'zksync-web3'; -import { Wallet } from 'zksync-web3'; -import { serialize } from 'zksync-web3/build/src/utils'; +import { expect } from "chai"; +import { ethers, network } from "hardhat"; +import * as zksync from "zksync-web3"; +import type { Wallet } from "zksync-web3"; +import { serialize } from "zksync-web3/build/src/utils"; +import type { Callable, DefaultAccount, L2EthToken, MockERC20Approve, NonceHolder } from "../typechain-types"; +import { DefaultAccount__factory, L2EthToken__factory, NonceHolder__factory } from "../typechain-types"; import { - Callable, - DefaultAccount, - DefaultAccount__factory, - L2EthToken, - L2EthToken__factory, - MockERC20Approve, - NonceHolder, - NonceHolder__factory -} from '../typechain-types'; -import { - BOOTLOADER_FORMAL_ADDRESS, - ETH_TOKEN_SYSTEM_CONTRACT_ADDRESS, - NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS -} from './shared/constants'; -import { signedTxToTransactionData } from './shared/transactions'; -import { deployContract, getWallets, loadArtifact, setCode } from './shared/utils'; - -describe('DefaultAccount tests', function () { - let wallet: Wallet; - let account: Wallet; - let defaultAccount: DefaultAccount; - let bootloader: ethers.Signer; - let nonceHolder: NonceHolder; - let l2EthToken: L2EthToken; - let callable: Callable; - let mockERC20Approve: MockERC20Approve; - let paymasterFlowInterface: ethers.utils.Interface; - - const RANDOM_ADDRESS = ethers.utils.getAddress('0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'); - - before(async () => { - wallet = getWallets()[0]; - account = getWallets()[2]; - const defaultAccountArtifact = await loadArtifact('DefaultAccount'); - await setCode(account.address, defaultAccountArtifact.bytecode); - defaultAccount = DefaultAccount__factory.connect(account.address, wallet); - nonceHolder = NonceHolder__factory.connect(NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS, wallet); - l2EthToken = L2EthToken__factory.connect(ETH_TOKEN_SYSTEM_CONTRACT_ADDRESS, wallet); - callable = (await deployContract('Callable')) as Callable; - mockERC20Approve = (await deployContract('MockERC20Approve')) as MockERC20Approve; - - const paymasterFlowInterfaceArtifact = await loadArtifact('IPaymasterFlow'); - paymasterFlowInterface = new ethers.utils.Interface(paymasterFlowInterfaceArtifact.abi); - - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); + BOOTLOADER_FORMAL_ADDRESS, + ETH_TOKEN_SYSTEM_CONTRACT_ADDRESS, + NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS, +} from "./shared/constants"; +import { signedTxToTransactionData } from "./shared/transactions"; +import { deployContract, getWallets, loadArtifact, setCode } from "./shared/utils"; + +describe("DefaultAccount tests", function () { + let wallet: Wallet; + let account: Wallet; + let defaultAccount: DefaultAccount; + let bootloader: ethers.Signer; + let nonceHolder: NonceHolder; + let l2EthToken: L2EthToken; + let callable: Callable; + let mockERC20Approve: MockERC20Approve; + let paymasterFlowInterface: ethers.utils.Interface; + + const RANDOM_ADDRESS = ethers.utils.getAddress("0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); + + before(async () => { + wallet = getWallets()[0]; + account = getWallets()[2]; + const defaultAccountArtifact = await loadArtifact("DefaultAccount"); + await setCode(account.address, defaultAccountArtifact.bytecode); + defaultAccount = DefaultAccount__factory.connect(account.address, wallet); + nonceHolder = NonceHolder__factory.connect(NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS, wallet); + l2EthToken = L2EthToken__factory.connect(ETH_TOKEN_SYSTEM_CONTRACT_ADDRESS, wallet); + callable = (await deployContract("Callable")) as Callable; + mockERC20Approve = (await deployContract("MockERC20Approve")) as MockERC20Approve; + + const paymasterFlowInterfaceArtifact = await loadArtifact("IPaymasterFlow"); + paymasterFlowInterface = new ethers.utils.Interface(paymasterFlowInterfaceArtifact.abi); + + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], }); + bootloader = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); + }); - after(async function () { - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); + after(async function () { + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], + }); + }); + + describe("validateTransaction", function () { + it("non-deployer ignored", async () => { + const nonce = await nonceHolder.getMinNonce(account.address); + const legacyTx = await account.populateTransaction({ + type: 0, + to: RANDOM_ADDRESS, + from: account.address, + nonce: nonce, + data: "0x", + value: 0, + gasLimit: 50000, + }); + const txBytes = await account.signTransaction(legacyTx); + const parsedTx = zksync.utils.parseTransaction(txBytes); + const txData = signedTxToTransactionData(parsedTx)!; + + const txHash = parsedTx.hash; + delete legacyTx.from; + const signedHash = ethers.utils.keccak256(serialize(legacyTx)); + + const call = { + from: wallet.address, + to: defaultAccount.address, + value: 0, + data: defaultAccount.interface.encodeFunctionData("validateTransaction", [txHash, signedHash, txData]), + }; + expect(await wallet.provider.call(call)).to.be.eq("0x"); }); - describe('validateTransaction', function () { - it('non-deployer ignored', async () => { - const nonce = await nonceHolder.getMinNonce(account.address); - const legacyTx = await account.populateTransaction({ - type: 0, - to: RANDOM_ADDRESS, - from: account.address, - nonce: nonce, - data: '0x', - value: 0, - gasLimit: 50000 - }); - const txBytes = await account.signTransaction(legacyTx); - const parsedTx = zksync.utils.parseTransaction(txBytes); - const txData = signedTxToTransactionData(parsedTx)!; - - const txHash = parsedTx.hash; - delete legacyTx.from; - const signedHash = ethers.utils.keccak256(serialize(legacyTx)); - - const call = { - from: wallet.address, - to: defaultAccount.address, - value: 0, - data: defaultAccount.interface.encodeFunctionData('validateTransaction', [txHash, signedHash, txData]) - }; - expect(await wallet.provider.call(call)).to.be.eq('0x'); - }); - - it('invalid ignature', async () => { - const nonce = await nonceHolder.getMinNonce(account.address); - const legacyTx = await account.populateTransaction({ - type: 0, - to: RANDOM_ADDRESS, - from: account.address, - nonce: nonce, - data: '0x', - value: 0, - gasLimit: 50000 - }); - const txBytes = await account.signTransaction(legacyTx); - const parsedTx = zksync.utils.parseTransaction(txBytes); - parsedTx.s = '0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0'; - const txData = signedTxToTransactionData(parsedTx)!; - - const txHash = parsedTx.hash; - delete legacyTx.from; - const signedHash = ethers.utils.keccak256(serialize(legacyTx)); - - const call = { - from: BOOTLOADER_FORMAL_ADDRESS, - to: defaultAccount.address, - value: 0, - data: defaultAccount.interface.encodeFunctionData('validateTransaction', [txHash, signedHash, txData]) - }; - expect(await bootloader.provider.call(call)).to.be.eq(ethers.constants.HashZero); - }); - - it('valid tx', async () => { - const nonce = await nonceHolder.getMinNonce(account.address); - const legacyTx = await account.populateTransaction({ - type: 0, - to: RANDOM_ADDRESS, - from: account.address, - nonce: nonce, - data: '0x', - value: 0, - gasLimit: 50000 - }); - const txBytes = await account.signTransaction(legacyTx); - const parsedTx = zksync.utils.parseTransaction(txBytes); - const txData = signedTxToTransactionData(parsedTx)!; - - const txHash = parsedTx.hash; - delete legacyTx.from; - const signedHash = ethers.utils.keccak256(serialize(legacyTx)); - - const call = { - from: BOOTLOADER_FORMAL_ADDRESS, - to: defaultAccount.address, - value: 0, - data: defaultAccount.interface.encodeFunctionData('validateTransaction', [txHash, signedHash, txData]) - }; - expect(await bootloader.provider.call(call)).to.be.eq( - defaultAccount.interface.getSighash('validateTransaction') + '0'.repeat(56) - ); - }); + it("invalid ignature", async () => { + const nonce = await nonceHolder.getMinNonce(account.address); + const legacyTx = await account.populateTransaction({ + type: 0, + to: RANDOM_ADDRESS, + from: account.address, + nonce: nonce, + data: "0x", + value: 0, + gasLimit: 50000, + }); + const txBytes = await account.signTransaction(legacyTx); + const parsedTx = zksync.utils.parseTransaction(txBytes); + parsedTx.s = "0x0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0"; + const txData = signedTxToTransactionData(parsedTx)!; + + const txHash = parsedTx.hash; + delete legacyTx.from; + const signedHash = ethers.utils.keccak256(serialize(legacyTx)); + + const call = { + from: BOOTLOADER_FORMAL_ADDRESS, + to: defaultAccount.address, + value: 0, + data: defaultAccount.interface.encodeFunctionData("validateTransaction", [txHash, signedHash, txData]), + }; + expect(await bootloader.provider.call(call)).to.be.eq(ethers.constants.HashZero); }); - describe('executeTransaction', function () { - it('non-deployer ignored', async () => { - const nonce = await nonceHolder.getMinNonce(account.address); - const legacyTx = await account.populateTransaction({ - type: 0, - to: callable.address, - from: account.address, - nonce: nonce, - data: '0xdeadbeef', - value: 5, - gasLimit: 50000 - }); - const txBytes = await account.signTransaction(legacyTx); - const parsedTx = zksync.utils.parseTransaction(txBytes); - const txData = signedTxToTransactionData(parsedTx)!; - - const txHash = parsedTx.hash; - delete legacyTx.from; - const signedHash = ethers.utils.keccak256(serialize(legacyTx)); - - await expect(await defaultAccount.executeTransaction(txHash, signedHash, txData)).to.not.emit( - callable, - 'Called' - ); - }); - - it('successfully executed', async () => { - const nonce = await nonceHolder.getMinNonce(account.address); - const legacyTx = await account.populateTransaction({ - type: 0, - to: callable.address, - from: account.address, - nonce: nonce, - data: '0xdeadbeef', - value: 5, - gasLimit: 50000 - }); - const txBytes = await account.signTransaction(legacyTx); - const parsedTx = zksync.utils.parseTransaction(txBytes); - const txData = signedTxToTransactionData(parsedTx)!; - - const txHash = parsedTx.hash; - delete legacyTx.from; - const signedHash = ethers.utils.keccak256(serialize(legacyTx)); - - await expect(await defaultAccount.connect(bootloader).executeTransaction(txHash, signedHash, txData)) - .to.emit(callable, 'Called') - .withArgs(5, '0xdeadbeef'); - }); + it("valid tx", async () => { + const nonce = await nonceHolder.getMinNonce(account.address); + const legacyTx = await account.populateTransaction({ + type: 0, + to: RANDOM_ADDRESS, + from: account.address, + nonce: nonce, + data: "0x", + value: 0, + gasLimit: 50000, + }); + const txBytes = await account.signTransaction(legacyTx); + const parsedTx = zksync.utils.parseTransaction(txBytes); + const txData = signedTxToTransactionData(parsedTx)!; + + const txHash = parsedTx.hash; + delete legacyTx.from; + const signedHash = ethers.utils.keccak256(serialize(legacyTx)); + + const call = { + from: BOOTLOADER_FORMAL_ADDRESS, + to: defaultAccount.address, + value: 0, + data: defaultAccount.interface.encodeFunctionData("validateTransaction", [txHash, signedHash, txData]), + }; + expect(await bootloader.provider.call(call)).to.be.eq( + defaultAccount.interface.getSighash("validateTransaction") + "0".repeat(56) + ); + }); + }); + + describe("executeTransaction", function () { + it("non-deployer ignored", async () => { + const nonce = await nonceHolder.getMinNonce(account.address); + const legacyTx = await account.populateTransaction({ + type: 0, + to: callable.address, + from: account.address, + nonce: nonce, + data: "0xdeadbeef", + value: 5, + gasLimit: 50000, + }); + const txBytes = await account.signTransaction(legacyTx); + const parsedTx = zksync.utils.parseTransaction(txBytes); + const txData = signedTxToTransactionData(parsedTx)!; + + const txHash = parsedTx.hash; + delete legacyTx.from; + const signedHash = ethers.utils.keccak256(serialize(legacyTx)); + + await expect(await defaultAccount.executeTransaction(txHash, signedHash, txData)).to.not.emit(callable, "Called"); }); - describe('executeTransactionFromOutside', function () { - it('nothing', async () => { - const nonce = await nonceHolder.getMinNonce(account.address); - const legacyTx = await account.populateTransaction({ - type: 0, - to: callable.address, - from: account.address, - nonce: nonce, - data: '0xdeadbeef', - value: 5, - gasLimit: 50000 - }); - const txBytes = await account.signTransaction(legacyTx); - const parsedTx = zksync.utils.parseTransaction(txBytes); - const txData = signedTxToTransactionData(parsedTx)!; - - delete legacyTx.from; - - await expect(await defaultAccount.executeTransactionFromOutside(txData)).to.not.emit(callable, 'Called'); - }); + it("successfully executed", async () => { + const nonce = await nonceHolder.getMinNonce(account.address); + const legacyTx = await account.populateTransaction({ + type: 0, + to: callable.address, + from: account.address, + nonce: nonce, + data: "0xdeadbeef", + value: 5, + gasLimit: 50000, + }); + const txBytes = await account.signTransaction(legacyTx); + const parsedTx = zksync.utils.parseTransaction(txBytes); + const txData = signedTxToTransactionData(parsedTx)!; + + const txHash = parsedTx.hash; + delete legacyTx.from; + const signedHash = ethers.utils.keccak256(serialize(legacyTx)); + + await expect(await defaultAccount.connect(bootloader).executeTransaction(txHash, signedHash, txData)) + .to.emit(callable, "Called") + .withArgs(5, "0xdeadbeef"); + }); + }); + + describe("executeTransactionFromOutside", function () { + it("nothing", async () => { + const nonce = await nonceHolder.getMinNonce(account.address); + const legacyTx = await account.populateTransaction({ + type: 0, + to: callable.address, + from: account.address, + nonce: nonce, + data: "0xdeadbeef", + value: 5, + gasLimit: 50000, + }); + const txBytes = await account.signTransaction(legacyTx); + const parsedTx = zksync.utils.parseTransaction(txBytes); + const txData = signedTxToTransactionData(parsedTx)!; + + delete legacyTx.from; + + await expect(await defaultAccount.executeTransactionFromOutside(txData)).to.not.emit(callable, "Called"); + }); + }); + + describe("payForTransaction", function () { + it("non-deployer ignored", async () => { + const nonce = await nonceHolder.getMinNonce(account.address); + const legacyTx = await account.populateTransaction({ + type: 0, + to: callable.address, + from: account.address, + nonce: nonce, + data: "0xdeadbeef", + value: 5, + gasLimit: 50000, + gasPrice: 200, + }); + const txBytes = await account.signTransaction(legacyTx); + const parsedTx = zksync.utils.parseTransaction(txBytes); + const txData = signedTxToTransactionData(parsedTx)!; + + const txHash = parsedTx.hash; + delete legacyTx.from; + const signedHash = ethers.utils.keccak256(serialize(legacyTx)); + + const balanceBefore = await l2EthToken.balanceOf(defaultAccount.address); + await defaultAccount.payForTransaction(txHash, signedHash, txData); + const balanceAfter = await l2EthToken.balanceOf(defaultAccount.address); + expect(balanceAfter).to.be.eq(balanceBefore); }); - describe('payForTransaction', function () { - it('non-deployer ignored', async () => { - const nonce = await nonceHolder.getMinNonce(account.address); - const legacyTx = await account.populateTransaction({ - type: 0, - to: callable.address, - from: account.address, - nonce: nonce, - data: '0xdeadbeef', - value: 5, - gasLimit: 50000, - gasPrice: 200 - }); - const txBytes = await account.signTransaction(legacyTx); - const parsedTx = zksync.utils.parseTransaction(txBytes); - const txData = signedTxToTransactionData(parsedTx)!; - - const txHash = parsedTx.hash; - delete legacyTx.from; - const signedHash = ethers.utils.keccak256(serialize(legacyTx)); - - const balanceBefore = await l2EthToken.balanceOf(defaultAccount.address); - await defaultAccount.payForTransaction(txHash, signedHash, txData); - const balanceAfter = await l2EthToken.balanceOf(defaultAccount.address); - expect(balanceAfter).to.be.eq(balanceBefore); - }); - - it('successfully payed', async () => { - const nonce = await nonceHolder.getMinNonce(account.address); - const legacyTx = await account.populateTransaction({ - type: 0, - to: callable.address, - from: account.address, - nonce: nonce, - data: '0xdeadbeef', - value: 5, - gasLimit: 50000, - gasPrice: 200 - }); - const txBytes = await account.signTransaction(legacyTx); - const parsedTx = zksync.utils.parseTransaction(txBytes); - const txData = signedTxToTransactionData(parsedTx)!; - - const txHash = parsedTx.hash; - delete legacyTx.from; - const signedHash = ethers.utils.keccak256(serialize(legacyTx)); - - await expect(await defaultAccount.connect(bootloader).payForTransaction(txHash, signedHash, txData)) - .to.emit(l2EthToken, 'Transfer') - .withArgs(account.address, BOOTLOADER_FORMAL_ADDRESS, 50000 * 200); - }); + it("successfully payed", async () => { + const nonce = await nonceHolder.getMinNonce(account.address); + const legacyTx = await account.populateTransaction({ + type: 0, + to: callable.address, + from: account.address, + nonce: nonce, + data: "0xdeadbeef", + value: 5, + gasLimit: 50000, + gasPrice: 200, + }); + const txBytes = await account.signTransaction(legacyTx); + const parsedTx = zksync.utils.parseTransaction(txBytes); + const txData = signedTxToTransactionData(parsedTx)!; + + const txHash = parsedTx.hash; + delete legacyTx.from; + const signedHash = ethers.utils.keccak256(serialize(legacyTx)); + + await expect(await defaultAccount.connect(bootloader).payForTransaction(txHash, signedHash, txData)) + .to.emit(l2EthToken, "Transfer") + .withArgs(account.address, BOOTLOADER_FORMAL_ADDRESS, 50000 * 200); + }); + }); + + describe("prepareForPaymaster", function () { + it("non-deployer ignored", async () => { + const eip712Tx = await account.populateTransaction({ + type: 113, + to: callable.address, + from: account.address, + data: "0x", + value: 0, + maxFeePerGas: 12000, + maxPriorityFeePerGas: 100, + gasLimit: 50000, + customData: { + gasPerPubdata: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, + paymasterParams: { + paymaster: RANDOM_ADDRESS, + paymasterInput: paymasterFlowInterface.encodeFunctionData("approvalBased", [ + mockERC20Approve.address, + 2023, + "0x", + ]), + }, + }, + }); + const signedEip712Tx = await account.signTransaction(eip712Tx); + const parsedEIP712tx = zksync.utils.parseTransaction(signedEip712Tx); + + const eip712TxData = signedTxToTransactionData(parsedEIP712tx)!; + const eip712TxHash = parsedEIP712tx.hash; + const eip712SignedHash = zksync.EIP712Signer.getSignedDigest(eip712Tx); + + await expect(await defaultAccount.prepareForPaymaster(eip712TxHash, eip712SignedHash, eip712TxData)).to.not.emit( + mockERC20Approve, + "Approved" + ); }); - describe('prepareForPaymaster', function () { - it('non-deployer ignored', async () => { - const eip712Tx = await account.populateTransaction({ - type: 113, - to: callable.address, - from: account.address, - data: '0x', - value: 0, - maxFeePerGas: 12000, - maxPriorityFeePerGas: 100, - gasLimit: 50000, - customData: { - gasPerPubdata: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams: { - paymaster: RANDOM_ADDRESS, - paymasterInput: paymasterFlowInterface.encodeFunctionData('approvalBased', [ - mockERC20Approve.address, - 2023, - '0x' - ]) - } - } - }); - const signedEip712Tx = await account.signTransaction(eip712Tx); - const parsedEIP712tx = zksync.utils.parseTransaction(signedEip712Tx); - - const eip712TxData = signedTxToTransactionData(parsedEIP712tx)!; - const eip712TxHash = parsedEIP712tx.hash; - const eip712SignedHash = zksync.EIP712Signer.getSignedDigest(eip712Tx); - - await expect( - await defaultAccount.prepareForPaymaster(eip712TxHash, eip712SignedHash, eip712TxData) - ).to.not.emit(mockERC20Approve, 'Approved'); - }); - - it('successfully prepared', async () => { - const eip712Tx = await account.populateTransaction({ - type: 113, - to: callable.address, - from: account.address, - data: '0x', - value: 0, - maxFeePerGas: 12000, - maxPriorityFeePerGas: 100, - gasLimit: 50000, - customData: { - gasPerPubdata: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - paymasterParams: { - paymaster: RANDOM_ADDRESS, - paymasterInput: paymasterFlowInterface.encodeFunctionData('approvalBased', [ - mockERC20Approve.address, - 2023, - '0x' - ]) - } - } - }); - const signedEip712Tx = await account.signTransaction(eip712Tx); - const parsedEIP712tx = zksync.utils.parseTransaction(signedEip712Tx); - - const eip712TxData = signedTxToTransactionData(parsedEIP712tx)!; - const eip712TxHash = parsedEIP712tx.hash; - const eip712SignedHash = zksync.EIP712Signer.getSignedDigest(eip712Tx); - - await expect( - await defaultAccount - .connect(bootloader) - .prepareForPaymaster(eip712TxHash, eip712SignedHash, eip712TxData) - ) - .to.emit(mockERC20Approve, 'Approved') - .withArgs(RANDOM_ADDRESS, 2023); - }); + it("successfully prepared", async () => { + const eip712Tx = await account.populateTransaction({ + type: 113, + to: callable.address, + from: account.address, + data: "0x", + value: 0, + maxFeePerGas: 12000, + maxPriorityFeePerGas: 100, + gasLimit: 50000, + customData: { + gasPerPubdata: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, + paymasterParams: { + paymaster: RANDOM_ADDRESS, + paymasterInput: paymasterFlowInterface.encodeFunctionData("approvalBased", [ + mockERC20Approve.address, + 2023, + "0x", + ]), + }, + }, + }); + const signedEip712Tx = await account.signTransaction(eip712Tx); + const parsedEIP712tx = zksync.utils.parseTransaction(signedEip712Tx); + + const eip712TxData = signedTxToTransactionData(parsedEIP712tx)!; + const eip712TxHash = parsedEIP712tx.hash; + const eip712SignedHash = zksync.EIP712Signer.getSignedDigest(eip712Tx); + + await expect( + await defaultAccount.connect(bootloader).prepareForPaymaster(eip712TxHash, eip712SignedHash, eip712TxData) + ) + .to.emit(mockERC20Approve, "Approved") + .withArgs(RANDOM_ADDRESS, 2023); + }); + }); + + describe("fallback/receive", function () { + it("zero value", async () => { + const call = { + from: wallet.address, + to: defaultAccount.address, + value: 0, + data: "0x872384894899834939049043904390390493434343434344433443433434344234234234", + }; + expect(await wallet.provider.call(call)).to.be.eq("0x"); }); - describe('fallback/receive', function () { - it('zero value', async () => { - const call = { - from: wallet.address, - to: defaultAccount.address, - value: 0, - data: '0x872384894899834939049043904390390493434343434344433443433434344234234234' - }; - expect(await wallet.provider.call(call)).to.be.eq('0x'); - }); - - it('non-zero value', async () => { - const call = { - from: wallet.address, - to: defaultAccount.address, - value: 3223, - data: '0x87238489489983493904904390431212224343434344433443433434344234234234' - }; - expect(await wallet.provider.call(call)).to.be.eq('0x'); - }); + it("non-zero value", async () => { + const call = { + from: wallet.address, + to: defaultAccount.address, + value: 3223, + data: "0x87238489489983493904904390431212224343434344433443433434344234234234", + }; + expect(await wallet.provider.call(call)).to.be.eq("0x"); }); + }); }); diff --git a/test/EcAdd.spec.ts b/test/EcAdd.spec.ts index 8daf2d55781..a17a9f0b699 100644 --- a/test/EcAdd.spec.ts +++ b/test/EcAdd.spec.ts @@ -1,188 +1,188 @@ -import { expect } from 'chai'; -import { Contract } from 'zksync-web3'; -import { callFallback, deployContractYul } from './shared/utils'; - -describe('EcAdd tests', function () { - let ecAdd: Contract; - - before(async () => { - ecAdd = await deployContractYul('EcAdd', 'precompiles'); - }); - - describe('Ethereum tests', function () { - it('0 bytes: (0, 0) + (0, 0)', async () => { - const returnData = await callFallback(ecAdd, ''); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - }); - - it('128 bytes: (6, 9) + (19274124, 124124)', async () => { - const call = callFallback( - ecAdd, - '0x00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000126198c000000000000000000000000000000000000000000000000000000000001e4dc' - ); - await expect(call).to.be.reverted; - }); - - it('128 bytes: (1, 2) + (0, 0)', async () => { - const returnData = await callFallback( - ecAdd, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002' - ); - }); - - it('128 bytes: (0, 0) + (0, 0)', async () => { - const returnData = await callFallback( - ecAdd, - '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - }); - - it('128 bytes: (0, 3) + (1, 2)', async () => { - const call = callFallback( - ecAdd, - '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002' - ); - await expect(call).to.be.reverted; - }); - - it('128 bytes: (0, 0) + (1, 3)', async () => { - const call = callFallback( - ecAdd, - '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003' - ); - await expect(call).to.be.reverted; - }); - - it('128 bytes: (0, 0) + (1, 2)', async () => { - const returnData = await callFallback( - ecAdd, - '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002' - ); - }); - - it('64 bytes: (0, 0) + (0, 0)', async () => { - const returnData = await callFallback( - ecAdd, - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - }); - - it('128 bytes: (1, 2) + (1, 2)', async () => { - const returnData = await callFallback( - ecAdd, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002' - ); - await expect(returnData).to.be.equal( - '0x030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4' - ); - }); - - it('80 bytes: (1, 3) + (0, 0)', async () => { - const call = callFallback( - ecAdd, - '0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(call).to.be.reverted; - }); - - it('192 bytes: (1, 2) + (0, 0)', async () => { - const returnData = await callFallback( - ecAdd, - '0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002' - ); - }); - - it('192 bytes: (0, 0) + (0, 0)', async () => { - const returnData = await callFallback( - ecAdd, - '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - }); - - it('80 bytes: (0, 0) + (0, 0)', async () => { - const returnData = await callFallback( - ecAdd, - '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - }); - - // (10744596414106452074759370245733544594153395043370666422502510773307029471145, 848677436511517736191562425154572367705380862894644942948681172815252343932) - // + - // (10744596414106452074759370245733544594153395043370666422502510773307029471145, 21039565435327757486054843320102702720990930294403178719740356721829973864651) - it('192 bytes: (1074..1145, 8486..3932) + (1074..1145, 2103..4651)', async () => { - const returnData = await callFallback( - ecAdd, - '0x17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa92e83f8d734803fc370eba25ed1f6b8768bd6d83887b87165fc2434fe11a830cb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - }); - - it('192 bytes: (0, 0) + (1, 2)', async () => { - const returnData = await callFallback( - ecAdd, - '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002' - ); - }); - - it('192 bytes: (1, 2) + (1, 2)', async () => { - const returnData = await callFallback( - ecAdd, - '0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4' - ); - }); - - it('64 bytes: (1, 2) + (0, 0)', async () => { - const returnData = await callFallback( - ecAdd, - '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002' - ); - }); - - // (10744596414106452074759370245733544594153395043370666422502510773307029471145, 848677436511517736191562425154572367705380862894644942948681172815252343932) - // + - // (1624070059937464756887933993293429854168590106605707304006200119738501412969, 3269329550605213075043232856820720631601935657990457502777101397807070461336) - it('128 bytes: (1074..1145, 8486..3932) + (1624..2969, 3269..1336)', async () => { - const returnData = await callFallback( - ecAdd, - '0x17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98' - ); - await expect(returnData).to.be.equal( - '0x15bf2bb17880144b5d1cd2b1f46eff9d617bffd1ca57c37fb5a49bd84e53cf66049c797f9ce0d17083deb32b5e36f2ea2a212ee036598dd7624c168993d1355f' - ); - }); +import { expect } from "chai"; +import type { Contract } from "zksync-web3"; +import { callFallback, deployContractYul } from "./shared/utils"; + +describe("EcAdd tests", function () { + let ecAdd: Contract; + + before(async () => { + ecAdd = await deployContractYul("EcAdd", "precompiles"); + }); + + describe("Ethereum tests", function () { + it("0 bytes: (0, 0) + (0, 0)", async () => { + const returnData = await callFallback(ecAdd, ""); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); }); + + it("128 bytes: (6, 9) + (19274124, 124124)", async () => { + const call = callFallback( + ecAdd, + "0x00000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000126198c000000000000000000000000000000000000000000000000000000000001e4dc" + ); + await expect(call).to.be.reverted; + }); + + it("128 bytes: (1, 2) + (0, 0)", async () => { + const returnData = await callFallback( + ecAdd, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002" + ); + }); + + it("128 bytes: (0, 0) + (0, 0)", async () => { + const returnData = await callFallback( + ecAdd, + "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + }); + + it("128 bytes: (0, 3) + (1, 2)", async () => { + const call = callFallback( + ecAdd, + "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002" + ); + await expect(call).to.be.reverted; + }); + + it("128 bytes: (0, 0) + (1, 3)", async () => { + const call = callFallback( + ecAdd, + "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003" + ); + await expect(call).to.be.reverted; + }); + + it("128 bytes: (0, 0) + (1, 2)", async () => { + const returnData = await callFallback( + ecAdd, + "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002" + ); + }); + + it("64 bytes: (0, 0) + (0, 0)", async () => { + const returnData = await callFallback( + ecAdd, + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + }); + + it("128 bytes: (1, 2) + (1, 2)", async () => { + const returnData = await callFallback( + ecAdd, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002" + ); + await expect(returnData).to.be.equal( + "0x030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4" + ); + }); + + it("80 bytes: (1, 3) + (0, 0)", async () => { + const call = callFallback( + ecAdd, + "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(call).to.be.reverted; + }); + + it("192 bytes: (1, 2) + (0, 0)", async () => { + const returnData = await callFallback( + ecAdd, + "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002" + ); + }); + + it("192 bytes: (0, 0) + (0, 0)", async () => { + const returnData = await callFallback( + ecAdd, + "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + }); + + it("80 bytes: (0, 0) + (0, 0)", async () => { + const returnData = await callFallback( + ecAdd, + "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + }); + + // (10744596414106452074759370245733544594153395043370666422502510773307029471145, 848677436511517736191562425154572367705380862894644942948681172815252343932) + // + + // (10744596414106452074759370245733544594153395043370666422502510773307029471145, 21039565435327757486054843320102702720990930294403178719740356721829973864651) + it("192 bytes: (1074..1145, 8486..3932) + (1074..1145, 2103..4651)", async () => { + const returnData = await callFallback( + ecAdd, + "0x17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa92e83f8d734803fc370eba25ed1f6b8768bd6d83887b87165fc2434fe11a830cb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + }); + + it("192 bytes: (0, 0) + (1, 2)", async () => { + const returnData = await callFallback( + ecAdd, + "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002" + ); + }); + + it("192 bytes: (1, 2) + (1, 2)", async () => { + const returnData = await callFallback( + ecAdd, + "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4" + ); + }); + + it("64 bytes: (1, 2) + (0, 0)", async () => { + const returnData = await callFallback( + ecAdd, + "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002" + ); + }); + + // (10744596414106452074759370245733544594153395043370666422502510773307029471145, 848677436511517736191562425154572367705380862894644942948681172815252343932) + // + + // (1624070059937464756887933993293429854168590106605707304006200119738501412969, 3269329550605213075043232856820720631601935657990457502777101397807070461336) + it("128 bytes: (1074..1145, 8486..3932) + (1624..2969, 3269..1336)", async () => { + const returnData = await callFallback( + ecAdd, + "0x17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98" + ); + await expect(returnData).to.be.equal( + "0x15bf2bb17880144b5d1cd2b1f46eff9d617bffd1ca57c37fb5a49bd84e53cf66049c797f9ce0d17083deb32b5e36f2ea2a212ee036598dd7624c168993d1355f" + ); + }); + }); }); diff --git a/test/EcMul.spec.ts b/test/EcMul.spec.ts index b490d029809..8a29c29b2e6 100644 --- a/test/EcMul.spec.ts +++ b/test/EcMul.spec.ts @@ -1,399 +1,399 @@ -import { expect } from 'chai'; -import { Contract } from 'zksync-web3'; -import { callFallback, deployContractYul } from './shared/utils'; - -describe('EcMul tests', function () { - let ecMul: Contract; - - before(async () => { - ecMul = await deployContractYul('EcMul', 'precompiles'); - }); - - describe('Ethereum tests', function () { - it('128 bytes: (1, 3) * 0', async () => { - const call = callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(call).to.be.reverted; - }); - - it('128 bytes: (1, 2) * 21888242871839275222246405745257275088548364400416034343698204186575808495616', async () => { - const returnData = await callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000230644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000000000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45' - ); - }); - - it('64 bytes: (1, 3) * 0', async () => { - const call = callFallback( - ecMul, - '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003' - ); - await expect(call).to.be.reverted; - }); - - it('128 bytes: (1, 3) * 21888242871839275222246405745257275088548364400416034343698204186575808495616', async () => { - const call = callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000330644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000000000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(call).to.be.reverted; - }); - - it('96 bytes: (1, 3) * 21888242871839275222246405745257275088548364400416034343698204186575808495617', async () => { - const call = callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000330644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001' - ); - await expect(call).to.be.reverted; - }); - - it('96 bytes: (1, 3) * 1', async () => { - const call = callFallback( - ecMul, - '0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001' - ); - await expect(call).to.be.reverted; - }); - - // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) - // * - // 21888242871839275222246405745257275088548364400416034343698204186575808495616 - it('96 bytes: (1199..7827, 1184..6598) * 2188..5616', async () => { - const returnData = await callFallback( - ecMul, - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f630644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000' - ); - await expect(returnData).to.be.equal( - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe3163511ddc1c3f25d396745388200081287b3fd1472d8339d5fecb2eae0830451' - ); - }); - - it('128 bytes: (1, 3) * 9', async () => { - const call = callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(call).to.be.reverted; - }); - - it('128 bytes: (1, 3) * 21888242871839275222246405745257275088548364400416034343698204186575808495617', async () => { - const call = callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000330644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(call).to.be.reverted; - }); - - it('128 bytes: (1, 2) * 340282366920938463463374607431768211456', async () => { - const returnData = await callFallback( - ecMul, - '0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000100000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x13b8fec4a1eb2c7e3ccc07061ad516277c3bbe57bd4a302012b58a517f6437a4224d978b5763831dff16ce9b2c42222684835fedfc70ffec005789bb0c10de36' - ); - }); - - it('96 bytes: (1, 3) * 2', async () => { - const call = callFallback( - ecMul, - '0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000002' - ); - await expect(call).to.be.reverted; - }); - - it('128 bytes: (1, 3) * 1', async () => { - const call = callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(call).to.be.reverted; - }); - - it('96 bytes: (1, 2) * 115792089237316195423570985008687907853269984665640564039457584007913129639935', async () => { - const returnData = await callFallback( - ecMul, - '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - ); - await expect(returnData).to.be.equal( - '0x2f588cffe99db877a4434b598ab28f81e0522910ea52b45f0adaa772b2d5d35212f42fa8fd34fb1b33d8c6a718b6590198389b26fc9d8808d971f8b009777a97' - ); - }); - - it('128 bytes: (1, 2) * 21888242871839275222246405745257275088548364400416034343698204186575808495617', async () => { - const returnData = await callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000230644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - }); - - it('128 bytes: (1, 2) * 2', async () => { - const returnData = await callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4' - ); - }); - - // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) - // * - // 340282366920938463463374607431768211456 - it('80 bytes: (1199..7827, 1184..6598) * 340282366920938463463374607431768211456', async () => { - const returnData = await callFallback( - ecMul, - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000100000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x1051acb0700ec6d42a88215852d582efbaef31529b6fcbc3277b5c1b300f5cf0135b2394bb45ab04b8bd7611bd2dfe1de6a4e6e2ccea1ea1955f577cd66af85b' - ); - }); - - // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) - // * - // 0 - it('96 bytes: (1199..7827, 1184..6598) * 0', async () => { - const returnData = await callFallback( - ecMul, - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - }); - - it('96 bytes: (1, 3) * 9', async () => { - const call = callFallback( - ecMul, - '0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000009' - ); - await expect(call).to.be.reverted; - }); - - // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) - // * - // 115792089237316195423570985008687907853269984665640564039457584007913129639935 - it('96 bytes: (1, 3) * 9', async () => { - const returnData = await callFallback( - ecMul, - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' - ); - await expect(returnData).to.be.equal( - '0x2cde5879ba6f13c0b5aa4ef627f159a3347df9722efce88a9afbb20b763b4c411aa7e43076f6aee272755a7f9b84832e71559ba0d2e0b17d5f9f01755e5b0d11' - ); - }); - - it('96 bytes: (1, 3) * 115792089237316195423570985008687907853269984665640564039457584007913129639935', async () => { - const call = callFallback( - ecMul, - '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(call).to.be.reverted; - }); - - // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) - // * - // 0 - it('64 bytes: (1199..7827, 1184..6598) * 0', async () => { - const returnData = await callFallback( - ecMul, - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - }); - - it('128 bytes: (1, 2) * 115792089237316195423570985008687907853269984665640564039457584007913129639935', async () => { - const returnData = await callFallback( - ecMul, - '0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x2f588cffe99db877a4434b598ab28f81e0522910ea52b45f0adaa772b2d5d35212f42fa8fd34fb1b33d8c6a718b6590198389b26fc9d8808d971f8b009777a97' - ); - }); - - // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) - // * - // 1 - it('96 bytes: (1199..7827, 1184..6598) * 1', async () => { - const returnData = await callFallback( - ecMul, - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000001' - ); - await expect(returnData).to.be.equal( - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6' - ); - }); - - it('96 bytes: (1, 2) * 9', async () => { - const returnData = await callFallback( - ecMul, - '0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009' - ); - await expect(returnData).to.be.equal( - '0x039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98' - ); - }); - - it('96 bytes: (1, 2) * 21888242871839275222246405745257275088548364400416034343698204186575808495617', async () => { - const returnData = await callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000230644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - }); - - it('80 bytes: (1, 3) * 340282366920938463463374607431768211456', async () => { - const call = callFallback( - ecMul, - '0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000100000000000000000000000000000000' - ); - await expect(call).to.be.reverted; - }); - - it('80 bytes: (1, 3) * 2', async () => { - const call = callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(call).to.be.reverted; - }); - - it('96 bytes: (1, 3) * 21888242871839275222246405745257275088548364400416034343698204186575808495616', async () => { - const call = callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000330644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000' - ); - await expect(call).to.be.reverted; - }); - - // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) - // * - // 2 - it('96 bytes: (1199..7827, 1184..6598) * 2', async () => { - const returnData = await callFallback( - ecMul, - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000002' - ); - await expect(returnData).to.be.equal( - '0x03d64e49ebb3c56c99e0769c1833879c9b86ead23945e1e7477cbd057e961c500d6840b39f8c2fefe0eced3e7d210b830f50831e756f1cc9039af65dc292e6d0' - ); - }); - - it('128 bytes: (1, 2) * 9', async () => { - const returnData = await callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98' - ); - }); - - it('96 bytes: (1, 3) * 0', async () => { - const call = callFallback( - ecMul, - '0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(call).to.be.reverted; - }); - - // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) - // * - // 21888242871839275222246405745257275088548364400416034343698204186575808495617 - it('96 bytes: (1199..7827, 1184..6598) * 2188..5617', async () => { - const returnData = await callFallback( - ecMul, - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f630644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - }); - - // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) - // * - // 9 - it('96 bytes: (1199..7827, 1184..6598) * 9', async () => { - const returnData = await callFallback( - ecMul, - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000009' - ); - await expect(returnData).to.be.equal( - '0x1dbad7d39dbc56379f78fac1bca147dc8e66de1b9d183c7b167351bfe0aeab742cd757d51289cd8dbd0acf9e673ad67d0f0a89f912af47ed1be53664f5692575' - ); - }); - - it('96 bytes: (1, 2) * 21888242871839275222246405745257275088548364400416034343698204186575808495616', async () => { - const returnData = await callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000230644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000' - ); - await expect(returnData).to.be.equal( - '0x000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45' - ); - }); - - // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) - // * - // 2 - it('128 bytes: (1199..7827, 1184..6598) * 2', async () => { - const returnData = await callFallback( - ecMul, - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x03d64e49ebb3c56c99e0769c1833879c9b86ead23945e1e7477cbd057e961c500d6840b39f8c2fefe0eced3e7d210b830f50831e756f1cc9039af65dc292e6d0' - ); - }); - - it('128 bytes: (1, 2) * 340282366920938463463374607431768211456', async () => { - const returnData = await callFallback( - ecMul, - '0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x13b8fec4a1eb2c7e3ccc07061ad516277c3bbe57bd4a302012b58a517f6437a4224d978b5763831dff16ce9b2c42222684835fedfc70ffec005789bb0c10de36' - ); - }); - - // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) - // * - // 115792089237316195423570985008687907853269984665640564039457584007913129639935 - it('128 bytes: (1199..7827, 1184..6598) * 1157..9935', async () => { - const returnData = await callFallback( - ecMul, - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x2cde5879ba6f13c0b5aa4ef627f159a3347df9722efce88a9afbb20b763b4c411aa7e43076f6aee272755a7f9b84832e71559ba0d2e0b17d5f9f01755e5b0d11' - ); - }); - - // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) - // * - // 21888242871839275222246405745257275088548364400416034343698204186575808495617 - it('128 bytes: (1199..7827, 1184..6598) * 2188..5617', async () => { - const returnData = await callFallback( - ecMul, - '0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f630644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010000000000000000000000000000000000000000000000000000000000000000' - ); - await expect(returnData).to.be.equal( - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' - ); - }); +import { expect } from "chai"; +import type { Contract } from "zksync-web3"; +import { callFallback, deployContractYul } from "./shared/utils"; + +describe("EcMul tests", function () { + let ecMul: Contract; + + before(async () => { + ecMul = await deployContractYul("EcMul", "precompiles"); + }); + + describe("Ethereum tests", function () { + it("128 bytes: (1, 3) * 0", async () => { + const call = callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(call).to.be.reverted; }); + + it("128 bytes: (1, 2) * 21888242871839275222246405745257275088548364400416034343698204186575808495616", async () => { + const returnData = await callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000230644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000000000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45" + ); + }); + + it("64 bytes: (1, 3) * 0", async () => { + const call = callFallback( + ecMul, + "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003" + ); + await expect(call).to.be.reverted; + }); + + it("128 bytes: (1, 3) * 21888242871839275222246405745257275088548364400416034343698204186575808495616", async () => { + const call = callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000330644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000000000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(call).to.be.reverted; + }); + + it("96 bytes: (1, 3) * 21888242871839275222246405745257275088548364400416034343698204186575808495617", async () => { + const call = callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000330644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001" + ); + await expect(call).to.be.reverted; + }); + + it("96 bytes: (1, 3) * 1", async () => { + const call = callFallback( + ecMul, + "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001" + ); + await expect(call).to.be.reverted; + }); + + // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) + // * + // 21888242871839275222246405745257275088548364400416034343698204186575808495616 + it("96 bytes: (1199..7827, 1184..6598) * 2188..5616", async () => { + const returnData = await callFallback( + ecMul, + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f630644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000" + ); + await expect(returnData).to.be.equal( + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe3163511ddc1c3f25d396745388200081287b3fd1472d8339d5fecb2eae0830451" + ); + }); + + it("128 bytes: (1, 3) * 9", async () => { + const call = callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(call).to.be.reverted; + }); + + it("128 bytes: (1, 3) * 21888242871839275222246405745257275088548364400416034343698204186575808495617", async () => { + const call = callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000330644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(call).to.be.reverted; + }); + + it("128 bytes: (1, 2) * 340282366920938463463374607431768211456", async () => { + const returnData = await callFallback( + ecMul, + "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000100000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x13b8fec4a1eb2c7e3ccc07061ad516277c3bbe57bd4a302012b58a517f6437a4224d978b5763831dff16ce9b2c42222684835fedfc70ffec005789bb0c10de36" + ); + }); + + it("96 bytes: (1, 3) * 2", async () => { + const call = callFallback( + ecMul, + "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000002" + ); + await expect(call).to.be.reverted; + }); + + it("128 bytes: (1, 3) * 1", async () => { + const call = callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(call).to.be.reverted; + }); + + it("96 bytes: (1, 2) * 115792089237316195423570985008687907853269984665640564039457584007913129639935", async () => { + const returnData = await callFallback( + ecMul, + "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + ); + await expect(returnData).to.be.equal( + "0x2f588cffe99db877a4434b598ab28f81e0522910ea52b45f0adaa772b2d5d35212f42fa8fd34fb1b33d8c6a718b6590198389b26fc9d8808d971f8b009777a97" + ); + }); + + it("128 bytes: (1, 2) * 21888242871839275222246405745257275088548364400416034343698204186575808495617", async () => { + const returnData = await callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000230644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + }); + + it("128 bytes: (1, 2) * 2", async () => { + const returnData = await callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4" + ); + }); + + // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) + // * + // 340282366920938463463374607431768211456 + it("80 bytes: (1199..7827, 1184..6598) * 340282366920938463463374607431768211456", async () => { + const returnData = await callFallback( + ecMul, + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000100000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x1051acb0700ec6d42a88215852d582efbaef31529b6fcbc3277b5c1b300f5cf0135b2394bb45ab04b8bd7611bd2dfe1de6a4e6e2ccea1ea1955f577cd66af85b" + ); + }); + + // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) + // * + // 0 + it("96 bytes: (1199..7827, 1184..6598) * 0", async () => { + const returnData = await callFallback( + ecMul, + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + }); + + it("96 bytes: (1, 3) * 9", async () => { + const call = callFallback( + ecMul, + "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000009" + ); + await expect(call).to.be.reverted; + }); + + // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) + // * + // 115792089237316195423570985008687907853269984665640564039457584007913129639935 + it("96 bytes: (1, 3) * 9", async () => { + const returnData = await callFallback( + ecMul, + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + ); + await expect(returnData).to.be.equal( + "0x2cde5879ba6f13c0b5aa4ef627f159a3347df9722efce88a9afbb20b763b4c411aa7e43076f6aee272755a7f9b84832e71559ba0d2e0b17d5f9f01755e5b0d11" + ); + }); + + it("96 bytes: (1, 3) * 115792089237316195423570985008687907853269984665640564039457584007913129639935", async () => { + const call = callFallback( + ecMul, + "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(call).to.be.reverted; + }); + + // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) + // * + // 0 + it("64 bytes: (1199..7827, 1184..6598) * 0", async () => { + const returnData = await callFallback( + ecMul, + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + }); + + it("128 bytes: (1, 2) * 115792089237316195423570985008687907853269984665640564039457584007913129639935", async () => { + const returnData = await callFallback( + ecMul, + "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x2f588cffe99db877a4434b598ab28f81e0522910ea52b45f0adaa772b2d5d35212f42fa8fd34fb1b33d8c6a718b6590198389b26fc9d8808d971f8b009777a97" + ); + }); + + // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) + // * + // 1 + it("96 bytes: (1199..7827, 1184..6598) * 1", async () => { + const returnData = await callFallback( + ecMul, + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000001" + ); + await expect(returnData).to.be.equal( + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6" + ); + }); + + it("96 bytes: (1, 2) * 9", async () => { + const returnData = await callFallback( + ecMul, + "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009" + ); + await expect(returnData).to.be.equal( + "0x039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98" + ); + }); + + it("96 bytes: (1, 2) * 21888242871839275222246405745257275088548364400416034343698204186575808495617", async () => { + const returnData = await callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000230644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + }); + + it("80 bytes: (1, 3) * 340282366920938463463374607431768211456", async () => { + const call = callFallback( + ecMul, + "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000100000000000000000000000000000000" + ); + await expect(call).to.be.reverted; + }); + + it("80 bytes: (1, 3) * 2", async () => { + const call = callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(call).to.be.reverted; + }); + + it("96 bytes: (1, 3) * 21888242871839275222246405745257275088548364400416034343698204186575808495616", async () => { + const call = callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000330644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000" + ); + await expect(call).to.be.reverted; + }); + + // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) + // * + // 2 + it("96 bytes: (1199..7827, 1184..6598) * 2", async () => { + const returnData = await callFallback( + ecMul, + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000002" + ); + await expect(returnData).to.be.equal( + "0x03d64e49ebb3c56c99e0769c1833879c9b86ead23945e1e7477cbd057e961c500d6840b39f8c2fefe0eced3e7d210b830f50831e756f1cc9039af65dc292e6d0" + ); + }); + + it("128 bytes: (1, 2) * 9", async () => { + const returnData = await callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98" + ); + }); + + it("96 bytes: (1, 3) * 0", async () => { + const call = callFallback( + ecMul, + "0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(call).to.be.reverted; + }); + + // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) + // * + // 21888242871839275222246405745257275088548364400416034343698204186575808495617 + it("96 bytes: (1199..7827, 1184..6598) * 2188..5617", async () => { + const returnData = await callFallback( + ecMul, + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f630644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + }); + + // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) + // * + // 9 + it("96 bytes: (1199..7827, 1184..6598) * 9", async () => { + const returnData = await callFallback( + ecMul, + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000009" + ); + await expect(returnData).to.be.equal( + "0x1dbad7d39dbc56379f78fac1bca147dc8e66de1b9d183c7b167351bfe0aeab742cd757d51289cd8dbd0acf9e673ad67d0f0a89f912af47ed1be53664f5692575" + ); + }); + + it("96 bytes: (1, 2) * 21888242871839275222246405745257275088548364400416034343698204186575808495616", async () => { + const returnData = await callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000230644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000" + ); + await expect(returnData).to.be.equal( + "0x000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45" + ); + }); + + // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) + // * + // 2 + it("128 bytes: (1199..7827, 1184..6598) * 2", async () => { + const returnData = await callFallback( + ecMul, + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x03d64e49ebb3c56c99e0769c1833879c9b86ead23945e1e7477cbd057e961c500d6840b39f8c2fefe0eced3e7d210b830f50831e756f1cc9039af65dc292e6d0" + ); + }); + + it("128 bytes: (1, 2) * 340282366920938463463374607431768211456", async () => { + const returnData = await callFallback( + ecMul, + "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x13b8fec4a1eb2c7e3ccc07061ad516277c3bbe57bd4a302012b58a517f6437a4224d978b5763831dff16ce9b2c42222684835fedfc70ffec005789bb0c10de36" + ); + }); + + // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) + // * + // 115792089237316195423570985008687907853269984665640564039457584007913129639935 + it("128 bytes: (1199..7827, 1184..6598) * 1157..9935", async () => { + const returnData = await callFallback( + ecMul, + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x2cde5879ba6f13c0b5aa4ef627f159a3347df9722efce88a9afbb20b763b4c411aa7e43076f6aee272755a7f9b84832e71559ba0d2e0b17d5f9f01755e5b0d11" + ); + }); + + // (11999875504842010600789954262886096740416429265635183817701593963271973497827, 11843594000332171325303933275547366297934113019079887694534126289021216356598) + // * + // 21888242871839275222246405745257275088548364400416034343698204186575808495617 + it("128 bytes: (1199..7827, 1184..6598) * 2188..5617", async () => { + const returnData = await callFallback( + ecMul, + "0x1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f630644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010000000000000000000000000000000000000000000000000000000000000000" + ); + await expect(returnData).to.be.equal( + "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ); + }); + }); }); diff --git a/test/EmptyContract.spec.ts b/test/EmptyContract.spec.ts index 9c0291bc684..a56a454fcf0 100644 --- a/test/EmptyContract.spec.ts +++ b/test/EmptyContract.spec.ts @@ -1,44 +1,44 @@ -import { expect } from 'chai'; -import { ethers } from 'hardhat'; -import { Wallet } from 'zksync-web3'; -import { EmptyContract } from '../typechain-types'; -import { deployContract, getWallets, provider } from './shared/utils'; +import { expect } from "chai"; +import { ethers } from "hardhat"; +import type { Wallet } from "zksync-web3"; +import type { EmptyContract } from "../typechain-types"; +import { deployContract, getWallets, provider } from "./shared/utils"; -describe('EmptyContract tests', function () { - let wallet: Wallet; - let emptyContract: EmptyContract; +describe("EmptyContract tests", function () { + let wallet: Wallet; + let emptyContract: EmptyContract; - before(async () => { - wallet = getWallets()[0]; - emptyContract = (await deployContract('EmptyContract')) as EmptyContract; - }); + before(async () => { + wallet = getWallets()[0]; + emptyContract = (await deployContract("EmptyContract")) as EmptyContract; + }); - it('zero value', async () => { - const tx = { - from: wallet.address, - to: emptyContract.address, - value: 0, - data: '0x1234567890deadbeef1234567890' - }; - expect(await provider.call(tx)).to.be.eq('0x'); - }); + it("zero value", async () => { + const tx = { + from: wallet.address, + to: emptyContract.address, + value: 0, + data: "0x1234567890deadbeef1234567890", + }; + expect(await provider.call(tx)).to.be.eq("0x"); + }); - it('non-zero value', async () => { - const tx = { - from: wallet.address, - to: emptyContract.address, - value: ethers.utils.parseEther('1.0'), - data: '0x1234567890deadbeef1234567890' - }; - expect(await provider.call(tx)).to.be.eq('0x'); - }); + it("non-zero value", async () => { + const tx = { + from: wallet.address, + to: emptyContract.address, + value: ethers.utils.parseEther("1.0"), + data: "0x1234567890deadbeef1234567890", + }; + expect(await provider.call(tx)).to.be.eq("0x"); + }); - it('empty calldata', async () => { - const tx = { - from: wallet.address, - to: emptyContract.address, - data: '' - }; - expect(await provider.call(tx)).to.be.eq('0x'); - }); + it("empty calldata", async () => { + const tx = { + from: wallet.address, + to: emptyContract.address, + data: "", + }; + expect(await provider.call(tx)).to.be.eq("0x"); + }); }); diff --git a/test/EventWriter.spec.ts b/test/EventWriter.spec.ts index 46a6fc56999..ab3e39429ce 100644 --- a/test/EventWriter.spec.ts +++ b/test/EventWriter.spec.ts @@ -1,82 +1,81 @@ -import { expect } from 'chai'; -import { Contract, Wallet } from 'zksync-web3'; -import { Language } from '../scripts/constants'; -import { readYulBytecode } from '../scripts/utils'; -import { EventWriterTest } from '../typechain-types'; -import { EVENT_WRITER_CONTRACT_ADDRESS } from './shared/constants'; -import { deployContract, getCode, getWallets, setCode } from './shared/utils'; +import { expect } from "chai"; +import type { Wallet } from "zksync-web3"; +import { Contract } from "zksync-web3"; +import { Language } from "../scripts/constants"; +import { readYulBytecode } from "../scripts/utils"; +import type { EventWriterTest } from "../typechain-types"; +import { EVENT_WRITER_CONTRACT_ADDRESS } from "./shared/constants"; +import { deployContract, getCode, getWallets, setCode } from "./shared/utils"; -describe('EventWriter tests', function () { - let wallet: Wallet; - let eventWriter: Contract; - let eventWriterTest: EventWriterTest; +describe("EventWriter tests", function () { + let wallet: Wallet; + let eventWriter: Contract; + let eventWriterTest: EventWriterTest; - let _eventWriterCode: string; + let _eventWriterCode: string; - before(async () => { - _eventWriterCode = await getCode(EVENT_WRITER_CONTRACT_ADDRESS); - const eventWriterTestCode = readYulBytecode({ - codeName: 'EventWriter', - path: '', - lang: Language.Yul, - address: ethers.constants.AddressZero - }); - await setCode(EVENT_WRITER_CONTRACT_ADDRESS, eventWriterTestCode); - - wallet = (await getWallets())[0]; - eventWriter = new Contract(EVENT_WRITER_CONTRACT_ADDRESS, [], wallet); - eventWriterTest = (await deployContract('EventWriterTest')) as EventWriterTest; + before(async () => { + _eventWriterCode = await getCode(EVENT_WRITER_CONTRACT_ADDRESS); + const eventWriterTestCode = readYulBytecode({ + codeName: "EventWriter", + path: "", + lang: Language.Yul, + address: ethers.constants.AddressZero, }); + await setCode(EVENT_WRITER_CONTRACT_ADDRESS, eventWriterTestCode); - after(async () => { - await setCode(EVENT_WRITER_CONTRACT_ADDRESS, _eventWriterCode); - }); + wallet = (await getWallets())[0]; + eventWriter = new Contract(EVENT_WRITER_CONTRACT_ADDRESS, [], wallet); + eventWriterTest = (await deployContract("EventWriterTest")) as EventWriterTest; + }); - it('non system call failed', async () => { - await expect(eventWriter.fallback({ data: '0x' })).to.be.reverted; - }); + after(async () => { + await setCode(EVENT_WRITER_CONTRACT_ADDRESS, _eventWriterCode); + }); - // TODO: anonymous events doesn't work - it.skip('zero topics', async () => { - console.log((await (await eventWriterTest.zeroTopics('0x')).wait()).events); - await expect(eventWriterTest.zeroTopics('0x')).to.emit(eventWriterTest, 'ZeroTopics').withArgs('0x'); - }); + it("non system call failed", async () => { + await expect(eventWriter.fallback({ data: "0x" })).to.be.reverted; + }); - it('one topic', async () => { - await expect(eventWriterTest.oneTopic('0xdeadbeef')) - .to.emit(eventWriterTest, 'OneTopic') - .withArgs('0xdeadbeef'); - }); + // TODO: anonymous events doesn't work + it.skip("zero topics", async () => { + console.log((await (await eventWriterTest.zeroTopics("0x")).wait()).events); + await expect(eventWriterTest.zeroTopics("0x")).to.emit(eventWriterTest, "ZeroTopics").withArgs("0x"); + }); - it('two topics', async () => { - await expect( - eventWriterTest.twoTopics('0x1278378123784223232874782378478237848723784782378423747237848723', '0xabcd') - ) - .to.emit(eventWriterTest, 'TwoTopics') - .withArgs('0x1278378123784223232874782378478237848723784782378423747237848723', '0xabcd'); - }); + it("one topic", async () => { + await expect(eventWriterTest.oneTopic("0xdeadbeef")).to.emit(eventWriterTest, "OneTopic").withArgs("0xdeadbeef"); + }); - it('three topics', async () => { - await expect(eventWriterTest.threeTopics(0, 1133, '0x')) - .to.emit(eventWriterTest, 'ThreeTopics') - .withArgs(0, 1133, '0x'); - }); + it("two topics", async () => { + await expect( + eventWriterTest.twoTopics("0x1278378123784223232874782378478237848723784782378423747237848723", "0xabcd") + ) + .to.emit(eventWriterTest, "TwoTopics") + .withArgs("0x1278378123784223232874782378478237848723784782378423747237848723", "0xabcd"); + }); - it('four topics', async () => { - await expect( - eventWriterTest.fourTopics( - '0x1234567890', - 0, - 22, - '0x2828383489438934898934893894893895348915893489589348958349589348958934859348958934858394589348958934854385838954893489' - ) - ) - .to.emit(eventWriterTest, 'FourTopics') - .withArgs( - '0x1234567890', - 0, - 22, - '0x2828383489438934898934893894893895348915893489589348958349589348958934859348958934858394589348958934854385838954893489' - ); - }); + it("three topics", async () => { + await expect(eventWriterTest.threeTopics(0, 1133, "0x")) + .to.emit(eventWriterTest, "ThreeTopics") + .withArgs(0, 1133, "0x"); + }); + + it("four topics", async () => { + await expect( + eventWriterTest.fourTopics( + "0x1234567890", + 0, + 22, + "0x2828383489438934898934893894893895348915893489589348958349589348958934859348958934858394589348958934854385838954893489" + ) + ) + .to.emit(eventWriterTest, "FourTopics") + .withArgs( + "0x1234567890", + 0, + 22, + "0x2828383489438934898934893894893895348915893489589348958349589348958934859348958934858394589348958934854385838954893489" + ); + }); }); diff --git a/test/ImmutableSimulator.spec.ts b/test/ImmutableSimulator.spec.ts index 64ca735c95a..022e529a38b 100644 --- a/test/ImmutableSimulator.spec.ts +++ b/test/ImmutableSimulator.spec.ts @@ -1,61 +1,59 @@ -import { expect } from 'chai'; -import { ethers, network } from 'hardhat'; -import { ImmutableSimulator } from '../typechain-types'; -import { DEPLOYER_SYSTEM_CONTRACT_ADDRESS } from './shared/constants'; -import { deployContract } from './shared/utils'; - -describe('ImmutableSimulator tests', function () { - let immutableSimulator: ImmutableSimulator; - - const RANDOM_ADDRESS = '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'; - const IMMUTABLES_DATA = [ - { - index: 0, - value: '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' - }, - { - index: 23, - value: '0x0000000000000000000000000000000000000000000000000000000000000111' - } - ]; - - before(async () => { - immutableSimulator = (await deployContract('ImmutableSimulator')) as ImmutableSimulator; +import { expect } from "chai"; +import { ethers, network } from "hardhat"; +import type { ImmutableSimulator } from "../typechain-types"; +import { DEPLOYER_SYSTEM_CONTRACT_ADDRESS } from "./shared/constants"; +import { deployContract } from "./shared/utils"; + +describe("ImmutableSimulator tests", function () { + let immutableSimulator: ImmutableSimulator; + + const RANDOM_ADDRESS = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; + const IMMUTABLES_DATA = [ + { + index: 0, + value: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", + }, + { + index: 23, + value: "0x0000000000000000000000000000000000000000000000000000000000000111", + }, + ]; + + before(async () => { + immutableSimulator = (await deployContract("ImmutableSimulator")) as ImmutableSimulator; + }); + + 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" + ); }); - 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' - ); - }); - - it('successfully set', async () => { - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS] - }); - - const deployer_account = await ethers.getSigner(DEPLOYER_SYSTEM_CONTRACT_ADDRESS); - - await immutableSimulator.connect(deployer_account).setImmutables(RANDOM_ADDRESS, IMMUTABLES_DATA); - - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS] - }); - - for (const immutable of IMMUTABLES_DATA) { - expect(await immutableSimulator.getImmutable(RANDOM_ADDRESS, immutable.index)).to.be.eq( - immutable.value - ); - } - }); + it("successfully set", async () => { + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS], + }); + + const deployer_account = await ethers.getSigner(DEPLOYER_SYSTEM_CONTRACT_ADDRESS); + + await immutableSimulator.connect(deployer_account).setImmutables(RANDOM_ADDRESS, IMMUTABLES_DATA); + + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS], + }); + + for (const immutable of IMMUTABLES_DATA) { + expect(await immutableSimulator.getImmutable(RANDOM_ADDRESS, immutable.index)).to.be.eq(immutable.value); + } }); + }); - describe('getImmutable', function () { - it('zero', async () => { - expect(await immutableSimulator.getImmutable(RANDOM_ADDRESS, 333)).to.be.eq(ethers.constants.HashZero); - }); + describe("getImmutable", function () { + it("zero", async () => { + expect(await immutableSimulator.getImmutable(RANDOM_ADDRESS, 333)).to.be.eq(ethers.constants.HashZero); }); + }); }); diff --git a/test/KnownCodesStorage.spec.ts b/test/KnownCodesStorage.spec.ts index 49d4b3742a9..a9769463a2e 100644 --- a/test/KnownCodesStorage.spec.ts +++ b/test/KnownCodesStorage.spec.ts @@ -1,156 +1,156 @@ -import { expect } from 'chai'; -import { ethers, network } from 'hardhat'; -import { Wallet } from 'zksync-web3'; -import { KnownCodesStorage, MockL1Messenger, MockL1Messenger__factory } from '../typechain-types'; +import { expect } from "chai"; +import { ethers, network } from "hardhat"; +import type { Wallet } from "zksync-web3"; +import type { KnownCodesStorage, MockL1Messenger } from "../typechain-types"; +import { MockL1Messenger__factory } from "../typechain-types"; import { - BOOTLOADER_FORMAL_ADDRESS, - COMPRESSOR_CONTRACT_ADDRESS, - L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS -} from './shared/constants'; -import { deployContract, getCode, getWallets, loadArtifact, setCode } from './shared/utils'; - -describe('KnownCodesStorage tests', function () { - let wallet: Wallet; - let knownCodesStorage: KnownCodesStorage; - let mockL1Messenger: MockL1Messenger; - let bootloaderAccount: ethers.Signer; - let compressorAccount: ethers.Signer; - - let _l1MessengerCode: string; - - const BYTECODE_HASH_1 = '0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF'; - const BYTECODE_HASH_2 = '0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEE1'; - const BYTECODE_HASH_3 = '0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEE2'; - const BYTECODE_HASH_4 = '0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEE3'; - const INCORRECTLY_FORMATTED_HASH = '0x0120FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF'; - const INVALID_LENGTH_HASH = '0x0100FFFEDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF'; - - before(async () => { - wallet = (await getWallets())[0]; - knownCodesStorage = (await deployContract('KnownCodesStorage')) as KnownCodesStorage; - - _l1MessengerCode = await getCode(L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS); - const l1MessengerArtifact = await loadArtifact('MockL1Messenger'); - await setCode(L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, l1MessengerArtifact.bytecode); - mockL1Messenger = MockL1Messenger__factory.connect(L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, wallet); - - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [COMPRESSOR_CONTRACT_ADDRESS] - }); - bootloaderAccount = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); - compressorAccount = await ethers.getSigner(COMPRESSOR_CONTRACT_ADDRESS); - }); - - after(async () => { - await setCode(L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, _l1MessengerCode); - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [BOOTLOADER_FORMAL_ADDRESS] - }); - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [COMPRESSOR_CONTRACT_ADDRESS] - }); - }); - - 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' - ); - }); - - it('incorrectly fomatted bytecode hash failed to call', async () => { - await expect( - knownCodesStorage.connect(compressorAccount).markBytecodeAsPublished(INCORRECTLY_FORMATTED_HASH) - ).to.be.revertedWith('Incorrectly formatted bytecodeHash'); - }); - - 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'); - }); - - it('successfuly marked', async () => { - await expect(knownCodesStorage.connect(compressorAccount).markBytecodeAsPublished(BYTECODE_HASH_1)) - .to.emit(knownCodesStorage, 'MarkedAsKnown') - .withArgs(BYTECODE_HASH_1.toLowerCase(), false) - .not.emit(mockL1Messenger, 'MockBytecodeL1Published'); - expect(await knownCodesStorage.getMarker(BYTECODE_HASH_1)).to.be.eq(1); - }); - - it('not marked second time', async () => { - await expect( - knownCodesStorage.connect(compressorAccount).markBytecodeAsPublished(BYTECODE_HASH_1) - ).to.not.emit(knownCodesStorage, 'MarkedAsKnown'); - }); - }); - - 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'); - }); - - it('incorrectly fomatted bytecode hash failed to call', async () => { - await expect( - knownCodesStorage - .connect(bootloaderAccount) - .markFactoryDeps(true, [BYTECODE_HASH_2, INCORRECTLY_FORMATTED_HASH]) - ).to.be.revertedWith('Incorrectly formatted bytecodeHash'); - }); - - 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'); - }); - - it('successfuly marked', async () => { - await expect( - knownCodesStorage.connect(bootloaderAccount).markFactoryDeps(false, [BYTECODE_HASH_2, BYTECODE_HASH_3]) - ) - .to.emit(knownCodesStorage, 'MarkedAsKnown') - .withArgs(BYTECODE_HASH_2.toLowerCase(), false) - .emit(knownCodesStorage, 'MarkedAsKnown') - .withArgs(BYTECODE_HASH_3.toLowerCase(), false) - .not.emit(mockL1Messenger, 'MockBytecodeL1Published'); - expect(await knownCodesStorage.getMarker(BYTECODE_HASH_2)).to.be.eq(1); - expect(await knownCodesStorage.getMarker(BYTECODE_HASH_3)).to.be.eq(1); - }); - - it('not marked second time', async () => { - await expect( - knownCodesStorage.connect(bootloaderAccount).markFactoryDeps(false, [BYTECODE_HASH_2, BYTECODE_HASH_3]) - ).to.not.emit(knownCodesStorage, 'MarkedAsKnown'); - }); - - it('sent to l1', async () => { - await expect(knownCodesStorage.connect(bootloaderAccount).markFactoryDeps(true, [BYTECODE_HASH_4])) - .to.emit(knownCodesStorage, 'MarkedAsKnown') - .withArgs(BYTECODE_HASH_4.toLowerCase(), true) - .emit(mockL1Messenger, 'MockBytecodeL1Published') - .withArgs(BYTECODE_HASH_4.toLowerCase()); - expect(await knownCodesStorage.getMarker(BYTECODE_HASH_4)).to.be.eq(1); - }); - }); - - describe('getMarker', function () { - it('not known', async () => { - expect(await knownCodesStorage.getMarker(INCORRECTLY_FORMATTED_HASH)).to.be.eq(0); - }); - - it('known', async () => { - expect(await knownCodesStorage.getMarker(BYTECODE_HASH_1)).to.be.eq(1); - }); + BOOTLOADER_FORMAL_ADDRESS, + COMPRESSOR_CONTRACT_ADDRESS, + L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, +} from "./shared/constants"; +import { deployContract, getCode, getWallets, loadArtifact, setCode } from "./shared/utils"; + +describe("KnownCodesStorage tests", function () { + let wallet: Wallet; + let knownCodesStorage: KnownCodesStorage; + let mockL1Messenger: MockL1Messenger; + let bootloaderAccount: ethers.Signer; + let compressorAccount: ethers.Signer; + + let _l1MessengerCode: string; + + const BYTECODE_HASH_1 = "0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"; + const BYTECODE_HASH_2 = "0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEE1"; + const BYTECODE_HASH_3 = "0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEE2"; + const BYTECODE_HASH_4 = "0x0100FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEE3"; + const INCORRECTLY_FORMATTED_HASH = "0x0120FFFFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"; + const INVALID_LENGTH_HASH = "0x0100FFFEDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"; + + before(async () => { + wallet = (await getWallets())[0]; + knownCodesStorage = (await deployContract("KnownCodesStorage")) as KnownCodesStorage; + + _l1MessengerCode = await getCode(L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS); + const l1MessengerArtifact = await loadArtifact("MockL1Messenger"); + await setCode(L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, l1MessengerArtifact.bytecode); + mockL1Messenger = MockL1Messenger__factory.connect(L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, wallet); + + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], }); + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [COMPRESSOR_CONTRACT_ADDRESS], + }); + bootloaderAccount = await ethers.getSigner(BOOTLOADER_FORMAL_ADDRESS); + compressorAccount = await ethers.getSigner(COMPRESSOR_CONTRACT_ADDRESS); + }); + + after(async () => { + await setCode(L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS, _l1MessengerCode); + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [BOOTLOADER_FORMAL_ADDRESS], + }); + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [COMPRESSOR_CONTRACT_ADDRESS], + }); + }); + + 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" + ); + }); + + it("incorrectly fomatted bytecode hash failed to call", async () => { + await expect( + knownCodesStorage.connect(compressorAccount).markBytecodeAsPublished(INCORRECTLY_FORMATTED_HASH) + ).to.be.revertedWith("Incorrectly formatted bytecodeHash"); + }); + + 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"); + }); + + it("successfuly marked", async () => { + await expect(knownCodesStorage.connect(compressorAccount).markBytecodeAsPublished(BYTECODE_HASH_1)) + .to.emit(knownCodesStorage, "MarkedAsKnown") + .withArgs(BYTECODE_HASH_1.toLowerCase(), false) + .not.emit(mockL1Messenger, "MockBytecodeL1Published"); + expect(await knownCodesStorage.getMarker(BYTECODE_HASH_1)).to.be.eq(1); + }); + + it("not marked second time", async () => { + await expect(knownCodesStorage.connect(compressorAccount).markBytecodeAsPublished(BYTECODE_HASH_1)).to.not.emit( + knownCodesStorage, + "MarkedAsKnown" + ); + }); + }); + + 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" + ); + }); + + it("incorrectly fomatted bytecode hash failed to call", async () => { + await expect( + knownCodesStorage + .connect(bootloaderAccount) + .markFactoryDeps(true, [BYTECODE_HASH_2, INCORRECTLY_FORMATTED_HASH]) + ).to.be.revertedWith("Incorrectly formatted bytecodeHash"); + }); + + 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"); + }); + + it("successfuly marked", async () => { + await expect( + knownCodesStorage.connect(bootloaderAccount).markFactoryDeps(false, [BYTECODE_HASH_2, BYTECODE_HASH_3]) + ) + .to.emit(knownCodesStorage, "MarkedAsKnown") + .withArgs(BYTECODE_HASH_2.toLowerCase(), false) + .emit(knownCodesStorage, "MarkedAsKnown") + .withArgs(BYTECODE_HASH_3.toLowerCase(), false) + .not.emit(mockL1Messenger, "MockBytecodeL1Published"); + expect(await knownCodesStorage.getMarker(BYTECODE_HASH_2)).to.be.eq(1); + expect(await knownCodesStorage.getMarker(BYTECODE_HASH_3)).to.be.eq(1); + }); + + it("not marked second time", async () => { + await expect( + knownCodesStorage.connect(bootloaderAccount).markFactoryDeps(false, [BYTECODE_HASH_2, BYTECODE_HASH_3]) + ).to.not.emit(knownCodesStorage, "MarkedAsKnown"); + }); + + it("sent to l1", async () => { + await expect(knownCodesStorage.connect(bootloaderAccount).markFactoryDeps(true, [BYTECODE_HASH_4])) + .to.emit(knownCodesStorage, "MarkedAsKnown") + .withArgs(BYTECODE_HASH_4.toLowerCase(), true) + .emit(mockL1Messenger, "MockBytecodeL1Published") + .withArgs(BYTECODE_HASH_4.toLowerCase()); + expect(await knownCodesStorage.getMarker(BYTECODE_HASH_4)).to.be.eq(1); + }); + }); + + describe("getMarker", function () { + it("not known", async () => { + expect(await knownCodesStorage.getMarker(INCORRECTLY_FORMATTED_HASH)).to.be.eq(0); + }); + + it("known", async () => { + expect(await knownCodesStorage.getMarker(BYTECODE_HASH_1)).to.be.eq(1); + }); + }); }); diff --git a/test/shared/constants.ts b/test/shared/constants.ts index 489259cb904..d46d5e4a987 100644 --- a/test/shared/constants.ts +++ b/test/shared/constants.ts @@ -1,14 +1,14 @@ -import { BigNumber } from 'ethers'; +import { BigNumber } from "ethers"; -export const BOOTLOADER_FORMAL_ADDRESS = '0x0000000000000000000000000000000000008001'; -export const NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS = '0x0000000000000000000000000000000000008003'; -export const KNOWN_CODE_STORAGE_CONTRACT_ADDRESS = '0x0000000000000000000000000000000000008004'; -export const DEPLOYER_SYSTEM_CONTRACT_ADDRESS = '0x0000000000000000000000000000000000008006'; -export const FORCE_DEPLOYER_ADDRESS = '0x0000000000000000000000000000000000008007'; -export const L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS = '0x0000000000000000000000000000000000008008'; -export const ETH_TOKEN_SYSTEM_CONTRACT_ADDRESS = '0x000000000000000000000000000000000000800a'; -export const EVENT_WRITER_CONTRACT_ADDRESS = '0x000000000000000000000000000000000000800d'; -export const COMPRESSOR_CONTRACT_ADDRESS = '0x000000000000000000000000000000000000800e'; -export const EMPTY_STRING_KECCAK = '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'; +export const BOOTLOADER_FORMAL_ADDRESS = "0x0000000000000000000000000000000000008001"; +export const NONCE_HOLDER_SYSTEM_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000008003"; +export const KNOWN_CODE_STORAGE_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000008004"; +export const DEPLOYER_SYSTEM_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000008006"; +export const FORCE_DEPLOYER_ADDRESS = "0x0000000000000000000000000000000000008007"; +export const L1_MESSENGER_SYSTEM_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000008008"; +export const ETH_TOKEN_SYSTEM_CONTRACT_ADDRESS = "0x000000000000000000000000000000000000800a"; +export const EVENT_WRITER_CONTRACT_ADDRESS = "0x000000000000000000000000000000000000800d"; +export const COMPRESSOR_CONTRACT_ADDRESS = "0x000000000000000000000000000000000000800e"; +export const EMPTY_STRING_KECCAK = "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; export const TWO_IN_256 = BigNumber.from(2).pow(256); diff --git a/test/shared/transactions.ts b/test/shared/transactions.ts index 8052b36dc04..73c4fcc216d 100644 --- a/test/shared/transactions.ts +++ b/test/shared/transactions.ts @@ -1,150 +1,150 @@ -import { BigNumberish, BytesLike, Transaction } from 'ethers'; -import * as zksync from 'zksync-web3'; +import type { BigNumberish, BytesLike, Transaction } from "ethers"; +import * as zksync from "zksync-web3"; // Interface encoding the transaction struct used for AA protocol export interface TransactionData { - txType: BigNumberish; - from: BigNumberish; - to: BigNumberish; - gasLimit: BigNumberish; - gasPerPubdataByteLimit: BigNumberish; - maxFeePerGas: BigNumberish; - maxPriorityFeePerGas: BigNumberish; - paymaster: BigNumberish; - nonce: BigNumberish; - value: BigNumberish; - // In the future, we might want to add some - // new fields to the struct. The `txData` struct - // is to be passed to account and any changes to its structure - // would mean a breaking change to these accounts. In order to prevent this, - // we should keep some fields as "reserved". - // It is also recommneded that their length is fixed, since - // it would allow easier proof integration (in case we will need - // some special circuit for preprocessing transactions). - reserved: [BigNumberish, BigNumberish, BigNumberish, BigNumberish]; - data: BytesLike; - signature: BytesLike; - factoryDeps: BytesLike[]; - paymasterInput: BytesLike; - // Reserved dynamic type for the future use-case. Using it should be avoided, - // But it is still here, just in case we want to enable some additional functionality. - reservedDynamic: BytesLike; + txType: BigNumberish; + from: BigNumberish; + to: BigNumberish; + gasLimit: BigNumberish; + gasPerPubdataByteLimit: BigNumberish; + maxFeePerGas: BigNumberish; + maxPriorityFeePerGas: BigNumberish; + paymaster: BigNumberish; + nonce: BigNumberish; + value: BigNumberish; + // In the future, we might want to add some + // new fields to the struct. The `txData` struct + // is to be passed to account and any changes to its structure + // would mean a breaking change to these accounts. In order to prevent this, + // we should keep some fields as "reserved". + // It is also recommneded that their length is fixed, since + // it would allow easier proof integration (in case we will need + // some special circuit for preprocessing transactions). + reserved: [BigNumberish, BigNumberish, BigNumberish, BigNumberish]; + data: BytesLike; + signature: BytesLike; + factoryDeps: BytesLike[]; + paymasterInput: BytesLike; + // Reserved dynamic type for the future use-case. Using it should be avoided, + // But it is still here, just in case we want to enable some additional functionality. + reservedDynamic: BytesLike; } export function signedTxToTransactionData(tx: Transaction) { - // Transform legacy transaction's `v` part of the signature - // to a single byte used in the packed eth signature - function unpackV(v: number) { - if (v >= 35) { - const chainId = Math.floor((v - 35) / 2); - return v - chainId * 2 - 8; - } else if (v <= 1) { - return 27 + v; - } - - throw new Error('Invalid `v`'); + // Transform legacy transaction's `v` part of the signature + // to a single byte used in the packed eth signature + function unpackV(v: number) { + if (v >= 35) { + const chainId = Math.floor((v - 35) / 2); + return v - chainId * 2 - 8; + } else if (v <= 1) { + return 27 + v; } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - function legacyTxToTransactionData(tx: any): TransactionData { - return { - txType: 0, - from: tx.from!, - to: tx.to!, - gasLimit: tx.gasLimit!, - gasPerPubdataByteLimit: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - maxFeePerGas: tx.gasPrice!, - maxPriorityFeePerGas: tx.gasPrice!, - paymaster: 0, - nonce: tx.nonce, - value: tx.value || 0, - reserved: [tx.chainId || 0, 0, 0, 0], - data: tx.data!, - signature: ethers.utils.hexConcat([tx.r, tx.s, new Uint8Array([unpackV(tx.v)])]), - factoryDeps: [], - paymasterInput: '0x', - reservedDynamic: '0x' - }; - } + throw new Error("Invalid `v`"); + } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - function eip2930TxToTransactionData(tx: any): TransactionData { - return { - txType: 1, - from: tx.from!, - to: tx.to!, - gasLimit: tx.gasLimit!, - gasPerPubdataByteLimit: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - maxFeePerGas: tx.gasPrice!, - maxPriorityFeePerGas: tx.gasPrice!, - paymaster: 0, - nonce: tx.nonce, - value: tx.value || 0, - reserved: [0, 0, 0, 0], - data: tx.data!, - signature: ethers.utils.hexConcat([tx.r, tx.s, unpackV(tx.v)]), - factoryDeps: [], - paymasterInput: '0x', - reservedDynamic: '0x' - }; - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + function legacyTxToTransactionData(tx: any): TransactionData { + return { + txType: 0, + from: tx.from!, + to: tx.to!, + gasLimit: tx.gasLimit!, + gasPerPubdataByteLimit: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, + maxFeePerGas: tx.gasPrice!, + maxPriorityFeePerGas: tx.gasPrice!, + paymaster: 0, + nonce: tx.nonce, + value: tx.value || 0, + reserved: [tx.chainId || 0, 0, 0, 0], + data: tx.data!, + signature: ethers.utils.hexConcat([tx.r, tx.s, new Uint8Array([unpackV(tx.v)])]), + factoryDeps: [], + paymasterInput: "0x", + reservedDynamic: "0x", + }; + } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - function eip1559TxToTransactionData(tx: any): TransactionData { - return { - txType: 2, - from: tx.from!, - to: tx.to!, - gasLimit: tx.gasLimit!, - gasPerPubdataByteLimit: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - maxFeePerGas: tx.maxFeePerGas, - maxPriorityFeePerGas: tx.maxPriorityFeePerGas, - paymaster: 0, - nonce: tx.nonce, - value: tx.value || 0, - reserved: [0, 0, 0, 0], - data: tx.data!, - signature: ethers.utils.hexConcat([tx.r, tx.s, unpackV(tx.v)]), - factoryDeps: [], - paymasterInput: '0x', - reservedDynamic: '0x' - }; - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + function eip2930TxToTransactionData(tx: any): TransactionData { + return { + txType: 1, + from: tx.from!, + to: tx.to!, + gasLimit: tx.gasLimit!, + gasPerPubdataByteLimit: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, + maxFeePerGas: tx.gasPrice!, + maxPriorityFeePerGas: tx.gasPrice!, + paymaster: 0, + nonce: tx.nonce, + value: tx.value || 0, + reserved: [0, 0, 0, 0], + data: tx.data!, + signature: ethers.utils.hexConcat([tx.r, tx.s, unpackV(tx.v)]), + factoryDeps: [], + paymasterInput: "0x", + reservedDynamic: "0x", + }; + } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - function eip712TxToTransactionData(tx: any): TransactionData { - return { - txType: 113, - from: tx.from!, - to: tx.to!, - gasLimit: tx.gasLimit!, - gasPerPubdataByteLimit: tx.customData.gasPerPubdata || zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, - maxFeePerGas: tx.maxFeePerGas, - maxPriorityFeePerGas: tx.maxPriorityFeePerGas, - paymaster: tx.customData.paymasterParams?.paymaster || 0, - nonce: tx.nonce, - value: tx.value || 0, - reserved: [0, 0, 0, 0], - data: tx.data!, - signature: tx.customData.customSignature, - factoryDeps: tx.customData.factoryDeps.map(zksync.utils.hashBytecode), - paymasterInput: tx.customData.paymasterParams?.paymasterInput || '0x', - reservedDynamic: '0x' - }; - } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + function eip1559TxToTransactionData(tx: any): TransactionData { + return { + txType: 2, + from: tx.from!, + to: tx.to!, + gasLimit: tx.gasLimit!, + gasPerPubdataByteLimit: zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, + maxFeePerGas: tx.maxFeePerGas, + maxPriorityFeePerGas: tx.maxPriorityFeePerGas, + paymaster: 0, + nonce: tx.nonce, + value: tx.value || 0, + reserved: [0, 0, 0, 0], + data: tx.data!, + signature: ethers.utils.hexConcat([tx.r, tx.s, unpackV(tx.v)]), + factoryDeps: [], + paymasterInput: "0x", + reservedDynamic: "0x", + }; + } - const txType = tx.type ?? 0; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + function eip712TxToTransactionData(tx: any): TransactionData { + return { + txType: 113, + from: tx.from!, + to: tx.to!, + gasLimit: tx.gasLimit!, + gasPerPubdataByteLimit: tx.customData.gasPerPubdata || zksync.utils.DEFAULT_GAS_PER_PUBDATA_LIMIT, + maxFeePerGas: tx.maxFeePerGas, + maxPriorityFeePerGas: tx.maxPriorityFeePerGas, + paymaster: tx.customData.paymasterParams?.paymaster || 0, + nonce: tx.nonce, + value: tx.value || 0, + reserved: [0, 0, 0, 0], + data: tx.data!, + signature: tx.customData.customSignature, + factoryDeps: tx.customData.factoryDeps.map(zksync.utils.hashBytecode), + paymasterInput: tx.customData.paymasterParams?.paymasterInput || "0x", + reservedDynamic: "0x", + }; + } - switch (txType) { - case 0: - return legacyTxToTransactionData(tx); - case 1: - return eip2930TxToTransactionData(tx); - case 2: - return eip1559TxToTransactionData(tx); - case 113: - return eip712TxToTransactionData(tx); - default: - throw new Error('Unsupported tx type'); - } + const txType = tx.type ?? 0; + + switch (txType) { + case 0: + return legacyTxToTransactionData(tx); + case 1: + return eip2930TxToTransactionData(tx); + case 2: + return eip1559TxToTransactionData(tx); + case 113: + return eip712TxToTransactionData(tx); + default: + throw new Error("Unsupported tx type"); + } } diff --git a/test/shared/utils.ts b/test/shared/utils.ts index d875b32696c..448f505e464 100644 --- a/test/shared/utils.ts +++ b/test/shared/utils.ts @@ -1,32 +1,33 @@ -import { Deployer } from '@matterlabs/hardhat-zksync-deploy'; -import { ZkSyncArtifact } from '@matterlabs/hardhat-zksync-deploy/dist/types'; -import { BytesLike } from 'ethers'; -import * as hre from 'hardhat'; -import { ethers, network } from 'hardhat'; -import * as zksync from 'zksync-web3'; -import { Contract, Provider, Wallet } from 'zksync-web3'; -import { Language } from '../../scripts/constants'; -import { readYulBytecode } from '../../scripts/utils'; -import { ContractDeployer__factory } from '../../typechain-types'; -import { DEPLOYER_SYSTEM_CONTRACT_ADDRESS } from './constants'; +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import type { ZkSyncArtifact } from "@matterlabs/hardhat-zksync-deploy/dist/types"; +import type { BytesLike } from "ethers"; +import * as hre from "hardhat"; +import { ethers, network } from "hardhat"; +import * as zksync from "zksync-web3"; +import type { Contract } from "zksync-web3"; +import { Provider, Wallet } from "zksync-web3"; +import { Language } from "../../scripts/constants"; +import { readYulBytecode } from "../../scripts/utils"; +import { ContractDeployer__factory } from "../../typechain-types"; +import { DEPLOYER_SYSTEM_CONTRACT_ADDRESS } from "./constants"; const RICH_WALLETS = [ - { - address: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', - privateKey: '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110' - }, - { - address: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', - privateKey: '0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3' - }, - { - address: '0x0D43eB5B8a47bA8900d84AA36656c92024e9772e', - privateKey: '0xd293c684d884d56f8d6abd64fc76757d3664904e309a0645baf8522ab6366d9e' - }, - { - address: '0xA13c10C0D5bd6f79041B9835c63f91de35A15883', - privateKey: '0x850683b40d4a740aa6e745f889a6fdc8327be76e122f5aba645a5b02d0248db8' - } + { + address: "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049", + privateKey: "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110", + }, + { + address: "0xa61464658AfeAf65CccaaFD3a512b69A83B77618", + privateKey: "0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3", + }, + { + address: "0x0D43eB5B8a47bA8900d84AA36656c92024e9772e", + privateKey: "0xd293c684d884d56f8d6abd64fc76757d3664904e309a0645baf8522ab6366d9e", + }, + { + address: "0xA13c10C0D5bd6f79041B9835c63f91de35A15883", + privateKey: "0x850683b40d4a740aa6e745f889a6fdc8327be76e122f5aba645a5b02d0248db8", + }, ]; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -36,102 +37,102 @@ const wallet = new Wallet(RICH_WALLETS[0].privateKey, provider); const deployer = new Deployer(hre, wallet); export async function callFallback(contract: Contract, data: string) { - // `eth_Call` revert is not parsed by ethers, so we send - // transaction to catch the error and use `eth_Call` to the return data. - await contract.fallback({ data }); - return contract.provider.call({ - to: contract.address, - data - }); + // `eth_Call` revert is not parsed by ethers, so we send + // transaction to catch the error and use `eth_Call` to the return data. + await contract.fallback({ data }); + return contract.provider.call({ + to: contract.address, + data, + }); } export function getWallets(): Wallet[] { - const wallets = []; - for (let i = 0; i < RICH_WALLETS.length; i++) { - wallets[i] = new Wallet(RICH_WALLETS[i].privateKey, provider); - } - return wallets; + const wallets = []; + for (let i = 0; i < RICH_WALLETS.length; i++) { + wallets[i] = new Wallet(RICH_WALLETS[i].privateKey, provider); + } + return wallets; } export async function loadArtifact(name: string): Promise { - return await deployer.loadArtifact(name); + return await deployer.loadArtifact(name); } // eslint-disable-next-line @typescript-eslint/no-explicit-any export async function deployContract(name: string, constructorArguments?: any[] | undefined): Promise { - const artifact = await loadArtifact(name); - return await deployer.deploy(artifact, constructorArguments); + const artifact = await loadArtifact(name); + return await deployer.deploy(artifact, constructorArguments); } export async function deployContractYul(codeName: string, path: string): Promise { - const bytecode = readYulBytecode({ - codeName, - path, - lang: Language.Yul, - address: '0x0000000000000000000000000000000000000000' - }); - return await deployer.deploy( - { - bytecode, - factoryDeps: {}, - sourceMapping: '', - _format: '', - contractName: '', - sourceName: '', - abi: [], - deployedBytecode: bytecode, - linkReferences: {}, - deployedLinkReferences: {} - }, - [] - ); + const bytecode = readYulBytecode({ + codeName, + path, + lang: Language.Yul, + address: "0x0000000000000000000000000000000000000000", + }); + return await deployer.deploy( + { + bytecode, + factoryDeps: {}, + sourceMapping: "", + _format: "", + contractName: "", + sourceName: "", + abi: [], + deployedBytecode: bytecode, + linkReferences: {}, + deployedLinkReferences: {}, + }, + [] + ); } export async function publishBytecode(bytecode: BytesLike) { - await wallet.sendTransaction({ - type: 113, - to: ethers.constants.AddressZero, - data: '0x', - customData: { - factoryDeps: [bytecode], - gasPerPubdata: 50000 - } - }); + await wallet.sendTransaction({ + type: 113, + to: ethers.constants.AddressZero, + data: "0x", + customData: { + factoryDeps: [bytecode], + gasPerPubdata: 50000, + }, + }); } export async function getCode(address: string): Promise { - return await provider.getCode(address); + return await provider.getCode(address); } // Force deploy bytecode on the address export async function setCode(address: string, bytecode: BytesLike) { - // TODO: think about factoryDeps with eth_sendTransaction - try { - // publish bytecode in a separate tx - await publishBytecode(bytecode); - } catch { - // ignore error - } + // TODO: think about factoryDeps with eth_sendTransaction + try { + // publish bytecode in a separate tx + await publishBytecode(bytecode); + } catch { + // ignore error + } - await network.provider.request({ - method: 'hardhat_impersonateAccount', - params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS] - }); + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS], + }); - const deployerAccount = await ethers.getSigner(DEPLOYER_SYSTEM_CONTRACT_ADDRESS); - const deployerContract = ContractDeployer__factory.connect(DEPLOYER_SYSTEM_CONTRACT_ADDRESS, deployerAccount); + const deployerAccount = await ethers.getSigner(DEPLOYER_SYSTEM_CONTRACT_ADDRESS); + const deployerContract = ContractDeployer__factory.connect(DEPLOYER_SYSTEM_CONTRACT_ADDRESS, deployerAccount); - const deployment = { - bytecodeHash: zksync.utils.hashBytecode(bytecode), - newAddress: address, - callConstructor: false, - value: 0, - input: '0x' - }; - await deployerContract.forceDeployOnAddress(deployment, ethers.constants.AddressZero); + const deployment = { + bytecodeHash: zksync.utils.hashBytecode(bytecode), + newAddress: address, + callConstructor: false, + value: 0, + input: "0x", + }; + await deployerContract.forceDeployOnAddress(deployment, ethers.constants.AddressZero); - await network.provider.request({ - method: 'hardhat_stopImpersonatingAccount', - params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS] - }); + await network.provider.request({ + method: "hardhat_stopImpersonatingAccount", + params: [DEPLOYER_SYSTEM_CONTRACT_ADDRESS], + }); } diff --git a/yarn.lock b/yarn.lock index 761111a91c9..166747deee4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -98,9 +98,9 @@ eslint-visitor-keys "^3.3.0" "@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": - version "4.9.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.1.tgz#449dfa81a57a1d755b09aa58d826c1262e4283b4" - integrity sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA== + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== "@eslint/eslintrc@^2.1.2": version "2.1.2" @@ -117,10 +117,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.51.0": - version "8.51.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.51.0.tgz#6d419c240cfb2b66da37df230f7e7eef801c32fa" - integrity sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg== +"@eslint/js@8.52.0": + version "8.52.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.52.0.tgz#78fe5f117840f69dc4a353adf9b9cd926353378c" + integrity sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA== "@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.7.0": version "5.7.0" @@ -469,12 +469,12 @@ resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.0.0.tgz#f22824caff3ae506b18207bad4126dbc6ccdb6b8" integrity sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ== -"@humanwhocodes/config-array@^0.11.11": - version "0.11.11" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" - integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== +"@humanwhocodes/config-array@^0.11.13": + version "0.11.13" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" + integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" + "@humanwhocodes/object-schema" "^2.0.1" debug "^4.1.1" minimatch "^3.0.5" @@ -483,10 +483,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/object-schema@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" + integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== "@jridgewell/resolve-uri@^3.0.3": version "3.1.1" @@ -506,6 +506,11 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@matterlabs/eslint-config-typescript@^1.1.2": + version "1.1.2" + 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" @@ -532,6 +537,11 @@ proper-lockfile "^4.1.2" semver "^7.5.1" +"@matterlabs/prettier-config@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@matterlabs/prettier-config/-/prettier-config-1.0.3.tgz#3e2eb559c0112bbe9671895f935700dad2a15d38" + integrity sha512-JW7nHREPqEtjBWz3EfxLarkmJBD8vi7Kx/1AQ6eBZnz12eHc1VkOyrc6mpR5ogTf0dOUNXFAfZut+cDe2dn4kQ== + "@metamask/eth-sig-util@^4.0.0": version "4.0.1" resolved "https://registry.yarnpkg.com/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz#3ad61f6ea9ad73ba5b19db780d40d9aae5157088" @@ -807,6 +817,18 @@ fs-extra "^7.0.1" solpp "^0.11.5" +"@pkgr/utils@^2.3.1": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc" + integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw== + dependencies: + cross-spawn "^7.0.3" + fast-glob "^3.3.0" + is-glob "^4.0.3" + open "^9.1.0" + picocolors "^1.0.0" + tslib "^2.6.0" + "@scure/base@~1.1.0": version "1.1.3" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.3.tgz#8584115565228290a6c6c4961973e0903bb3df2f" @@ -981,9 +1003,14 @@ integrity sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g== "@types/json-schema@^7.0.12": - version "7.0.13" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" - integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== + version "7.0.14" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.14.tgz#74a97a5573980802f32c8e47b663530ab3b6b7d1" + integrity sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== "@types/lodash@^4.14.199": version "4.14.199" @@ -1052,20 +1079,20 @@ "@types/node" "*" "@types/semver@^7.5.0": - version "7.5.3" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.3.tgz#9a726e116beb26c24f1ccd6850201e1246122e04" - integrity sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw== + version "7.5.4" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.4.tgz#0a41252ad431c473158b22f9bfb9a63df7541cff" + integrity sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ== "@typescript-eslint/eslint-plugin@^6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz#057338df21b6062c2f2fc5999fbea8af9973ac6d" - integrity sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA== + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz#fdb6f3821c0167e3356e9d89c80e8230b2e401f4" + integrity sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.7.4" - "@typescript-eslint/type-utils" "6.7.4" - "@typescript-eslint/utils" "6.7.4" - "@typescript-eslint/visitor-keys" "6.7.4" + "@typescript-eslint/scope-manager" "6.9.0" + "@typescript-eslint/type-utils" "6.9.0" + "@typescript-eslint/utils" "6.9.0" + "@typescript-eslint/visitor-keys" "6.9.0" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -1074,73 +1101,78 @@ ts-api-utils "^1.0.1" "@typescript-eslint/parser@^6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.4.tgz#23d1dd4fe5d295c7fa2ab651f5406cd9ad0bd435" - integrity sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA== - dependencies: - "@typescript-eslint/scope-manager" "6.7.4" - "@typescript-eslint/types" "6.7.4" - "@typescript-eslint/typescript-estree" "6.7.4" - "@typescript-eslint/visitor-keys" "6.7.4" + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.9.0.tgz#2b402cadeadd3f211c25820e5433413347b27391" + integrity sha512-GZmjMh4AJ/5gaH4XF2eXA8tMnHWP+Pm1mjQR2QN4Iz+j/zO04b9TOvJYOX2sCNIQHtRStKTxRY1FX7LhpJT4Gw== + dependencies: + "@typescript-eslint/scope-manager" "6.9.0" + "@typescript-eslint/types" "6.9.0" + "@typescript-eslint/typescript-estree" "6.9.0" + "@typescript-eslint/visitor-keys" "6.9.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz#a484a17aa219e96044db40813429eb7214d7b386" - integrity sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A== +"@typescript-eslint/scope-manager@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz#2626e9a7fe0e004c3e25f3b986c75f584431134e" + integrity sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw== dependencies: - "@typescript-eslint/types" "6.7.4" - "@typescript-eslint/visitor-keys" "6.7.4" + "@typescript-eslint/types" "6.9.0" + "@typescript-eslint/visitor-keys" "6.9.0" -"@typescript-eslint/type-utils@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz#847cd3b59baf948984499be3e0a12ff07373e321" - integrity sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ== +"@typescript-eslint/type-utils@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz#23923c8c9677c2ad41457cf8e10a5f2946be1b04" + integrity sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ== dependencies: - "@typescript-eslint/typescript-estree" "6.7.4" - "@typescript-eslint/utils" "6.7.4" + "@typescript-eslint/typescript-estree" "6.9.0" + "@typescript-eslint/utils" "6.9.0" debug "^4.3.4" ts-api-utils "^1.0.1" -"@typescript-eslint/types@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.4.tgz#5d358484d2be986980c039de68e9f1eb62ea7897" - integrity sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA== +"@typescript-eslint/types@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.9.0.tgz#86a0cbe7ac46c0761429f928467ff3d92f841098" + integrity sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw== -"@typescript-eslint/typescript-estree@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz#f2baece09f7bb1df9296e32638b2e1130014ef1a" - integrity sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ== +"@typescript-eslint/typescript-estree@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz#d0601b245be873d8fe49f3737f93f8662c8693d4" + integrity sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ== dependencies: - "@typescript-eslint/types" "6.7.4" - "@typescript-eslint/visitor-keys" "6.7.4" + "@typescript-eslint/types" "6.9.0" + "@typescript-eslint/visitor-keys" "6.9.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.4.tgz#2236f72b10e38277ee05ef06142522e1de470ff2" - integrity sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA== +"@typescript-eslint/utils@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.9.0.tgz#5bdac8604fca4823f090e4268e681c84d3597c9f" + integrity sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.7.4" - "@typescript-eslint/types" "6.7.4" - "@typescript-eslint/typescript-estree" "6.7.4" + "@typescript-eslint/scope-manager" "6.9.0" + "@typescript-eslint/types" "6.9.0" + "@typescript-eslint/typescript-estree" "6.9.0" semver "^7.5.4" -"@typescript-eslint/visitor-keys@6.7.4": - version "6.7.4" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz#80dfecf820fc67574012375859085f91a4dff043" - integrity sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA== +"@typescript-eslint/visitor-keys@6.9.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz#cc69421c10c4ac997ed34f453027245988164e80" + integrity sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg== dependencies: - "@typescript-eslint/types" "6.7.4" + "@typescript-eslint/types" "6.9.0" eslint-visitor-keys "^3.4.1" +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + JSONStream@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.2.tgz#c102371b6ec3a7cf3b847ca00c20bb0fce4c6dea" @@ -1179,11 +1211,16 @@ acorn-walk@^8.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^8.4.1, acorn@^8.9.0: +acorn@^8.4.1: version "8.10.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== +acorn@^8.9.0: + version "8.11.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" + integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== + adm-zip@^0.4.16: version "0.4.16" resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" @@ -1313,11 +1350,74 @@ array-back@^4.0.1, array-back@^4.0.2: resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + +array-includes@^3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" + integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-string "^1.0.7" + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +array.prototype.findlastindex@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" + integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.2.1" + +array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +arraybuffer.prototype.slice@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" + integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" + asn1@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" @@ -1345,6 +1445,11 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + axios@^0.21.1: version "0.21.4" resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" @@ -1381,6 +1486,11 @@ bech32@1.1.4: resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== +big-integer@^1.6.44: + version "1.6.51" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" + integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== + bigint-crypto-utils@^3.0.23: version "3.3.0" resolved "https://registry.yarnpkg.com/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz#72ad00ae91062cf07f2b1def9594006c279c1d77" @@ -1431,6 +1541,13 @@ bn.js@^5.2.0, bn.js@^5.2.1: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== +bplist-parser@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e" + integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw== + dependencies: + big-integer "^1.6.44" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1550,11 +1667,27 @@ buildcheck@~0.0.6: resolved "https://registry.yarnpkg.com/buildcheck/-/buildcheck-0.0.6.tgz#89aa6e417cfd1e2196e3f8fe915eb709d2fe4238" integrity sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A== +bundle-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-3.0.0.tgz#ba59bcc9ac785fb67ccdbf104a2bf60c099f0e1a" + integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw== + dependencies: + run-applescript "^5.0.0" + bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -1830,7 +1963,7 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^7.0.2: +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -1846,7 +1979,7 @@ debug@4, debug@4.3.4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, de dependencies: ms "2.1.2" -debug@^3.2.6: +debug@^3.2.6, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -1880,6 +2013,47 @@ 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== +default-browser-id@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-3.0.0.tgz#bee7bbbef1f4e75d31f98f4d3f1556a14cea790c" + integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA== + dependencies: + bplist-parser "^0.2.0" + untildify "^4.0.0" + +default-browser@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-4.0.0.tgz#53c9894f8810bf86696de117a6ce9085a3cbc7da" + integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA== + dependencies: + bundle-name "^3.0.0" + default-browser-id "^3.0.0" + execa "^7.1.1" + titleize "^3.0.0" + +define-data-property@^1.0.1, define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +define-lazy-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" + integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== + +define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + depd@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -1940,6 +2114,13 @@ dockerode@^3.3.4: docker-modem "^3.0.0" tar-fs "~2.0.1" +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -1972,6 +2153,14 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" +enhanced-resolve@^5.12.0: + version "5.15.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" + integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + enquirer@^2.3.0: version "2.4.1" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" @@ -1997,6 +2186,76 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +es-abstract@^1.22.1: + version "1.22.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" + integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== + dependencies: + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.2" + available-typed-arrays "^1.0.5" + call-bind "^1.0.5" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.2" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.12" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + safe-array-concat "^1.0.1" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.8" + string.prototype.trimend "^1.0.7" + string.prototype.trimstart "^1.0.7" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.13" + +es-set-tostringtag@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" + integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== + dependencies: + get-intrinsic "^1.2.2" + has-tostringtag "^1.0.0" + hasown "^2.0.0" + +es-shim-unscopables@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -2012,6 +2271,66 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-import-resolver-typescript@^3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz#7b983680edd3f1c5bce1a5829ae0bc2d57fe9efa" + integrity sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg== + dependencies: + debug "^4.3.4" + enhanced-resolve "^5.12.0" + eslint-module-utils "^2.7.4" + fast-glob "^3.3.1" + get-tsconfig "^4.5.0" + is-core-module "^2.11.0" + is-glob "^4.0.3" + +eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" + integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== + dependencies: + debug "^3.2.7" + +eslint-plugin-import@^2.29.0: + version "2.29.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz#8133232e4329ee344f2f612885ac3073b0b7e155" + integrity sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg== + dependencies: + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.8.0" + hasown "^2.0.0" + is-core-module "^2.13.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" + semver "^6.3.1" + tsconfig-paths "^3.14.2" + +eslint-plugin-prettier@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz#a3b399f04378f79f066379f544e42d6b73f11515" + integrity sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg== + dependencies: + prettier-linter-helpers "^1.0.0" + synckit "^0.8.5" + eslint-scope@^7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" @@ -2026,17 +2345,18 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8.51.0: - version "8.51.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.51.0.tgz#4a82dae60d209ac89a5cff1604fea978ba4950f3" - integrity sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA== + version "8.52.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.52.0.tgz#d0cd4a1fac06427a61ef9242b9353f36ea7062fc" + integrity sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.51.0" - "@humanwhocodes/config-array" "^0.11.11" + "@eslint/js" "8.52.0" + "@humanwhocodes/config-array" "^0.11.13" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -2210,17 +2530,47 @@ evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +execa@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9" + integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^4.3.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-diff@^1.2.0: +fast-diff@^1.1.2, fast-diff@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@^3.2.12, fast-glob@^3.2.9: +fast-glob@^3.2.12, fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== @@ -2308,6 +2658,13 @@ follow-redirects@^1.12.1, follow-redirects@^1.14.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + fp-ts@1.19.3: version "1.19.3" resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.3.tgz#261a60d1088fbff01f91256f91d21d0caaaaa96f" @@ -2377,11 +2734,31 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -2392,11 +2769,41 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== + dependencies: + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + get-stdin@~9.0.0: version "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.0, 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.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +get-tsconfig@^4.5.0: + version "4.7.2" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.2.tgz#0dcd6fb330391d46332f4c6c1bf89a6514c2ddce" + integrity sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A== + dependencies: + resolve-pkg-maps "^1.0.0" + glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -2476,6 +2883,13 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -2488,6 +2902,13 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -2558,6 +2979,11 @@ hardhat@=2.16.0: uuid "^8.3.2" ws "^7.4.6" +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -2568,6 +2994,30 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-property-descriptors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== + dependencies: + get-intrinsic "^1.2.2" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -2592,6 +3042,13 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + he@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" @@ -2625,6 +3082,16 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +human-signals@^4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" + integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -2683,6 +3150,15 @@ ini@~3.0.0: resolved "https://registry.yarnpkg.com/ini/-/ini-3.0.1.tgz#c76ec81007875bc44d544ff7a11a55d12294102d" integrity sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ== +internal-slot@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" + integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== + dependencies: + get-intrinsic "^1.2.2" + hasown "^2.0.0" + side-channel "^1.0.4" + io-ts@1.10.4: version "1.10.4" resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.10.4.tgz#cd5401b138de88e4f920adbcb7026e2d1967e6e2" @@ -2690,11 +3166,27 @@ io-ts@1.10.4: dependencies: fp-ts "^1.0.0" +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -2702,11 +3194,31 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-buffer@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.11.0, is-core-module@^2.13.1: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + is-core-module@^2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" @@ -2714,6 +3226,23 @@ is-core-module@^2.13.0: dependencies: has "^1.0.3" +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-docker@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" + integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -2736,6 +3265,25 @@ is-hex-prefixed@1.0.0: resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== +is-inside-container@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" + integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== + dependencies: + is-docker "^3.0.0" + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -2751,16 +3299,81 @@ is-plain-obj@^2.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + is-unicode-supported@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -2818,6 +3431,13 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + jsonc-parser@~3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" @@ -3055,6 +3675,11 @@ memorystream@^0.3.1: resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -3068,6 +3693,16 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + 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" @@ -3106,7 +3741,7 @@ minimatch@^7.4.3: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.6, minimist@^1.2.8: +minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -3233,11 +3868,73 @@ 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== +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +npm-run-path@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" + integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== + dependencies: + path-key "^4.0.0" + object-assign@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== +object-inspect@^1.13.1, object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.fromentries@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" + integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +object.groupby@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" + integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + +object.values@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" + integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + obliterator@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/obliterator/-/obliterator-2.0.4.tgz#fa650e019b2d075d745e44f1effeb13a2adbe816" @@ -3250,6 +3947,30 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + +open@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6" + integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg== + dependencies: + default-browser "^4.0.0" + define-lazy-prop "^3.0.0" + is-inside-container "^1.0.0" + is-wsl "^2.2.0" + optionator@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" @@ -3356,11 +4077,16 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + path-parse@^1.0.6, path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -3392,6 +4118,11 @@ pbkdf2@^3.0.17: safe-buffer "^5.0.1" sha.js "^2.4.8" +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -3414,6 +4145,13 @@ preprocess@^3.2.0: dependencies: xregexp "3.1.0" +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + prettier-plugin-solidity@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.3.tgz#9a35124f578404caf617634a8cab80862d726cba" @@ -3539,6 +4277,15 @@ reduce-flatten@^2.0.0: resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== +regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + set-function-name "^2.0.0" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -3554,6 +4301,11 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + resolve@1.17.0: version "1.17.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" @@ -3570,6 +4322,15 @@ resolve@^1.10.0, resolve@^1.8.1: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@^1.22.4: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -3609,6 +4370,13 @@ rlp@^2.2.3: dependencies: bn.js "^5.2.0" +run-applescript@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-5.0.0.tgz#e11e1c932e055d5c6b40d98374e0268d9b11899c" + integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg== + dependencies: + execa "^5.0.0" + run-con@~1.2.11: version "1.2.12" resolved "https://registry.yarnpkg.com/run-con/-/run-con-1.2.12.tgz#51c319910e45a3bd71ee773564a89d96635c8c64" @@ -3638,6 +4406,16 @@ rustbn.js@~0.2.0: resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" integrity sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA== +safe-array-concat@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" + integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + isarray "^2.0.5" + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -3648,6 +4426,15 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + "safer-buffer@>= 2.1.2 < 3", safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -3672,7 +4459,7 @@ semver@^5.5.0, semver@^5.6.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.3.0: +semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -3691,6 +4478,25 @@ serialize-javascript@6.0.0: dependencies: randombytes "^2.1.0" +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +set-function-name@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + dependencies: + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" + setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -3721,7 +4527,16 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -signal-exit@^3.0.2: +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -3855,6 +4670,33 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string.prototype.trim@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" + integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string.prototype.trimend@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" + integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string.prototype.trimstart@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" + integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -3881,6 +4723,21 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + strip-hex-prefix@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" @@ -3919,6 +4776,14 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +synckit@^0.8.5: + version "0.8.5" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3" + integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q== + dependencies: + "@pkgr/utils" "^2.3.1" + tslib "^2.5.0" + table-layout@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" @@ -3940,6 +4805,11 @@ table@^6.8.1: string-width "^4.2.3" strip-ansi "^6.0.1" +tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + tar-fs@~1.16.3: version "1.16.3" resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" @@ -4018,6 +4888,11 @@ thenify-all@^1.0.0: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +titleize@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53" + integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ== + tmp@0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -4114,11 +4989,26 @@ ts-node@^10.7.0: v8-compile-cache-lib "^3.0.1" yn "3.1.1" +tsconfig-paths@^3.14.2: + version "3.14.2" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" + integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tslib@^2.5.0, tslib@^2.6.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + tsort@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" @@ -4182,6 +5072,45 @@ typechain@^8.1.1: ts-command-line-args "^2.2.0" ts-essentials "^7.0.1" +typed-array-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" + integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-typed-array "^1.1.10" + +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -4207,6 +5136,16 @@ uc.micro@^1.0.1, uc.micro@^1.0.5: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + undici@^5.14.0: version "5.26.4" resolved "https://registry.yarnpkg.com/undici/-/undici-5.26.4.tgz#dc861c35fb53ae025a173a790d984aa9b2e279a1" @@ -4229,6 +5168,11 @@ unpipe@1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -4264,6 +5208,28 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-typed-array@^1.1.11, which-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.4" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"