From 27f06e50fa0328f163152e855155be8e5cca6c5a Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Wed, 19 Jul 2023 17:25:39 +0300 Subject: [PATCH 01/37] chore: add .idea folder to the gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 06b33e083..74095b734 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.idea/ build/ node_modules/ .DS_Store @@ -17,4 +18,4 @@ typechain-types # Certora Formal Verification related files .certora_internal .certora_recent_jobs.json -.zip-output-url.txt \ No newline at end of file +.zip-output-url.txt From f2fc3811fd315ec47afa283e8cdf952942ff4bb0 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Wed, 19 Jul 2023 20:45:59 +0300 Subject: [PATCH 02/37] chore(deps): add zksync related packages --- package.json | 6 +++++- tsconfig.json | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8cf8f7695..7269c2951 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,9 @@ "url": "https://github.com/safe-global/safe-contracts/issues" }, "devDependencies": { + "@matterlabs/hardhat-zksync-deploy": "^0.6.3", + "@matterlabs/hardhat-zksync-solc": "^0.4.1", + "@matterlabs/hardhat-zksync-verify": "^0.1.8", "@nomicfoundation/hardhat-toolbox": "^3.0.0", "@openzeppelin/contracts": "^3.4.0", "@safe-global/mock-contract": "^4.0.0", @@ -73,6 +76,7 @@ "solhint": "3.6.2", "ts-node": "^10.9.1", "typescript": "^5.1.6", - "yargs": "^17.7.2" + "yargs": "^17.7.2", + "zksync-web3": "^0.14.3" } } diff --git a/tsconfig.json b/tsconfig.json index 2c764454a..595a08074 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,7 +15,8 @@ "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */, "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, - "resolveJsonModule": true + "resolveJsonModule": true, + "skipLibCheck": true }, "exclude": ["dist", "node_modules"], "include": ["./src/index.ts", "./types", "./test/**/*", "./typechain-types/", "./benchmark/**/*"], From 26cfa3e76f3ebc794582785110156b16be89c376 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Wed, 19 Jul 2023 20:47:48 +0300 Subject: [PATCH 03/37] feat: add zksync configuration for hardhat --- hardhat.config.ts | 26 ++++++++++++++++ src/zk-utils/constants.ts | 62 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 src/zk-utils/constants.ts diff --git a/hardhat.config.ts b/hardhat.config.ts index 6dd58ae52..53cbe9667 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,5 +1,8 @@ import "@nomicfoundation/hardhat-toolbox"; import type { HardhatUserConfig, HttpNetworkUserConfig } from "hardhat/types"; +import "@matterlabs/hardhat-zksync-deploy"; +import "@matterlabs/hardhat-zksync-solc"; +import "@matterlabs/hardhat-zksync-verify"; import "hardhat-deploy"; import dotenv from "dotenv"; import yargs from "yargs"; @@ -38,6 +41,7 @@ import "./src/tasks/deploy_contracts"; import "./src/tasks/show_codesize"; import { BigNumber } from "@ethersproject/bignumber"; import { DeterministicDeploymentInfo } from "hardhat-deploy/dist/types"; +import { LOCAL_NODE_RICH_WALLETS } from "./src/zk-utils/constants"; const primarySolidityVersion = SOLIDITY_VERSION || "0.7.6"; const soliditySettings = SOLIDITY_SETTINGS ? JSON.parse(SOLIDITY_SETTINGS) : undefined; @@ -72,6 +76,13 @@ const userConfig: HardhatUserConfig = { solidity: { compilers: [{ version: primarySolidityVersion, settings: soliditySettings }, { version: "0.6.12" }, { version: "0.5.17" }], }, + zksolc: { + version: "1.3.13", + compilerSource: "binary", + settings: { + isSystem: true, + }, + }, networks: { hardhat: { allowUnlimitedContractSize: true, @@ -114,6 +125,21 @@ const userConfig: HardhatUserConfig = { ...sharedNetworkConfig, url: `https://api.avax.network/ext/bc/C/rpc`, }, + zkSyncTestnet: { + ...sharedNetworkConfig, + url: "https://testnet.era.zksync.dev", + ethNetwork: "goerli", + zksync: true, + verifyURL: "https://zksync2-testnet-explorer.zksync.dev/contract_verification", + }, + zkSyncLocal: { + chainId: 270, + accounts: LOCAL_NODE_RICH_WALLETS.map((account) => account.privateKey), + url: "http://localhost:3050", + ethNetwork: "http://localhost:8545", + zksync: true, + saveDeployments: true, + }, }, deterministicDeployment, namedAccounts: { diff --git a/src/zk-utils/constants.ts b/src/zk-utils/constants.ts new file mode 100644 index 000000000..2ebad14c2 --- /dev/null +++ b/src/zk-utils/constants.ts @@ -0,0 +1,62 @@ +// https://github.com/matter-labs/local-setup/blob/main/rich-wallets.json +export const LOCAL_NODE_RICH_WALLETS = [ + { + address: "0x36615Cf349d7F6344891B1e7CA7C72883F5dc049", + balance: "100000000000000000000", + privateKey: "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110", + }, + { + address: "0xa61464658AfeAf65CccaaFD3a512b69A83B77618", + balance: "100000000000000000000", + privateKey: "0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3", + }, + { + address: "0x0D43eB5B8a47bA8900d84AA36656c92024e9772e", + balance: "100000000000000000000", + privateKey: "0xd293c684d884d56f8d6abd64fc76757d3664904e309a0645baf8522ab6366d9e", + }, + { + address: "0xA13c10C0D5bd6f79041B9835c63f91de35A15883", + balance: "100000000000000000000", + privateKey: "0x850683b40d4a740aa6e745f889a6fdc8327be76e122f5aba645a5b02d0248db8", + }, + { + address: "0x8002cD98Cfb563492A6fB3E7C8243b7B9Ad4cc92", + balance: "100000000000000000000", + privateKey: "0xf12e28c0eb1ef4ff90478f6805b68d63737b7f33abfa091601140805da450d93", + }, + { + address: "0x4F9133D1d3F50011A6859807C837bdCB31Aaab13", + balance: "100000000000000000000", + privateKey: "0xe667e57a9b8aaa6709e51ff7d093f1c5b73b63f9987e4ab4aa9a5c699e024ee8", + }, + { + address: "0xbd29A1B981925B94eEc5c4F1125AF02a2Ec4d1cA", + balance: "100000000000000000000", + privateKey: "0x28a574ab2de8a00364d5dd4b07c4f2f574ef7fcc2a86a197f65abaec836d1959", + }, + { + address: "0xedB6F5B4aab3dD95C7806Af42881FF12BE7e9daa", + balance: "100000000000000000000", + privateKey: "0x74d8b3a188f7260f67698eb44da07397a298df5427df681ef68c45b34b61f998", + }, + { + address: "0xe706e60ab5Dc512C36A4646D719b889F398cbBcB", + balance: "100000000000000000000", + privateKey: "0xbe79721778b48bcc679b78edac0ce48306a8578186ffcb9f2ee455ae6efeace1", + }, + { + address: "0xE90E12261CCb0F3F7976Ae611A29e84a6A85f424", + balance: "100000000000000000000", + privateKey: "0x3eb15da85647edd9a1159a4a13b9e7c56877c4eb33f614546d4db06a51868b1c", + }, +]; + +export const factoryABI = ` +[ + { + "stateMutability": "payable", + "type": "fallback" + } +] +`; From 81195ff54bfe3a34ae9d6ae7feb6bfe69eaf9310 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Wed, 19 Jul 2023 20:48:39 +0300 Subject: [PATCH 04/37] feat: build zk contracts on prepublish --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 7269c2951..5096a0640 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ ], "scripts": { "build": "hardhat compile", + "build:zk": "hardhat compile --network zkSyncLocal", "build:ts": "rimraf dist && tsc -p tsconfig.prod.json", "build:ts:dev": "rimraf dist && tsc -p tsconfig.json", "test": "hardhat test", @@ -32,7 +33,7 @@ "fmt:ts": "prettier 'src/**/*.ts' 'test/**/*.ts' -w", "prepack": "npm run build", "prepare": "husky install", - "prepublish": "rimraf build && npm run build && npm run build:ts" + "prepublish": "rimraf build && npm run build && npm run build:zk && npm run build:ts" }, "repository": { "type": "git", From f7c7c7a69e7de8776489a0766211e6532c737d55 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Thu, 20 Jul 2023 14:34:08 +0300 Subject: [PATCH 05/37] feat: zkSync related utils for tests --- test/utils/setup.ts | 76 ++++++++++++++++++++++++++++++++++------ test/utils/zk.ts | 85 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 10 deletions(-) create mode 100644 test/utils/zk.ts diff --git a/test/utils/setup.ts b/test/utils/setup.ts index 79ebcf87b..ca40eb192 100644 --- a/test/utils/setup.ts +++ b/test/utils/setup.ts @@ -1,9 +1,12 @@ -import hre, { deployments } from "hardhat"; -import { Contract, Signer } from "ethers"; +import hre, { deployments, waffle } from "hardhat"; +import { Contract, Signer, ethers } from "ethers"; import { AddressZero } from "@ethersproject/constants"; import solc from "solc"; +import * as zk from "zksync-web3"; import { logGas } from "../../src/utils/execution"; import { safeContractUnderTest } from "./config"; +import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; +import { getZkContractFactoryByName, zkCompile } from "./zk"; import { getRandomIntAsString } from "./numbers"; import { Safe, SafeL2 } from "../../typechain-types"; @@ -100,8 +103,24 @@ export const migrationContract = async () => { }; export const getMock = async () => { - const Mock = await hre.ethers.getContractFactory("MockContract"); - return await Mock.deploy(); + if (!hre.network.zksync) { + const Mock = await hre.ethers.getContractFactory("MockContract"); + return Mock.deploy(); + } else { + const deployer = new Deployer(hre, getWallets()[0] as zk.Wallet); + const artifact = await deployer.loadArtifact("MockContract"); + const contract = await deployer.deploy(artifact); + await contract.deployTransaction.wait(); + return contract; + } +}; + +export const getContractFactoryByName = async (contractName: string) => { + if (hre.network.zksync) { + return getZkContractFactoryByName(hre, contractName, getWallets()[0] as zk.Wallet); + } else { + return hre.ethers.getContractFactory(contractName); + } }; export const getSafeTemplate = async (saltNumber: string = getRandomIntAsString()) => { @@ -192,13 +211,50 @@ export const compile = async (source: string) => { }; export const deployContract = async (deployer: Signer, source: string): Promise => { - const output = await compile(source); - const transaction = await deployer.sendTransaction({ data: output.data, gasLimit: 6000000 }); - const receipt = await transaction.wait(); + if (!hre.network.zksync) { + const output = await compile(source); + const transaction = await deployer.sendTransaction({ data: output.data, gasLimit: 6000000 }); + const receipt = await transaction.wait(); + + if (!receipt?.contractAddress) { + throw Error("Could not deploy contract"); + } + + return new Contract(receipt.contractAddress, output.interface, deployer); + } else { + const output = await zkCompile(hre, source); + + const factory = new zk.ContractFactory(output.abi, output.data, getWallets()[0] as zk.Wallet, "create"); + // Encode and send the deploy transaction providing factory dependencies. + const contract = await factory.deploy(); + await contract.deployed(); - if (!receipt?.contractAddress) { - throw Error("Could not deploy contract"); + return contract; } +}; + +export const getWallets = (): (ethers.Wallet | zk.Wallet)[] => { + if (hre.network.name === "hardhat") return waffle.provider.getWallets(); + if (!hre.network.zksync) throw new Error("You can get wallets only on Hardhat or ZkSyncLocal networks!"); + + const { accounts } = hre.network.config; + + if (typeof accounts === "string") throw new Error("Unsupported accounts config"); - return new Contract(receipt.contractAddress, output.interface, deployer); + const zkProvider = zk.Provider.getDefaultProvider(); + if (Array.isArray(accounts)) { + const wallets = []; + + for (const account of accounts) { + if (typeof account === "string") { + wallets.push(new zk.Wallet(account).connect(zkProvider)); + } else if (typeof account === "object" && "privateKey" in account) { + wallets.push(new zk.Wallet(account.privateKey).connect(zkProvider)); + } + } + + return wallets; + } else { + throw new Error("Unsupported accounts config"); + } }; diff --git a/test/utils/zk.ts b/test/utils/zk.ts new file mode 100644 index 000000000..f5116945d --- /dev/null +++ b/test/utils/zk.ts @@ -0,0 +1,85 @@ +import { exec } from "child_process"; +import { ContractInterface } from "ethers"; +import { TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD } from "hardhat/builtin-tasks/task-names"; +import { Compiler } from "hardhat/internal/solidity/compiler/downloader"; +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import * as zk from "zksync-web3"; + +export const getZkContractFactoryByName = async (hre: HardhatRuntimeEnvironment, contractName: string, signer: zk.Signer | zk.Wallet) => { + const artifact = await hre.artifacts.readArtifact(contractName); + + if (artifact.bytecode === "0x") { + throw new Error( + `You are trying to create a contract factory for the contract ${contractName}, which is abstract and can't be deployed.`, + ); + } + + return new zk.ContractFactory(artifact.abi, artifact.bytecode, signer, "create"); +}; + +let _solcBuild: Compiler; +async function getSolcBuild(hre: HardhatRuntimeEnvironment) { + if (!_solcBuild) { + _solcBuild = await hre.run(TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD, { + quiet: false, + solcVersion: hre.config.solidity.compilers[0].version, + }); + } + return _solcBuild; +} + +export async function zkCompile(hre: HardhatRuntimeEnvironment, source: string): Promise<{ data: string; abi: ContractInterface }> { + const zkSolcCompilerPath = hre.config.zksolc.settings.compilerPath; + const solcBuild = await getSolcBuild(hre); + + const input = JSON.stringify({ + language: "Solidity", + settings: { + optimizer: { + runs: 200, + enabled: false, + }, + outputSelection: { + "*": { + "*": ["abi"], + }, + }, + }, + sources: { + "tmp.sol": { + content: source, + }, + }, + }); + + const zkSolcData: string = await new Promise((resolve, reject) => { + const process = exec( + `${zkSolcCompilerPath} --standard-json --solc ${solcBuild.compilerPath}`, + { + maxBuffer: 1024 * 1024 * 500, + }, + (err, stdout, _stderr) => { + if (err !== null) { + return reject(err); + } + resolve(stdout); + }, + ); + + process.stdin?.write(input); + process.stdin?.end(); + }); + + const output = JSON.parse(zkSolcData); + if (!output["contracts"]) { + console.log(output); + throw Error("Could not compile contract"); + } + + const fileOutput = output["contracts"]["tmp.sol"]; + const contractOutput = fileOutput[Object.keys(fileOutput)[0]]; + const abi = contractOutput["abi"]; + const data = "0x" + contractOutput["evm"]["bytecode"]["object"]; + + return { data, abi }; +} From fa7075e0c971407c269212043da06a3791d10c44 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Thu, 20 Jul 2023 15:02:28 +0300 Subject: [PATCH 06/37] refactor: adjust SimulateTxAccessor.spec.ts for zksync --- test/accessors/SimulateTxAccessor.spec.ts | 30 +++++++++++++++++------ 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/test/accessors/SimulateTxAccessor.spec.ts b/test/accessors/SimulateTxAccessor.spec.ts index baaffb2e2..e61fe3f7c 100644 --- a/test/accessors/SimulateTxAccessor.spec.ts +++ b/test/accessors/SimulateTxAccessor.spec.ts @@ -1,6 +1,6 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; -import { deployContract, getSimulateTxAccessor, getSafeWithOwners, getCompatFallbackHandler } from "../utils/setup"; +import hre, { ethers } from "hardhat"; +import { deployContract, getSimulateTxAccessor, getSafeWithOwners, getCompatFallbackHandler, getWallets } from "../utils/setup"; import { buildContractCall, executeTxWithSigners } from "../../src/utils/execution"; describe("SimulateTxAccessor", () => { @@ -11,9 +11,9 @@ describe("SimulateTxAccessor", () => { } }`; - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const signers = await ethers.getSigners(); + const signers = getWallets(); const [user1] = signers; const accessor = await getSimulateTxAccessor(); const source = ` @@ -40,7 +40,14 @@ describe("SimulateTxAccessor", () => { }); describe("estimate", () => { - it("should enforce delegatecall", async () => { + it("should enforce delegatecall", async function () { + /** + * ## Test not applicable for zkSync, therefore should skip. + * The `SELFDESTRUCT` instruction is not supported + * @see https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#selfdestruct + */ + if (hre.network.zksync) this.skip(); + const { accessor, signers } = await setupTests(); const [user1] = signers; const killLib = await deployContract(user1, killLibSource); @@ -73,7 +80,7 @@ describe("SimulateTxAccessor", () => { const [user1, user2] = signers; const accessorAddress = await accessor.getAddress(); const safeAddress = await safe.getAddress(); - await user1.sendTransaction({ to: safeAddress, value: ethers.parseEther("1") }); + await (await user1.sendTransaction({ to: safeAddress, value: ethers.parseEther("1") })).wait(); const userBalance = await hre.ethers.provider.getBalance(user2.address); const tx = await buildContractCall(interactor, "sendAndReturnBalance", [user2.address, ethers.parseEther("1")], 0, true); const simulationData = accessor.interface.encodeFunctionData("simulate", [tx.to, tx.value, tx.data, tx.operation]); @@ -83,10 +90,17 @@ describe("SimulateTxAccessor", () => { userBalance + ethers.parseEther("1"), ); expect(simulation.success).to.be.true; - expect(simulation.estimate).to.be.lte(15000n); + expect(simulation.estimate.toNumber()).to.be.lte(hre.network.zksync ? 30000n : 15000n); }); - it("simulate selfdestruct", async () => { + it("simulate selfdestruct", async function () { + /** + * ## Test not applicable for zkSync, therefore should skip. + * The `SELFDESTRUCT` instruction is not supported + * @see https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#selfdestruct + */ + if (hre.network.zksync) this.skip(); + const { safe, accessor, simulator, signers } = await setupTests(); const [user1] = signers; const safeAddress = await safe.getAddress(); From 4b6e3ca3fc346ad5133d18577454fa99b4e3eaae Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Thu, 20 Jul 2023 18:21:28 +0300 Subject: [PATCH 07/37] refactor: adjust Safe.Execution.spec.ts for zksync --- test/core/Safe.Execution.spec.ts | 56 ++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/test/core/Safe.Execution.spec.ts b/test/core/Safe.Execution.spec.ts index 5cadef1a2..21a493b19 100644 --- a/test/core/Safe.Execution.spec.ts +++ b/test/core/Safe.Execution.spec.ts @@ -1,6 +1,6 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; -import { deployContract, getSafeWithOwners } from "../utils/setup"; +import hre, { ethers } from "hardhat"; +import { deployContract, getSafeWithOwners, getWallets } from "../utils/setup"; import { safeApproveHash, buildSignatureBytes, @@ -14,9 +14,9 @@ import { import { chainId } from "../utils/encoding"; describe("Safe", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; const setterSource = ` contract StorageSetter { @@ -55,21 +55,27 @@ describe("Safe", () => { const safeAddress = await safe.getAddress(); const tx = buildSafeTransaction({ to: safeAddress, safeTxGas: 1000000, nonce: await safe.nonce() }); const signatureBytes = buildSignatureBytes([await safeApproveHash(user1, safe, tx, true)]); - await expect( - safe.execTransaction( - tx.to, - tx.value, - tx.data, - tx.operation, - tx.safeTxGas, - tx.baseGas, - tx.gasPrice, - tx.gasToken, - tx.refundReceiver, - signatureBytes, - { gasLimit: 1000000 }, - ), - ).to.be.revertedWith("GS010"); + + const txPromise = safe.execTransaction( + tx.to, + tx.value, + tx.data, + tx.operation, + tx.safeTxGas, + tx.baseGas, + tx.gasPrice, + tx.gasToken, + tx.refundReceiver, + signatureBytes, + { gasLimit: 1000000 }, + ); + + // Reverted reason seems not properly returned by zkSync local node, though it is in fact GS010 when using debug_traceTransaction + if (hre.network.zksync) { + await expect((await txPromise).wait()).to.be.reverted; + } else { + await expect(txPromise).to.be.revertedWith("GS010"); + } }); it("should emit event for successful call execution", async () => { @@ -112,7 +118,7 @@ describe("Safe", () => { const [user1] = signers; const safeAddress = await safe.getAddress(); // Fund refund - await user1.sendTransaction({ to: safeAddress, value: 10000000 }); + await (await user1.sendTransaction({ to: safeAddress, value: 10000000 })).wait(); await expect(executeContractCallWithSigners(safe, reverter, "revert", [], [user1], false, { gasPrice: 1 })).to.emit( safe, "ExecutionFailure", @@ -199,7 +205,7 @@ describe("Safe", () => { refundReceiver: user2.address, }); - await user1.sendTransaction({ to: safeAddress, value: ethers.parseEther("1") }); + await (await user1.sendTransaction({ to: safeAddress, value: ethers.parseEther("1") })).wait(); const userBalance = await hre.ethers.provider.getBalance(user2.address); await expect(await hre.ethers.provider.getBalance(safeAddress)).to.be.eq(ethers.parseEther("1")); @@ -212,7 +218,8 @@ describe("Safe", () => { ).to.emit(safe, "ExecutionSuccess"); const receipt = await hre.ethers.provider.getTransactionReceipt(executedTx!.hash); const receiptLogs = receipt?.logs ?? []; - const logIndex = receiptLogs.length - 1; + // There are additional ETH transfer events on zkSync related to transaction fees + const logIndex = receiptLogs.length - (hre.network.zksync ? 2 : 1); const successEvent = safe.interface.decodeEventLog( "ExecutionSuccess", receiptLogs[logIndex].data, @@ -240,7 +247,7 @@ describe("Safe", () => { refundReceiver: user2.address, }); - await user1.sendTransaction({ to: safeAddress, value: ethers.parseEther("1") }); + await (await user1.sendTransaction({ to: safeAddress, value: ethers.parseEther("1") })).wait(); const userBalance = await hre.ethers.provider.getBalance(user2.address); await expect(await hre.ethers.provider.getBalance(safeAddress)).to.eq(ethers.parseEther("1")); @@ -253,7 +260,8 @@ describe("Safe", () => { ).to.emit(safe, "ExecutionFailure"); const receipt = await hre.ethers.provider.getTransactionReceipt(executedTx!.hash); const receiptLogs = receipt?.logs ?? []; - const logIndex = receiptLogs.length - 1; + // There are additional ETH transfer events on zkSync related to transaction fees + const logIndex = receiptLogs.length - (hre.network.zksync ? 2 : 1); const successEvent = safe.interface.decodeEventLog( "ExecutionFailure", receiptLogs[logIndex].data, From 247ffcb1105fa18d3b27a7ba4820d0254dcb9041 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Thu, 20 Jul 2023 18:44:56 +0300 Subject: [PATCH 08/37] refactor: adjust Safe.FallbackManager.spec.ts for zksync --- test/core/Safe.FallbackManager.spec.ts | 30 ++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/test/core/Safe.FallbackManager.spec.ts b/test/core/Safe.FallbackManager.spec.ts index 04cad84b4..806471cfc 100644 --- a/test/core/Safe.FallbackManager.spec.ts +++ b/test/core/Safe.FallbackManager.spec.ts @@ -1,11 +1,11 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; +import hre, { ethers } from "hardhat"; import { AddressZero } from "@ethersproject/constants"; -import { defaultTokenCallbackHandlerDeployment, deployContract, getSafeTemplate, getTokenCallbackHandler } from "../utils/setup"; +import { defaultTokenCallbackHandlerDeployment, deployContract, getSafeTemplate, getTokenCallbackHandler, getWallets } from "../utils/setup"; import { executeContractCallWithSigners } from "../../src/utils/execution"; describe("FallbackManager", () => { - const setupWithTemplate = deployments.createFixture(async ({ deployments }) => { + const setupWithTemplate = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); const source = ` contract Mirror { @@ -17,7 +17,7 @@ describe("FallbackManager", () => { return msg.data; } }`; - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; const mirror = await deployContract(user1, source); return { @@ -42,7 +42,9 @@ describe("FallbackManager", () => { ).to.be.eq("0x" + "".padStart(64, "0")); // Setup Safe - await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", handler.address, AddressZero, 0, AddressZero); + await ( + await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", handler.address, AddressZero, 0, AddressZero) + ).wait(); // Check fallback handler await expect( @@ -59,7 +61,7 @@ describe("FallbackManager", () => { const [user1, user2] = signers; // Setup Safe - await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", AddressZero, AddressZero, 0, AddressZero); + await (await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", AddressZero, AddressZero, 0, AddressZero)).wait(); // Check fallback handler await expect( @@ -88,7 +90,7 @@ describe("FallbackManager", () => { const [user1, user2] = signers; // Setup Safe - await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", AddressZero, AddressZero, 0, AddressZero); + await (await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", AddressZero, AddressZero, 0, AddressZero)).wait(); // Check event await expect(executeContractCallWithSigners(safe, safe, "setFallbackHandler", [handler.address], [user1])) @@ -110,7 +112,9 @@ describe("FallbackManager", () => { await expect(safeHandler.onERC1155Received.staticCall(AddressZero, AddressZero, 0, 0, "0x")).to.be.rejected; // Setup Safe - await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", handler.address, AddressZero, 0, AddressZero); + await ( + await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", handler.address, AddressZero, 0, AddressZero) + ).wait(); // Check callbacks expect(await safeHandler.onERC1155Received.staticCall(AddressZero, AddressZero, 0, 0, "0x")).to.be.eq("0xf23a6e61"); @@ -121,7 +125,9 @@ describe("FallbackManager", () => { const mirrorAddress = await mirror.getAddress(); const [user1, user2] = signers; // Setup Safe - await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", mirrorAddress, AddressZero, 0, AddressZero); + await ( + await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", mirrorAddress, AddressZero, 0, AddressZero) + ).wait(); const tx = { to: await safe.getAddress(), @@ -144,7 +150,9 @@ describe("FallbackManager", () => { const mirrorAddress = await mirror.getAddress(); const [user1, user2] = signers; // Setup Safe - await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", mirrorAddress, AddressZero, 0, AddressZero); + await ( + await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", mirrorAddress, AddressZero, 0, AddressZero) + ).wait(); const tx = { to: await safe.getAddress(), @@ -172,7 +180,7 @@ describe("FallbackManager", () => { const { safe, signers } = await setupWithTemplate(); const [user1] = signers; // Setup Safe - await safe.setup([user1.address], 1, AddressZero, "0x", AddressZero, AddressZero, 0, AddressZero); + await (await safe.setup([user1.address], 1, AddressZero, "0x", AddressZero, AddressZero, 0, AddressZero)).wait(); // The transaction execution function doesn't bubble up revert messages so we check for a generic transaction fail code GS013 await expect( From af4f1294ecb8dee2d0b2cb1ea22c7178c7775ddb Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Thu, 20 Jul 2023 19:32:20 +0300 Subject: [PATCH 09/37] refactor: adjust Safe.GuardManager.spec.ts for zksync --- test/core/Safe.GuardManager.spec.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/core/Safe.GuardManager.spec.ts b/test/core/Safe.GuardManager.spec.ts index c760b258e..c190de2f7 100644 --- a/test/core/Safe.GuardManager.spec.ts +++ b/test/core/Safe.GuardManager.spec.ts @@ -1,7 +1,7 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; +import hre, { ethers } from "hardhat"; import { AddressZero } from "@ethersproject/constants"; -import { getMock, getSafeWithOwners } from "../utils/setup"; +import { getMock, getSafeWithOwners, getWallets } from "../utils/setup"; import { buildContractCall, buildSafeTransaction, @@ -17,18 +17,18 @@ import { chainId } from "../utils/encoding"; describe("GuardManager", () => { const GUARD_STORAGE_SLOT = ethers.keccak256(ethers.toUtf8Bytes("guard_manager.guard.address")); - const setupWithTemplate = deployments.createFixture(async ({ deployments }) => { + const setupWithTemplate = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); const validGuardMock = await getMock(); const validGuardMockAddress = await validGuardMock.getAddress(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [, user2] = signers; const guardContract = await hre.ethers.getContractAt("Guard", AddressZero); const guardEip165Calldata = guardContract.interface.encodeFunctionData("supportsInterface", ["0x945b8148"]); - await validGuardMock.givenCalldataReturnBool(guardEip165Calldata, true); + await (await validGuardMock.givenCalldataReturnBool(guardEip165Calldata, true)).wait(); const safe = await getSafeWithOwners([user2.address]); - await executeContractCallWithSigners(safe, safe, "setGuard", [validGuardMockAddress], [user2]); + await (await executeContractCallWithSigners(safe, safe, "setGuard", [validGuardMockAddress], [user2])).wait(); return { safe, @@ -73,7 +73,7 @@ describe("GuardManager", () => { const validGuardMockAddress = await validGuardMock.getAddress(); const safe = await getSafeWithOwners([user1.address]); - await executeContractCallWithSigners(safe, safe, "setGuard", [validGuardMockAddress], [user1]); + await (await executeContractCallWithSigners(safe, safe, "setGuard", [validGuardMockAddress], [user1])).wait(); // Check guard await expect(await hre.ethers.provider.getStorage(await safe.getAddress(), GUARD_STORAGE_SLOT)).to.be.eq( @@ -163,7 +163,7 @@ describe("GuardManager", () => { signatureBytes, user1.address, ]); - await validGuardMock.givenCalldataRevertWithMessage(checkTxData, "Computer says Nah"); + await (await validGuardMock.givenCalldataRevertWithMessage(checkTxData, "Computer says Nah")).wait(); const checkExecData = guardInterface.encodeFunctionData("checkAfterExecution", [ calculateSafeTransactionHash(safeAddress, safeTx, await chainId()), true, @@ -171,7 +171,7 @@ describe("GuardManager", () => { await expect(executeTx(safe, safeTx, [signature])).to.be.revertedWith("Computer says Nah"); - await validGuardMock.reset(); + await (await validGuardMock.reset()).wait(); await expect(executeTx(safe, safeTx, [signature])).to.emit(safe, "ExecutionSuccess"); @@ -211,11 +211,11 @@ describe("GuardManager", () => { calculateSafeTransactionHash(safeAddress, safeTx, await chainId()), true, ]); - await validGuardMock.givenCalldataRevertWithMessage(checkExecData, "Computer says Nah"); + await (await validGuardMock.givenCalldataRevertWithMessage(checkExecData, "Computer says Nah")).wait(); await expect(executeTx(safe, safeTx, [signature])).to.be.revertedWith("Computer says Nah"); - await validGuardMock.reset(); + await (await validGuardMock.reset()).wait(); await expect(executeTx(safe, safeTx, [signature])).to.emit(safe, "ExecutionSuccess"); From 38c84a4b024db2f09fae6b42c28262ded79ec858 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Fri, 21 Jul 2023 10:03:08 +0300 Subject: [PATCH 10/37] refactor: adjust Safe.Incoming.spec.ts for zksync --- test/core/Safe.Incoming.spec.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/test/core/Safe.Incoming.spec.ts b/test/core/Safe.Incoming.spec.ts index aa91277e8..4e0f53c6d 100644 --- a/test/core/Safe.Incoming.spec.ts +++ b/test/core/Safe.Incoming.spec.ts @@ -1,9 +1,9 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; -import { deployContract, getSafeWithOwners } from "../utils/setup"; +import hre, { ethers } from "hardhat"; +import { deployContract, getSafeWithOwners, getWallets } from "../utils/setup"; describe("Safe", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); const source = ` contract Test { @@ -18,7 +18,7 @@ describe("Safe", () => { require(success); } }`; - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; return { safe: await getSafeWithOwners([user1.address]), @@ -84,7 +84,14 @@ describe("Safe", () => { } = await setupTests(); const safeAddress = await safe.getAddress(); - await expect(user1.sendTransaction({ to: safeAddress, value: 23, data: "0xbaddad" })).to.be.reverted; + if (hre.network.zksync) { + await expect((await user1.sendTransaction({ to: safeAddress, value: 23, data: "0xbaddad", gasLimit: 150000 })).wait()).to + .be.reverted; + } else { + await expect(user1.sendTransaction({ to: safeAddress, value: 23, data: "0xbaddad" })).to.be.revertedWith( + "fallback function is not payable and was called with value 23", + ); + } }); }); }); From 664d58558b750c8e787a29fa9b911d7688453fca Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Fri, 21 Jul 2023 10:03:47 +0300 Subject: [PATCH 11/37] refactor: adjust Safe.ModuleManager.spec.ts for zksync --- test/core/Safe.ModuleManager.spec.ts | 44 ++++++++++++++++------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/test/core/Safe.ModuleManager.spec.ts b/test/core/Safe.ModuleManager.spec.ts index d932faab7..86b1a73c5 100644 --- a/test/core/Safe.ModuleManager.spec.ts +++ b/test/core/Safe.ModuleManager.spec.ts @@ -1,14 +1,14 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; +import hre, { ethers } from "hardhat"; import { AddressZero } from "@ethersproject/constants"; -import { getSafeWithOwners, getMock } from "../utils/setup"; +import { getSafeWithOwners, getMock, getWallets } from "../utils/setup"; import { executeContractCallWithSigners } from "../../src/utils/execution"; import { AddressOne } from "../../src/utils/constants"; describe("ModuleManager", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; return { @@ -50,7 +50,7 @@ describe("ModuleManager", () => { signers: [user1, user2], } = await setupTests(); // Use module for execution to see error - await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1])).wait(); await expect(executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1])).to.revertedWith("GS013"); }); @@ -159,9 +159,9 @@ describe("ModuleManager", () => { safe, signers: [user1, user2], } = await setupTests(); - await executeContractCallWithSigners(safe, safe, "enableModule", [user1.address], [user1]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user1.address], [user1])).wait(); await expect(await safe.isModuleEnabled(user1.address)).to.be.true; - await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1])).wait(); await expect(await safe.isModuleEnabled(user2.address)).to.be.true; await expect(await safe.getModulesPaginated(AddressOne, 10)).to.be.deep.equal([[user2.address, user1.address], AddressOne]); @@ -208,9 +208,12 @@ describe("ModuleManager", () => { } = await setupTests(); const mockAddress = await mock.getAddress(); const user2Safe = safe.connect(user2); - await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1])).wait(); - await expect(user2Safe.execTransactionFromModule(mockAddress, 0, "0xbaddad", 0)) + // Use manual gasLimit for zkSync because gas estimation fails for this function on zkSync, though transaction executed successfully + await expect( + user2Safe.execTransactionFromModule(mockAddress, 0, "0xbaddad", 0, { gasLimit: hre.network.zksync ? 200_000 : undefined }), + ) .to.emit(safe, "ExecutionFromModuleSuccess") .withArgs(user2.address); expect(await mock.invocationCountForCalldata.staticCall("0xbaddad")).to.equal(1n); @@ -224,7 +227,7 @@ describe("ModuleManager", () => { } = await setupTests(); const mockAddress = await mock.getAddress(); const user2Safe = safe.connect(user2); - await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1])).wait(); await mock.givenAnyRevert(); await expect(user2Safe.execTransactionFromModule(mockAddress, 0, "0xbaddad", 0)) @@ -262,7 +265,7 @@ describe("ModuleManager", () => { } = await setupTests(); const mockAddress = await mock.getAddress(); const user2Safe = safe.connect(user2); - await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1])).wait(); await mock.givenAnyRevert(); await expect(user2Safe.execTransactionFromModuleReturnData(mockAddress, 0, "0xbaddad", 0)) @@ -278,9 +281,14 @@ describe("ModuleManager", () => { } = await setupTests(); const mockAddress = await mock.getAddress(); const user2Safe = safe.connect(user2); - await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1])).wait(); - await expect(user2Safe.execTransactionFromModuleReturnData(mockAddress, 0, "0xbaddad", 0)) + // Use manual gasLimit for zkSync because gas estimation fails for this function on zkSync, though transaction executed successfully + await expect( + user2Safe.execTransactionFromModuleReturnData(mockAddress, 0, "0xbaddad", 0, { + gasLimit: hre.network.zksync ? 200_000 : undefined, + }), + ) .to.emit(safe, "ExecutionFromModuleSuccess") .withArgs(user2.address); expect(await mock.invocationCountForCalldata.staticCall("0xbaddad")).to.equal(1n); @@ -294,9 +302,9 @@ describe("ModuleManager", () => { } = await setupTests(); const mockAddress = await mock.getAddress(); const user2Safe = safe.connect(user2); - await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1])).wait(); - await mock.givenCalldataReturn("0xbaddad", "0xdeaddeed"); + await (await mock.givenCalldataReturn("0xbaddad", "0xdeaddeed")).wait(); await expect(await user2Safe.execTransactionFromModuleReturnData.staticCall(mockAddress, 0, "0xbaddad", 0)).to.be.deep.eq([ true, "0xdeaddeed", @@ -311,9 +319,9 @@ describe("ModuleManager", () => { } = await setupTests(); const mockAddress = await mock.getAddress(); const user2Safe = safe.connect(user2); - await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1])).wait(); - await mock.givenCalldataRevertWithMessage("0xbaddad", "Some random message"); + await (await mock.givenCalldataRevertWithMessage("0xbaddad", "Some random message")).wait(); await expect(await user2Safe.execTransactionFromModuleReturnData.staticCall(mockAddress, 0, "0xbaddad", 0)).to.be.deep.eq([ false, "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000013536f6d652072616e646f6d206d65737361676500000000000000000000000000", @@ -334,7 +342,7 @@ describe("ModuleManager", () => { } = await setupTests(); await expect(safe.getModulesPaginated(AddressZero, 1)).to.be.reverted; - await executeContractCallWithSigners(safe, safe, "enableModule", [user1.address], [user1]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user1.address], [user1])).wait(); expect(await safe.getModulesPaginated(user1.address, 1)).to.be.deep.equal([[], AddressOne]); await expect(safe.getModulesPaginated(user2.address, 1)).to.be.revertedWith("GS105"); }); From ed6fc55862a9e62bed4aa4c7b4ef60826fcbf629 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Fri, 21 Jul 2023 10:04:34 +0300 Subject: [PATCH 12/37] refactor: adjust Safe.OwnerManager.spec.ts for zksync --- test/core/Safe.OwnerManager.spec.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/core/Safe.OwnerManager.spec.ts b/test/core/Safe.OwnerManager.spec.ts index 86a05762a..4a8e56c43 100644 --- a/test/core/Safe.OwnerManager.spec.ts +++ b/test/core/Safe.OwnerManager.spec.ts @@ -1,14 +1,14 @@ import { expect } from "chai"; -import { deployments, ethers } from "hardhat"; +import hre, { ethers } from "hardhat"; import { AddressZero } from "@ethersproject/constants"; -import { getSafeWithOwners } from "../utils/setup"; +import { getSafeWithOwners, getWallets } from "../utils/setup"; import { executeContractCallWithSigners } from "../../src/utils/execution"; import { AddressOne } from "../../src/utils/constants"; describe("OwnerManager", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; return { safe: await getSafeWithOwners([user1.address]), @@ -63,7 +63,7 @@ describe("OwnerManager", () => { safe, signers: [user1, user2], } = await setupTests(); - await executeContractCallWithSigners(safe, safe, "addOwnerWithThreshold", [user2.address, 1], [user1]); + await (await executeContractCallWithSigners(safe, safe, "addOwnerWithThreshold", [user2.address, 1], [user1])).wait(); await expect(executeContractCallWithSigners(safe, safe, "addOwnerWithThreshold", [user2.address, 1], [user1])).to.revertedWith( "GS013", @@ -225,8 +225,8 @@ describe("OwnerManager", () => { safe, signers: [user1, user2, user3], } = await setupTests(); - await executeContractCallWithSigners(safe, safe, "addOwnerWithThreshold", [user2.address, 1], [user1]); - await executeContractCallWithSigners(safe, safe, "addOwnerWithThreshold", [user3.address, 2], [user1]); + await (await executeContractCallWithSigners(safe, safe, "addOwnerWithThreshold", [user2.address, 1], [user1])).wait(); + await (await executeContractCallWithSigners(safe, safe, "addOwnerWithThreshold", [user3.address, 2], [user1])).wait(); await expect(await safe.getOwners()).to.be.deep.equal([user3.address, user2.address, user1.address]); await expect(await safe.getThreshold()).to.be.deep.eq(2n); await expect(await safe.isOwner(user1.address)).to.be.true; From 51acbb7db5a642c370645c97b1a64156fbe3cf6b Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Fri, 21 Jul 2023 10:04:58 +0300 Subject: [PATCH 13/37] refactor: adjust Safe.Setup.spec.ts for zksync --- test/core/Safe.Setup.spec.ts | 100 ++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 38 deletions(-) diff --git a/test/core/Safe.Setup.spec.ts b/test/core/Safe.Setup.spec.ts index 83e2af1ae..a8aa66dfd 100644 --- a/test/core/Safe.Setup.spec.ts +++ b/test/core/Safe.Setup.spec.ts @@ -1,16 +1,16 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; +import hre, { ethers } from "hardhat"; import { AddressZero } from "@ethersproject/constants"; -import { deployContract, getMock, getSafeSingleton, getSafeTemplate } from "../utils/setup"; +import { deployContract, getMock, getSafeSingleton, getSafeTemplate, getWallets } from "../utils/setup"; import { calculateSafeDomainSeparator } from "../../src/utils/execution"; import { AddressOne } from "../../src/utils/constants"; import { chainId, encodeTransfer } from "../utils/encoding"; describe("Safe", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); return { template: await getSafeTemplate(), mock: await getMock(), @@ -79,16 +79,18 @@ describe("Safe", () => { template, signers: [user1, user2, user3], } = await setupTests(); - await template.setup( - [user1.address, user2.address, user3.address], - 2, - AddressZero, - "0x", - AddressZero, - AddressZero, - 0, - AddressZero, - ); + await ( + await template.setup( + [user1.address, user2.address, user3.address], + 2, + AddressZero, + "0x", + AddressZero, + AddressZero, + 0, + AddressZero, + ) + ).wait(); await expect( template.setup( [user1.address, user2.address, user3.address], @@ -304,7 +306,16 @@ describe("Safe", () => { ).to.be.revertedWith("GS011"); }); - it("should work with ether payment to deployer", async () => { + /** + * ## Skip for zkSync, due to Expected to fail with official SafeL2.sol due to the use of the unsupported send() function in the handlePayment() + * ## Expected to pass when send() will be replaced with call() + * ## Or after a protocol upgrade (see link2) + * @see https://era.zksync.io/docs/dev/building-on-zksync/contracts/differences-with-ethereum.html#using-call-over-send-or-transfer + * @see https://twitter.com/zksync/status/1644459406828924934 + */ + it("should work with ether payment to deployer", async function () { + if (hre.network.zksync) this.skip(); + const { template, signers: [user1, user2, user3], @@ -330,7 +341,16 @@ describe("Safe", () => { await expect(userBalance < (await hre.ethers.provider.getBalance(user1.address))).to.be.true; }); - it("should work with ether payment to account", async () => { + /** + * ## Skip for zkSync, due to Expected to fail with official SafeL2.sol due to the use of the unsupported send() function in the handlePayment() + * ## Expected to pass when send() will be replaced with call() + * ## Or after a protocol upgrade (see link2) + * @see https://era.zksync.io/docs/dev/building-on-zksync/contracts/differences-with-ethereum.html#using-call-over-send-or-transfer + * @see https://twitter.com/zksync/status/1644459406828924934 + */ + it("should work with ether payment to account", async function () { + if (hre.network.zksync) this.skip(); + const { template, signers: [user1, user2, user3], @@ -393,17 +413,19 @@ describe("Safe", () => { const payment = 133742; const transferData = encodeTransfer(user1.address, payment); - await mock.givenCalldataReturnBool(transferData, true); - await template.setup( - [user1.address, user2.address, user3.address], - 2, - AddressZero, - "0x", - AddressZero, - mockAddress, - payment, - AddressZero, - ); + await (await mock.givenCalldataReturnBool(transferData, true)).wait(); + await ( + await template.setup( + [user1.address, user2.address, user3.address], + 2, + AddressZero, + "0x", + AddressZero, + mockAddress, + payment, + AddressZero, + ) + ).wait(); expect(await mock.invocationCountForCalldata.staticCall(transferData)).to.eq(1n); @@ -420,17 +442,19 @@ describe("Safe", () => { const payment = 133742; const transferData = encodeTransfer(user2.address, payment); - await mock.givenCalldataReturnBool(transferData, true); - await template.setup( - [user1.address, user2.address, user3.address], - 2, - AddressZero, - "0x", - AddressZero, - mockAddress, - payment, - user2.address, - ); + await (await mock.givenCalldataReturnBool(transferData, true)).wait(); + await ( + await template.setup( + [user1.address, user2.address, user3.address], + 2, + AddressZero, + "0x", + AddressZero, + mockAddress, + payment, + user2.address, + ) + ).wait(); expect(await mock.invocationCountForCalldata.staticCall(transferData)).to.eq(1n); From e25c11c3fe6035317a7380f7201b0908225bbd92 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Fri, 21 Jul 2023 10:05:22 +0300 Subject: [PATCH 14/37] refactor: adjust Safe.Signatures.spec.ts for zksync --- test/core/Safe.Signatures.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/core/Safe.Signatures.spec.ts b/test/core/Safe.Signatures.spec.ts index b1ee3960d..b18506548 100644 --- a/test/core/Safe.Signatures.spec.ts +++ b/test/core/Safe.Signatures.spec.ts @@ -1,7 +1,7 @@ -import { getCompatFallbackHandler } from "./../utils/setup"; +import { getCompatFallbackHandler, getWallets } from "./../utils/setup"; import { calculateSafeMessageHash, signHash, buildContractSignature } from "./../../src/utils/execution"; import { expect } from "chai"; -import { deployments, ethers } from "hardhat"; +import hre, { ethers } from "hardhat"; import { AddressZero } from "@ethersproject/constants"; import { getSafeTemplate, getSafeWithOwners } from "../utils/setup"; import { @@ -23,7 +23,7 @@ describe("Safe", () => { await deployments.fixture(); const compatFallbackHandler = await getCompatFallbackHandler(); const compatFallbackHandlerAddress = await compatFallbackHandler.getAddress(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; const safe = await getSafeWithOwners([user1.address], 1, compatFallbackHandlerAddress); const safeAddress = await safe.getAddress(); From 71006e042758e46703f7645cf6b54dc11c6c8748 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Fri, 21 Jul 2023 10:07:09 +0300 Subject: [PATCH 15/37] refactor: adjust Safe.StorageAccessible.spec.ts for zksync --- src/utils/execution.ts | 2 +- test/core/Safe.StorageAccessible.spec.ts | 19 +++++++++---- test/utils/contracts.ts | 36 ++++++++++++++++++++++-- test/utils/setup.ts | 14 ++------- 4 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/utils/execution.ts b/src/utils/execution.ts index 67cf797ba..aae0b273d 100644 --- a/src/utils/execution.ts +++ b/src/utils/execution.ts @@ -85,7 +85,7 @@ export const safeApproveHash = async ( const safeAddress = await safe.getAddress(); const typedDataHash = calculateSafeTransactionHash(safeAddress, safeTx, chainId); const signerSafe = safe.connect(signer); - await signerSafe.approveHash(typedDataHash); + await (await signerSafe.approveHash(typedDataHash)).wait(); } const signerAddress = await signer.getAddress(); return { diff --git a/test/core/Safe.StorageAccessible.spec.ts b/test/core/Safe.StorageAccessible.spec.ts index 700800439..bc3e8652e 100644 --- a/test/core/Safe.StorageAccessible.spec.ts +++ b/test/core/Safe.StorageAccessible.spec.ts @@ -1,13 +1,13 @@ import { expect } from "chai"; -import { deployments, ethers } from "hardhat"; -import { getSafeSingleton, getSafeWithOwners } from "../utils/setup"; +import hre, { ethers } from "hardhat"; +import { getSafeSingleton, getSafeWithOwners, getWallets } from "../utils/setup"; import { killLibContract } from "../utils/contracts"; describe("StorageAccessible", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const [user1, user2] = await ethers.getSigners(); - const killLib = await killLibContract(user1); + const [user1, user2] = await getWallets(); + const killLib = await killLibContract(user1, hre.network.zksync); return { safe: await getSafeWithOwners([user1.address, user2.address], 1), killLib, @@ -34,7 +34,14 @@ describe("StorageAccessible", () => { }); describe("simulateAndRevert", () => { - it("should revert changes", async () => { + it("should revert changes", async function () { + /** + * ## Test not applicable for zkSync, therefore should skip. + * The `SELFDESTRUCT` instruction is not supported + * @see https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#selfdestruct + */ + if (hre.network.zksync) this.skip(); + const { safe, killLib } = await setupTests(); const killLibAddress = await killLib.getAddress(); diff --git a/test/utils/contracts.ts b/test/utils/contracts.ts index 05be3af2e..e5e1413aa 100644 --- a/test/utils/contracts.ts +++ b/test/utils/contracts.ts @@ -32,6 +32,38 @@ contract Test { revert("Why are you doing this?"); } }`; -export const killLibContract = async (deployer: Signer) => { - return await deployContract(deployer, killLibSource); + +export const killLibSourceZk = ` +contract Test { + function expose() public returns (address handler) { + bytes32 slot = 0x6c9a6c4a39284e37ed1cf53d337577d14212a4870fb976a4366c693b939918d5; + assembly { + handler := sload(slot) + } + } + + function estimate(address to, bytes memory data) public returns (uint256) { + uint256 startGas = gasleft(); + (bool success,) = to.call{ gas: gasleft() }(data); + require(success, "Transaction failed"); + return startGas - gasleft(); + } + + address singleton; + uint256 public value = 0; + function updateAndGet() public returns (uint256) { + value++; + return value; + } + + function trever() public returns (address handler) { + revert("Why are you doing this?"); + } +}`; + +export const killLibContract = async (deployer: Signer, zkSync?: boolean) => { + // selfdestruct is not supported by zkSync and compilation cannot be completed, therefore we have to ditch it + if (zkSync) return deployContract(deployer, killLibSourceZk); + + return deployContract(deployer, killLibSource); }; diff --git a/test/utils/setup.ts b/test/utils/setup.ts index ca40eb192..250c2b7b8 100644 --- a/test/utils/setup.ts +++ b/test/utils/setup.ts @@ -5,7 +5,6 @@ import solc from "solc"; import * as zk from "zksync-web3"; import { logGas } from "../../src/utils/execution"; import { safeContractUnderTest } from "./config"; -import { Deployer } from "@matterlabs/hardhat-zksync-deploy"; import { getZkContractFactoryByName, zkCompile } from "./zk"; import { getRandomIntAsString } from "./numbers"; import { Safe, SafeL2 } from "../../typechain-types"; @@ -103,16 +102,9 @@ export const migrationContract = async () => { }; export const getMock = async () => { - if (!hre.network.zksync) { - const Mock = await hre.ethers.getContractFactory("MockContract"); - return Mock.deploy(); - } else { - const deployer = new Deployer(hre, getWallets()[0] as zk.Wallet); - const artifact = await deployer.loadArtifact("MockContract"); - const contract = await deployer.deploy(artifact); - await contract.deployTransaction.wait(); - return contract; - } + const contractFactory = await getContractFactoryByName("MockContract"); + const contract = await contractFactory.deploy(); + return contract.deployed(); }; export const getContractFactoryByName = async (contractName: string) => { From ca587349d1329fbedfd8966f0975d1e04cea7181 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Fri, 21 Jul 2023 13:50:18 +0300 Subject: [PATCH 16/37] refactor: adjust prediction of create2 address for zksync --- src/utils/proxies.ts | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/utils/proxies.ts b/src/utils/proxies.ts index c370563c8..c0c53c86f 100644 --- a/src/utils/proxies.ts +++ b/src/utils/proxies.ts @@ -1,10 +1,20 @@ import { ethers, BigNumberish } from "ethers"; +import hre from "hardhat"; +import * as zk from "zksync-web3"; import { SafeProxyFactory } from "../../typechain-types"; export const calculateProxyAddress = async (factory: SafeProxyFactory, singleton: string, inititalizer: string, nonce: number | string) => { + const salt = ethers.solidityPackedKeccak256(["bytes32", "uint256"], [ethers.solidityPackedKeccak256(["bytes"], [inititalizer]), nonce]); + + if (hre.network.zksync) { + const proxyCreationCode = (await hre.artifacts.readArtifact("SafeProxy")).deployedBytecode; + const bytecodehash = zk.utils.hashBytecode(proxyCreationCode); + const input = new ethers.utils.AbiCoder().encode(["address"], [singleton]); + return zk.utils.create2Address(factory.address, bytecodehash, salt, input); + } + const factoryAddress = await factory.getAddress(); const deploymentCode = ethers.solidityPacked(["bytes", "uint256"], [await factory.proxyCreationCode(), singleton]); - const salt = ethers.solidityPackedKeccak256(["bytes32", "uint256"], [ethers.solidityPackedKeccak256(["bytes"], [inititalizer]), nonce]); return ethers.getCreate2Address(factoryAddress, salt, ethers.keccak256(deploymentCode)); }; @@ -26,11 +36,19 @@ export const calculateChainSpecificProxyAddress = async ( nonce: number | string, chainId: BigNumberish, ) => { - const factoryAddress = await factory.getAddress(); - const deploymentCode = ethers.solidityPacked(["bytes", "uint256"], [await factory.proxyCreationCode(), singleton]); const salt = ethers.solidityPackedKeccak256( ["bytes32", "uint256", "uint256"], [ethers.solidityPackedKeccak256(["bytes"], [inititalizer]), nonce, chainId], ); + + if (hre.network.zksync) { + const proxyCreationCode = (await hre.artifacts.readArtifact("SafeProxy")).deployedBytecode; + const bytecodehash = zk.utils.hashBytecode(proxyCreationCode); + const input = new ethers.utils.AbiCoder().encode(["address"], [singleton]); + return zk.utils.create2Address(factory.address, bytecodehash, salt, input); + } + + const factoryAddress = await factory.getAddress(); + const deploymentCode = ethers.solidityPacked(["bytes", "uint256"], [await factory.proxyCreationCode(), singleton]); return ethers.getCreate2Address(factoryAddress, salt, ethers.keccak256(deploymentCode)); }; From 7053ee5514b85ce15ca46fe490cb8cfc59302cae Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Fri, 21 Jul 2023 13:50:31 +0300 Subject: [PATCH 17/37] refactor: adjust Proxy.spec.ts and ProxyFactory.spec.ts for zksync --- test/factory/Proxy.spec.ts | 4 ++-- test/factory/ProxyFactory.spec.ts | 24 +++++++++++++++--------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/test/factory/Proxy.spec.ts b/test/factory/Proxy.spec.ts index a60d368c8..17098bb8e 100644 --- a/test/factory/Proxy.spec.ts +++ b/test/factory/Proxy.spec.ts @@ -1,11 +1,11 @@ import { expect } from "chai"; -import hre from "hardhat"; import { AddressZero } from "@ethersproject/constants"; +import { getContractFactoryByName } from "../utils/setup"; describe("Proxy", () => { describe("constructor", () => { it("should revert with invalid singleton address", async () => { - const Proxy = await hre.ethers.getContractFactory("SafeProxy"); + const Proxy = await getContractFactoryByName("SafeProxy"); await expect(Proxy.deploy(AddressZero)).to.be.revertedWith("Invalid singleton address provided"); }); }); diff --git a/test/factory/ProxyFactory.spec.ts b/test/factory/ProxyFactory.spec.ts index 15232aa44..b6f94fd53 100644 --- a/test/factory/ProxyFactory.spec.ts +++ b/test/factory/ProxyFactory.spec.ts @@ -1,7 +1,7 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; +import hre, { ethers } from "hardhat"; import { Contract } from "ethers"; -import { deployContract, getFactory, getMock, getSafeWithOwners, getSafeProxyRuntimeCode } from "../utils/setup"; +import { deployContract, getFactory, getMock, getSafeWithOwners, getSafeProxyRuntimeCode, getWallets } from "../utils/setup"; import { AddressZero } from "@ethersproject/constants"; import { calculateChainSpecificProxyAddress, calculateProxyAddress, calculateProxyAddressWithCallback } from "../../src/utils/proxies"; import { chainId } from "./../utils/encoding"; @@ -31,9 +31,9 @@ describe("ProxyFactory", () => { } }`; - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; const singleton = await deployContract(user1, SINGLETON_SOURCE); return { @@ -58,7 +58,10 @@ describe("ProxyFactory", () => { it("should revert with invalid initializer", async () => { const { factory, singleton } = await setupTests(); const singletonAddress = await singleton.getAddress(); - await expect(factory.createProxyWithNonce(singletonAddress, "0x42baddad", saltNonce)).to.be.revertedWithoutReason(); + // TODO: look at revertedWithoutReason + await expect(factory.createProxyWithNonce(singletonAddress, "0x42baddad", saltNonce)).to.be.revertedWith( + hre.network.zksync ? "execution reverted" : "Transaction reverted without a reason", + ); }); it("should emit event without initializing", async () => { @@ -121,7 +124,10 @@ describe("ProxyFactory", () => { const { factory, singleton } = await setupTests(); const singletonAddress = await singleton.getAddress(); - await expect(factory.createProxyWithNonce(singletonAddress, "0x42baddad", saltNonce)).to.be.revertedWithoutReason(); + // TODO: look at revertedWithoutReason + await expect(factory.createProxyWithNonce(singletonAddress, "0x42baddad", saltNonce)).to.be.revertedWith( + hre.network.zksync ? "execution reverted" : "Transaction reverted without a reason", + ); }); it("should emit event without initializing", async () => { @@ -165,7 +171,7 @@ describe("ProxyFactory", () => { const proxyAddress = await calculateChainSpecificProxyAddress(factory, singletonAddress, initCode, saltNonce, await chainId()); expect(await provider.getCode(proxyAddress)).to.eq("0x"); - await factory.createChainSpecificProxyWithNonce(singletonAddress, initCode, saltNonce); + await (await factory.createChainSpecificProxyWithNonce(singletonAddress, initCode, saltNonce)).wait(); expect(await provider.getCode(proxyAddress)).to.be.eq(await getSafeProxyRuntimeCode()); }); @@ -210,13 +216,13 @@ describe("ProxyFactory", () => { const singletonAddress = await singleton.getAddress(); const mockAddress = await mock.getAddress(); const initCode = "0x"; - await mock.givenAnyRevert(); + await (await mock.givenAnyRevert()).wait(); await expect( factory.createProxyWithCallback(singletonAddress, initCode, saltNonce, mockAddress), "Should fail if callback fails", ).to.be.reverted; - await mock.reset(); + await (await mock.reset()).wait(); // Should be successfull now const proxyAddress = await calculateProxyAddressWithCallback(factory, singletonAddress, initCode, saltNonce, mockAddress); await expect(factory.createProxyWithCallback(singletonAddress, initCode, saltNonce, mockAddress)) From 0bdfb380128879b00ba79a8c85b4b571bea738ea Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Fri, 21 Jul 2023 13:50:31 +0300 Subject: [PATCH 18/37] refactor: adjust guard tests for zksync --- test/guards/DebugTransactionGuard.spec.ts | 12 ++++++------ .../guards/DelegateCallTransactionGuard.spec.ts | 14 +++++++------- test/guards/OnlyOwnersGuard.spec.ts | 12 ++++++------ test/guards/ReentrancyTransactionGuard.spec.ts | 17 ++++++++--------- 4 files changed, 27 insertions(+), 28 deletions(-) diff --git a/test/guards/DebugTransactionGuard.spec.ts b/test/guards/DebugTransactionGuard.spec.ts index 3d4bf1fc4..c98934c2b 100644 --- a/test/guards/DebugTransactionGuard.spec.ts +++ b/test/guards/DebugTransactionGuard.spec.ts @@ -1,21 +1,21 @@ import { signHash } from "./../../src/utils/execution"; import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; -import { getMock, getSafeWithOwners } from "../utils/setup"; +import hre, { ethers } from "hardhat"; +import { getContractFactoryByName, getMock, getSafeWithOwners, getWallets } from "../utils/setup"; import { buildSafeTransaction, calculateSafeTransactionHash, executeContractCallWithSigners, executeTx } from "../../src/utils/execution"; import { chainId } from "../utils/encoding"; describe("DebugTransactionGuard", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; const safe = await getSafeWithOwners([user1.address]); - const guardFactory = await hre.ethers.getContractFactory("DebugTransactionGuard"); + const guardFactory = await getContractFactoryByName("DebugTransactionGuard"); const guard = await guardFactory.deploy(); const guardAddress = await guard.getAddress(); const mock = await getMock(); - await executeContractCallWithSigners(safe, safe, "setGuard", [guardAddress], [user1]); + await (await executeContractCallWithSigners(safe, safe, "setGuard", [guardAddress], [user1])).wait(); return { safe, mock, diff --git a/test/guards/DelegateCallTransactionGuard.spec.ts b/test/guards/DelegateCallTransactionGuard.spec.ts index 1ad62b602..027fc647f 100644 --- a/test/guards/DelegateCallTransactionGuard.spec.ts +++ b/test/guards/DelegateCallTransactionGuard.spec.ts @@ -1,20 +1,20 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; +import hre, { ethers } from "hardhat"; import { AddressZero } from "@ethersproject/constants"; -import { getSafeWithOwners } from "../utils/setup"; +import { getContractFactoryByName, getSafeWithOwners, getWallets } from "../utils/setup"; import { buildContractCall, executeContractCallWithSigners } from "../../src/utils/execution"; import { AddressOne } from "../../src/utils/constants"; describe("DelegateCallTransactionGuard", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; const safe = await getSafeWithOwners([user1.address]); - const guardFactory = await hre.ethers.getContractFactory("DelegateCallTransactionGuard"); + const guardFactory = await getContractFactoryByName("DelegateCallTransactionGuard"); const guard = await guardFactory.deploy(AddressZero); const guardAddress = await guard.getAddress(); - await executeContractCallWithSigners(safe, safe, "setGuard", [guardAddress], [user1]); + await (await executeContractCallWithSigners(safe, safe, "setGuard", [guardAddress], [user1])).wait(); return { safe, guardFactory, @@ -118,7 +118,7 @@ describe("DelegateCallTransactionGuard", () => { } = await setupTests(); const guard = await guardFactory.deploy(AddressOne); const guardAddress = await guard.getAddress(); - await executeContractCallWithSigners(safe, safe, "setGuard", [guardAddress], [user1]); + await (await executeContractCallWithSigners(safe, safe, "setGuard", [guardAddress], [user1])).wait(); expect(await guard.allowedTarget()).to.be.eq(AddressOne); const allowedTarget = safe.attach(AddressOne); diff --git a/test/guards/OnlyOwnersGuard.spec.ts b/test/guards/OnlyOwnersGuard.spec.ts index 2fb5c4d14..5f5695496 100644 --- a/test/guards/OnlyOwnersGuard.spec.ts +++ b/test/guards/OnlyOwnersGuard.spec.ts @@ -1,19 +1,19 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; -import { getMock, getSafeWithOwners } from "../utils/setup"; +import hre, { ethers } from "hardhat"; +import { getContractFactoryByName, getMock, getSafeWithOwners, getWallets } from "../utils/setup"; import { buildSafeTransaction, executeContractCallWithSigners, executeTxWithSigners } from "../../src/utils/execution"; describe("OnlyOwnersGuard", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; const safe = await getSafeWithOwners([user1.address]); - const guardFactory = await hre.ethers.getContractFactory("OnlyOwnersGuard"); + const guardFactory = await getContractFactoryByName("OnlyOwnersGuard"); const guard = await guardFactory.deploy(); const guardAddress = await guard.getAddress(); const mock = await getMock(); - await executeContractCallWithSigners(safe, safe, "setGuard", [guardAddress], [user1]); + await (await executeContractCallWithSigners(safe, safe, "setGuard", [guardAddress], [user1])).wait(); return { safe, diff --git a/test/guards/ReentrancyTransactionGuard.spec.ts b/test/guards/ReentrancyTransactionGuard.spec.ts index bdea21fd3..7def13aae 100644 --- a/test/guards/ReentrancyTransactionGuard.spec.ts +++ b/test/guards/ReentrancyTransactionGuard.spec.ts @@ -1,6 +1,6 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; -import { getMock, getSafeWithOwners } from "../utils/setup"; +import hre, { ethers } from "hardhat"; +import { getContractFactoryByName, getMock, getSafeWithOwners, getWallets } from "../utils/setup"; import { buildSafeTransaction, buildSignatureBytes, @@ -11,17 +11,16 @@ import { } from "../../src/utils/execution"; describe("ReentrancyTransactionGuard", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; const safe = await getSafeWithOwners([user1.address]); - const guardFactory = await hre.ethers.getContractFactory("ReentrancyTransactionGuard"); + const guardFactory = await getContractFactoryByName("ReentrancyTransactionGuard"); const guard = await guardFactory.deploy(); const guardAddress = await guard.getAddress(); const mock = await getMock(); - await executeContractCallWithSigners(safe, safe, "setGuard", [guardAddress], [user1]); - + await (await executeContractCallWithSigners(safe, safe, "setGuard", [guardAddress], [user1])).wait(); return { safe, mock, @@ -110,8 +109,8 @@ describe("ReentrancyTransactionGuard", () => { const safeTx = buildSafeTransaction({ to: mockAddress, data: "0xbaddad42", nonce: nonce + 1n }); const signatures = [await safeSignTypedData(user1, safeAddress, safeTx)]; - await executeTxWithSigners(safe, buildSafeTransaction({ to: safeAddress, data: "0x", nonce: nonce }), [user1]); - await executeTx(safe, safeTx, signatures); + await (await executeTxWithSigners(safe, buildSafeTransaction({ to: guardAddress, data: "0x", nonce: nonce }), [user1])).wait(); + await (await executeTx(safe, safeTx, signatures)).wait(); expect(await mock.invocationCount()).to.be.eq(1); expect(await mock.invocationCountForCalldata("0xbaddad42")).to.be.eq(1); From 4f3568975be4881cb8f0bae9bb741a3e8505db94 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Mon, 24 Jul 2023 17:39:40 +0300 Subject: [PATCH 19/37] refactor: adjust handlers tests for zksync --- .../CompatibilityFallbackHandler.spec.ts | 21 ++++++++++++------- test/handlers/HandlerContext.spec.ts | 12 +++++------ test/handlers/TokenCallbackHandler.spec.ts | 2 +- test/utils/setup.ts | 20 +++++++++--------- 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/test/handlers/CompatibilityFallbackHandler.spec.ts b/test/handlers/CompatibilityFallbackHandler.spec.ts index 4569fadaf..90c9631e9 100644 --- a/test/handlers/CompatibilityFallbackHandler.spec.ts +++ b/test/handlers/CompatibilityFallbackHandler.spec.ts @@ -1,7 +1,7 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; +import hre, { ethers } from "hardhat"; import { AddressZero } from "@ethersproject/constants"; -import { getCompatFallbackHandler, getSafeWithOwners } from "../utils/setup"; +import { getCompatFallbackHandler, getContractFactoryByName, getSafeWithOwners, getWallets } from "../utils/setup"; import { buildSignatureBytes, executeContractCallWithSigners, @@ -14,9 +14,9 @@ import { chainId } from "../utils/encoding"; import { killLibContract } from "../utils/contracts"; describe("CompatibilityFallbackHandler", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const signLib = await (await hre.ethers.getContractFactory("SignMessageLib")).deploy(); + const signLib = await (await getContractFactoryByName("SignMessageLib")).deploy(); const handler = await getCompatFallbackHandler(); const handlerAddress = await handler.getAddress(); const signers = await ethers.getSigners(); @@ -26,7 +26,7 @@ describe("CompatibilityFallbackHandler", () => { const safe = await getSafeWithOwners([user1.address, user2.address, signerSafeAddress], 2, handlerAddress); const safeAddress = await safe.getAddress(); const validator = await getCompatFallbackHandler(safeAddress); - const killLib = await killLibContract(user1); + const killLib = await killLibContract(user1, hre.network.zksync); return { safe, validator, @@ -91,7 +91,7 @@ describe("CompatibilityFallbackHandler", () => { signers: [user1, user2], } = await setupTests(); const dataHash = ethers.keccak256("0xbaddad"); - await executeContractCallWithSigners(safe, signLib, "signMessage", [dataHash], [user1, user2], true); + await (await executeContractCallWithSigners(safe, signLib, "signMessage", [dataHash], [user1, user2], true)).wait(); expect(await validator.isValidSignature.staticCall(dataHash, "0x")).to.be.eq("0x1626ba7e"); }); @@ -171,7 +171,14 @@ describe("CompatibilityFallbackHandler", () => { // eslint-disable-next-line @typescript-eslint/no-empty-function it.skip("can be called for any Safe", async () => {}); - it("should revert changes", async () => { + it("should revert changes", async function () { + /** + * ## Test not applicable for zkSync, therefore should skip. + * The `SELFDESTRUCT` instruction is not supported + * @see https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#selfdestruct + */ + if (hre.network.zksync) this.skip(); + const { validator, killLib } = await setupTests(); const validatorAddress = await validator.getAddress(); const killLibAddress = await killLib.getAddress(); diff --git a/test/handlers/HandlerContext.spec.ts b/test/handlers/HandlerContext.spec.ts index 5c7c89af2..744d49d60 100644 --- a/test/handlers/HandlerContext.spec.ts +++ b/test/handlers/HandlerContext.spec.ts @@ -1,14 +1,14 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; +import hre from "hardhat"; import { AddressZero } from "@ethersproject/constants"; -import { getSafeTemplate } from "../utils/setup"; +import { getContractFactoryByName, getSafeTemplate, getWallets } from "../utils/setup"; describe("HandlerContext", () => { - const setup = deployments.createFixture(async ({ deployments }) => { + const setup = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const TestHandler = await hre.ethers.getContractFactory("TestHandler"); + const TestHandler = await getContractFactoryByName("TestHandler"); const handler = await TestHandler.deploy(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); return { safe: await getSafeTemplate(), handler, @@ -38,7 +38,7 @@ describe("HandlerContext", () => { } = await setup(); const handlerAddress = await handler.getAddress(); const safeAddress = await safe.getAddress(); - await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", handlerAddress, AddressZero, 0, AddressZero); + await (await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", handlerAddress, AddressZero, 0, AddressZero)).wait(); const response = await user1.call({ to: safeAddress, diff --git a/test/handlers/TokenCallbackHandler.spec.ts b/test/handlers/TokenCallbackHandler.spec.ts index d9594d07b..781f77575 100644 --- a/test/handlers/TokenCallbackHandler.spec.ts +++ b/test/handlers/TokenCallbackHandler.spec.ts @@ -5,7 +5,7 @@ import { getTokenCallbackHandler } from "../utils/setup"; describe("TokenCallbackHandler", () => { beforeEach(async () => { - await deployments.fixture(); + await hre.deployments.fixture(); }); describe("ERC1155", () => { diff --git a/test/utils/setup.ts b/test/utils/setup.ts index 250c2b7b8..4dfe2ca95 100644 --- a/test/utils/setup.ts +++ b/test/utils/setup.ts @@ -10,19 +10,19 @@ import { getRandomIntAsString } from "./numbers"; import { Safe, SafeL2 } from "../../typechain-types"; export const defaultTokenCallbackHandlerDeployment = async () => { - return await deployments.get("TokenCallbackHandler"); + return deployments.get("TokenCallbackHandler"); }; export const defaultTokenCallbackHandlerContract = async () => { - return await hre.ethers.getContractFactory("TokenCallbackHandler"); + return getContractFactoryByName("TokenCallbackHandler"); }; export const compatFallbackHandlerDeployment = async () => { - return await deployments.get("CompatibilityFallbackHandler"); + return deployments.get("CompatibilityFallbackHandler"); }; export const compatFallbackHandlerContract = async () => { - return await hre.ethers.getContractFactory("CompatibilityFallbackHandler"); + return getContractFactoryByName("CompatibilityFallbackHandler"); }; export const getSafeSingleton = async () => { @@ -32,13 +32,13 @@ export const getSafeSingleton = async () => { }; export const getSafeSingletonContract = async () => { - const safeSingleton = await hre.ethers.getContractFactory("Safe"); + const safeSingleton = await getContractFactoryByName("Safe"); return safeSingleton; }; export const getSafeL2SingletonContract = async () => { - const safeSingleton = await hre.ethers.getContractFactory("SafeL2"); + const safeSingleton = await getContractFactoryByName("SafeL2"); return safeSingleton; }; @@ -57,7 +57,7 @@ export const getSafeSingletonAt = async (address: string) => { }; export const getFactoryContract = async () => { - const factory = await hre.ethers.getContractFactory("SafeProxyFactory"); + const factory = await getContractFactoryByName("SafeProxyFactory"); return factory; }; @@ -98,7 +98,7 @@ export const getCreateCall = async () => { }; export const migrationContract = async () => { - return await hre.ethers.getContractFactory("Migration"); + return await getContractFactoryByName("Migration"); }; export const getMock = async () => { @@ -225,8 +225,8 @@ export const deployContract = async (deployer: Signer, source: string): Promise< } }; -export const getWallets = (): (ethers.Wallet | zk.Wallet)[] => { - if (hre.network.name === "hardhat") return waffle.provider.getWallets(); +export const getWallets = async (): (ethers.Signer | zk.Wallet)[] => { + if (hre.network.name === "hardhat") return ethers.getSigners(); if (!hre.network.zksync) throw new Error("You can get wallets only on Hardhat or ZkSyncLocal networks!"); const { accounts } = hre.network.config; From e825ceaa4efe380d1dd3db33c200abb372a0f3ba Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Mon, 24 Jul 2023 17:48:02 +0300 Subject: [PATCH 20/37] refactor: adjust integration tests for zksync --- test/integration/Safe.0xExploit.spec.ts | 22 ++++++------- test/integration/Safe.ERC1155.spec.ts | 33 ++++++++++--------- .../Safe.ReservedAddresses.spec.ts | 8 ++--- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/test/integration/Safe.0xExploit.spec.ts b/test/integration/Safe.0xExploit.spec.ts index fe4d6818c..a965438be 100644 --- a/test/integration/Safe.0xExploit.spec.ts +++ b/test/integration/Safe.0xExploit.spec.ts @@ -1,16 +1,16 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; +import hre, { ethers } from "hardhat"; import { AddressZero } from "@ethersproject/constants"; import { defaultAbiCoder } from "@ethersproject/abi"; -import { getSafeWithOwners, deployContract, getCompatFallbackHandler } from "../utils/setup"; +import { getSafeWithOwners, deployContract, getCompatFallbackHandler, getWallets } from "../utils/setup"; import { buildSignatureBytes, executeContractCallWithSigners, signHash } from "../../src/utils/execution"; describe("Safe", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); const handler = await getCompatFallbackHandler(); const handlerAddress = await handler.getAddress(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1, user2] = signers; const ownerSafe = await getSafeWithOwners([user1.address, user2.address], 2, handlerAddress); const ownerSafeAddress = await ownerSafe.getAddress(); @@ -37,7 +37,7 @@ describe("Safe", () => { } = await setupTests(); const ownerSafeAddress = await ownerSafe.getAddress(); // Safe should be empty again - await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") }); + await (await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") })).wait(); await expect(await hre.ethers.provider.getBalance(await safe.getAddress())).to.eq(ethers.parseEther("1")); const operation = 0; @@ -77,7 +77,7 @@ describe("Safe", () => { "00" + // r, s, v encodedOwnerSigns; - await safe.execTransaction(to, value, data, operation, 0, 0, 0, AddressZero, AddressZero, sigs); + await (await safe.execTransaction(to, value, data, operation, 0, 0, 0, AddressZero, AddressZero, sigs)).wait(); // Safe should be empty again await expect(await hre.ethers.provider.getBalance(await safe.getAddress())).to.eq(ethers.parseEther("0")); @@ -109,13 +109,13 @@ describe("Safe", () => { }`; const testValidator = await deployContract(user1, source); const testValidatorAddress = await testValidator.getAddress(); - await testValidator.shouldChangeState(true); + await (await testValidator.shouldChangeState(true)).wait(); - await executeContractCallWithSigners(safe, safe, "addOwnerWithThreshold", [testValidatorAddress, 1], [user1]); + await (await executeContractCallWithSigners(safe, safe, "addOwnerWithThreshold", [testValidatorAddress, 1], [user1])).wait(); await expect(await safe.getOwners()).to.be.deep.eq([testValidatorAddress, ownerSafeAddress, user1.address]); // Deposit 1 ETH + some spare money for execution - await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") }); + await (await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") })).wait(); await expect(await hre.ethers.provider.getBalance(await safe.getAddress())).to.eq(ethers.parseEther("1")); const operation = 0; @@ -146,8 +146,8 @@ describe("Safe", () => { ).to.be.reverted; await expect(await hre.ethers.provider.getBalance(await safe.getAddress())).to.eq(ethers.parseEther("1")); - await testValidator.shouldChangeState(false); - await safe.execTransaction(to, value, data, operation, 0, 0, 0, AddressZero, AddressZero, sigs); + await (await testValidator.shouldChangeState(false)).wait(); + await (await safe.execTransaction(to, value, data, operation, 0, 0, 0, AddressZero, AddressZero, sigs)).wait(); // Safe should be empty again await expect(await hre.ethers.provider.getBalance(await safe.getAddress())).to.eq(ethers.parseEther("0")); diff --git a/test/integration/Safe.ERC1155.spec.ts b/test/integration/Safe.ERC1155.spec.ts index bea067bef..7f981886b 100644 --- a/test/integration/Safe.ERC1155.spec.ts +++ b/test/integration/Safe.ERC1155.spec.ts @@ -1,20 +1,19 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; +import hre from "hardhat"; import { AddressZero } from "@ethersproject/constants"; -import { defaultTokenCallbackHandlerDeployment, getSafeTemplate } from "../utils/setup"; +import { defaultTokenCallbackHandlerDeployment, getContractFactoryByName, getSafeTemplate, getWallets } from "../utils/setup"; describe("Safe", () => { - const mockErc1155 = async () => { - const Erc1155 = await hre.ethers.getContractFactory("ERC1155Token"); - return await Erc1155.deploy(); - }; - - const setupWithTemplate = deployments.createFixture(async ({ deployments }) => { + const setupWithTemplate = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); + + const mockErc1155 = await (await getContractFactoryByName("ERC1155Token")).deploy(); + await mockErc1155.deployed(); + return { safe: await getSafeTemplate(), - token: await mockErc1155(), + token: mockErc1155, signers, }; }); @@ -29,10 +28,10 @@ describe("Safe", () => { const safeAddress = await safe.getAddress(); // Setup Safe - await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", AddressZero, AddressZero, 0, AddressZero); + await (await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", AddressZero, AddressZero, 0, AddressZero)).wait(); // Mint test tokens - await token.mint(user1.address, 23, 1337, "0x"); + await (await token.mint(user1.address, 23, 1337, "0x")).wait(); await expect(await token.balanceOf(user1.address, 23)).to.be.deep.eq(1337n); await expect(token.mint(safeAddress, 23, 1337, "0x"), "Should not accept minted token if handler not set").to.be.reverted; @@ -53,15 +52,17 @@ describe("Safe", () => { const handler = await defaultTokenCallbackHandlerDeployment(); // Setup Safe - await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", handler.address, AddressZero, 0, AddressZero); + await ( + await safe.setup([user1.address, user2.address], 1, AddressZero, "0x", handler.address, AddressZero, 0, AddressZero) + ).wait(); - await token.mint(safeAddress, 23, 1337, "0x"); + await (await token.mint(safeAddress, 23, 1337, "0x")).wait(); await expect(await token.balanceOf(safeAddress, 23)).to.be.deep.eq(1337n); - await token.mint(user1.address, 23, 23, "0x"); + await (await token.mint(user1.address, 23, 23, "0x")).wait(); await expect(await token.balanceOf(user1.address, 23)).to.be.deep.eq(23n); - await token.safeTransferFrom(user1.address, safeAddress, 23, 23, "0x"); + await (await token.safeTransferFrom(user1.address, safeAddress, 23, 23, "0x")).wait(); await expect(await token.balanceOf(user1.address, 23)).to.be.deep.eq(0n); await expect(await token.balanceOf(safeAddress, 23)).to.be.deep.eq(1360n); }); diff --git a/test/integration/Safe.ReservedAddresses.spec.ts b/test/integration/Safe.ReservedAddresses.spec.ts index 599b3a3ba..4eda27b9f 100644 --- a/test/integration/Safe.ReservedAddresses.spec.ts +++ b/test/integration/Safe.ReservedAddresses.spec.ts @@ -1,12 +1,12 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; -import { getSafeWithOwners } from "../utils/setup"; +import hre, { ethers } from "hardhat"; +import { getSafeWithOwners, getWallets } from "../utils/setup"; import { AddressOne } from "../../src/utils/constants"; describe("Safe - Reserved Addresses", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const [user1] = await ethers.getSigners(); + const [user1] = await getWallets(); return { safe: await getSafeWithOwners([user1.address]), }; From 4470fd0fe64541a742ec5c948d3d3285d711aa2b Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Mon, 24 Jul 2023 17:48:53 +0300 Subject: [PATCH 21/37] refactor: adjust l2 execution tests for zksync --- test/l2/Safe.Execution.spec.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/test/l2/Safe.Execution.spec.ts b/test/l2/Safe.Execution.spec.ts index f552e9a44..ab59a0ebe 100644 --- a/test/l2/Safe.Execution.spec.ts +++ b/test/l2/Safe.Execution.spec.ts @@ -1,6 +1,6 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; -import { getMock, getSafeWithOwners } from "../utils/setup"; +import hre, { ethers } from "hardhat"; +import { getMock, getSafeWithOwners, getWallets } from "../utils/setup"; import { safeApproveHash, buildSafeTransaction, @@ -17,8 +17,8 @@ describe("SafeL2", () => { } }); - const setupTests = deployments.createFixture(async ({ deployments }) => { - const signers = await ethers.getSigners(); + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { + const signers = await getWallets(); const [user1] = signers; await deployments.fixture(); const mock = await getMock(); @@ -45,7 +45,7 @@ describe("SafeL2", () => { refundReceiver: user2.address, }); - await user1.sendTransaction({ to: safeAddress, value: ethers.parseEther("1") }); + await (await user1.sendTransaction({ to: safeAddress, value: ethers.parseEther("1") })).wait(); await expect(await hre.ethers.provider.getBalance(safeAddress)).to.be.deep.eq(ethers.parseEther("1")); const additionalInfo = ethers.AbiCoder.defaultAbiCoder().encode( @@ -81,9 +81,12 @@ describe("SafeL2", () => { } = await setupTests(); const mockAddress = await mock.getAddress(); const user2Safe = safe.connect(user2); - await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1])).wait(); - await expect(user2Safe.execTransactionFromModule(mockAddress, 0, "0xbaddad", 0)) + //Use manual gasLimit because gas estimation fails for this function on zkSync, though transaction executed successfully + await expect( + user2Safe.execTransactionFromModule(mockAddress, 0, "0xbaddad", 0, { gasLimit: hre.network.zksync ? 250_000 : undefined }), + ) .to.emit(safe, "SafeModuleTransaction") .withArgs(user2.address, mockAddress, 0, "0xbaddad", 0) .to.emit(safe, "ExecutionFromModuleSuccess") From ae6865cacc5b134707b3800c5d94689b7f66ab75 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Mon, 24 Jul 2023 17:49:56 +0300 Subject: [PATCH 22/37] refactor: adjust libraries tests for zksync --- test/libraries/CreateCall.spec.ts | 16 ++++++++++++---- test/libraries/Migration.spec.ts | 15 +++++++++++---- test/libraries/MultiSend.spec.ts | 21 ++++++++++++++------- test/libraries/MultiSendCallOnly.spec.ts | 14 +++++++------- test/libraries/SignMessageLib.spec.ts | 12 ++++++------ 5 files changed, 50 insertions(+), 28 deletions(-) diff --git a/test/libraries/CreateCall.spec.ts b/test/libraries/CreateCall.spec.ts index 0ccc1242a..cdb0f97d2 100644 --- a/test/libraries/CreateCall.spec.ts +++ b/test/libraries/CreateCall.spec.ts @@ -1,6 +1,6 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; -import { compile, getCreateCall, getSafeWithOwners } from "../utils/setup"; +import hre, { ethers } from "hardhat"; +import { compile, getCreateCall, getSafeWithOwners, getWallets } from "../utils/setup"; import { buildContractCall, executeTx, safeApproveHash } from "../../src/utils/execution"; const CONTRACT_SOURCE = ` @@ -16,10 +16,18 @@ contract Test { }`; describe("CreateCall", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + before(function () { + /** + * ## performCreate and performCreate2 functions of CreateCall.sol will not work on zkSync + * @see https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#create-create2 + */ + if (hre.network.zksync) this.skip(); + }); + + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); const testContract = await compile(CONTRACT_SOURCE); - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; return { safe: await getSafeWithOwners([user1.address]), diff --git a/test/libraries/Migration.spec.ts b/test/libraries/Migration.spec.ts index 3e4b461d9..991da38cd 100644 --- a/test/libraries/Migration.spec.ts +++ b/test/libraries/Migration.spec.ts @@ -1,19 +1,26 @@ import { expect } from "chai"; -import { ethers, deployments } from "hardhat"; +import hre, { ethers } from "hardhat"; import { AddressZero } from "@ethersproject/constants"; -import { getSafeWithOwners, getSafeSingleton, migrationContract } from "../utils/setup"; +import { getSafeWithOwners, getSafeSingleton, migrationContract, getWallets } from "../utils/setup"; import deploymentData from "../json/safeDeployment.json"; import { executeContractCallWithSigners } from "../../src/utils/execution"; describe("Migration", () => { + before(function () { + /** + * ## Migration test is not relevant for zkSync: there is no 1.2.0 of safe-contracts on zkSync + */ + if (hre.network.zksync) this.skip(); + }); + const MigratedInterface = new ethers.Interface([ "function domainSeparator() view returns(bytes32)", "function masterCopy() view returns(address)", ]); - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; const singleton120 = (await (await user1.sendTransaction({ data: deploymentData.safe120 })).wait())?.contractAddress; if (!singleton120) { diff --git a/test/libraries/MultiSend.spec.ts b/test/libraries/MultiSend.spec.ts index 4bc8aff51..26d588ee0 100644 --- a/test/libraries/MultiSend.spec.ts +++ b/test/libraries/MultiSend.spec.ts @@ -1,11 +1,11 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; -import { deployContract, getMock, getMultiSend, getSafeWithOwners, getDelegateCaller } from "../utils/setup"; +import hre, { ethers } from "hardhat"; +import { deployContract, getMock, getMultiSend, getSafeWithOwners, getDelegateCaller, getWallets } from "../utils/setup"; import { buildContractCall, buildSafeTransaction, executeTx, MetaTransaction, safeApproveHash } from "../../src/utils/execution"; import { buildMultiSendSafeTx, encodeMultiSend } from "../../src/utils/multisend"; describe("MultiSend", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); const setterSource = ` contract StorageSetter { @@ -31,7 +31,14 @@ describe("MultiSend", () => { }); describe("multiSend", () => { - it("should enforce delegatecall to MultiSend", async () => { + it("should enforce delegatecall to MultiSend", async function () { + /** + * ## Test not applicable for zkSync, therefore should skip. + * The `SELFDESTRUCT` instruction is not supported + * @see https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#selfdestruct + */ + if (hre.network.zksync) this.skip(); + const { multiSend, signers: [user1], @@ -83,7 +90,7 @@ describe("MultiSend", () => { multiSend, signers: [user1, user2], } = await setupTests(); - await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") }); + await (await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") })).wait(); const userBalance = await hre.ethers.provider.getBalance(user2.address); await expect(await hre.ethers.provider.getBalance(await safe.getAddress())).to.eq(ethers.parseEther("1")); @@ -101,7 +108,7 @@ describe("MultiSend", () => { multiSend, signers: [user1, user2], } = await setupTests(); - await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") }); + await (await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") })).wait(); const userBalance = await hre.ethers.provider.getBalance(user2.address); await expect(await hre.ethers.provider.getBalance(await safe.getAddress())).to.eq(ethers.parseEther("1")); @@ -199,7 +206,7 @@ describe("MultiSend", () => { } = await setupTests(); const storageSetterAddress = await storageSetter.getAddress(); - await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") }); + await (await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") })).wait(); const userBalance = await hre.ethers.provider.getBalance(user2.address); await expect(await hre.ethers.provider.getBalance(await safe.getAddress())).to.eq(ethers.parseEther("1")); diff --git a/test/libraries/MultiSendCallOnly.spec.ts b/test/libraries/MultiSendCallOnly.spec.ts index 113210e6a..61036661c 100644 --- a/test/libraries/MultiSendCallOnly.spec.ts +++ b/test/libraries/MultiSendCallOnly.spec.ts @@ -1,11 +1,11 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; -import { deployContract, getMock, getMultiSendCallOnly, getSafeWithOwners, getDelegateCaller } from "../utils/setup"; +import hre, { ethers } from "hardhat"; +import { deployContract, getMock, getMultiSendCallOnly, getSafeWithOwners, getDelegateCaller, getWallets } from "../utils/setup"; import { buildContractCall, buildSafeTransaction, executeTx, MetaTransaction, safeApproveHash } from "../../src/utils/execution"; import { buildMultiSendSafeTx } from "../../src/utils/multisend"; describe("MultiSendCallOnly", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); const setterSource = ` contract StorageSetter { @@ -17,7 +17,7 @@ describe("MultiSendCallOnly", () => { } } }`; - const signers = await ethers.getSigners(); + const signers = await getWallets(); const [user1] = signers; const storageSetter = await deployContract(user1, setterSource); return { @@ -73,7 +73,7 @@ describe("MultiSendCallOnly", () => { multiSend, signers: [user1, user2], } = await setupTests(); - await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") }); + await (await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") })).wait(); const userBalance = await hre.ethers.provider.getBalance(user2.address); await expect(await hre.ethers.provider.getBalance(await safe.getAddress())).to.be.deep.eq(ethers.parseEther("1")); @@ -91,7 +91,7 @@ describe("MultiSendCallOnly", () => { multiSend, signers: [user1, user2], } = await setupTests(); - await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") }); + await (await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") })).wait(); const userBalance = await hre.ethers.provider.getBalance(user2.address); await expect(await hre.ethers.provider.getBalance(await safe.getAddress())).to.eq(ethers.parseEther("1")); @@ -162,7 +162,7 @@ describe("MultiSendCallOnly", () => { } = await setupTests(); const storageSetterAddress = await storageSetter.getAddress(); - await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") }); + await (await user1.sendTransaction({ to: await safe.getAddress(), value: ethers.parseEther("1") })).wait(); const userBalance = await hre.ethers.provider.getBalance(user2.address); await expect(await hre.ethers.provider.getBalance(await safe.getAddress())).to.eq(ethers.parseEther("1")); diff --git a/test/libraries/SignMessageLib.spec.ts b/test/libraries/SignMessageLib.spec.ts index 2c0617914..0cc0253f8 100644 --- a/test/libraries/SignMessageLib.spec.ts +++ b/test/libraries/SignMessageLib.spec.ts @@ -1,14 +1,14 @@ import { expect } from "chai"; -import hre, { deployments, ethers } from "hardhat"; -import { getSafeWithOwners } from "../utils/setup"; +import hre from "hardhat"; +import { getContractFactoryByName, getSafeWithOwners, getWallets } from "../utils/setup"; import { executeContractCallWithSigners, calculateSafeMessageHash } from "../../src/utils/execution"; import { chainId } from "../utils/encoding"; describe("SignMessageLib", () => { - const setupTests = deployments.createFixture(async ({ deployments }) => { + const setupTests = hre.deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const lib = await (await hre.ethers.getContractFactory("SignMessageLib")).deploy(); - const signers = await ethers.getSigners(); + const lib = await (await getContractFactoryByName("SignMessageLib")).deploy(); + const signers = await getWallets(); const [user1, user2] = signers; return { safe: await getSafeWithOwners([user1.address, user2.address]), @@ -81,7 +81,7 @@ describe("SignMessageLib", () => { expect(await safe.signedMessages(safeInternalMsgHash)).to.be.eq(0); expect(msgStorageSlotBeforeSigning).to.be.eq(`0x${"0".padStart(64, "0")}`); - await executeContractCallWithSigners(safe, lib, "signMessage", [eip191MessageHash], [user1, user2], true); + await (await executeContractCallWithSigners(safe, lib, "signMessage", [eip191MessageHash], [user1, user2], true)).wait(); const masterCopyAddressAfterSigning = await hre.ethers.provider.getStorage(await safe.getAddress(), 0); const ownerCountAfterSigning = await hre.ethers.provider.getStorage(await safe.getAddress(), 3); From 240b49c88174ff4fc391173efb7b21c85967fe2c Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Mon, 24 Jul 2023 17:50:37 +0300 Subject: [PATCH 23/37] refactor: skip migration tests for zksync --- test/migration/UpgradeFromSafe111.spec.ts | 4 ++-- test/migration/UpgradeFromSafe120.spec.ts | 4 ++-- test/migration/subTests.spec.ts | 10 +++++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/test/migration/UpgradeFromSafe111.spec.ts b/test/migration/UpgradeFromSafe111.spec.ts index e5457ac22..6b5117daa 100644 --- a/test/migration/UpgradeFromSafe111.spec.ts +++ b/test/migration/UpgradeFromSafe111.spec.ts @@ -1,7 +1,7 @@ import { expect } from "chai"; import hre, { ethers, deployments } from "hardhat"; import { AddressZero } from "@ethersproject/constants"; -import { getSafeSingleton, getFactory, getMock, getMultiSend } from "../utils/setup"; +import { getSafeSingleton, getFactory, getMock, getMultiSend, getWallets } from "../utils/setup"; import { buildSafeTransaction, executeTx, safeApproveHash } from "../../src/utils/execution"; import { verificationTests } from "./subTests.spec"; import deploymentData from "../json/safeDeployment.json"; @@ -12,7 +12,7 @@ describe("Upgrade from Safe 1.1.1", () => { // We migrate the Safe and run the verification tests const setupTests = deployments.createFixture(async ({ deployments }) => { - const [user1] = await ethers.getSigners(); + const [user1] = await getWallets(); await deployments.fixture(); const mock = await getMock(); const mockAddress = await mock.getAddress(); diff --git a/test/migration/UpgradeFromSafe120.spec.ts b/test/migration/UpgradeFromSafe120.spec.ts index f5d7adccd..9f9f930b4 100644 --- a/test/migration/UpgradeFromSafe120.spec.ts +++ b/test/migration/UpgradeFromSafe120.spec.ts @@ -1,7 +1,7 @@ import { expect } from "chai"; import hre, { ethers, deployments } from "hardhat"; import { AddressZero } from "@ethersproject/constants"; -import { getSafeSingleton, getFactory, getMock, getMultiSend } from "../utils/setup"; +import { getSafeSingleton, getFactory, getMock, getMultiSend, getWallets } from "../utils/setup"; import { buildSafeTransaction, executeTx, safeApproveHash } from "../../src/utils/execution"; import { verificationTests } from "./subTests.spec"; import deploymentData from "../json/safeDeployment.json"; @@ -15,7 +15,7 @@ describe("Upgrade from Safe 1.2.0", () => { await deployments.fixture(); const mock = await getMock(); const mockAddress = await mock.getAddress(); - const [user1] = await ethers.getSigners(); + const [user1] = await getWallets(); const singleton120 = (await (await user1.sendTransaction({ data: deploymentData.safe120 })).wait())?.contractAddress; if (!singleton120) throw new Error("Could not deploy Safe 1.2.0"); diff --git a/test/migration/subTests.spec.ts b/test/migration/subTests.spec.ts index a34b98202..283f9fd8b 100644 --- a/test/migration/subTests.spec.ts +++ b/test/migration/subTests.spec.ts @@ -4,6 +4,7 @@ import { AddressOne } from "../../src/utils/constants"; import { buildSafeTransaction, executeContractCallWithSigners, executeTxWithSigners, MetaTransaction } from "../../src/utils/execution"; import { buildMultiSendSafeTx } from "../../src/utils/multisend"; import { MockContract, MultiSend, Safe } from "../../typechain-types"; +import { getWallets } from "../utils/setup"; interface TestSetup { migratedSafe: Safe; @@ -12,7 +13,14 @@ interface TestSetup { } export const verificationTests = async (setupTests: () => Promise) => { - const [user1, user2, user3] = await ethers.getSigners(); + before(function () { + /** + * ## Migration tests are not relevant for zkSync: there are no older versions of safe-contracts on zkSync + */ + if (hre.network.zksync) this.skip(); + }); + + const [user1, user2, user3] = await getWallets(); describe("execTransaction", () => { it("should be able to transfer ETH", async () => { From 6d15fec0c49ce055dac0f0fd653b698205d91f37 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Mon, 24 Jul 2023 17:52:52 +0300 Subject: [PATCH 24/37] feat: update hardhat-deploy package --- package.json | 1 + yarn.lock | 0 2 files changed, 1 insertion(+) create mode 100644 yarn.lock diff --git a/package.json b/package.json index 5096a0640..e38dbe17f 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "build:ts": "rimraf dist && tsc -p tsconfig.prod.json", "build:ts:dev": "rimraf dist && tsc -p tsconfig.json", "test": "hardhat test", + "test:zk": "hardhat test --network zkSyncLocal", "test:parallel": "hardhat test --parallel", "coverage": "hardhat coverage", "benchmark": "npm run test benchmark/*.ts", diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..e69de29bb From 1abd61f8d1f99665374e0d5c7aa98d81c83ba7c9 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Mon, 24 Jul 2023 19:25:59 +0300 Subject: [PATCH 25/37] refactor: adjust Safe.ModuleManager.spec.ts for zksync --- test/core/Safe.ModuleManager.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/Safe.ModuleManager.spec.ts b/test/core/Safe.ModuleManager.spec.ts index 86b1a73c5..306dfca41 100644 --- a/test/core/Safe.ModuleManager.spec.ts +++ b/test/core/Safe.ModuleManager.spec.ts @@ -147,8 +147,8 @@ describe("ModuleManager", () => { safe, signers: [user1, user2], } = await setupTests(); - await executeContractCallWithSigners(safe, safe, "enableModule", [user1.address], [user1]); - await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user1.address], [user1])).wait(); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user2.address], [user1])).wait(); await expect( executeContractCallWithSigners(safe, safe, "disableModule", [user1.address, user2.address], [user1]), ).to.revertedWith("GS013"); From 04237bb2b63dfae5af5bff4f8154a0b09c2b8d7a Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Mon, 24 Jul 2023 20:45:06 +0300 Subject: [PATCH 26/37] refactor: adjust hardhat tasks for zksync --- hardhat.config.ts | 1 + src/tasks/deploy_contracts.ts | 8 +++- src/tasks/local_verify.ts | 69 +++++++++++++++++++++-------------- src/tasks/zk.ts | 46 +++++++++++++++++++++++ 4 files changed, 95 insertions(+), 29 deletions(-) create mode 100644 src/tasks/zk.ts diff --git a/hardhat.config.ts b/hardhat.config.ts index 53cbe9667..d73984a5e 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -39,6 +39,7 @@ if (["mainnet", "rinkeby", "kovan", "goerli", "ropsten", "mumbai", "polygon"].in import "./src/tasks/local_verify"; import "./src/tasks/deploy_contracts"; import "./src/tasks/show_codesize"; +import "./src/tasks/zk"; import { BigNumber } from "@ethersproject/bignumber"; import { DeterministicDeploymentInfo } from "hardhat-deploy/dist/types"; import { LOCAL_NODE_RICH_WALLETS } from "./src/zk-utils/constants"; diff --git a/src/tasks/deploy_contracts.ts b/src/tasks/deploy_contracts.ts index 707e03c12..4729bb727 100644 --- a/src/tasks/deploy_contracts.ts +++ b/src/tasks/deploy_contracts.ts @@ -1,10 +1,16 @@ import { task } from "hardhat/config"; +import { TASK_VERIFY_ZK_ALL } from "./zk"; task("deploy-contracts", "Deploys and verifies Safe contracts").setAction(async (_, hre) => { await hre.run("deploy"); await hre.run("local-verify"); await hre.run("sourcify"); - await hre.run("etherscan-verify", { forceLicense: true, license: "LGPL-3.0" }); + + if (!hre.network.zksync) { + await hre.run("etherscan-verify", { forceLicense: true, license: "LGPL-3.0" }); + } else { + await hre.run(TASK_VERIFY_ZK_ALL); + } }); export {}; diff --git a/src/tasks/local_verify.ts b/src/tasks/local_verify.ts index 66594fb09..50ecc7606 100644 --- a/src/tasks/local_verify.ts +++ b/src/tasks/local_verify.ts @@ -2,37 +2,50 @@ import { task } from "hardhat/config"; import { loadSolc } from "../utils/solc"; task("local-verify", "Verifies that the local deployment files correspond to the on chain code").setAction(async (_, hre) => { - const allowedSourceKey = ["keccak256", "content"]; - const deployedContracts = await hre.deployments.all(); - for (const contract of Object.keys(deployedContracts)) { - const deployment = await hre.deployments.get(contract); - const meta = JSON.parse(deployment.metadata!); - const solcjs = await loadSolc(meta.compiler.version); - delete meta.compiler; - delete meta.output; - delete meta.version; - const sources = Object.values(meta.sources); - for (const source of sources) { - for (const key of Object.keys(source)) { - if (allowedSourceKey.indexOf(key) < 0) delete source[key]; + if (!hre.network.zksync) { + const allowedSourceKey = ["keccak256", "content"]; + const deployedContracts = await hre.deployments.all(); + for (const contract of Object.keys(deployedContracts)) { + const deployment = await hre.deployments.get(contract); + const meta = JSON.parse(deployment.metadata!); + const solcjs = await loadSolc(meta.compiler.version); + delete meta.compiler; + delete meta.output; + delete meta.version; + const sources = Object.values(meta.sources); + for (const source of sources) { + for (const key of Object.keys(source)) { + if (allowedSourceKey.indexOf(key) < 0) delete source[key]; + } + } + meta.settings.outputSelection = {}; + const targets = Object.entries(meta.settings.compilationTarget); + for (const [key, value] of targets) { + meta.settings.outputSelection[key] = {}; + meta.settings.outputSelection[key][value as string] = ["evm.bytecode", "evm.deployedBytecode", "metadata"]; + } + delete meta.settings.compilationTarget; + const compiled = solcjs.compile(JSON.stringify(meta)); + const output = JSON.parse(compiled); + for (const [key, value] of targets) { + const compiledContract = output.contracts[key][value as string]; + const onChainCode = await hre.ethers.provider.getCode(deployment.address); + const onchainBytecodeHash = hre.ethers.keccak256(onChainCode); + const localBytecodeHash = hre.ethers.keccak256(`0x${compiledContract.evm.deployedBytecode.object}`); + const verifySuccess = onchainBytecodeHash === localBytecodeHash ? "SUCCESS" : "FAILURE"; + console.log(`Verification status for ${value}: ${verifySuccess}`); } } - meta.settings.outputSelection = {}; - const targets = Object.entries(meta.settings.compilationTarget); - for (const [key, value] of targets) { - meta.settings.outputSelection[key] = {}; - meta.settings.outputSelection[key][value as string] = ["evm.bytecode", "evm.deployedBytecode", "metadata"]; - } - delete meta.settings.compilationTarget; - const compiled = solcjs.compile(JSON.stringify(meta)); - const output = JSON.parse(compiled); - for (const [key, value] of targets) { - const compiledContract = output.contracts[key][value as string]; + } else { + const deployedContracts = await hre.deployments.all(); + for (const contract of Object.keys(deployedContracts)) { + const deployment = await hre.deployments.get(contract); const onChainCode = await hre.ethers.provider.getCode(deployment.address); - const onchainBytecodeHash = hre.ethers.keccak256(onChainCode); - const localBytecodeHash = hre.ethers.keccak256(`0x${compiledContract.evm.deployedBytecode.object}`); - const verifySuccess = onchainBytecodeHash === localBytecodeHash ? "SUCCESS" : "FAILURE"; - console.log(`Verification status for ${value}: ${verifySuccess}`); + const onchainBytecodeHash = hre.ethers.utils.keccak256(onChainCode); + // TODO: compile contract in realtime and compare the compiled bytecode with onchain bytecode + const localBytecodeHash = hre.ethers.utils.keccak256(deployment.deployedBytecode!); + const verifySuccess = onchainBytecodeHash === localBytecodeHash ? "\x1b[32mSUCCESS\x1b[0m" : "\x1b[31mFAILURE\x1b[0m"; + console.log(`Verification status for ${contract}: ${verifySuccess}`); } } }); diff --git a/src/tasks/zk.ts b/src/tasks/zk.ts new file mode 100644 index 000000000..7bec80eb2 --- /dev/null +++ b/src/tasks/zk.ts @@ -0,0 +1,46 @@ +import "hardhat-deploy"; +import { TASK_DEPLOY } from "hardhat-deploy"; +import { TASK_VERIFY_VERIFY } from "@matterlabs/hardhat-zksync-verify/dist/src/constants"; +import "@nomiclabs/hardhat-ethers"; +import { TASK_TEST_SETUP_TEST_ENVIRONMENT } from "hardhat/builtin-tasks/task-names"; +import { subtask } from "hardhat/config"; + +subtask(TASK_TEST_SETUP_TEST_ENVIRONMENT).setAction(async (taskArgs, hre, runSuper) => { + if (hre.network.zksync) { + // due to problems with zkSyncLocal node we modify the mocha configuration + hre.config.mocha.retries = 3; + hre.config.mocha.timeout = 90_000; + hre.config.mocha.slow = 30_000; + + await hre.run(TASK_DEPLOY, { nonDeterministicZk: true, ...taskArgs }); + } else { + await runSuper(taskArgs); + } +}); + +const TASK_VERIFY_ZK_ALL = "verify:verify-zk-all"; + +subtask(TASK_VERIFY_ZK_ALL).setAction(async (_, hre) => { + if (!hre.network.zksync) throw new Error("Current subtask works only for zk networks!"); + + console.log(`\nRunning zk verification on block explorer`); + const deployedContracts = await hre.deployments.all(); + + for (const contract of Object.keys(deployedContracts)) { + const deployment = await hre.deployments.get(contract); + + try { + console.log(`\nVerifying ${contract} at ${deployment.address}...`); + await hre.run(TASK_VERIFY_VERIFY, { address: deployment.address }); + } catch (error) { + if (error instanceof Error && error.message.includes("contract is already verified")) { + console.log(`\x1b[32m${contract} is already verified!\x1b[0m`); + } else { + // Re-throw error if it is not about verified issue + throw error; + } + } + } +}); + +export { TASK_VERIFY_ZK_ALL }; From 0a2e35ad1aa7258327099c213cc289d42db8ecb1 Mon Sep 17 00:00:00 2001 From: nick8319 Date: Thu, 27 Jul 2023 15:50:29 +0300 Subject: [PATCH 27/37] feat: add zkSync Mainnet to hardhat config --- hardhat.config.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hardhat.config.ts b/hardhat.config.ts index d73984a5e..808bf9152 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -126,6 +126,14 @@ const userConfig: HardhatUserConfig = { ...sharedNetworkConfig, url: `https://api.avax.network/ext/bc/C/rpc`, }, + zkSyncMainnet: { + ...sharedNetworkConfig, + url: "https://mainnet.era.zksync.io", + ethNetwork: "mainnet", + zksync: true, + verifyURL: + "https://zksync2-mainnet-explorer.zksync.io/contract_verification", + }, zkSyncTestnet: { ...sharedNetworkConfig, url: "https://testnet.era.zksync.dev", From b09bdc2d9e14cbceb5a709be8d00569ba9028298 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Tue, 22 Aug 2023 17:56:08 +0300 Subject: [PATCH 28/37] feat: restore execution tests related to send method for zksync --- test/core/Safe.Execution.spec.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/core/Safe.Execution.spec.ts b/test/core/Safe.Execution.spec.ts index 21a493b19..3cfaa1c62 100644 --- a/test/core/Safe.Execution.spec.ts +++ b/test/core/Safe.Execution.spec.ts @@ -1,6 +1,6 @@ import { expect } from "chai"; import hre, { ethers } from "hardhat"; -import { deployContract, getSafeWithOwners, getWallets } from "../utils/setup"; +import { deployContract, getContractFactoryByName, getSafeWithOwners, getWallets } from "../utils/setup"; import { safeApproveHash, buildSignatureBytes, @@ -29,7 +29,7 @@ describe("Safe", () => { } }`; const storageSetter = await deployContract(user1, setterSource); - const TestNativeTokenReceiver = await hre.ethers.getContractFactory("TestNativeTokenReceiver"); + const TestNativeTokenReceiver = await getContractFactoryByName("TestNativeTokenReceiver"); const nativeTokenReceiver = await TestNativeTokenReceiver.deploy(); const reverterSource = ` @@ -171,7 +171,7 @@ describe("Safe", () => { const { safe, reverter, signers } = await setupTests(); const [user1] = signers; const safeAddress = await safe.getAddress(); - await user1.sendTransaction({ to: safeAddress, value: 10000000 }); + await (await user1.sendTransaction({ to: safeAddress, value: 10000000 })).wait(); await expect(executeContractCallWithSigners(safe, reverter, "revert", [], [user1], true, { gasPrice: 1 })).to.emit( safe, "ExecutionFailure", @@ -338,7 +338,7 @@ describe("Safe", () => { refundReceiver: nativeTokenReceiverAddress, }); - await user1.sendTransaction({ to: safeAddress, value: ethers.parseEther("1") }); + await (await user1.sendTransaction({ to: safeAddress, value: ethers.parseEther("1") })).wait(); await expect(await hre.ethers.provider.getBalance(safeAddress)).to.eq(ethers.parseEther("1")); const executedTx = await executeTx(safe, tx, [await safeApproveHash(user1, safe, tx, true)], { gasLimit: 500000 }); @@ -353,7 +353,7 @@ describe("Safe", () => { } } - expect(parsedLogs[0].forwardedGas).to.be.gte(400000n); + expect(parsedLogs[0].forwardedGas).to.be.gte(hre.network.zksync ? 340000n : 400000n); }); }); }); From deff3c1e993f2e8c76efc7fd00eb14bcc792c46d Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Tue, 22 Aug 2023 18:28:28 +0300 Subject: [PATCH 29/37] feat: force to use SafeL2 for tests on zkSync --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index e38dbe17f..3c1d2879e 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "build:ts": "rimraf dist && tsc -p tsconfig.prod.json", "build:ts:dev": "rimraf dist && tsc -p tsconfig.json", "test": "hardhat test", - "test:zk": "hardhat test --network zkSyncLocal", + "test:zk": "cross-env SAFE_CONTRACT_UNDER_TEST=SafeL2 hardhat test --network zkSyncLocal", "test:parallel": "hardhat test --parallel", "coverage": "hardhat coverage", "benchmark": "npm run test benchmark/*.ts", @@ -63,6 +63,7 @@ "@types/yargs": "^17.0.24", "@typescript-eslint/eslint-plugin": "^6.4.1", "@typescript-eslint/parser": "^6.4.1", + "cross-env": "^7.0.3", "debug": "^4.2.0", "dotenv": "^16.3.1", "eslint": "^8.47.0", From 4ec6926b0cfc62a872ca25183df76ab237db29c1 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Tue, 22 Aug 2023 18:29:30 +0300 Subject: [PATCH 30/37] feat: adjust new GuardManager tests for zksync --- test/core/Safe.GuardManager.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/core/Safe.GuardManager.spec.ts b/test/core/Safe.GuardManager.spec.ts index c190de2f7..33b542e89 100644 --- a/test/core/Safe.GuardManager.spec.ts +++ b/test/core/Safe.GuardManager.spec.ts @@ -277,7 +277,7 @@ describe("GuardManager", () => { const validGuardMockAddress = await validGuardMock.getAddress(); const hash = "0x" + crypto.randomBytes(32).toString("hex"); - await executeContractCallWithSigners(safe, safe, "enableModule", [user1.address], [user2]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user1.address], [user2])).wait(); const guardInterface = (await hre.ethers.getContractAt("Guard", validGuardMockAddress)).interface; const checkModuleTxData = guardInterface.encodeFunctionData("checkModuleTransaction", [ @@ -291,7 +291,7 @@ describe("GuardManager", () => { const checkAfterExecutionTxData = guardInterface.encodeFunctionData("checkAfterExecution", [hash, true]); await validGuardMock.givenCalldataReturnBytes32(checkModuleTxData, hash); - await safe.execTransactionFromModule(user1.address, 0, "0xbeef73", 1); + await (await safe.execTransactionFromModule(user1.address, 0, "0xbeef73", 1)).wait(); expect(await validGuardMock.invocationCountForCalldata(checkAfterExecutionTxData)).to.equal(1); }); @@ -347,7 +347,7 @@ describe("GuardManager", () => { const validGuardMockAddress = await validGuardMock.getAddress(); const hash = "0x" + crypto.randomBytes(32).toString("hex"); - await executeContractCallWithSigners(safe, safe, "enableModule", [user1.address], [user2]); + await (await executeContractCallWithSigners(safe, safe, "enableModule", [user1.address], [user2])).wait(); const guardInterface = (await hre.ethers.getContractAt("Guard", validGuardMockAddress)).interface; const checkModuleTxData = guardInterface.encodeFunctionData("checkModuleTransaction", [ @@ -361,7 +361,7 @@ describe("GuardManager", () => { const checkAfterExecutionTxData = guardInterface.encodeFunctionData("checkAfterExecution", [hash, true]); await validGuardMock.givenCalldataReturnBytes32(checkModuleTxData, hash); - await safe.execTransactionFromModuleReturnData(user1.address, 0, "0xbeef73", 1); + await (await safe.execTransactionFromModuleReturnData(user1.address, 0, "0xbeef73", 1)).wait(); expect(await validGuardMock.invocationCountForCalldata(checkAfterExecutionTxData)).to.equal(1); }); From 7deb8fc5c71c5444fb2ed4165d7d21a0425c3f12 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Tue, 22 Aug 2023 18:56:46 +0300 Subject: [PATCH 31/37] feat: restore setup tests related to send method for zksync --- test/core/Safe.Setup.spec.ts | 70 +++++++++++++++--------------------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/test/core/Safe.Setup.spec.ts b/test/core/Safe.Setup.spec.ts index a8aa66dfd..fd0f26a85 100644 --- a/test/core/Safe.Setup.spec.ts +++ b/test/core/Safe.Setup.spec.ts @@ -306,71 +306,57 @@ describe("Safe", () => { ).to.be.revertedWith("GS011"); }); - /** - * ## Skip for zkSync, due to Expected to fail with official SafeL2.sol due to the use of the unsupported send() function in the handlePayment() - * ## Expected to pass when send() will be replaced with call() - * ## Or after a protocol upgrade (see link2) - * @see https://era.zksync.io/docs/dev/building-on-zksync/contracts/differences-with-ethereum.html#using-call-over-send-or-transfer - * @see https://twitter.com/zksync/status/1644459406828924934 - */ - it("should work with ether payment to deployer", async function () { - if (hre.network.zksync) this.skip(); - + it("should work with ether payment to deployer", async () => { const { template, signers: [user1, user2, user3], } = await setupTests(); const templateAddress = await template.getAddress(); const payment = ethers.parseEther("10"); - await user1.sendTransaction({ to: templateAddress, value: payment }); + await (await user1.sendTransaction({ to: templateAddress, value: payment })).wait(); const userBalance = await hre.ethers.provider.getBalance(user1.address); await expect(await hre.ethers.provider.getBalance(templateAddress)).to.eq(ethers.parseEther("10")); - await template.setup( - [user1.address, user2.address, user3.address], - 2, - AddressZero, - "0x", - AddressZero, - AddressZero, - payment, - AddressZero, - ); + await ( + await template.setup( + [user1.address, user2.address, user3.address], + 2, + AddressZero, + "0x", + AddressZero, + AddressZero, + payment, + AddressZero, + ) + ).wait(); await expect(await hre.ethers.provider.getBalance(templateAddress)).to.eq(ethers.parseEther("0")); await expect(userBalance < (await hre.ethers.provider.getBalance(user1.address))).to.be.true; }); - /** - * ## Skip for zkSync, due to Expected to fail with official SafeL2.sol due to the use of the unsupported send() function in the handlePayment() - * ## Expected to pass when send() will be replaced with call() - * ## Or after a protocol upgrade (see link2) - * @see https://era.zksync.io/docs/dev/building-on-zksync/contracts/differences-with-ethereum.html#using-call-over-send-or-transfer - * @see https://twitter.com/zksync/status/1644459406828924934 - */ - it("should work with ether payment to account", async function () { - if (hre.network.zksync) this.skip(); - + it("should work with ether payment to account", async () => { const { template, signers: [user1, user2, user3], } = await setupTests(); const templateAddress = await template.getAddress(); const payment = ethers.parseEther("10"); - await user1.sendTransaction({ to: templateAddress, value: payment }); + await (await user1.sendTransaction({ to: templateAddress, value: payment })).wait(); const userBalance = await hre.ethers.provider.getBalance(user2.address); await expect(await hre.ethers.provider.getBalance(templateAddress)).to.eq(ethers.parseEther("10")); - await template.setup( - [user1.address, user2.address, user3.address], - 2, - AddressZero, - "0x", - AddressZero, - AddressZero, - payment, - user2.address, - ); + await ( + await template.setup( + [user1.address, user2.address, user3.address], + 2, + AddressZero, + "0x", + AddressZero, + AddressZero, + payment, + user2.address, + ) + ).wait(); await expect(await hre.ethers.provider.getBalance(templateAddress)).to.eq(ethers.parseEther("0")); await expect(await hre.ethers.provider.getBalance(user2.address)).to.eq(userBalance + payment); From 08e589422475f29acd65d082b4de654c589a1426 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Tue, 22 Aug 2023 19:24:10 +0300 Subject: [PATCH 32/37] fix: remove duplicated imports --- test/handlers/CompatibilityFallbackHandler.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/handlers/CompatibilityFallbackHandler.spec.ts b/test/handlers/CompatibilityFallbackHandler.spec.ts index 90c9631e9..b3dc3ac3a 100644 --- a/test/handlers/CompatibilityFallbackHandler.spec.ts +++ b/test/handlers/CompatibilityFallbackHandler.spec.ts @@ -3,6 +3,7 @@ import hre, { ethers } from "hardhat"; import { AddressZero } from "@ethersproject/constants"; import { getCompatFallbackHandler, getContractFactoryByName, getSafeWithOwners, getWallets } from "../utils/setup"; import { + buildContractSignature, buildSignatureBytes, executeContractCallWithSigners, calculateSafeMessageHash, From 0b46d6c2be59b390dfbcbb1192c62a5b2c2d0194 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Tue, 22 Aug 2023 20:07:39 +0300 Subject: [PATCH 33/37] feat: adjust new MultiSend tests for zksync --- test/libraries/MultiSend.spec.ts | 2 +- test/utils/setup.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/libraries/MultiSend.spec.ts b/test/libraries/MultiSend.spec.ts index 26d588ee0..631b77a12 100644 --- a/test/libraries/MultiSend.spec.ts +++ b/test/libraries/MultiSend.spec.ts @@ -242,7 +242,7 @@ describe("MultiSend", () => { const triggerCalldata = "0xbaddad"; const errorMessage = "Some random message"; - await mock.givenCalldataRevertWithMessage(triggerCalldata, errorMessage); + await (await mock.givenCalldataRevertWithMessage(triggerCalldata, errorMessage)).wait(); const txs: MetaTransaction[] = [ { diff --git a/test/utils/setup.ts b/test/utils/setup.ts index 4dfe2ca95..dccdb6140 100644 --- a/test/utils/setup.ts +++ b/test/utils/setup.ts @@ -166,7 +166,7 @@ export const getSafeProxyRuntimeCode = async () => { }; export const getDelegateCaller = async () => { - const DelegateCaller = await hre.ethers.getContractFactory("DelegateCaller"); + const DelegateCaller = await getContractFactoryByName("DelegateCaller"); return await DelegateCaller.deploy(); }; From 949949c52b4b206a726193e86d1ca16ee260d39d Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Tue, 22 Aug 2023 20:13:25 +0300 Subject: [PATCH 34/37] feat: adjust new MultiSendCallOnly test for zksync --- hardhat.config.ts | 3 +-- test/libraries/MultiSendCallOnly.spec.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/hardhat.config.ts b/hardhat.config.ts index 808bf9152..44127b3fe 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -131,8 +131,7 @@ const userConfig: HardhatUserConfig = { url: "https://mainnet.era.zksync.io", ethNetwork: "mainnet", zksync: true, - verifyURL: - "https://zksync2-mainnet-explorer.zksync.io/contract_verification", + verifyURL: "https://zksync2-mainnet-explorer.zksync.io/contract_verification", }, zkSyncTestnet: { ...sharedNetworkConfig, diff --git a/test/libraries/MultiSendCallOnly.spec.ts b/test/libraries/MultiSendCallOnly.spec.ts index 61036661c..000577ac1 100644 --- a/test/libraries/MultiSendCallOnly.spec.ts +++ b/test/libraries/MultiSendCallOnly.spec.ts @@ -197,7 +197,7 @@ describe("MultiSendCallOnly", () => { const triggerCalldata = "0xbaddad"; const errorMessage = "Some random message"; - await mock.givenCalldataRevertWithMessage(triggerCalldata, errorMessage); + await (await mock.givenCalldataRevertWithMessage(triggerCalldata, errorMessage)).wait(); const txs: MetaTransaction[] = [ { From d23c42bdcb13c3a2ce5400d256148afdba22aa52 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Tue, 22 Aug 2023 20:44:44 +0300 Subject: [PATCH 35/37] fix: remove redundant argument for TASK_DEPLOY before running zksync tests --- src/tasks/zk.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tasks/zk.ts b/src/tasks/zk.ts index 7bec80eb2..baaf643cc 100644 --- a/src/tasks/zk.ts +++ b/src/tasks/zk.ts @@ -12,10 +12,10 @@ subtask(TASK_TEST_SETUP_TEST_ENVIRONMENT).setAction(async (taskArgs, hre, runSup hre.config.mocha.timeout = 90_000; hre.config.mocha.slow = 30_000; - await hre.run(TASK_DEPLOY, { nonDeterministicZk: true, ...taskArgs }); - } else { - await runSuper(taskArgs); + await hre.run(TASK_DEPLOY, taskArgs); } + + await runSuper(taskArgs); }); const TASK_VERIFY_ZK_ALL = "verify:verify-zk-all"; From 0a9775b16f1df78bdf32d4f84fabdba28cb68581 Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Thu, 31 Aug 2023 16:00:07 +0300 Subject: [PATCH 36/37] wip: remove conflicting deps --- package-lock.json | 893 +++++++++++++++++++++++++++++++++++++++++++--- package.json | 8 +- 2 files changed, 839 insertions(+), 62 deletions(-) diff --git a/package-lock.json b/package-lock.json index ad5613a78..893b4e4cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "1.4.1-build.0", "license": "LGPL-3.0", "devDependencies": { + "@matterlabs/hardhat-zksync-solc": "^0.4.1", + "@matterlabs/hardhat-zksync-verify": "^0.2.0", "@nomicfoundation/hardhat-toolbox": "^3.0.0", "@openzeppelin/contracts": "^3.4.0", "@safe-global/mock-contract": "^4.0.0", @@ -19,6 +21,7 @@ "@types/yargs": "^17.0.24", "@typescript-eslint/eslint-plugin": "^6.4.1", "@typescript-eslint/parser": "^6.4.1", + "cross-env": "^7.0.3", "debug": "^4.2.0", "dotenv": "^16.3.1", "eslint": "^8.47.0", @@ -89,6 +92,12 @@ "node": ">=6.9.0" } }, + "node_modules/@balena/dockerignore": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz", + "integrity": "sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==", + "dev": true + }, "node_modules/@chainsafe/as-sha256": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz", @@ -1023,6 +1032,249 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@matterlabs/hardhat-zksync-solc": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-0.4.1.tgz", + "integrity": "sha512-fdlGf/2yZR5ihVNc2ubea1R/nNFXRONL29Fgz5FwB3azB13rPb76fkQgcFIg9zSufHsEy6zUUT029NkxLNA9Sw==", + "dev": true, + "dependencies": { + "@nomiclabs/hardhat-docker": "^2.0.0", + "chalk": "4.1.2", + "dockerode": "^3.3.4", + "fs-extra": "^11.1.1", + "semver": "^7.5.1" + }, + "peerDependencies": { + "hardhat": "^2.14.0" + } + }, + "node_modules/@matterlabs/hardhat-zksync-solc/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@matterlabs/hardhat-zksync-solc/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@matterlabs/hardhat-zksync-solc/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@matterlabs/hardhat-zksync-solc/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@matterlabs/hardhat-zksync-solc/node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@matterlabs/hardhat-zksync-solc/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@matterlabs/hardhat-zksync-solc/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@matterlabs/hardhat-zksync-solc/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@matterlabs/hardhat-zksync-solc/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@matterlabs/hardhat-zksync-solc/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@matterlabs/hardhat-zksync-verify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@matterlabs/hardhat-zksync-verify/-/hardhat-zksync-verify-0.2.0.tgz", + "integrity": "sha512-iUwxhPlNk+HWe+UadLqQzdDb2fammbKYoz8wqVuyr9jygFUf8JNPLWDZOS0KCQgRn/dmT22+i9nSREOg66bAHA==", + "dev": true, + "dependencies": { + "@matterlabs/hardhat-zksync-solc": "0.3.17", + "axios": "^1.4.0", + "chalk": "4.1.2", + "dockerode": "^3.3.4" + }, + "peerDependencies": { + "@nomicfoundation/hardhat-verify": "^1.0.2" + } + }, + "node_modules/@matterlabs/hardhat-zksync-verify/node_modules/@matterlabs/hardhat-zksync-solc": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-0.3.17.tgz", + "integrity": "sha512-aZgQ0yfXW5xPkfuEH1d44ncWV4T2LzKZd0VVPo4PL5cUrYs2/II1FaEDp5zsf3FxOR1xT3mBsjuSrtJkk4AL8Q==", + "dev": true, + "dependencies": { + "@nomiclabs/hardhat-docker": "^2.0.0", + "chalk": "4.1.2", + "dockerode": "^3.3.4" + }, + "peerDependencies": { + "hardhat": "^2.14.0" + } + }, + "node_modules/@matterlabs/hardhat-zksync-verify/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@matterlabs/hardhat-zksync-verify/node_modules/axios": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/@matterlabs/hardhat-zksync-verify/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@matterlabs/hardhat-zksync-verify/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@matterlabs/hardhat-zksync-verify/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@matterlabs/hardhat-zksync-verify/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@matterlabs/hardhat-zksync-verify/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@metamask/eth-sig-util": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", @@ -1681,52 +1933,273 @@ "node": ">= 10" } }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", - "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", - "cpu": [ - "arm64" - ], + "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz", + "integrity": "sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", + "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", + "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomiclabs/hardhat-docker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-docker/-/hardhat-docker-2.0.2.tgz", + "integrity": "sha512-XgGEpRT3wlA1VslyB57zyAHV+oll8KnV1TjwnxxC1tpAL04/lbdwpdO5KxInVN8irMSepqFpsiSkqlcnvbE7Ng==", + "dev": true, + "dependencies": { + "dockerode": "^2.5.8", + "fs-extra": "^7.0.1", + "node-fetch": "^2.6.0" + } + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "dev": true, + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/bl/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/bl/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/bl/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/docker-modem": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-1.0.9.tgz", + "integrity": "sha512-lVjqCSCIAUDZPAZIeyM125HXfNvOmYYInciphNrLrylUtKyW66meAjSPXWchKVzoIYZx69TPnAepVSSkeawoIw==", + "dev": true, + "dependencies": { + "debug": "^3.2.6", + "JSONStream": "1.3.2", + "readable-stream": "~1.0.26-4", + "split-ca": "^1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/dockerode": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-2.5.8.tgz", + "integrity": "sha512-+7iOUYBeDTScmOmQqpUYQaE7F4vvIt6+gIZNHWhqAQEI887tiPFB9OvXI/HzQYqfUNvukMK+9myLW63oTJPZpw==", + "dev": true, + "dependencies": { + "concat-stream": "~1.6.2", + "docker-modem": "^1.0.8", + "tar-fs": "~1.16.3" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/pump": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/tar-fs": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", + "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", + "dev": true, + "dependencies": { + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" + } + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "dev": true, + "dependencies": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/tar-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/@nomiclabs/hardhat-docker/node_modules/tar-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz", - "integrity": "sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==", - "cpu": [ - "ia32" - ], + "node_modules/@nomiclabs/hardhat-docker/node_modules/tar-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz", - "integrity": "sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==", - "cpu": [ - "x64" - ], + "node_modules/@nomiclabs/hardhat-docker/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">= 10" + "node": ">= 4.0.0" } }, "node_modules/@openzeppelin/contracts": { @@ -2813,7 +3286,6 @@ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, - "peer": true, "dependencies": { "safer-buffer": "~2.1.0" } @@ -2955,7 +3427,6 @@ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, - "peer": true, "dependencies": { "tweetnacl": "^0.14.3" } @@ -2964,8 +3435,7 @@ "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/bech32": { "version": "1.1.4", @@ -3000,6 +3470,41 @@ "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/blakejs": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", @@ -3128,6 +3633,28 @@ "ieee754": "^1.2.1" } }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", + "dev": true + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3140,6 +3667,16 @@ "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", "dev": true }, + "node_modules/buildcheck": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.6.tgz", + "integrity": "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==", + "dev": true, + "optional": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/bundle-name": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", @@ -3353,6 +3890,12 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, "node_modules/ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -3564,7 +4107,6 @@ "engines": [ "node >= 0.8" ], - "peer": true, "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -3577,7 +4119,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -3592,15 +4133,13 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "peer": true + "dev": true }, "node_modules/concat-stream/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -3618,8 +4157,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true, - "peer": true + "dev": true }, "node_modules/cosmiconfig": { "version": "8.2.0", @@ -3639,6 +4177,21 @@ "url": "https://github.com/sponsors/d-fischer" } }, + "node_modules/cpu-features": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.9.tgz", + "integrity": "sha512-AKjgn2rP2yJyfbepsmLfiYcmtNn/2eUvocUyM/09yB0YDiz39HteK/5/T4Onf0pmdYDMgkBoGvRLvEguzyL7wQ==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "buildcheck": "~0.0.6", + "nan": "^2.17.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/crc-32": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", @@ -3684,6 +4237,24 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3916,6 +4487,35 @@ "node": ">=8" } }, + "node_modules/docker-modem": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-3.0.8.tgz", + "integrity": "sha512-f0ReSURdM3pcKPNS30mxOHSbaFLcknGmQjwSfmbcdOw1XWKXVhukM3NJHhr7NpY9BIyyWQb0EBo3KQvvuU5egQ==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "readable-stream": "^3.5.0", + "split-ca": "^1.0.1", + "ssh2": "^1.11.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/dockerode": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-3.3.5.tgz", + "integrity": "sha512-/0YNa3ZDNeLr/tSckmD69+Gq+qVNhvKfAHNeZJBnp7EOP6RGKV8ORrJHkUn20So5wU+xxT7+1n5u8PjHbfjbSA==", + "dev": true, + "dependencies": { + "@balena/dockerignore": "^1.0.2", + "docker-modem": "^3.0.0", + "tar-fs": "~2.0.1" + }, + "engines": { + "node": ">= 8.0" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -3984,6 +4584,15 @@ "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==", "dev": true }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enquirer": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", @@ -5609,6 +6218,12 @@ "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", "dev": true }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -7290,8 +7905,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "peer": true + "dev": true }, "node_modules/isexe": { "version": "2.0.0", @@ -7391,6 +8005,15 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, "node_modules/jsonschema": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", @@ -7401,6 +8024,22 @@ "node": "*" } }, + "node_modules/JSONStream": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz", + "integrity": "sha512-mn0KSip7N4e0UDPZHnqDsHECo5uGQrixQKnAskOM1BIB8hd7QKbd6il8IPRPudPHOeHiECoCFqhyMaRO9+nWyA==", + "dev": true, + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -7833,7 +8472,6 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7843,7 +8481,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, - "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -7851,6 +8488,12 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, "node_modules/mnemonist": { "version": "0.38.5", "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", @@ -8050,6 +8693,13 @@ "imul": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", + "dev": true, + "optional": true + }, "node_modules/nanoid": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", @@ -8118,6 +8768,26 @@ "semver": "bin/semver" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-gyp-build": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", @@ -8669,8 +9339,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "peer": true + "dev": true }, "node_modules/promise": { "version": "8.3.0", @@ -8682,6 +9351,12 @@ "asap": "~2.0.6" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -8689,6 +9364,16 @@ "dev": true, "peer": true }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -10578,6 +11263,12 @@ "node": ">=0.10.0" } }, + "node_modules/split-ca": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz", + "integrity": "sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==", + "dev": true + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -10585,6 +11276,24 @@ "dev": true, "peer": true }, + "node_modules/ssh2": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.14.0.tgz", + "integrity": "sha512-AqzD1UCqit8tbOKoj6ztDDi1ffJZ2rV2SwlgrVVrHPkV5vWqGJOVp5pmtj18PunkPJAuKQsnInyKV+/Nb2bUnA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "asn1": "^0.2.6", + "bcrypt-pbkdf": "^1.0.2" + }, + "engines": { + "node": ">=10.16.0" + }, + "optionalDependencies": { + "cpu-features": "~0.0.8", + "nan": "^2.17.0" + } + }, "node_modules/sshpk": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", @@ -10973,6 +11682,34 @@ "node": ">=8" } }, + "node_modules/tar-fs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz", + "integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -11024,6 +11761,12 @@ "node": ">= 0.12" } }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, "node_modules/titleize": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", @@ -11048,6 +11791,12 @@ "node": ">=0.6.0" } }, + "node_modules/to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "dev": true + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -11083,6 +11832,12 @@ "node": ">=0.8" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, "node_modules/ts-api-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", @@ -11504,8 +12259,7 @@ "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/typescript": { "version": "5.1.6", @@ -11697,6 +12451,22 @@ "@scure/bip39": "1.2.1" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -11924,6 +12694,15 @@ "node": ">=0.4.0" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 3c1d2879e..33221a9a0 100644 --- a/package.json +++ b/package.json @@ -50,9 +50,8 @@ "url": "https://github.com/safe-global/safe-contracts/issues" }, "devDependencies": { - "@matterlabs/hardhat-zksync-deploy": "^0.6.3", "@matterlabs/hardhat-zksync-solc": "^0.4.1", - "@matterlabs/hardhat-zksync-verify": "^0.1.8", + "@matterlabs/hardhat-zksync-verify": "^0.2.0", "@nomicfoundation/hardhat-toolbox": "^3.0.0", "@openzeppelin/contracts": "^3.4.0", "@safe-global/mock-contract": "^4.0.0", @@ -63,7 +62,7 @@ "@types/yargs": "^17.0.24", "@typescript-eslint/eslint-plugin": "^6.4.1", "@typescript-eslint/parser": "^6.4.1", - "cross-env": "^7.0.3", + "cross-env": "^7.0.3", "debug": "^4.2.0", "dotenv": "^16.3.1", "eslint": "^8.47.0", @@ -79,7 +78,6 @@ "solhint": "3.6.2", "ts-node": "^10.9.1", "typescript": "^5.1.6", - "yargs": "^17.7.2", - "zksync-web3": "^0.14.3" + "yargs": "^17.7.2" } } From fd1f3b055ab6722f2ce6ef4ef9bbf58c53bf065f Mon Sep 17 00:00:00 2001 From: Nikita Zasimuk Date: Thu, 31 Aug 2023 16:11:32 +0300 Subject: [PATCH 37/37] wip: fix rebasing conflicts --- src/tasks/local_verify.ts | 4 ++-- src/tasks/zk.ts | 1 - src/utils/proxies.ts | 12 ++++++------ test/utils/setup.ts | 2 +- yarn.lock | 0 5 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 yarn.lock diff --git a/src/tasks/local_verify.ts b/src/tasks/local_verify.ts index 50ecc7606..f525642ab 100644 --- a/src/tasks/local_verify.ts +++ b/src/tasks/local_verify.ts @@ -41,9 +41,9 @@ task("local-verify", "Verifies that the local deployment files correspond to the for (const contract of Object.keys(deployedContracts)) { const deployment = await hre.deployments.get(contract); const onChainCode = await hre.ethers.provider.getCode(deployment.address); - const onchainBytecodeHash = hre.ethers.utils.keccak256(onChainCode); + const onchainBytecodeHash = hre.ethers.keccak256(onChainCode); // TODO: compile contract in realtime and compare the compiled bytecode with onchain bytecode - const localBytecodeHash = hre.ethers.utils.keccak256(deployment.deployedBytecode!); + const localBytecodeHash = hre.ethers.keccak256(deployment.deployedBytecode!); const verifySuccess = onchainBytecodeHash === localBytecodeHash ? "\x1b[32mSUCCESS\x1b[0m" : "\x1b[31mFAILURE\x1b[0m"; console.log(`Verification status for ${contract}: ${verifySuccess}`); } diff --git a/src/tasks/zk.ts b/src/tasks/zk.ts index baaf643cc..92dc9f8cf 100644 --- a/src/tasks/zk.ts +++ b/src/tasks/zk.ts @@ -1,7 +1,6 @@ import "hardhat-deploy"; import { TASK_DEPLOY } from "hardhat-deploy"; import { TASK_VERIFY_VERIFY } from "@matterlabs/hardhat-zksync-verify/dist/src/constants"; -import "@nomiclabs/hardhat-ethers"; import { TASK_TEST_SETUP_TEST_ENVIRONMENT } from "hardhat/builtin-tasks/task-names"; import { subtask } from "hardhat/config"; diff --git a/src/utils/proxies.ts b/src/utils/proxies.ts index c0c53c86f..ec7758441 100644 --- a/src/utils/proxies.ts +++ b/src/utils/proxies.ts @@ -5,15 +5,15 @@ import { SafeProxyFactory } from "../../typechain-types"; export const calculateProxyAddress = async (factory: SafeProxyFactory, singleton: string, inititalizer: string, nonce: number | string) => { const salt = ethers.solidityPackedKeccak256(["bytes32", "uint256"], [ethers.solidityPackedKeccak256(["bytes"], [inititalizer]), nonce]); + const factoryAddress = await factory.getAddress(); if (hre.network.zksync) { const proxyCreationCode = (await hre.artifacts.readArtifact("SafeProxy")).deployedBytecode; const bytecodehash = zk.utils.hashBytecode(proxyCreationCode); - const input = new ethers.utils.AbiCoder().encode(["address"], [singleton]); - return zk.utils.create2Address(factory.address, bytecodehash, salt, input); + const input = new ethers.AbiCoder().encode(["address"], [singleton]); + return zk.utils.create2Address(factoryAddress, bytecodehash, salt, input); } - const factoryAddress = await factory.getAddress(); const deploymentCode = ethers.solidityPacked(["bytes", "uint256"], [await factory.proxyCreationCode(), singleton]); return ethers.getCreate2Address(factoryAddress, salt, ethers.keccak256(deploymentCode)); }; @@ -40,15 +40,15 @@ export const calculateChainSpecificProxyAddress = async ( ["bytes32", "uint256", "uint256"], [ethers.solidityPackedKeccak256(["bytes"], [inititalizer]), nonce, chainId], ); + const factoryAddress = await factory.getAddress(); if (hre.network.zksync) { const proxyCreationCode = (await hre.artifacts.readArtifact("SafeProxy")).deployedBytecode; const bytecodehash = zk.utils.hashBytecode(proxyCreationCode); - const input = new ethers.utils.AbiCoder().encode(["address"], [singleton]); - return zk.utils.create2Address(factory.address, bytecodehash, salt, input); + const input = new ethers.AbiCoder().encode(["address"], [singleton]); + return zk.utils.create2Address(factoryAddress, bytecodehash, salt, input); } - const factoryAddress = await factory.getAddress(); const deploymentCode = ethers.solidityPacked(["bytes", "uint256"], [await factory.proxyCreationCode(), singleton]); return ethers.getCreate2Address(factoryAddress, salt, ethers.keccak256(deploymentCode)); }; diff --git a/test/utils/setup.ts b/test/utils/setup.ts index dccdb6140..250929b5e 100644 --- a/test/utils/setup.ts +++ b/test/utils/setup.ts @@ -1,4 +1,4 @@ -import hre, { deployments, waffle } from "hardhat"; +import hre, { deployments } from "hardhat"; import { Contract, Signer, ethers } from "ethers"; import { AddressZero } from "@ethersproject/constants"; import solc from "solc"; diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index e69de29bb..000000000