From 6e50457b799e2702da9ecf2c03cd5df517649171 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:18:09 +0200 Subject: [PATCH 01/73] build: Bump FHEVM to 0.5 --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 516bbde..d3a9ef0 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,13 @@ "eslint": "^8.57.0", "eslint-config-prettier": "^8.10.0", "ethers": "^6.11.1", - "fhevm": "^0.4.0", - "fhevmjs": "^0.4.0-7", + "fhevm": "^0.5.9", + "fhevmjs": "^0.5.7", "fs-extra": "^10.1.0", "hardhat": "2.21.0", "hardhat-deploy": "^0.11.45", "hardhat-gas-reporter": "^1.0.10", + "hardhat-ignore-warnings": "^0.2.11", "hardhat-preprocessor": "^0.1.5", "lodash": "^4.17.21", "mocha": "^10.3.0", @@ -79,7 +80,7 @@ "typechain": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat typechain", "test": "hardhat test", "test:mock": "HARDHAT_NETWORK=hardhat npx hardhat test --network hardhat", - "coverage:mock": "HARDHAT_NETWORK=hardhat npx hardhat coverage-mock --network hardhat", + "coverage:mock": "hardhat coverage", "task:getEthereumAddress": "hardhat task:getEthereumAddress", "task:accounts": "hardhat task:accounts", "fhevm:start": "./launch-fhevm.sh", From f989af4eb267520776acc72f1be998b6e8b95417 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 21 Oct 2024 16:54:41 +0200 Subject: [PATCH 02/73] chore: Updates hardhat config --- hardhat.config.ts | 150 +++++++++++++++++++--------------------------- 1 file changed, 61 insertions(+), 89 deletions(-) diff --git a/hardhat.config.ts b/hardhat.config.ts index 8edd0d9..2b82be9 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,68 +1,46 @@ import "@nomicfoundation/hardhat-toolbox"; import dotenv from "dotenv"; -import * as fs from "fs"; +import * as fs from "fs-extra"; import "hardhat-deploy"; -import "hardhat-preprocessor"; -import { TASK_PREPROCESS } from "hardhat-preprocessor"; +import "hardhat-ignore-warnings"; import type { HardhatUserConfig } from "hardhat/config"; +import { extendProvider } from "hardhat/config"; import { task } from "hardhat/config"; import type { NetworkUserConfig } from "hardhat/types"; import { resolve } from "path"; import * as path from "path"; +import CustomProvider from "./CustomProvider"; +// Adjust the import path as needed import "./tasks/accounts"; import "./tasks/getEthereumAddress"; -import "./tasks/taskOracleRelayer"; +import "./tasks/taskDeploy"; +import "./tasks/taskGatewayRelayer"; +import "./tasks/taskTFHE"; -function getAllSolidityFiles(dir: string, fileList: string[] = []): string[] { - fs.readdirSync(dir).forEach((file) => { - const filePath = path.join(dir, file); - if (fs.statSync(filePath).isDirectory()) { - getAllSolidityFiles(filePath, fileList); - } else if (filePath.endsWith(".sol")) { - fileList.push(filePath); - } - }); - return fileList; -} +extendProvider(async (provider) => { + const newProvider = new CustomProvider(provider); + return newProvider; +}); -task("coverage-mock", "Run coverage after running pre-process task").setAction(async function (args, env) { - const contractsPath = path.join(env.config.paths.root, "contracts/"); - const solidityFiles = getAllSolidityFiles(contractsPath); - const originalContents: Record = {}; - solidityFiles.forEach((filePath) => { - originalContents[filePath] = fs.readFileSync(filePath, { encoding: "utf8" }); - }); +task("compile:specific", "Compiles only the specified contract") + .addParam("contract", "The contract's path") + .setAction(async ({ contract }, hre) => { + // Adjust the configuration to include only the specified contract + hre.config.paths.sources = contract; - try { - await env.run(TASK_PREPROCESS); - await env.run("coverage"); - } finally { - // Restore original files - for (const filePath in originalContents) { - fs.writeFileSync(filePath, originalContents[filePath], { encoding: "utf8" }); - } - } -}); + await hre.run("compile"); + }); const dotenvConfigPath: string = process.env.DOTENV_CONFIG_PATH || "./.env"; dotenv.config({ path: resolve(__dirname, dotenvConfigPath) }); +// Ensure that we have all the environment variables we need. const mnemonic: string | undefined = process.env.MNEMONIC; if (!mnemonic) { throw new Error("Please set your MNEMONIC in a .env file"); } -const network = process.env.HARDHAT_NETWORK; - -function getRemappings() { - return fs - .readFileSync("remappings.txt", "utf8") - .split("\n") - .filter(Boolean) // remove empty lines - .map((line: string) => line.trim().split("=")); -} - const chainIds = { zama: 8009, local: 9000, @@ -97,59 +75,49 @@ function getChainConfig(chain: keyof typeof chainIds): NetworkUserConfig { }; } +task("coverage").setAction(async (taskArgs, hre, runSuper) => { + hre.config.networks.hardhat.allowUnlimitedContractSize = true; + hre.config.networks.hardhat.blockGasLimit = 1099511627775; + await runSuper(taskArgs); +}); + task("test", async (taskArgs, hre, runSuper) => { // Run modified test task - - if (network === "hardhat") { + if (hre.network.name === "hardhat") { // in fhevm mode all this block is done when launching the node via `pnmp fhevm:start` - const privKeyDeployer = process.env.PRIVATE_KEY_ORACLE_DEPLOYER; - const privKeyOwner = process.env.PRIVATE_KEY_ORACLE_OWNER; - const privKeyRelayer = process.env.PRIVATE_KEY_ORACLE_RELAYER; - const deployerAddress = new hre.ethers.Wallet(privKeyDeployer!).address; - const ownerAddress = new hre.ethers.Wallet(privKeyOwner!).address; - const relayerAddress = new hre.ethers.Wallet(privKeyRelayer!).address; - + const privKeyDeployer = process.env.PRIVATE_KEY_GATEWAY_DEPLOYER; await hre.run("task:computePredeployAddress", { privateKey: privKeyDeployer }); - - const bal = "0x1000000000000000000000000000000000000000"; - const p1 = hre.network.provider.send("hardhat_setBalance", [deployerAddress, bal]); - const p2 = hre.network.provider.send("hardhat_setBalance", [ownerAddress, bal]); - const p3 = hre.network.provider.send("hardhat_setBalance", [relayerAddress, bal]); - await Promise.all([p1, p2, p3]); - await hre.run("compile"); - await hre.run("task:deployOracle", { privateKey: privKeyDeployer, ownerAddress: ownerAddress }); - - const parsedEnv = dotenv.parse(fs.readFileSync("node_modules/fhevm/oracle/.env.oracle")); - const oraclePredeployAddress = parsedEnv.ORACLE_CONTRACT_PREDEPLOY_ADDRESS; - - await hre.run("task:addRelayer", { - privateKey: privKeyOwner, - oracleAddress: oraclePredeployAddress, - relayerAddress: relayerAddress, - }); + await hre.run("task:computeACLAddress"); + await hre.run("task:computeTFHEExecutorAddress"); + await hre.run("task:computeKMSVerifierAddress"); + + await hre.run("compile:specific", { contract: "contracts" }); + const sourceDir = path.resolve(__dirname, "node_modules/fhevm/"); + const destinationDir = path.resolve(__dirname, "fhevmTemp/"); + fs.copySync(sourceDir, destinationDir, { dereference: true }); + await hre.run("compile:specific", { contract: "fhevmTemp/lib" }); + await hre.run("compile:specific", { contract: "fhevmTemp/gateway" }); + const abiDir = path.resolve(__dirname, "abi"); + fs.ensureDirSync(abiDir); + const sourceFile = path.resolve(__dirname, "artifacts/fhevmTemp/lib/TFHEExecutor.sol/TFHEExecutor.json"); + const destinationFile = path.resolve(abiDir, "TFHEExecutor.json"); + fs.copyFileSync(sourceFile, destinationFile); + + const targetAddress = "0x000000000000000000000000000000000000005d"; + const MockedPrecompile = await hre.artifacts.readArtifact("MockedPrecompile"); + const bytecode = MockedPrecompile.deployedBytecode; + await hre.network.provider.send("hardhat_setCode", [targetAddress, bytecode]); + console.log(`Code of Mocked Pre-compile set at address: ${targetAddress}`); + + await hre.run("task:deployACL"); + await hre.run("task:deployTFHEExecutor"); + await hre.run("task:deployKMSVerifier"); + await hre.run("task:launchFhevm", { skipGetCoin: false }); } - await runSuper(); }); const config: HardhatUserConfig = { - preprocess: { - eachLine: () => ({ - transform: (line: string) => { - if (network === "hardhat") { - if (line.match(/".*.sol";$/)) { - for (const [from, to] of getRemappings()) { - if (line.includes(from)) { - line = line.replace(from, to); - break; - } - } - } - } - return line; - }, - }), - }, defaultNetwork: "local", namedAccounts: { deployer: 0, @@ -165,7 +133,6 @@ const config: HardhatUserConfig = { }, networks: { hardhat: { - gas: "auto", accounts: { count: 10, mnemonic, @@ -185,7 +152,7 @@ const config: HardhatUserConfig = { tests: "./test", }, solidity: { - version: "0.8.22", + version: "0.8.24", settings: { metadata: { // Not including the metadata hash @@ -198,7 +165,12 @@ const config: HardhatUserConfig = { enabled: true, runs: 800, }, - evmVersion: "shanghai", + evmVersion: "cancun", + }, + }, + warnings: { + "*": { + "transient-storage": false, }, }, typechain: { From a24c1dfc559194f366fa22fd7f724e6e13d68116 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:13:30 +0200 Subject: [PATCH 03/73] chore: Updates tasks for fhevm 0.5 --- tasks/taskDeploy.ts | 65 ++++++++++++++++ tasks/taskGatewayRelayer.ts | 149 ++++++++++++++++++++++++++++++++++++ tasks/taskOracleRelayer.ts | 2 +- tasks/taskTFHE.ts | 97 +++++++++++++++++++++++ 4 files changed, 312 insertions(+), 1 deletion(-) create mode 100644 tasks/taskDeploy.ts create mode 100644 tasks/taskGatewayRelayer.ts create mode 100644 tasks/taskTFHE.ts diff --git a/tasks/taskDeploy.ts b/tasks/taskDeploy.ts new file mode 100644 index 0000000..86888ce --- /dev/null +++ b/tasks/taskDeploy.ts @@ -0,0 +1,65 @@ +import dotenv from "dotenv"; +import fs from "fs"; +import { task } from "hardhat/config"; +import type { TaskArguments } from "hardhat/types"; + +task("task:deployGateway") + .addParam("privateKey", "The deployer private key") + .addParam("ownerAddress", "The owner address") + .setAction(async function (taskArguments: TaskArguments, { ethers }) { + const deployer = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); + const envConfig2 = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.kmsverifier")); + const gatewayFactory = await ethers.getContractFactory("fhevm/gateway/GatewayContract.sol:GatewayContract"); + const Gateway = await gatewayFactory + .connect(deployer) + .deploy(taskArguments.ownerAddress, envConfig2.KMS_VERIFIER_CONTRACT_ADDRESS); + await Gateway.waitForDeployment(); + const GatewayContractAddress = await Gateway.getAddress(); + const envConfig = dotenv.parse(fs.readFileSync("node_modules/fhevm/gateway/.env.gateway")); + if (GatewayContractAddress !== envConfig.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS) { + throw new Error( + `The nonce of the deployer account is not null. Please use another deployer private key or relaunch a clean instance of the fhEVM`, + ); + } + console.log("GatewayContract was deployed at address: ", GatewayContractAddress); + }); + +task("task:deployACL").setAction(async function (taskArguments: TaskArguments, { ethers }) { + const deployer = (await ethers.getSigners())[9]; + const factory = await ethers.getContractFactory("fhevm/lib/ACL.sol:ACL"); + const envConfigExec = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.exec")); + const acl = await factory.connect(deployer).deploy(envConfigExec.TFHE_EXECUTOR_CONTRACT_ADDRESS); + await acl.waitForDeployment(); + const address = await acl.getAddress(); + const envConfigAcl = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.acl")); + if (address !== envConfigAcl.ACL_CONTRACT_ADDRESS) { + throw new Error(`The nonce of the deployer account is not corret. Please relaunch a clean instance of the fhEVM`); + } + console.log("ACL was deployed at address:", address); +}); + +task("task:deployTFHEExecutor").setAction(async function (taskArguments: TaskArguments, { ethers }) { + const deployer = (await ethers.getSigners())[9]; + const factory = await ethers.getContractFactory("TFHEExecutor"); + const exec = await factory.connect(deployer).deploy(); + await exec.waitForDeployment(); + const address = await exec.getAddress(); + const envConfig = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.exec")); + if (address !== envConfig.TFHE_EXECUTOR_CONTRACT_ADDRESS) { + throw new Error(`The nonce of the deployer account is not corret. Please relaunch a clean instance of the fhEVM`); + } + console.log("TFHEExecutor was deployed at address:", address); +}); + +task("task:deployKMSVerifier").setAction(async function (taskArguments: TaskArguments, { ethers }) { + const deployer = (await ethers.getSigners())[9]; + const factory = await ethers.getContractFactory("fhevm/lib/KMSVerifier.sol:KMSVerifier"); + const exec = await factory.connect(deployer).deploy(); + await exec.waitForDeployment(); + const address = await exec.getAddress(); + const envConfig = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.kmsverifier")); + if (address !== envConfig.KMS_VERIFIER_CONTRACT_ADDRESS) { + throw new Error(`The nonce of the deployer account is not corret. Please relaunch a clean instance of the fhEVM`); + } + console.log("KMSVerifier was deployed at address:", address); +}); diff --git a/tasks/taskGatewayRelayer.ts b/tasks/taskGatewayRelayer.ts new file mode 100644 index 0000000..fb22ce9 --- /dev/null +++ b/tasks/taskGatewayRelayer.ts @@ -0,0 +1,149 @@ +import { exec as oldExec } from "child_process"; +import dotenv from "dotenv"; +import fs from "fs"; +import { task, types } from "hardhat/config"; +import type { TaskArguments } from "hardhat/types"; +import path from "path"; +import { promisify } from "util"; + +const exec = promisify(oldExec); + +const getCoin = async (address: string) => { + const containerName = process.env["TEST_CONTAINER_NAME"] || "zama-kms-validator-1"; + const response = await exec(`docker exec -i ${containerName} faucet ${address} | grep height`); + const res = JSON.parse(response.stdout); + if (res.raw_log.match("account sequence mismatch")) await getCoin(address); +}; + +task("task:computePredeployAddress") + .addParam("privateKey", "The deployer private key") + .setAction(async function (taskArguments: TaskArguments, { ethers }) { + const deployerAddress = new ethers.Wallet(taskArguments.privateKey).address; + const gatewayContractAddressPrecomputed = ethers.getCreateAddress({ + from: deployerAddress, + nonce: 0, // deployer is supposed to have nonce 0 when deploying GatewayContract + }); + const envFilePath = path.join(__dirname, "../node_modules/fhevm/gateway/.env.gateway"); + const content = `GATEWAY_CONTRACT_PREDEPLOY_ADDRESS=${gatewayContractAddressPrecomputed}\n`; + try { + fs.writeFileSync(envFilePath, content, { flag: "w" }); + console.log("gatewayContractAddress written to gateway/.env.gateway successfully!"); + } catch (err) { + console.error("Failed to write to node_modules/fhevm/gateway/.env.gateway:", err); + } + + const solidityTemplate = `// SPDX-License-Identifier: BSD-3-Clause-Clear + +pragma solidity ^0.8.24; + +address constant GATEWAY_CONTRACT_PREDEPLOY_ADDRESS = ${gatewayContractAddressPrecomputed}; + `; + + try { + fs.writeFileSync("./node_modules/fhevm/gateway/lib/PredeployAddress.sol", solidityTemplate, { + encoding: "utf8", + flag: "w", + }); + console.log("node_modules/fhevm/gateway/lib/PredeployAddress.sol file has been generated successfully."); + } catch (error) { + console.error("Failed to write node_modules/fhevm/gateway/lib/PredeployAddress.sol", error); + } + }); + +task("task:addRelayer") + .addParam("privateKey", "The owner private key") + .addParam("gatewayAddress", "The GatewayContract address") + .addParam("relayerAddress", "The relayer address") + .setAction(async function (taskArguments: TaskArguments, { ethers }) { + const codeAtAddress = await ethers.provider.getCode(taskArguments.gatewayAddress); + if (codeAtAddress === "0x") { + throw Error(`${taskArguments.gatewayAddress} is not a smart contract`); + } + const owner = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); + const gateway = await ethers.getContractAt( + "fhevm/gateway/GatewayContract.sol:GatewayContract", + taskArguments.gatewayAddress, + owner, + ); + const tx = await gateway.addRelayer(taskArguments.relayerAddress); + const rcpt = await tx.wait(); + if (rcpt!.status === 1) { + console.log(`Account ${taskArguments.relayerAddress} was succesfully added as an gateway relayer`); + } else { + console.log("Adding relayer failed"); + } + }); + +task("task:removeRelayer") + .addParam("privateKey", "The owner private key") + .addParam("gatewayAddress", "The GatewayContract address") + .addParam("relayerAddress", "The relayer address") + .setAction(async function (taskArguments: TaskArguments, { ethers }) { + const codeAtAddress = await ethers.provider.getCode(taskArguments.gatewayAddress); + if (codeAtAddress === "0x") { + throw Error(`${taskArguments.gatewayAddress} is not a smart contract`); + } + const owner = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); + const gateway = await ethers.getContractAt( + "fhevm/gateway/GatewayContract.sol:GatewayContract", + taskArguments.gatewayAddress, + owner, + ); + const tx = await gateway.removeRelayer(taskArguments.relayerAddress); + const rcpt = await tx.wait(); + if (rcpt!.status === 1) { + console.log(`Account ${taskArguments.relayerAddress} was succesfully removed from authorized relayers`); + } else { + console.log("Removing relayer failed"); + } + }); + +task("task:launchFhevm") + .addOptionalParam("skipGetCoin", "Skip calling getCoin()", false, types.boolean) + .setAction(async function (taskArgs, hre) { + const privKeyDeployer = process.env.PRIVATE_KEY_GATEWAY_DEPLOYER; + const privKeyOwner = process.env.PRIVATE_KEY_GATEWAY_OWNER; + const privKeyRelayer = process.env.PRIVATE_KEY_GATEWAY_RELAYER; + const deployerAddress = new hre.ethers.Wallet(privKeyDeployer!).address; + const ownerAddress = new hre.ethers.Wallet(privKeyOwner!).address; + const relayerAddress = new hre.ethers.Wallet(privKeyRelayer!).address; + if (!taskArgs.skipGetCoin) { + if (hre.network.name === "hardhat") { + const bal = "0x1000000000000000000000000000000000000000"; + const p1 = hre.network.provider.send("hardhat_setBalance", [deployerAddress, bal]); + const p2 = hre.network.provider.send("hardhat_setBalance", [ownerAddress, bal]); + const p3 = hre.network.provider.send("hardhat_setBalance", [relayerAddress, bal]); + await Promise.all([p1, p2, p3]); + } else { + const p1 = getCoin(deployerAddress); + const p2 = getCoin(ownerAddress); + const p3 = getCoin(relayerAddress); + await Promise.all([p1, p2, p3]); + await new Promise((res) => setTimeout(res, 5000)); // wait 5 seconds + } + } + console.log(`privateKey ${privKeyDeployer}`); + console.log(`ownerAddress ${ownerAddress}`); + await hre.run("task:deployGateway", { privateKey: privKeyDeployer, ownerAddress: ownerAddress }); + + const parsedEnv = dotenv.parse(fs.readFileSync("node_modules/fhevm/gateway/.env.gateway")); + const gatewayContractAddress = parsedEnv.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS; + + await hre.run("task:addRelayer", { + privateKey: privKeyOwner, + gatewayAddress: gatewayContractAddress, + relayerAddress: relayerAddress, + }); + }); + +task("task:getBalances").setAction(async function (taskArgs, hre) { + const privKeyDeployer = process.env.PRIVATE_KEY_GATEWAY_DEPLOYER; + const privKeyOwner = process.env.PRIVATE_KEY_GATEWAY_OWNER; + const privKeyRelayer = process.env.PRIVATE_KEY_GATEWAY_RELAYER; + const deployerAddress = new hre.ethers.Wallet(privKeyDeployer!).address; + const ownerAddress = new hre.ethers.Wallet(privKeyOwner!).address; + const relayerAddress = new hre.ethers.Wallet(privKeyRelayer!).address; + console.log(await hre.ethers.provider.getBalance(deployerAddress)); + console.log(await hre.ethers.provider.getBalance(ownerAddress)); + console.log(await hre.ethers.provider.getBalance(relayerAddress)); +}); diff --git a/tasks/taskOracleRelayer.ts b/tasks/taskOracleRelayer.ts index f20472c..f4ac15f 100644 --- a/tasks/taskOracleRelayer.ts +++ b/tasks/taskOracleRelayer.ts @@ -52,7 +52,7 @@ task("task:computePredeployAddress") const solidityTemplate = `// SPDX-License-Identifier: BSD-3-Clause-Clear -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; address constant ORACLE_CONTRACT_PREDEPLOY_ADDRESS = ${oraclePredeployAddressPrecomputed}; `; diff --git a/tasks/taskTFHE.ts b/tasks/taskTFHE.ts new file mode 100644 index 0000000..15ee0ef --- /dev/null +++ b/tasks/taskTFHE.ts @@ -0,0 +1,97 @@ +import fs from "fs"; +import { task } from "hardhat/config"; +import type { TaskArguments } from "hardhat/types"; +import path from "path"; + +task("task:computeACLAddress").setAction(async function (taskArguments: TaskArguments, { ethers }) { + const deployer = (await ethers.getSigners())[9].address; + const aclAddress = ethers.getCreateAddress({ + from: deployer, + nonce: 0, // using nonce of 0 for the ACL contract + }); + const envFilePath = path.join(__dirname, "../node_modules/fhevm/lib/.env.acl"); + const content = `ACL_CONTRACT_ADDRESS=${aclAddress}\n`; + try { + fs.writeFileSync(envFilePath, content, { flag: "w" }); + console.log(`ACL address ${aclAddress} written successfully!`); + } catch (err) { + console.error("Failed to write ACL address:", err); + } + + const solidityTemplate = `// SPDX-License-Identifier: BSD-3-Clause-Clear + +pragma solidity ^0.8.24; + +address constant aclAdd = ${aclAddress};\n`; + + try { + fs.writeFileSync("node_modules/fhevm/lib/ACLAddress.sol", solidityTemplate, { encoding: "utf8", flag: "w" }); + console.log("node_modules/fhevm/lib/ACLAddress.sol file generated successfully!"); + } catch (error) { + console.error("Failed to write node_modules/fhevm/lib/ACLAddress.sol", error); + } +}); + +task("task:computeTFHEExecutorAddress").setAction(async function (taskArguments: TaskArguments, { ethers }) { + const deployer = (await ethers.getSigners())[9].address; + const execAddress = ethers.getCreateAddress({ + from: deployer, + nonce: 1, // using nonce of 1 for the TFHEExecutor contract + }); + const envFilePath = path.join(__dirname, "../node_modules/fhevm/lib/.env.exec"); + const content = `TFHE_EXECUTOR_CONTRACT_ADDRESS=${execAddress}\n`; + try { + fs.writeFileSync(envFilePath, content, { flag: "w" }); + console.log(`TFHE Executor address ${execAddress} written successfully!`); + } catch (err) { + console.error("Failed to write TFHE Executor address:", err); + } + + const solidityTemplateCoprocessor = `// SPDX-License-Identifier: BSD-3-Clause-Clear + +pragma solidity ^0.8.24; + +address constant fhevmCoprocessorAdd = ${execAddress};\n`; + + try { + fs.writeFileSync("node_modules/fhevm/lib/FHEVMCoprocessorAddress.sol", solidityTemplateCoprocessor, { + encoding: "utf8", + flag: "w", + }); + console.log("node_modules/fhevm/lib/FHEVMCoprocessorAddress.sol file generated successfully!"); + } catch (error) { + console.error("Failed to write node_modules/fhevm/lib/FHEVMCoprocessorAddress.sol", error); + } +}); + +task("task:computeKMSVerifierAddress").setAction(async function (taskArguments: TaskArguments, { ethers }) { + const deployer = (await ethers.getSigners())[9].address; + const kmsVerifierAddress = ethers.getCreateAddress({ + from: deployer, + nonce: 2, // using nonce of 2 for the Kms Verifier contract + }); + const envFilePath = path.join(__dirname, "../node_modules/fhevm/lib/.env.kmsverifier"); + const content = `KMS_VERIFIER_CONTRACT_ADDRESS=${kmsVerifierAddress}\n`; + try { + fs.writeFileSync(envFilePath, content, { flag: "w" }); + console.log(`KMS Verifier address ${kmsVerifierAddress} written successfully!`); + } catch (err) { + console.error("Failed to write KMS Verifier address:", err); + } + + const solidityTemplate = `// SPDX-License-Identifier: BSD-3-Clause-Clear + +pragma solidity ^0.8.24; + +address constant KMS_VERIFIER_CONTRACT_ADDRESS = ${kmsVerifierAddress};\n`; + + try { + fs.writeFileSync("node_modules/fhevm/lib/KMSVerifierAddress.sol", solidityTemplate, { + encoding: "utf8", + flag: "w", + }); + console.log("node_modules/fhevm/lib/KMSVerifierAddress.sol file generated successfully!"); + } catch (error) { + console.error("Failed to write node_modules/fhevm/lib/KMSVerifierAddress.sol", error); + } +}); From 2182ebe005b2a2e6c5c1a8f9b72d8b860e987a06 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:14:07 +0200 Subject: [PATCH 04/73] chore: Updates EIP1193 custom provider --- CustomProvider.ts | 62 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 CustomProvider.ts diff --git a/CustomProvider.ts b/CustomProvider.ts new file mode 100644 index 0000000..b60308e --- /dev/null +++ b/CustomProvider.ts @@ -0,0 +1,62 @@ +import { ethers } from "ethers"; +import { ProviderWrapper } from "hardhat/plugins"; +import type { EIP1193Provider, RequestArguments } from "hardhat/types"; + +interface Test { + request: EIP1193Provider["request"]; +} + +class CustomProvider extends ProviderWrapper implements Test { + public lastBlockSnapshot: number; + public lastCounterRand: number; + public lastBlockSnapshotForDecrypt: number; + + constructor(protected readonly _wrappedProvider: EIP1193Provider) { + super(_wrappedProvider); + this.lastBlockSnapshot = 0; // Initialize the variable + this.lastCounterRand = 0; + this.lastBlockSnapshotForDecrypt = 0; + } + + async request(args: RequestArguments): ReturnType { + if (args.method === "eth_estimateGas") { + const estimatedGasLimit = BigInt((await this._wrappedProvider.request(args)) as bigint); + const increasedGasLimit = ethers.toBeHex((estimatedGasLimit * 120n) / 100n); // override estimated gasLimit by 120%, to avoid some edge case with ethermint gas estimation + return increasedGasLimit; + } + if (args.method === "evm_revert") { + const result = await this._wrappedProvider.request(args); + const blockNumberHex = (await this._wrappedProvider.request({ method: "eth_blockNumber" })) as string; + this.lastBlockSnapshot = parseInt(blockNumberHex); + this.lastBlockSnapshotForDecrypt = parseInt(blockNumberHex); + + const callData = { + to: "0x000000000000000000000000000000000000005d", + data: "0x1f20d85c", + }; + this.lastCounterRand = (await this._wrappedProvider.request({ + method: "eth_call", + params: [callData, "latest"], + })) as number; + return result; + } + if (args.method === "get_lastBlockSnapshot") { + return [this.lastBlockSnapshot, this.lastCounterRand]; + } + if (args.method === "get_lastBlockSnapshotForDecrypt") { + return this.lastBlockSnapshotForDecrypt; + } + if (args.method === "set_lastBlockSnapshot") { + this.lastBlockSnapshot = Array.isArray(args.params!) && args.params[0]; + return this.lastBlockSnapshot; + } + if (args.method === "set_lastBlockSnapshotForDecrypt") { + this.lastBlockSnapshotForDecrypt = Array.isArray(args.params!) && args.params[0]; + return this.lastBlockSnapshotForDecrypt; + } + const result = this._wrappedProvider.request(args); + return result; + } +} + +export default CustomProvider; From 0329676b7b6a86d89b95fef6cd5ed6c31edc2d78 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:14:36 +0200 Subject: [PATCH 05/73] fix: Example env --- .env.example | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index dbba210..84dba80 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,8 @@ export INFURA_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" export MNEMONIC="adapt mosquito move limb mobile illegal tree voyage juice mosquito burger raise father hope layer" -export PRIVATE_KEY_ORACLE_DEPLOYER="717fd99986df414889fd8b51069d4f90a50af72e542c58ee065f5883779099c6" -export PRIVATE_KEY_ORACLE_OWNER="717fd99986df414889fd8b51069d4f90a50af72e542c58ee065f5883779099c6" -export PRIVATE_KEY_ORACLE_RELAYER="7ec931411ad75a7c201469a385d6f18a325d4923f9f213bd882bbea87e160b67" +export PRIVATE_KEY_GATEWAY_DEPLOYER="717fd99986df414889fd8b51069d4f90a50af72e542c58ee065f5883779099c6" +export PRIVATE_KEY_GATEWAY_OWNER="717fd99986df414889fd8b51069d4f90a50af72e542c58ee065f5883779099c6" +export PRIVATE_KEY_GATEWAY_RELAYER="7ec931411ad75a7c201469a385d6f18a325d4923f9f213bd882bbea87e160b67" # Block explorer API keys export ARBISCAN_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" From 0e7a0f551b41f9dd4448288fdd383d1dd7c1c5cc Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:14:57 +0200 Subject: [PATCH 06/73] chore: Gitignore --- .gitignore | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4aba7c5..73ddb24 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,10 @@ dist node_modules types deployments +kms-fhe-keys/ +network-fhe-keys/ +fhevmTemp/ +abi/ # files *.env @@ -18,4 +22,9 @@ deployments .pnp.* coverage.json package-lock.json -yarn.lock \ No newline at end of file +yarn.lock + +res/ +running_node/ + +docker-compose/docker-compose-full.yml From 47e473a4da2b0bfb43cdc31af6b9a4d2594d27dd Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:15:40 +0200 Subject: [PATCH 07/73] fix: TestAsyncDecrypt for 0.5 --- contracts/asyncDecrypt/TestAsyncDecrypt.sol | 303 ++++++++++++++++---- 1 file changed, 244 insertions(+), 59 deletions(-) diff --git a/contracts/asyncDecrypt/TestAsyncDecrypt.sol b/contracts/asyncDecrypt/TestAsyncDecrypt.sol index 05376ad..0fd8c03 100644 --- a/contracts/asyncDecrypt/TestAsyncDecrypt.sol +++ b/contracts/asyncDecrypt/TestAsyncDecrypt.sol @@ -1,18 +1,21 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; -import "fhevm/oracle/OracleCaller.sol"; +import "fhevm/gateway/GatewayCaller.sol"; -contract TestAsyncDecrypt is OracleCaller { +contract TestAsyncDecrypt is GatewayCaller { ebool xBool; euint4 xUint4; euint8 xUint8; euint16 xUint16; euint32 xUint32; euint64 xUint64; + euint64 xUint64_2; + euint64 xUint64_3; eaddress xAddress; + eaddress xAddress2; bool public yBool; uint8 public yUint4; @@ -20,109 +23,181 @@ contract TestAsyncDecrypt is OracleCaller { uint16 public yUint16; uint32 public yUint32; uint64 public yUint64; + uint64 public yUint64_2; + uint64 public yUint64_3; address public yAddress; + address public yAddress2; + bytes public yBytes256; + + uint256 public latestRequestID; constructor() { xBool = TFHE.asEbool(true); + TFHE.allow(xBool, address(this)); xUint4 = TFHE.asEuint4(4); + TFHE.allow(xUint4, address(this)); xUint8 = TFHE.asEuint8(42); + TFHE.allow(xUint8, address(this)); xUint16 = TFHE.asEuint16(16); + TFHE.allow(xUint16, address(this)); xUint32 = TFHE.asEuint32(32); - xUint64 = TFHE.asEuint64(64); + TFHE.allow(xUint32, address(this)); + xUint64 = TFHE.asEuint64(18446744073709551600); + TFHE.allow(xUint64, address(this)); + xUint64_2 = TFHE.asEuint64(76575465786); + TFHE.allow(xUint64_2, address(this)); + xUint64_3 = TFHE.asEuint64(6400); + TFHE.allow(xUint64_3, address(this)); xAddress = TFHE.asEaddress(0x8ba1f109551bD432803012645Ac136ddd64DBA72); + TFHE.allow(xAddress, address(this)); + xAddress2 = TFHE.asEaddress(0xf48b8840387ba3809DAE990c930F3b4766A86ca3); + TFHE.allow(xAddress2, address(this)); + } + + function requestBoolInfinite() public { + uint256[] memory cts = new uint256[](1); + cts[0] = Gateway.toUint256(xBool); + Gateway.requestDecryption(cts, this.callbackBoolInfinite.selector, 0, block.timestamp + 100, false); + } + + function callbackBoolInfinite(uint256 /*requestID*/, bool decryptedInput) public onlyGateway returns (bool) { + uint256 i = 0; + while (true) { + i++; + } + yBool = decryptedInput; + return yBool; } function requestBoolAboveDelay() public { // should revert - ebool[] memory cts = new ebool[](1); - cts[0] = xBool; - Oracle.requestDecryption(cts, this.callbackBool.selector, 0, block.timestamp + 2 days); + uint256[] memory cts = new uint256[](1); + cts[0] = Gateway.toUint256(xBool); + Gateway.requestDecryption(cts, this.callbackBool.selector, 0, block.timestamp + 2 days, false); } function requestBool() public { - ebool[] memory cts = new ebool[](1); - cts[0] = xBool; - Oracle.requestDecryption(cts, this.callbackBool.selector, 0, block.timestamp + 100); + uint256[] memory cts = new uint256[](1); + cts[0] = Gateway.toUint256(xBool); + Gateway.requestDecryption(cts, this.callbackBool.selector, 0, block.timestamp + 100, false); + } + + function requestBoolTrustless() public { + uint256[] memory cts = new uint256[](1); + cts[0] = Gateway.toUint256(xBool); + uint256 requestID = Gateway.requestDecryption( + cts, + this.callbackBoolTrustless.selector, + 0, + block.timestamp + 100, + true + ); + latestRequestID = requestID; + saveRequestedHandles(requestID, cts); } function requestFakeBool() public { - ebool[] memory cts = new ebool[](1); - cts[0] = ebool.wrap(42); - Oracle.requestDecryption(cts, this.callbackBool.selector, 0, block.timestamp + 100); // this should revert because previous ebool is not honestly obtained + uint256[] memory cts = new uint256[](1); + cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000000); + // this should revert because previous ebool is not honestly obtained + Gateway.requestDecryption(cts, this.callbackBool.selector, 0, block.timestamp + 100, false); + } + + function callbackBool(uint256, bool decryptedInput) public onlyGateway returns (bool) { + yBool = decryptedInput; + return yBool; } - function callbackBool(uint256 /*requestID*/, bool decryptedInput) public onlyOracle returns (bool) { + function callbackBoolTrustless( + uint256 requestID, + bool decryptedInput, + bytes[] memory signatures + ) public onlyGateway returns (bool) { + require(latestRequestID == requestID, "wrong requestID passed by Gateway"); + uint256[] memory requestedHandles = loadRequestedHandles(latestRequestID); + bool isKMSVerified = Gateway.verifySignatures(requestedHandles, signatures); + require(isKMSVerified, "KMS did not verify this decryption result"); yBool = decryptedInput; return yBool; } function requestUint4() public { - euint4[] memory cts = new euint4[](1); - cts[0] = xUint4; - Oracle.requestDecryption(cts, this.callbackUint4.selector, 0, block.timestamp + 100); + uint256[] memory cts = new uint256[](1); + cts[0] = Gateway.toUint256(xUint4); + Gateway.requestDecryption(cts, this.callbackUint4.selector, 0, block.timestamp + 100, false); } function requestFakeUint4() public { - euint4[] memory cts = new euint4[](1); - cts[0] = euint4.wrap(42); - Oracle.requestDecryption(cts, this.callbackUint4.selector, 0, block.timestamp + 100); // this should revert because previous ebool is not honestly obtained + uint256[] memory cts = new uint256[](1); + cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000100); + // this should revert because previous handle is not honestly obtained + Gateway.requestDecryption(cts, this.callbackUint4.selector, 0, block.timestamp + 100, false); } - function callbackUint4(uint256 /*requestID*/, uint8 decryptedInput) public onlyOracle returns (uint8) { + function callbackUint4(uint256, uint8 decryptedInput) public onlyGateway returns (uint8) { yUint4 = decryptedInput; return decryptedInput; } function requestUint8() public { - euint8[] memory cts = new euint8[](1); - cts[0] = xUint8; - Oracle.requestDecryption(cts, this.callbackUint8.selector, 0, block.timestamp + 100); + uint256[] memory cts = new uint256[](1); + cts[0] = Gateway.toUint256(xUint8); + Gateway.requestDecryption(cts, this.callbackUint8.selector, 0, block.timestamp + 100, false); } function requestFakeUint8() public { - euint8[] memory cts = new euint8[](1); - cts[0] = euint8.wrap(42); - Oracle.requestDecryption(cts, this.callbackUint8.selector, 0, block.timestamp + 100); // this should revert because previous ebool is not honestly obtained + uint256[] memory cts = new uint256[](1); + cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000200); + // this should revert because previous handle is not honestly obtained + Gateway.requestDecryption(cts, this.callbackUint8.selector, 0, block.timestamp + 100, false); } - function callbackUint8(uint256 /*requestID*/, uint8 decryptedInput) public onlyOracle returns (uint8) { + function callbackUint8(uint256, uint8 decryptedInput) public onlyGateway returns (uint8) { yUint8 = decryptedInput; return decryptedInput; } function requestUint16() public { - euint16[] memory cts = new euint16[](1); - cts[0] = xUint16; - Oracle.requestDecryption(cts, this.callbackUint16.selector, 0, block.timestamp + 100); + uint256[] memory cts = new uint256[](1); + cts[0] = Gateway.toUint256(xUint16); + Gateway.requestDecryption(cts, this.callbackUint16.selector, 0, block.timestamp + 100, false); } function requestFakeUint16() public { - euint16[] memory cts = new euint16[](1); - cts[0] = euint16.wrap(42); - Oracle.requestDecryption(cts, this.callbackUint16.selector, 0, block.timestamp + 100); // this should revert because previous ebool is not honestly obtained + uint256[] memory cts = new uint256[](1); + cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000300); + // this should revert because previous handle is not honestly obtained + Gateway.requestDecryption(cts, this.callbackUint16.selector, 0, block.timestamp + 100, false); } - function callbackUint16(uint256 /*requestID*/, uint16 decryptedInput) public onlyOracle returns (uint16) { + function callbackUint16(uint256, uint16 decryptedInput) public onlyGateway returns (uint16) { yUint16 = decryptedInput; return decryptedInput; } function requestUint32(uint32 input1, uint32 input2) public { - euint32[] memory cts = new euint32[](1); - cts[0] = xUint32; - uint256 requestID = Oracle.requestDecryption(cts, this.callbackUint32.selector, 0, block.timestamp + 100); - addParamsUint(requestID, input1); - addParamsUint(requestID, input2); + uint256[] memory cts = new uint256[](1); + cts[0] = Gateway.toUint256(xUint32); + uint256 requestID = Gateway.requestDecryption( + cts, + this.callbackUint32.selector, + 0, + block.timestamp + 100, + false + ); + addParamsUint256(requestID, input1); + addParamsUint256(requestID, input2); } function requestFakeUint32() public { - euint32[] memory cts = new euint32[](1); - cts[0] = euint32.wrap(42); - Oracle.requestDecryption(cts, this.callbackUint32.selector, 0, block.timestamp + 100); // this should revert because previous ebool is not honestly obtained + uint256[] memory cts = new uint256[](1); + cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000400); + // this should revert because previous handle is not honestly obtained + Gateway.requestDecryption(cts, this.callbackUint32.selector, 0, block.timestamp + 100, false); } - function callbackUint32(uint256 requestID, uint32 decryptedInput) public onlyOracle returns (uint32) { - uint256[] memory params = getParamsUint(requestID); + function callbackUint32(uint256 requestID, uint32 decryptedInput) public onlyGateway returns (uint32) { + uint256[] memory params = getParamsUint256(requestID); unchecked { uint32 result = uint32(params[0]) + uint32(params[1]) + decryptedInput; yUint32 = result; @@ -131,36 +206,146 @@ contract TestAsyncDecrypt is OracleCaller { } function requestUint64() public { - euint64[] memory cts = new euint64[](1); - cts[0] = xUint64; - Oracle.requestDecryption(cts, this.callbackUint64.selector, 0, block.timestamp + 100); + uint256[] memory cts = new uint256[](1); + cts[0] = Gateway.toUint256(xUint64); + Gateway.requestDecryption(cts, this.callbackUint64.selector, 0, block.timestamp + 100, false); } function requestFakeUint64() public { - euint64[] memory cts = new euint64[](1); - cts[0] = euint64.wrap(42); - Oracle.requestDecryption(cts, this.callbackUint64.selector, 0, block.timestamp + 100); // this should revert because previous ebool is not honestly obtained + uint256[] memory cts = new uint256[](1); + cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000500); + // this should revert because previous handle is not honestly obtained + Gateway.requestDecryption(cts, this.callbackUint64.selector, 0, block.timestamp + 100, false); } - function callbackUint64(uint256 /*requestID*/, uint64 decryptedInput) public onlyOracle returns (uint64) { + function requestUint64NonTrivial(einput inputHandle, bytes calldata inputProof) public { + euint64 inputNonTrivial = TFHE.asEuint64(inputHandle, inputProof); + uint256[] memory cts = new uint256[](1); + cts[0] = Gateway.toUint256(inputNonTrivial); + Gateway.requestDecryption(cts, this.callbackUint64.selector, 0, block.timestamp + 100, false); + } + + function callbackUint64(uint256, uint64 decryptedInput) public onlyGateway returns (uint64) { yUint64 = decryptedInput; return decryptedInput; } + function requestEbytes256NonTrivial(einput inputHandle, bytes calldata inputProof) public { + ebytes256 inputNonTrivial = TFHE.asEbytes256(inputHandle, inputProof); + uint256[] memory cts = new uint256[](1); + cts[0] = Gateway.toUint256(inputNonTrivial); + Gateway.requestDecryption(cts, this.callbackBytes256.selector, 0, block.timestamp + 100, false); + } + + function callbackBytes256(uint256, bytes calldata decryptedInput) public onlyGateway returns (bytes memory) { + yBytes256 = decryptedInput; + return decryptedInput; + } + function requestAddress() public { - eaddress[] memory cts = new eaddress[](1); - cts[0] = xAddress; - Oracle.requestDecryption(cts, this.callbackAddress.selector, 0, block.timestamp + 100); + uint256[] memory cts = new uint256[](1); + cts[0] = Gateway.toUint256(xAddress); + Gateway.requestDecryption(cts, this.callbackAddress.selector, 0, block.timestamp + 100, false); + } + + function requestSeveralAddresses() public { + uint256[] memory cts = new uint256[](2); + cts[0] = Gateway.toUint256(xAddress); + cts[1] = Gateway.toUint256(xAddress2); + Gateway.requestDecryption(cts, this.callbackAddresses.selector, 0, block.timestamp + 100, false); + } + + function callbackAddresses( + uint256 /*requestID*/, + address decryptedInput1, + address decryptedInput2 + ) public onlyGateway returns (address) { + yAddress = decryptedInput1; + yAddress2 = decryptedInput2; + return decryptedInput1; } function requestFakeAddress() public { - eaddress[] memory cts = new eaddress[](1); - cts[0] = eaddress.wrap(42); - Oracle.requestDecryption(cts, this.callbackAddress.selector, 0, block.timestamp + 100); // this should revert because previous ebool is not honestly obtained + uint256[] memory cts = new uint256[](1); + cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000700); + // this should revert because previous handle is not honestly obtained + Gateway.requestDecryption(cts, this.callbackAddress.selector, 0, block.timestamp + 100, false); } - function callbackAddress(uint256 /*requestID*/, address decryptedInput) public onlyOracle returns (address) { + function callbackAddress(uint256, address decryptedInput) public onlyGateway returns (address) { yAddress = decryptedInput; return decryptedInput; } + + function requestMixed(uint32 input1, uint32 input2) public { + uint256[] memory cts = new uint256[](10); + cts[0] = Gateway.toUint256(xBool); + cts[1] = Gateway.toUint256(xBool); + cts[2] = Gateway.toUint256(xUint4); + cts[3] = Gateway.toUint256(xUint8); + cts[4] = Gateway.toUint256(xUint16); + cts[5] = Gateway.toUint256(xUint32); + cts[6] = Gateway.toUint256(xUint64); + cts[7] = Gateway.toUint256(xUint64); + cts[8] = Gateway.toUint256(xUint64); + cts[9] = Gateway.toUint256(xAddress); + uint256 requestID = Gateway.requestDecryption( + cts, + this.callbackMixed.selector, + 0, + block.timestamp + 100, + false + ); + addParamsUint256(requestID, input1); + addParamsUint256(requestID, input2); + } + + function callbackMixed( + uint256 requestID, + bool decBool_1, + bool decBool_2, + uint8 decUint4, + uint8 decUint8, + uint16 decUint16, + uint32 decUint32, + uint64 decUint64_1, + uint64 decUint64_2, + uint64 decUint64_3, + address decAddress + ) public onlyGateway returns (uint8) { + yBool = decBool_1; + require(decBool_1 == decBool_2, "Wrong decryption"); + yUint4 = decUint4; + yUint8 = decUint8; + yUint16 = decUint16; + uint256[] memory params = getParamsUint256(requestID); + unchecked { + uint32 result = uint32(params[0]) + uint32(params[1]) + decUint32; + yUint32 = result; + } + yUint64 = decUint64_1; + require(decUint64_1 == decUint64_2 && decUint64_2 == decUint64_3, "Wrong decryption"); + yAddress = decAddress; + return yUint4; + } + + function requestMixedBytes256(einput inputHandle, bytes calldata inputProof) public { + ebytes256 xBytes256 = TFHE.asEbytes256(inputHandle, inputProof); + uint256[] memory cts = new uint256[](3); + cts[0] = Gateway.toUint256(xBool); + cts[1] = Gateway.toUint256(xAddress); + cts[2] = Gateway.toUint256(xBytes256); + Gateway.requestDecryption(cts, this.callbackMixedBytes256.selector, 0, block.timestamp + 100, false); + } + + function callbackMixedBytes256( + uint256, + bool decBool, + address decAddress, + bytes memory bytesRes + ) public onlyGateway { + yBool = decBool; + yAddress = decAddress; + yBytes256 = bytesRes; + } } From 9e0fa604cba42edc3d10e21cbb6569548cb4d193 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:17:07 +0200 Subject: [PATCH 08/73] build: Bump to Solidity 0.8.24 --- .prettierrc.yml | 2 +- README.md | 2 +- contracts/DAO/Comp.sol | 2 +- contracts/DAO/GovernorZama.sol | 2 +- contracts/DAO/Timelock.sol | 2 +- contracts/token/ERC20/EncryptedERC20.sol | 2 +- contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol | 2 +- contracts/utils/EncryptedErrors.sol | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.prettierrc.yml b/.prettierrc.yml index 42ad8c5..56221e3 100644 --- a/.prettierrc.yml +++ b/.prettierrc.yml @@ -11,7 +11,7 @@ trailingComma: "all" overrides: - files: "*.sol" options: - compiler: "0.8.22" + compiler: "0.8.24" parser: "solidity-parse" tabWidth: 4 - files: "*.ts" diff --git a/README.md b/README.md index 4c5b7c6..e8615e6 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ pnpm add fhevm-contracts ```solidity // SPDX-License-Identifier: BSD-3-Clause-Clear -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; import "fhevm-contracts/contracts/token/ERC20/EncryptedERC20.sol"; diff --git a/contracts/DAO/Comp.sol b/contracts/DAO/Comp.sol index f221ec1..8a23432 100644 --- a/contracts/DAO/Comp.sol +++ b/contracts/DAO/Comp.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; import "fhevm/abstracts/Reencrypt.sol"; import "fhevm/lib/TFHE.sol"; diff --git a/contracts/DAO/GovernorZama.sol b/contracts/DAO/GovernorZama.sol index acfb61a..e668713 100644 --- a/contracts/DAO/GovernorZama.sol +++ b/contracts/DAO/GovernorZama.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; import "fhevm/abstracts/Reencrypt.sol"; import "fhevm/lib/TFHE.sol"; diff --git a/contracts/DAO/Timelock.sol b/contracts/DAO/Timelock.sol index c4cac1e..f0979a7 100644 --- a/contracts/DAO/Timelock.sol +++ b/contracts/DAO/Timelock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; contract Timelock { event NewAdmin(address indexed newAdmin); diff --git a/contracts/token/ERC20/EncryptedERC20.sol b/contracts/token/ERC20/EncryptedERC20.sol index 6ce1b13..0633959 100644 --- a/contracts/token/ERC20/EncryptedERC20.sol +++ b/contracts/token/ERC20/EncryptedERC20.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; import "fhevm/abstracts/Reencrypt.sol"; diff --git a/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol b/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol index 2afa0e5..cc330ae 100644 --- a/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol +++ b/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; import "../EncryptedERC20.sol"; import "@openzeppelin/contracts/access/Ownable2Step.sol"; diff --git a/contracts/utils/EncryptedErrors.sol b/contracts/utils/EncryptedErrors.sol index 4f9ae2c..b9347d8 100644 --- a/contracts/utils/EncryptedErrors.sol +++ b/contracts/utils/EncryptedErrors.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear -pragma solidity ^0.8.20; +pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; From 5d72e27081103c94ad2b66aa2d24d776ebeade60 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 21 Oct 2024 17:18:29 +0200 Subject: [PATCH 09/73] chore: Updates lockfile --- pnpm-lock.yaml | 6976 +++++++++++++++++++++++++++--------------------- 1 file changed, 3974 insertions(+), 3002 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b7fc87d..b0b2a89 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,240 +1,3151 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - '@openzeppelin/contracts': - specifier: ^5.0.2 - version: 5.0.2 - -devDependencies: - '@nomicfoundation/hardhat-chai-matchers': - specifier: ^2.0.6 - version: 2.0.6(@nomicfoundation/hardhat-ethers@3.0.5)(chai@4.4.1)(ethers@6.11.1)(hardhat@2.21.0) - '@nomicfoundation/hardhat-ethers': - specifier: ^3.0.5 - version: 3.0.5(ethers@6.11.1)(hardhat@2.21.0) - '@nomicfoundation/hardhat-network-helpers': - specifier: ^1.0.10 - version: 1.0.10(hardhat@2.21.0) - '@nomicfoundation/hardhat-toolbox': - specifier: ^3.0.0 - version: 3.0.0(@nomicfoundation/hardhat-chai-matchers@2.0.6)(@nomicfoundation/hardhat-ethers@3.0.5)(@nomicfoundation/hardhat-network-helpers@1.0.10)(@nomicfoundation/hardhat-verify@1.1.1)(@typechain/ethers-v6@0.4.3)(@typechain/hardhat@8.0.3)(@types/chai@4.3.12)(@types/mocha@10.0.6)(@types/node@18.19.23)(chai@4.4.1)(ethers@6.11.1)(hardhat-gas-reporter@1.0.10)(hardhat@2.21.0)(solidity-coverage@0.8.6)(ts-node@10.9.2)(typechain@8.3.2)(typescript@5.4.2) - '@nomicfoundation/hardhat-verify': - specifier: ^1.1.1 - version: 1.1.1(hardhat@2.21.0) - '@trivago/prettier-plugin-sort-imports': - specifier: ^4.3.0 - version: 4.3.0(prettier@2.8.8) - '@typechain/ethers-v6': - specifier: ^0.4.3 - version: 0.4.3(ethers@6.11.1)(typechain@8.3.2)(typescript@5.4.2) - '@typechain/hardhat': - specifier: ^8.0.3 - version: 8.0.3(@typechain/ethers-v6@0.4.3)(ethers@6.11.1)(hardhat@2.21.0)(typechain@8.3.2) - '@types/chai': - specifier: ^4.3.12 - version: 4.3.12 - '@types/fs-extra': - specifier: ^9.0.13 - version: 9.0.13 - '@types/mocha': - specifier: ^10.0.6 - version: 10.0.6 - '@types/node': - specifier: ^18.19.23 - version: 18.19.23 - '@typescript-eslint/eslint-plugin': - specifier: ^5.62.0 - version: 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@5.4.2) - '@typescript-eslint/parser': - specifier: ^5.62.0 - version: 5.62.0(eslint@8.57.0)(typescript@5.4.2) - chai: - specifier: ^4.4.1 - version: 4.4.1 - cross-env: - specifier: ^7.0.3 - version: 7.0.3 - dotenv: - specifier: ^16.4.5 - version: 16.4.5 - eslint: - specifier: ^8.57.0 - version: 8.57.0 - eslint-config-prettier: - specifier: ^8.10.0 - version: 8.10.0(eslint@8.57.0) - ethers: - specifier: ^6.11.1 - version: 6.11.1 - fhevm: - specifier: ^0.4.0 - version: 0.4.0(hardhat@2.21.0) - fhevmjs: - specifier: ^0.4.0-7 - version: 0.4.0-7 - fs-extra: - specifier: ^10.1.0 - version: 10.1.0 - hardhat: - specifier: 2.21.0 - version: 2.21.0(ts-node@10.9.2)(typescript@5.4.2) - hardhat-deploy: - specifier: ^0.11.45 - version: 0.11.45 - hardhat-gas-reporter: - specifier: ^1.0.10 - version: 1.0.10(hardhat@2.21.0) - hardhat-preprocessor: - specifier: ^0.1.5 - version: 0.1.5(hardhat@2.21.0) - lodash: - specifier: ^4.17.21 - version: 4.17.21 - mocha: - specifier: ^10.3.0 - version: 10.3.0 - prettier: - specifier: ^2.8.8 - version: 2.8.8 - prettier-plugin-solidity: - specifier: ^1.3.1 - version: 1.3.1(prettier@2.8.8) - rimraf: - specifier: ^4.4.1 - version: 4.4.1 - solhint: - specifier: ^3.6.2 - version: 3.6.2(typescript@5.4.2) - solhint-plugin-prettier: - specifier: ^0.0.5 - version: 0.0.5(prettier-plugin-solidity@1.3.1)(prettier@2.8.8) - solidity-coverage: - specifier: 0.8.6 - version: 0.8.6(hardhat@2.21.0) - solidity-docgen: - specifier: 0.6.0-beta.36 - version: 0.6.0-beta.36(hardhat@2.21.0) - ts-generator: - specifier: ^0.1.1 - version: 0.1.1 - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@types/node@18.19.23)(typescript@5.4.2) - typechain: - specifier: ^8.3.2 - version: 8.3.2(typescript@5.4.2) - typescript: - specifier: ^5.4.2 - version: 5.4.2 +importers: + + .: + dependencies: + '@openzeppelin/contracts': + specifier: ^5.0.2 + version: 5.0.2 + devDependencies: + '@nomicfoundation/hardhat-chai-matchers': + specifier: ^2.0.6 + version: 2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-ethers': + specifier: ^3.0.5 + version: 3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-network-helpers': + specifier: ^1.0.10 + version: 1.0.10(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-toolbox': + specifier: ^3.0.0 + version: 3.0.0(efoxkvpld3mcx7zgojgym4euli) + '@nomicfoundation/hardhat-verify': + specifier: ^1.1.1 + version: 1.1.1(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@trivago/prettier-plugin-sort-imports': + specifier: ^4.3.0 + version: 4.3.0(prettier@2.8.8) + '@typechain/ethers-v6': + specifier: ^0.4.3 + version: 0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2) + '@typechain/hardhat': + specifier: ^8.0.3 + version: 8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2)) + '@types/chai': + specifier: ^4.3.12 + version: 4.3.12 + '@types/fs-extra': + specifier: ^9.0.13 + version: 9.0.13 + '@types/mocha': + specifier: ^10.0.6 + version: 10.0.6 + '@types/node': + specifier: ^18.19.23 + version: 18.19.23 + '@typescript-eslint/eslint-plugin': + specifier: ^5.62.0 + version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.2))(eslint@8.57.0)(typescript@5.4.2) + '@typescript-eslint/parser': + specifier: ^5.62.0 + version: 5.62.0(eslint@8.57.0)(typescript@5.4.2) + chai: + specifier: ^4.4.1 + version: 4.4.1 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 + eslint: + specifier: ^8.57.0 + version: 8.57.0 + eslint-config-prettier: + specifier: ^8.10.0 + version: 8.10.0(eslint@8.57.0) + ethers: + specifier: ^6.11.1 + version: 6.11.1 + fhevm: + specifier: ^0.5.9 + version: 0.5.9 + fhevmjs: + specifier: ^0.5.7 + version: 0.5.7 + fs-extra: + specifier: ^10.1.0 + version: 10.1.0 + hardhat: + specifier: 2.21.0 + version: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat-deploy: + specifier: ^0.11.45 + version: 0.11.45 + hardhat-gas-reporter: + specifier: ^1.0.10 + version: 1.0.10(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + hardhat-ignore-warnings: + specifier: ^0.2.11 + version: 0.2.11 + hardhat-preprocessor: + specifier: ^0.1.5 + version: 0.1.5(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + lodash: + specifier: ^4.17.21 + version: 4.17.21 + mocha: + specifier: ^10.3.0 + version: 10.3.0 + prettier: + specifier: ^2.8.8 + version: 2.8.8 + prettier-plugin-solidity: + specifier: ^1.3.1 + version: 1.3.1(prettier@2.8.8) + rimraf: + specifier: ^4.4.1 + version: 4.4.1 + solhint: + specifier: ^3.6.2 + version: 3.6.2(typescript@5.4.2) + solhint-plugin-prettier: + specifier: ^0.0.5 + version: 0.0.5(prettier-plugin-solidity@1.3.1(prettier@2.8.8))(prettier@2.8.8) + solidity-coverage: + specifier: 0.8.6 + version: 0.8.6(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + solidity-docgen: + specifier: 0.6.0-beta.36 + version: 0.6.0-beta.36(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + ts-generator: + specifier: ^0.1.1 + version: 0.1.1 + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@18.19.23)(typescript@5.4.2) + typechain: + specifier: ^8.3.2 + version: 8.3.2(typescript@5.4.2) + typescript: + specifier: ^5.4.2 + version: 5.4.2 + +packages: + + '@aashutoshrathi/word-wrap@1.2.6': + resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + engines: {node: '>=0.10.0'} + + '@adraffy/ens-normalize@1.10.1': + resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==} + + '@babel/code-frame@7.23.5': + resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.17.7': + resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.23.6': + resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-environment-visitor@7.22.20': + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-function-name@7.23.0': + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-hoist-variables@7.22.5': + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-split-export-declaration@7.22.6': + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.23.4': + resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.22.20': + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.23.4': + resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.24.0': + resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/template@7.24.0': + resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.23.2': + resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.17.0': + resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.24.0': + resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} + engines: {node: '>=6.9.0'} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@eslint-community/eslint-utils@4.4.0': + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.10.0': + resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.0': + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@ethereumjs/rlp@4.0.1': + resolution: {integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==} + engines: {node: '>=14'} + hasBin: true + + '@ethereumjs/util@8.1.0': + resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} + engines: {node: '>=14'} + + '@ethersproject/abi@5.7.0': + resolution: {integrity: sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==} + + '@ethersproject/abstract-provider@5.7.0': + resolution: {integrity: sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==} + + '@ethersproject/abstract-signer@5.7.0': + resolution: {integrity: sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==} + + '@ethersproject/address@5.7.0': + resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==} + + '@ethersproject/base64@5.7.0': + resolution: {integrity: sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==} + + '@ethersproject/basex@5.7.0': + resolution: {integrity: sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==} + + '@ethersproject/bignumber@5.7.0': + resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==} + + '@ethersproject/bytes@5.7.0': + resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} + + '@ethersproject/constants@5.7.0': + resolution: {integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==} + + '@ethersproject/contracts@5.7.0': + resolution: {integrity: sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==} + + '@ethersproject/hash@5.7.0': + resolution: {integrity: sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==} + + '@ethersproject/hdnode@5.7.0': + resolution: {integrity: sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==} + + '@ethersproject/json-wallets@5.7.0': + resolution: {integrity: sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==} + + '@ethersproject/keccak256@5.7.0': + resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==} + + '@ethersproject/logger@5.7.0': + resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==} + + '@ethersproject/networks@5.7.1': + resolution: {integrity: sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==} + + '@ethersproject/pbkdf2@5.7.0': + resolution: {integrity: sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==} + + '@ethersproject/properties@5.7.0': + resolution: {integrity: sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==} + + '@ethersproject/providers@5.7.2': + resolution: {integrity: sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==} + + '@ethersproject/random@5.7.0': + resolution: {integrity: sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==} + + '@ethersproject/rlp@5.7.0': + resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==} + + '@ethersproject/sha2@5.7.0': + resolution: {integrity: sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==} + + '@ethersproject/signing-key@5.7.0': + resolution: {integrity: sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==} + + '@ethersproject/solidity@5.7.0': + resolution: {integrity: sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==} + + '@ethersproject/strings@5.7.0': + resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==} + + '@ethersproject/transactions@5.7.0': + resolution: {integrity: sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==} + + '@ethersproject/units@5.7.0': + resolution: {integrity: sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==} + + '@ethersproject/wallet@5.7.0': + resolution: {integrity: sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==} + + '@ethersproject/web@5.7.1': + resolution: {integrity: sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==} + + '@ethersproject/wordlists@5.7.0': + resolution: {integrity: sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==} + + '@fastify/busboy@2.1.1': + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} + + '@humanwhocodes/config-array@0.11.14': + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@2.0.2': + resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} + + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.4.15': + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@metamask/eth-sig-util@4.0.1': + resolution: {integrity: sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==} + engines: {node: '>=12.0.0'} + + '@noble/curves@1.2.0': + resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} + + '@noble/curves@1.3.0': + resolution: {integrity: sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==} + + '@noble/hashes@1.2.0': + resolution: {integrity: sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==} + + '@noble/hashes@1.3.2': + resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} + engines: {node: '>= 16'} + + '@noble/hashes@1.3.3': + resolution: {integrity: sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==} + engines: {node: '>= 16'} + + '@noble/secp256k1@1.7.1': + resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nomicfoundation/edr-darwin-arm64@0.2.1': + resolution: {integrity: sha512-aMYaRaZVQ/TmyNJIoXf1bU4k0zfinaL9Sy1day4yGlL6eiQPFfRGj9W6TZaZIoYG0XTx/mQWD7dkXJ7LdrleJA==} + engines: {node: '>= 18'} + cpu: [arm64] + os: [darwin] + + '@nomicfoundation/edr-darwin-x64@0.2.1': + resolution: {integrity: sha512-ma0SLcjHm5L3nPHcKFJB0jv/gKGSKaxr5Z65rurX/eaYUQJ7YGMsb8er9bSCo9rjzOtxf4FoPj3grL3zGpOj8A==} + engines: {node: '>= 18'} + cpu: [x64] + os: [darwin] + + '@nomicfoundation/edr-linux-arm64-gnu@0.2.1': + resolution: {integrity: sha512-NX3G4pBhRitWrjSGY3HTyCq3wKSm5YqrKVOCNQGl9/jcjSovqxlgzFMiTx4YZCzGntfJ/1om9AI84OWxYJjoDw==} + engines: {node: '>= 18'} + cpu: [arm64] + os: [linux] + + '@nomicfoundation/edr-linux-arm64-musl@0.2.1': + resolution: {integrity: sha512-gdQ3QHkt9XRkdtOGQ8fMwS11MXdjLeZgLrqoial4V4qtMaamIMMhVczK+VEvUhD8p7G4BVmp6kmkvcsthmndmw==} + engines: {node: '>= 18'} + cpu: [arm64] + os: [linux] + + '@nomicfoundation/edr-linux-x64-gnu@0.2.1': + resolution: {integrity: sha512-OqabFY37vji6mYbLD9CvG28lja68czeVw58oWByIhFV3BpBu/cyP1oAbhzk3LieylujabS3Ekpvjw2Tkf0A9RQ==} + engines: {node: '>= 18'} + cpu: [x64] + os: [linux] + + '@nomicfoundation/edr-linux-x64-musl@0.2.1': + resolution: {integrity: sha512-vHfFFK2EPISuQUQge+bdjXamb0EUjfl8srYSog1qfiwyLwLeuSbpyyFzDeITAgPpkkFuedTfJW553K0Hipspyg==} + engines: {node: '>= 18'} + cpu: [x64] + os: [linux] + + '@nomicfoundation/edr-win32-arm64-msvc@0.2.1': + resolution: {integrity: sha512-K/mui67RCKxghbSyvhvW3rvyVN1pa9M1Q9APUx1PtWjSSdXDFpqEY1NYsv2syb47Ca8ObJwVMF+LvnB6GvhUOQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@nomicfoundation/edr-win32-ia32-msvc@0.2.1': + resolution: {integrity: sha512-HHK0mXEtjvfjJrJlqcYgQCy3lZIXS1KNl2GaP8bwEIuEwx++XxXs/ThLjPepM1nhCGICij8IGy7p3KrkzRelsw==} + engines: {node: '>= 18'} + cpu: [ia32] + os: [win32] + + '@nomicfoundation/edr-win32-x64-msvc@0.2.1': + resolution: {integrity: sha512-FY4eQJdj1/y8ST0RyQycx63yr+lvdYNnUkzgWf4X+vPH1lOhXae+L2NDcNCQlTDAfQcD6yz0bkBUkLrlJ8pTww==} + engines: {node: '>= 18'} + cpu: [x64] + os: [win32] + + '@nomicfoundation/edr@0.2.1': + resolution: {integrity: sha512-Dleau3ItHJh2n85G2J6AIPBoLgu/mOWkmrh26z3VsJE2tp/e00hUk/dqz85ncsVcBYEc6/YOn/DomWu0wSF9tQ==} + engines: {node: '>= 18'} + + '@nomicfoundation/ethereumjs-common@4.0.4': + resolution: {integrity: sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==} + + '@nomicfoundation/ethereumjs-rlp@5.0.4': + resolution: {integrity: sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==} + engines: {node: '>=18'} + hasBin: true + + '@nomicfoundation/ethereumjs-tx@5.0.4': + resolution: {integrity: sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==} + engines: {node: '>=18'} + peerDependencies: + c-kzg: ^2.1.2 + peerDependenciesMeta: + c-kzg: + optional: true + + '@nomicfoundation/ethereumjs-util@9.0.4': + resolution: {integrity: sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==} + engines: {node: '>=18'} + peerDependencies: + c-kzg: ^2.1.2 + peerDependenciesMeta: + c-kzg: + optional: true + + '@nomicfoundation/hardhat-chai-matchers@2.0.6': + resolution: {integrity: sha512-Te1Uyo9oJcTCF0Jy9dztaLpshmlpjLf2yPtWXlXuLjMt3RRSmJLm/+rKVTW6gfadAEs12U/it6D0ZRnnRGiICQ==} + peerDependencies: + '@nomicfoundation/hardhat-ethers': ^3.0.0 + chai: ^4.2.0 + ethers: ^6.1.0 + hardhat: ^2.9.4 + + '@nomicfoundation/hardhat-ethers@3.0.5': + resolution: {integrity: sha512-RNFe8OtbZK6Ila9kIlHp0+S80/0Bu/3p41HUpaRIoHLm6X3WekTd83vob3rE54Duufu1edCiBDxspBzi2rxHHw==} + peerDependencies: + ethers: ^6.1.0 + hardhat: ^2.0.0 + + '@nomicfoundation/hardhat-network-helpers@1.0.10': + resolution: {integrity: sha512-R35/BMBlx7tWN5V6d/8/19QCwEmIdbnA4ZrsuXgvs8i2qFx5i7h6mH5pBS4Pwi4WigLH+upl6faYusrNPuzMrQ==} + peerDependencies: + hardhat: ^2.9.5 + + '@nomicfoundation/hardhat-toolbox@3.0.0': + resolution: {integrity: sha512-MsteDXd0UagMksqm9KvcFG6gNKYNa3GGNCy73iQ6bEasEgg2v8Qjl6XA5hjs8o5UD5A3153B6W2BIVJ8SxYUtA==} + peerDependencies: + '@nomicfoundation/hardhat-chai-matchers': ^2.0.0 + '@nomicfoundation/hardhat-ethers': ^3.0.0 + '@nomicfoundation/hardhat-network-helpers': ^1.0.0 + '@nomicfoundation/hardhat-verify': ^1.0.0 + '@typechain/ethers-v6': ^0.4.0 + '@typechain/hardhat': ^8.0.0 + '@types/chai': ^4.2.0 + '@types/mocha': '>=9.1.0' + '@types/node': '>=12.0.0' + chai: ^4.2.0 + ethers: ^6.4.0 + hardhat: ^2.11.0 + hardhat-gas-reporter: ^1.0.8 + solidity-coverage: ^0.8.1 + ts-node: '>=8.0.0' + typechain: ^8.2.0 + typescript: '>=4.5.0' + + '@nomicfoundation/hardhat-verify@1.1.1': + resolution: {integrity: sha512-9QsTYD7pcZaQFEA3tBb/D/oCStYDiEVDN7Dxeo/4SCyHRSm86APypxxdOMEPlGmXsAvd+p1j/dTODcpxb8aztA==} + peerDependencies: + hardhat: ^2.0.4 + + '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1': + resolution: {integrity: sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@nomicfoundation/solidity-analyzer-darwin-x64@0.1.1': + resolution: {integrity: sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@nomicfoundation/solidity-analyzer-freebsd-x64@0.1.1': + resolution: {integrity: sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.1': + resolution: {integrity: sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.1': + resolution: {integrity: sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.1': + resolution: {integrity: sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.1': + resolution: {integrity: sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@nomicfoundation/solidity-analyzer-win32-arm64-msvc@0.1.1': + resolution: {integrity: sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@nomicfoundation/solidity-analyzer-win32-ia32-msvc@0.1.1': + resolution: {integrity: sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.1': + resolution: {integrity: sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nomicfoundation/solidity-analyzer@0.1.1': + resolution: {integrity: sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==} + engines: {node: '>= 12'} + + '@openzeppelin/contracts@5.0.2': + resolution: {integrity: sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA==} + + '@scure/base@1.1.5': + resolution: {integrity: sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==} + + '@scure/bip32@1.1.5': + resolution: {integrity: sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==} + + '@scure/bip32@1.3.3': + resolution: {integrity: sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==} + + '@scure/bip39@1.1.1': + resolution: {integrity: sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==} + + '@scure/bip39@1.2.2': + resolution: {integrity: sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==} + + '@sentry/core@5.30.0': + resolution: {integrity: sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==} + engines: {node: '>=6'} + + '@sentry/hub@5.30.0': + resolution: {integrity: sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==} + engines: {node: '>=6'} + + '@sentry/minimal@5.30.0': + resolution: {integrity: sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==} + engines: {node: '>=6'} + + '@sentry/node@5.30.0': + resolution: {integrity: sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==} + engines: {node: '>=6'} + + '@sentry/tracing@5.30.0': + resolution: {integrity: sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==} + engines: {node: '>=6'} + + '@sentry/types@5.30.0': + resolution: {integrity: sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==} + engines: {node: '>=6'} + + '@sentry/utils@5.30.0': + resolution: {integrity: sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==} + engines: {node: '>=6'} + + '@solidity-parser/parser@0.14.5': + resolution: {integrity: sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==} + + '@solidity-parser/parser@0.16.2': + resolution: {integrity: sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==} + + '@solidity-parser/parser@0.17.0': + resolution: {integrity: sha512-Nko8R0/kUo391jsEHHxrGM07QFdnPGvlmox4rmH0kNiNAashItAilhy4Mv4pK5gQmW5f4sXAF58fwJbmlkGcVw==} + + '@solidity-parser/parser@0.18.0': + resolution: {integrity: sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==} + + '@trivago/prettier-plugin-sort-imports@4.3.0': + resolution: {integrity: sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==} + peerDependencies: + '@vue/compiler-sfc': 3.x + prettier: 2.x - 3.x + peerDependenciesMeta: + '@vue/compiler-sfc': + optional: true + + '@tsconfig/node10@1.0.9': + resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@typechain/ethers-v6@0.4.3': + resolution: {integrity: sha512-TrxBsyb4ryhaY9keP6RzhFCviWYApcLCIRMPyWaKp2cZZrfaM3QBoxXTnw/eO4+DAY3l+8O0brNW0WgeQeOiDA==} + peerDependencies: + ethers: 6.x + typechain: ^8.3.1 + typescript: '>=4.7.0' + + '@typechain/hardhat@8.0.3': + resolution: {integrity: sha512-MytSmJJn+gs7Mqrpt/gWkTCOpOQ6ZDfRrRT2gtZL0rfGe4QrU4x9ZdW15fFbVM/XTa+5EsKiOMYXhRABibNeng==} + peerDependencies: + '@typechain/ethers-v6': ^0.4.3 + ethers: ^6.1.0 + hardhat: ^2.9.9 + typechain: ^8.3.1 + + '@types/bn.js@4.11.6': + resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} + + '@types/bn.js@5.1.5': + resolution: {integrity: sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==} + + '@types/chai-as-promised@7.1.8': + resolution: {integrity: sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==} + + '@types/chai@4.3.12': + resolution: {integrity: sha512-zNKDHG/1yxm8Il6uCCVsm+dRdEsJlFoDu73X17y09bId6UwoYww+vFBsAcRzl8knM1sab3Dp1VRikFQwDOtDDw==} + + '@types/concat-stream@1.6.1': + resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==} + + '@types/form-data@0.0.33': + resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==} + + '@types/fs-extra@9.0.13': + resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + + '@types/glob@7.2.0': + resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/keccak@3.0.5': + resolution: {integrity: sha512-Mvu4StIJ9KyfPXDVRv3h0fWNBAjHPBQZ8EPcxhqA8FG6pLzxtytVXU5owB6J2/8xZ+ZspWTXJEUjAHt0pk0I1Q==} + + '@types/lru-cache@5.1.1': + resolution: {integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==} + + '@types/minimatch@5.1.2': + resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + + '@types/mkdirp@0.5.2': + resolution: {integrity: sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==} + + '@types/mocha@10.0.6': + resolution: {integrity: sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==} + + '@types/node@10.17.60': + resolution: {integrity: sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==} + + '@types/node@18.15.13': + resolution: {integrity: sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==} + + '@types/node@18.19.23': + resolution: {integrity: sha512-wtE3d0OUfNKtZYAqZb8HAWGxxXsImJcPUAgZNw+dWFxO6s5tIwIjyKnY76tsTatsNCLJPkVYwUpq15D38ng9Aw==} + + '@types/node@8.10.66': + resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} + + '@types/pbkdf2@3.1.2': + resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} + + '@types/prettier@2.7.3': + resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} + + '@types/qs@6.9.12': + resolution: {integrity: sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg==} + + '@types/resolve@0.0.8': + resolution: {integrity: sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==} + + '@types/secp256k1@4.0.6': + resolution: {integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==} + + '@types/semver@7.5.8': + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + + '@typescript-eslint/eslint-plugin@5.62.0': + resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@5.62.0': + resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@5.62.0': + resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/type-utils@5.62.0': + resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@5.62.0': + resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/typescript-estree@5.62.0': + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@5.62.0': + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@typescript-eslint/visitor-keys@5.62.0': + resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@ungap/structured-clone@1.2.0': + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + + abbrev@1.0.9: + resolution: {integrity: sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + engines: {node: '>=0.4.0'} + + acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + + address@1.2.2: + resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} + engines: {node: '>= 10.0.0'} + + adm-zip@0.4.16: + resolution: {integrity: sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==} + engines: {node: '>=0.3.0'} + + aes-js@3.0.0: + resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==} + + aes-js@4.0.0-beta.5: + resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + + amdefine@1.0.1: + resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} + engines: {node: '>=0.4.2'} + + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + + ansi-colors@4.1.1: + resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} + engines: {node: '>=6'} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@3.0.1: + resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==} + engines: {node: '>=4'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + antlr4@4.13.1: + resolution: {integrity: sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA==} + engines: {node: '>=16'} + + antlr4ts@0.5.0-alpha.4: + resolution: {integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-back@3.1.0: + resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==} + engines: {node: '>=6'} + + array-back@4.0.2: + resolution: {integrity: sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==} + engines: {node: '>=8'} + + array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + array-uniq@1.0.3: + resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} + engines: {node: '>=0.10.0'} + + array.prototype.findlast@1.2.4: + resolution: {integrity: sha512-BMtLxpV+8BD+6ZPFIWmnUBpQoy+A+ujcg4rhp2iwCRJYA7PEh2MS4NL3lz8EiDlLrJPp2hg9qWihr5pd//jcGw==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + + assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + + ast-parents@0.0.1: + resolution: {integrity: sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==} + + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + + async@1.5.2: + resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axios@0.21.4: + resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} + + axios@1.6.7: + resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base-x@3.0.9: + resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bech32@1.1.4: + resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} + + bigint-buffer@1.1.5: + resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} + engines: {node: '>= 10.0.0'} + + binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + blakejs@1.2.1: + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} + + bn.js@4.11.6: + resolution: {integrity: sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==} + + bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + + bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + + boxen@5.1.2: + resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} + engines: {node: '>=10'} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + + browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + + bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + + bs58check@2.1.2: + resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caseless@0.12.0: + resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} + + cbor@8.1.0: + resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} + engines: {node: '>=12.19'} + + chai-as-promised@7.1.1: + resolution: {integrity: sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==} + peerDependencies: + chai: '>= 2.1.2 < 5' + + chai@4.4.1: + resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} + engines: {node: '>=4'} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + charenc@0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + + check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + + chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + ci-info@2.0.0: + resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + + cipher-base@1.0.4: + resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + cli-boxes@2.2.1: + resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} + engines: {node: '>=6'} + + cli-table3@0.5.1: + resolution: {integrity: sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==} + engines: {node: '>=6'} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colors@1.4.0: + resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} + engines: {node: '>=0.1.90'} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + command-exists@1.2.9: + resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} + + command-line-args@5.2.1: + resolution: {integrity: sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==} + engines: {node: '>=4.0.0'} + + command-line-usage@6.1.3: + resolution: {integrity: sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==} + engines: {node: '>=8.0.0'} + + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + commander@3.0.2: + resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concat-stream@1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} + + cookie@0.4.2: + resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} + engines: {node: '>= 0.6'} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + + create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + crypt@0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + + death@1.1.0: + resolution: {integrity: sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==} + + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + + deep-eql@4.1.3: + resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + engines: {node: '>=6'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + detect-port@1.5.1: + resolution: {integrity: sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==} + hasBin: true + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + diff@5.0.0: + resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} + engines: {node: '>=0.3.1'} + + difflib@0.2.4: + resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + + elliptic@6.5.4: + resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} + + elliptic@6.5.5: + resolution: {integrity: sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + encode-utf8@1.0.3: + resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es-abstract@1.22.5: + resolution: {integrity: sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + + es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escodegen@1.8.1: + resolution: {integrity: sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==} + engines: {node: '>=0.12.0'} + hasBin: true + + eslint-config-prettier@8.10.0: + resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esprima@2.7.3: + resolution: {integrity: sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==} + engines: {node: '>=0.10.0'} + hasBin: true + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@1.9.3: + resolution: {integrity: sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==} + engines: {node: '>=0.10.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + eth-gas-reporter@0.2.27: + resolution: {integrity: sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw==} + peerDependencies: + '@codechecks/client': ^0.1.0 + peerDependenciesMeta: + '@codechecks/client': + optional: true + + ethereum-bloom-filters@1.0.10: + resolution: {integrity: sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==} + + ethereum-cryptography@0.1.3: + resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} + + ethereum-cryptography@1.2.0: + resolution: {integrity: sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==} + + ethereum-cryptography@2.1.3: + resolution: {integrity: sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==} + + ethereumjs-abi@0.6.8: + resolution: {integrity: sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==} + + ethereumjs-util@6.2.1: + resolution: {integrity: sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==} + + ethereumjs-util@7.1.5: + resolution: {integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==} + engines: {node: '>=10.0.0'} + + ethers@5.7.2: + resolution: {integrity: sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==} + + ethers@6.11.1: + resolution: {integrity: sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==} + engines: {node: '>=14.0.0'} + + ethjs-unit@0.1.6: + resolution: {integrity: sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==} + engines: {node: '>=6.5.0', npm: '>=3'} + + ethjs-util@0.1.6: + resolution: {integrity: sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==} + engines: {node: '>=6.5.0', npm: '>=3'} + + evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + fhevm@0.5.9: + resolution: {integrity: sha512-9cSfmAa4AJUuROd4kESvtNYJpnea1PUvjU7yaNnrJsaHqPkVGQvpnIDEnO4KTsJ36Etup1ksPs8PvyGNYwkatQ==} + engines: {node: '>=20.0.0'} + + fhevmjs@0.5.7: + resolution: {integrity: sha512-HWVpV0pK4glaTVvSjAvo/FBreI9M+wfmyxau/GVwELuVMCDCChEu/EE8OpnVWt8UhgLtvBrkD5dbhbNYoFjDSQ==} + engines: {node: '>=20'} + hasBin: true + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + + find-replace@3.0.0: + resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==} + engines: {node: '>=4.0.0'} + + find-up@2.1.0: + resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} + engines: {node: '>=4'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + + fmix@0.1.0: + resolution: {integrity: sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==} + + follow-redirects@1.15.5: + resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + + form-data@2.5.1: + resolution: {integrity: sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==} + engines: {node: '>= 0.12'} + + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + + fp-ts@1.19.3: + resolution: {integrity: sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==} + + fs-extra@0.30.0: + resolution: {integrity: sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + + fs-readdir-recursive@1.1.0: + resolution: {integrity: sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + + get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + + get-port@3.2.0: + resolution: {integrity: sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==} + engines: {node: '>=4'} + + get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + + ghost-testrpc@0.0.2: + resolution: {integrity: sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==} + hasBin: true + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@5.0.15: + resolution: {integrity: sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==} + + glob@7.1.7: + resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} + + glob@7.2.0: + resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + + glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + + glob@9.3.5: + resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} + engines: {node: '>=16 || 14 >=14.17'} + + global-modules@2.0.0: + resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} + engines: {node: '>=6'} + + global-prefix@3.0.0: + resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} + engines: {node: '>=6'} + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + + globby@10.0.2: + resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} + engines: {node: '>=8'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + handlebars@4.7.8: + resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + engines: {node: '>=0.4.7'} + hasBin: true + + hardhat-deploy@0.11.45: + resolution: {integrity: sha512-aC8UNaq3JcORnEUIwV945iJuvBwi65tjHVDU3v6mOcqik7WAzHVCJ7cwmkkipsHrWysrB5YvGF1q9S1vIph83w==} + + hardhat-gas-reporter@1.0.10: + resolution: {integrity: sha512-02N4+So/fZrzJ88ci54GqwVA3Zrf0C9duuTyGt0CFRIh/CdNwbnTgkXkRfojOMLBQ+6t+lBIkgbsOtqMvNwikA==} + peerDependencies: + hardhat: ^2.0.2 + + hardhat-ignore-warnings@0.2.11: + resolution: {integrity: sha512-+nHnRbP6COFZaXE7HAY7TZNE3au5vHe5dkcnyq0XaP07ikT2fJ3NhFY0vn7Deh4Qbz0Z/9Xpnj2ki6Ktgk61pg==} + + hardhat-preprocessor@0.1.5: + resolution: {integrity: sha512-j8m44mmPxpxAAd0G8fPHRHOas/INZdzptSur0TNJvMEGcFdLDhbHHxBcqZVQ/bmiW42q4gC60AP4CXn9EF018g==} + peerDependencies: + hardhat: ^2.0.5 + + hardhat@2.21.0: + resolution: {integrity: sha512-8DlJAVJDEVHaV1sh9FLuKLLgCFv9EAJ+M+8IbjSIPgoeNo3ss5L1HgGBMfnI88c7OzMEZkdcuyGoobFeK3Orqw==} + hasBin: true + peerDependencies: + ts-node: '*' + typescript: '*' + peerDependenciesMeta: + ts-node: + optional: true + typescript: + optional: true + + has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + + has-flag@1.0.0: + resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==} + engines: {node: '>=0.10.0'} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hash-base@3.1.0: + resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} + engines: {node: '>=4'} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + heap@0.2.7: + resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} + + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + + http-basic@8.1.3: + resolution: {integrity: sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==} + engines: {node: '>=6.0.0'} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + http-response-object@3.0.2: + resolution: {integrity: sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + engines: {node: '>= 4'} + + immutable@4.3.5: + resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + imul@1.0.1: + resolution: {integrity: sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==} + engines: {node: '>=0.10.0'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + + interpret@1.4.0: + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} + + io-ts@1.10.4: + resolution: {integrity: sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==} + + is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + + is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@2.0.0: + resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} + engines: {node: '>=4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hex-prefixed@1.0.0: + resolution: {integrity: sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==} + engines: {node: '>=6.5.0', npm: '>=3'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + + is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + + is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + + is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + javascript-natural-sort@0.7.1: + resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} + + js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + jsonfile@2.4.0: + resolution: {integrity: sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==} + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + jsonschema@1.4.1: + resolution: {integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==} + + keccak@3.0.4: + resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} + engines: {node: '>=10.0.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + klaw@1.3.1: + resolution: {integrity: sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==} + + levn@0.3.0: + resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} + engines: {node: '>= 0.8.0'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@2.0.0: + resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} + engines: {node: '>=4'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + + lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + + lru-cache@10.2.0: + resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} + engines: {node: 14 || >=16.14} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + lru_map@0.3.3: + resolution: {integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + markdown-table@1.1.3: + resolution: {integrity: sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==} + + match-all@1.2.6: + resolution: {integrity: sha512-0EESkXiTkWzrQQntBu2uzKvLu6vVkUGz40nGPbSZuegcfE5UuSzNjLaIu76zJWuaT/2I3Z/8M06OlUOZLGwLlQ==} + + md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + + memorystream@0.3.1: + resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} + engines: {node: '>= 0.10.0'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micro-ftch@0.3.1: + resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} + + micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.0.1: + resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} + engines: {node: '>=10'} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimatch@8.0.4: + resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@4.2.8: + resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} + engines: {node: '>=8'} + + minipass@7.0.4: + resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + engines: {node: '>=16 || 14 >=14.17'} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + mnemonist@0.38.5: + resolution: {integrity: sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==} + + mocha@10.3.0: + resolution: {integrity: sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==} + engines: {node: '>= 14.0.0'} + hasBin: true + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + murmur-128@0.2.1: + resolution: {integrity: sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg==} + + natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + node-addon-api@2.0.2: + resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} + + node-emoji@1.11.0: + resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-gyp-build@4.8.0: + resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==} + hasBin: true + + node-interval-tree@2.1.2: + resolution: {integrity: sha512-bJ9zMDuNGzVQg1xv0bCPzyEDxHgbrx7/xGj6CDokvizZZmastPsOh0JJLuY8wA5q2SfX1TLNMk7XNV8WxbGxzA==} + engines: {node: '>= 14.0.0'} + + node-tfhe@0.6.4: + resolution: {integrity: sha512-V/SJjc5GPKIB/KcNGEFSDDQelIKvFIFiCgefeDARgxOnN69fyB+omV4e4j3tMDEz6aN7xRd/NqqQ0im17emXeA==} + + nofilter@3.1.0: + resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} + engines: {node: '>=12.19'} + + nopt@3.0.6: + resolution: {integrity: sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==} + hasBin: true + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + number-to-bn@1.7.0: + resolution: {integrity: sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==} + engines: {node: '>=6.5.0', npm: '>=3'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + + obliterator@2.0.4: + resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.8.3: + resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} + engines: {node: '>= 0.8.0'} + + optionator@0.9.3: + resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + engines: {node: '>= 0.8.0'} + + ordinal@1.0.3: + resolution: {integrity: sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==} + + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + + p-limit@1.3.0: + resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} + engines: {node: '>=4'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@2.0.0: + resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} + engines: {node: '>=4'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + + p-try@1.0.0: + resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} + engines: {node: '>=4'} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-cache-control@1.0.1: + resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + + pbkdf2@3.1.2: + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + prelude-ls@1.1.2: + resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} + engines: {node: '>= 0.8.0'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier-plugin-solidity@1.3.1: + resolution: {integrity: sha512-MN4OP5I2gHAzHZG1wcuJl0FsLS3c4Cc5494bbg+6oQWBPuEamjwDvmGfFMZ6NFzsh3Efd9UUxeT7ImgjNH4ozA==} + engines: {node: '>=16'} + peerDependencies: + prettier: '>=2.3.0' + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + promise@8.3.0: + resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.12.0: + resolution: {integrity: sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==} + engines: {node: '>=0.6'} + + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + rechoir@0.6.2: + resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} + engines: {node: '>= 0.10'} + + recursive-readdir@2.2.3: + resolution: {integrity: sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==} + engines: {node: '>=6.0.0'} + + reduce-flatten@2.0.0: + resolution: {integrity: sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==} + engines: {node: '>=6'} + + regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + engines: {node: '>= 0.4'} + + req-cwd@2.0.0: + resolution: {integrity: sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==} + engines: {node: '>=4'} + + req-from@2.0.0: + resolution: {integrity: sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==} + engines: {node: '>=4'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@3.0.0: + resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==} + engines: {node: '>=4'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve@1.1.7: + resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} + + resolve@1.17.0: + resolution: {integrity: sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==} + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + hasBin: true + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + + rimraf@4.4.1: + resolution: {integrity: sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==} + engines: {node: '>=14'} + hasBin: true + + ripemd160@2.0.2: + resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + + rlp@2.2.7: + resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sc-istanbul@0.4.6: + resolution: {integrity: sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==} + hasBin: true + + scrypt-js@3.0.1: + resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} + + secp256k1@4.0.3: + resolution: {integrity: sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==} + engines: {node: '>=10.0.0'} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + + serialize-javascript@6.0.0: + resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sha.js@2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true + + sha1@1.1.1: + resolution: {integrity: sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==} + + sha3@2.1.4: + resolution: {integrity: sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==} + + shallowequal@1.1.0: + resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shelljs@0.8.5: + resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} + engines: {node: '>=4'} + hasBin: true + + side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + + solc@0.7.3: + resolution: {integrity: sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==} + engines: {node: '>=8.0.0'} + hasBin: true + + solhint-plugin-prettier@0.0.5: + resolution: {integrity: sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA==} + peerDependencies: + prettier: ^1.15.0 || ^2.0.0 + prettier-plugin-solidity: ^1.0.0-alpha.14 + + solhint@3.6.2: + resolution: {integrity: sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ==} + hasBin: true + + solidity-ast@0.4.55: + resolution: {integrity: sha512-qeEU/r/K+V5lrAw8iswf2/yfWAnSGs3WKPHI+zAFKFjX0dIBVXEU/swQ8eJQYHf6PJWUZFO2uWV4V1wEOkeQbA==} + + solidity-comments-darwin-arm64@0.0.2: + resolution: {integrity: sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + solidity-comments-darwin-x64@0.0.2: + resolution: {integrity: sha512-Zjs0Ruz6faBTPT6fBecUt6qh4CdloT8Bwoc0+qxRoTn9UhYscmbPQkUgQEbS0FQPysYqVzzxJB4h1Ofbf4wwtA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + solidity-comments-extractor@0.0.8: + resolution: {integrity: sha512-htM7Vn6LhHreR+EglVMd2s+sZhcXAirB1Zlyrv5zBuTxieCvjfnRpd7iZk75m/u6NOlEyQ94C6TWbBn2cY7w8g==} + + solidity-comments-freebsd-x64@0.0.2: + resolution: {integrity: sha512-8Qe4mpjuAxFSwZJVk7B8gAoLCdbtS412bQzBwk63L8dmlHogvE39iT70aAk3RHUddAppT5RMBunlPUCFYJ3ZTw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + solidity-comments-linux-arm64-gnu@0.0.2: + resolution: {integrity: sha512-spkb0MZZnmrP+Wtq4UxP+nyPAVRe82idOjqndolcNR0S9Xvu4ebwq+LvF4HiUgjTDmeiqYiFZQ8T9KGdLSIoIg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + solidity-comments-linux-arm64-musl@0.0.2: + resolution: {integrity: sha512-guCDbHArcjE+JDXYkxx5RZzY1YF6OnAKCo+sTC5fstyW/KGKaQJNPyBNWuwYsQiaEHpvhW1ha537IvlGek8GqA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + solidity-comments-linux-x64-gnu@0.0.2: + resolution: {integrity: sha512-zIqLehBK/g7tvrFmQljrfZXfkEeLt2v6wbe+uFu6kH/qAHZa7ybt8Vc0wYcmjo2U0PeBm15d79ee3AkwbIjFdQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + solidity-comments-linux-x64-musl@0.0.2: + resolution: {integrity: sha512-R9FeDloVlFGTaVkOlELDVC7+1Tjx5WBPI5L8r0AGOPHK3+jOcRh6sKYpI+VskSPDc3vOO46INkpDgUXrKydlIw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + solidity-comments-win32-arm64-msvc@0.0.2: + resolution: {integrity: sha512-QnWJoCQcJj+rnutULOihN9bixOtYWDdF5Rfz9fpHejL1BtNjdLW1om55XNVHGAHPqBxV4aeQQ6OirKnp9zKsug==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + solidity-comments-win32-ia32-msvc@0.0.2: + resolution: {integrity: sha512-vUg4nADtm/NcOtlIymG23NWJUSuMsvX15nU7ynhGBsdKtt8xhdP3C/zA6vjDk8Jg+FXGQL6IHVQ++g/7rSQi0w==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + solidity-comments-win32-x64-msvc@0.0.2: + resolution: {integrity: sha512-36j+KUF4V/y0t3qatHm/LF5sCUCBx2UndxE1kq5bOzh/s+nQgatuyB+Pd5BfuPQHdWu2KaExYe20FlAa6NL7+Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + solidity-comments@0.0.2: + resolution: {integrity: sha512-G+aK6qtyUfkn1guS8uzqUeua1dURwPlcOjoTYW/TwmXAcE7z/1+oGCfZUdMSe4ZMKklNbVZNiG5ibnF8gkkFfw==} + engines: {node: '>= 12'} + + solidity-coverage@0.8.6: + resolution: {integrity: sha512-vV03mA/0nNMskOdVwNarUcqk0N/aYdelxAbf6RZ5l84FcYHbqDTr2JXyeYMp4bT48qHtAQjnKrygW1FrECyWNw==} + hasBin: true + peerDependencies: + hardhat: ^2.11.0 + + solidity-docgen@0.6.0-beta.36: + resolution: {integrity: sha512-f/I5G2iJgU1h0XrrjRD0hHMr7C10u276vYvm//rw1TzFcYQ4xTOyAoi9oNAHRU0JU4mY9eTuxdVc2zahdMuhaQ==} + peerDependencies: + hardhat: ^2.8.0 + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.2.0: + resolution: {integrity: sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==} + engines: {node: '>=0.8.0'} + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stacktrace-parser@0.1.10: + resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} + engines: {node: '>=6'} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + string-format@2.0.0: + resolution: {integrity: sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==} + + string-width@2.1.1: + resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==} + engines: {node: '>=4'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + + string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@4.0.0: + resolution: {integrity: sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==} + engines: {node: '>=4'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-hex-prefix@1.0.0: + resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} + engines: {node: '>=6.5.0', npm: '>=3'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@3.2.3: + resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==} + engines: {node: '>=0.8.0'} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + sync-request@6.1.0: + resolution: {integrity: sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==} + engines: {node: '>=8.0.0'} + + sync-rpc@1.3.6: + resolution: {integrity: sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==} + + table-layout@1.0.2: + resolution: {integrity: sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==} + engines: {node: '>=8.0.0'} + + table@6.8.1: + resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} + engines: {node: '>=10.0.0'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + tfhe@0.6.4: + resolution: {integrity: sha512-80fP2iJJQXrlhyC81u6/aUWMMMDoOXmlY5uqKka2CEd222xM96+z9+FTZc0MjlrR3U+NHja1WOte+A3nlvZkKw==} + + then-request@6.0.2: + resolution: {integrity: sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==} + engines: {node: '>=6.0.0'} + + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + ts-command-line-args@2.5.1: + resolution: {integrity: sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==} + hasBin: true + + ts-essentials@1.0.4: + resolution: {integrity: sha512-q3N1xS4vZpRouhYHDPwO0bDW3EZ6SK9CrrDHxi/D6BPReSjpVgWIOpLS2o0gSBZm+7q/wyKp6RVM1AeeW7uyfQ==} + + ts-essentials@7.0.3: + resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} + peerDependencies: + typescript: '>=3.7.0' + + ts-generator@0.1.1: + resolution: {integrity: sha512-N+ahhZxTLYu1HNTQetwWcx3so8hcYbkKBHTr4b4/YgObFTIKkOSSsaa+nal12w8mfrJAyzJfETXawbNjSfP2gQ==} + hasBin: true + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.4.0: + resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + + tsort@0.0.1: + resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} + + tsutils@3.21.0: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + + tweetnacl-util@0.15.1: + resolution: {integrity: sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==} + + tweetnacl@1.0.3: + resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} + + type-check@0.3.2: + resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} + engines: {node: '>= 0.8.0'} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@0.7.1: + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} + + typechain@8.3.2: + resolution: {integrity: sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==} + hasBin: true + peerDependencies: + typescript: '>=4.3.0' + + typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.5: + resolution: {integrity: sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==} + engines: {node: '>= 0.4'} + + typedarray@0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + + typescript@5.4.2: + resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} + engines: {node: '>=14.17'} + hasBin: true + + typical@4.0.0: + resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} + engines: {node: '>=8'} + + typical@5.2.0: + resolution: {integrity: sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==} + engines: {node: '>=8'} + + uglify-js@3.17.4: + resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} + engines: {node: '>=0.8.0'} + hasBin: true + + unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici@5.28.3: + resolution: {integrity: sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==} + engines: {node: '>=14.0'} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + url@0.11.4: + resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} + engines: {node: '>= 0.4'} + + utf8@3.0.0: + resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + web3-errors@1.3.0: + resolution: {integrity: sha512-j5JkAKCtuVMbY3F5PYXBqg1vWrtF4jcyyMY1rlw8a4PV67AkqlepjGgpzWJZd56Mt+TvHy6DA1F/3Id8LatDSQ==} + engines: {node: '>=14', npm: '>=6.12.0'} + + web3-types@1.8.1: + resolution: {integrity: sha512-isspsvQbBJFUkJYz2Badb7dz/BrLLLpOop/WmnL5InyYMr7kYYc8038NYO7Vkp1M7Bupa/wg+yALvBm7EGbyoQ==} + engines: {node: '>=14', npm: '>=6.12.0'} + + web3-utils@1.10.4: + resolution: {integrity: sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==} + engines: {node: '>=8.0.0'} + + web3-validator@2.0.6: + resolution: {integrity: sha512-qn9id0/l1bWmvH4XfnG/JtGKKwut2Vokl6YXP5Kfg424npysmtRLe9DgiNBM9Op7QL/aSiaA0TVXibuIuWcizg==} + engines: {node: '>=14', npm: '>=6.12.0'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + + which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true -packages: + widest-line@3.1.0: + resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} + engines: {node: '>=8'} - /@aashutoshrathi/word-wrap@1.2.6: - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - dev: true - /@adraffy/ens-normalize@1.10.1: - resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==} - dev: true + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - /@babel/code-frame@7.23.5: - resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} - engines: {node: '>=6.9.0'} + wordwrapjs@4.0.1: + resolution: {integrity: sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==} + engines: {node: '>=8.0.0'} + + workerpool@6.2.1: + resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@7.4.6: + resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@7.5.9: + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.5.0: + resolution: {integrity: sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yargs-parser@20.2.4: + resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} + engines: {node: '>=10'} + + yargs-unparser@2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zksync-web3@0.14.4: + resolution: {integrity: sha512-kYehMD/S6Uhe1g434UnaMN+sBr9nQm23Ywn0EUP5BfQCsbjcr3ORuS68PosZw8xUTu3pac7G6YMSnNHk+fwzvg==} + deprecated: This package has been deprecated in favor of zksync-ethers@5.0.0 + peerDependencies: + ethers: ^5.7.0 + + zod@3.23.8: + resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + +snapshots: + + '@aashutoshrathi/word-wrap@1.2.6': {} + + '@adraffy/ens-normalize@1.10.1': {} + + '@babel/code-frame@7.23.5': dependencies: '@babel/highlight': 7.23.4 chalk: 2.4.2 - dev: true - /@babel/generator@7.17.7: - resolution: {integrity: sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==} - engines: {node: '>=6.9.0'} + '@babel/generator@7.17.7': dependencies: '@babel/types': 7.17.0 jsesc: 2.5.2 source-map: 0.5.7 - dev: true - /@babel/generator@7.23.6: - resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} - engines: {node: '>=6.9.0'} + '@babel/generator@7.23.6': dependencies: '@babel/types': 7.24.0 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 - dev: true - /@babel/helper-environment-visitor@7.22.20: - resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-environment-visitor@7.22.20': {} - /@babel/helper-function-name@7.23.0: - resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} - engines: {node: '>=6.9.0'} + '@babel/helper-function-name@7.23.0': dependencies: '@babel/template': 7.24.0 '@babel/types': 7.24.0 - dev: true - /@babel/helper-hoist-variables@7.22.5: - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} - engines: {node: '>=6.9.0'} + '@babel/helper-hoist-variables@7.22.5': dependencies: '@babel/types': 7.24.0 - dev: true - /@babel/helper-split-export-declaration@7.22.6: - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} - engines: {node: '>=6.9.0'} + '@babel/helper-split-export-declaration@7.22.6': dependencies: '@babel/types': 7.24.0 - dev: true - /@babel/helper-string-parser@7.23.4: - resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-string-parser@7.23.4': {} - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-validator-identifier@7.22.20': {} - /@babel/highlight@7.23.4: - resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} - engines: {node: '>=6.9.0'} + '@babel/highlight@7.23.4': dependencies: '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 js-tokens: 4.0.0 - dev: true - /@babel/parser@7.24.0: - resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==} - engines: {node: '>=6.0.0'} - hasBin: true + '@babel/parser@7.24.0': dependencies: '@babel/types': 7.17.0 - dev: true - /@babel/template@7.24.0: - resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} - engines: {node: '>=6.9.0'} + '@babel/template@7.24.0': dependencies: '@babel/code-frame': 7.23.5 '@babel/parser': 7.24.0 '@babel/types': 7.24.0 - dev: true - /@babel/traverse@7.23.2: - resolution: {integrity: sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==} - engines: {node: '>=6.9.0'} + '@babel/traverse@7.23.2': dependencies: '@babel/code-frame': 7.23.5 '@babel/generator': 7.23.6 @@ -248,50 +3159,30 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color - dev: true - /@babel/types@7.17.0: - resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==} - engines: {node: '>=6.9.0'} + '@babel/types@7.17.0': dependencies: '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 - dev: true - /@babel/types@7.24.0: - resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} - engines: {node: '>=6.9.0'} + '@babel/types@7.24.0': dependencies: '@babel/helper-string-parser': 7.23.4 '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 - dev: true - /@cspotcode/source-map-support@0.8.1: - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 - dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': dependencies: eslint: 8.57.0 eslint-visitor-keys: 3.4.3 - dev: true - /@eslint-community/regexpp@4.10.0: - resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true + '@eslint-community/regexpp@4.10.0': {} - /@eslint/eslintrc@2.1.4: - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 debug: 4.3.4(supports-color@8.1.1) @@ -304,30 +3195,18 @@ packages: strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - dev: true - /@eslint/js@8.57.0: - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true + '@eslint/js@8.57.0': {} - /@ethereumjs/rlp@4.0.1: - resolution: {integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==} - engines: {node: '>=14'} - hasBin: true - dev: true + '@ethereumjs/rlp@4.0.1': {} - /@ethereumjs/util@8.1.0: - resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} - engines: {node: '>=14'} + '@ethereumjs/util@8.1.0': dependencies: '@ethereumjs/rlp': 4.0.1 ethereum-cryptography: 2.1.3 micro-ftch: 0.3.1 - dev: true - /@ethersproject/abi@5.7.0: - resolution: {integrity: sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==} + '@ethersproject/abi@5.7.0': dependencies: '@ethersproject/address': 5.7.0 '@ethersproject/bignumber': 5.7.0 @@ -338,10 +3217,8 @@ packages: '@ethersproject/logger': 5.7.0 '@ethersproject/properties': 5.7.0 '@ethersproject/strings': 5.7.0 - dev: true - /@ethersproject/abstract-provider@5.7.0: - resolution: {integrity: sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==} + '@ethersproject/abstract-provider@5.7.0': dependencies: '@ethersproject/bignumber': 5.7.0 '@ethersproject/bytes': 5.7.0 @@ -350,63 +3227,47 @@ packages: '@ethersproject/properties': 5.7.0 '@ethersproject/transactions': 5.7.0 '@ethersproject/web': 5.7.1 - dev: true - /@ethersproject/abstract-signer@5.7.0: - resolution: {integrity: sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==} + '@ethersproject/abstract-signer@5.7.0': dependencies: '@ethersproject/abstract-provider': 5.7.0 '@ethersproject/bignumber': 5.7.0 '@ethersproject/bytes': 5.7.0 '@ethersproject/logger': 5.7.0 '@ethersproject/properties': 5.7.0 - dev: true - /@ethersproject/address@5.7.0: - resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==} + '@ethersproject/address@5.7.0': dependencies: '@ethersproject/bignumber': 5.7.0 '@ethersproject/bytes': 5.7.0 '@ethersproject/keccak256': 5.7.0 '@ethersproject/logger': 5.7.0 '@ethersproject/rlp': 5.7.0 - dev: true - /@ethersproject/base64@5.7.0: - resolution: {integrity: sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==} + '@ethersproject/base64@5.7.0': dependencies: '@ethersproject/bytes': 5.7.0 - dev: true - /@ethersproject/basex@5.7.0: - resolution: {integrity: sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==} + '@ethersproject/basex@5.7.0': dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/properties': 5.7.0 - dev: true - /@ethersproject/bignumber@5.7.0: - resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==} + '@ethersproject/bignumber@5.7.0': dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/logger': 5.7.0 bn.js: 5.2.1 - dev: true - /@ethersproject/bytes@5.7.0: - resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} + '@ethersproject/bytes@5.7.0': dependencies: '@ethersproject/logger': 5.7.0 - dev: true - /@ethersproject/constants@5.7.0: - resolution: {integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==} + '@ethersproject/constants@5.7.0': dependencies: '@ethersproject/bignumber': 5.7.0 - dev: true - /@ethersproject/contracts@5.7.0: - resolution: {integrity: sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==} + '@ethersproject/contracts@5.7.0': dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/abstract-provider': 5.7.0 @@ -418,10 +3279,8 @@ packages: '@ethersproject/logger': 5.7.0 '@ethersproject/properties': 5.7.0 '@ethersproject/transactions': 5.7.0 - dev: true - /@ethersproject/hash@5.7.0: - resolution: {integrity: sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==} + '@ethersproject/hash@5.7.0': dependencies: '@ethersproject/abstract-signer': 5.7.0 '@ethersproject/address': 5.7.0 @@ -432,10 +3291,8 @@ packages: '@ethersproject/logger': 5.7.0 '@ethersproject/properties': 5.7.0 '@ethersproject/strings': 5.7.0 - dev: true - /@ethersproject/hdnode@5.7.0: - resolution: {integrity: sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==} + '@ethersproject/hdnode@5.7.0': dependencies: '@ethersproject/abstract-signer': 5.7.0 '@ethersproject/basex': 5.7.0 @@ -449,10 +3306,8 @@ packages: '@ethersproject/strings': 5.7.0 '@ethersproject/transactions': 5.7.0 '@ethersproject/wordlists': 5.7.0 - dev: true - /@ethersproject/json-wallets@5.7.0: - resolution: {integrity: sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==} + '@ethersproject/json-wallets@5.7.0': dependencies: '@ethersproject/abstract-signer': 5.7.0 '@ethersproject/address': 5.7.0 @@ -467,40 +3322,28 @@ packages: '@ethersproject/transactions': 5.7.0 aes-js: 3.0.0 scrypt-js: 3.0.1 - dev: true - /@ethersproject/keccak256@5.7.0: - resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==} + '@ethersproject/keccak256@5.7.0': dependencies: '@ethersproject/bytes': 5.7.0 js-sha3: 0.8.0 - dev: true - /@ethersproject/logger@5.7.0: - resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==} - dev: true + '@ethersproject/logger@5.7.0': {} - /@ethersproject/networks@5.7.1: - resolution: {integrity: sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==} + '@ethersproject/networks@5.7.1': dependencies: '@ethersproject/logger': 5.7.0 - dev: true - /@ethersproject/pbkdf2@5.7.0: - resolution: {integrity: sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==} + '@ethersproject/pbkdf2@5.7.0': dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/sha2': 5.7.0 - dev: true - /@ethersproject/properties@5.7.0: - resolution: {integrity: sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==} + '@ethersproject/properties@5.7.0': dependencies: '@ethersproject/logger': 5.7.0 - dev: true - /@ethersproject/providers@5.7.2: - resolution: {integrity: sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==} + '@ethersproject/providers@5.7.2': dependencies: '@ethersproject/abstract-provider': 5.7.0 '@ethersproject/abstract-signer': 5.7.0 @@ -525,32 +3368,24 @@ packages: transitivePeerDependencies: - bufferutil - utf-8-validate - dev: true - /@ethersproject/random@5.7.0: - resolution: {integrity: sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==} + '@ethersproject/random@5.7.0': dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/logger': 5.7.0 - dev: true - /@ethersproject/rlp@5.7.0: - resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==} + '@ethersproject/rlp@5.7.0': dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/logger': 5.7.0 - dev: true - /@ethersproject/sha2@5.7.0: - resolution: {integrity: sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==} + '@ethersproject/sha2@5.7.0': dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/logger': 5.7.0 hash.js: 1.1.7 - dev: true - /@ethersproject/signing-key@5.7.0: - resolution: {integrity: sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==} + '@ethersproject/signing-key@5.7.0': dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/logger': 5.7.0 @@ -558,10 +3393,8 @@ packages: bn.js: 5.2.1 elliptic: 6.5.4 hash.js: 1.1.7 - dev: true - /@ethersproject/solidity@5.7.0: - resolution: {integrity: sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==} + '@ethersproject/solidity@5.7.0': dependencies: '@ethersproject/bignumber': 5.7.0 '@ethersproject/bytes': 5.7.0 @@ -569,18 +3402,14 @@ packages: '@ethersproject/logger': 5.7.0 '@ethersproject/sha2': 5.7.0 '@ethersproject/strings': 5.7.0 - dev: true - /@ethersproject/strings@5.7.0: - resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==} + '@ethersproject/strings@5.7.0': dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/constants': 5.7.0 '@ethersproject/logger': 5.7.0 - dev: true - /@ethersproject/transactions@5.7.0: - resolution: {integrity: sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==} + '@ethersproject/transactions@5.7.0': dependencies: '@ethersproject/address': 5.7.0 '@ethersproject/bignumber': 5.7.0 @@ -591,18 +3420,14 @@ packages: '@ethersproject/properties': 5.7.0 '@ethersproject/rlp': 5.7.0 '@ethersproject/signing-key': 5.7.0 - dev: true - /@ethersproject/units@5.7.0: - resolution: {integrity: sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==} + '@ethersproject/units@5.7.0': dependencies: '@ethersproject/bignumber': 5.7.0 '@ethersproject/constants': 5.7.0 '@ethersproject/logger': 5.7.0 - dev: true - /@ethersproject/wallet@5.7.0: - resolution: {integrity: sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==} + '@ethersproject/wallet@5.7.0': dependencies: '@ethersproject/abstract-provider': 5.7.0 '@ethersproject/abstract-signer': 5.7.0 @@ -619,236 +3444,123 @@ packages: '@ethersproject/signing-key': 5.7.0 '@ethersproject/transactions': 5.7.0 '@ethersproject/wordlists': 5.7.0 - dev: true - /@ethersproject/web@5.7.1: - resolution: {integrity: sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==} + '@ethersproject/web@5.7.1': dependencies: '@ethersproject/base64': 5.7.0 '@ethersproject/bytes': 5.7.0 '@ethersproject/logger': 5.7.0 '@ethersproject/properties': 5.7.0 '@ethersproject/strings': 5.7.0 - dev: true - /@ethersproject/wordlists@5.7.0: - resolution: {integrity: sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==} + '@ethersproject/wordlists@5.7.0': dependencies: '@ethersproject/bytes': 5.7.0 '@ethersproject/hash': 5.7.0 '@ethersproject/logger': 5.7.0 '@ethersproject/properties': 5.7.0 '@ethersproject/strings': 5.7.0 - dev: true - /@fastify/busboy@2.1.1: - resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} - engines: {node: '>=14'} - dev: true + '@fastify/busboy@2.1.1': {} - /@humanwhocodes/config-array@0.11.14: - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} - engines: {node: '>=10.10.0'} + '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.2 debug: 4.3.4(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color - dev: true - /@humanwhocodes/module-importer@1.0.1: - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - dev: true + '@humanwhocodes/module-importer@1.0.1': {} - /@humanwhocodes/object-schema@2.0.2: - resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} - dev: true + '@humanwhocodes/object-schema@2.0.2': {} - /@jridgewell/gen-mapping@0.3.5: - resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} - engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.25 - dev: true - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - dev: true + '@jridgewell/resolve-uri@3.1.2': {} - /@jridgewell/set-array@1.2.1: - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} - dev: true + '@jridgewell/set-array@1.2.1': {} - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true + '@jridgewell/sourcemap-codec@1.4.15': {} - /@jridgewell/trace-mapping@0.3.25: - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@jridgewell/trace-mapping@0.3.9': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /@metamask/eth-sig-util@4.0.1: - resolution: {integrity: sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==} - engines: {node: '>=12.0.0'} + '@metamask/eth-sig-util@4.0.1': dependencies: ethereumjs-abi: 0.6.8 ethereumjs-util: 6.2.1 ethjs-util: 0.1.6 tweetnacl: 1.0.3 tweetnacl-util: 0.15.1 - dev: true - /@noble/curves@1.2.0: - resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} + '@noble/curves@1.2.0': dependencies: '@noble/hashes': 1.3.2 - dev: true - /@noble/curves@1.3.0: - resolution: {integrity: sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==} + '@noble/curves@1.3.0': dependencies: '@noble/hashes': 1.3.3 - dev: true - /@noble/hashes@1.2.0: - resolution: {integrity: sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==} - dev: true + '@noble/hashes@1.2.0': {} - /@noble/hashes@1.3.2: - resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} - engines: {node: '>= 16'} - dev: true + '@noble/hashes@1.3.2': {} - /@noble/hashes@1.3.3: - resolution: {integrity: sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==} - engines: {node: '>= 16'} - dev: true + '@noble/hashes@1.3.3': {} - /@noble/secp256k1@1.7.1: - resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} - dev: true + '@noble/secp256k1@1.7.1': {} - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - dev: true - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true + '@nodelib/fs.stat@2.0.5': {} - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - dev: true - /@nomicfoundation/edr-darwin-arm64@0.2.1: - resolution: {integrity: sha512-aMYaRaZVQ/TmyNJIoXf1bU4k0zfinaL9Sy1day4yGlL6eiQPFfRGj9W6TZaZIoYG0XTx/mQWD7dkXJ7LdrleJA==} - engines: {node: '>= 18'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true + '@nomicfoundation/edr-darwin-arm64@0.2.1': optional: true - /@nomicfoundation/edr-darwin-x64@0.2.1: - resolution: {integrity: sha512-ma0SLcjHm5L3nPHcKFJB0jv/gKGSKaxr5Z65rurX/eaYUQJ7YGMsb8er9bSCo9rjzOtxf4FoPj3grL3zGpOj8A==} - engines: {node: '>= 18'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true + '@nomicfoundation/edr-darwin-x64@0.2.1': optional: true - /@nomicfoundation/edr-linux-arm64-gnu@0.2.1: - resolution: {integrity: sha512-NX3G4pBhRitWrjSGY3HTyCq3wKSm5YqrKVOCNQGl9/jcjSovqxlgzFMiTx4YZCzGntfJ/1om9AI84OWxYJjoDw==} - engines: {node: '>= 18'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true + '@nomicfoundation/edr-linux-arm64-gnu@0.2.1': optional: true - /@nomicfoundation/edr-linux-arm64-musl@0.2.1: - resolution: {integrity: sha512-gdQ3QHkt9XRkdtOGQ8fMwS11MXdjLeZgLrqoial4V4qtMaamIMMhVczK+VEvUhD8p7G4BVmp6kmkvcsthmndmw==} - engines: {node: '>= 18'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true + '@nomicfoundation/edr-linux-arm64-musl@0.2.1': optional: true - /@nomicfoundation/edr-linux-x64-gnu@0.2.1: - resolution: {integrity: sha512-OqabFY37vji6mYbLD9CvG28lja68czeVw58oWByIhFV3BpBu/cyP1oAbhzk3LieylujabS3Ekpvjw2Tkf0A9RQ==} - engines: {node: '>= 18'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true + '@nomicfoundation/edr-linux-x64-gnu@0.2.1': optional: true - /@nomicfoundation/edr-linux-x64-musl@0.2.1: - resolution: {integrity: sha512-vHfFFK2EPISuQUQge+bdjXamb0EUjfl8srYSog1qfiwyLwLeuSbpyyFzDeITAgPpkkFuedTfJW553K0Hipspyg==} - engines: {node: '>= 18'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true + '@nomicfoundation/edr-linux-x64-musl@0.2.1': optional: true - /@nomicfoundation/edr-win32-arm64-msvc@0.2.1: - resolution: {integrity: sha512-K/mui67RCKxghbSyvhvW3rvyVN1pa9M1Q9APUx1PtWjSSdXDFpqEY1NYsv2syb47Ca8ObJwVMF+LvnB6GvhUOQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true + '@nomicfoundation/edr-win32-arm64-msvc@0.2.1': optional: true - /@nomicfoundation/edr-win32-ia32-msvc@0.2.1: - resolution: {integrity: sha512-HHK0mXEtjvfjJrJlqcYgQCy3lZIXS1KNl2GaP8bwEIuEwx++XxXs/ThLjPepM1nhCGICij8IGy7p3KrkzRelsw==} - engines: {node: '>= 18'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true + '@nomicfoundation/edr-win32-ia32-msvc@0.2.1': optional: true - /@nomicfoundation/edr-win32-x64-msvc@0.2.1: - resolution: {integrity: sha512-FY4eQJdj1/y8ST0RyQycx63yr+lvdYNnUkzgWf4X+vPH1lOhXae+L2NDcNCQlTDAfQcD6yz0bkBUkLrlJ8pTww==} - engines: {node: '>= 18'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true + '@nomicfoundation/edr-win32-x64-msvc@0.2.1': optional: true - /@nomicfoundation/edr@0.2.1: - resolution: {integrity: sha512-Dleau3ItHJh2n85G2J6AIPBoLgu/mOWkmrh26z3VsJE2tp/e00hUk/dqz85ncsVcBYEc6/YOn/DomWu0wSF9tQ==} - engines: {node: '>= 18'} + '@nomicfoundation/edr@0.2.1': optionalDependencies: '@nomicfoundation/edr-darwin-arm64': 0.2.1 '@nomicfoundation/edr-darwin-x64': 0.2.1 @@ -859,243 +3571,118 @@ packages: '@nomicfoundation/edr-win32-arm64-msvc': 0.2.1 '@nomicfoundation/edr-win32-ia32-msvc': 0.2.1 '@nomicfoundation/edr-win32-x64-msvc': 0.2.1 - dev: true - /@nomicfoundation/ethereumjs-common@4.0.4: - resolution: {integrity: sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==} + '@nomicfoundation/ethereumjs-common@4.0.4': dependencies: '@nomicfoundation/ethereumjs-util': 9.0.4 transitivePeerDependencies: - c-kzg - dev: true - /@nomicfoundation/ethereumjs-rlp@5.0.4: - resolution: {integrity: sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==} - engines: {node: '>=18'} - hasBin: true - dev: true + '@nomicfoundation/ethereumjs-rlp@5.0.4': {} - /@nomicfoundation/ethereumjs-tx@5.0.4: - resolution: {integrity: sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==} - engines: {node: '>=18'} - peerDependencies: - c-kzg: ^2.1.2 - peerDependenciesMeta: - c-kzg: - optional: true + '@nomicfoundation/ethereumjs-tx@5.0.4': dependencies: '@nomicfoundation/ethereumjs-common': 4.0.4 '@nomicfoundation/ethereumjs-rlp': 5.0.4 '@nomicfoundation/ethereumjs-util': 9.0.4 ethereum-cryptography: 0.1.3 - dev: true - /@nomicfoundation/ethereumjs-util@9.0.4: - resolution: {integrity: sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==} - engines: {node: '>=18'} - peerDependencies: - c-kzg: ^2.1.2 - peerDependenciesMeta: - c-kzg: - optional: true + '@nomicfoundation/ethereumjs-util@9.0.4': dependencies: - '@nomicfoundation/ethereumjs-rlp': 5.0.4 - ethereum-cryptography: 0.1.3 - dev: true - - /@nomicfoundation/hardhat-chai-matchers@2.0.6(@nomicfoundation/hardhat-ethers@3.0.5)(chai@4.4.1)(ethers@6.11.1)(hardhat@2.21.0): - resolution: {integrity: sha512-Te1Uyo9oJcTCF0Jy9dztaLpshmlpjLf2yPtWXlXuLjMt3RRSmJLm/+rKVTW6gfadAEs12U/it6D0ZRnnRGiICQ==} - peerDependencies: - '@nomicfoundation/hardhat-ethers': ^3.0.0 - chai: ^4.2.0 - ethers: ^6.1.0 - hardhat: ^2.9.4 + '@nomicfoundation/ethereumjs-rlp': 5.0.4 + ethereum-cryptography: 0.1.3 + + '@nomicfoundation/hardhat-chai-matchers@2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': dependencies: - '@nomicfoundation/hardhat-ethers': 3.0.5(ethers@6.11.1)(hardhat@2.21.0) + '@nomicfoundation/hardhat-ethers': 3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) '@types/chai-as-promised': 7.1.8 chai: 4.4.1 chai-as-promised: 7.1.1(chai@4.4.1) deep-eql: 4.1.3 ethers: 6.11.1 - hardhat: 2.21.0(ts-node@10.9.2)(typescript@5.4.2) + hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) ordinal: 1.0.3 - dev: true - /@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.21.0): - resolution: {integrity: sha512-RNFe8OtbZK6Ila9kIlHp0+S80/0Bu/3p41HUpaRIoHLm6X3WekTd83vob3rE54Duufu1edCiBDxspBzi2rxHHw==} - peerDependencies: - ethers: ^6.1.0 - hardhat: ^2.0.0 + '@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': dependencies: debug: 4.3.4(supports-color@8.1.1) ethers: 6.11.1 - hardhat: 2.21.0(ts-node@10.9.2)(typescript@5.4.2) + hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) lodash.isequal: 4.5.0 transitivePeerDependencies: - supports-color - dev: true - /@nomicfoundation/hardhat-network-helpers@1.0.10(hardhat@2.21.0): - resolution: {integrity: sha512-R35/BMBlx7tWN5V6d/8/19QCwEmIdbnA4ZrsuXgvs8i2qFx5i7h6mH5pBS4Pwi4WigLH+upl6faYusrNPuzMrQ==} - peerDependencies: - hardhat: ^2.9.5 + '@nomicfoundation/hardhat-network-helpers@1.0.10(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': dependencies: ethereumjs-util: 7.1.5 - hardhat: 2.21.0(ts-node@10.9.2)(typescript@5.4.2) - dev: true + hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) - /@nomicfoundation/hardhat-toolbox@3.0.0(@nomicfoundation/hardhat-chai-matchers@2.0.6)(@nomicfoundation/hardhat-ethers@3.0.5)(@nomicfoundation/hardhat-network-helpers@1.0.10)(@nomicfoundation/hardhat-verify@1.1.1)(@typechain/ethers-v6@0.4.3)(@typechain/hardhat@8.0.3)(@types/chai@4.3.12)(@types/mocha@10.0.6)(@types/node@18.19.23)(chai@4.4.1)(ethers@6.11.1)(hardhat-gas-reporter@1.0.10)(hardhat@2.21.0)(solidity-coverage@0.8.6)(ts-node@10.9.2)(typechain@8.3.2)(typescript@5.4.2): - resolution: {integrity: sha512-MsteDXd0UagMksqm9KvcFG6gNKYNa3GGNCy73iQ6bEasEgg2v8Qjl6XA5hjs8o5UD5A3153B6W2BIVJ8SxYUtA==} - peerDependencies: - '@nomicfoundation/hardhat-chai-matchers': ^2.0.0 - '@nomicfoundation/hardhat-ethers': ^3.0.0 - '@nomicfoundation/hardhat-network-helpers': ^1.0.0 - '@nomicfoundation/hardhat-verify': ^1.0.0 - '@typechain/ethers-v6': ^0.4.0 - '@typechain/hardhat': ^8.0.0 - '@types/chai': ^4.2.0 - '@types/mocha': '>=9.1.0' - '@types/node': '>=12.0.0' - chai: ^4.2.0 - ethers: ^6.4.0 - hardhat: ^2.11.0 - hardhat-gas-reporter: ^1.0.8 - solidity-coverage: ^0.8.1 - ts-node: '>=8.0.0' - typechain: ^8.2.0 - typescript: '>=4.5.0' + '@nomicfoundation/hardhat-toolbox@3.0.0(efoxkvpld3mcx7zgojgym4euli)': dependencies: - '@nomicfoundation/hardhat-chai-matchers': 2.0.6(@nomicfoundation/hardhat-ethers@3.0.5)(chai@4.4.1)(ethers@6.11.1)(hardhat@2.21.0) - '@nomicfoundation/hardhat-ethers': 3.0.5(ethers@6.11.1)(hardhat@2.21.0) - '@nomicfoundation/hardhat-network-helpers': 1.0.10(hardhat@2.21.0) - '@nomicfoundation/hardhat-verify': 1.1.1(hardhat@2.21.0) - '@typechain/ethers-v6': 0.4.3(ethers@6.11.1)(typechain@8.3.2)(typescript@5.4.2) - '@typechain/hardhat': 8.0.3(@typechain/ethers-v6@0.4.3)(ethers@6.11.1)(hardhat@2.21.0)(typechain@8.3.2) + '@nomicfoundation/hardhat-chai-matchers': 2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-ethers': 3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-network-helpers': 1.0.10(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-verify': 1.1.1(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@typechain/ethers-v6': 0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2) + '@typechain/hardhat': 8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2)) '@types/chai': 4.3.12 '@types/mocha': 10.0.6 '@types/node': 18.19.23 chai: 4.4.1 ethers: 6.11.1 - hardhat: 2.21.0(ts-node@10.9.2)(typescript@5.4.2) - hardhat-gas-reporter: 1.0.10(hardhat@2.21.0) - solidity-coverage: 0.8.6(hardhat@2.21.0) + hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat-gas-reporter: 1.0.10(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + solidity-coverage: 0.8.6(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) ts-node: 10.9.2(@types/node@18.19.23)(typescript@5.4.2) typechain: 8.3.2(typescript@5.4.2) typescript: 5.4.2 - dev: true - /@nomicfoundation/hardhat-verify@1.1.1(hardhat@2.21.0): - resolution: {integrity: sha512-9QsTYD7pcZaQFEA3tBb/D/oCStYDiEVDN7Dxeo/4SCyHRSm86APypxxdOMEPlGmXsAvd+p1j/dTODcpxb8aztA==} - peerDependencies: - hardhat: ^2.0.4 + '@nomicfoundation/hardhat-verify@1.1.1(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/address': 5.7.0 cbor: 8.1.0 chalk: 2.4.2 debug: 4.3.4(supports-color@8.1.1) - hardhat: 2.21.0(ts-node@10.9.2)(typescript@5.4.2) + hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) lodash.clonedeep: 4.5.0 semver: 6.3.1 table: 6.8.1 undici: 5.28.3 transitivePeerDependencies: - supports-color - dev: true - /@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1: - resolution: {integrity: sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true + '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1': optional: true - /@nomicfoundation/solidity-analyzer-darwin-x64@0.1.1: - resolution: {integrity: sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true + '@nomicfoundation/solidity-analyzer-darwin-x64@0.1.1': optional: true - /@nomicfoundation/solidity-analyzer-freebsd-x64@0.1.1: - resolution: {integrity: sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true + '@nomicfoundation/solidity-analyzer-freebsd-x64@0.1.1': optional: true - /@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.1: - resolution: {integrity: sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true + '@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.1': optional: true - /@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.1: - resolution: {integrity: sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true + '@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.1': optional: true - /@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.1: - resolution: {integrity: sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true + '@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.1': optional: true - /@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.1: - resolution: {integrity: sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true + '@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.1': optional: true - /@nomicfoundation/solidity-analyzer-win32-arm64-msvc@0.1.1: - resolution: {integrity: sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true + '@nomicfoundation/solidity-analyzer-win32-arm64-msvc@0.1.1': optional: true - /@nomicfoundation/solidity-analyzer-win32-ia32-msvc@0.1.1: - resolution: {integrity: sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true + '@nomicfoundation/solidity-analyzer-win32-ia32-msvc@0.1.1': optional: true - /@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.1: - resolution: {integrity: sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true + '@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.1': optional: true - /@nomicfoundation/solidity-analyzer@0.1.1: - resolution: {integrity: sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==} - engines: {node: '>= 12'} + '@nomicfoundation/solidity-analyzer@0.1.1': optionalDependencies: '@nomicfoundation/solidity-analyzer-darwin-arm64': 0.1.1 '@nomicfoundation/solidity-analyzer-darwin-x64': 0.1.1 @@ -1107,77 +3694,54 @@ packages: '@nomicfoundation/solidity-analyzer-win32-arm64-msvc': 0.1.1 '@nomicfoundation/solidity-analyzer-win32-ia32-msvc': 0.1.1 '@nomicfoundation/solidity-analyzer-win32-x64-msvc': 0.1.1 - dev: true - /@openzeppelin/contracts@5.0.2: - resolution: {integrity: sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA==} + '@openzeppelin/contracts@5.0.2': {} - /@scure/base@1.1.5: - resolution: {integrity: sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==} - dev: true + '@scure/base@1.1.5': {} - /@scure/bip32@1.1.5: - resolution: {integrity: sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==} + '@scure/bip32@1.1.5': dependencies: '@noble/hashes': 1.2.0 '@noble/secp256k1': 1.7.1 '@scure/base': 1.1.5 - dev: true - /@scure/bip32@1.3.3: - resolution: {integrity: sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==} + '@scure/bip32@1.3.3': dependencies: '@noble/curves': 1.3.0 '@noble/hashes': 1.3.3 '@scure/base': 1.1.5 - dev: true - /@scure/bip39@1.1.1: - resolution: {integrity: sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==} + '@scure/bip39@1.1.1': dependencies: '@noble/hashes': 1.2.0 '@scure/base': 1.1.5 - dev: true - /@scure/bip39@1.2.2: - resolution: {integrity: sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==} + '@scure/bip39@1.2.2': dependencies: '@noble/hashes': 1.3.3 '@scure/base': 1.1.5 - dev: true - /@sentry/core@5.30.0: - resolution: {integrity: sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==} - engines: {node: '>=6'} + '@sentry/core@5.30.0': dependencies: '@sentry/hub': 5.30.0 '@sentry/minimal': 5.30.0 '@sentry/types': 5.30.0 '@sentry/utils': 5.30.0 tslib: 1.14.1 - dev: true - /@sentry/hub@5.30.0: - resolution: {integrity: sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==} - engines: {node: '>=6'} + '@sentry/hub@5.30.0': dependencies: '@sentry/types': 5.30.0 '@sentry/utils': 5.30.0 tslib: 1.14.1 - dev: true - /@sentry/minimal@5.30.0: - resolution: {integrity: sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==} - engines: {node: '>=6'} + '@sentry/minimal@5.30.0': dependencies: '@sentry/hub': 5.30.0 '@sentry/types': 5.30.0 tslib: 1.14.1 - dev: true - /@sentry/node@5.30.0: - resolution: {integrity: sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==} - engines: {node: '>=6'} + '@sentry/node@5.30.0': dependencies: '@sentry/core': 5.30.0 '@sentry/hub': 5.30.0 @@ -1190,60 +3754,35 @@ packages: tslib: 1.14.1 transitivePeerDependencies: - supports-color - dev: true - /@sentry/tracing@5.30.0: - resolution: {integrity: sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==} - engines: {node: '>=6'} + '@sentry/tracing@5.30.0': dependencies: '@sentry/hub': 5.30.0 '@sentry/minimal': 5.30.0 '@sentry/types': 5.30.0 '@sentry/utils': 5.30.0 tslib: 1.14.1 - dev: true - /@sentry/types@5.30.0: - resolution: {integrity: sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==} - engines: {node: '>=6'} - dev: true + '@sentry/types@5.30.0': {} - /@sentry/utils@5.30.0: - resolution: {integrity: sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==} - engines: {node: '>=6'} + '@sentry/utils@5.30.0': dependencies: '@sentry/types': 5.30.0 tslib: 1.14.1 - dev: true - /@solidity-parser/parser@0.14.5: - resolution: {integrity: sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==} + '@solidity-parser/parser@0.14.5': dependencies: antlr4ts: 0.5.0-alpha.4 - dev: true - /@solidity-parser/parser@0.16.2: - resolution: {integrity: sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==} + '@solidity-parser/parser@0.16.2': dependencies: antlr4ts: 0.5.0-alpha.4 - dev: true - /@solidity-parser/parser@0.17.0: - resolution: {integrity: sha512-Nko8R0/kUo391jsEHHxrGM07QFdnPGvlmox4rmH0kNiNAashItAilhy4Mv4pK5gQmW5f4sXAF58fwJbmlkGcVw==} - dev: true + '@solidity-parser/parser@0.17.0': {} - /@solidity-parser/parser@0.18.0: - resolution: {integrity: sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==} - dev: true + '@solidity-parser/parser@0.18.0': {} - /@trivago/prettier-plugin-sort-imports@4.3.0(prettier@2.8.8): - resolution: {integrity: sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==} - peerDependencies: - '@vue/compiler-sfc': 3.x - prettier: 2.x - 3.x - peerDependenciesMeta: - '@vue/compiler-sfc': - optional: true + '@trivago/prettier-plugin-sort-imports@4.3.0(prettier@2.8.8)': dependencies: '@babel/generator': 7.17.7 '@babel/parser': 7.24.0 @@ -1254,180 +3793,107 @@ packages: prettier: 2.8.8 transitivePeerDependencies: - supports-color - dev: true - /@tsconfig/node10@1.0.9: - resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} - dev: true + '@tsconfig/node10@1.0.9': {} - /@tsconfig/node12@1.0.11: - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - dev: true + '@tsconfig/node12@1.0.11': {} - /@tsconfig/node14@1.0.3: - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - dev: true + '@tsconfig/node14@1.0.3': {} - /@tsconfig/node16@1.0.4: - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - dev: true + '@tsconfig/node16@1.0.4': {} - /@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2)(typescript@5.4.2): - resolution: {integrity: sha512-TrxBsyb4ryhaY9keP6RzhFCviWYApcLCIRMPyWaKp2cZZrfaM3QBoxXTnw/eO4+DAY3l+8O0brNW0WgeQeOiDA==} - peerDependencies: - ethers: 6.x - typechain: ^8.3.1 - typescript: '>=4.7.0' + '@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2)': dependencies: ethers: 6.11.1 lodash: 4.17.21 ts-essentials: 7.0.3(typescript@5.4.2) typechain: 8.3.2(typescript@5.4.2) typescript: 5.4.2 - dev: true - /@typechain/hardhat@8.0.3(@typechain/ethers-v6@0.4.3)(ethers@6.11.1)(hardhat@2.21.0)(typechain@8.3.2): - resolution: {integrity: sha512-MytSmJJn+gs7Mqrpt/gWkTCOpOQ6ZDfRrRT2gtZL0rfGe4QrU4x9ZdW15fFbVM/XTa+5EsKiOMYXhRABibNeng==} - peerDependencies: - '@typechain/ethers-v6': ^0.4.3 - ethers: ^6.1.0 - hardhat: ^2.9.9 - typechain: ^8.3.1 + '@typechain/hardhat@8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2))': dependencies: - '@typechain/ethers-v6': 0.4.3(ethers@6.11.1)(typechain@8.3.2)(typescript@5.4.2) + '@typechain/ethers-v6': 0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2) ethers: 6.11.1 fs-extra: 9.1.0 - hardhat: 2.21.0(ts-node@10.9.2)(typescript@5.4.2) + hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) typechain: 8.3.2(typescript@5.4.2) - dev: true - /@types/bn.js@4.11.6: - resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} + '@types/bn.js@4.11.6': dependencies: '@types/node': 18.19.23 - dev: true - /@types/bn.js@5.1.5: - resolution: {integrity: sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==} + '@types/bn.js@5.1.5': dependencies: '@types/node': 18.19.23 - dev: true - /@types/chai-as-promised@7.1.8: - resolution: {integrity: sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==} + '@types/chai-as-promised@7.1.8': dependencies: '@types/chai': 4.3.12 - dev: true - /@types/chai@4.3.12: - resolution: {integrity: sha512-zNKDHG/1yxm8Il6uCCVsm+dRdEsJlFoDu73X17y09bId6UwoYww+vFBsAcRzl8knM1sab3Dp1VRikFQwDOtDDw==} - dev: true + '@types/chai@4.3.12': {} - /@types/concat-stream@1.6.1: - resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==} + '@types/concat-stream@1.6.1': dependencies: '@types/node': 18.19.23 - dev: true - /@types/form-data@0.0.33: - resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==} + '@types/form-data@0.0.33': dependencies: '@types/node': 18.19.23 - dev: true - /@types/fs-extra@9.0.13: - resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + '@types/fs-extra@9.0.13': dependencies: '@types/node': 18.19.23 - dev: true - /@types/glob@7.2.0: - resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} + '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 '@types/node': 18.19.23 - dev: true - /@types/json-schema@7.0.15: - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - dev: true + '@types/json-schema@7.0.15': {} - /@types/lru-cache@5.1.1: - resolution: {integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==} - dev: true + '@types/keccak@3.0.5': + dependencies: + '@types/node': 18.19.23 - /@types/minimatch@5.1.2: - resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - dev: true + '@types/lru-cache@5.1.1': {} - /@types/mkdirp@0.5.2: - resolution: {integrity: sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==} + '@types/minimatch@5.1.2': {} + + '@types/mkdirp@0.5.2': dependencies: '@types/node': 18.19.23 - dev: true - /@types/mocha@10.0.6: - resolution: {integrity: sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==} - dev: true + '@types/mocha@10.0.6': {} - /@types/node@10.17.60: - resolution: {integrity: sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==} - dev: true + '@types/node@10.17.60': {} - /@types/node@18.15.13: - resolution: {integrity: sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==} - dev: true + '@types/node@18.15.13': {} - /@types/node@18.19.23: - resolution: {integrity: sha512-wtE3d0OUfNKtZYAqZb8HAWGxxXsImJcPUAgZNw+dWFxO6s5tIwIjyKnY76tsTatsNCLJPkVYwUpq15D38ng9Aw==} + '@types/node@18.19.23': dependencies: undici-types: 5.26.5 - dev: true - /@types/node@8.10.66: - resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} - dev: true + '@types/node@8.10.66': {} - /@types/pbkdf2@3.1.2: - resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} + '@types/pbkdf2@3.1.2': dependencies: '@types/node': 18.19.23 - dev: true - /@types/prettier@2.7.3: - resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} - dev: true + '@types/prettier@2.7.3': {} - /@types/qs@6.9.12: - resolution: {integrity: sha512-bZcOkJ6uWrL0Qb2NAWKa7TBU+mJHPzhx9jjLL1KHF+XpzEcR7EXHvjbHlGtR/IsP1vyPrehuS6XqkmaePy//mg==} - dev: true + '@types/qs@6.9.12': {} - /@types/resolve@0.0.8: - resolution: {integrity: sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==} + '@types/resolve@0.0.8': dependencies: '@types/node': 18.19.23 - dev: true - /@types/secp256k1@4.0.6: - resolution: {integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==} + '@types/secp256k1@4.0.6': dependencies: '@types/node': 18.19.23 - dev: true - /@types/semver@7.5.8: - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - dev: true + '@types/semver@7.5.8': {} - /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - '@typescript-eslint/parser': ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.2))(eslint@8.57.0)(typescript@5.4.2)': dependencies: '@eslint-community/regexpp': 4.10.0 '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@5.4.2) @@ -1441,72 +3907,43 @@ packages: natural-compare-lite: 1.4.0 semver: 7.6.0 tsutils: 3.21.0(typescript@5.4.2) + optionalDependencies: typescript: 5.4.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.2)': dependencies: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.2) debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 + optionalDependencies: typescript: 5.4.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/scope-manager@5.62.0: - resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/scope-manager@5.62.0': dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - dev: true - /@typescript-eslint/type-utils@5.62.0(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: '*' - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/type-utils@5.62.0(eslint@8.57.0)(typescript@5.4.2)': dependencies: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.4.2) '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@5.4.2) debug: 4.3.4(supports-color@8.1.1) eslint: 8.57.0 tsutils: 3.21.0(typescript@5.4.2) + optionalDependencies: typescript: 5.4.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/types@5.62.0: - resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true + '@typescript-eslint/types@5.62.0': {} - /@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.2): - resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/typescript-estree@5.62.0(typescript@5.4.2)': dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 @@ -1515,16 +3952,12 @@ packages: is-glob: 4.0.3 semver: 7.6.0 tsutils: 3.21.0(typescript@5.4.2) + optionalDependencies: typescript: 5.4.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@5.4.2)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.15 @@ -1538,223 +3971,123 @@ packages: transitivePeerDependencies: - supports-color - typescript - dev: true - /@typescript-eslint/visitor-keys@5.62.0: - resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/visitor-keys@5.62.0': dependencies: '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 - dev: true - /@ungap/structured-clone@1.2.0: - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - dev: true + '@ungap/structured-clone@1.2.0': {} - /abbrev@1.0.9: - resolution: {integrity: sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==} - dev: true + abbrev@1.0.9: {} - /acorn-jsx@5.3.2(acorn@8.11.3): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-jsx@5.3.2(acorn@8.11.3): dependencies: acorn: 8.11.3 - dev: true - /acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} - engines: {node: '>=0.4.0'} - dev: true + acorn-walk@8.3.2: {} - /acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true + acorn@8.11.3: {} - /address@1.2.2: - resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} - engines: {node: '>= 10.0.0'} - dev: true + address@1.2.2: {} - /adm-zip@0.4.16: - resolution: {integrity: sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==} - engines: {node: '>=0.3.0'} - dev: true + adm-zip@0.4.16: {} - /aes-js@3.0.0: - resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==} - dev: true + aes-js@3.0.0: {} - /aes-js@4.0.0-beta.5: - resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} - dev: true + aes-js@4.0.0-beta.5: {} - /agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} + agent-base@6.0.2: dependencies: debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color - dev: true - /aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} + aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 indent-string: 4.0.0 - dev: true - /ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - dev: true - /ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + ajv@8.12.0: dependencies: fast-deep-equal: 3.1.3 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 uri-js: 4.4.1 - dev: true - /amdefine@1.0.1: - resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} - engines: {node: '>=0.4.2'} - requiresBuild: true - dev: true + amdefine@1.0.1: optional: true - /ansi-align@3.0.1: - resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + ansi-align@3.0.1: dependencies: string-width: 4.2.3 - dev: true - /ansi-colors@4.1.1: - resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} - engines: {node: '>=6'} - dev: true + ansi-colors@4.1.1: {} - /ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - dev: true + ansi-colors@4.1.3: {} - /ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 - dev: true - /ansi-regex@3.0.1: - resolution: {integrity: sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==} - engines: {node: '>=4'} - dev: true + ansi-regex@3.0.1: {} - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true + ansi-regex@5.0.1: {} - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} + ansi-styles@3.2.1: dependencies: color-convert: 1.9.3 - dev: true - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - dev: true - /antlr4@4.13.1: - resolution: {integrity: sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA==} - engines: {node: '>=16'} - dev: true + antlr4@4.13.1: {} - /antlr4ts@0.5.0-alpha.4: - resolution: {integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==} - dev: true + antlr4ts@0.5.0-alpha.4: {} - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - dev: true - /arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - dev: true + arg@4.1.3: {} - /argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 - dev: true - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true + argparse@2.0.1: {} - /array-back@3.1.0: - resolution: {integrity: sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==} - engines: {node: '>=6'} - dev: true + array-back@3.1.0: {} - /array-back@4.0.2: - resolution: {integrity: sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==} - engines: {node: '>=8'} - dev: true + array-back@4.0.2: {} - /array-buffer-byte-length@1.0.1: - resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} - engines: {node: '>= 0.4'} + array-buffer-byte-length@1.0.1: dependencies: call-bind: 1.0.7 is-array-buffer: 3.0.4 - dev: true - /array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - dev: true + array-union@2.1.0: {} - /array-uniq@1.0.3: - resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} - engines: {node: '>=0.10.0'} - dev: true + array-uniq@1.0.3: {} - /array.prototype.findlast@1.2.4: - resolution: {integrity: sha512-BMtLxpV+8BD+6ZPFIWmnUBpQoy+A+ujcg4rhp2iwCRJYA7PEh2MS4NL3lz8EiDlLrJPp2hg9qWihr5pd//jcGw==} - engines: {node: '>= 0.4'} + array.prototype.findlast@1.2.4: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.5 es-errors: 1.3.0 es-shim-unscopables: 1.0.2 - dev: true - /arraybuffer.prototype.slice@1.0.3: - resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} - engines: {node: '>= 0.4'} + arraybuffer.prototype.slice@1.0.3: dependencies: array-buffer-byte-length: 1.0.1 call-bind: 1.0.7 @@ -1764,115 +4097,68 @@ packages: get-intrinsic: 1.2.4 is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 - dev: true - /asap@2.0.6: - resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - dev: true + asap@2.0.6: {} - /assertion-error@1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - dev: true + assertion-error@1.1.0: {} - /ast-parents@0.0.1: - resolution: {integrity: sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==} - dev: true + ast-parents@0.0.1: {} - /astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} - dev: true + astral-regex@2.0.0: {} - /async@1.5.2: - resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} - dev: true + async@1.5.2: {} - /asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: true + asynckit@0.4.0: {} - /at-least-node@1.0.0: - resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} - engines: {node: '>= 4.0.0'} - dev: true + at-least-node@1.0.0: {} - /available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 - dev: true - /axios@0.21.4(debug@4.3.4): - resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==} + axios@0.21.4(debug@4.3.4): dependencies: follow-redirects: 1.15.5(debug@4.3.4) transitivePeerDependencies: - debug - dev: true - /axios@1.6.7: - resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==} + axios@1.6.7: dependencies: follow-redirects: 1.15.5(debug@4.3.4) form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug - dev: true - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true + balanced-match@1.0.2: {} - /base-x@3.0.9: - resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} + base-x@3.0.9: dependencies: safe-buffer: 5.2.1 - dev: true - /bech32@1.1.4: - resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} - dev: true + base64-js@1.5.1: {} - /bigint-buffer@1.1.5: - resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} - engines: {node: '>= 10.0.0'} - requiresBuild: true + bech32@1.1.4: {} + + bigint-buffer@1.1.5: dependencies: bindings: 1.5.0 - dev: true - /binary-extensions@2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} - engines: {node: '>=8'} - dev: true + binary-extensions@2.2.0: {} - /bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + bindings@1.5.0: dependencies: file-uri-to-path: 1.0.0 - dev: true - /blakejs@1.2.1: - resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} - dev: true + blakejs@1.2.1: {} - /bn.js@4.11.6: - resolution: {integrity: sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==} - dev: true + bn.js@4.11.6: {} - /bn.js@4.12.0: - resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} - dev: true + bn.js@4.12.0: {} - /bn.js@5.2.1: - resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} - dev: true + bn.js@5.2.1: {} - /boxen@5.1.2: - resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} - engines: {node: '>=10'} + boxen@5.1.2: dependencies: ansi-align: 3.0.1 camelcase: 6.3.0 @@ -1882,38 +4168,25 @@ packages: type-fest: 0.20.2 widest-line: 3.1.0 wrap-ansi: 7.0.0 - dev: true - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - dev: true - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@2.0.1: dependencies: balanced-match: 1.0.2 - dev: true - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} + braces@3.0.2: dependencies: fill-range: 7.0.1 - dev: true - /brorand@1.1.0: - resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - dev: true + brorand@1.1.0: {} - /browser-stdout@1.3.1: - resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} - dev: true + browser-stdout@1.3.1: {} - /browserify-aes@1.2.0: - resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + browserify-aes@1.2.0: dependencies: buffer-xor: 1.0.3 cipher-base: 1.0.4 @@ -1921,79 +4194,52 @@ packages: evp_bytestokey: 1.0.3 inherits: 2.0.4 safe-buffer: 5.2.1 - dev: true - /bs58@4.0.1: - resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + bs58@4.0.1: dependencies: base-x: 3.0.9 - dev: true - /bs58check@2.1.2: - resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} + bs58check@2.1.2: dependencies: bs58: 4.0.1 create-hash: 1.2.0 safe-buffer: 5.2.1 - dev: true - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true + buffer-from@1.1.2: {} - /buffer-xor@1.0.3: - resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} - dev: true + buffer-xor@1.0.3: {} - /bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - dev: true + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 - /call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} - engines: {node: '>= 0.4'} + bytes@3.1.2: {} + + call-bind@1.0.7: dependencies: es-define-property: 1.0.0 es-errors: 1.3.0 function-bind: 1.1.2 get-intrinsic: 1.2.4 set-function-length: 1.2.2 - dev: true - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true + callsites@3.1.0: {} - /camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - dev: true + camelcase@6.3.0: {} - /caseless@0.12.0: - resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} - dev: true + caseless@0.12.0: {} - /cbor@8.1.0: - resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} - engines: {node: '>=12.19'} + cbor@8.1.0: dependencies: nofilter: 3.1.0 - dev: true - /chai-as-promised@7.1.1(chai@4.4.1): - resolution: {integrity: sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==} - peerDependencies: - chai: '>= 2.1.2 < 5' + chai-as-promised@7.1.1(chai@4.4.1): dependencies: chai: 4.4.1 check-error: 1.0.3 - dev: true - /chai@4.4.1: - resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} - engines: {node: '>=4'} + chai@4.4.1: dependencies: assertion-error: 1.1.0 check-error: 1.0.3 @@ -2002,38 +4248,25 @@ packages: loupe: 2.3.7 pathval: 1.1.1 type-detect: 4.0.8 - dev: true - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 - dev: true - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: true - /charenc@0.0.2: - resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} - dev: true + charenc@0.0.2: {} - /check-error@1.0.3: - resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + check-error@1.0.3: dependencies: get-func-name: 2.0.2 - dev: true - /chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} + chokidar@3.5.3: dependencies: anymatch: 3.1.3 braces: 3.0.2 @@ -2044,11 +4277,8 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: true - /chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 braces: 3.0.2 @@ -2059,169 +4289,102 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: true - /ci-info@2.0.0: - resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} - dev: true + ci-info@2.0.0: {} - /cipher-base@1.0.4: - resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + cipher-base@1.0.4: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 - dev: true - /clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - dev: true + clean-stack@2.2.0: {} - /cli-boxes@2.2.1: - resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} - engines: {node: '>=6'} - dev: true + cli-boxes@2.2.1: {} - /cli-table3@0.5.1: - resolution: {integrity: sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==} - engines: {node: '>=6'} + cli-table3@0.5.1: dependencies: object-assign: 4.1.1 string-width: 2.1.1 optionalDependencies: colors: 1.4.0 - dev: true - /cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + cliui@7.0.4: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - dev: true - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + color-convert@1.9.3: dependencies: color-name: 1.1.3 - dev: true - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + color-convert@2.0.1: dependencies: color-name: 1.1.4 - dev: true - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true + color-name@1.1.3: {} - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true + color-name@1.1.4: {} - /colors@1.4.0: - resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} - engines: {node: '>=0.1.90'} - dev: true + colors@1.4.0: {} - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 - dev: true - /command-exists@1.2.9: - resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==} - dev: true + command-exists@1.2.9: {} - /command-line-args@5.2.1: - resolution: {integrity: sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==} - engines: {node: '>=4.0.0'} + command-line-args@5.2.1: dependencies: array-back: 3.1.0 find-replace: 3.0.0 lodash.camelcase: 4.3.0 typical: 4.0.0 - dev: true - /command-line-usage@6.1.3: - resolution: {integrity: sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==} - engines: {node: '>=8.0.0'} + command-line-usage@6.1.3: dependencies: array-back: 4.0.2 chalk: 2.4.2 table-layout: 1.0.2 typical: 5.2.0 - dev: true - /commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - engines: {node: '>=14'} - dev: true + commander@10.0.1: {} - /commander@11.1.0: - resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} - engines: {node: '>=16'} - dev: true + commander@11.1.0: {} - /commander@3.0.2: - resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} - dev: true + commander@3.0.2: {} - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true + concat-map@0.0.1: {} - /concat-stream@1.6.2: - resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} - engines: {'0': node >= 0.8} + concat-stream@1.6.2: dependencies: buffer-from: 1.1.2 inherits: 2.0.4 readable-stream: 2.3.8 typedarray: 0.0.6 - dev: true - /cookie@0.4.2: - resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} - engines: {node: '>= 0.6'} - dev: true + cookie@0.4.2: {} - /core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - dev: true + core-util-is@1.0.3: {} - /cosmiconfig@8.3.6(typescript@5.4.2): - resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} - engines: {node: '>=14'} - peerDependencies: - typescript: '>=4.9.5' - peerDependenciesMeta: - typescript: - optional: true + cosmiconfig@8.3.6(typescript@5.4.2): dependencies: import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 + optionalDependencies: typescript: 5.4.2 - dev: true - /create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + create-hash@1.2.0: dependencies: cipher-base: 1.0.4 inherits: 2.0.4 md5.js: 1.3.5 ripemd160: 2.0.2 sha.js: 2.4.11 - dev: true - /create-hmac@1.1.7: - resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + create-hmac@1.1.7: dependencies: cipher-base: 1.0.4 create-hash: 1.2.0 @@ -2229,150 +4392,81 @@ packages: ripemd160: 2.0.2 safe-buffer: 5.2.1 sha.js: 2.4.11 - dev: true - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - dev: true + create-require@1.1.1: {} - /cross-env@7.0.3: - resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} - engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} - hasBin: true + cross-env@7.0.3: dependencies: cross-spawn: 7.0.3 - dev: true - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: true - - /crypt@0.0.2: - resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} - dev: true - /crypto-js@4.2.0: - resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} - dev: true + crypt@0.0.2: {} - /death@1.1.0: - resolution: {integrity: sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==} - dev: true + death@1.1.0: {} - /debug@4.3.4(supports-color@8.1.1): - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + debug@4.3.4(supports-color@8.1.1): dependencies: ms: 2.1.2 + optionalDependencies: supports-color: 8.1.1 - dev: true - /decamelize@4.0.0: - resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} - engines: {node: '>=10'} - dev: true + decamelize@4.0.0: {} - /deep-eql@4.1.3: - resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} - engines: {node: '>=6'} + deep-eql@4.1.3: dependencies: type-detect: 4.0.8 - dev: true - /deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - dev: true + deep-extend@0.6.0: {} - /deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true + deep-is@0.1.4: {} - /define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} + define-data-property@1.1.4: dependencies: es-define-property: 1.0.0 es-errors: 1.3.0 gopd: 1.0.1 - dev: true - /define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 has-property-descriptors: 1.0.2 object-keys: 1.1.1 - dev: true - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - dev: true + delayed-stream@1.0.0: {} - /depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - dev: true + depd@2.0.0: {} - /detect-port@1.5.1: - resolution: {integrity: sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==} - hasBin: true + detect-port@1.5.1: dependencies: address: 1.2.2 debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color - dev: true - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - dev: true + diff@4.0.2: {} - /diff@5.0.0: - resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} - engines: {node: '>=0.3.1'} - dev: true + diff@5.0.0: {} - /difflib@0.2.4: - resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==} + difflib@0.2.4: dependencies: heap: 0.2.7 - dev: true - /dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 - dev: true - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} + doctrine@3.0.0: dependencies: esutils: 2.0.3 - dev: true - /dotenv@16.4.5: - resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} - engines: {node: '>=12'} - dev: true + dotenv@16.4.5: {} - /elliptic@6.5.4: - resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} + elliptic@6.5.4: dependencies: bn.js: 4.12.0 brorand: 1.1.0 @@ -2381,10 +4475,8 @@ packages: inherits: 2.0.4 minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - dev: true - /elliptic@6.5.5: - resolution: {integrity: sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==} + elliptic@6.5.5: dependencies: bn.js: 4.12.0 brorand: 1.1.0 @@ -2393,38 +4485,23 @@ packages: inherits: 2.0.4 minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - dev: true - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true + emoji-regex@8.0.0: {} - /encode-utf8@1.0.3: - resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} - dev: true + encode-utf8@1.0.3: {} - /enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} + enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 strip-ansi: 6.0.1 - dev: true - /env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} - dev: true + env-paths@2.2.1: {} - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 - dev: true - /es-abstract@1.22.5: - resolution: {integrity: sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==} - engines: {node: '>= 0.4'} + es-abstract@1.22.5: dependencies: array-buffer-byte-length: 1.0.1 arraybuffer.prototype.slice: 1.0.3 @@ -2467,63 +4544,36 @@ packages: typed-array-length: 1.0.5 unbox-primitive: 1.0.2 which-typed-array: 1.1.15 - dev: true - /es-define-property@1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} - engines: {node: '>= 0.4'} + es-define-property@1.0.0: dependencies: get-intrinsic: 1.2.4 - dev: true - /es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - dev: true + es-errors@1.3.0: {} - /es-set-tostringtag@2.0.3: - resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} - engines: {node: '>= 0.4'} + es-set-tostringtag@2.0.3: dependencies: get-intrinsic: 1.2.4 has-tostringtag: 1.0.2 hasown: 2.0.2 - dev: true - /es-shim-unscopables@1.0.2: - resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + es-shim-unscopables@1.0.2: dependencies: hasown: 2.0.2 - dev: true - /es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} + es-to-primitive@1.2.1: dependencies: is-callable: 1.2.7 is-date-object: 1.0.5 is-symbol: 1.0.4 - dev: true - /escalade@3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} - engines: {node: '>=6'} - dev: true + escalade@3.1.2: {} - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - dev: true + escape-string-regexp@1.0.5: {} - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true + escape-string-regexp@4.0.0: {} - /escodegen@1.8.1: - resolution: {integrity: sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==} - engines: {node: '>=0.12.0'} - hasBin: true + escodegen@1.8.1: dependencies: esprima: 2.7.3 estraverse: 1.9.3 @@ -2531,42 +4581,24 @@ packages: optionator: 0.8.3 optionalDependencies: source-map: 0.2.0 - dev: true - /eslint-config-prettier@8.10.0(eslint@8.57.0): - resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' + eslint-config-prettier@8.10.0(eslint@8.57.0): dependencies: eslint: 8.57.0 - dev: true - /eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} + eslint-scope@5.1.1: dependencies: esrecurse: 4.3.0 estraverse: 4.3.0 - dev: true - /eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@7.2.2: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 - dev: true - /eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true + eslint-visitor-keys@3.4.3: {} - /eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true + eslint@8.57.0: dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@eslint-community/regexpp': 4.10.0 @@ -2608,70 +4640,34 @@ packages: text-table: 0.2.0 transitivePeerDependencies: - supports-color - dev: true - /espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + espree@9.6.1: dependencies: acorn: 8.11.3 acorn-jsx: 5.3.2(acorn@8.11.3) eslint-visitor-keys: 3.4.3 - dev: true - /esprima@2.7.3: - resolution: {integrity: sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==} - engines: {node: '>=0.10.0'} - hasBin: true - dev: true + esprima@2.7.3: {} - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - dev: true + esprima@4.0.1: {} - /esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} - engines: {node: '>=0.10'} + esquery@1.5.0: dependencies: estraverse: 5.3.0 - dev: true - /esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 - dev: true - /estraverse@1.9.3: - resolution: {integrity: sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==} - engines: {node: '>=0.10.0'} - dev: true + estraverse@1.9.3: {} - /estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - dev: true + estraverse@4.3.0: {} - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - dev: true + estraverse@5.3.0: {} - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true + esutils@2.0.3: {} - /eth-gas-reporter@0.2.27: - resolution: {integrity: sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw==} - peerDependencies: - '@codechecks/client': ^0.1.0 - peerDependenciesMeta: - '@codechecks/client': - optional: true + eth-gas-reporter@0.2.27: dependencies: '@solidity-parser/parser': 0.14.5 axios: 1.6.7 @@ -2690,16 +4686,12 @@ packages: - bufferutil - debug - utf-8-validate - dev: true - /ethereum-bloom-filters@1.0.10: - resolution: {integrity: sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==} + ethereum-bloom-filters@1.0.10: dependencies: js-sha3: 0.8.0 - dev: true - /ethereum-cryptography@0.1.3: - resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} + ethereum-cryptography@0.1.3: dependencies: '@types/pbkdf2': 3.1.2 '@types/secp256k1': 4.0.6 @@ -2716,35 +4708,27 @@ packages: scrypt-js: 3.0.1 secp256k1: 4.0.3 setimmediate: 1.0.5 - dev: true - /ethereum-cryptography@1.2.0: - resolution: {integrity: sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==} + ethereum-cryptography@1.2.0: dependencies: '@noble/hashes': 1.2.0 '@noble/secp256k1': 1.7.1 '@scure/bip32': 1.1.5 '@scure/bip39': 1.1.1 - dev: true - /ethereum-cryptography@2.1.3: - resolution: {integrity: sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==} + ethereum-cryptography@2.1.3: dependencies: '@noble/curves': 1.3.0 '@noble/hashes': 1.3.3 '@scure/bip32': 1.3.3 '@scure/bip39': 1.2.2 - dev: true - /ethereumjs-abi@0.6.8: - resolution: {integrity: sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==} + ethereumjs-abi@0.6.8: dependencies: bn.js: 4.12.0 ethereumjs-util: 6.2.1 - dev: true - /ethereumjs-util@6.2.1: - resolution: {integrity: sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==} + ethereumjs-util@6.2.1: dependencies: '@types/bn.js': 4.11.6 bn.js: 4.12.0 @@ -2753,21 +4737,16 @@ packages: ethereum-cryptography: 0.1.3 ethjs-util: 0.1.6 rlp: 2.2.7 - dev: true - /ethereumjs-util@7.1.5: - resolution: {integrity: sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==} - engines: {node: '>=10.0.0'} + ethereumjs-util@7.1.5: dependencies: '@types/bn.js': 5.1.5 bn.js: 5.2.1 create-hash: 1.2.0 ethereum-cryptography: 0.1.3 rlp: 2.2.7 - dev: true - /ethers@5.7.2: - resolution: {integrity: sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==} + ethers@5.7.2: dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/abstract-provider': 5.7.0 @@ -2802,11 +4781,8 @@ packages: transitivePeerDependencies: - bufferutil - utf-8-validate - dev: true - /ethers@6.11.1: - resolution: {integrity: sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg==} - engines: {node: '>=14.0.0'} + ethers@6.11.1: dependencies: '@adraffy/ens-normalize': 1.10.1 '@noble/curves': 1.2.0 @@ -2818,343 +4794,212 @@ packages: transitivePeerDependencies: - bufferutil - utf-8-validate - dev: true - /ethjs-unit@0.1.6: - resolution: {integrity: sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==} - engines: {node: '>=6.5.0', npm: '>=3'} + ethjs-unit@0.1.6: dependencies: bn.js: 4.11.6 number-to-bn: 1.7.0 - dev: true - /ethjs-util@0.1.6: - resolution: {integrity: sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==} - engines: {node: '>=6.5.0', npm: '>=3'} + ethjs-util@0.1.6: dependencies: is-hex-prefixed: 1.0.0 strip-hex-prefix: 1.0.0 - dev: true - /evp_bytestokey@1.0.3: - resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + evp_bytestokey@1.0.3: dependencies: md5.js: 1.3.5 safe-buffer: 5.2.1 - dev: true - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true + fast-deep-equal@3.1.3: {} - /fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - dev: true + fast-diff@1.3.0: {} - /fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.5 - dev: true - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true + fast-json-stable-stringify@2.1.0: {} - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true + fast-levenshtein@2.0.6: {} - /fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fastq@1.17.1: dependencies: reusify: 1.0.4 - dev: true - /fhevm@0.4.0(hardhat@2.21.0): - resolution: {integrity: sha512-UuOYMgAodOoGX69G6EXzb7QRes80KeUzDOhRNEqXh7l4npC/0JZXVNoqKwSRe0hGQJE6Qwx+FforPhs5rPzXtg==} + fhevm@0.5.9: dependencies: '@openzeppelin/contracts': 5.0.2 - hardhat-preprocessor: 0.1.5(hardhat@2.21.0) - transitivePeerDependencies: - - hardhat - dev: true - /fhevmjs@0.4.0-7: - resolution: {integrity: sha512-3SiLl9J8HmvVwP4hfAsvpbWb9DlgxOB+zQJzKV8adO8sLcxlO0pWINKqsdL6wnuPqYt2v4WQa+bViLC2NeSi9A==} - hasBin: true + fhevmjs@0.5.7: dependencies: + '@types/keccak': 3.0.5 bigint-buffer: 1.1.5 commander: 11.1.0 - crypto-js: 4.2.0 - ethers: 6.11.1 - libsodium: 0.7.13 - libsodium-wrappers: 0.7.13 - node-tfhe: 0.5.3 - tfhe: 0.5.3 + node-fetch: 2.7.0 + node-tfhe: 0.6.4 + sha3: 2.1.4 + tfhe: 0.6.4 + url: 0.11.4 + web3-validator: 2.0.6 transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: true + - encoding - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 - dev: true - /file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - dev: true + file-uri-to-path@1.0.0: {} - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} + fill-range@7.0.1: dependencies: to-regex-range: 5.0.1 - dev: true - /find-replace@3.0.0: - resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==} - engines: {node: '>=4.0.0'} + find-replace@3.0.0: dependencies: array-back: 3.1.0 - dev: true - /find-up@2.1.0: - resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} - engines: {node: '>=4'} + find-up@2.1.0: dependencies: locate-path: 2.0.0 - dev: true - /find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} + find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - dev: true - /flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@3.2.0: dependencies: flatted: 3.3.1 keyv: 4.5.4 rimraf: 3.0.2 - dev: true - /flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - dev: true + flat@5.0.2: {} - /flatted@3.3.1: - resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - dev: true + flatted@3.3.1: {} - /fmix@0.1.0: - resolution: {integrity: sha512-Y6hyofImk9JdzU8k5INtTXX1cu8LDlePWDFU5sftm9H+zKCr5SGrVjdhkvsim646cw5zD0nADj8oHyXMZmCZ9w==} + fmix@0.1.0: dependencies: imul: 1.0.1 - dev: true - /follow-redirects@1.15.5(debug@4.3.4): - resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - dependencies: + follow-redirects@1.15.5(debug@4.3.4): + optionalDependencies: debug: 4.3.4(supports-color@8.1.1) - dev: true - /for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + for-each@0.3.3: dependencies: is-callable: 1.2.7 - dev: true - /form-data@2.5.1: - resolution: {integrity: sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==} - engines: {node: '>= 0.12'} + form-data@2.5.1: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 - dev: true - /form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} + form-data@4.0.0: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 - dev: true - /fp-ts@1.19.3: - resolution: {integrity: sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==} - dev: true + fp-ts@1.19.3: {} - /fs-extra@0.30.0: - resolution: {integrity: sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==} + fs-extra@0.30.0: dependencies: graceful-fs: 4.2.11 jsonfile: 2.4.0 klaw: 1.3.1 path-is-absolute: 1.0.1 rimraf: 2.7.1 - dev: true - /fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} + fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.1 - dev: true - /fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} + fs-extra@7.0.1: dependencies: graceful-fs: 4.2.11 jsonfile: 4.0.0 universalify: 0.1.2 - dev: true - /fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} + fs-extra@8.1.0: dependencies: graceful-fs: 4.2.11 jsonfile: 4.0.0 universalify: 0.1.2 - dev: true - /fs-extra@9.1.0: - resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} - engines: {node: '>=10'} + fs-extra@9.1.0: dependencies: at-least-node: 1.0.0 graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.1 - dev: true - /fs-readdir-recursive@1.1.0: - resolution: {integrity: sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==} - dev: true + fs-readdir-recursive@1.1.0: {} - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true + fs.realpath@1.0.0: {} - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true + fsevents@2.3.3: optional: true - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: true + function-bind@1.1.2: {} - /function.prototype.name@1.1.6: - resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} - engines: {node: '>= 0.4'} + function.prototype.name@1.1.6: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.5 functions-have-names: 1.2.3 - dev: true - /functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - dev: true + functions-have-names@1.2.3: {} - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: true + get-caller-file@2.0.5: {} - /get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - dev: true + get-func-name@2.0.2: {} - /get-intrinsic@1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} - engines: {node: '>= 0.4'} + get-intrinsic@1.2.4: dependencies: es-errors: 1.3.0 function-bind: 1.1.2 has-proto: 1.0.3 has-symbols: 1.0.3 hasown: 2.0.2 - dev: true - /get-port@3.2.0: - resolution: {integrity: sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==} - engines: {node: '>=4'} - dev: true + get-port@3.2.0: {} - /get-symbol-description@1.0.2: - resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} - engines: {node: '>= 0.4'} + get-symbol-description@1.0.2: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 - dev: true - /ghost-testrpc@0.0.2: - resolution: {integrity: sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==} - hasBin: true + ghost-testrpc@0.0.2: dependencies: chalk: 2.4.2 node-emoji: 1.11.0 - dev: true - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 - dev: true - /glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 - dev: true - /glob@5.0.15: - resolution: {integrity: sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==} + glob@5.0.15: dependencies: inflight: 1.0.6 inherits: 2.0.4 minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true - /glob@7.1.7: - resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} + glob@7.1.7: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -3162,10 +5007,8 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true - /glob@7.2.0: - resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + glob@7.2.0: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -3173,10 +5016,8 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + glob@7.2.3: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -3184,67 +5025,43 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true - /glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} + glob@8.1.0: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 minimatch: 5.0.1 once: 1.4.0 - dev: true - /glob@9.3.5: - resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} - engines: {node: '>=16 || 14 >=14.17'} + glob@9.3.5: dependencies: fs.realpath: 1.0.0 minimatch: 8.0.4 minipass: 4.2.8 path-scurry: 1.10.1 - dev: true - /global-modules@2.0.0: - resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} - engines: {node: '>=6'} + global-modules@2.0.0: dependencies: global-prefix: 3.0.0 - dev: true - /global-prefix@3.0.0: - resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} - engines: {node: '>=6'} + global-prefix@3.0.0: dependencies: ini: 1.3.8 kind-of: 6.0.3 which: 1.3.1 - dev: true - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - dev: true + globals@11.12.0: {} - /globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} + globals@13.24.0: dependencies: type-fest: 0.20.2 - dev: true - /globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} - engines: {node: '>= 0.4'} + globalthis@1.0.3: dependencies: define-properties: 1.2.1 - dev: true - /globby@10.0.2: - resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} - engines: {node: '>=8'} + globby@10.0.2: dependencies: '@types/glob': 7.2.0 array-union: 2.1.0 @@ -3254,11 +5071,8 @@ packages: ignore: 5.3.1 merge2: 1.4.1 slash: 3.0.0 - dev: true - /globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} + globby@11.1.0: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 @@ -3266,26 +5080,16 @@ packages: ignore: 5.3.1 merge2: 1.4.1 slash: 3.0.0 - dev: true - /gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + gopd@1.0.1: dependencies: get-intrinsic: 1.2.4 - dev: true - /graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true + graceful-fs@4.2.11: {} - /graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: true + graphemer@1.4.0: {} - /handlebars@4.7.8: - resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} - engines: {node: '>=0.4.7'} - hasBin: true + handlebars@4.7.8: dependencies: minimist: 1.2.8 neo-async: 2.6.2 @@ -3293,10 +5097,8 @@ packages: wordwrap: 1.0.0 optionalDependencies: uglify-js: 3.17.4 - dev: true - /hardhat-deploy@0.11.45: - resolution: {integrity: sha512-aC8UNaq3JcORnEUIwV945iJuvBwi65tjHVDU3v6mOcqik7WAzHVCJ7cwmkkipsHrWysrB5YvGF1q9S1vIph83w==} + hardhat-deploy@0.11.45: dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/abstract-signer': 5.7.0 @@ -3326,44 +5128,31 @@ packages: - bufferutil - supports-color - utf-8-validate - dev: true - /hardhat-gas-reporter@1.0.10(hardhat@2.21.0): - resolution: {integrity: sha512-02N4+So/fZrzJ88ci54GqwVA3Zrf0C9duuTyGt0CFRIh/CdNwbnTgkXkRfojOMLBQ+6t+lBIkgbsOtqMvNwikA==} - peerDependencies: - hardhat: ^2.0.2 + hardhat-gas-reporter@1.0.10(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): dependencies: array-uniq: 1.0.3 eth-gas-reporter: 0.2.27 - hardhat: 2.21.0(ts-node@10.9.2)(typescript@5.4.2) + hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) sha1: 1.1.1 transitivePeerDependencies: - '@codechecks/client' - bufferutil - debug - utf-8-validate - dev: true - /hardhat-preprocessor@0.1.5(hardhat@2.21.0): - resolution: {integrity: sha512-j8m44mmPxpxAAd0G8fPHRHOas/INZdzptSur0TNJvMEGcFdLDhbHHxBcqZVQ/bmiW42q4gC60AP4CXn9EF018g==} - peerDependencies: - hardhat: ^2.0.5 + hardhat-ignore-warnings@0.2.11: + dependencies: + minimatch: 5.1.6 + node-interval-tree: 2.1.2 + solidity-comments: 0.0.2 + + hardhat-preprocessor@0.1.5(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): dependencies: - hardhat: 2.21.0(ts-node@10.9.2)(typescript@5.4.2) + hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) murmur-128: 0.2.1 - dev: true - /hardhat@2.21.0(ts-node@10.9.2)(typescript@5.4.2): - resolution: {integrity: sha512-8DlJAVJDEVHaV1sh9FLuKLLgCFv9EAJ+M+8IbjSIPgoeNo3ss5L1HgGBMfnI88c7OzMEZkdcuyGoobFeK3Orqw==} - hasBin: true - peerDependencies: - ts-node: '*' - typescript: '*' - peerDependenciesMeta: - ts-node: - optional: true - typescript: - optional: true + hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2): dependencies: '@ethersproject/abi': 5.7.0 '@metamask/eth-sig-util': 4.0.1 @@ -3404,698 +5193,403 @@ packages: solc: 0.7.3(debug@4.3.4) source-map-support: 0.5.21 stacktrace-parser: 0.1.10 - ts-node: 10.9.2(@types/node@18.19.23)(typescript@5.4.2) tsort: 0.0.1 - typescript: 5.4.2 undici: 5.28.3 uuid: 8.3.2 ws: 7.5.9 + optionalDependencies: + ts-node: 10.9.2(@types/node@18.19.23)(typescript@5.4.2) + typescript: 5.4.2 transitivePeerDependencies: - bufferutil - c-kzg - supports-color - utf-8-validate - dev: true - /has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - dev: true + has-bigints@1.0.2: {} - /has-flag@1.0.0: - resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==} - engines: {node: '>=0.10.0'} - dev: true + has-flag@1.0.0: {} - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - dev: true + has-flag@3.0.0: {} - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true + has-flag@4.0.0: {} - /has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.0 - dev: true - /has-proto@1.0.3: - resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} - engines: {node: '>= 0.4'} - dev: true + has-proto@1.0.3: {} - /has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - dev: true + has-symbols@1.0.3: {} - /has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: dependencies: has-symbols: 1.0.3 - dev: true - /hash-base@3.1.0: - resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} - engines: {node: '>=4'} + hash-base@3.1.0: dependencies: inherits: 2.0.4 readable-stream: 3.6.2 safe-buffer: 5.2.1 - dev: true - /hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + hash.js@1.1.7: dependencies: inherits: 2.0.4 minimalistic-assert: 1.0.1 - dev: true - /hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} + hasown@2.0.2: dependencies: function-bind: 1.1.2 - dev: true - /he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - dev: true + he@1.2.0: {} - /heap@0.2.7: - resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} - dev: true + heap@0.2.7: {} - /hmac-drbg@1.0.1: - resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + hmac-drbg@1.0.1: dependencies: hash.js: 1.1.7 minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - dev: true - /http-basic@8.1.3: - resolution: {integrity: sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==} - engines: {node: '>=6.0.0'} + http-basic@8.1.3: dependencies: caseless: 0.12.0 concat-stream: 1.6.2 http-response-object: 3.0.2 parse-cache-control: 1.0.1 - dev: true - /http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} + http-errors@2.0.0: dependencies: depd: 2.0.0 inherits: 2.0.4 setprototypeof: 1.2.0 statuses: 2.0.1 toidentifier: 1.0.1 - dev: true - /http-response-object@3.0.2: - resolution: {integrity: sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==} + http-response-object@3.0.2: dependencies: '@types/node': 10.17.60 - dev: true - /https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} + https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color - dev: true - /iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 - dev: true - /ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} - engines: {node: '>= 4'} - dev: true + ieee754@1.2.1: {} - /immutable@4.3.5: - resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==} - dev: true + ignore@5.3.1: {} - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} + immutable@4.3.5: {} + + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - dev: true - /imul@1.0.1: - resolution: {integrity: sha512-WFAgfwPLAjU66EKt6vRdTlKj4nAgIDQzh29JonLa4Bqtl6D8JrIMvWjCnx7xEjVNmP3U0fM5o8ZObk7d0f62bA==} - engines: {node: '>=0.10.0'} - dev: true + imul@1.0.1: {} - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true + imurmurhash@0.1.4: {} - /indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - dev: true + indent-string@4.0.0: {} - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + inflight@1.0.6: dependencies: once: 1.4.0 wrappy: 1.0.2 - dev: true - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true + inherits@2.0.4: {} - /ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - dev: true + ini@1.3.8: {} - /internal-slot@1.0.7: - resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} - engines: {node: '>= 0.4'} + internal-slot@1.0.7: dependencies: es-errors: 1.3.0 hasown: 2.0.2 side-channel: 1.0.6 - dev: true - /interpret@1.4.0: - resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} - engines: {node: '>= 0.10'} - dev: true + interpret@1.4.0: {} - /io-ts@1.10.4: - resolution: {integrity: sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==} + io-ts@1.10.4: dependencies: fp-ts: 1.19.3 - dev: true - /is-array-buffer@3.0.4: - resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} - engines: {node: '>= 0.4'} + is-arguments@1.1.1: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-array-buffer@3.0.4: dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 - dev: true - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: true + is-arrayish@0.2.1: {} - /is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + is-bigint@1.0.4: dependencies: has-bigints: 1.0.2 - dev: true - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} + is-binary-path@2.1.0: dependencies: binary-extensions: 2.2.0 - dev: true - /is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} + is-boolean-object@1.1.2: dependencies: call-bind: 1.0.7 has-tostringtag: 1.0.2 - dev: true - /is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - dev: true + is-callable@1.2.7: {} - /is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + is-core-module@2.13.1: dependencies: hasown: 2.0.2 - dev: true - /is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} + is-date-object@1.0.5: dependencies: has-tostringtag: 1.0.2 - dev: true - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true + is-extglob@2.1.1: {} - /is-fullwidth-code-point@2.0.0: - resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} - engines: {node: '>=4'} - dev: true + is-fullwidth-code-point@2.0.0: {} - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true + is-fullwidth-code-point@3.0.0: {} - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + is-generator-function@1.0.10: + dependencies: + has-tostringtag: 1.0.2 + + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - dev: true - /is-hex-prefixed@1.0.0: - resolution: {integrity: sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==} - engines: {node: '>=6.5.0', npm: '>=3'} - dev: true + is-hex-prefixed@1.0.0: {} - /is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} - dev: true + is-negative-zero@2.0.3: {} - /is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} + is-number-object@1.0.7: dependencies: has-tostringtag: 1.0.2 - dev: true - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true + is-number@7.0.0: {} - /is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - dev: true + is-path-inside@3.0.3: {} - /is-plain-obj@2.1.0: - resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} - engines: {node: '>=8'} - dev: true + is-plain-obj@2.1.0: {} - /is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} - engines: {node: '>= 0.4'} + is-regex@1.1.4: dependencies: call-bind: 1.0.7 has-tostringtag: 1.0.2 - dev: true - /is-shared-array-buffer@1.0.3: - resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} - engines: {node: '>= 0.4'} + is-shared-array-buffer@1.0.3: dependencies: call-bind: 1.0.7 - dev: true - /is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} + is-string@1.0.7: dependencies: has-tostringtag: 1.0.2 - dev: true - /is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} - engines: {node: '>= 0.4'} + is-symbol@1.0.4: dependencies: has-symbols: 1.0.3 - dev: true - /is-typed-array@1.1.13: - resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} - engines: {node: '>= 0.4'} + is-typed-array@1.1.13: dependencies: which-typed-array: 1.1.15 - dev: true - /is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - dev: true + is-unicode-supported@0.1.0: {} - /is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + is-weakref@1.0.2: dependencies: call-bind: 1.0.7 - dev: true - /isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - dev: true + isarray@1.0.0: {} - /isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - dev: true + isarray@2.0.5: {} - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true + isexe@2.0.0: {} - /javascript-natural-sort@0.7.1: - resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} - dev: true + javascript-natural-sort@0.7.1: {} - /js-sha3@0.8.0: - resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} - dev: true + js-sha3@0.8.0: {} - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true + js-tokens@4.0.0: {} - /js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true + js-yaml@3.14.1: dependencies: argparse: 1.0.10 esprima: 4.0.1 - dev: true - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true + js-yaml@4.1.0: dependencies: argparse: 2.0.1 - dev: true - /jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true - dev: true + jsesc@2.5.2: {} - /json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - dev: true + json-buffer@3.0.1: {} - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: true + json-parse-even-better-errors@2.3.1: {} - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true + json-schema-traverse@0.4.1: {} - /json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - dev: true + json-schema-traverse@1.0.0: {} - /json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true + json-stable-stringify-without-jsonify@1.0.1: {} - /jsonfile@2.4.0: - resolution: {integrity: sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==} + jsonfile@2.4.0: optionalDependencies: graceful-fs: 4.2.11 - dev: true - /jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 - dev: true - /jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + jsonfile@6.1.0: dependencies: universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 - dev: true - /jsonschema@1.4.1: - resolution: {integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==} - dev: true + jsonschema@1.4.1: {} - /keccak@3.0.4: - resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} - engines: {node: '>=10.0.0'} - requiresBuild: true + keccak@3.0.4: dependencies: node-addon-api: 2.0.2 node-gyp-build: 4.8.0 readable-stream: 3.6.2 - dev: true - /keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 - dev: true - /kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - dev: true + kind-of@6.0.3: {} - /klaw@1.3.1: - resolution: {integrity: sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==} + klaw@1.3.1: optionalDependencies: graceful-fs: 4.2.11 - dev: true - /levn@0.3.0: - resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} - engines: {node: '>= 0.8.0'} + levn@0.3.0: dependencies: prelude-ls: 1.1.2 type-check: 0.3.2 - dev: true - /levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 - dev: true - - /libsodium-wrappers@0.7.13: - resolution: {integrity: sha512-kasvDsEi/r1fMzKouIDv7B8I6vNmknXwGiYodErGuESoFTohGSKZplFtVxZqHaoQ217AynyIFgnOVRitpHs0Qw==} - dependencies: - libsodium: 0.7.13 - dev: true - - /libsodium@0.7.13: - resolution: {integrity: sha512-mK8ju0fnrKXXfleL53vtp9xiPq5hKM0zbDQtcxQIsSmxNgSxqCj6R7Hl9PkrNe2j29T4yoDaF7DJLK9/i5iWUw==} - dev: true - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: true + lines-and-columns@1.2.4: {} - /locate-path@2.0.0: - resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} - engines: {node: '>=4'} + locate-path@2.0.0: dependencies: p-locate: 2.0.0 path-exists: 3.0.0 - dev: true - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} + locate-path@6.0.0: dependencies: p-locate: 5.0.0 - dev: true - /lodash.camelcase@4.3.0: - resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} - dev: true + lodash.camelcase@4.3.0: {} - /lodash.clonedeep@4.5.0: - resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} - dev: true + lodash.clonedeep@4.5.0: {} - /lodash.isequal@4.5.0: - resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} - dev: true + lodash.isequal@4.5.0: {} - /lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true + lodash.merge@4.6.2: {} - /lodash.truncate@4.4.2: - resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} - dev: true + lodash.truncate@4.4.2: {} - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: true + lodash@4.17.21: {} - /log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} + log-symbols@4.1.0: dependencies: chalk: 4.1.2 is-unicode-supported: 0.1.0 - dev: true - /loupe@2.3.7: - resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + loupe@2.3.7: dependencies: get-func-name: 2.0.2 - dev: true - /lru-cache@10.2.0: - resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} - engines: {node: 14 || >=16.14} - dev: true + lru-cache@10.2.0: {} - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} + lru-cache@6.0.0: dependencies: yallist: 4.0.0 - dev: true - /lru_map@0.3.3: - resolution: {integrity: sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==} - dev: true + lru_map@0.3.3: {} - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true + make-error@1.3.6: {} - /markdown-table@1.1.3: - resolution: {integrity: sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==} - dev: true + markdown-table@1.1.3: {} - /match-all@1.2.6: - resolution: {integrity: sha512-0EESkXiTkWzrQQntBu2uzKvLu6vVkUGz40nGPbSZuegcfE5UuSzNjLaIu76zJWuaT/2I3Z/8M06OlUOZLGwLlQ==} - dev: true + match-all@1.2.6: {} - /md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + md5.js@1.3.5: dependencies: hash-base: 3.1.0 inherits: 2.0.4 safe-buffer: 5.2.1 - dev: true - /memorystream@0.3.1: - resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} - engines: {node: '>= 0.10.0'} - dev: true + memorystream@0.3.1: {} - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true + merge2@1.4.1: {} - /micro-ftch@0.3.1: - resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} - dev: true + micro-ftch@0.3.1: {} - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} + micromatch@4.0.5: dependencies: braces: 3.0.2 picomatch: 2.3.1 - dev: true - /mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - dev: true + mime-db@1.52.0: {} - /mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 - dev: true - /minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - dev: true + minimalistic-assert@1.0.1: {} - /minimalistic-crypto-utils@1.0.1: - resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - dev: true + minimalistic-crypto-utils@1.0.1: {} - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 - dev: true - /minimatch@5.0.1: - resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} - engines: {node: '>=10'} + minimatch@5.0.1: dependencies: brace-expansion: 2.0.1 - dev: true - /minimatch@8.0.4: - resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==} - engines: {node: '>=16 || 14 >=14.17'} + minimatch@5.1.6: dependencies: brace-expansion: 2.0.1 - dev: true - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true + minimatch@8.0.4: + dependencies: + brace-expansion: 2.0.1 - /minipass@4.2.8: - resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} - engines: {node: '>=8'} - dev: true + minimist@1.2.8: {} - /minipass@7.0.4: - resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} - engines: {node: '>=16 || 14 >=14.17'} - dev: true + minipass@4.2.8: {} - /mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true + minipass@7.0.4: {} + + mkdirp@0.5.6: dependencies: minimist: 1.2.8 - dev: true - /mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - dev: true + mkdirp@1.0.4: {} - /mnemonist@0.38.5: - resolution: {integrity: sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==} + mnemonist@0.38.5: dependencies: obliterator: 2.0.4 - dev: true - /mocha@10.3.0: - resolution: {integrity: sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==} - engines: {node: '>= 14.0.0'} - hasBin: true + mocha@10.3.0: dependencies: ansi-colors: 4.1.1 browser-stdout: 1.3.1 @@ -4117,117 +5611,74 @@ packages: yargs: 16.2.0 yargs-parser: 20.2.4 yargs-unparser: 2.0.0 - dev: true - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true + ms@2.1.2: {} - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true + ms@2.1.3: {} - /murmur-128@0.2.1: - resolution: {integrity: sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg==} + murmur-128@0.2.1: dependencies: encode-utf8: 1.0.3 fmix: 0.1.0 imul: 1.0.1 - dev: true - /natural-compare-lite@1.4.0: - resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} - dev: true + natural-compare-lite@1.4.0: {} - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true + natural-compare@1.4.0: {} - /neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - dev: true + neo-async@2.6.2: {} - /node-addon-api@2.0.2: - resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} - dev: true + node-addon-api@2.0.2: {} - /node-emoji@1.11.0: - resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + node-emoji@1.11.0: dependencies: lodash: 4.17.21 - dev: true - /node-gyp-build@4.8.0: - resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==} - hasBin: true - dev: true + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 - /node-tfhe@0.5.3: - resolution: {integrity: sha512-72HFj9Lj9hC5PWaW5TH306uPAUUL6We2lAXLW6ibxwsLcSUgEL7NEVGz5MqAYa5PcwpVEvzLDZSHCFRz8glqaQ==} - dev: true + node-gyp-build@4.8.0: {} - /nofilter@3.1.0: - resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} - engines: {node: '>=12.19'} - dev: true + node-interval-tree@2.1.2: + dependencies: + shallowequal: 1.1.0 - /nopt@3.0.6: - resolution: {integrity: sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==} - hasBin: true + node-tfhe@0.6.4: {} + + nofilter@3.1.0: {} + + nopt@3.0.6: dependencies: abbrev: 1.0.9 - dev: true - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true + normalize-path@3.0.0: {} - /number-to-bn@1.7.0: - resolution: {integrity: sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==} - engines: {node: '>=6.5.0', npm: '>=3'} + number-to-bn@1.7.0: dependencies: bn.js: 4.11.6 strip-hex-prefix: 1.0.0 - dev: true - /object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - dev: true + object-assign@4.1.1: {} - /object-inspect@1.13.1: - resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} - dev: true + object-inspect@1.13.1: {} - /object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - dev: true + object-keys@1.1.1: {} - /object.assign@4.1.5: - resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} - engines: {node: '>= 0.4'} + object.assign@4.1.5: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 has-symbols: 1.0.3 object-keys: 1.1.1 - dev: true - /obliterator@2.0.4: - resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} - dev: true + obliterator@2.0.4: {} - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + once@1.4.0: dependencies: wrappy: 1.0.2 - dev: true - /optionator@0.8.3: - resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} - engines: {node: '>= 0.8.0'} + optionator@0.8.3: dependencies: deep-is: 0.1.4 fast-levenshtein: 2.0.6 @@ -4235,11 +5686,8 @@ packages: prelude-ls: 1.1.2 type-check: 0.3.2 word-wrap: 1.2.5 - dev: true - /optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} - engines: {node: '>= 0.8.0'} + optionator@0.9.3: dependencies: '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 @@ -4247,233 +5695,132 @@ packages: levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 - dev: true - /ordinal@1.0.3: - resolution: {integrity: sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ==} - dev: true + ordinal@1.0.3: {} - /os-tmpdir@1.0.2: - resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} - engines: {node: '>=0.10.0'} - dev: true + os-tmpdir@1.0.2: {} - /p-limit@1.3.0: - resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} - engines: {node: '>=4'} + p-limit@1.3.0: dependencies: p-try: 1.0.0 - dev: true - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - dev: true - /p-locate@2.0.0: - resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} - engines: {node: '>=4'} + p-locate@2.0.0: dependencies: p-limit: 1.3.0 - dev: true - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} + p-locate@5.0.0: dependencies: p-limit: 3.1.0 - dev: true - /p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} + p-map@4.0.0: dependencies: aggregate-error: 3.1.0 - dev: true - /p-try@1.0.0: - resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} - engines: {node: '>=4'} - dev: true + p-try@1.0.0: {} - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} + parent-module@1.0.1: dependencies: callsites: 3.1.0 - dev: true - /parse-cache-control@1.0.1: - resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} - dev: true + parse-cache-control@1.0.1: {} - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.23.5 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - dev: true - /path-exists@3.0.0: - resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} - engines: {node: '>=4'} - dev: true + path-exists@3.0.0: {} - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true + path-exists@4.0.0: {} - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true + path-is-absolute@1.0.1: {} - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true + path-key@3.1.1: {} - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true + path-parse@1.0.7: {} - /path-scurry@1.10.1: - resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} - engines: {node: '>=16 || 14 >=14.17'} + path-scurry@1.10.1: dependencies: lru-cache: 10.2.0 minipass: 7.0.4 - dev: true - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: true + path-type@4.0.0: {} - /pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - dev: true + pathval@1.1.1: {} - /pbkdf2@3.1.2: - resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} - engines: {node: '>=0.12'} + pbkdf2@3.1.2: dependencies: create-hash: 1.2.0 create-hmac: 1.1.7 ripemd160: 2.0.2 safe-buffer: 5.2.1 sha.js: 2.4.11 - dev: true - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true + picomatch@2.3.1: {} - /pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} - dev: true + pify@4.0.1: {} - /pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - dev: true + pluralize@8.0.0: {} - /possible-typed-array-names@1.0.0: - resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} - engines: {node: '>= 0.4'} - dev: true + possible-typed-array-names@1.0.0: {} - /prelude-ls@1.1.2: - resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} - engines: {node: '>= 0.8.0'} - dev: true + prelude-ls@1.1.2: {} - /prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - dev: true + prelude-ls@1.2.1: {} - /prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} - engines: {node: '>=6.0.0'} + prettier-linter-helpers@1.0.0: dependencies: fast-diff: 1.3.0 - dev: true - /prettier-plugin-solidity@1.3.1(prettier@2.8.8): - resolution: {integrity: sha512-MN4OP5I2gHAzHZG1wcuJl0FsLS3c4Cc5494bbg+6oQWBPuEamjwDvmGfFMZ6NFzsh3Efd9UUxeT7ImgjNH4ozA==} - engines: {node: '>=16'} - peerDependencies: - prettier: '>=2.3.0' + prettier-plugin-solidity@1.3.1(prettier@2.8.8): dependencies: '@solidity-parser/parser': 0.17.0 prettier: 2.8.8 semver: 7.6.0 solidity-comments-extractor: 0.0.8 - dev: true - /prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} - hasBin: true - dev: true + prettier@2.8.8: {} - /process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - dev: true + process-nextick-args@2.0.1: {} - /promise@8.3.0: - resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} + promise@8.3.0: dependencies: asap: 2.0.6 - dev: true - /proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - dev: true + proxy-from-env@1.1.0: {} - /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - dev: true + punycode@1.4.1: {} - /qs@6.12.0: - resolution: {integrity: sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==} - engines: {node: '>=0.6'} + punycode@2.3.1: {} + + qs@6.12.0: dependencies: side-channel: 1.0.6 - dev: true - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true + qs@6.13.0: + dependencies: + side-channel: 1.0.6 - /randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + queue-microtask@1.2.3: {} + + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 - dev: true - /raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} + raw-body@2.5.2: dependencies: bytes: 3.1.2 http-errors: 2.0.0 iconv-lite: 0.4.24 unpipe: 1.0.0 - dev: true - /readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 inherits: 2.0.4 @@ -4482,187 +5829,109 @@ packages: safe-buffer: 5.1.2 string_decoder: 1.1.1 util-deprecate: 1.0.2 - dev: true - /readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} + readable-stream@3.6.2: dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - dev: true - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + readdirp@3.6.0: dependencies: picomatch: 2.3.1 - dev: true - /rechoir@0.6.2: - resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} - engines: {node: '>= 0.10'} + rechoir@0.6.2: dependencies: resolve: 1.22.8 - dev: true - /recursive-readdir@2.2.3: - resolution: {integrity: sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==} - engines: {node: '>=6.0.0'} + recursive-readdir@2.2.3: dependencies: minimatch: 3.1.2 - dev: true - /reduce-flatten@2.0.0: - resolution: {integrity: sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==} - engines: {node: '>=6'} - dev: true + reduce-flatten@2.0.0: {} - /regexp.prototype.flags@1.5.2: - resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} - engines: {node: '>= 0.4'} + regexp.prototype.flags@1.5.2: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-errors: 1.3.0 set-function-name: 2.0.2 - dev: true - /req-cwd@2.0.0: - resolution: {integrity: sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==} - engines: {node: '>=4'} + req-cwd@2.0.0: dependencies: req-from: 2.0.0 - dev: true - /req-from@2.0.0: - resolution: {integrity: sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==} - engines: {node: '>=4'} + req-from@2.0.0: dependencies: resolve-from: 3.0.0 - dev: true - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: true + require-directory@2.1.1: {} - /require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - dev: true + require-from-string@2.0.2: {} - /resolve-from@3.0.0: - resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==} - engines: {node: '>=4'} - dev: true + resolve-from@3.0.0: {} - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true + resolve-from@4.0.0: {} - /resolve@1.1.7: - resolution: {integrity: sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==} - dev: true + resolve@1.1.7: {} - /resolve@1.17.0: - resolution: {integrity: sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==} + resolve@1.17.0: dependencies: path-parse: 1.0.7 - dev: true - /resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true + resolve@1.22.8: dependencies: is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true + reusify@1.0.4: {} - /rimraf@2.7.1: - resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} - hasBin: true + rimraf@2.7.1: dependencies: glob: 7.2.3 - dev: true - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true + rimraf@3.0.2: dependencies: glob: 7.2.3 - dev: true - /rimraf@4.4.1: - resolution: {integrity: sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og==} - engines: {node: '>=14'} - hasBin: true + rimraf@4.4.1: dependencies: glob: 9.3.5 - dev: true - /ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + ripemd160@2.0.2: dependencies: hash-base: 3.1.0 inherits: 2.0.4 - dev: true - /rlp@2.2.7: - resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==} - hasBin: true + rlp@2.2.7: dependencies: bn.js: 5.2.1 - dev: true - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - dev: true - /safe-array-concat@1.1.2: - resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} - engines: {node: '>=0.4'} + safe-array-concat@1.1.2: dependencies: call-bind: 1.0.7 get-intrinsic: 1.2.4 has-symbols: 1.0.3 isarray: 2.0.5 - dev: true - /safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - dev: true + safe-buffer@5.1.2: {} - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - dev: true + safe-buffer@5.2.1: {} - /safe-regex-test@1.0.3: - resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} - engines: {node: '>= 0.4'} + safe-regex-test@1.0.3: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-regex: 1.1.4 - dev: true - /safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - dev: true + safer-buffer@2.1.2: {} - /sc-istanbul@0.4.6: - resolution: {integrity: sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==} - hasBin: true + sc-istanbul@0.4.6: dependencies: abbrev: 1.0.9 async: 1.5.2 @@ -4678,49 +5947,28 @@ packages: supports-color: 3.2.3 which: 1.3.1 wordwrap: 1.0.0 - dev: true - /scrypt-js@3.0.1: - resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} - dev: true + scrypt-js@3.0.1: {} - /secp256k1@4.0.3: - resolution: {integrity: sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==} - engines: {node: '>=10.0.0'} - requiresBuild: true + secp256k1@4.0.3: dependencies: elliptic: 6.5.5 node-addon-api: 2.0.2 node-gyp-build: 4.8.0 - dev: true - /semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - dev: true + semver@5.7.2: {} - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true + semver@6.3.1: {} - /semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} - engines: {node: '>=10'} - hasBin: true + semver@7.6.0: dependencies: lru-cache: 6.0.0 - dev: true - /serialize-javascript@6.0.0: - resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + serialize-javascript@6.0.0: dependencies: randombytes: 2.1.0 - dev: true - /set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 @@ -4728,91 +5976,62 @@ packages: get-intrinsic: 1.2.4 gopd: 1.0.1 has-property-descriptors: 1.0.2 - dev: true - /set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} + set-function-name@2.0.2: dependencies: define-data-property: 1.1.4 es-errors: 1.3.0 functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 - dev: true - /setimmediate@1.0.5: - resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - dev: true + setimmediate@1.0.5: {} - /setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - dev: true + setprototypeof@1.2.0: {} - /sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} - hasBin: true + sha.js@2.4.11: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 - dev: true - /sha1@1.1.1: - resolution: {integrity: sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==} + sha1@1.1.1: dependencies: charenc: 0.0.2 crypt: 0.0.2 - dev: true - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + sha3@2.1.4: + dependencies: + buffer: 6.0.3 + + shallowequal@1.1.0: {} + + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - dev: true - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true + shebang-regex@3.0.0: {} - /shelljs@0.8.5: - resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} - engines: {node: '>=4'} - hasBin: true + shelljs@0.8.5: dependencies: glob: 7.2.3 interpret: 1.4.0 rechoir: 0.6.2 - dev: true - /side-channel@1.0.6: - resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} - engines: {node: '>= 0.4'} + side-channel@1.0.6: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 get-intrinsic: 1.2.4 object-inspect: 1.13.1 - dev: true - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true + slash@3.0.0: {} - /slice-ansi@4.0.0: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} + slice-ansi@4.0.0: dependencies: ansi-styles: 4.3.0 astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 - dev: true - /solc@0.7.3(debug@4.3.4): - resolution: {integrity: sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==} - engines: {node: '>=8.0.0'} - hasBin: true + solc@0.7.3(debug@4.3.4): dependencies: command-exists: 1.2.9 commander: 3.0.2 @@ -4825,22 +6044,14 @@ packages: tmp: 0.0.33 transitivePeerDependencies: - debug - dev: true - /solhint-plugin-prettier@0.0.5(prettier-plugin-solidity@1.3.1)(prettier@2.8.8): - resolution: {integrity: sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA==} - peerDependencies: - prettier: ^1.15.0 || ^2.0.0 - prettier-plugin-solidity: ^1.0.0-alpha.14 + solhint-plugin-prettier@0.0.5(prettier-plugin-solidity@1.3.1(prettier@2.8.8))(prettier@2.8.8): dependencies: prettier: 2.8.8 prettier-linter-helpers: 1.0.0 prettier-plugin-solidity: 1.3.1(prettier@2.8.8) - dev: true - - /solhint@3.6.2(typescript@5.4.2): - resolution: {integrity: sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ==} - hasBin: true + + solhint@3.6.2(typescript@5.4.2): dependencies: '@solidity-parser/parser': 0.16.2 ajv: 6.12.6 @@ -4863,23 +6074,57 @@ packages: prettier: 2.8.8 transitivePeerDependencies: - typescript - dev: true - /solidity-ast@0.4.55: - resolution: {integrity: sha512-qeEU/r/K+V5lrAw8iswf2/yfWAnSGs3WKPHI+zAFKFjX0dIBVXEU/swQ8eJQYHf6PJWUZFO2uWV4V1wEOkeQbA==} + solidity-ast@0.4.55: dependencies: array.prototype.findlast: 1.2.4 - dev: true - /solidity-comments-extractor@0.0.8: - resolution: {integrity: sha512-htM7Vn6LhHreR+EglVMd2s+sZhcXAirB1Zlyrv5zBuTxieCvjfnRpd7iZk75m/u6NOlEyQ94C6TWbBn2cY7w8g==} - dev: true + solidity-comments-darwin-arm64@0.0.2: + optional: true - /solidity-coverage@0.8.6(hardhat@2.21.0): - resolution: {integrity: sha512-vV03mA/0nNMskOdVwNarUcqk0N/aYdelxAbf6RZ5l84FcYHbqDTr2JXyeYMp4bT48qHtAQjnKrygW1FrECyWNw==} - hasBin: true - peerDependencies: - hardhat: ^2.11.0 + solidity-comments-darwin-x64@0.0.2: + optional: true + + solidity-comments-extractor@0.0.8: {} + + solidity-comments-freebsd-x64@0.0.2: + optional: true + + solidity-comments-linux-arm64-gnu@0.0.2: + optional: true + + solidity-comments-linux-arm64-musl@0.0.2: + optional: true + + solidity-comments-linux-x64-gnu@0.0.2: + optional: true + + solidity-comments-linux-x64-musl@0.0.2: + optional: true + + solidity-comments-win32-arm64-msvc@0.0.2: + optional: true + + solidity-comments-win32-ia32-msvc@0.0.2: + optional: true + + solidity-comments-win32-x64-msvc@0.0.2: + optional: true + + solidity-comments@0.0.2: + optionalDependencies: + solidity-comments-darwin-arm64: 0.0.2 + solidity-comments-darwin-x64: 0.0.2 + solidity-comments-freebsd-x64: 0.0.2 + solidity-comments-linux-arm64-gnu: 0.0.2 + solidity-comments-linux-arm64-musl: 0.0.2 + solidity-comments-linux-x64-gnu: 0.0.2 + solidity-comments-linux-x64-musl: 0.0.2 + solidity-comments-win32-arm64-msvc: 0.0.2 + solidity-comments-win32-ia32-msvc: 0.0.2 + solidity-comments-win32-x64-msvc: 0.0.2 + + solidity-coverage@0.8.6(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): dependencies: '@ethersproject/abi': 5.7.0 '@solidity-parser/parser': 0.18.0 @@ -4891,7 +6136,7 @@ packages: ghost-testrpc: 0.0.2 global-modules: 2.0.0 globby: 10.0.2 - hardhat: 2.21.0(ts-node@10.9.2)(typescript@5.4.2) + hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) jsonschema: 1.4.1 lodash: 4.17.21 mocha: 10.3.0 @@ -4904,224 +6149,136 @@ packages: web3-utils: 1.10.4 transitivePeerDependencies: - supports-color - dev: true - /solidity-docgen@0.6.0-beta.36(hardhat@2.21.0): - resolution: {integrity: sha512-f/I5G2iJgU1h0XrrjRD0hHMr7C10u276vYvm//rw1TzFcYQ4xTOyAoi9oNAHRU0JU4mY9eTuxdVc2zahdMuhaQ==} - peerDependencies: - hardhat: ^2.8.0 + solidity-docgen@0.6.0-beta.36(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): dependencies: handlebars: 4.7.8 - hardhat: 2.21.0(ts-node@10.9.2)(typescript@5.4.2) + hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) solidity-ast: 0.4.55 - dev: true - /source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - dev: true - /source-map@0.2.0: - resolution: {integrity: sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==} - engines: {node: '>=0.8.0'} - requiresBuild: true + source-map@0.2.0: dependencies: amdefine: 1.0.1 - dev: true optional: true - /source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} - dev: true + source-map@0.5.7: {} - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - dev: true + source-map@0.6.1: {} - /sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: true + sprintf-js@1.0.3: {} - /stacktrace-parser@0.1.10: - resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} - engines: {node: '>=6'} + stacktrace-parser@0.1.10: dependencies: type-fest: 0.7.1 - dev: true - /statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - dev: true + statuses@2.0.1: {} - /string-format@2.0.0: - resolution: {integrity: sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==} - dev: true + string-format@2.0.0: {} - /string-width@2.1.1: - resolution: {integrity: sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==} - engines: {node: '>=4'} + string-width@2.1.1: dependencies: is-fullwidth-code-point: 2.0.0 strip-ansi: 4.0.0 - dev: true - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true - /string.prototype.trim@1.2.8: - resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} - engines: {node: '>= 0.4'} + string.prototype.trim@1.2.8: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.5 - dev: true - /string.prototype.trimend@1.0.7: - resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + string.prototype.trimend@1.0.7: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.5 - dev: true - /string.prototype.trimstart@1.0.7: - resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + string.prototype.trimstart@1.0.7: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.22.5 - dev: true - /string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 - dev: true - /string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 - dev: true - /strip-ansi@4.0.0: - resolution: {integrity: sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==} - engines: {node: '>=4'} + strip-ansi@4.0.0: dependencies: ansi-regex: 3.0.1 - dev: true - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - dev: true - /strip-hex-prefix@1.0.0: - resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} - engines: {node: '>=6.5.0', npm: '>=3'} + strip-hex-prefix@1.0.0: dependencies: is-hex-prefixed: 1.0.0 - dev: true - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true + strip-json-comments@3.1.1: {} - /supports-color@3.2.3: - resolution: {integrity: sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==} - engines: {node: '>=0.8.0'} + supports-color@3.2.3: dependencies: has-flag: 1.0.0 - dev: true - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} + supports-color@5.5.0: dependencies: has-flag: 3.0.0 - dev: true - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 - dev: true - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} + supports-color@8.1.1: dependencies: has-flag: 4.0.0 - dev: true - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true + supports-preserve-symlinks-flag@1.0.0: {} - /sync-request@6.1.0: - resolution: {integrity: sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==} - engines: {node: '>=8.0.0'} + sync-request@6.1.0: dependencies: http-response-object: 3.0.2 sync-rpc: 1.3.6 then-request: 6.0.2 - dev: true - /sync-rpc@1.3.6: - resolution: {integrity: sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==} + sync-rpc@1.3.6: dependencies: get-port: 3.2.0 - dev: true - /table-layout@1.0.2: - resolution: {integrity: sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==} - engines: {node: '>=8.0.0'} + table-layout@1.0.2: dependencies: array-back: 4.0.2 deep-extend: 0.6.0 typical: 5.2.0 wordwrapjs: 4.0.1 - dev: true - /table@6.8.1: - resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} - engines: {node: '>=10.0.0'} + table@6.8.1: dependencies: ajv: 8.12.0 lodash.truncate: 4.4.2 slice-ansi: 4.0.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true + text-table@0.2.0: {} - /tfhe@0.5.3: - resolution: {integrity: sha512-LrZXKPzI/YsLwJA+y41uYvQU+G1/JbXea30eQXXFdLSeYPPO45a9jCL5ZqvkWZkRFA9Ox2/7t86+1ysR/1DNyw==} - dev: true + tfhe@0.6.4: {} - /then-request@6.0.2: - resolution: {integrity: sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==} - engines: {node: '>=6.0.0'} + then-request@6.0.2: dependencies: '@types/concat-stream': 1.6.1 '@types/form-data': 0.0.33 @@ -5134,57 +6291,35 @@ packages: http-response-object: 3.0.2 promise: 8.3.0 qs: 6.12.0 - dev: true - /tmp@0.0.33: - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} - engines: {node: '>=0.6.0'} + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 - dev: true - /to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - dev: true + to-fast-properties@2.0.0: {} - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - dev: true - /toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - dev: true + toidentifier@1.0.1: {} - /ts-command-line-args@2.5.1: - resolution: {integrity: sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==} - hasBin: true + tr46@0.0.3: {} + + ts-command-line-args@2.5.1: dependencies: chalk: 4.1.2 command-line-args: 5.2.1 command-line-usage: 6.1.3 string-format: 2.0.0 - dev: true - /ts-essentials@1.0.4: - resolution: {integrity: sha512-q3N1xS4vZpRouhYHDPwO0bDW3EZ6SK9CrrDHxi/D6BPReSjpVgWIOpLS2o0gSBZm+7q/wyKp6RVM1AeeW7uyfQ==} - dev: true + ts-essentials@1.0.4: {} - /ts-essentials@7.0.3(typescript@5.4.2): - resolution: {integrity: sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==} - peerDependencies: - typescript: '>=3.7.0' + ts-essentials@7.0.3(typescript@5.4.2): dependencies: typescript: 5.4.2 - dev: true - /ts-generator@0.1.1: - resolution: {integrity: sha512-N+ahhZxTLYu1HNTQetwWcx3so8hcYbkKBHTr4b4/YgObFTIKkOSSsaa+nal12w8mfrJAyzJfETXawbNjSfP2gQ==} - hasBin: true + ts-generator@0.1.1: dependencies: '@types/mkdirp': 0.5.2 '@types/prettier': 2.7.3 @@ -5195,21 +6330,8 @@ packages: prettier: 2.8.8 resolve: 1.22.8 ts-essentials: 1.0.4 - dev: true - /ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2): - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true + ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.9 @@ -5226,77 +6348,39 @@ packages: typescript: 5.4.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - dev: true - /tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - dev: true + tslib@1.14.1: {} - /tslib@2.4.0: - resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} - dev: true + tslib@2.4.0: {} - /tsort@0.0.1: - resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} - dev: true + tsort@0.0.1: {} - /tsutils@3.21.0(typescript@5.4.2): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + tsutils@3.21.0(typescript@5.4.2): dependencies: tslib: 1.14.1 typescript: 5.4.2 - dev: true - /tweetnacl-util@0.15.1: - resolution: {integrity: sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==} - dev: true + tweetnacl-util@0.15.1: {} - /tweetnacl@1.0.3: - resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} - dev: true + tweetnacl@1.0.3: {} - /type-check@0.3.2: - resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} - engines: {node: '>= 0.8.0'} + type-check@0.3.2: dependencies: prelude-ls: 1.1.2 - dev: true - /type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - dev: true - /type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - dev: true + type-detect@4.0.8: {} - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - dev: true + type-fest@0.20.2: {} - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - dev: true + type-fest@0.21.3: {} - /type-fest@0.7.1: - resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} - engines: {node: '>=8'} - dev: true + type-fest@0.7.1: {} - /typechain@8.3.2(typescript@5.4.2): - resolution: {integrity: sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==} - hasBin: true - peerDependencies: - typescript: '>=4.3.0' + typechain@8.3.2(typescript@5.4.2): dependencies: '@types/prettier': 2.7.3 debug: 4.3.4(supports-color@8.1.1) @@ -5311,31 +6395,22 @@ packages: typescript: 5.4.2 transitivePeerDependencies: - supports-color - dev: true - /typed-array-buffer@1.0.2: - resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} - engines: {node: '>= 0.4'} + typed-array-buffer@1.0.2: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 is-typed-array: 1.1.13 - dev: true - /typed-array-byte-length@1.0.1: - resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} - engines: {node: '>= 0.4'} + typed-array-byte-length@1.0.1: dependencies: call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 has-proto: 1.0.3 is-typed-array: 1.1.13 - dev: true - /typed-array-byte-offset@1.0.2: - resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} - engines: {node: '>= 0.4'} + typed-array-byte-offset@1.0.2: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.7 @@ -5343,11 +6418,8 @@ packages: gopd: 1.0.1 has-proto: 1.0.3 is-typed-array: 1.1.13 - dev: true - /typed-array-length@1.0.5: - resolution: {integrity: sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==} - engines: {node: '>= 0.4'} + typed-array-length@1.0.5: dependencies: call-bind: 1.0.7 for-each: 0.3.3 @@ -5355,97 +6427,69 @@ packages: has-proto: 1.0.3 is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 - dev: true - /typedarray@0.0.6: - resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - dev: true + typedarray@0.0.6: {} - /typescript@5.4.2: - resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} - engines: {node: '>=14.17'} - hasBin: true - dev: true + typescript@5.4.2: {} - /typical@4.0.0: - resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} - engines: {node: '>=8'} - dev: true + typical@4.0.0: {} - /typical@5.2.0: - resolution: {integrity: sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==} - engines: {node: '>=8'} - dev: true + typical@5.2.0: {} - /uglify-js@3.17.4: - resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} - engines: {node: '>=0.8.0'} - hasBin: true - requiresBuild: true - dev: true + uglify-js@3.17.4: optional: true - /unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + unbox-primitive@1.0.2: dependencies: call-bind: 1.0.7 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - dev: true - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true + undici-types@5.26.5: {} - /undici@5.28.3: - resolution: {integrity: sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==} - engines: {node: '>=14.0'} + undici@5.28.3: dependencies: '@fastify/busboy': 2.1.1 - dev: true - /universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - dev: true + universalify@0.1.2: {} - /universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - dev: true + universalify@2.0.1: {} - /unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - dev: true + unpipe@1.0.0: {} - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + uri-js@4.4.1: dependencies: punycode: 2.3.1 - dev: true - /utf8@3.0.0: - resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} - dev: true + url@0.11.4: + dependencies: + punycode: 1.4.1 + qs: 6.13.0 - /util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - dev: true + utf8@3.0.0: {} - /uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true - dev: true + util-deprecate@1.0.2: {} - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - dev: true + util@0.12.5: + dependencies: + inherits: 2.0.4 + is-arguments: 1.1.1 + is-generator-function: 1.0.10 + is-typed-array: 1.1.13 + which-typed-array: 1.1.15 - /web3-utils@1.10.4: - resolution: {integrity: sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==} - engines: {node: '>=8.0.0'} + uuid@8.3.2: {} + + v8-compile-cache-lib@3.0.1: {} + + web3-errors@1.3.0: + dependencies: + web3-types: 1.8.1 + + web3-types@1.8.1: {} + + web3-utils@1.10.4: dependencies: '@ethereumjs/util': 8.1.0 bn.js: 5.2.1 @@ -5455,151 +6499,89 @@ packages: number-to-bn: 1.7.0 randombytes: 2.1.0 utf8: 3.0.0 - dev: true - /which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + web3-validator@2.0.6: + dependencies: + ethereum-cryptography: 2.1.3 + util: 0.12.5 + web3-errors: 1.3.0 + web3-types: 1.8.1 + zod: 3.23.8 + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which-boxed-primitive@1.0.2: dependencies: is-bigint: 1.0.4 is-boolean-object: 1.1.2 is-number-object: 1.0.7 is-string: 1.0.7 is-symbol: 1.0.4 - dev: true - /which-typed-array@1.1.15: - resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} - engines: {node: '>= 0.4'} + which-typed-array@1.1.15: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.7 for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.2 - dev: true - /which@1.3.1: - resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} - hasBin: true + which@1.3.1: dependencies: isexe: 2.0.0 - dev: true - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true + which@2.0.2: dependencies: isexe: 2.0.0 - dev: true - /widest-line@3.1.0: - resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} - engines: {node: '>=8'} + widest-line@3.1.0: dependencies: string-width: 4.2.3 - dev: true - /word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - dev: true + word-wrap@1.2.5: {} - /wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - dev: true + wordwrap@1.0.0: {} - /wordwrapjs@4.0.1: - resolution: {integrity: sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==} - engines: {node: '>=8.0.0'} + wordwrapjs@4.0.1: dependencies: reduce-flatten: 2.0.0 typical: 5.2.0 - dev: true - /workerpool@6.2.1: - resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} - dev: true + workerpool@6.2.1: {} - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true + wrappy@1.0.2: {} - /ws@7.4.6: - resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: true + ws@7.4.6: {} - /ws@7.5.9: - resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: true + ws@7.5.9: {} - /ws@8.5.0: - resolution: {integrity: sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: true + ws@8.5.0: {} - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: true + y18n@5.0.8: {} - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true + yallist@4.0.0: {} - /yargs-parser@20.2.4: - resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} - engines: {node: '>=10'} - dev: true + yargs-parser@20.2.4: {} - /yargs-unparser@2.0.0: - resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} - engines: {node: '>=10'} + yargs-unparser@2.0.0: dependencies: camelcase: 6.3.0 decamelize: 4.0.0 flat: 5.0.2 is-plain-obj: 2.1.0 - dev: true - /yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} + yargs@16.2.0: dependencies: cliui: 7.0.4 escalade: 3.1.2 @@ -5608,23 +6590,13 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 20.2.4 - dev: true - /yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - dev: true + yn@3.1.1: {} - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true + yocto-queue@0.1.0: {} - /zksync-web3@0.14.4(ethers@5.7.2): - resolution: {integrity: sha512-kYehMD/S6Uhe1g434UnaMN+sBr9nQm23Ywn0EUP5BfQCsbjcr3ORuS68PosZw8xUTu3pac7G6YMSnNHk+fwzvg==} - deprecated: This package has been deprecated in favor of zksync-ethers@5.0.0 - peerDependencies: - ethers: ^5.7.0 + zksync-web3@0.14.4(ethers@5.7.2): dependencies: ethers: 5.7.2 - dev: true + + zod@3.23.8: {} From 08da3f4d352316e66d674b8c6d48d4d4f4e5965e Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Tue, 22 Oct 2024 11:28:39 +0200 Subject: [PATCH 10/73] chore: Update hardhat version for tstorage --- package.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d3a9ef0..124fd4e 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "fhevm": "^0.5.9", "fhevmjs": "^0.5.7", "fs-extra": "^10.1.0", - "hardhat": "2.21.0", + "hardhat": "2.22.14", "hardhat-deploy": "^0.11.45", "hardhat-gas-reporter": "^1.0.10", "hardhat-ignore-warnings": "^0.2.11", @@ -43,8 +43,7 @@ "rimraf": "^4.4.1", "solhint": "^3.6.2", "solhint-plugin-prettier": "^0.0.5", - "solidity-coverage": "0.8.6", - "solidity-docgen": "0.6.0-beta.36", + "solidity-coverage": "0.8.12", "ts-generator": "^0.1.1", "ts-node": "^10.9.2", "typechain": "^8.3.2", @@ -80,7 +79,7 @@ "typechain": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat typechain", "test": "hardhat test", "test:mock": "HARDHAT_NETWORK=hardhat npx hardhat test --network hardhat", - "coverage:mock": "hardhat coverage", + "coverage:mock": "npx hardhat coverage", "task:getEthereumAddress": "hardhat task:getEthereumAddress", "task:accounts": "hardhat task:accounts", "fhevm:start": "./launch-fhevm.sh", @@ -94,6 +93,8 @@ "fhevm:faucet:eve": "docker exec -i fhevm faucet $(npx hardhat task:getEthereumAddressEve)" }, "dependencies": { - "@openzeppelin/contracts": "^5.0.2" + "@openzeppelin/contracts": "^5.0.2", + "extra-bigint": "^1.1.18", + "sqlite3": "^5.1.7" } } From 898e90ae956b27df42f3ffc24b991db11e9f9cba Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Tue, 22 Oct 2024 11:37:18 +0200 Subject: [PATCH 11/73] chore: Updates config --- .solcover.js | 6 +++++- .solhint.json | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.solcover.js b/.solcover.js index d71a669..938b911 100644 --- a/.solcover.js +++ b/.solcover.js @@ -3,5 +3,9 @@ module.exports = { providerOptions: { mnemonic: process.env.MNEMONIC, }, - skipFiles: ["test"], + skipFiles: ["test", "fhevmTemp"], + mocha: { + fgrep: "[skip-on-coverage]", + invert: true, + }, }; diff --git a/.solhint.json b/.solhint.json index 122f1f6..08cba13 100644 --- a/.solhint.json +++ b/.solhint.json @@ -3,7 +3,7 @@ "plugins": ["prettier"], "rules": { "code-complexity": ["error", 8], - "compiler-version": ["error", ">=0.8.4"], + "compiler-version": ["error", ">=0.8.24"], "func-visibility": ["error", { "ignoreConstructors": true }], "max-line-length": ["error", 120], "named-parameters-mapping": "warn", From 8d5bc9447b1a7f8095907cd6293d47317a56e0a6 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Tue, 22 Oct 2024 11:38:19 +0200 Subject: [PATCH 12/73] build: Lockfile --- pnpm-lock.yaml | 1416 +++++++++++++++++++++++++++--------------------- 1 file changed, 801 insertions(+), 615 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b0b2a89..728a714 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,22 +11,28 @@ importers: '@openzeppelin/contracts': specifier: ^5.0.2 version: 5.0.2 + extra-bigint: + specifier: ^1.1.18 + version: 1.2.0 + sqlite3: + specifier: ^5.1.7 + version: 5.1.7 devDependencies: '@nomicfoundation/hardhat-chai-matchers': specifier: ^2.0.6 - version: 2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + version: 2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) '@nomicfoundation/hardhat-ethers': specifier: ^3.0.5 - version: 3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + version: 3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) '@nomicfoundation/hardhat-network-helpers': specifier: ^1.0.10 - version: 1.0.10(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + version: 1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) '@nomicfoundation/hardhat-toolbox': specifier: ^3.0.0 - version: 3.0.0(efoxkvpld3mcx7zgojgym4euli) + version: 3.0.0(ugreflrcgmhzqdan7c47drajhi) '@nomicfoundation/hardhat-verify': specifier: ^1.1.1 - version: 1.1.1(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + version: 1.1.1(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) '@trivago/prettier-plugin-sort-imports': specifier: ^4.3.0 version: 4.3.0(prettier@2.8.8) @@ -35,7 +41,7 @@ importers: version: 0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2) '@typechain/hardhat': specifier: ^8.0.3 - version: 8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2)) + version: 8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2)) '@types/chai': specifier: ^4.3.12 version: 4.3.12 @@ -77,25 +83,25 @@ importers: version: 0.5.9 fhevmjs: specifier: ^0.5.7 - version: 0.5.7 + version: 0.5.7(encoding@0.1.13) fs-extra: specifier: ^10.1.0 version: 10.1.0 hardhat: - specifier: 2.21.0 - version: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + specifier: 2.22.14 + version: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) hardhat-deploy: specifier: ^0.11.45 version: 0.11.45 hardhat-gas-reporter: specifier: ^1.0.10 - version: 1.0.10(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + version: 1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) hardhat-ignore-warnings: specifier: ^0.2.11 version: 0.2.11 hardhat-preprocessor: specifier: ^0.1.5 - version: 0.1.5(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + version: 0.1.5(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) lodash: specifier: ^4.17.21 version: 4.17.21 @@ -118,11 +124,8 @@ importers: specifier: ^0.0.5 version: 0.0.5(prettier-plugin-solidity@1.3.1(prettier@2.8.8))(prettier@2.8.8) solidity-coverage: - specifier: 0.8.6 - version: 0.8.6(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) - solidity-docgen: - specifier: 0.6.0-beta.36 - version: 0.6.0-beta.36(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + specifier: 0.8.12 + version: 0.8.12(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) ts-generator: specifier: ^0.1.1 version: 0.1.1 @@ -331,6 +334,9 @@ packages: resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} + '@gar/promisify@1.1.3': + resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} @@ -399,62 +405,36 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@nomicfoundation/edr-darwin-arm64@0.2.1': - resolution: {integrity: sha512-aMYaRaZVQ/TmyNJIoXf1bU4k0zfinaL9Sy1day4yGlL6eiQPFfRGj9W6TZaZIoYG0XTx/mQWD7dkXJ7LdrleJA==} - engines: {node: '>= 18'} - cpu: [arm64] - os: [darwin] - - '@nomicfoundation/edr-darwin-x64@0.2.1': - resolution: {integrity: sha512-ma0SLcjHm5L3nPHcKFJB0jv/gKGSKaxr5Z65rurX/eaYUQJ7YGMsb8er9bSCo9rjzOtxf4FoPj3grL3zGpOj8A==} + '@nomicfoundation/edr-darwin-arm64@0.6.4': + resolution: {integrity: sha512-QNQErISLgssV9+qia8sIjRANqtbW8snSDvjspixT/kSQ5ZSGxxctTg7x72wPSrcu8+EBEveIe5uqENIp5GH8HQ==} engines: {node: '>= 18'} - cpu: [x64] - os: [darwin] - '@nomicfoundation/edr-linux-arm64-gnu@0.2.1': - resolution: {integrity: sha512-NX3G4pBhRitWrjSGY3HTyCq3wKSm5YqrKVOCNQGl9/jcjSovqxlgzFMiTx4YZCzGntfJ/1om9AI84OWxYJjoDw==} + '@nomicfoundation/edr-darwin-x64@0.6.4': + resolution: {integrity: sha512-cjVmREiwByyc9+oGfvAh49IAw+oVJHF9WWYRD+Tm/ZlSpnEVWxrGNBak2bd/JSYjn+mZE7gmWS4SMRi4nKaLUg==} engines: {node: '>= 18'} - cpu: [arm64] - os: [linux] - '@nomicfoundation/edr-linux-arm64-musl@0.2.1': - resolution: {integrity: sha512-gdQ3QHkt9XRkdtOGQ8fMwS11MXdjLeZgLrqoial4V4qtMaamIMMhVczK+VEvUhD8p7G4BVmp6kmkvcsthmndmw==} + '@nomicfoundation/edr-linux-arm64-gnu@0.6.4': + resolution: {integrity: sha512-96o9kRIVD6W5VkgKvUOGpWyUGInVQ5BRlME2Fa36YoNsRQMaKtmYJEU0ACosYES6ZTpYC8U5sjMulvPtVoEfOA==} engines: {node: '>= 18'} - cpu: [arm64] - os: [linux] - '@nomicfoundation/edr-linux-x64-gnu@0.2.1': - resolution: {integrity: sha512-OqabFY37vji6mYbLD9CvG28lja68czeVw58oWByIhFV3BpBu/cyP1oAbhzk3LieylujabS3Ekpvjw2Tkf0A9RQ==} + '@nomicfoundation/edr-linux-arm64-musl@0.6.4': + resolution: {integrity: sha512-+JVEW9e5plHrUfQlSgkEj/UONrIU6rADTEk+Yp9pbe+mzNkJdfJYhs5JYiLQRP4OjxH4QOrXI97bKU6FcEbt5Q==} engines: {node: '>= 18'} - cpu: [x64] - os: [linux] - '@nomicfoundation/edr-linux-x64-musl@0.2.1': - resolution: {integrity: sha512-vHfFFK2EPISuQUQge+bdjXamb0EUjfl8srYSog1qfiwyLwLeuSbpyyFzDeITAgPpkkFuedTfJW553K0Hipspyg==} + '@nomicfoundation/edr-linux-x64-gnu@0.6.4': + resolution: {integrity: sha512-nzYWW+fO3EZItOeP4CrdMgDXfaGBIBkKg0Y/7ySpUxLqzut40O4Mb0/+quqLAFkacUSWMlFp8nsmypJfOH5zoA==} engines: {node: '>= 18'} - cpu: [x64] - os: [linux] - - '@nomicfoundation/edr-win32-arm64-msvc@0.2.1': - resolution: {integrity: sha512-K/mui67RCKxghbSyvhvW3rvyVN1pa9M1Q9APUx1PtWjSSdXDFpqEY1NYsv2syb47Ca8ObJwVMF+LvnB6GvhUOQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - '@nomicfoundation/edr-win32-ia32-msvc@0.2.1': - resolution: {integrity: sha512-HHK0mXEtjvfjJrJlqcYgQCy3lZIXS1KNl2GaP8bwEIuEwx++XxXs/ThLjPepM1nhCGICij8IGy7p3KrkzRelsw==} + '@nomicfoundation/edr-linux-x64-musl@0.6.4': + resolution: {integrity: sha512-QFRoE9qSQ2boRrVeQ1HdzU+XN7NUgwZ1SIy5DQt4d7jCP+5qTNsq8LBNcqhRBOATgO63nsweNUhxX/Suj5r1Sw==} engines: {node: '>= 18'} - cpu: [ia32] - os: [win32] - '@nomicfoundation/edr-win32-x64-msvc@0.2.1': - resolution: {integrity: sha512-FY4eQJdj1/y8ST0RyQycx63yr+lvdYNnUkzgWf4X+vPH1lOhXae+L2NDcNCQlTDAfQcD6yz0bkBUkLrlJ8pTww==} + '@nomicfoundation/edr-win32-x64-msvc@0.6.4': + resolution: {integrity: sha512-2yopjelNkkCvIjUgBGhrn153IBPLwnsDeNiq6oA0WkeM8tGmQi4td+PGi9jAriUDAkc59Yoi2q9hYA6efiY7Zw==} engines: {node: '>= 18'} - cpu: [x64] - os: [win32] - '@nomicfoundation/edr@0.2.1': - resolution: {integrity: sha512-Dleau3ItHJh2n85G2J6AIPBoLgu/mOWkmrh26z3VsJE2tp/e00hUk/dqz85ncsVcBYEc6/YOn/DomWu0wSF9tQ==} + '@nomicfoundation/edr@0.6.4': + resolution: {integrity: sha512-YgrSuT3yo5ZQkbvBGqQ7hG+RDvz3YygSkddg4tb1Z0Y6pLXFzwrcEwWaJCFAVeeZxdxGfCgGMUYgRVneK+WXkw==} engines: {node: '>= 18'} '@nomicfoundation/ethereumjs-common@4.0.4': @@ -592,6 +572,14 @@ packages: resolution: {integrity: sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg==} engines: {node: '>= 12'} + '@npmcli/fs@1.1.1': + resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} + + '@npmcli/move-file@1.1.2': + resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==} + engines: {node: '>=10'} + deprecated: This functionality has been moved to @npmcli/fs + '@openzeppelin/contracts@5.0.2': resolution: {integrity: sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA==} @@ -650,6 +638,10 @@ packages: '@solidity-parser/parser@0.18.0': resolution: {integrity: sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==} + '@tootallnate/once@1.1.2': + resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} + engines: {node: '>= 6'} + '@trivago/prettier-plugin-sort-imports@4.3.0': resolution: {integrity: sha512-r3n0onD3BTOVUNPhR4lhVK4/pABGpbA7bW3eumZnYdKaHkf1qEC+Mag6DPbGNuuh0eG8AaYj+YqmVHSiGslaTQ==} peerDependencies: @@ -836,10 +828,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - address@1.2.2: - resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} - engines: {node: '>= 10.0.0'} - adm-zip@0.4.16: resolution: {integrity: sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==} engines: {node: '>=0.3.0'} @@ -854,6 +842,10 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} + agentkeepalive@4.5.0: + resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} + engines: {node: '>= 8.0.0'} + aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -910,6 +902,14 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + aproba@2.0.0: + resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} + + are-we-there-yet@3.0.1: + resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. + arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -927,10 +927,6 @@ packages: resolution: {integrity: sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==} engines: {node: '>=8'} - array-buffer-byte-length@1.0.1: - resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} - engines: {node: '>= 0.4'} - array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -939,14 +935,6 @@ packages: resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} engines: {node: '>=0.10.0'} - array.prototype.findlast@1.2.4: - resolution: {integrity: sha512-BMtLxpV+8BD+6ZPFIWmnUBpQoy+A+ujcg4rhp2iwCRJYA7PEh2MS4NL3lz8EiDlLrJPp2hg9qWihr5pd//jcGw==} - engines: {node: '>= 0.4'} - - arraybuffer.prototype.slice@1.0.3: - resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} - engines: {node: '>= 0.4'} - asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} @@ -1003,6 +991,9 @@ packages: bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + blakejs@1.2.1: resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} @@ -1050,6 +1041,9 @@ packages: buffer-xor@1.0.3: resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} @@ -1057,6 +1051,10 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + cacache@15.3.0: + resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==} + engines: {node: '>= 10'} + call-bind@1.0.7: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} @@ -1107,6 +1105,17 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chokidar@4.0.1: + resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} + engines: {node: '>= 14.16.0'} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + ci-info@2.0.0: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} @@ -1141,6 +1150,10 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + colors@1.4.0: resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} engines: {node: '>=0.1.90'} @@ -1168,8 +1181,9 @@ packages: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} - commander@3.0.2: - resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -1178,6 +1192,9 @@ packages: resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} engines: {'0': node >= 0.8} + console-control-strings@1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + cookie@0.4.2: resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} engines: {node: '>= 0.6'} @@ -1231,6 +1248,10 @@ packages: resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} engines: {node: '>=10'} + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + deep-eql@4.1.3: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} engines: {node: '>=6'} @@ -1246,21 +1267,20 @@ packages: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + delegates@1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} - detect-port@1.5.1: - resolution: {integrity: sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==} - hasBin: true + detect-libc@2.0.3: + resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} + engines: {node: '>=8'} diff@4.0.2: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} @@ -1297,6 +1317,12 @@ packages: encode-utf8@1.0.3: resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + encoding@0.1.13: + resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} @@ -1305,13 +1331,12 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} + err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - es-abstract@1.22.5: - resolution: {integrity: sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==} - engines: {node: '>= 0.4'} - es-define-property@1.0.0: resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} engines: {node: '>= 0.4'} @@ -1320,17 +1345,6 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-set-tostringtag@2.0.3: - resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} - engines: {node: '>= 0.4'} - - es-shim-unscopables@1.0.2: - resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} - - es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} - escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} @@ -1457,6 +1471,13 @@ packages: evp_bytestokey@1.0.3: resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + + extra-bigint@1.2.0: + resolution: {integrity: sha512-F9T/pcT5xPZTjlFMKGCZgBY2/jKqEPxXHT4kLSwsa7gp7D05nQq8z9NzRTzVy5Z4AOO1E/iD9r9OBz4csGD7nw==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1545,8 +1566,8 @@ packages: fp-ts@1.19.3: resolution: {integrity: sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==} - fs-extra@0.30.0: - resolution: {integrity: sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==} + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} @@ -1564,6 +1585,10 @@ packages: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} + fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + fs-readdir-recursive@1.1.0: resolution: {integrity: sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==} @@ -1578,12 +1603,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function.prototype.name@1.1.6: - resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} - engines: {node: '>= 0.4'} - - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + gauge@4.0.4: + resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} @@ -1600,14 +1623,13 @@ packages: resolution: {integrity: sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==} engines: {node: '>=4'} - get-symbol-description@1.0.2: - resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} - engines: {node: '>= 0.4'} - ghost-testrpc@0.0.2: resolution: {integrity: sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==} hasBin: true + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1618,12 +1640,14 @@ packages: glob@5.0.15: resolution: {integrity: sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==} + deprecated: Glob versions prior to v9 are no longer supported glob@7.1.7: resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} glob@7.2.0: resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + deprecated: Glob versions prior to v9 are no longer supported glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} @@ -1652,10 +1676,6 @@ packages: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} - globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} - engines: {node: '>= 0.4'} - globby@10.0.2: resolution: {integrity: sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==} engines: {node: '>=8'} @@ -1694,8 +1714,8 @@ packages: peerDependencies: hardhat: ^2.0.5 - hardhat@2.21.0: - resolution: {integrity: sha512-8DlJAVJDEVHaV1sh9FLuKLLgCFv9EAJ+M+8IbjSIPgoeNo3ss5L1HgGBMfnI88c7OzMEZkdcuyGoobFeK3Orqw==} + hardhat@2.22.14: + resolution: {integrity: sha512-sD8vHtS9l5QQVHzyPPe3auwZDJyZ0fG3Z9YENVa4oOqVEefCuHcPzdU736rei3zUKTqkX0zPIHkSMHpu02Fq1A==} hasBin: true peerDependencies: ts-node: '*' @@ -1706,9 +1726,6 @@ packages: typescript: optional: true - has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - has-flag@1.0.0: resolution: {integrity: sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==} engines: {node: '>=0.10.0'} @@ -1736,6 +1753,9 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} + has-unicode@2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + hash-base@3.1.0: resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} engines: {node: '>=4'} @@ -1761,10 +1781,17 @@ packages: resolution: {integrity: sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==} engines: {node: '>=6.0.0'} + http-cache-semantics@4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} + http-proxy-agent@4.0.1: + resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} + engines: {node: '>= 6'} + http-response-object@3.0.2: resolution: {integrity: sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==} @@ -1772,10 +1799,17 @@ packages: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -1802,6 +1836,9 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + infer-owner@1.0.4: + resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} @@ -1811,10 +1848,6 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - internal-slot@1.0.7: - resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} - engines: {node: '>= 0.4'} - interpret@1.4.0: resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} engines: {node: '>= 0.10'} @@ -1822,28 +1855,21 @@ packages: io-ts@1.10.4: resolution: {integrity: sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==} + ip-address@9.0.5: + resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} + engines: {node: '>= 12'} + is-arguments@1.1.1: resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} engines: {node: '>= 0.4'} - is-array-buffer@3.0.4: - resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} - engines: {node: '>= 0.4'} - is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} - is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} - is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} - is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -1851,10 +1877,6 @@ packages: is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} - is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} - is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -1879,13 +1901,8 @@ packages: resolution: {integrity: sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==} engines: {node: '>=6.5.0', npm: '>=3'} - is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} - - is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} + is-lambda@1.0.1: + resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} @@ -1899,22 +1916,6 @@ packages: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} - is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} - engines: {node: '>= 0.4'} - - is-shared-array-buffer@1.0.3: - resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} - engines: {node: '>= 0.4'} - - is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} - - is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} - engines: {node: '>= 0.4'} - is-typed-array@1.1.13: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} @@ -1923,15 +1924,9 @@ packages: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} - is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} - isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -1952,6 +1947,9 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + jsbn@1.1.0: + resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} + jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} @@ -1972,8 +1970,9 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - jsonfile@2.4.0: - resolution: {integrity: sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==} + json-stream-stringify@3.1.6: + resolution: {integrity: sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==} + engines: {node: '>=7.10.1'} jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -1995,9 +1994,6 @@ packages: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - klaw@1.3.1: - resolution: {integrity: sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==} - levn@0.3.0: resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} engines: {node: '>= 0.8.0'} @@ -2056,6 +2052,10 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + make-fetch-happen@9.1.0: + resolution: {integrity: sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==} + engines: {node: '>= 10'} + markdown-table@1.1.3: resolution: {integrity: sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==} @@ -2088,6 +2088,10 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} @@ -2112,14 +2116,49 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass-collect@1.0.2: + resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} + engines: {node: '>= 8'} + + minipass-fetch@1.4.1: + resolution: {integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==} + engines: {node: '>=8'} + + minipass-flush@1.0.5: + resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} + engines: {node: '>= 8'} + + minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + + minipass-sized@1.0.3: + resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} + engines: {node: '>=8'} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + minipass@4.2.8: resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} engines: {node: '>=8'} + minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + minipass@7.0.4: resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} engines: {node: '>=16 || 14 >=14.17'} + minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -2146,18 +2185,32 @@ packages: murmur-128@0.2.1: resolution: {integrity: sha512-WseEgiRkI6aMFBbj8Cg9yBj/y+OdipwVC7zUo3W2W1JAJITwouUOtpqsmGSg67EQmwwSyod7hsVsWY5LsrfQVg==} + napi-build-utils@1.0.2: + resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + negotiator@0.6.4: + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + node-abi@3.71.0: + resolution: {integrity: sha512-SZ40vRiy/+wRTf21hxkkEjPJZpARzUMVcJoQse2EF8qkUWbbO2z7vd5oA/H6bVH6SZQ5STGcu0KRDS7biNRfxw==} + engines: {node: '>=10'} + node-addon-api@2.0.2: resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} @@ -2174,6 +2227,11 @@ packages: resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==} hasBin: true + node-gyp@8.4.1: + resolution: {integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==} + engines: {node: '>= 10.12.0'} + hasBin: true + node-interval-tree@2.1.2: resolution: {integrity: sha512-bJ9zMDuNGzVQg1xv0bCPzyEDxHgbrx7/xGj6CDokvizZZmastPsOh0JJLuY8wA5q2SfX1TLNMk7XNV8WxbGxzA==} engines: {node: '>= 14.0.0'} @@ -2189,10 +2247,20 @@ packages: resolution: {integrity: sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==} hasBin: true + nopt@5.0.0: + resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} + engines: {node: '>=6'} + hasBin: true + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + npmlog@6.0.2: + resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. + number-to-bn@1.7.0: resolution: {integrity: sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==} engines: {node: '>=6.5.0', npm: '>=3'} @@ -2204,14 +2272,6 @@ packages: object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - object.assign@4.1.5: - resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} - engines: {node: '>= 0.4'} - obliterator@2.0.4: resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} @@ -2318,6 +2378,11 @@ packages: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} + prebuild-install@7.1.2: + resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} + engines: {node: '>=10'} + hasBin: true + prelude-ls@1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} @@ -2344,12 +2409,27 @@ packages: process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + promise-inflight@1.0.1: + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + peerDependencies: + bluebird: '*' + peerDependenciesMeta: + bluebird: + optional: true + + promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + promise@8.3.0: resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + pump@3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + punycode@1.4.1: resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} @@ -2375,6 +2455,10 @@ packages: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -2386,6 +2470,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@4.0.2: + resolution: {integrity: sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==} + engines: {node: '>= 14.16.0'} + rechoir@0.6.2: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} engines: {node: '>= 0.10'} @@ -2398,10 +2486,6 @@ packages: resolution: {integrity: sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==} engines: {node: '>=6'} - regexp.prototype.flags@1.5.2: - resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} - engines: {node: '>= 0.4'} - req-cwd@2.0.0: resolution: {integrity: sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==} engines: {node: '>=4'} @@ -2436,14 +2520,14 @@ packages: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@2.7.1: - resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} - hasBin: true - rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true @@ -2463,20 +2547,12 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - safe-array-concat@1.1.2: - resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} - engines: {node: '>=0.4'} - safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-regex-test@1.0.3: - resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} - engines: {node: '>= 0.4'} - safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -2507,14 +2583,13 @@ packages: serialize-javascript@6.0.0: resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} - set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} - setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} @@ -2551,6 +2626,15 @@ packages: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -2559,9 +2643,21 @@ packages: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} - solc@0.7.3: - resolution: {integrity: sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==} - engines: {node: '>=8.0.0'} + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + + socks-proxy-agent@6.2.1: + resolution: {integrity: sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==} + engines: {node: '>= 10'} + + socks@2.8.3: + resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + + solc@0.8.26: + resolution: {integrity: sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g==} + engines: {node: '>=10.0.0'} hasBin: true solhint-plugin-prettier@0.0.5: @@ -2574,9 +2670,6 @@ packages: resolution: {integrity: sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ==} hasBin: true - solidity-ast@0.4.55: - resolution: {integrity: sha512-qeEU/r/K+V5lrAw8iswf2/yfWAnSGs3WKPHI+zAFKFjX0dIBVXEU/swQ8eJQYHf6PJWUZFO2uWV4V1wEOkeQbA==} - solidity-comments-darwin-arm64@0.0.2: resolution: {integrity: sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==} engines: {node: '>= 10'} @@ -2644,17 +2737,12 @@ packages: resolution: {integrity: sha512-G+aK6qtyUfkn1guS8uzqUeua1dURwPlcOjoTYW/TwmXAcE7z/1+oGCfZUdMSe4ZMKklNbVZNiG5ibnF8gkkFfw==} engines: {node: '>= 12'} - solidity-coverage@0.8.6: - resolution: {integrity: sha512-vV03mA/0nNMskOdVwNarUcqk0N/aYdelxAbf6RZ5l84FcYHbqDTr2JXyeYMp4bT48qHtAQjnKrygW1FrECyWNw==} + solidity-coverage@0.8.12: + resolution: {integrity: sha512-8cOB1PtjnjFRqOgwFiD8DaUsYJtVJ6+YdXQtSZDrLGf8cdhhh8xzTtGzVTGeBf15kTv0v7lYPJlV/az7zLEPJw==} hasBin: true peerDependencies: hardhat: ^2.11.0 - solidity-docgen@0.6.0-beta.36: - resolution: {integrity: sha512-f/I5G2iJgU1h0XrrjRD0hHMr7C10u276vYvm//rw1TzFcYQ4xTOyAoi9oNAHRU0JU4mY9eTuxdVc2zahdMuhaQ==} - peerDependencies: - hardhat: ^2.8.0 - source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} @@ -2673,6 +2761,16 @@ packages: sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + + sqlite3@5.1.7: + resolution: {integrity: sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==} + + ssri@8.0.1: + resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} + engines: {node: '>= 8'} + stacktrace-parser@0.1.10: resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} engines: {node: '>=6'} @@ -2692,16 +2790,6 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} - string.prototype.trim@1.2.8: - resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} - engines: {node: '>= 0.4'} - - string.prototype.trimend@1.0.7: - resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} - - string.prototype.trimstart@1.0.7: - resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} - string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} @@ -2720,6 +2808,10 @@ packages: resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} engines: {node: '>=6.5.0', npm: '>=3'} + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -2759,6 +2851,17 @@ packages: resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} engines: {node: '>=10.0.0'} + tar-fs@2.1.1: + resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -2833,6 +2936,9 @@ packages: peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + tweetnacl-util@0.15.1: resolution: {integrity: sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==} @@ -2869,22 +2975,6 @@ packages: peerDependencies: typescript: '>=4.3.0' - typed-array-buffer@1.0.2: - resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} - engines: {node: '>= 0.4'} - - typed-array-byte-length@1.0.1: - resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.2: - resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} - engines: {node: '>= 0.4'} - - typed-array-length@1.0.5: - resolution: {integrity: sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==} - engines: {node: '>= 0.4'} - typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} @@ -2906,9 +2996,6 @@ packages: engines: {node: '>=0.8.0'} hasBin: true - unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} @@ -2916,6 +3003,12 @@ packages: resolution: {integrity: sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==} engines: {node: '>=14.0'} + unique-filename@1.1.1: + resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} + + unique-slug@2.0.2: + resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -2973,9 +3066,6 @@ packages: whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} - which-typed-array@1.1.15: resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} @@ -2989,6 +3079,9 @@ packages: engines: {node: '>= 8'} hasBin: true + wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + widest-line@3.1.0: resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} engines: {node: '>=8'} @@ -3463,6 +3556,9 @@ snapshots: '@fastify/busboy@2.1.1': {} + '@gar/promisify@1.1.3': + optional: true + '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.2 @@ -3533,44 +3629,29 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 - '@nomicfoundation/edr-darwin-arm64@0.2.1': - optional: true - - '@nomicfoundation/edr-darwin-x64@0.2.1': - optional: true - - '@nomicfoundation/edr-linux-arm64-gnu@0.2.1': - optional: true + '@nomicfoundation/edr-darwin-arm64@0.6.4': {} - '@nomicfoundation/edr-linux-arm64-musl@0.2.1': - optional: true + '@nomicfoundation/edr-darwin-x64@0.6.4': {} - '@nomicfoundation/edr-linux-x64-gnu@0.2.1': - optional: true + '@nomicfoundation/edr-linux-arm64-gnu@0.6.4': {} - '@nomicfoundation/edr-linux-x64-musl@0.2.1': - optional: true + '@nomicfoundation/edr-linux-arm64-musl@0.6.4': {} - '@nomicfoundation/edr-win32-arm64-msvc@0.2.1': - optional: true + '@nomicfoundation/edr-linux-x64-gnu@0.6.4': {} - '@nomicfoundation/edr-win32-ia32-msvc@0.2.1': - optional: true + '@nomicfoundation/edr-linux-x64-musl@0.6.4': {} - '@nomicfoundation/edr-win32-x64-msvc@0.2.1': - optional: true + '@nomicfoundation/edr-win32-x64-msvc@0.6.4': {} - '@nomicfoundation/edr@0.2.1': - optionalDependencies: - '@nomicfoundation/edr-darwin-arm64': 0.2.1 - '@nomicfoundation/edr-darwin-x64': 0.2.1 - '@nomicfoundation/edr-linux-arm64-gnu': 0.2.1 - '@nomicfoundation/edr-linux-arm64-musl': 0.2.1 - '@nomicfoundation/edr-linux-x64-gnu': 0.2.1 - '@nomicfoundation/edr-linux-x64-musl': 0.2.1 - '@nomicfoundation/edr-win32-arm64-msvc': 0.2.1 - '@nomicfoundation/edr-win32-ia32-msvc': 0.2.1 - '@nomicfoundation/edr-win32-x64-msvc': 0.2.1 + '@nomicfoundation/edr@0.6.4': + dependencies: + '@nomicfoundation/edr-darwin-arm64': 0.6.4 + '@nomicfoundation/edr-darwin-x64': 0.6.4 + '@nomicfoundation/edr-linux-arm64-gnu': 0.6.4 + '@nomicfoundation/edr-linux-arm64-musl': 0.6.4 + '@nomicfoundation/edr-linux-x64-gnu': 0.6.4 + '@nomicfoundation/edr-linux-x64-musl': 0.6.4 + '@nomicfoundation/edr-win32-x64-msvc': 0.6.4 '@nomicfoundation/ethereumjs-common@4.0.4': dependencies: @@ -3592,59 +3673,59 @@ snapshots: '@nomicfoundation/ethereumjs-rlp': 5.0.4 ethereum-cryptography: 0.1.3 - '@nomicfoundation/hardhat-chai-matchers@2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': + '@nomicfoundation/hardhat-chai-matchers@2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': dependencies: - '@nomicfoundation/hardhat-ethers': 3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-ethers': 3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) '@types/chai-as-promised': 7.1.8 chai: 4.4.1 chai-as-promised: 7.1.1(chai@4.4.1) deep-eql: 4.1.3 ethers: 6.11.1 - hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) ordinal: 1.0.3 - '@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': + '@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': dependencies: debug: 4.3.4(supports-color@8.1.1) ethers: 6.11.1 - hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) lodash.isequal: 4.5.0 transitivePeerDependencies: - supports-color - '@nomicfoundation/hardhat-network-helpers@1.0.10(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': + '@nomicfoundation/hardhat-network-helpers@1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': dependencies: ethereumjs-util: 7.1.5 - hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) - '@nomicfoundation/hardhat-toolbox@3.0.0(efoxkvpld3mcx7zgojgym4euli)': + '@nomicfoundation/hardhat-toolbox@3.0.0(ugreflrcgmhzqdan7c47drajhi)': dependencies: - '@nomicfoundation/hardhat-chai-matchers': 2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) - '@nomicfoundation/hardhat-ethers': 3.0.5(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) - '@nomicfoundation/hardhat-network-helpers': 1.0.10(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) - '@nomicfoundation/hardhat-verify': 1.1.1(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-chai-matchers': 2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-ethers': 3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-network-helpers': 1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-verify': 1.1.1(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) '@typechain/ethers-v6': 0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2) - '@typechain/hardhat': 8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2)) + '@typechain/hardhat': 8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2)) '@types/chai': 4.3.12 '@types/mocha': 10.0.6 '@types/node': 18.19.23 chai: 4.4.1 ethers: 6.11.1 - hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) - hardhat-gas-reporter: 1.0.10(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) - solidity-coverage: 0.8.6(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat-gas-reporter: 1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + solidity-coverage: 0.8.12(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) ts-node: 10.9.2(@types/node@18.19.23)(typescript@5.4.2) typechain: 8.3.2(typescript@5.4.2) typescript: 5.4.2 - '@nomicfoundation/hardhat-verify@1.1.1(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': + '@nomicfoundation/hardhat-verify@1.1.1(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/address': 5.7.0 cbor: 8.1.0 chalk: 2.4.2 debug: 4.3.4(supports-color@8.1.1) - hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) lodash.clonedeep: 4.5.0 semver: 6.3.1 table: 6.8.1 @@ -3695,6 +3776,18 @@ snapshots: '@nomicfoundation/solidity-analyzer-win32-ia32-msvc': 0.1.1 '@nomicfoundation/solidity-analyzer-win32-x64-msvc': 0.1.1 + '@npmcli/fs@1.1.1': + dependencies: + '@gar/promisify': 1.1.3 + semver: 7.6.0 + optional: true + + '@npmcli/move-file@1.1.2': + dependencies: + mkdirp: 1.0.4 + rimraf: 3.0.2 + optional: true + '@openzeppelin/contracts@5.0.2': {} '@scure/base@1.1.5': {} @@ -3782,6 +3875,9 @@ snapshots: '@solidity-parser/parser@0.18.0': {} + '@tootallnate/once@1.1.2': + optional: true + '@trivago/prettier-plugin-sort-imports@4.3.0(prettier@2.8.8)': dependencies: '@babel/generator': 7.17.7 @@ -3810,12 +3906,12 @@ snapshots: typechain: 8.3.2(typescript@5.4.2) typescript: 5.4.2 - '@typechain/hardhat@8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2))': + '@typechain/hardhat@8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2))': dependencies: '@typechain/ethers-v6': 0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2) ethers: 6.11.1 fs-extra: 9.1.0 - hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) typechain: 8.3.2(typescript@5.4.2) '@types/bn.js@4.11.6': @@ -3989,8 +4085,6 @@ snapshots: acorn@8.11.3: {} - address@1.2.2: {} - adm-zip@0.4.16: {} aes-js@3.0.0: {} @@ -4003,6 +4097,11 @@ snapshots: transitivePeerDependencies: - supports-color + agentkeepalive@4.5.0: + dependencies: + humanize-ms: 1.2.1 + optional: true + aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 @@ -4058,6 +4157,15 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + aproba@2.0.0: + optional: true + + are-we-there-yet@3.0.1: + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.2 + optional: true + arg@4.1.3: {} argparse@1.0.10: @@ -4070,34 +4178,10 @@ snapshots: array-back@4.0.2: {} - array-buffer-byte-length@1.0.1: - dependencies: - call-bind: 1.0.7 - is-array-buffer: 3.0.4 - array-union@2.1.0: {} array-uniq@1.0.3: {} - array.prototype.findlast@1.2.4: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.22.5 - es-errors: 1.3.0 - es-shim-unscopables: 1.0.2 - - arraybuffer.prototype.slice@1.0.3: - dependencies: - array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.22.5 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - is-array-buffer: 3.0.4 - is-shared-array-buffer: 1.0.3 - asap@2.0.6: {} assertion-error@1.1.0: {} @@ -4150,6 +4234,12 @@ snapshots: dependencies: file-uri-to-path: 1.0.0 + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + blakejs@1.2.1: {} bn.js@4.11.6: {} @@ -4209,6 +4299,11 @@ snapshots: buffer-xor@1.0.3: {} + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + buffer@6.0.3: dependencies: base64-js: 1.5.1 @@ -4216,6 +4311,30 @@ snapshots: bytes@3.1.2: {} + cacache@15.3.0: + dependencies: + '@npmcli/fs': 1.1.1 + '@npmcli/move-file': 1.1.2 + chownr: 2.0.0 + fs-minipass: 2.1.0 + glob: 7.2.3 + infer-owner: 1.0.4 + lru-cache: 6.0.0 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + mkdirp: 1.0.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + rimraf: 3.0.2 + ssri: 8.0.1 + tar: 6.2.1 + unique-filename: 1.1.1 + transitivePeerDependencies: + - bluebird + optional: true + call-bind@1.0.7: dependencies: es-define-property: 1.0.0 @@ -4290,6 +4409,14 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chokidar@4.0.1: + dependencies: + readdirp: 4.0.2 + + chownr@1.1.4: {} + + chownr@2.0.0: {} + ci-info@2.0.0: {} cipher-base@1.0.4: @@ -4326,6 +4453,9 @@ snapshots: color-name@1.1.4: {} + color-support@1.1.3: + optional: true + colors@1.4.0: {} combined-stream@1.0.8: @@ -4352,7 +4482,7 @@ snapshots: commander@11.1.0: {} - commander@3.0.2: {} + commander@8.3.0: {} concat-map@0.0.1: {} @@ -4363,6 +4493,9 @@ snapshots: readable-stream: 2.3.8 typedarray: 0.0.6 + console-control-strings@1.1.0: + optional: true + cookie@0.4.2: {} core-util-is@1.0.3: {} @@ -4417,6 +4550,10 @@ snapshots: decamelize@4.0.0: {} + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + deep-eql@4.1.3: dependencies: type-detect: 4.0.8 @@ -4431,22 +4568,14 @@ snapshots: es-errors: 1.3.0 gopd: 1.0.1 - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - delayed-stream@1.0.0: {} + delegates@1.0.0: + optional: true + depd@2.0.0: {} - detect-port@1.5.1: - dependencies: - address: 1.2.2 - debug: 4.3.4(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color + detect-libc@2.0.3: {} diff@4.0.2: {} @@ -4490,6 +4619,15 @@ snapshots: encode-utf8@1.0.3: {} + encoding@0.1.13: + dependencies: + iconv-lite: 0.6.3 + optional: true + + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 @@ -4497,76 +4635,19 @@ snapshots: env-paths@2.2.1: {} + err-code@2.0.3: + optional: true + error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 - es-abstract@1.22.5: - dependencies: - array-buffer-byte-length: 1.0.1 - arraybuffer.prototype.slice: 1.0.3 - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - es-define-property: 1.0.0 - es-errors: 1.3.0 - es-set-tostringtag: 2.0.3 - es-to-primitive: 1.2.1 - function.prototype.name: 1.1.6 - get-intrinsic: 1.2.4 - get-symbol-description: 1.0.2 - globalthis: 1.0.3 - gopd: 1.0.1 - has-property-descriptors: 1.0.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - hasown: 2.0.2 - internal-slot: 1.0.7 - is-array-buffer: 3.0.4 - is-callable: 1.2.7 - is-negative-zero: 2.0.3 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.3 - is-string: 1.0.7 - is-typed-array: 1.1.13 - is-weakref: 1.0.2 - object-inspect: 1.13.1 - object-keys: 1.1.1 - object.assign: 4.1.5 - regexp.prototype.flags: 1.5.2 - safe-array-concat: 1.1.2 - safe-regex-test: 1.0.3 - string.prototype.trim: 1.2.8 - string.prototype.trimend: 1.0.7 - string.prototype.trimstart: 1.0.7 - typed-array-buffer: 1.0.2 - typed-array-byte-length: 1.0.1 - typed-array-byte-offset: 1.0.2 - typed-array-length: 1.0.5 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.15 - es-define-property@1.0.0: dependencies: get-intrinsic: 1.2.4 es-errors@1.3.0: {} - es-set-tostringtag@2.0.3: - dependencies: - get-intrinsic: 1.2.4 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - es-shim-unscopables@1.0.2: - dependencies: - hasown: 2.0.2 - - es-to-primitive@1.2.1: - dependencies: - is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.0.4 - escalade@3.1.2: {} escape-string-regexp@1.0.5: {} @@ -4810,6 +4891,10 @@ snapshots: md5.js: 1.3.5 safe-buffer: 5.2.1 + expand-template@2.0.3: {} + + extra-bigint@1.2.0: {} + fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} @@ -4834,12 +4919,12 @@ snapshots: dependencies: '@openzeppelin/contracts': 5.0.2 - fhevmjs@0.5.7: + fhevmjs@0.5.7(encoding@0.1.13): dependencies: '@types/keccak': 3.0.5 bigint-buffer: 1.1.5 commander: 11.1.0 - node-fetch: 2.7.0 + node-fetch: 2.7.0(encoding@0.1.13) node-tfhe: 0.6.4 sha3: 2.1.4 tfhe: 0.6.4 @@ -4907,13 +4992,7 @@ snapshots: fp-ts@1.19.3: {} - fs-extra@0.30.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 2.4.0 - klaw: 1.3.1 - path-is-absolute: 1.0.1 - rimraf: 2.7.1 + fs-constants@1.0.0: {} fs-extra@10.1.0: dependencies: @@ -4940,6 +5019,10 @@ snapshots: jsonfile: 6.1.0 universalify: 2.0.1 + fs-minipass@2.1.0: + dependencies: + minipass: 3.3.6 + fs-readdir-recursive@1.1.0: {} fs.realpath@1.0.0: {} @@ -4949,14 +5032,17 @@ snapshots: function-bind@1.1.2: {} - function.prototype.name@1.1.6: + gauge@4.0.4: dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.22.5 - functions-have-names: 1.2.3 - - functions-have-names@1.2.3: {} + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + optional: true get-caller-file@2.0.5: {} @@ -4972,17 +5058,13 @@ snapshots: get-port@3.2.0: {} - get-symbol-description@1.0.2: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - ghost-testrpc@0.0.2: dependencies: chalk: 2.4.2 node-emoji: 1.11.0 + github-from-package@0.0.0: {} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -5057,10 +5139,6 @@ snapshots: dependencies: type-fest: 0.20.2 - globalthis@1.0.3: - dependencies: - define-properties: 1.2.1 - globby@10.0.2: dependencies: '@types/glob': 7.2.0 @@ -5129,11 +5207,11 @@ snapshots: - supports-color - utf-8-validate - hardhat-gas-reporter@1.0.10(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): + hardhat-gas-reporter@1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): dependencies: array-uniq: 1.0.3 eth-gas-reporter: 0.2.27 - hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) sha1: 1.1.1 transitivePeerDependencies: - '@codechecks/client' @@ -5147,16 +5225,16 @@ snapshots: node-interval-tree: 2.1.2 solidity-comments: 0.0.2 - hardhat-preprocessor@0.1.5(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): + hardhat-preprocessor@0.1.5(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): dependencies: - hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) murmur-128: 0.2.1 - hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2): + hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2): dependencies: '@ethersproject/abi': 5.7.0 '@metamask/eth-sig-util': 4.0.1 - '@nomicfoundation/edr': 0.2.1 + '@nomicfoundation/edr': 0.6.4 '@nomicfoundation/ethereumjs-common': 4.0.4 '@nomicfoundation/ethereumjs-tx': 5.0.4 '@nomicfoundation/ethereumjs-util': 9.0.4 @@ -5169,7 +5247,7 @@ snapshots: ansi-escapes: 4.3.2 boxen: 5.1.2 chalk: 2.4.2 - chokidar: 3.6.0 + chokidar: 4.0.1 ci-info: 2.0.0 debug: 4.3.4(supports-color@8.1.1) enquirer: 2.4.1 @@ -5182,6 +5260,7 @@ snapshots: glob: 7.2.0 immutable: 4.3.5 io-ts: 1.10.4 + json-stream-stringify: 3.1.6 keccak: 3.0.4 lodash: 4.17.21 mnemonist: 0.38.5 @@ -5190,7 +5269,7 @@ snapshots: raw-body: 2.5.2 resolve: 1.17.0 semver: 6.3.1 - solc: 0.7.3(debug@4.3.4) + solc: 0.8.26(debug@4.3.4) source-map-support: 0.5.21 stacktrace-parser: 0.1.10 tsort: 0.0.1 @@ -5206,8 +5285,6 @@ snapshots: - supports-color - utf-8-validate - has-bigints@1.0.2: {} - has-flag@1.0.0: {} has-flag@3.0.0: {} @@ -5226,6 +5303,9 @@ snapshots: dependencies: has-symbols: 1.0.3 + has-unicode@2.0.1: + optional: true + hash-base@3.1.0: dependencies: inherits: 2.0.4 @@ -5258,6 +5338,9 @@ snapshots: http-response-object: 3.0.2 parse-cache-control: 1.0.1 + http-cache-semantics@4.1.1: + optional: true + http-errors@2.0.0: dependencies: depd: 2.0.0 @@ -5266,6 +5349,15 @@ snapshots: statuses: 2.0.1 toidentifier: 1.0.1 + http-proxy-agent@4.0.1: + dependencies: + '@tootallnate/once': 1.1.2 + agent-base: 6.0.2 + debug: 4.3.4(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + optional: true + http-response-object@3.0.2: dependencies: '@types/node': 10.17.60 @@ -5277,10 +5369,20 @@ snapshots: transitivePeerDependencies: - supports-color + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + optional: true + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + optional: true + ieee754@1.2.1: {} ignore@5.3.1: {} @@ -5298,6 +5400,9 @@ snapshots: indent-string@4.0.0: {} + infer-owner@1.0.4: + optional: true + inflight@1.0.6: dependencies: once: 1.4.0 @@ -5307,53 +5412,35 @@ snapshots: ini@1.3.8: {} - internal-slot@1.0.7: - dependencies: - es-errors: 1.3.0 - hasown: 2.0.2 - side-channel: 1.0.6 - interpret@1.4.0: {} io-ts@1.10.4: dependencies: fp-ts: 1.19.3 - is-arguments@1.1.1: + ip-address@9.0.5: dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 + jsbn: 1.1.0 + sprintf-js: 1.1.3 + optional: true - is-array-buffer@3.0.4: + is-arguments@1.1.1: dependencies: call-bind: 1.0.7 - get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 is-arrayish@0.2.1: {} - is-bigint@1.0.4: - dependencies: - has-bigints: 1.0.2 - is-binary-path@2.1.0: dependencies: binary-extensions: 2.2.0 - is-boolean-object@1.1.2: - dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 - is-callable@1.2.7: {} is-core-module@2.13.1: dependencies: hasown: 2.0.2 - is-date-object@1.0.5: - dependencies: - has-tostringtag: 1.0.2 - is-extglob@2.1.1: {} is-fullwidth-code-point@2.0.0: {} @@ -5370,11 +5457,8 @@ snapshots: is-hex-prefixed@1.0.0: {} - is-negative-zero@2.0.3: {} - - is-number-object@1.0.7: - dependencies: - has-tostringtag: 1.0.2 + is-lambda@1.0.1: + optional: true is-number@7.0.0: {} @@ -5382,37 +5466,14 @@ snapshots: is-plain-obj@2.1.0: {} - is-regex@1.1.4: - dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 - - is-shared-array-buffer@1.0.3: - dependencies: - call-bind: 1.0.7 - - is-string@1.0.7: - dependencies: - has-tostringtag: 1.0.2 - - is-symbol@1.0.4: - dependencies: - has-symbols: 1.0.3 - is-typed-array@1.1.13: dependencies: which-typed-array: 1.1.15 is-unicode-supported@0.1.0: {} - is-weakref@1.0.2: - dependencies: - call-bind: 1.0.7 - isarray@1.0.0: {} - isarray@2.0.5: {} - isexe@2.0.0: {} javascript-natural-sort@0.7.1: {} @@ -5430,6 +5491,9 @@ snapshots: dependencies: argparse: 2.0.1 + jsbn@1.1.0: + optional: true + jsesc@2.5.2: {} json-buffer@3.0.1: {} @@ -5442,9 +5506,7 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} - jsonfile@2.4.0: - optionalDependencies: - graceful-fs: 4.2.11 + json-stream-stringify@3.1.6: {} jsonfile@4.0.0: optionalDependencies: @@ -5470,10 +5532,6 @@ snapshots: kind-of@6.0.3: {} - klaw@1.3.1: - optionalDependencies: - graceful-fs: 4.2.11 - levn@0.3.0: dependencies: prelude-ls: 1.1.2 @@ -5526,6 +5584,29 @@ snapshots: make-error@1.3.6: {} + make-fetch-happen@9.1.0: + dependencies: + agentkeepalive: 4.5.0 + cacache: 15.3.0 + http-cache-semantics: 4.1.1 + http-proxy-agent: 4.0.1 + https-proxy-agent: 5.0.1 + is-lambda: 1.0.1 + lru-cache: 6.0.0 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-fetch: 1.4.1 + minipass-flush: 1.0.5 + minipass-pipeline: 1.2.4 + negotiator: 0.6.4 + promise-retry: 2.0.1 + socks-proxy-agent: 6.2.1 + ssri: 8.0.1 + transitivePeerDependencies: + - bluebird + - supports-color + optional: true + markdown-table@1.1.3: {} match-all@1.2.6: {} @@ -5553,6 +5634,8 @@ snapshots: dependencies: mime-db: 1.52.0 + mimic-response@3.1.0: {} + minimalistic-assert@1.0.1: {} minimalistic-crypto-utils@1.0.1: {} @@ -5575,10 +5658,52 @@ snapshots: minimist@1.2.8: {} + minipass-collect@1.0.2: + dependencies: + minipass: 3.3.6 + optional: true + + minipass-fetch@1.4.1: + dependencies: + minipass: 3.3.6 + minipass-sized: 1.0.3 + minizlib: 2.1.2 + optionalDependencies: + encoding: 0.1.13 + optional: true + + minipass-flush@1.0.5: + dependencies: + minipass: 3.3.6 + optional: true + + minipass-pipeline@1.2.4: + dependencies: + minipass: 3.3.6 + optional: true + + minipass-sized@1.0.3: + dependencies: + minipass: 3.3.6 + optional: true + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + minipass@4.2.8: {} + minipass@5.0.0: {} + minipass@7.0.4: {} + minizlib@2.1.2: + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + + mkdirp-classic@0.5.3: {} + mkdirp@0.5.6: dependencies: minimist: 1.2.8 @@ -5622,24 +5747,54 @@ snapshots: fmix: 0.1.0 imul: 1.0.1 + napi-build-utils@1.0.2: {} + natural-compare-lite@1.4.0: {} natural-compare@1.4.0: {} + negotiator@0.6.4: + optional: true + neo-async@2.6.2: {} + node-abi@3.71.0: + dependencies: + semver: 7.6.0 + node-addon-api@2.0.2: {} + node-addon-api@7.1.1: {} + node-emoji@1.11.0: dependencies: lodash: 4.17.21 - node-fetch@2.7.0: + node-fetch@2.7.0(encoding@0.1.13): dependencies: whatwg-url: 5.0.0 + optionalDependencies: + encoding: 0.1.13 node-gyp-build@4.8.0: {} + node-gyp@8.4.1: + dependencies: + env-paths: 2.2.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + make-fetch-happen: 9.1.0 + nopt: 5.0.0 + npmlog: 6.0.2 + rimraf: 3.0.2 + semver: 7.6.0 + tar: 6.2.1 + which: 2.0.2 + transitivePeerDependencies: + - bluebird + - supports-color + optional: true + node-interval-tree@2.1.2: dependencies: shallowequal: 1.1.0 @@ -5652,8 +5807,21 @@ snapshots: dependencies: abbrev: 1.0.9 + nopt@5.0.0: + dependencies: + abbrev: 1.0.9 + optional: true + normalize-path@3.0.0: {} + npmlog@6.0.2: + dependencies: + are-we-there-yet: 3.0.1 + console-control-strings: 1.1.0 + gauge: 4.0.4 + set-blocking: 2.0.0 + optional: true + number-to-bn@1.7.0: dependencies: bn.js: 4.11.6 @@ -5663,15 +5831,6 @@ snapshots: object-inspect@1.13.1: {} - object-keys@1.1.1: {} - - object.assign@4.1.5: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - has-symbols: 1.0.3 - object-keys: 1.1.1 - obliterator@2.0.4: {} once@1.4.0: @@ -5770,6 +5929,21 @@ snapshots: possible-typed-array-names@1.0.0: {} + prebuild-install@7.1.2: + dependencies: + detect-libc: 2.0.3 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 1.0.2 + node-abi: 3.71.0 + pump: 3.0.2 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + prelude-ls@1.1.2: {} prelude-ls@1.2.1: {} @@ -5789,12 +5963,26 @@ snapshots: process-nextick-args@2.0.1: {} + promise-inflight@1.0.1: + optional: true + + promise-retry@2.0.1: + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + optional: true + promise@8.3.0: dependencies: asap: 2.0.6 proxy-from-env@1.1.0: {} + pump@3.0.2: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + punycode@1.4.1: {} punycode@2.3.1: {} @@ -5820,6 +6008,13 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -5840,6 +6035,8 @@ snapshots: dependencies: picomatch: 2.3.1 + readdirp@4.0.2: {} + rechoir@0.6.2: dependencies: resolve: 1.22.8 @@ -5850,13 +6047,6 @@ snapshots: reduce-flatten@2.0.0: {} - regexp.prototype.flags@1.5.2: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-errors: 1.3.0 - set-function-name: 2.0.2 - req-cwd@2.0.0: dependencies: req-from: 2.0.0 @@ -5885,11 +6075,10 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - reusify@1.0.4: {} + retry@0.12.0: + optional: true - rimraf@2.7.1: - dependencies: - glob: 7.2.3 + reusify@1.0.4: {} rimraf@3.0.2: dependencies: @@ -5912,23 +6101,10 @@ snapshots: dependencies: queue-microtask: 1.2.3 - safe-array-concat@1.1.2: - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - isarray: 2.0.5 - safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} - safe-regex-test@1.0.3: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-regex: 1.1.4 - safer-buffer@2.1.2: {} sc-istanbul@0.4.6: @@ -5968,6 +6144,9 @@ snapshots: dependencies: randombytes: 2.1.0 + set-blocking@2.0.0: + optional: true + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -5977,13 +6156,6 @@ snapshots: gopd: 1.0.1 has-property-descriptors: 1.0.2 - set-function-name@2.0.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 - setimmediate@1.0.5: {} setprototypeof@1.2.0: {} @@ -6023,6 +6195,17 @@ snapshots: get-intrinsic: 1.2.4 object-inspect: 1.13.1 + signal-exit@3.0.7: + optional: true + + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + slash@3.0.0: {} slice-ansi@4.0.0: @@ -6031,15 +6214,31 @@ snapshots: astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 - solc@0.7.3(debug@4.3.4): + smart-buffer@4.2.0: + optional: true + + socks-proxy-agent@6.2.1: + dependencies: + agent-base: 6.0.2 + debug: 4.3.4(supports-color@8.1.1) + socks: 2.8.3 + transitivePeerDependencies: + - supports-color + optional: true + + socks@2.8.3: + dependencies: + ip-address: 9.0.5 + smart-buffer: 4.2.0 + optional: true + + solc@0.8.26(debug@4.3.4): dependencies: command-exists: 1.2.9 - commander: 3.0.2 + commander: 8.3.0 follow-redirects: 1.15.5(debug@4.3.4) - fs-extra: 0.30.0 js-sha3: 0.8.0 memorystream: 0.3.1 - require-from-string: 2.0.2 semver: 5.7.2 tmp: 0.0.33 transitivePeerDependencies: @@ -6075,10 +6274,6 @@ snapshots: transitivePeerDependencies: - typescript - solidity-ast@0.4.55: - dependencies: - array.prototype.findlast: 1.2.4 - solidity-comments-darwin-arm64@0.0.2: optional: true @@ -6124,19 +6319,18 @@ snapshots: solidity-comments-win32-ia32-msvc: 0.0.2 solidity-comments-win32-x64-msvc: 0.0.2 - solidity-coverage@0.8.6(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): + solidity-coverage@0.8.12(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): dependencies: '@ethersproject/abi': 5.7.0 '@solidity-parser/parser': 0.18.0 chalk: 2.4.2 death: 1.1.0 - detect-port: 1.5.1 difflib: 0.2.4 fs-extra: 8.1.0 ghost-testrpc: 0.0.2 global-modules: 2.0.0 globby: 10.0.2 - hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) jsonschema: 1.4.1 lodash: 4.17.21 mocha: 10.3.0 @@ -6147,14 +6341,6 @@ snapshots: semver: 7.6.0 shelljs: 0.8.5 web3-utils: 1.10.4 - transitivePeerDependencies: - - supports-color - - solidity-docgen@0.6.0-beta.36(hardhat@2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): - dependencies: - handlebars: 4.7.8 - hardhat: 2.21.0(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) - solidity-ast: 0.4.55 source-map-support@0.5.21: dependencies: @@ -6172,6 +6358,26 @@ snapshots: sprintf-js@1.0.3: {} + sprintf-js@1.1.3: + optional: true + + sqlite3@5.1.7: + dependencies: + bindings: 1.5.0 + node-addon-api: 7.1.1 + prebuild-install: 7.1.2 + tar: 6.2.1 + optionalDependencies: + node-gyp: 8.4.1 + transitivePeerDependencies: + - bluebird + - supports-color + + ssri@8.0.1: + dependencies: + minipass: 3.3.6 + optional: true + stacktrace-parser@0.1.10: dependencies: type-fest: 0.7.1 @@ -6191,24 +6397,6 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - string.prototype.trim@1.2.8: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.22.5 - - string.prototype.trimend@1.0.7: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.22.5 - - string.prototype.trimstart@1.0.7: - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.22.5 - string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 @@ -6229,6 +6417,8 @@ snapshots: dependencies: is-hex-prefixed: 1.0.0 + strip-json-comments@2.0.1: {} + strip-json-comments@3.1.1: {} supports-color@3.2.3: @@ -6274,6 +6464,30 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + tar-fs@2.1.1: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.2 + tar-stream: 2.2.0 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + tar@6.2.1: + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + text-table@0.2.0: {} tfhe@0.6.4: {} @@ -6360,6 +6574,10 @@ snapshots: tslib: 1.14.1 typescript: 5.4.2 + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + tweetnacl-util@0.15.1: {} tweetnacl@1.0.3: {} @@ -6396,38 +6614,6 @@ snapshots: transitivePeerDependencies: - supports-color - typed-array-buffer@1.0.2: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-typed-array: 1.1.13 - - typed-array-byte-length@1.0.1: - dependencies: - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 - is-typed-array: 1.1.13 - - typed-array-byte-offset@1.0.2: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 - is-typed-array: 1.1.13 - - typed-array-length@1.0.5: - dependencies: - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 - is-typed-array: 1.1.13 - possible-typed-array-names: 1.0.0 - typedarray@0.0.6: {} typescript@5.4.2: {} @@ -6439,19 +6625,22 @@ snapshots: uglify-js@3.17.4: optional: true - unbox-primitive@1.0.2: - dependencies: - call-bind: 1.0.7 - has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 - undici-types@5.26.5: {} undici@5.28.3: dependencies: '@fastify/busboy': 2.1.1 + unique-filename@1.1.1: + dependencies: + unique-slug: 2.0.2 + optional: true + + unique-slug@2.0.2: + dependencies: + imurmurhash: 0.1.4 + optional: true + universalify@0.1.2: {} universalify@2.0.1: {} @@ -6515,14 +6704,6 @@ snapshots: tr46: 0.0.3 webidl-conversions: 3.0.1 - which-boxed-primitive@1.0.2: - dependencies: - is-bigint: 1.0.4 - is-boolean-object: 1.1.2 - is-number-object: 1.0.7 - is-string: 1.0.7 - is-symbol: 1.0.4 - which-typed-array@1.1.15: dependencies: available-typed-arrays: 1.0.7 @@ -6539,6 +6720,11 @@ snapshots: dependencies: isexe: 2.0.0 + wide-align@1.1.5: + dependencies: + string-width: 4.2.3 + optional: true + widest-line@3.1.0: dependencies: string-width: 4.2.3 From 21c073f156be1290c303423dad1a0a7b6d1e4543 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:06:34 +0200 Subject: [PATCH 13/73] feat: IEncryptedERC20 and EncryptedERC20 --- contracts/test/TestEncryptedERC20Mintable.sol | 35 +++ contracts/token/ERC20/EncryptedERC20.sol | 283 ++++++++---------- contracts/token/ERC20/IEncryptedERC20.sol | 83 +++++ .../extensions/EncryptedERC20Mintable.sol | 19 -- 4 files changed, 250 insertions(+), 170 deletions(-) create mode 100644 contracts/test/TestEncryptedERC20Mintable.sol create mode 100644 contracts/token/ERC20/IEncryptedERC20.sol delete mode 100644 contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol diff --git a/contracts/test/TestEncryptedERC20Mintable.sol b/contracts/test/TestEncryptedERC20Mintable.sol new file mode 100644 index 0000000..addb494 --- /dev/null +++ b/contracts/test/TestEncryptedERC20Mintable.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import "fhevm/lib/TFHE.sol"; +import { EncryptedERC20 } from "../token/ERC20/EncryptedERC20.sol"; + +/** + * @title TestEncryptedERC20Mintable + * @notice This test contract inherits EncryptedERC20. + * @dev It allows any account to mint tokens. Mint amounts are public. + */ +contract TestEncryptedERC20Mintable is EncryptedERC20 { + /** + * @notice Emitted when `amount` tokens are minted to one account (`to`). + */ + event Mint(address indexed to, uint64 amount); + + /** + * @param name_ Name of the token. + * @param symbol_ Symbol. + */ + constructor(string memory name_, string memory symbol_) EncryptedERC20(name_, symbol_) {} + + /** + * @notice Mint tokens. + * @param amount Amount of tokens to mint. + */ + function mint(uint64 amount) public { + _balances[msg.sender] = TFHE.add(_balances[msg.sender], amount); // overflow impossible because of next line + TFHE.allow(_balances[msg.sender], address(this)); + TFHE.allow(_balances[msg.sender], msg.sender); + _totalSupply = _totalSupply + amount; + emit Mint(msg.sender, amount); + } +} diff --git a/contracts/token/ERC20/EncryptedERC20.sol b/contracts/token/ERC20/EncryptedERC20.sol index 0633959..cb9ec57 100644 --- a/contracts/token/ERC20/EncryptedERC20.sol +++ b/contracts/token/ERC20/EncryptedERC20.sol @@ -1,201 +1,182 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear - pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; -import "fhevm/abstracts/Reencrypt.sol"; -import "../../utils/EncryptedErrors.sol"; +import { IEncryptedERC20 } from "./IEncryptedERC20.sol"; -abstract contract EncryptedERC20 is Reencrypt, EncryptedErrors { - enum ErrorCodes { - NO_ERROR, - UNSUFFICIENT_BALANCE, - UNSUFFICIENT_APPROVAL - } +/** + * @title EncryptedERC20 + */ +abstract contract EncryptedERC20 is IEncryptedERC20 { + /// @notice Number of decimals. + uint8 internal constant _DECIMALS = 6; - struct AllowedErrorReencryption { - address spender; // account's address allowed to reencrypt errorCode - euint8 errorCode; - } + /// @notice Total supply. + uint64 internal _totalSupply; - event Transfer(uint256 indexed transferId, address indexed from, address indexed to); - event Approval(address indexed owner, address indexed spender); - event Mint(address indexed to, uint64 amount); + /// @notice Name. + string internal _name; - uint64 internal _totalSupply; - string private _name; - string private _symbol; - uint8 public constant decimals = 6; + /// @notice Symbol. + string internal _symbol; - // A mapping from transferId to the AllowedErrorReencryption. - mapping(uint256 => AllowedErrorReencryption) internal allowedErrorReencryptions; + /// @notice A mapping from `account` address to an encrypted `balance`. + mapping(address account => euint64 balance) internal _balances; - // A mapping from address to an encrypted balance. - mapping(address => euint64) internal balances; + /// @notice A mapping of the form mapping(account => mapping(spender => allowance)). + mapping(address account => mapping(address spender => euint64 allowance)) internal _allowances; - // A mapping of the form mapping(owner => mapping(spender => allowance)). - mapping(address => mapping(address => euint64)) internal allowances; + /** + * @notice Error when the `sender` is not allowed to access a value. + */ + error TFHESenderNotAllowed(); - constructor(string memory name_, string memory symbol_) EncryptedErrors(uint8(type(ErrorCodes).max)) { + /** + * @param name_ Name of the token. + * @param symbol_ Symbol. + */ + constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } - // Returns the name of the token. - function name() public view virtual returns (string memory) { - return _name; + /** + * @notice See {IEncryptedERC20-approve}. + */ + function approve(address spender, einput encryptedAmount, bytes calldata inputProof) public virtual returns (bool) { + approve(spender, TFHE.asEuint64(encryptedAmount, inputProof)); + return true; } - // Returns the symbol of the token, usually a shorter version of the name. - function symbol() public view virtual returns (string memory) { - return _symbol; + /** + * @notice See {IEncryptedERC20-approve}. + */ + function approve(address spender, euint64 amount) public virtual returns (bool) { + _isSenderAllowedForAmount(amount); + address owner = msg.sender; + _approve(owner, spender, amount); + emit Approval(owner, spender); + return true; } - // Returns the total supply of the token. - function totalSupply() public view virtual returns (uint64) { - return _totalSupply; + /** + * @notice See {IEncryptedERC20-transfer}. + */ + function transfer(address to, einput encryptedAmount, bytes calldata inputProof) public virtual returns (bool) { + transfer(to, TFHE.asEuint64(encryptedAmount, inputProof)); + return true; } - // Increase sender's balance by the given `amount`. - function _mint(uint64 amount, address to) internal virtual { - balances[to] = TFHE.add(balances[to], amount); // overflow impossible because of next line - _totalSupply = _totalSupply + amount; - emit Mint(to, amount); - } + /** + * @notice See {IEncryptedERC20-transfer}. + */ + function transfer(address to, euint64 amount) public virtual returns (bool) { + _isSenderAllowedForAmount(amount); - // Transfers an encrypted amount from the message sender address to the `to` address. - function transfer(address to, bytes calldata encryptedAmount) public virtual returns (bool) { - transfer(to, TFHE.asEuint64(encryptedAmount)); + // Make sure the owner has enough tokens + ebool canTransfer = TFHE.le(amount, _balances[msg.sender]); + _transfer(msg.sender, to, amount, canTransfer); return true; } - // Transfers an amount from the message sender address to the `to` address. - function transfer(address to, euint64 amount) public virtual returns (bool) { - // makes sure the owner has enough tokens - ebool canTransfer = TFHE.le(amount, balances[msg.sender]); - euint8 errorCode = defineErrorIfNot(canTransfer, uint8(ErrorCodes.UNSUFFICIENT_BALANCE)); - _transfer(msg.sender, to, amount, canTransfer, errorCode); + /** + * @notice See {IEncryptedERC20-transferFrom}. + */ + function transferFrom( + address from, + address to, + einput encryptedAmount, + bytes calldata inputProof + ) public virtual returns (bool) { + transferFrom(from, to, TFHE.asEuint64(encryptedAmount, inputProof)); return true; } - // Returns the balance of the caller encrypted under the provided public key. - function balanceOf( - address wallet, - bytes32 publicKey, - bytes calldata signature - ) public view virtual onlySignedPublicKey(publicKey, signature) returns (bytes memory) { - require(wallet == msg.sender, "User cannot reencrypt a non-owned wallet balance"); - return TFHE.reencrypt(balances[wallet], publicKey, 0); + /** + * @notice See {IEncryptedERC20-transferFrom}. + */ + function transferFrom(address from, address to, euint64 amount) public virtual returns (bool) { + _isSenderAllowedForAmount(amount); + address spender = msg.sender; + ebool isTransferable = _updateAllowance(from, spender, amount); + _transfer(from, to, amount, isTransferable); + return true; } - // Returns the encrypted balance of the caller. - function balanceOfMe() public view virtual returns (euint64) { - return balances[msg.sender]; + /** + * @notice See {IEncryptedERC20-allowance}. + */ + function allowance(address owner, address spender) public view virtual returns (euint64) { + return _allowance(owner, spender); } - // Sets the `encryptedAmount` as the allowance of `spender` over the caller's tokens. - function approve(address spender, bytes calldata encryptedAmount) public virtual returns (bool) { - approve(spender, TFHE.asEuint64(encryptedAmount)); - return true; + /** + * @notice See {IEncryptedERC20-balanceOf}. + */ + function balanceOf(address account) public view virtual returns (euint64) { + return _balances[account]; } - // Sets the `amount` as the allowance of `spender` over the caller's tokens. - function approve(address spender, euint64 amount) public virtual returns (bool) { - address owner = msg.sender; - _approve(owner, spender, amount); - emit Approval(owner, spender); - return true; + /** + * @notice See {IEncryptedERC20-name}. + */ + function name() public view virtual returns (string memory) { + return _name; } - // Returns the remaining number of tokens that `spender` is allowed to spend - // on behalf of the `owner`. The returned ciphertext is under the caller's `publicKey`. - function allowance( - address owner, - address spender, - bytes32 publicKey, - bytes calldata signature - ) public view virtual onlySignedPublicKey(publicKey, signature) returns (bytes memory) { - require(owner == msg.sender || spender == msg.sender, "Caller must be owner or spender"); - return TFHE.reencrypt(_allowance(owner, spender), publicKey); + /** + * @notice See {IEncryptedERC20-symbol}. + */ + function symbol() public view virtual returns (string memory) { + return _symbol; } - // Transfers `encryptedAmount` tokens using the caller's allowance. - function transferFrom(address from, address to, bytes calldata encryptedAmount) public virtual returns (bool) { - transferFrom(from, to, TFHE.asEuint64(encryptedAmount)); - return true; + /** + * @notice See {IEncryptedERC20-totalSupply}. + */ + function totalSupply() public view virtual returns (uint64) { + return _totalSupply; } - // Transfers `amount` tokens using the caller's allowance. - function transferFrom(address from, address to, euint64 amount) public virtual returns (bool) { - address spender = msg.sender; - (ebool isTransferable, euint8 errorCode) = _updateAllowance(from, spender, amount); - _transfer(from, to, amount, isTransferable, errorCode); - return true; + function _approve(address owner, address spender, euint64 amount) internal virtual { + _allowances[owner][spender] = amount; + TFHE.allow(amount, address(this)); + TFHE.allow(amount, owner); + TFHE.allow(amount, spender); } - function _approve(address owner, address spender, euint64 amount) internal virtual { - allowances[owner][spender] = amount; + function _transfer(address from, address to, euint64 amount, ebool isTransferable) internal virtual { + // Add to the balance of `to` and subract from the balance of `from`. + euint64 transferValue = TFHE.select(isTransferable, amount, TFHE.asEuint64(0)); + euint64 newBalanceTo = TFHE.add(_balances[to], transferValue); + _balances[to] = newBalanceTo; + TFHE.allow(newBalanceTo, address(this)); + TFHE.allow(newBalanceTo, to); + euint64 newBalanceFrom = TFHE.sub(_balances[from], transferValue); + _balances[from] = newBalanceFrom; + TFHE.allow(newBalanceFrom, address(this)); + TFHE.allow(newBalanceFrom, from); + emit Transfer(from, to); + } + + function _updateAllowance(address owner, address spender, euint64 amount) internal virtual returns (ebool) { + euint64 currentAllowance = _allowance(owner, spender); + // Make sure sure the allowance suffices + ebool allowedTransfer = TFHE.le(amount, currentAllowance); + // Make sure the owner has enough tokens + ebool canTransfer = TFHE.le(amount, _balances[owner]); + ebool isTransferable = TFHE.and(canTransfer, allowedTransfer); + _approve(owner, spender, TFHE.select(isTransferable, TFHE.sub(currentAllowance, amount), currentAllowance)); + return isTransferable; } function _allowance(address owner, address spender) internal view virtual returns (euint64) { - if (TFHE.isInitialized(allowances[owner][spender])) { - return allowances[owner][spender]; - } else { - return TFHE.asEuint64(0); - } + return _allowances[owner][spender]; } - function _updateAllowance(address owner, address spender, euint64 amount) internal virtual returns (ebool, euint8) { - euint64 currentAllowance = _allowance(owner, spender); - // makes sure the allowance suffices - ebool allowedTransfer = TFHE.le(amount, currentAllowance); - euint8 errorCode = defineErrorIfNot(allowedTransfer, uint8(ErrorCodes.UNSUFFICIENT_APPROVAL)); - // makes sure the owner has enough tokens - ebool canTransfer = TFHE.le(amount, balances[owner]); - ebool isTransferable = TFHE.and(canTransfer, allowedTransfer); - _approve(owner, spender, TFHE.select(isTransferable, currentAllowance - amount, currentAllowance)); - ebool isNotTransferableButIsApproved = TFHE.and(TFHE.not(canTransfer), allowedTransfer); - errorCode = changeErrorIf( - isNotTransferableButIsApproved, // should indeed check that spender is approved to not leak information - // on balance of `from` to unauthorized spender via calling reencryptTransferError afterwards - uint8(ErrorCodes.UNSUFFICIENT_BALANCE), - errorCode - ); - return (isTransferable, errorCode); - } - - // Transfers an encrypted amount. - function _transfer( - address from, - address to, - euint64 amount, - ebool isTransferable, - euint8 errorCode - ) internal virtual { - // Add to the balance of `to` and subract from the balance of `from`. - euint64 amountTransferred = TFHE.select(isTransferable, amount, TFHE.asEuint64(0)); - balances[to] = balances[to] + amountTransferred; - balances[from] = balances[from] - amountTransferred; - uint256 transferId = saveError(errorCode); - emit Transfer(transferId, from, to); - AllowedErrorReencryption memory allowedErrorReencryption = AllowedErrorReencryption( - msg.sender, - getError(transferId) - ); - allowedErrorReencryptions[transferId] = allowedErrorReencryption; - } - - // Returns the error code corresponding to transferId. - // The returned ciphertext is under the caller's `publicKey`. - function reencryptError( - uint256 transferId, - bytes32 publicKey, - bytes calldata signature - ) external view virtual onlySignedPublicKey(publicKey, signature) returns (bytes memory) { - AllowedErrorReencryption memory allowedErrorReencryption = allowedErrorReencryptions[transferId]; - euint8 errorCode = allowedErrorReencryption.errorCode; - require(TFHE.isInitialized(errorCode), "Invalid transferId"); - require(msg.sender == allowedErrorReencryption.spender, "Only spender can reencrypt his error"); - return TFHE.reencrypt(errorCode, publicKey); + function _isSenderAllowedForAmount(euint64 amount) internal view { + if (!TFHE.isSenderAllowed(amount)) { + revert TFHESenderNotAllowed(); + } } } diff --git a/contracts/token/ERC20/IEncryptedERC20.sol b/contracts/token/ERC20/IEncryptedERC20.sol new file mode 100644 index 0000000..b066b41 --- /dev/null +++ b/contracts/token/ERC20/IEncryptedERC20.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.24; + +import "fhevm/lib/TFHE.sol"; + +/** + * @title IEncryptedERC20 + * @notice Interface that defines ERC20-like tokens with encrypted balances. + */ +interface IEncryptedERC20 { + /** + * @notice Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. + */ + event Approval(address indexed owner, address indexed spender); + + /** + * @notice Emitted when tokens are moved from one account (`from`) to + * another (`to`). + */ + event Transfer(address indexed from, address indexed to); + + /** + * @notice Sets the `encryptedAmount` as the allowance of `spender` over the caller's tokens. + */ + function approve(address spender, einput encryptedAmount, bytes calldata inputProof) external returns (bool); + + /** + * @notice Sets the `amount` as the allowance of `spender` over the caller's tokens. + */ + function approve(address spender, euint64 amount) external returns (bool); + + /** + * @notice Transfers an encrypted amount from the message sender address to the `to` address. + */ + function transfer(address to, einput encryptedAmount, bytes calldata inputProof) external returns (bool); + + /** + * @notice Transfers an amount from the message sender address to the `to` address. + */ + function transfer(address to, euint64 amount) external returns (bool); + + /** + * @notice Transfers `amount` tokens using the caller's allowance. + */ + function transferFrom(address from, address to, euint64 amount) external returns (bool); + + /** + * @notice Transfers `encryptedAmount` tokens using the caller's allowance. + */ + function transferFrom( + address from, + address to, + einput encryptedAmount, + bytes calldata inputProof + ) external returns (bool); + + /** + * @notice Returns the remaining number of tokens that `spender` is allowed to spend + on behalf of the caller. + */ + function allowance(address owner, address spender) external view returns (euint64); + + /** + * @notice Returns the balance handle of the caller. + */ + function balanceOf(address wallet) external view returns (euint64); + + /** + * @notice Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @notice Returns the symbol of the token, usually a shorter version of the name. + */ + function symbol() external view returns (string memory); + + /** + * @notice Returns the total supply of the token. + */ + function totalSupply() external view returns (uint64); +} diff --git a/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol b/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol deleted file mode 100644 index cc330ae..0000000 --- a/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause-Clear - -pragma solidity ^0.8.24; - -import "../EncryptedERC20.sol"; -import "@openzeppelin/contracts/access/Ownable2Step.sol"; - -contract EncryptedERC20Mintable is Ownable2Step, EncryptedERC20 { - constructor( - string memory name_, - string memory symbol_, - address owner - ) Ownable(owner) EncryptedERC20(name_, symbol_) {} - - // Increase owner's balance by the given `mintedAmount`. - function mint(uint64 mintedAmount, address to) public virtual onlyOwner { - _mint(mintedAmount, to); - } -} From 133c420195141ad8398c03184b63e84941acdb04 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:08:41 +0200 Subject: [PATCH 14/73] refactor: TestAsyncDecrypt --- .../TestAsyncDecrypt.sol | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) rename contracts/{asyncDecrypt => test}/TestAsyncDecrypt.sol (96%) diff --git a/contracts/asyncDecrypt/TestAsyncDecrypt.sol b/contracts/test/TestAsyncDecrypt.sol similarity index 96% rename from contracts/asyncDecrypt/TestAsyncDecrypt.sol rename to contracts/test/TestAsyncDecrypt.sol index 0fd8c03..8110011 100644 --- a/contracts/asyncDecrypt/TestAsyncDecrypt.sol +++ b/contracts/test/TestAsyncDecrypt.sol @@ -1,21 +1,24 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear - pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; import "fhevm/gateway/GatewayCaller.sol"; +/** + * @title TestAsyncDecrypt + * @notice This test contract is used to test the Gateway. + */ contract TestAsyncDecrypt is GatewayCaller { - ebool xBool; - euint4 xUint4; - euint8 xUint8; - euint16 xUint16; - euint32 xUint32; - euint64 xUint64; - euint64 xUint64_2; - euint64 xUint64_3; - eaddress xAddress; - eaddress xAddress2; + ebool internal xBool; + euint4 internal xUint4; + euint8 internal xUint8; + euint16 internal xUint16; + euint32 internal xUint32; + euint64 internal xUint64; + euint64 internal xUint64_2; + euint64 internal xUint64_3; + eaddress internal xAddress; + eaddress internal xAddress2; bool public yBool; uint8 public yUint4; From 0c9621eb593a33744076d6bee63f4e9367fc1d73 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:10:16 +0200 Subject: [PATCH 15/73] refactor: Test helpers for v0.5 --- test/asyncDecrypt.ts | 438 +++--------- test/coprocessorUtils.ts | 893 ++++++++++++++++++++++++ test/fhevmjsMocked.ts | 302 ++++++++ test/gatewayDecrypt/testAsyncDecrypt.ts | 217 ++++++ test/instance.ts | 251 +++++-- test/types.ts | 10 + test/utils.ts | 36 +- 7 files changed, 1722 insertions(+), 425 deletions(-) create mode 100644 test/coprocessorUtils.ts create mode 100644 test/fhevmjsMocked.ts create mode 100644 test/gatewayDecrypt/testAsyncDecrypt.ts diff --git a/test/asyncDecrypt.ts b/test/asyncDecrypt.ts index bee5804..7dff151 100644 --- a/test/asyncDecrypt.ts +++ b/test/asyncDecrypt.ts @@ -1,405 +1,157 @@ import dotenv from "dotenv"; import fs from "fs"; -import { ethers } from "hardhat"; +import { ethers, network } from "hardhat"; -import { OraclePredeploy } from "../../types"; +import { GatewayContract } from "../types"; +import { awaitCoprocessor, getClearText } from "./coprocessorUtils"; import { waitNBlocks } from "./utils"; -const network = process.env.HARDHAT_NETWORK; +const networkName = network.name; + +const parsedEnvACL = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.acl")); +const aclAdd = parsedEnvACL.ACL_CONTRACT_ADDRESS.replace(/^0x/, "").replace(/^0+/, "").toLowerCase(); + +const CiphertextType = { + 0: "bool", + 1: "uint8", // corresponding to euint4 + 2: "uint8", // corresponding to euint8 + 3: "uint16", + 4: "uint32", + 5: "uint64", + 6: "uint128", + 7: "address", + 11: "bytes", +}; const currentTime = (): string => { const now = new Date(); return now.toLocaleTimeString("en-US", { hour12: true, hour: "numeric", minute: "numeric", second: "numeric" }); }; -const parsedEnv = dotenv.parse(fs.readFileSync("node_modules/fhevm/oracle/.env.oracle")); -const privKeyRelayer = process.env.PRIVATE_KEY_ORACLE_RELAYER; +const parsedEnv = dotenv.parse(fs.readFileSync("node_modules/fhevm/gateway/.env.gateway")); +const privKeyRelayer = process.env.PRIVATE_KEY_GATEWAY_RELAYER; const relayer = new ethers.Wallet(privKeyRelayer!, ethers.provider); const argEvents = - "(uint256 indexed requestID, uint256[] cts, address contractCaller, bytes4 callbackSelector, uint256 msgValue, uint256 maxTimestamp)"; -const ifaceEventDecryptionEBool = new ethers.Interface(["event EventDecryptionEBool" + argEvents]); -const ifaceEventDecryptionEUint4 = new ethers.Interface(["event EventDecryptionEUint4" + argEvents]); -const ifaceEventDecryptionEUint8 = new ethers.Interface(["event EventDecryptionEUint8" + argEvents]); -const ifaceEventDecryptionEUint16 = new ethers.Interface(["event EventDecryptionEUint16" + argEvents]); -const ifaceEventDecryptionEUint32 = new ethers.Interface(["event EventDecryptionEUint32" + argEvents]); -const ifaceEventDecryptionEUint64 = new ethers.Interface(["event EventDecryptionEUint64" + argEvents]); -const ifaceEventDecryptionEAddress = new ethers.Interface(["event EventDecryptionEAddress" + argEvents]); + "(uint256 indexed requestID, uint256[] cts, address contractCaller, bytes4 callbackSelector, uint256 msgValue, uint256 maxTimestamp, bool passSignaturesToCaller)"; +const ifaceEventDecryption = new ethers.Interface(["event EventDecryption" + argEvents]); const argEvents2 = "(uint256 indexed requestID, bool success, bytes result)"; -const ifaceResultCallbackBool = new ethers.Interface(["event ResultCallbackBool" + argEvents2]); -const ifaceResultCallbackUint4 = new ethers.Interface(["event ResultCallbackUint4" + argEvents2]); -const ifaceResultCallbackUint8 = new ethers.Interface(["event ResultCallbackUint8" + argEvents2]); -const ifaceResultCallbackUint16 = new ethers.Interface(["event ResultCallbackUint16" + argEvents2]); -const ifaceResultCallbackUint32 = new ethers.Interface(["event ResultCallbackUint32" + argEvents2]); -const ifaceResultCallbackUint64 = new ethers.Interface(["event ResultCallbackUint64" + argEvents2]); -const ifaceResultcallbackAddress = new ethers.Interface(["event ResultcallbackAddress" + argEvents2]); +const ifaceResultCallback = new ethers.Interface(["event ResultCallback" + argEvents2]); -let oracle: OraclePredeploy; +let gateway: GatewayContract; let firstBlockListening: number; +let lastBlockSnapshotForDecrypt: number; export const asyncDecrypt = async (): Promise => { firstBlockListening = await ethers.provider.getBlockNumber(); + if (networkName === "hardhat" && hre.__SOLIDITY_COVERAGE_RUNNING !== true) { + // evm_snapshot is not supported in coverage mode + await ethers.provider.send("set_lastBlockSnapshotForDecrypt", [firstBlockListening]); + } // this function will emit logs for every request and fulfilment of a decryption - oracle = await ethers.getContractAt("OraclePredeploy", parsedEnv.ORACLE_CONTRACT_PREDEPLOY_ADDRESS); - oracle.on( - "EventDecryptionEBool", - async (requestID, cts, contractCaller, callbackSelector, msgValue, maxTimestamp, eventData) => { - const blockNumber = eventData.log.blockNumber; - console.log(`${await currentTime()} - Requested ebool decrypt on block ${blockNumber} (requestID ${requestID})`); - }, - ); - oracle.on("ResultCallbackBool", async (requestID, success, result, eventData) => { - const blockNumber = eventData.log.blockNumber; - console.log(`${await currentTime()} - Fulfilled ebool decrypt on block ${blockNumber} (requestID ${requestID})`); - }); - oracle.on( - "EventDecryptionEUint4", - async (requestID, cts, contractCaller, callbackSelector, msgValue, maxTimestamp, eventData) => { - const blockNumber = eventData.log.blockNumber; - console.log(`${await currentTime()} - Requested euint4 decrypt on block ${blockNumber} (requestID ${requestID})`); - }, + gateway = await ethers.getContractAt( + "fhevm/gateway/GatewayContract.sol:GatewayContract", + parsedEnv.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS, ); - oracle.on("ResultCallbackUint4", async (requestID, success, result, eventData) => { - const blockNumber = eventData.log.blockNumber; - console.log(`${await currentTime()} - Fulfilled euint4 decrypt on block ${blockNumber} (requestID ${requestID})`); - }); - oracle.on( - "EventDecryptionEUint8", + await gateway.on( + "EventDecryption", async (requestID, cts, contractCaller, callbackSelector, msgValue, maxTimestamp, eventData) => { const blockNumber = eventData.log.blockNumber; - console.log(`${await currentTime()} - Requested euint8 decrypt on block ${blockNumber} (requestID ${requestID})`); + console.log(`${await currentTime()} - Requested decrypt on block ${blockNumber} (requestID ${requestID})`); }, ); - oracle.on("ResultCallbackUint8", async (requestID, success, result, eventData) => { + await gateway.on("ResultCallback", async (requestID, success, result, eventData) => { const blockNumber = eventData.log.blockNumber; - console.log(`${await currentTime()} - Fulfilled euint8 decrypt on block ${blockNumber} (requestID ${requestID})`); - }); - oracle.on( - "EventDecryptionEUint16", - async (requestID, cts, contractCaller, callbackSelector, msgValue, maxTimestamp, eventData) => { - const blockNumber = eventData.log.blockNumber; - console.log( - `${await currentTime()} - Requested euint16 decrypt on block ${blockNumber} (requestID ${requestID})`, - ); - }, - ); - oracle.on("ResultCallbackUint16", async (requestID, success, result, eventData) => { - const blockNumber = eventData.log.blockNumber; - console.log(`${await currentTime()} - Fulfilled euint16 decrypt on block ${blockNumber} (requestID ${requestID})`); - }); - oracle.on( - "EventDecryptionEUint32", - async (requestID, cts, contractCaller, callbackSelector, msgValue, maxTimestamp, eventData) => { - const blockNumber = eventData.log.blockNumber; - console.log( - `${await currentTime()} - Requested euint32 decrypt on block ${blockNumber} (requestID ${requestID})`, - ); - }, - ); - oracle.on("ResultCallbackUint32", async (requestID, success, result, eventData) => { - const blockNumber = eventData.log.blockNumber; - console.log(`${await currentTime()} - Fulfilled euint32 decrypt on block ${blockNumber} (requestID ${requestID})`); - }); - oracle.on( - "EventDecryptionEUint64", - async (requestID, cts, contractCaller, callbackSelector, msgValue, maxTimestamp, eventData) => { - const blockNumber = eventData.log.blockNumber; - console.log( - `${await currentTime()} - Requested euint64 decrypt on block ${blockNumber} (requestID ${requestID})`, - ); - }, - ); - oracle.on("ResultCallbackUint64", async (requestID, success, result, eventData) => { - const blockNumber = eventData.log.blockNumber; - console.log(`${await currentTime()} - Fulfilled euint64 decrypt on block ${blockNumber} (requestID ${requestID})`); - }); - - oracle.on( - "EventDecryptionEAddress", - async (requestID, cts, contractCaller, callbackSelector, msgValue, maxTimestamp, eventData) => { - const blockNumber = eventData.log.blockNumber; - console.log( - `${await currentTime()} - Requested eaddress decrypt on block ${blockNumber} (requestID ${requestID})`, - ); - }, - ); - oracle.on("ResultcallbackAddress", async (requestID, success, result, eventData) => { - const blockNumber = eventData.log.blockNumber; - console.log(`${await currentTime()} - Fulfilled eaddress decrypt on block ${blockNumber} (requestID ${requestID})`); + console.log(`${await currentTime()} - Fulfilled decrypt on block ${blockNumber} (requestID ${requestID})`); }); }; export const awaitAllDecryptionResults = async (): Promise => { - oracle = await ethers.getContractAt("OraclePredeploy", parsedEnv.ORACLE_CONTRACT_PREDEPLOY_ADDRESS); - await fulfillAllPastRequestsIds(network === "hardhat"); - firstBlockListening = await ethers.provider.getBlockNumber(); + gateway = await ethers.getContractAt( + "fhevm/gateway/GatewayContract.sol:GatewayContract", + parsedEnv.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS, + ); + const provider = ethers.provider; + if (networkName === "hardhat" && hre.__SOLIDITY_COVERAGE_RUNNING !== true) { + // evm_snapshot is not supported in coverage mode + lastBlockSnapshotForDecrypt = await provider.send("get_lastBlockSnapshotForDecrypt"); + if (lastBlockSnapshotForDecrypt < firstBlockListening) { + firstBlockListening = lastBlockSnapshotForDecrypt + 1; + } + } + await fulfillAllPastRequestsIds(networkName === "hardhat"); + firstBlockListening = (await ethers.provider.getBlockNumber()) + 1; + if (networkName === "hardhat" && hre.__SOLIDITY_COVERAGE_RUNNING !== true) { + // evm_snapshot is not supported in coverage mode + await provider.send("set_lastBlockSnapshotForDecrypt", [firstBlockListening]); + } }; const getAlreadyFulfilledDecryptions = async (): Promise<[bigint]> => { let results = []; - const eventDecryptionResultBool = await oracle.filters.ResultCallbackBool().getTopicFilter(); - const filterDecryptionResultBool = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, + const eventDecryptionResult = await gateway.filters.ResultCallback().getTopicFilter(); + const filterDecryptionResult = { + address: process.env.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS, fromBlock: firstBlockListening, toBlock: "latest", - topics: eventDecryptionResultBool, + topics: eventDecryptionResult, }; - const pastResultsEbool = await ethers.provider.getLogs(filterDecryptionResultBool); - results = results.concat(pastResultsEbool.map((result) => ifaceResultCallbackBool.parseLog(result).args[0])); - - const eventDecryptionResultEUint4 = await oracle.filters.ResultCallbackUint4().getTopicFilter(); - const filterDecryptionResultUint4 = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, - fromBlock: firstBlockListening, - toBlock: "latest", - topics: eventDecryptionResultEUint4, - }; - const pastResultsEuint4 = await ethers.provider.getLogs(filterDecryptionResultUint4); - results = results.concat(pastResultsEuint4.map((result) => ifaceResultCallbackUint4.parseLog(result).args[0])); - - const eventDecryptionResultEUint8 = await oracle.filters.ResultCallbackUint8().getTopicFilter(); - const filterDecryptionResultUint8 = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, - fromBlock: firstBlockListening, - toBlock: "latest", - topics: eventDecryptionResultEUint8, - }; - const pastResultsEuint8 = await ethers.provider.getLogs(filterDecryptionResultUint8); - results = results.concat(pastResultsEuint8.map((result) => ifaceResultCallbackUint8.parseLog(result).args[0])); - - const eventDecryptionResultEUint16 = await oracle.filters.ResultCallbackUint16().getTopicFilter(); - const filterDecryptionResultUint16 = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, - fromBlock: firstBlockListening, - toBlock: "latest", - topics: eventDecryptionResultEUint16, - }; - const pastResultsEuint16 = await ethers.provider.getLogs(filterDecryptionResultUint16); - results = results.concat(pastResultsEuint16.map((result) => ifaceResultCallbackUint16.parseLog(result).args[0])); - - const eventDecryptionResultEUint32 = await oracle.filters.ResultCallbackUint32().getTopicFilter(); - const filterDecryptionResultUint32 = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, - fromBlock: firstBlockListening, - toBlock: "latest", - topics: eventDecryptionResultEUint32, - }; - const pastResultsEuint32 = await ethers.provider.getLogs(filterDecryptionResultUint32); - results = results.concat(pastResultsEuint32.map((result) => ifaceResultCallbackUint32.parseLog(result).args[0])); - - const eventDecryptionResultEUint64 = await oracle.filters.ResultCallbackUint64().getTopicFilter(); - const filterDecryptionResultUint64 = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, - fromBlock: firstBlockListening, - toBlock: "latest", - topics: eventDecryptionResultEUint64, - }; - const pastResultsEuint64 = await ethers.provider.getLogs(filterDecryptionResultUint64); - results = results.concat(pastResultsEuint64.map((result) => ifaceResultCallbackUint64.parseLog(result).args[0])); - - const eventDecryptionResultEAddress = await oracle.filters.ResultcallbackAddress().getTopicFilter(); - const filterDecryptionResultAddress = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, - fromBlock: firstBlockListening, - toBlock: "latest", - topics: eventDecryptionResultEAddress, - }; - const pastResultsEaddress = await ethers.provider.getLogs(filterDecryptionResultAddress); - results = results.concat(pastResultsEaddress.map((result) => ifaceResultcallbackAddress.parseLog(result).args[0])); + const pastResults = await ethers.provider.getLogs(filterDecryptionResult); + results = results.concat(pastResults.map((result) => ifaceResultCallback.parseLog(result).args[0])); return results; }; +const allTrue = (arr: boolean[], fn = Boolean) => arr.every(fn); + const fulfillAllPastRequestsIds = async (mocked: boolean) => { - const eventDecryptionEBool = await oracle.filters.EventDecryptionEBool().getTopicFilter(); + const eventDecryption = await gateway.filters.EventDecryption().getTopicFilter(); const results = await getAlreadyFulfilledDecryptions(); - const filterDecryptionEBool = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, + const filterDecryption = { + address: process.env.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS, fromBlock: firstBlockListening, toBlock: "latest", - topics: eventDecryptionEBool, + topics: eventDecryption, }; - const pastRequestsEbool = await ethers.provider.getLogs(filterDecryptionEBool); - for (const request of pastRequestsEbool) { - const event = ifaceEventDecryptionEBool.parseLog(request); + const pastRequests = await ethers.provider.getLogs(filterDecryption); + for (const request of pastRequests) { + const event = ifaceEventDecryption.parseLog(request); const requestID = event.args[0]; - const cts = event.args[1]; + const handles = event.args[1]; + const typesList = handles.map((handle) => parseInt(handle.toString(16).slice(-4, -2), 16)); const msgValue = event.args[4]; if (!results.includes(requestID)) { // if request is not already fulfilled if (mocked) { // in mocked mode, we trigger the decryption fulfillment manually - const tx = await oracle.connect(relayer).fulfillRequestBool( - requestID, - cts.map((value) => value === 1n), - { value: msgValue }, + await awaitCoprocessor(); + + // first check tat all handles are allowed for decryption + const aclFactory = await ethers.getContractFactory("fhevm/lib/ACL.sol:ACL"); + const acl = aclFactory.attach(`0x${aclAdd}`); + const isAllowedForDec = await Promise.all(handles.map(async (handle) => acl.allowedForDecryption(handle))); + if (!allTrue(isAllowedForDec)) { + throw new Error("Some handle is not authorized for decryption"); + } + + const types = typesList.map((num) => CiphertextType[num]); + const values = await Promise.all(handles.map(async (handle) => BigInt(await getClearText(handle)))); + const valuesFormatted = values.map((value, index) => + types[index] === "address" ? "0x" + value.toString(16).padStart(40, "0") : value, + ); + const valuesFormatted2 = valuesFormatted.map((value, index) => + types[index] === "bytes" ? "0x" + value.toString(16).padStart(512, "0") : value, ); - await tx.wait(); - } else { - // in fhEVM mode we must wait until the oracle service relayer submits the decryption fulfillment tx - await waitNBlocks(1); - await fulfillAllPastRequestsIds(mocked); - } - } - } - - const eventDecryptionEUint4 = await oracle.filters.EventDecryptionEUint4().getTopicFilter(); - const filterDecryptionEUint4 = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, - fromBlock: firstBlockListening, - toBlock: "latest", - topics: eventDecryptionEUint4, - }; - const pastRequestsEUint4 = await ethers.provider.getLogs(filterDecryptionEUint4); - for (const request of pastRequestsEUint4) { - const event = ifaceEventDecryptionEUint4.parseLog(request); - const requestID = event.args[0]; - const cts = event.args[1]; - const msgValue = event.args[4]; - if (!results.includes(requestID)) { - // if request is not already fulfilled - if (mocked) { - // in mocked mode, we trigger the decryption fulfillment manually - const tx = await oracle.connect(relayer).fulfillRequestUint4(requestID, [...cts], { value: msgValue }); - await tx.wait(); - } else { - // in fhEVM mode we must wait until the oracle service relayer submits the decryption fulfillment tx - await waitNBlocks(1); - await fulfillAllPastRequestsIds(mocked); - } - } - } - - const eventDecryptionEUint8 = await oracle.filters.EventDecryptionEUint8().getTopicFilter(); - const filterDecryptionEUint8 = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, - fromBlock: firstBlockListening, - toBlock: "latest", - topics: eventDecryptionEUint8, - }; - const pastRequestsEUint8 = await ethers.provider.getLogs(filterDecryptionEUint8); - for (const request of pastRequestsEUint8) { - const event = ifaceEventDecryptionEUint8.parseLog(request); - const requestID = event.args[0]; - const cts = event.args[1]; - const msgValue = event.args[4]; - if (!results.includes(requestID)) { - // if request is not already fulfilled - if (mocked) { - // in mocked mode, we trigger the decryption fulfillment manually - const tx = await oracle.connect(relayer).fulfillRequestUint8(requestID, [...cts], { value: msgValue }); - await tx.wait(); - } else { - // in fhEVM mode we must wait until the oracle service relayer submits the decryption fulfillment tx - await waitNBlocks(1); - await fulfillAllPastRequestsIds(mocked); - } - } - } - - const eventDecryptionEUint16 = await oracle.filters.EventDecryptionEUint16().getTopicFilter(); - const filterDecryptionEUint16 = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, - fromBlock: firstBlockListening, - toBlock: "latest", - topics: eventDecryptionEUint16, - }; - const pastRequestsEUint16 = await ethers.provider.getLogs(filterDecryptionEUint16); - for (const request of pastRequestsEUint16) { - const event = ifaceEventDecryptionEUint16.parseLog(request); - const requestID = event.args[0]; - const cts = event.args[1]; - const msgValue = event.args[4]; - if (!results.includes(requestID)) { - // if request is not already fulfilled - if (mocked) { - // in mocked mode, we trigger the decryption fulfillment manually - const tx = await oracle.connect(relayer).fulfillRequestUint16(requestID, [...cts], { value: msgValue }); - await tx.wait(); - } else { - // in fhEVM mode we must wait until the oracle service relayer submits the decryption fulfillment tx - await waitNBlocks(1); - await fulfillAllPastRequestsIds(mocked); - } - } - } - - const eventDecryptionEUint32 = await oracle.filters.EventDecryptionEUint32().getTopicFilter(); - const filterDecryptionEUint32 = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, - fromBlock: firstBlockListening, - toBlock: "latest", - topics: eventDecryptionEUint32, - }; - const pastRequestsEUint32 = await ethers.provider.getLogs(filterDecryptionEUint32); - for (const request of pastRequestsEUint32) { - const event = ifaceEventDecryptionEUint32.parseLog(request); - const requestID = event.args[0]; - const cts = event.args[1]; - const msgValue = event.args[4]; - if (!results.includes(requestID)) { - // if request is not already fulfilled - if (mocked) { - // in mocked mode, we trigger the decryption fulfillment manually - const tx = await oracle.connect(relayer).fulfillRequestUint32(requestID, [...cts], { value: msgValue }); - await tx.wait(); - } else { - // in fhEVM mode we must wait until the oracle service relayer submits the decryption fulfillment tx - await waitNBlocks(1); - await fulfillAllPastRequestsIds(mocked); - } - } - } - const eventDecryptionEUint64 = await oracle.filters.EventDecryptionEUint64().getTopicFilter(); - const filterDecryptionEUint64 = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, - fromBlock: firstBlockListening, - toBlock: "latest", - topics: eventDecryptionEUint64, - }; - const pastRequestsEUint64 = await ethers.provider.getLogs(filterDecryptionEUint64); - for (const request of pastRequestsEUint64) { - const event = ifaceEventDecryptionEUint64.parseLog(request); - const requestID = event.args[0]; - const cts = event.args[1]; - const msgValue = event.args[4]; - if (!results.includes(requestID)) { - // if request is not already fulfilled - if (mocked) { - // in mocked mode, we trigger the decryption fulfillment manually - const tx = await oracle.connect(relayer).fulfillRequestUint64(requestID, [...cts], { value: msgValue }); - await tx.wait(); - } else { - // in fhEVM mode we must wait until the oracle service relayer submits the decryption fulfillment tx - await waitNBlocks(1); - await fulfillAllPastRequestsIds(mocked); - } - } - } + const abiCoder = new ethers.AbiCoder(); + const encodedData = abiCoder.encode(["uint256", ...types], [31, ...valuesFormatted2]); // 31 is just a dummy uint256 requestID to get correct abi encoding for the remaining arguments (i.e everything except the requestID) + const calldata = "0x" + encodedData.slice(66); // we just pop the dummy requestID to get the correct value to pass for `decryptedCts` - const eventDecryptionEAddress = await oracle.filters.EventDecryptionEAddress().getTopicFilter(); - const filterDecryptionEAddress = { - address: process.env.ORACLE_CONTRACT_PREDEPLOY_ADDRESS, - fromBlock: firstBlockListening, - toBlock: "latest", - topics: eventDecryptionEAddress, - }; - const pastRequestsEAddress = await ethers.provider.getLogs(filterDecryptionEAddress); - for (const request of pastRequestsEAddress) { - const event = ifaceEventDecryptionEAddress.parseLog(request); - const requestID = event.args[0]; - const cts = event.args[1]; - const msgValue = event.args[4]; - if (!results.includes(requestID)) { - // if request is not already fulfilled - if (mocked) { - // in mocked mode, we trigger the decryption fulfillment manually - const tx = await oracle.connect(relayer).fulfillRequestAddress(requestID, [...cts], { value: msgValue }); + const tx = await gateway.connect(relayer).fulfillRequest(requestID, calldata, [], { value: msgValue }); await tx.wait(); } else { - // in fhEVM mode we must wait until the oracle service relayer submits the decryption fulfillment tx + // in fhEVM mode we must wait until the gateway service relayer submits the decryption fulfillment tx await waitNBlocks(1); await fulfillAllPastRequestsIds(mocked); } diff --git a/test/coprocessorUtils.ts b/test/coprocessorUtils.ts new file mode 100644 index 0000000..12bab6b --- /dev/null +++ b/test/coprocessorUtils.ts @@ -0,0 +1,893 @@ +import dotenv from "dotenv"; +import { log2 } from "extra-bigint"; +import * as fs from "fs"; +import { ethers } from "hardhat"; +import hre from "hardhat"; +import { Database } from "sqlite3"; + +const parsedEnvCoprocessor = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.exec")); +const coprocAdd = parsedEnvCoprocessor.TFHE_EXECUTOR_CONTRACT_ADDRESS.replace(/^0x/, "") + .replace(/^0+/, "") + .toLowerCase(); + +let firstBlockListening = 0; +let lastBlockSnapshot = 0; +let lastCounterRand = 0; +let counterRand = 0; + +const contractABI = JSON.parse(fs.readFileSync("abi/TFHEExecutor.json").toString()).abi; + +const iface = new ethers.Interface(contractABI); + +const functions = iface.fragments.filter((fragment) => fragment.type === "function"); + +const selectors = functions.reduce((acc, func) => { + const signature = `${func.name}(${func.inputs.map((input) => input.type).join(",")})`; + acc[func.selector] = signature; + return acc; +}, {}); + +//const db = new Database('./sql.db'); // on-disk db for debugging +const db = new Database(":memory:"); + +function insertSQL(handle: string, clearText: bigint, replace: boolean = false) { + if (replace) { + // this is useful if using snapshots while sampling different random numbers on each revert + db.run("INSERT OR REPLACE INTO ciphertexts (handle, clearText) VALUES (?, ?)", [handle, clearText.toString()]); + } else { + db.run("INSERT OR IGNORE INTO ciphertexts (handle, clearText) VALUES (?, ?)", [handle, clearText.toString()]); + } +} + +// Decrypt any handle, bypassing ACL +// WARNING : only for testing or internal use +export const getClearText = async (handle: bigint): Promise => { + const handleStr = "0x" + handle.toString(16).padStart(64, "0"); + + return new Promise((resolve, reject) => { + let attempts = 0; + const maxRetries = 10; + + function executeQuery() { + db.get("SELECT clearText FROM ciphertexts WHERE handle = ?", [handleStr], (err, row) => { + if (err) { + reject(new Error(`Error querying database: ${err.message}`)); + } else if (row) { + resolve(row.clearText); + } else if (attempts < maxRetries) { + attempts++; + executeQuery(); + } else { + reject(new Error("No record found after maximum retries")); + } + }); + } + + executeQuery(); + }); +}; + +db.serialize(() => db.run("CREATE TABLE IF NOT EXISTS ciphertexts (handle BINARY PRIMARY KEY,clearText TEXT)")); + +enum Operators { + fheAdd = 0, + fheSub, + fheMul, + fheDiv, + fheRem, + fheBitAnd, + fheBitOr, + fheBitXor, + fheShl, + fheShr, + fheRotl, + fheRotr, + fheEq, + fheNe, + fheGe, + fheGt, + fheLe, + fheLt, + fheMin, + fheMax, + fheNeg, + fheNot, + verifyCiphertext, + cast, + trivialEncrypt, + fheIfThenElse, + fheRand, + fheRandBounded, +} + +interface EvmState { + stack: string[]; + memory: string[]; +} + +function extractCalldata(memory: string[], offset: number, size: number): string { + const startIndex = Math.floor(offset / 32); + const endIndex = Math.ceil((offset + size) / 32); + const memorySegments = memory.slice(startIndex, endIndex); + let calldata = ""; + for (let i = 0; i < memorySegments.length; i++) { + calldata += memorySegments[i]; + } + const calldataStart = (offset % 32) * 2; + const calldataEnd = calldataStart + size * 2; + return calldata.slice(calldataStart, calldataEnd); +} + +const TypesBytesSize = { + 0: 1, //ebool + 1: 1, //euint4 + 2: 1, //euint8 + 3: 2, //euint16 + 4: 4, //euint32 + 5: 8, //euint64 + 6: 16, //euint128 + 7: 20, //eaddress + 8: 32, //euint256 + 9: 64, //ebytes64 + 10: 128, //ebytes128 + 11: 256, //ebytes256 +}; + +const NumBits = { + 0: 1n, //ebool + 1: 4n, //euint4 + 2: 8n, //euint8 + 3: 16n, //euint16 + 4: 32n, //euint32 + 5: 64n, //euint64 + 6: 128n, //euint128 + 7: 160n, //eaddress + 8: 256n, //euint256 + 9: 512n, //ebytes64 + 10: 1024n, //ebytes128 + 11: 2048n, //ebytes256 +}; + +const HANDLE_VERSION = 0; + +export function numberToEvenHexString(num: number) { + if (typeof num !== "number" || num < 0) { + throw new Error("Input should be a non-negative number."); + } + let hexString = num.toString(16); + if (hexString.length % 2 !== 0) { + hexString = "0" + hexString; + } + return hexString; +} + +function appendType(handle: string, type: number): string { + return handle.slice(0, -4) + numberToEvenHexString(type) + numberToEvenHexString(HANDLE_VERSION); +} + +function getRandomBigInt(numBits: number): bigint { + if (numBits <= 0) { + throw new Error("Number of bits must be greater than 0"); + } + const numBytes = Math.ceil(numBits / 8); + const randomBytes = new Uint8Array(numBytes); + crypto.getRandomValues(randomBytes); + let randomBigInt = BigInt(0); + for (let i = 0; i < numBytes; i++) { + randomBigInt = (randomBigInt << BigInt(8)) | BigInt(randomBytes[i]); + } + const mask = (BigInt(1) << BigInt(numBits)) - BigInt(1); + randomBigInt = randomBigInt & mask; + return randomBigInt; +} + +async function insertHandle(obj2: EvmState, validIdxes: [number]) { + const obj = obj2.value; + if (isCoprocAdd(obj!.stack.at(-2))) { + const argsOffset = Number(`0x${obj!.stack.at(-4)}`); + const argsSize = Number(`0x${obj!.stack.at(-5)}`); + const calldata = extractCalldata(obj.memory, argsOffset, argsSize); + const currentSelector = "0x" + calldata.slice(0, 8); + const decodedData = iface.decodeFunctionData(currentSelector, "0x" + calldata); + + let handle; + let clearText; + let clearLHS; + let clearRHS; + let lhsType; + let resultType; + let shift; + + switch (selectors[currentSelector]) { + case "trivialEncrypt(uint256,bytes1)": + resultType = Number(decodedData[1]); + clearText = decodedData[0]; + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "bytes1"], + [Operators.trivialEncrypt, decodedData[0], decodedData[1]], + ), + ); + handle = appendType(handle, resultType); + insertSQL(handle, clearText); + break; + + case "fheAdd(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheAdd, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) + decodedData[1]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) + BigInt(clearRHS); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "fheSub(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheSub, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) - decodedData[1]; + if (clearText < 0n) clearText = clearText + 2n ** NumBits[resultType]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) - BigInt(clearRHS); + if (clearText < 0n) clearText = clearText + 2n ** NumBits[resultType]; + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "fheMul(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheMul, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) * decodedData[1]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) * BigInt(clearRHS); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "fheDiv(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheDiv, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) / decodedData[1]; + } else { + throw new Error("Non-scalar div not implemented yet"); + } + insertSQL(handle, clearText); + break; + + case "fheRem(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheRem, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) % decodedData[1]; + } else { + throw new Error("Non-scalar rem not implemented yet"); + } + insertSQL(handle, clearText); + break; + + case "fheBitAnd(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheBitAnd, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) & decodedData[1]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) & BigInt(clearRHS); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "fheBitOr(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheBitOr, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) | decodedData[1]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) | BigInt(clearRHS); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "fheBitXor(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheBitXor, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) ^ decodedData[1]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) ^ BigInt(clearRHS); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "fheShl(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheShl, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) << decodedData[1] % NumBits[resultType]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) << BigInt(clearRHS) % NumBits[resultType]; + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "fheShr(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheShr, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) >> decodedData[1] % NumBits[resultType]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) >> BigInt(clearRHS) % NumBits[resultType]; + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "fheRotl(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheRotl, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + + if (decodedData[2] === "0x01") { + shift = decodedData[1] % NumBits[resultType]; + clearText = (BigInt(clearLHS) << shift) | (BigInt(clearLHS) >> (NumBits[resultType] - shift)); + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(decodedData[1]); + shift = BigInt(clearRHS) % NumBits[resultType]; + clearText = (BigInt(clearLHS) << shift) | (BigInt(clearLHS) >> (NumBits[resultType] - shift)); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "fheRotr(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheRotr, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + + if (decodedData[2] === "0x01") { + shift = decodedData[1] % NumBits[resultType]; + clearText = (BigInt(clearLHS) >> shift) | (BigInt(clearLHS) << (NumBits[resultType] - shift)); + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(decodedData[1]); + shift = BigInt(clearRHS) % NumBits[resultType]; + clearText = (BigInt(clearLHS) >> shift) | (BigInt(clearLHS) << (NumBits[resultType] - shift)); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "fheEq(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheEq, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + handle = appendType(handle, 0); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) === decodedData[1] ? 1n : 0n; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) === BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "fheNe(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheNe, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + handle = appendType(handle, 0); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) !== decodedData[1] ? 1n : 0n; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) !== BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "fheGe(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheGe, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + handle = appendType(handle, 0); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) >= decodedData[1] ? 1n : 0n; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) >= BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "fheGt(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheGt, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + handle = appendType(handle, 0); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) > decodedData[1] ? 1n : 0n; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) > BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "fheLe(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheLe, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + handle = appendType(handle, 0); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) <= decodedData[1] ? 1n : 0n; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) <= BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "fheLt(uint256,uint256,bytes1)": + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheLt, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + handle = appendType(handle, 0); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) < decodedData[1] ? 1n : 0n; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) < BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "fheMax(uint256,uint256,bytes1)": + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheMax, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) > decodedData[1] ? clearLHS : decodedData[1]; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) > BigInt(clearRHS) ? clearLHS : clearRHS; + } + insertSQL(handle, clearText); + break; + + case "fheMin(uint256,uint256,bytes1)": + lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + resultType = lhsType; + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "bytes1"], + [Operators.fheMin, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + handle = appendType(handle, resultType); + clearLHS = await getClearText(decodedData[0]); + if (decodedData[2] === "0x01") { + clearText = BigInt(clearLHS) < decodedData[1] ? clearLHS : decodedData[1]; + } else { + clearRHS = await getClearText(decodedData[1]); + clearText = BigInt(clearLHS) < BigInt(clearRHS) ? clearLHS : clearRHS; + } + insertSQL(handle, clearText); + break; + + case "cast(uint256,bytes1)": + resultType = parseInt(decodedData[1]); + handle = ethers.keccak256( + ethers.solidityPacked(["uint8", "uint256", "bytes1"], [Operators.cast, decodedData[0], decodedData[1]]), + ); + clearText = BigInt(await getClearText(decodedData[0])) % 2n ** NumBits[resultType]; + handle = appendType(handle, resultType); + insertSQL(handle, clearText); + break; + + case "fheNot(uint256)": + resultType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + handle = ethers.keccak256(ethers.solidityPacked(["uint8", "uint256"], [Operators.fheNot, decodedData[0]])); + handle = appendType(handle, resultType); + clearText = BigInt(await getClearText(decodedData[0])); + clearText = bitwiseNotUintBits(clearText, Number(NumBits[resultType])); + insertSQL(handle, clearText); + break; + + case "fheNeg(uint256)": + resultType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); + handle = ethers.keccak256(ethers.solidityPacked(["uint8", "uint256"], [Operators.fheNeg, decodedData[0]])); + handle = appendType(handle, resultType); + clearText = BigInt(await getClearText(decodedData[0])); + clearText = bitwiseNotUintBits(clearText, Number(NumBits[resultType])); + clearText = (clearText + 1n) % 2n ** NumBits[resultType]; + insertSQL(handle, clearText); + break; + + case "verifyCiphertext(bytes32,address,bytes,bytes1)": + { + handle = decodedData[0]; + const type = parseInt(handle.slice(-4, -2), 16); + if (type !== 11) { + //not an ebytes256 + const typeSize = TypesBytesSize[type]; + const idx = parseInt(handle.slice(-6, -4), 16); + const inputProof = decodedData[2].replace(/^0x/, ""); + clearText = BigInt("0x" + inputProof.slice(2 + 2 * 53 * idx, 2 + 2 * typeSize + 2 * 53 * idx)); + insertSQL(handle, clearText); + } else { + const inputProof = decodedData[2].replace(/^0x/, ""); + clearText = BigInt("0x" + inputProof.slice(2, 2 + 2 * 256)); + insertSQL(handle, clearText); + } + } + break; + + case "fheIfThenElse(uint256,uint256,uint256)": + { + resultType = parseInt(decodedData[1].toString(16).slice(-4, -2), 16); + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "uint256", "uint256"], + [Operators.fheIfThenElse, decodedData[0], decodedData[1], decodedData[2]], + ), + ); + handle = appendType(handle, resultType); + const clearControl = BigInt(await getClearText(decodedData[0])); + const clearIfTrue = BigInt(await getClearText(decodedData[1])); + const clearIfFalse = BigInt(await getClearText(decodedData[2])); + if (clearControl === 1n) { + clearText = clearIfTrue; + } else { + clearText = clearIfFalse; + } + insertSQL(handle, clearText); + } + break; + + case "fheRand(bytes1)": + if (validIdxes.includes(obj2.index)) { + resultType = parseInt(decodedData[0], 16); + handle = ethers.keccak256( + ethers.solidityPacked(["uint8", "bytes1", "uint256"], [Operators.fheRand, decodedData[0], counterRand]), + ); + handle = appendType(handle, resultType); + clearText = getRandomBigInt(Number(NumBits[resultType])); + insertSQL(handle, clearText, true); + counterRand++; + } + break; + + case "fheRandBounded(uint256,bytes1)": + if (validIdxes.includes(obj2.index)) { + resultType = parseInt(decodedData[1], 16); + handle = ethers.keccak256( + ethers.solidityPacked( + ["uint8", "uint256", "bytes1", "uint256"], + [Operators.fheRandBounded, decodedData[0], decodedData[1], counterRand], + ), + ); + handle = appendType(handle, resultType); + clearText = getRandomBigInt(Number(log2(BigInt(decodedData[0])))); + insertSQL(handle, clearText, true); + counterRand++; + } + break; + } + } +} + +function bitwiseNotUintBits(value: bigint, numBits: number) { + if (typeof value !== "bigint") { + throw new TypeError("The input value must be a BigInt."); + } + if (typeof numBits !== "number" || numBits <= 0) { + throw new TypeError("The numBits parameter must be a positive integer."); + } + + // Create the mask with numBits bits set to 1 + const BIT_MASK = (BigInt(1) << BigInt(numBits)) - BigInt(1); + + return ~value & BIT_MASK; +} + +function isCoprocAdd(longString: string): boolean { + const strippedLongString = longString.replace(/^0+/, ""); + const normalizedLongString = strippedLongString.toLowerCase(); + return normalizedLongString === coprocAdd; +} + +async function processLogs(trace, validSubcallsIndexes) { + for (const obj of trace.structLogs + .map((value, index) => ({ value, index })) + .filter((obj) => obj.value.op === "CALL")) { + await insertHandle(obj, validSubcallsIndexes); + } +} + +export const awaitCoprocessor = async (): Promise => { + const pastTxHashes = await getAllPastTransactionHashes(); + for (const txHash of pastTxHashes) { + const trace = await ethers.provider.send("debug_traceTransaction", [txHash[0]]); + + if (!trace.failed) { + const callTree = await buildCallTree(trace, txHash[1]); + const validSubcallsIndexes = getValidSubcallsIds(callTree)[1]; + await processLogs(trace, validSubcallsIndexes); + } + } +}; + +async function getAllPastTransactionHashes() { + const provider = ethers.provider; + const latestBlockNumber = await provider.getBlockNumber(); + const txHashes = []; + + if (hre.__SOLIDITY_COVERAGE_RUNNING !== true) { + // evm_snapshot is not supported in coverage mode + [lastBlockSnapshot, lastCounterRand] = await provider.send("get_lastBlockSnapshot"); + if (lastBlockSnapshot < firstBlockListening) { + firstBlockListening = lastBlockSnapshot + 1; + counterRand = Number(lastCounterRand); + } + } + + // Iterate through all blocks and collect transaction hashes + for (let i = firstBlockListening; i <= latestBlockNumber; i++) { + const block = await provider.getBlock(i, true); + block!.transactions.forEach((tx, index) => { + const rcpt = block?.prefetchedTransactions[index]; + txHashes.push([tx, { to: rcpt.to, status: rcpt.status }]); + }); + } + firstBlockListening = latestBlockNumber + 1; + if (hre.__SOLIDITY_COVERAGE_RUNNING !== true) { + // evm_snapshot is not supported in coverage mode + await provider.send("set_lastBlockSnapshot", [firstBlockListening]); + } + return txHashes; +} + +async function buildCallTree(trace, receipt) { + const structLogs = trace.structLogs; + + const callStack = []; + const callTree = { + id: 0, + type: receipt.to ? "TOPCALL" : "TOPCREATE", + revert: receipt.status === 1 ? false : true, + to: receipt.to ? receipt.to : null, + calls: [], + indexTrace: 0, + }; + let currentNode = callTree; + const lenStructLogs = structLogs.length; + let index = 1; + for (const [i, log] of structLogs.entries()) { + if (i < lenStructLogs - 1) { + if (structLogs[i].depth - structLogs[i + 1].depth === 1) { + if (!["RETURN", "SELFDESTRUCT", "STOP", "REVERT", "INVALID"].includes(structLogs[i].op)) { + currentNode.outofgasOrOther = true; + currentNode = callStack.pop(); + } + } + } + + switch (log.op) { + case "CALL": + case "DELEGATECALL": + case "CALLCODE": + case "STATICCALL": + case "CREATE": + case "CREATE2": + if (i < lenStructLogs - 1) { + if (structLogs[i + 1].depth - structLogs[i].depth === 1) { + const newNode = { + id: index, + type: log.op, + to: log.stack[log.stack.length - 2], + calls: [], + revert: true, + outofgasOrOther: false, + indexTrace: i, + }; + currentNode.calls.push(newNode); + callStack.push(currentNode); + currentNode = newNode; + index += 1; + } + } + break; + case "RETURN": // some edge case probably not handled well : if memory expansion cost on RETURN exceeds the remaining gas in current subcall, but it's OK for a mocked mode + case "SELFDESTRUCT": // some edge case probably not handled well : if there is not enough gas remaining on SELFDESTRUCT, but it's OK for a mocked mode + case "STOP": + currentNode.revert = false; + currentNode = callStack.pop(); + break; + case "REVERT": + case "INVALID": + currentNode = callStack.pop(); + break; + } + + switch (log.op) { + case "CREATE": + case "CREATE2": + currentNode.to = null; + break; + } + } + return callTree; +} + +function getValidSubcallsIds(tree) { + const result = []; + const resultIndexes = []; + + function traverse(node, ancestorReverted) { + if (ancestorReverted || node.revert) { + ancestorReverted = true; + } else { + result.push(node.id); + resultIndexes.push(node.indexTrace); + } + for (const child of node.calls) { + traverse(child, ancestorReverted); + } + } + + traverse(tree, false); + + return [result, resultIndexes]; +} diff --git a/test/fhevmjsMocked.ts b/test/fhevmjsMocked.ts new file mode 100644 index 0000000..42ee6d2 --- /dev/null +++ b/test/fhevmjsMocked.ts @@ -0,0 +1,302 @@ +import { toBigIntLE } from "bigint-buffer"; +import { toBufferBE } from "bigint-buffer"; +import crypto from "crypto"; +import dotenv from "dotenv"; +import { ethers } from "ethers"; +import * as fs from "fs"; +import hre from "hardhat"; +import { Keccak } from "sha3"; +import { isAddress } from "web3-validator"; + +import { awaitCoprocessor, getClearText } from "./coprocessorUtils"; + +const parsedEnvACL = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.acl")); +const aclAdd = parsedEnvACL.ACL_CONTRACT_ADDRESS.replace(/^0x/, "").replace(/^0+/, "").toLowerCase(); + +enum Types { + ebool = 0, + euint4, + euint8, + euint16, + euint32, + euint64, + euint128, + eaddress, + euint256, + ebytes64, + ebytes128, + ebytes256, +} + +function bytesToBigInt(byteArray: Uint8Array): bigint { + if (!byteArray || byteArray?.length === 0) { + return BigInt(0); + } + const buffer = Buffer.from(byteArray); + const result = toBigIntLE(buffer); + return result; +} + +function createUintToUint8ArrayFunction(numBits: number) { + const numBytes = Math.ceil(numBits / 8); + return function (uint: number | bigint | boolean) { + const buffer = toBufferBE(BigInt(uint), numBytes); + + // concatenate 32 random bytes at the end of buffer to simulate encryption noise + const randomBytes = crypto.randomBytes(32); + const combinedBuffer = Buffer.concat([buffer, randomBytes]); + + let byteBuffer; + let totalBuffer; + const padBuffer = numBytes <= 20 ? Buffer.alloc(20 - numBytes) : Buffer.alloc(0); // to fit it in an E160List + + switch (numBits) { + case 1: + byteBuffer = Buffer.from([Types.ebool]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer, padBuffer]); + break; + case 4: + byteBuffer = Buffer.from([Types.euint4]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer, padBuffer]); + break; + case 8: + byteBuffer = Buffer.from([Types.euint8]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer, padBuffer]); + break; + case 16: + byteBuffer = Buffer.from([Types.euint16]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer, padBuffer]); + break; + case 32: + byteBuffer = Buffer.from([Types.euint32]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer, padBuffer]); + break; + case 64: + byteBuffer = Buffer.from([Types.euint64]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer, padBuffer]); + break; + case 160: + byteBuffer = Buffer.from([Types.eaddress]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); + break; + case 2048: + byteBuffer = Buffer.from([Types.ebytes256]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); + break; + default: + throw Error("Non-supported numBits"); + } + + return totalBuffer; + }; +} + +export const reencryptRequestMocked = async ( + handle: bigint, + privateKey: string, + publicKey: string, + signature: string, + contractAddress: string, + userAddress: string, +) => { + // Signature checking: + const domain = { + name: "Authorization token", + version: "1", + chainId: hre.network.config.chainId, + verifyingContract: contractAddress, + }; + const types = { + Reencrypt: [{ name: "publicKey", type: "bytes" }], + }; + const value = { + publicKey: `0x${publicKey}`, + }; + const signerAddress = ethers.verifyTypedData(domain, types, value, `0x${signature}`); + const normalizedSignerAddress = ethers.getAddress(signerAddress); + const normalizedUserAddress = ethers.getAddress(userAddress); + if (normalizedSignerAddress !== normalizedUserAddress) { + throw new Error("Invalid EIP-712 signature!"); + } + + // ACL checking + const aclFactory = await hre.ethers.getContractFactory("fhevm/lib/ACL.sol:ACL"); + const acl = aclFactory.attach(`0x${aclAdd}`); + const userAllowed = await acl.persistAllowed(handle, userAddress); + const contractAllowed = await acl.persistAllowed(handle, contractAddress); + const isAllowed = userAllowed && contractAllowed; + if (!isAllowed) { + throw new Error("User is not authorized to reencrypt this handle!"); + } + await awaitCoprocessor(); + return BigInt(await getClearText(handle)); +}; + +export const createEncryptedInputMocked = (contractAddress: string, callerAddress: string) => { + if (!isAddress(contractAddress)) { + throw new Error("Contract address is not a valid address."); + } + + if (!isAddress(callerAddress)) { + throw new Error("User address is not a valid address."); + } + + const values: bigint[] = []; + const bits: (keyof typeof ENCRYPTION_TYPES)[] = []; + return { + addBool(value: boolean | number | bigint) { + if (value == null) throw new Error("Missing value"); + if (typeof value !== "boolean" && typeof value !== "number" && typeof value !== "bigint") + throw new Error("The value must be a boolean, a number or a bigint."); + if ((typeof value !== "bigint" || typeof value !== "number") && Number(value) > 1) + throw new Error("The value must be 1 or 0."); + values.push(BigInt(value)); + bits.push(1); + return this; + }, + add4(value: number | bigint) { + checkEncryptedValue(value, 4); + values.push(BigInt(value)); + bits.push(4); + return this; + }, + add8(value: number | bigint) { + checkEncryptedValue(value, 8); + values.push(BigInt(value)); + bits.push(8); + return this; + }, + add16(value: number | bigint) { + checkEncryptedValue(value, 16); + values.push(BigInt(value)); + bits.push(16); + return this; + }, + add32(value: number | bigint) { + checkEncryptedValue(value, 32); + values.push(BigInt(value)); + bits.push(32); + return this; + }, + add64(value: number | bigint) { + checkEncryptedValue(value, 64); + values.push(BigInt(value)); + bits.push(64); + return this; + }, + add128(value: number | bigint) { + checkEncryptedValue(value, 128); + values.push(BigInt(value)); + bits.push(128); + return this; + }, + addAddress(value: string) { + if (!isAddress(value)) { + throw new Error("The value must be a valid address."); + } + values.push(BigInt(value)); + bits.push(160); + return this; + }, + addBytes256(value: Uint8Array) { + const bigIntValue = bytesToBigInt(value); + checkEncryptedValue(bigIntValue, 2048); + values.push(bigIntValue); + bits.push(2048); + return this; + }, + getValues() { + return values; + }, + getBits() { + return bits; + }, + resetValues() { + values.length = 0; + bits.length = 0; + return this; + }, + encrypt() { + const listType = getListType(bits); + + let encrypted = Buffer.alloc(0); + + switch (listType) { + case 160: { + bits.map((v, i) => { + encrypted = Buffer.concat([encrypted, createUintToUint8ArrayFunction(v)(values[i])]); + }); + break; + } + case 2048: { + encrypted = createUintToUint8ArrayFunction(2048)(values[0]); + break; + } + } + + const inputProof = new Uint8Array(encrypted); + const hash = new Keccak(256).update(Buffer.from(inputProof)).digest(); + + const handles = bits.map((v, i) => { + const dataWithIndex = new Uint8Array(hash.length + 1); + dataWithIndex.set(hash, 0); + dataWithIndex.set([i], hash.length); + const finalHash = new Keccak(256).update(Buffer.from(dataWithIndex)).digest(); + const dataInput = new Uint8Array(32); + dataInput.set(finalHash, 0); + dataInput.set([i, ENCRYPTION_TYPES[v], 0], 29); + return dataInput; + }); + return { + handles, + inputProof, + }; + }, + }; +}; + +const checkEncryptedValue = (value: number | bigint, bits: number) => { + if (value == null) throw new Error("Missing value"); + let limit; + if (bits >= 8) { + limit = BigInt(`0x${new Array(bits / 8).fill(null).reduce((v) => `${v}ff`, "")}`); + } else { + limit = BigInt(2 ** bits - 1); + } + if (typeof value !== "number" && typeof value !== "bigint") throw new Error("Value must be a number or a bigint."); + if (value > limit) { + throw new Error(`The value exceeds the limit for ${bits}bits integer (${limit.toString()}).`); + } +}; + +export const ENCRYPTION_TYPES = { + 1: 0, + 4: 1, + 8: 2, + 16: 3, + 32: 4, + 64: 5, + 128: 6, + 160: 7, + 256: 8, + 512: 9, + 1024: 10, + 2048: 11, +}; + +const getListType = (bits: (keyof typeof ENCRYPTION_TYPES)[]) => { + // We limit to 12 items because for now we are using FheUint160List + if (bits.length > 12) { + throw new Error("You can't pack more than 12 values."); + } + + if (bits.reduce((total, v) => total + v, 0) > 2048) { + throw new Error("Too many bits in provided values. Maximum is 2048."); + } + + if (bits.some((v) => v === 2048)) { + return 2048; + } else { + return 160; + } +}; diff --git a/test/gatewayDecrypt/testAsyncDecrypt.ts b/test/gatewayDecrypt/testAsyncDecrypt.ts new file mode 100644 index 0000000..8ae7ef4 --- /dev/null +++ b/test/gatewayDecrypt/testAsyncDecrypt.ts @@ -0,0 +1,217 @@ +import { expect } from "chai"; +import { ethers, network } from "hardhat"; + +import { asyncDecrypt, awaitAllDecryptionResults } from "../asyncDecrypt"; +import { createInstances } from "../instance"; +import { getSigners, initSigners } from "../signers"; +import { bigIntToBytes, waitNBlocks } from "../utils"; + +describe("TestAsyncDecrypt", function () { + before(async function () { + + await initSigners(); + this.signers = await getSigners(); + this.relayerAddress = "0x97F272ccfef4026A1F3f0e0E879d514627B84E69"; + + // very first request of decryption always fail at the moment due to a gateway bug + // TODO: remove following 8 lines when the gateway bug will be fixed + const contractFactory = await ethers.getContractFactory("TestAsyncDecrypt"); + + this.contract = await contractFactory.connect(this.signers.alice).deploy(); + + await this.contract.waitForDeployment(); + + this.contractAddress = await this.contract.getAddress(); + this.instances = await createInstances(this.signers); + const tx = await this.contract.connect(this.signers.carol).requestUint8({ gasLimit: 5_000_000 }); + await tx.wait(); // this first request is here just to silence the current gateway bug at the moment + await waitNBlocks(1); + + await asyncDecrypt(); + + }); + + beforeEach(async function () { + const contractFactory = await ethers.getContractFactory("TestAsyncDecrypt"); + this.contract = await contractFactory.connect(this.signers.alice).deploy(); + await this.contract.waitForDeployment(); + this.contractAddress = await this.contract.getAddress(); + this.instances = await createInstances(this.signers); + }); + + it("test async decrypt bool", async function () { + const balanceBeforeR = await ethers.provider.getBalance(this.relayerAddress); + const balanceBeforeU = await ethers.provider.getBalance(this.signers.carol.address); + const tx2 = await this.contract.connect(this.signers.carol).requestBool({ gasLimit: 5_000_000 }); + await tx2.wait(); + const balanceAfterU = await ethers.provider.getBalance(this.signers.carol.address); + await awaitAllDecryptionResults(); + const y = await this.contract.yBool(); + expect(y).to.equal(true); + const balanceAfterR = await ethers.provider.getBalance(this.relayerAddress); + console.log("gas paid by relayer (fulfil tx) : ", balanceBeforeR - balanceAfterR); + console.log("gas paid by user (request tx) : ", balanceBeforeU - balanceAfterU); + }); + + it("test async decrypt uint4", async function () { + const balanceBefore = await ethers.provider.getBalance(this.relayerAddress); + const tx2 = await this.contract.connect(this.signers.carol).requestUint4({ gasLimit: 5_000_000 }); + await tx2.wait(); + await awaitAllDecryptionResults(); + const y = await this.contract.yUint4(); + expect(y).to.equal(4); + const balanceAfter = await ethers.provider.getBalance(this.relayerAddress); + console.log(balanceBefore - balanceAfter); + }); + + it("test async decrypt uint8", async function () { + const tx2 = await this.contract.connect(this.signers.carol).requestUint8({ gasLimit: 5_000_000 }); + await tx2.wait(); + await awaitAllDecryptionResults(); + const y = await this.contract.yUint8(); + expect(y).to.equal(42); + }); + + it("test async decrypt uint16", async function () { + const tx2 = await this.contract.connect(this.signers.carol).requestUint16({ gasLimit: 5_000_000 }); + await tx2.wait(); + await awaitAllDecryptionResults(); + const y = await this.contract.yUint16(); + expect(y).to.equal(16); + }); + + it("test async decrypt uint32", async function () { + const tx2 = await this.contract.connect(this.signers.carol).requestUint32(5, 15, { gasLimit: 5_000_000 }); + await tx2.wait(); + await awaitAllDecryptionResults(); + const y = await this.contract.yUint32(); + expect(y).to.equal(52); // 5+15+32 + }); + + it("test async decrypt uint64", async function () { + const tx2 = await this.contract.connect(this.signers.carol).requestUint64({ gasLimit: 5_000_000 }); + await tx2.wait(); + await awaitAllDecryptionResults(); + const y = await this.contract.yUint64(); + expect(y).to.equal(18446744073709551600n); + }); + + it("test async decrypt address", async function () { + const tx2 = await this.contract.connect(this.signers.carol).requestAddress({ gasLimit: 5_000_000 }); + await tx2.wait(); + await awaitAllDecryptionResults(); + const y = await this.contract.yAddress(); + expect(y).to.equal("0x8ba1f109551bD432803012645Ac136ddd64DBA72"); + }); + + it("test async decrypt several addresses", async function () { + const tx2 = await this.contract.connect(this.signers.carol).requestSeveralAddresses({ gasLimit: 5_000_000 }); + await tx2.wait(); + await awaitAllDecryptionResults(); + const y = await this.contract.yAddress(); + const y2 = await this.contract.yAddress2(); + expect(y).to.equal("0x8ba1f109551bD432803012645Ac136ddd64DBA72"); + expect(y2).to.equal("0xf48b8840387ba3809DAE990c930F3b4766A86ca3"); + }); + + it("test async decrypt mixed", async function () { + const contractFactory = await ethers.getContractFactory("TestAsyncDecrypt"); + const contract2 = await contractFactory.connect(this.signers.alice).deploy(); + const tx2 = await contract2.connect(this.signers.carol).requestMixed(5, 15, { gasLimit: 5_000_000 }); + await tx2.wait(); + await awaitAllDecryptionResults(); + const yB = await contract2.yBool(); + expect(yB).to.equal(true); + let y = await contract2.yUint4(); + expect(y).to.equal(4); + y = await contract2.yUint8(); + expect(y).to.equal(42); + y = await contract2.yUint16(); + expect(y).to.equal(16); + const yAdd = await contract2.yAddress(); + expect(yAdd).to.equal("0x8ba1f109551bD432803012645Ac136ddd64DBA72"); + y = await contract2.yUint32(); + expect(y).to.equal(52); // 5+15+32 + y = await contract2.yUint64(); + expect(y).to.equal(18446744073709551600n); + }); + + it("test async decrypt uint64 non-trivial", async function () { + // console.log(this.instances.alice) + // console.log(this.instances.alice.address) + const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + inputAlice.add64(18446744073709550042n); + const encryptedAmount = inputAlice.encrypt(); + const tx = await this.contract.requestUint64NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof, { + gasLimit: 5_000_000, + }); + await tx.wait(); + await awaitAllDecryptionResults(); + const y = await this.contract.yUint64(); + expect(y).to.equal(18446744073709550042n); + }); + + it("test async decrypt ebytes256 non-trivial", async function () { + const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + inputAlice.addBytes256(bigIntToBytes(18446744073709550022n)); + const encryptedAmount = inputAlice.encrypt(); + const tx = await await this.contract.requestEbytes256NonTrivial( + encryptedAmount.handles[0], + encryptedAmount.inputProof, + { gasLimit: 5_000_000 }, + ); + await tx.wait(); + await awaitAllDecryptionResults(); + const y = await this.contract.yBytes256(); + expect(y).to.equal(ethers.toBeHex(18446744073709550022n, 256)); + }); + + it("test async decrypt ebytes256 non-trivial with snapshot [skip-on-coverage]", async function () { + if (network.name === "hardhat") { + this.snapshotId = await ethers.provider.send("evm_snapshot"); + const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + inputAlice.addBytes256(bigIntToBytes(18446744073709550022n)); + const encryptedAmount = inputAlice.encrypt(); + const tx = await await this.contract.requestEbytes256NonTrivial( + encryptedAmount.handles[0], + encryptedAmount.inputProof, + { gasLimit: 5_000_000 }, + ); + await tx.wait(); + await awaitAllDecryptionResults(); + const y = await this.contract.yBytes256(); + expect(y).to.equal(ethers.toBeHex(18446744073709550022n, 256)); + + await ethers.provider.send("evm_revert", [this.snapshotId]); + const inputAlice2 = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + inputAlice2.addBytes256(bigIntToBytes(424242n)); + const encryptedAmount2 = inputAlice2.encrypt(); + const tx2 = await await this.contract.requestEbytes256NonTrivial( + encryptedAmount2.handles[0], + encryptedAmount2.inputProof, + { gasLimit: 5_000_000 }, + ); + await tx2.wait(); + await awaitAllDecryptionResults(); + const y2 = await this.contract.yBytes256(); + expect(y2).to.equal(ethers.toBeHex(424242n, 256)); + } + }); + + it("test async decrypt mixed with ebytes256", async function () { + const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + inputAlice.addBytes256(bigIntToBytes(18446744073709550032n)); + const encryptedAmount = inputAlice.encrypt(); + const tx = await await this.contract.requestMixedBytes256(encryptedAmount.handles[0], encryptedAmount.inputProof, { + gasLimit: 5_000_000, + }); + await tx.wait(); + await awaitAllDecryptionResults(); + const y = await this.contract.yBytes256(); + expect(y).to.equal(ethers.toBeHex(18446744073709550032n, 256)); + const yb = await this.contract.yBool(); + expect(yb).to.equal(true); + const yAdd = await this.contract.yAddress(); + expect(yAdd).to.equal("0x8ba1f109551bD432803012645Ac136ddd64DBA72"); + }); +}); diff --git a/test/instance.ts b/test/instance.ts index 36f27ba..92c8ae4 100644 --- a/test/instance.ts +++ b/test/instance.ts @@ -1,87 +1,202 @@ -import { toBufferBE } from "bigint-buffer"; -import { Signer } from "ethers"; -import fhevmjs, { FhevmInstance, getPublicKeyCallParams } from "fhevmjs"; -import { ethers as hethers } from "hardhat"; +import dotenv from "dotenv"; +import { clientKeyDecryptor, createInstance as createFhevmInstance, getCiphertextCallParams } from "fhevmjs"; +import { readFileSync } from "fs"; +import * as fs from "fs"; +import { ethers, ethers as hethers, network } from "hardhat"; +import { homedir } from "os"; +import path from "path"; +import { awaitCoprocessor, getClearText } from "./coprocessorUtils"; +import { createEncryptedInputMocked, reencryptRequestMocked } from "./fhevmjsMocked"; import type { Signers } from "./signers"; import { FhevmInstances } from "./types"; -const HARDHAT_NETWORK = process.env.HARDHAT_NETWORK; +const FHE_CLIENT_KEY_PATH = process.env.FHE_CLIENT_KEY_PATH; -let publicKey: string | undefined; -let chainId: number; +let clientKey: Uint8Array | undefined; -export const createInstances = async ( - contractAddress: string, - ethers: typeof hethers, - accounts: Signers, -): Promise => { +const parsedEnvACL = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.acl")); +const aclAdd = parsedEnvACL.ACL_CONTRACT_ADDRESS; + +const createInstanceMocked = async () => { + const instance = await createFhevmInstance({ + chainId: network.config.chainId, + }); + instance.reencrypt = reencryptRequestMocked; + instance.createEncryptedInput = createEncryptedInputMocked; + instance.getPublicKey = () => "0xFFAA44433"; + return instance; +}; + +export const createInstances = async (accounts: Signers): Promise => { // Create instance const instances: FhevmInstances = {} as FhevmInstances; - await Promise.all( - Object.keys(accounts).map(async (k) => { - instances[k as keyof FhevmInstances] = await createInstance( - contractAddress, - accounts[k as keyof Signers], - ethers, - ); - }), - ); - + if (network.name === "hardhat") { + await Promise.all( + Object.keys(accounts).map(async (k) => { + instances[k as keyof FhevmInstances] = await createInstanceMocked(); + }), + ); + } else { + await Promise.all( + Object.keys(accounts).map(async (k) => { + instances[k as keyof FhevmInstances] = await createInstance(); + }), + ); + } return instances; }; -export const createInstance = async (contractAddress: string, account: Signer, ethers: typeof hethers) => { - // 1. Get chain id - const provider = ethers.provider; - - const network = await provider.getNetwork(); - chainId = +network.chainId.toString(); // Need to be a number - try { - // Get blockchain public key - const ret = await provider.call(getPublicKeyCallParams()); - const decoded = ethers.AbiCoder.defaultAbiCoder().decode(["bytes"], ret); - publicKey = decoded[0]; - } catch (e) { - publicKey = undefined; +export const createInstance = async () => { + const instance = await createFhevmInstance({ + networkUrl: network.config.url, + gatewayUrl: "http://localhost:7077", + aclAddress: aclAdd, + }); + return instance; +}; + +const getCiphertext = async (handle: bigint, ethers: typeof hethers): Promise => { + return ethers.provider.call(getCiphertextCallParams(handle)); +}; + +const getDecryptor = () => { + if (clientKey == null) { + if (FHE_CLIENT_KEY_PATH) { + clientKey = readFileSync(FHE_CLIENT_KEY_PATH); + } else { + const home = homedir(); + const clientKeyPath = path.join(home, "network-fhe-keys/cks"); + clientKey = readFileSync(clientKeyPath); + } + } + return clientKeyDecryptor(clientKey); +}; + +/** + * @debug + * This function is intended for debugging purposes only. + * It cannot be used in production code, since it requires the FHE private key for decryption. + * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. + * + * @param {bigint} a handle to decrypt + * @returns {bool} + */ +export const decryptBool = async (handle: bigint): Promise => { + if (network.name === "hardhat") { + await awaitCoprocessor(); + return (await getClearText(handle)) === "1"; + } else { + return getDecryptor().decryptBool(await getCiphertext(handle, ethers)); } +}; - const instance = await fhevmjs.createInstance({ chainId, publicKey }); - - if (HARDHAT_NETWORK === "hardhat") { - instance.encryptBool = createUintToUint8ArrayFunction(1); - instance.encrypt4 = createUintToUint8ArrayFunction(4); - instance.encrypt8 = createUintToUint8ArrayFunction(8); - instance.encrypt16 = createUintToUint8ArrayFunction(16); - instance.encrypt32 = createUintToUint8ArrayFunction(32); - instance.encrypt64 = createUintToUint8ArrayFunction(64); - instance.encryptAddress = createUintToUint8ArrayFunction(160); - instance.decrypt = (_, hexadecimalString) => BigInt(hexadecimalString); - instance.decryptAddress = (_, hexadecimalString) => ethers.getAddress(hexadecimalString.slice(26, 66)); +/** + * @debug + * This function is intended for debugging purposes only. + * It cannot be used in production code, since it requires the FHE private key for decryption. + * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. + * + * @param {bigint} handle to decrypt + * @returns {bigint} + */ +export const decrypt4 = async (handle: bigint): Promise => { + if (network.name === "hardhat") { + await awaitCoprocessor(); + return BigInt(await getClearText(handle)); + } else { + return getDecryptor().decrypt4(await getCiphertext(handle, ethers)); } - await generatePublicKey(contractAddress, account, instance); +}; - return instance; +/** + * @debug + * This function is intended for debugging purposes only. + * It cannot be used in production code, since it requires the FHE private key for decryption. + * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. + * + * @param {bigint} a handle to decrypt + * @returns {bigint} + */ +export const decrypt8 = async (handle: bigint): Promise => { + if (network.name === "hardhat") { + await awaitCoprocessor(); + return BigInt(await getClearText(handle)); + } else { + return getDecryptor().decrypt8(await getCiphertext(handle, ethers)); + } }; -const generatePublicKey = async (contractAddress: string, signer: Signer, instance: FhevmInstance) => { - // Generate token to decrypt - const generatedToken = instance.generatePublicKey({ - verifyingContract: contractAddress, - }); - // Sign the public key - const signature = await signer.signTypedData( - generatedToken.eip712.domain, - { Reencrypt: generatedToken.eip712.types.Reencrypt }, // Need to remove EIP712Domain from types - generatedToken.eip712.message, - ); - instance.setSignature(contractAddress, signature); +/** + * @debug + * This function is intended for debugging purposes only. + * It cannot be used in production code, since it requires the FHE private key for decryption. + * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. + * + * @param {bigint} a handle to decrypt + * @returns {bigint} + */ +export const decrypt16 = async (handle: bigint): Promise => { + if (network.name === "hardhat") { + await awaitCoprocessor(); + return BigInt(await getClearText(handle)); + } else { + return getDecryptor().decrypt16(await getCiphertext(handle, ethers)); + } }; -function createUintToUint8ArrayFunction(numBits: number) { - const numBytes = Math.ceil(numBits / 8); - return function (uint: number | bigint | boolean) { - const buffer = toBufferBE(BigInt(uint), numBytes); - return buffer; - }; -} +/** + * @debug + * This function is intended for debugging purposes only. + * It cannot be used in production code, since it requires the FHE private key for decryption. + * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. + * + * @param {bigint} a handle to decrypt + * @returns {bigint} + */ +export const decrypt32 = async (handle: bigint): Promise => { + if (network.name === "hardhat") { + await awaitCoprocessor(); + return BigInt(await getClearText(handle)); + } else { + return getDecryptor().decrypt32(await getCiphertext(handle, ethers)); + } +}; + +/** + * @debug + * This function is intended for debugging purposes only. + * It cannot be used in production code, since it requires the FHE private key for decryption. + * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. + * + * @param {bigint} a handle to decrypt + * @returns {bigint} + */ +export const decrypt64 = async (handle: bigint): Promise => { + if (network.name === "hardhat") { + await awaitCoprocessor(); + return BigInt(await getClearText(handle)); + } else { + return getDecryptor().decrypt64(await getCiphertext(handle, ethers)); + } +}; + +/** + * @debug + * This function is intended for debugging purposes only. + * It cannot be used in production code, since it requires the FHE private key for decryption. + * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. + * + * @param {bigint} a handle to decrypt + * @returns {string} + */ +export const decryptAddress = async (handle: bigint): Promise => { + if (network.name === "hardhat") { + await awaitCoprocessor(); + const bigintAdd = BigInt(await getClearText(handle)); + const handleStr = "0x" + bigintAdd.toString(16).padStart(40, "0"); + return handleStr; + } else { + return getDecryptor().decryptAddress(await getCiphertext(handle, ethers)); + } +}; diff --git a/test/types.ts b/test/types.ts index 1e13854..6afcffe 100644 --- a/test/types.ts +++ b/test/types.ts @@ -1,5 +1,15 @@ import type { FhevmInstance } from "fhevmjs"; +import type { Signers } from "./signers"; + +declare module "mocha" { + export interface Context { + signers: Signers; + contractAddress: string; + instances: FhevmInstances; + } +} + export interface FhevmInstances { alice: FhevmInstance; bob: FhevmInstance; diff --git a/test/utils.ts b/test/utils.ts index 0486b3d..5af310b 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,11 +1,11 @@ +import { toBufferLE } from "bigint-buffer"; import { ContractMethodArgs, Typed } from "ethers"; -import { ethers } from "hardhat"; +import { ethers, network } from "hardhat"; import { TypedContractMethod } from "../types/common"; -import { getSigners } from "./signers"; export const waitForBlock = (blockNumber: bigint | number) => { - if (process.env.HARDHAT_NETWORK === "hardhat") { + if (network.name === "hardhat") { return new Promise((resolve, reject) => { const intervalId = setInterval(async () => { try { @@ -37,7 +37,7 @@ export const waitForBlock = (blockNumber: bigint | number) => { export const waitNBlocks = async (Nblocks: number) => { const currentBlock = await ethers.provider.getBlockNumber(); - if (process.env.HARDHAT_NETWORK === "hardhat") { + if (network.name === "hardhat") { await produceDummyTransactions(Nblocks); } await waitForBlock(currentBlock + Nblocks); @@ -71,19 +71,27 @@ export const createTransaction = async { - const nullAddress = "0x0000000000000000000000000000000000000000"; - const signers = await getSigners(); - while (blockCount > 0) { - blockCount--; - // Sending 0 ETH to the null address - const tx = await signers.dave.sendTransaction({ + let counter = blockCount; + while (counter >= 0) { + counter--; + const [signer] = await ethers.getSigners(); + const nullAddress = "0x0000000000000000000000000000000000000000"; + const tx = { to: nullAddress, - value: ethers.parseEther("0"), - }); + value: 0n, + }; + const receipt = await signer.sendTransaction(tx); + await receipt.wait(); } }; export const mineNBlocks = async (n: number) => { - // this only works in mocked mode - await ethers.provider.send("hardhat_mine", ["0x" + n.toString(16)]); + for (let index = 0; index < n; index++) { + await ethers.provider.send("evm_mine"); + } +}; + +export const bigIntToBytes = (value: bigint) => { + const byteArrayLength = Math.ceil(value.toString(2).length / 8); + return new Uint8Array(toBufferLE(value, byteArrayLength)); }; From 4acfa1ee17571e5137798a62e886f5be77442900 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 23 Oct 2024 15:14:51 +0200 Subject: [PATCH 16/73] test: EncryptedERC20 --- test/encryptedERC20/EncryptedERC20.fixture.ts | 39 +- test/encryptedERC20/EncryptedERC20.test.ts | 367 +++++++++++++++++ test/encryptedERC20/EncryptedERC20.ts | 374 ------------------ test/reencrypt.ts | 34 ++ 4 files changed, 433 insertions(+), 381 deletions(-) create mode 100644 test/encryptedERC20/EncryptedERC20.test.ts delete mode 100644 test/encryptedERC20/EncryptedERC20.ts create mode 100644 test/reencrypt.ts diff --git a/test/encryptedERC20/EncryptedERC20.fixture.ts b/test/encryptedERC20/EncryptedERC20.fixture.ts index 87d8051..6549ddc 100644 --- a/test/encryptedERC20/EncryptedERC20.fixture.ts +++ b/test/encryptedERC20/EncryptedERC20.fixture.ts @@ -1,14 +1,39 @@ import { ethers } from "hardhat"; -import type { EncryptedERC20Mintable } from "../../types"; -import { getSigners } from "../signers"; +import type { IEncryptedERC20, TestEncryptedERC20Mintable } from "../../types"; +import { reencryptHandle } from "../reencrypt"; +import { Signers, getSigners } from "../signers"; +import { FhevmInstances } from "../types"; -export async function deployEncryptedERC20Fixture(): Promise { +export async function deployEncryptedERC20Fixture(name: string, symbol: string): Promise { const signers = await getSigners(); - - const contractFactory = await ethers.getContractFactory("EncryptedERC20Mintable"); - const contract = await contractFactory.connect(signers.alice).deploy("Naraggara", "NARA", signers.alice.address); // City of Zama's battle + const contractFactory = await ethers.getContractFactory("TestEncryptedERC20Mintable"); + const contract = await contractFactory.connect(signers.alice).deploy(name, symbol); await contract.waitForDeployment(); - return contract; } + +export async function reencryptAllowance( + signers: Signers, + instances: FhevmInstances, + user: string, + spender: string, + token: IEncryptedERC20, + tokenAddress: string, +): Promise { + const allowanceHandle = await token.allowance(signers[user as keyof Signers], signers[spender as keyof Signers]); + const allowance = await reencryptHandle(signers, instances, user, allowanceHandle, tokenAddress); + return allowance; +} + +export async function reencryptBalance( + signers: Signers, + instances: FhevmInstances, + user: string, + token: IEncryptedERC20, + tokenAddress: string, +): Promise { + const balanceHandle = await token.balanceOf(signers[user as keyof Signers]); + const balance = await reencryptHandle(signers, instances, user, balanceHandle, tokenAddress); + return balance; +} diff --git a/test/encryptedERC20/EncryptedERC20.test.ts b/test/encryptedERC20/EncryptedERC20.test.ts new file mode 100644 index 0000000..3f26641 --- /dev/null +++ b/test/encryptedERC20/EncryptedERC20.test.ts @@ -0,0 +1,367 @@ +import { expect } from "chai"; + +import { createInstances } from "../instance"; +import { getSigners, initSigners } from "../signers"; +import { deployEncryptedERC20Fixture, reencryptAllowance, reencryptBalance } from "./EncryptedERC20.fixture"; + +describe("EncryptedERC20", function () { + before(async function () { + await initSigners(); + this.signers = await getSigners(); + }); + + beforeEach(async function () { + const contract = await deployEncryptedERC20Fixture("Naraggara", "NARA"); + this.encryptedERC20Address = await contract.getAddress(); + this.encryptedERC20 = contract; + this.instances = await createInstances(this.signers); + }); + + it("post-deployment state", async function () { + expect(await this.encryptedERC20.totalSupply()).to.equal(0); + expect(await this.encryptedERC20.name()).to.equal("Naraggara"); + expect(await this.encryptedERC20.symbol()).to.equal("NARA"); + }); + + it("should mint the contract", async function () { + const mintAmount = 1000; + const tx = await this.encryptedERC20.mint(mintAmount); + await tx.wait(); + + expect( + await reencryptBalance(this.signers, this.instances, "alice", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(mintAmount); + + expect(await this.encryptedERC20.totalSupply()).to.equal(mintAmount); + }); + + it("should transfer tokens between two users", async function () { + const mintAmount = 10_000; + const transferAmount = 1337; + + let tx = await this.encryptedERC20.mint(mintAmount); + const t1 = await tx.wait(); + expect(t1?.status).to.eq(1); + + const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = input.encrypt(); + + tx = await this.encryptedERC20["transfer(address,bytes32,bytes)"]( + this.signers.bob.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + + const t2 = await tx.wait(); + expect(t2?.status).to.eq(1); + + // Decrypt Alice's balance + expect( + await reencryptBalance(this.signers, this.instances, "alice", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(mintAmount - transferAmount); + + // Decrypt Bob's balance + expect( + await reencryptBalance(this.signers, this.instances, "bob", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(transferAmount); + }); + + it("should not transfer tokens between two users if transfer amount is higher than balance", async function () { + // @dev There is no transfer done since the mint amount is smaller than the transfer + // amount. + const mintAmount = 1000; + const transferAmount = 1337; + + let tx = await this.encryptedERC20.mint(mintAmount); + await tx.wait(); + + const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = input.encrypt(); + tx = await this.encryptedERC20["transfer(address,bytes32,bytes)"]( + this.signers.bob.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + await tx.wait(); + + // Decrypt Alice's balance + expect( + await reencryptBalance(this.signers, this.instances, "alice", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(mintAmount); + + // Decrypt Bob's balance + expect( + await reencryptBalance(this.signers, this.instances, "bob", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(0); + }); + + it("should be able to transferFrom only if allowance is sufficient", async function () { + // @dev There is no transfer done since the mint amount is smaller than the transfer + // amount. + const mintAmount = 10_000; + const transferAmount = 1337; + + let tx = await this.encryptedERC20.mint(mintAmount); + await tx.wait(); + + const inputAlice = this.instances.alice.createEncryptedInput( + this.encryptedERC20Address, + this.signers.alice.address, + ); + inputAlice.add64(transferAmount); + const encryptedAllowanceAmount = inputAlice.encrypt(); + tx = await this.encryptedERC20["approve(address,bytes32,bytes)"]( + this.signers.bob.address, + encryptedAllowanceAmount.handles[0], + encryptedAllowanceAmount.inputProof, + ); + await tx.wait(); + + // @dev The allowance amount is set to be equal to the transfer amount. + expect( + await reencryptAllowance( + this.signers, + this.instances, + "alice", + "bob", + this.encryptedERC20, + this.encryptedERC20Address, + ), + ).to.equal(transferAmount); + + const bobErc20 = this.encryptedERC20.connect(this.signers.bob); + const inputBob1 = this.instances.bob.createEncryptedInput(this.encryptedERC20Address, this.signers.bob.address); + inputBob1.add64(transferAmount + 1); // above allowance so next tx should actually not send any token + const encryptedTransferAmount = inputBob1.encrypt(); + const tx2 = await bobErc20["transferFrom(address,address,bytes32,bytes)"]( + this.signers.alice.address, + this.signers.bob.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + await tx2.wait(); + + // Decrypt Alice's balance + expect( + await reencryptBalance(this.signers, this.instances, "alice", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(mintAmount); // check that transfer did not happen, as expected + + // Decrypt Bob's balance + expect( + await reencryptBalance(this.signers, this.instances, "bob", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(0); // check that transfer did not happen, as expected + + const inputBob2 = this.instances.bob.createEncryptedInput(this.encryptedERC20Address, this.signers.bob.address); + inputBob2.add64(transferAmount); // below allowance so next tx should send token + const encryptedTransferAmount2 = inputBob2.encrypt(); + const tx3 = await bobErc20["transferFrom(address,address,bytes32,bytes)"]( + this.signers.alice.address, + this.signers.bob.address, + encryptedTransferAmount2.handles[0], + encryptedTransferAmount2.inputProof, + ); + await tx3.wait(); + + // Decrypt Alice's balance + expect( + await reencryptBalance(this.signers, this.instances, "alice", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(mintAmount - transferAmount); // check that transfer did happen this time + + // Decrypt Bob's balance + expect( + await reencryptBalance(this.signers, this.instances, "bob", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(transferAmount); // check that transfer did happen this time + + // Verify Alice's allowance is 0 + expect( + await reencryptAllowance( + this.signers, + this.instances, + "alice", + "bob", + this.encryptedERC20, + this.encryptedERC20Address, + ), + ).to.equal(0); + }); + + it("should not be able to read the allowance if not spender/owner after initialization", async function () { + const amount = 10_000; + + const inputAlice = this.instances.alice.createEncryptedInput( + this.encryptedERC20Address, + this.signers.alice.address, + ); + inputAlice.add64(amount); + const encryptedAllowanceAmount = inputAlice.encrypt(); + + const tx = await this.encryptedERC20 + .connect(this.signers.alice) + ["approve(address,bytes32,bytes)"]( + this.signers.bob.address, + encryptedAllowanceAmount.handles[0], + encryptedAllowanceAmount.inputProof, + ); + + await tx.wait(); + + const allowanceHandleAlice = await this.encryptedERC20.allowance(this.signers.alice, this.signers.bob); + + const { publicKey: publicKeyCarol, privateKey: privateKeyCarol } = this.instances.carol.generateKeypair(); + const eip712Carol = this.instances.carol.createEIP712(publicKeyCarol, this.encryptedERC20Address); + const signatureCarol = await this.signers.carol.signTypedData( + eip712Carol.domain, + { Reencrypt: eip712Carol.types.Reencrypt }, + eip712Carol.message, + ); + + try { + await this.instances.bob.reencrypt( + allowanceHandleAlice, + privateKeyCarol, + publicKeyCarol, + signatureCarol.replace("0x", ""), + this.encryptedERC20Address, + this.signers.carol.address, + ); + + expect.fail("Expected an error to be thrown - Carol should not be able to reencrypt Bob's allowance for Alice"); + } catch (error) { + if (error instanceof Error) { + expect(error.message).to.equal("User is not authorized to reencrypt this handle!"); + } + } + }); + + it("should not be able to read the balance if not user after initialization", async function () { + // Mint is used to initialize the balanceOf(alice) + const amount = 10_000; + const tx = await this.encryptedERC20.connect(this.signers.alice).mint(amount); + await tx.wait(); + + const balanceHandleAlice = await this.encryptedERC20.balanceOf(this.signers.alice); + + const { publicKey: publicKeyBob, privateKey: privateKeyBob } = this.instances.bob.generateKeypair(); + const eip712Bob = this.instances.bob.createEIP712(publicKeyBob, this.encryptedERC20Address); + const signatureBob = await this.signers.bob.signTypedData( + eip712Bob.domain, + { Reencrypt: eip712Bob.types.Reencrypt }, + eip712Bob.message, + ); + + try { + await this.instances.bob.reencrypt( + balanceHandleAlice, + privateKeyBob, + publicKeyBob, + signatureBob.replace("0x", ""), + this.encryptedERC20Address, + this.signers.bob.address, + ); + expect.fail("Expected an error to be thrown - Bob should not be able to reencrypt Alice's balance"); + } catch (error) { + if (error instanceof Error) { + expect(error.message).to.equal("User is not authorized to reencrypt this handle!"); + } + } + }); + + it("Sender who is not allowed cannot transfer using a handle from another account", async function () { + const mintAmount = 100_000; + const transferAmount = 50_000; + let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); + await tx.wait(); + + const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = input.encrypt(); + + tx = await this.encryptedERC20 + .connect(this.signers.alice) + ["transfer(address,bytes32,bytes)"]( + this.signers.carol.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + + await tx.wait(); + + const balanceHandleAlice = await this.encryptedERC20.balanceOf(this.signers.alice.address); + + await expect( + this.encryptedERC20.connect(this.signers.bob).transfer(this.signers.carol.address, balanceHandleAlice), + ).to.be.revertedWithCustomError(this.encryptedERC20, "TFHESenderNotAllowed"); + }); + + it("Sender who is not allowed cannot transferFrom using a handle from another account", async function () { + const mintAmount = 100_000; + const transferAmount = 50_000; + + let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); + await tx.wait(); + + let input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(mintAmount); + const encryptedAllowanceAmount = input.encrypt(); + + tx = await this.encryptedERC20 + .connect(this.signers.alice) + ["approve(address,bytes32,bytes)"]( + this.signers.carol.address, + encryptedAllowanceAmount.handles[0], + encryptedAllowanceAmount.inputProof, + ); + + input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = input.encrypt(); + + tx = await this.encryptedERC20 + .connect(this.signers.carol) + ["transferFrom(address,address,bytes32,bytes)"]( + this.signers.alice.address, + this.signers.carol.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + + const allowanceHandleAlice = await this.encryptedERC20.allowance( + this.signers.alice.address, + this.signers.carol.address, + ); + + await expect( + this.encryptedERC20 + .connect(this.signers.bob) + .transferFrom(this.signers.alice.address, this.signers.bob.address, allowanceHandleAlice), + ).to.be.revertedWithCustomError(this.encryptedERC20, "TFHESenderNotAllowed"); + }); + + it("Sender who is not allowed cannot approve using a handle from another account", async function () { + const amount = 100_000; + const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(amount); + const encryptedAllowanceAmount = input.encrypt(); + + const tx = await this.encryptedERC20 + .connect(this.signers.alice) + ["approve(address,bytes32,bytes)"]( + this.signers.carol.address, + encryptedAllowanceAmount.handles[0], + encryptedAllowanceAmount.inputProof, + ); + + await tx.wait(); + + const allowanceHandleAlice = await this.encryptedERC20.allowance( + this.signers.alice.address, + this.signers.carol.address, + ); + + await expect( + this.encryptedERC20.connect(this.signers.bob).approve(this.signers.carol.address, allowanceHandleAlice), + ).to.be.revertedWithCustomError(this.encryptedERC20, "TFHESenderNotAllowed"); + }); +}); diff --git a/test/encryptedERC20/EncryptedERC20.ts b/test/encryptedERC20/EncryptedERC20.ts deleted file mode 100644 index bd144a2..0000000 --- a/test/encryptedERC20/EncryptedERC20.ts +++ /dev/null @@ -1,374 +0,0 @@ -import { expect } from "chai"; -import { ethers, network } from "hardhat"; - -import { createInstances } from "../instance"; -import { getSigners, initSigners } from "../signers"; -import { deployEncryptedERC20Fixture } from "./EncryptedERC20.fixture"; - -describe("EncryptedERC20", function () { - before(async function () { - await initSigners(); - this.signers = await getSigners(); - }); - - beforeEach(async function () { - const contract = await deployEncryptedERC20Fixture(); - this.contractAddress = await contract.getAddress(); - this.erc20 = contract; - this.instances = await createInstances(this.contractAddress, ethers, this.signers); - }); - - it("should read token name and symbol", async function () { - const name = await this.erc20.name(); - expect(name, "Naraggara"); - const symbol = await this.erc20.symbol(); - expect(symbol, "NARA"); - }); - - it("should mint the contract", async function () { - const transaction = await this.erc20.mint(1000, this.signers.alice.address); - await transaction.wait(); - // Call the method - const token = this.instances.alice.getPublicKey(this.contractAddress) || { - signature: "", - publicKey: "", - }; - const encryptedBalance = await this.erc20.balanceOf(this.signers.alice, token.publicKey, token.signature); - // Decrypt the balance - const balance = this.instances.alice.decrypt(this.contractAddress, encryptedBalance); - expect(balance).to.equal(1000); - - const totalSupply = await this.erc20.totalSupply(); - // Decrypt the total supply - expect(totalSupply).to.equal(1000); - }); - - it("non-owner should be unable to mint", async function () { - if (network.name === "hardhat") { - // mocked mode - await expect(this.erc20.connect(this.signers.bob).mint(1000, this.signers.alice.address)) - .to.be.revertedWithCustomError(this.erc20, "OwnableUnauthorizedAccount") - .withArgs(this.signers.bob.address); - } else { - // fhevm-mode - const tx = await this.erc20 - .connect(this.signers.bob) - .mint(1000, this.signers.alice.address, { gasLimit: 1_000_000n }); - await expect(tx.wait()).to.throw; - } - }); - - it("should transfer tokens between two users", async function () { - const transaction = await this.erc20.mint(10000, this.signers.alice.address); - await transaction.wait(); - - const encryptedTransferAmount = this.instances.alice.encrypt64(1337); - const tx = await this.erc20["transfer(address,bytes)"](this.signers.bob.address, encryptedTransferAmount); - await tx.wait(); - - const tokenAlice = this.instances.alice.getPublicKey(this.contractAddress)!; - - const encryptedBalanceAlice = await this.erc20.balanceOf( - this.signers.alice, - tokenAlice.publicKey, - tokenAlice.signature, - ); - - // Decrypt the balance - const balanceAlice = this.instances.alice.decrypt(this.contractAddress, encryptedBalanceAlice); - - expect(balanceAlice).to.equal(10000 - 1337); - - const bobErc20 = this.erc20.connect(this.signers.bob); - - const tokenBob = this.instances.bob.getPublicKey(this.contractAddress)!; - - const encryptedBalanceBob = await bobErc20.balanceOf(this.signers.bob, tokenBob.publicKey, tokenBob.signature); - - // Decrypt the balance - const balanceBob = this.instances.bob.decrypt(this.contractAddress, encryptedBalanceBob); - - expect(balanceBob).to.equal(1337); - }); - - it("should only be able to read hiw own balance", async function () { - const transaction = await this.erc20.mint(10000, this.signers.alice.address); - await transaction.wait(); - const tokenAlice = this.instances.alice.getPublicKey(this.contractAddress)!; - const encryptedBalanceAlice = await this.erc20.balanceOf( - this.signers.alice, - tokenAlice.publicKey, - tokenAlice.signature, - ); - // Decrypt own balance - const balanceAlice = this.instances.alice.decrypt(this.contractAddress, encryptedBalanceAlice); - expect(balanceAlice).to.equal(10000); - - // Alice cannot decrypt Bob's balance - await expect(this.erc20.balanceOf(this.signers.bob, tokenAlice.publicKey, tokenAlice.signature)).to.be.revertedWith( - "User cannot reencrypt a non-owned wallet balance", - ); - - // Alice cannot read her own balance with an invalid EIP-712 signature - const tokenBob = this.instances.bob.getPublicKey(this.contractAddress)!; - await expect(this.erc20.balanceOf(this.signers.alice, tokenBob.publicKey, tokenBob.signature)).to.be.revertedWith( - "EIP712 signer and transaction signer do not match", - ); - }); - - it("balanceOfMe should recover own's balance handle", async function () { - expect(await this.erc20.balanceOfMe()).to.be.eq(0n); // Alice's initial handle is 0 - const transaction = await this.erc20.mint(1000, this.signers.alice.address); - await transaction.wait(); - if (network.name === "hardhat") { - // mocked mode - expect(await this.erc20.balanceOfMe()).to.be.eq(1000n); - } else { - // fhevm node mode (real handle) - expect(await this.erc20.balanceOfMe()).to.be.gt(0); - } - }); - - it("should not transfer tokens between two users", async function () { - const transaction = await this.erc20.mint(1000, this.signers.alice.address); - await transaction.wait(); - - const encryptedTransferAmount = this.instances.alice.encrypt64(1337); - const tx = await this.erc20["transfer(address,bytes)"](this.signers.bob.address, encryptedTransferAmount); - await tx.wait(); - - const tokenAlice = this.instances.alice.getPublicKey(this.contractAddress)!; - - const encryptedBalanceAlice = await this.erc20.balanceOf( - this.signers.alice, - tokenAlice.publicKey, - tokenAlice.signature, - ); - - // Decrypt the balance - const balanceAlice = this.instances.alice.decrypt(this.contractAddress, encryptedBalanceAlice); - - expect(balanceAlice).to.equal(1000); - - const bobErc20 = this.erc20.connect(this.signers.bob); - - const tokenBob = this.instances.bob.getPublicKey(this.contractAddress)!; - - const encryptedBalanceBob = await bobErc20.balanceOf(this.signers.bob, tokenBob.publicKey, tokenBob.signature); - - // Decrypt the balance - const balanceBob = this.instances.bob.decrypt(this.contractAddress, encryptedBalanceBob); - - expect(balanceBob).to.equal(0); - }); - - it("should be able to transferFrom only if allowance is sufficient", async function () { - const transaction = await this.erc20.mint(10000, this.signers.alice.address); - await transaction.wait(); - - const encryptedAllowanceAmount = this.instances.alice.encrypt64(1337); - const tx = await this.erc20["approve(address,bytes)"](this.signers.bob.address, encryptedAllowanceAmount); - await tx.wait(); - - const bobErc20 = this.erc20.connect(this.signers.bob); - const encryptedTransferAmount = this.instances.bob.encrypt64(1338); // above allowance so next tx should actually not send any token - const tx2 = await bobErc20["transferFrom(address,address,bytes)"]( - this.signers.alice.address, - this.signers.bob.address, - encryptedTransferAmount, - ); - await tx2.wait(); - - const tokenAlice = this.instances.alice.getPublicKey(this.contractAddress)!; - const encryptedBalanceAlice = await this.erc20.balanceOf( - this.signers.alice, - tokenAlice.publicKey, - tokenAlice.signature, - ); - - // Decrypt the balance - const balanceAlice = this.instances.alice.decrypt(this.contractAddress, encryptedBalanceAlice); - expect(balanceAlice).to.equal(10000); // check that transfer did not happen, as expected - - const tokenBob = this.instances.bob.getPublicKey(this.contractAddress)!; - const encryptedBalanceBob = await bobErc20.balanceOf(this.signers.bob, tokenBob.publicKey, tokenBob.signature); - // Decrypt the balance - const balanceBob = this.instances.bob.decrypt(this.contractAddress, encryptedBalanceBob); - expect(balanceBob).to.equal(0); // check that transfer did not happen, as expected - - const encryptedTransferAmount2 = this.instances.bob.encrypt64(1337); // below allowance so next tx should send token - const tx3 = await bobErc20["transferFrom(address,address,bytes)"]( - this.signers.alice.address, - this.signers.bob.address, - encryptedTransferAmount2, - ); - await tx3.wait(); - - const encryptedBalanceAlice2 = await this.erc20.balanceOf( - this.signers.alice, - tokenAlice.publicKey, - tokenAlice.signature, - ); - // Decrypt the balance - const balanceAlice2 = this.instances.alice.decrypt(this.contractAddress, encryptedBalanceAlice2); - expect(balanceAlice2).to.equal(10000 - 1337); // check that transfer did happen this time - - const encryptedBalanceBob2 = await bobErc20.balanceOf(this.signers.bob, tokenBob.publicKey, tokenBob.signature); - const balanceBob2 = this.instances.bob.decrypt(this.contractAddress, encryptedBalanceBob2); - expect(balanceBob2).to.equal(1337); // check that transfer did happen this time - }); - - it("only spender and owner could read their allowance", async function () { - const transaction = await this.erc20.mint(10000, this.signers.alice.address); - await transaction.wait(); - - const encryptedAllowanceAmount = this.instances.alice.encrypt64(1337); - const tx = await this.erc20["approve(address,bytes)"](this.signers.bob.address, encryptedAllowanceAmount); - await tx.wait(); - - const bobErc20 = this.erc20.connect(this.signers.bob); - const encryptedTransferAmount = this.instances.bob.encrypt64(337); - const tx2 = await bobErc20["transferFrom(address,address,bytes)"]( - this.signers.alice.address, - this.signers.bob.address, - encryptedTransferAmount, - ); - await tx2.wait(); - - const tokenAlice = this.instances.alice.getPublicKey(this.contractAddress)!; - - // Alice decrypts the allowance for (Alice,Bob) - let encryptedAllowanceAliceBob = await this.erc20.allowance( - this.signers.alice, - this.signers.bob, - tokenAlice.publicKey, - tokenAlice.signature, - ); - let allowanceAliceBob = this.instances.alice.decrypt(this.contractAddress, encryptedAllowanceAliceBob); - expect(allowanceAliceBob).to.equal(1000); - - // Bob decrypts the allowance for (Alice,Bob) - const tokenBob = this.instances.bob.getPublicKey(this.contractAddress)!; - encryptedAllowanceAliceBob = await bobErc20.allowance( - this.signers.alice, - this.signers.bob, - tokenBob.publicKey, - tokenBob.signature, - ); - allowanceAliceBob = this.instances.bob.decrypt(this.contractAddress, encryptedAllowanceAliceBob); - expect(allowanceAliceBob).to.equal(1000); - - // Carol cannot get the allowance for (Alice,Bob) - const tokenCarol = this.instances.carol.getPublicKey(this.contractAddress)!; - await expect( - this.erc20 - .connect(this.signers.carol) - .allowance(this.signers.alice, this.signers.bob, tokenCarol.publicKey, tokenCarol.signature), - ).to.be.revertedWith("Caller must be owner or spender"); - - // Alice cannot decrypt with invalid EIP-712 signature - await expect( - this.erc20.allowance(this.signers.alice, this.signers.bob, tokenBob.publicKey, tokenBob.signature), - ).to.be.revertedWith("EIP712 signer and transaction signer do not match"); - - // Carol would get a null allowance for (Alice,Carol) - expect( - this.instances.carol.decrypt( - this.contractAddress, - await this.erc20 - .connect(this.signers.carol) - .allowance(this.signers.alice, this.signers.carol, tokenCarol.publicKey, tokenCarol.signature), - ), - ).to.equal(0n); - }); - - it("should handle errors correctly", async function () { - // case 1 succesful transfer - const transaction = await this.erc20.mint(10000, this.signers.alice.address); - await transaction.wait(); - let encryptedTransferAmount = this.instances.alice.encrypt64(1337); - const tx = await this.erc20["transfer(address,bytes)"](this.signers.bob.address, encryptedTransferAmount); - await tx.wait(); - const tokenAlice = this.instances.alice.getPublicKey(this.contractAddress)!; - let encryptedErrorCode = await this.erc20.reencryptError(0n, tokenAlice.publicKey, tokenAlice.signature); - // Decrypt the error code - let errorCode = this.instances.alice.decrypt(this.contractAddress, encryptedErrorCode); - expect(errorCode).to.equal(0); - - // case 2 failed transfer - encryptedTransferAmount = this.instances.alice.encrypt64(100000n); - const tx2 = await this.erc20["transfer(address,bytes)"](this.signers.bob.address, encryptedTransferAmount); - await tx2.wait(); - encryptedErrorCode = await this.erc20.reencryptError(1n, tokenAlice.publicKey, tokenAlice.signature); - // Decrypt the error code - errorCode = this.instances.alice.decrypt(this.contractAddress, encryptedErrorCode); - expect(errorCode).to.equal(1); - - // case 3 successful transferFrom - const encryptedAllowanceAmount = this.instances.alice.encrypt64(20000); - const tx3 = await this.erc20["approve(address,bytes)"](this.signers.bob.address, encryptedAllowanceAmount); - await tx3.wait(); - - const bobErc20 = this.erc20.connect(this.signers.bob); - encryptedTransferAmount = this.instances.bob.encrypt64(1338); - const tx4 = await bobErc20["transferFrom(address,address,bytes)"]( - this.signers.alice.address, - this.signers.bob.address, - encryptedTransferAmount, - ); - await tx4.wait(); - const tokenBob = this.instances.bob.getPublicKey(this.contractAddress)!; - encryptedErrorCode = await bobErc20.reencryptError(2n, tokenBob.publicKey, tokenBob.signature); - // Decrypt the error code - errorCode = this.instances.bob.decrypt(this.contractAddress, encryptedErrorCode); - expect(errorCode).to.equal(0); - // Bob cannot decrypt with invalid EIP-712 signature - await expect(bobErc20.reencryptError(2n, tokenAlice.publicKey, tokenAlice.signature)).to.be.revertedWith( - "EIP712 signer and transaction signer do not match", - ); - - // case 4 failed transferFrom because of unsufficient balance - encryptedTransferAmount = this.instances.bob.encrypt64(15000); - const tx5 = await bobErc20["transferFrom(address,address,bytes)"]( - this.signers.alice.address, - this.signers.bob.address, - encryptedTransferAmount, - ); - await tx5.wait(); - encryptedErrorCode = await bobErc20.reencryptError(3n, tokenBob.publicKey, tokenBob.signature); - // Decrypt the error code - errorCode = this.instances.bob.decrypt(this.contractAddress, encryptedErrorCode); - expect(errorCode).to.equal(1); - - // case 5 failed transferFrom because of unsufficient allowance - const tokenCarol = this.instances.carol.getPublicKey(this.contractAddress)!; - encryptedTransferAmount = this.instances.bob.encrypt64(1); - const tx6 = await this.erc20 - .connect(this.signers.carol) - ["transferFrom(address,address,bytes)"]( - this.signers.alice.address, - this.signers.bob.address, - encryptedTransferAmount, - ); - await tx6.wait(); - encryptedErrorCode = await this.erc20 - .connect(this.signers.carol) - .reencryptError(4n, tokenCarol.publicKey, tokenCarol.signature); - // Decrypt the error code - errorCode = this.instances.carol.decrypt(this.contractAddress, encryptedErrorCode); - expect(errorCode).to.equal(2); - - // Cannot decrypt an invalid transferID - if (network.name !== "hardhat") { - // only true in real fhEVM mode (TFHE.isInitialized always returns true in mocked mode) - await expect( - this.erc20.connect(this.signers.carol).reencryptError(5n, tokenCarol.publicKey, tokenCarol.signature), - ).to.be.revertedWith("Invalid transferId"); - } - - // Non-sender cannot decrypt - await expect( - this.erc20.connect(this.signers.alice).reencryptError(4n, tokenAlice.publicKey, tokenAlice.signature), - ).to.be.revertedWith("Only spender can reencrypt his error"); - }); -}); diff --git a/test/reencrypt.ts b/test/reencrypt.ts new file mode 100644 index 0000000..00b97a3 --- /dev/null +++ b/test/reencrypt.ts @@ -0,0 +1,34 @@ +import { Signers } from "./signers"; +import { FhevmInstances } from "./types"; + +/** + * @debug + * This function is to reencrypt handles. + */ +export async function reencryptHandle( + signers: Signers, + instances: FhevmInstances, + user: string, + handle: bigint, + contractAddress: string, +): Promise { + // Verify if the type is matched + const { publicKey: publicKey, privateKey: privateKey } = instances[user as keyof FhevmInstances].generateKeypair(); + const eip712 = instances[user as keyof FhevmInstances].createEIP712(publicKey, contractAddress); + const signature = await signers[user as keyof Signers].signTypedData( + eip712.domain, + { Reencrypt: eip712.types.Reencrypt }, + eip712.message, + ); + + const reencryptedHandle = await instances[user as keyof FhevmInstances].reencrypt( + handle, + privateKey, + publicKey, + signature.replace("0x", ""), + contractAddress, + signers[user as keyof Signers].address, + ); + + return reencryptedHandle; +} From f02c910545425d28a393b2d24d5f3ffdd87e0f42 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 24 Oct 2024 09:55:52 +0200 Subject: [PATCH 17/73] refactor: Decimals --- contracts/token/ERC20/EncryptedERC20.sol | 10 +++++++--- contracts/token/ERC20/IEncryptedERC20.sol | 5 +++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/contracts/token/ERC20/EncryptedERC20.sol b/contracts/token/ERC20/EncryptedERC20.sol index cb9ec57..2a2016a 100644 --- a/contracts/token/ERC20/EncryptedERC20.sol +++ b/contracts/token/ERC20/EncryptedERC20.sol @@ -8,9 +8,6 @@ import { IEncryptedERC20 } from "./IEncryptedERC20.sol"; * @title EncryptedERC20 */ abstract contract EncryptedERC20 is IEncryptedERC20 { - /// @notice Number of decimals. - uint8 internal constant _DECIMALS = 6; - /// @notice Total supply. uint64 internal _totalSupply; @@ -117,6 +114,13 @@ abstract contract EncryptedERC20 is IEncryptedERC20 { return _balances[account]; } + /** + * @notice See {IEncryptedERC20-decimals}. + */ + function decimals() public view virtual returns (uint8) { + return 6; + } + /** * @notice See {IEncryptedERC20-name}. */ diff --git a/contracts/token/ERC20/IEncryptedERC20.sol b/contracts/token/ERC20/IEncryptedERC20.sol index b066b41..08c2631 100644 --- a/contracts/token/ERC20/IEncryptedERC20.sol +++ b/contracts/token/ERC20/IEncryptedERC20.sol @@ -66,6 +66,11 @@ interface IEncryptedERC20 { */ function balanceOf(address wallet) external view returns (euint64); + /** + * @notice Returns the number of decimals. + */ + function decimals() external view returns (uint8); + /** * @notice Returns the name of the token. */ From 70e548ed71a92046e29818d029a77cf0a9ac7fd9 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 24 Oct 2024 09:57:54 +0200 Subject: [PATCH 18/73] refactor: Virtual _isSenderAllowedForAmount --- contracts/token/ERC20/EncryptedERC20.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/token/ERC20/EncryptedERC20.sol b/contracts/token/ERC20/EncryptedERC20.sol index 2a2016a..42b6d36 100644 --- a/contracts/token/ERC20/EncryptedERC20.sol +++ b/contracts/token/ERC20/EncryptedERC20.sol @@ -178,7 +178,7 @@ abstract contract EncryptedERC20 is IEncryptedERC20 { return _allowances[owner][spender]; } - function _isSenderAllowedForAmount(euint64 amount) internal view { + function _isSenderAllowedForAmount(euint64 amount) internal view virtual { if (!TFHE.isSenderAllowed(amount)) { revert TFHESenderNotAllowed(); } From d54db0f615c29e52e636aa494193bc5a15c7948a Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:37:45 +0200 Subject: [PATCH 19/73] build: Fix the version of OZ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 124fd4e..009daa5 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "fhevm:faucet:eve": "docker exec -i fhevm faucet $(npx hardhat task:getEthereumAddressEve)" }, "dependencies": { - "@openzeppelin/contracts": "^5.0.2", + "@openzeppelin/contracts": "5.0.2", "extra-bigint": "^1.1.18", "sqlite3": "^5.1.7" } From a3133100551554fe3e9bca3d0261bc5b46160c96 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:39:13 +0200 Subject: [PATCH 20/73] fix: EncryptedERC20Mintable.sol --- contracts/test/TestEncryptedERC20Mintable.sol | 35 --------------- .../extensions/EncryptedERC20Mintable.sol | 44 +++++++++++++++++++ test/encryptedERC20/EncryptedERC20.fixture.ts | 18 +++++--- test/encryptedERC20/EncryptedERC20.test.ts | 2 +- 4 files changed, 57 insertions(+), 42 deletions(-) delete mode 100644 contracts/test/TestEncryptedERC20Mintable.sol create mode 100644 contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol diff --git a/contracts/test/TestEncryptedERC20Mintable.sol b/contracts/test/TestEncryptedERC20Mintable.sol deleted file mode 100644 index addb494..0000000 --- a/contracts/test/TestEncryptedERC20Mintable.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause-Clear -pragma solidity ^0.8.24; - -import "fhevm/lib/TFHE.sol"; -import { EncryptedERC20 } from "../token/ERC20/EncryptedERC20.sol"; - -/** - * @title TestEncryptedERC20Mintable - * @notice This test contract inherits EncryptedERC20. - * @dev It allows any account to mint tokens. Mint amounts are public. - */ -contract TestEncryptedERC20Mintable is EncryptedERC20 { - /** - * @notice Emitted when `amount` tokens are minted to one account (`to`). - */ - event Mint(address indexed to, uint64 amount); - - /** - * @param name_ Name of the token. - * @param symbol_ Symbol. - */ - constructor(string memory name_, string memory symbol_) EncryptedERC20(name_, symbol_) {} - - /** - * @notice Mint tokens. - * @param amount Amount of tokens to mint. - */ - function mint(uint64 amount) public { - _balances[msg.sender] = TFHE.add(_balances[msg.sender], amount); // overflow impossible because of next line - TFHE.allow(_balances[msg.sender], address(this)); - TFHE.allow(_balances[msg.sender], msg.sender); - _totalSupply = _totalSupply + amount; - emit Mint(msg.sender, amount); - } -} diff --git a/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol b/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol new file mode 100644 index 0000000..b55ffb2 --- /dev/null +++ b/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import "fhevm/lib/TFHE.sol"; +import { Ownable2Step, Ownable } from "@openzeppelin/contracts/access/Ownable2Step.sol"; + +import { EncryptedERC20 } from "../EncryptedERC20.sol"; + +/** + * @title EncryptedERC20Mintable + * @notice This contract inherits EncryptedERC20. + * @dev It allows an owner to mint tokens. Mint amounts are public. + */ +contract EncryptedERC20Mintable is Ownable2Step, EncryptedERC20 { + /** + * @notice Emitted when `amount` tokens are minted to one account (`to`). + */ + event Mint(address indexed to, uint64 amount); + + /** + * @param name_ Name of the token. + * @param symbol_ Symbol. + * @param owner_ Owner address. + */ + constructor( + string memory name_, + string memory symbol_, + address owner_ + ) Ownable(owner_) EncryptedERC20(name_, symbol_) {} + + /** + * @notice Mint tokens. + * @param amount Amount of tokens to mint. + */ + function mint(uint64 amount) public { + _balances[msg.sender] = TFHE.add(_balances[msg.sender], amount); + TFHE.allow(_balances[msg.sender], address(this)); + TFHE.allow(_balances[msg.sender], msg.sender); + /// @dev Since _totalSupply is not encrypted and _totalSupply >= balances[msg.sender], + /// the next line contains an overflow check for the encrypted operation above. + _totalSupply = _totalSupply + amount; + emit Mint(msg.sender, amount); + } +} diff --git a/test/encryptedERC20/EncryptedERC20.fixture.ts b/test/encryptedERC20/EncryptedERC20.fixture.ts index 6549ddc..507c72f 100644 --- a/test/encryptedERC20/EncryptedERC20.fixture.ts +++ b/test/encryptedERC20/EncryptedERC20.fixture.ts @@ -1,14 +1,20 @@ import { ethers } from "hardhat"; -import type { IEncryptedERC20, TestEncryptedERC20Mintable } from "../../types"; +import type { EncryptedERC20Mintable, IEncryptedERC20 } from "../../types"; import { reencryptHandle } from "../reencrypt"; -import { Signers, getSigners } from "../signers"; +import { Signers } from "../signers"; import { FhevmInstances } from "../types"; -export async function deployEncryptedERC20Fixture(name: string, symbol: string): Promise { - const signers = await getSigners(); - const contractFactory = await ethers.getContractFactory("TestEncryptedERC20Mintable"); - const contract = await contractFactory.connect(signers.alice).deploy(name, symbol); +export async function deployEncryptedERC20Fixture( + signers: Signers, + name: string, + symbol: string, + owner: string, +): Promise { + const contractFactory = await ethers.getContractFactory("EncryptedERC20Mintable"); + const contract = await contractFactory + .connect(signers[owner as keyof Signers]) + .deploy(name, symbol, signers[owner as keyof Signers].address); await contract.waitForDeployment(); return contract; } diff --git a/test/encryptedERC20/EncryptedERC20.test.ts b/test/encryptedERC20/EncryptedERC20.test.ts index 3f26641..1374404 100644 --- a/test/encryptedERC20/EncryptedERC20.test.ts +++ b/test/encryptedERC20/EncryptedERC20.test.ts @@ -11,7 +11,7 @@ describe("EncryptedERC20", function () { }); beforeEach(async function () { - const contract = await deployEncryptedERC20Fixture("Naraggara", "NARA"); + const contract = await deployEncryptedERC20Fixture(this.signers, "Naraggara", "NARA", "alice"); this.encryptedERC20Address = await contract.getAddress(); this.encryptedERC20 = contract; this.instances = await createInstances(this.signers); From b15dac07002ef9aee0b69007d5d45e7d6d59f93c Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:40:55 +0200 Subject: [PATCH 21/73] fix: Modifier --- contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol b/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol index b55ffb2..737b4ac 100644 --- a/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol +++ b/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol @@ -32,7 +32,7 @@ contract EncryptedERC20Mintable is Ownable2Step, EncryptedERC20 { * @notice Mint tokens. * @param amount Amount of tokens to mint. */ - function mint(uint64 amount) public { + function mint(uint64 amount) public onlyOwner { _balances[msg.sender] = TFHE.add(_balances[msg.sender], amount); TFHE.allow(_balances[msg.sender], address(this)); TFHE.allow(_balances[msg.sender], msg.sender); From 8bec0915f283edb69c3aa73310aa9a7b503b5bdf Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 24 Oct 2024 11:32:47 +0200 Subject: [PATCH 22/73] docs: Natspec --- contracts/token/ERC20/EncryptedERC20.sol | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contracts/token/ERC20/EncryptedERC20.sol b/contracts/token/ERC20/EncryptedERC20.sol index 42b6d36..48358f3 100644 --- a/contracts/token/ERC20/EncryptedERC20.sol +++ b/contracts/token/ERC20/EncryptedERC20.sol @@ -6,6 +6,11 @@ import { IEncryptedERC20 } from "./IEncryptedERC20.sol"; /** * @title EncryptedERC20 + * @notice This contract implements an encrypted ERC20-like token with confidential balances using + * Zama's FHE (Fully Homomorphic Encryption) library. + * @dev It supports standard ERC20 functions such as transferring tokens, minting, + * and setting allowances, but uses encrypted data types. + * The total supply is not encrypted. */ abstract contract EncryptedERC20 is IEncryptedERC20 { /// @notice Total supply. From b755f568088fe2a8f3e5a6c77cdf06b109589b57 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 24 Oct 2024 14:41:59 +0200 Subject: [PATCH 23/73] feat: Add checks for handle types --- test/encryptedERC20/EncryptedERC20.fixture.ts | 6 +- test/handleTypeCheck.ts | 19 +++ test/instance.ts | 15 ++ test/reencrypt.ts | 151 +++++++++++++++++- 4 files changed, 185 insertions(+), 6 deletions(-) create mode 100644 test/handleTypeCheck.ts diff --git a/test/encryptedERC20/EncryptedERC20.fixture.ts b/test/encryptedERC20/EncryptedERC20.fixture.ts index 507c72f..9b43c25 100644 --- a/test/encryptedERC20/EncryptedERC20.fixture.ts +++ b/test/encryptedERC20/EncryptedERC20.fixture.ts @@ -1,7 +1,7 @@ import { ethers } from "hardhat"; import type { EncryptedERC20Mintable, IEncryptedERC20 } from "../../types"; -import { reencryptHandle } from "../reencrypt"; +import { reencryptEuint64 } from "../reencrypt"; import { Signers } from "../signers"; import { FhevmInstances } from "../types"; @@ -28,7 +28,7 @@ export async function reencryptAllowance( tokenAddress: string, ): Promise { const allowanceHandle = await token.allowance(signers[user as keyof Signers], signers[spender as keyof Signers]); - const allowance = await reencryptHandle(signers, instances, user, allowanceHandle, tokenAddress); + const allowance = await reencryptEuint64(signers, instances, user, allowanceHandle, tokenAddress); return allowance; } @@ -40,6 +40,6 @@ export async function reencryptBalance( tokenAddress: string, ): Promise { const balanceHandle = await token.balanceOf(signers[user as keyof Signers]); - const balance = await reencryptHandle(signers, instances, user, balanceHandle, tokenAddress); + const balance = await reencryptEuint64(signers, instances, user, balanceHandle, tokenAddress); return balance; } diff --git a/test/handleTypeCheck.ts b/test/handleTypeCheck.ts new file mode 100644 index 0000000..4a9a5e0 --- /dev/null +++ b/test/handleTypeCheck.ts @@ -0,0 +1,19 @@ +export const EBOOL_T = 0; +export const EUINT4_T = 1; +export const EUINT8_T = 2; +export const EUINT16_T = 3; +export const EUINT32_T = 4; +export const EUINT64_T = 5; +export const EUINT128_T = 6; +export const EUINT160_T = 7; +export const EUINT256_T = 8; +export const EBYTES64_T = 9; +export const EBYTES128_T = 10; +export const EBYTES256_T = 11; + +export function verifyType(handle: bigint, expectedType: number) { + const typeCt = handle >> 8n; + if (Number(typeCt % 256n) !== expectedType) { + throw "Wrong Type"; + } +} diff --git a/test/instance.ts b/test/instance.ts index 92c8ae4..cec33df 100644 --- a/test/instance.ts +++ b/test/instance.ts @@ -8,6 +8,7 @@ import path from "path"; import { awaitCoprocessor, getClearText } from "./coprocessorUtils"; import { createEncryptedInputMocked, reencryptRequestMocked } from "./fhevmjsMocked"; +import { EBOOL_T, EUINT160_T, EUINT16_T, EUINT4_T, EUINT8_T, verifyType } from "./handleTypeCheck"; import type { Signers } from "./signers"; import { FhevmInstances } from "./types"; @@ -83,6 +84,8 @@ const getDecryptor = () => { * @returns {bool} */ export const decryptBool = async (handle: bigint): Promise => { + verifyType(handle, EBOOL_T); + if (network.name === "hardhat") { await awaitCoprocessor(); return (await getClearText(handle)) === "1"; @@ -101,6 +104,8 @@ export const decryptBool = async (handle: bigint): Promise => { * @returns {bigint} */ export const decrypt4 = async (handle: bigint): Promise => { + verifyType(handle, EUINT4_T); + if (network.name === "hardhat") { await awaitCoprocessor(); return BigInt(await getClearText(handle)); @@ -119,6 +124,8 @@ export const decrypt4 = async (handle: bigint): Promise => { * @returns {bigint} */ export const decrypt8 = async (handle: bigint): Promise => { + verifyType(handle, EUINT8_T); + if (network.name === "hardhat") { await awaitCoprocessor(); return BigInt(await getClearText(handle)); @@ -137,6 +144,8 @@ export const decrypt8 = async (handle: bigint): Promise => { * @returns {bigint} */ export const decrypt16 = async (handle: bigint): Promise => { + verifyType(handle, EUINT16_T); + if (network.name === "hardhat") { await awaitCoprocessor(); return BigInt(await getClearText(handle)); @@ -155,6 +164,8 @@ export const decrypt16 = async (handle: bigint): Promise => { * @returns {bigint} */ export const decrypt32 = async (handle: bigint): Promise => { + verifyType(handle, EUINT32_T); + if (network.name === "hardhat") { await awaitCoprocessor(); return BigInt(await getClearText(handle)); @@ -173,6 +184,8 @@ export const decrypt32 = async (handle: bigint): Promise => { * @returns {bigint} */ export const decrypt64 = async (handle: bigint): Promise => { + verifyType(handle, EUINT64_T); + if (network.name === "hardhat") { await awaitCoprocessor(); return BigInt(await getClearText(handle)); @@ -191,6 +204,8 @@ export const decrypt64 = async (handle: bigint): Promise => { * @returns {string} */ export const decryptAddress = async (handle: bigint): Promise => { + verifyType(handle, EUINT160_T); + if (network.name === "hardhat") { await awaitCoprocessor(); const bigintAdd = BigInt(await getClearText(handle)); diff --git a/test/reencrypt.ts b/test/reencrypt.ts index 00b97a3..643d526 100644 --- a/test/reencrypt.ts +++ b/test/reencrypt.ts @@ -1,18 +1,163 @@ +import { + EBOOL_T, + EBYTES64_T, + EBYTES128_T, + EBYTES256_T, + EUINT4_T, + EUINT8_T, + EUINT16_T, + EUINT32_T, + EUINT64_T, + EUINT128_T, + EUINT160_T, + EUINT256_T, + verifyType, +} from "./handleTypeCheck"; import { Signers } from "./signers"; import { FhevmInstances } from "./types"; +export async function reencryptEbool( + signers: Signers, + instances: FhevmInstances, + user: string, + handle: bigint, + contractAddress: string, +): Promise { + verifyType(handle, EBOOL_T); + return reencryptHandle(signers, instances, user, handle, contractAddress); +} + +export async function reencryptEuint4( + signers: Signers, + instances: FhevmInstances, + user: string, + handle: bigint, + contractAddress: string, +): Promise { + verifyType(handle, EUINT4_T); + return reencryptHandle(signers, instances, user, handle, contractAddress); +} + +export async function reencryptEuint8( + signers: Signers, + instances: FhevmInstances, + user: string, + handle: bigint, + contractAddress: string, +): Promise { + verifyType(handle, EUINT8_T); + return reencryptHandle(signers, instances, user, handle, contractAddress); +} + +export async function reencryptEuint16( + signers: Signers, + instances: FhevmInstances, + user: string, + handle: bigint, + contractAddress: string, +): Promise { + verifyType(handle, EUINT16_T); + return reencryptHandle(signers, instances, user, handle, contractAddress); +} + +export async function reencryptEuint32( + signers: Signers, + instances: FhevmInstances, + user: string, + handle: bigint, + contractAddress: string, +): Promise { + verifyType(handle, EUINT32_T); + return reencryptHandle(signers, instances, user, handle, contractAddress); +} + +export async function reencryptEuint64( + signers: Signers, + instances: FhevmInstances, + user: string, + handle: bigint, + contractAddress: string, +): Promise { + verifyType(handle, EUINT64_T); + return reencryptHandle(signers, instances, user, handle, contractAddress); +} + +export async function reencryptEuint128( + signers: Signers, + instances: FhevmInstances, + user: string, + handle: bigint, + contractAddress: string, +): Promise { + verifyType(handle, EUINT128_T); + return reencryptHandle(signers, instances, user, handle, contractAddress); +} + +export async function reencryptEuint160( + signers: Signers, + instances: FhevmInstances, + user: string, + handle: bigint, + contractAddress: string, +): Promise { + verifyType(handle, EUINT160_T); + return reencryptHandle(signers, instances, user, handle, contractAddress); +} + +export async function reencryptEuint256( + signers: Signers, + instances: FhevmInstances, + user: string, + handle: bigint, + contractAddress: string, +): Promise { + verifyType(handle, EUINT256_T); + return reencryptHandle(signers, instances, user, handle, contractAddress); +} + +export async function reencryptEbytes64( + signers: Signers, + instances: FhevmInstances, + user: string, + handle: bigint, + contractAddress: string, +): Promise { + verifyType(handle, EBYTES64_T); + return reencryptHandle(signers, instances, user, handle, contractAddress); +} + +export async function reencryptEbytes128( + signers: Signers, + instances: FhevmInstances, + user: string, + handle: bigint, + contractAddress: string, +): Promise { + verifyType(handle, EBYTES128_T); + return reencryptHandle(signers, instances, user, handle, contractAddress); +} + +export async function reencryptEbytes256( + signers: Signers, + instances: FhevmInstances, + user: string, + handle: bigint, + contractAddress: string, +): Promise { + verifyType(handle, EBYTES256_T); + return reencryptHandle(signers, instances, user, handle, contractAddress); +} + /** - * @debug * This function is to reencrypt handles. */ -export async function reencryptHandle( +async function reencryptHandle( signers: Signers, instances: FhevmInstances, user: string, handle: bigint, contractAddress: string, ): Promise { - // Verify if the type is matched const { publicKey: publicKey, privateKey: privateKey } = instances[user as keyof FhevmInstances].generateKeypair(); const eip712 = instances[user as keyof FhevmInstances].createEIP712(publicKey, contractAddress); const signature = await signers[user as keyof Signers].signTypedData( From 09b375916e714ab325f25d173f1e361f75ce23da Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:13:36 +0200 Subject: [PATCH 24/73] feat: Add more checks for handle types --- test/handleTypeCheck.ts | 13 +++++++++++-- test/instance.ts | 19 ++++++++++++++----- test/reencrypt.ts | 15 +++++++++------ 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/test/handleTypeCheck.ts b/test/handleTypeCheck.ts index 4a9a5e0..cba7a73 100644 --- a/test/handleTypeCheck.ts +++ b/test/handleTypeCheck.ts @@ -5,15 +5,24 @@ export const EUINT16_T = 3; export const EUINT32_T = 4; export const EUINT64_T = 5; export const EUINT128_T = 6; -export const EUINT160_T = 7; +export const EUINT160_T = 7; // @dev It is the one for eaddresses. export const EUINT256_T = 8; export const EBYTES64_T = 9; export const EBYTES128_T = 10; export const EBYTES256_T = 11; export function verifyType(handle: bigint, expectedType: number) { + if (handle === 0n) { + throw "Handle is not initialized"; + } + + if (handle.toString(2).length === 34) { + throw "Handle is not a bytes32"; + } + const typeCt = handle >> 8n; + if (Number(typeCt % 256n) !== expectedType) { - throw "Wrong Type"; + throw "Wrong encrypted type for the handle"; } } diff --git a/test/instance.ts b/test/instance.ts index cec33df..07d90d2 100644 --- a/test/instance.ts +++ b/test/instance.ts @@ -8,7 +8,16 @@ import path from "path"; import { awaitCoprocessor, getClearText } from "./coprocessorUtils"; import { createEncryptedInputMocked, reencryptRequestMocked } from "./fhevmjsMocked"; -import { EBOOL_T, EUINT160_T, EUINT16_T, EUINT4_T, EUINT8_T, verifyType } from "./handleTypeCheck"; +import { + EBOOL_T, + EUINT4_T, + EUINT8_T, + EUINT16_T, + EUINT32_T, + EUINT64_T, + EUINT160_T, + verifyType, +} from "./handleTypeCheck"; import type { Signers } from "./signers"; import { FhevmInstances } from "./types"; @@ -140,7 +149,7 @@ export const decrypt8 = async (handle: bigint): Promise => { * It cannot be used in production code, since it requires the FHE private key for decryption. * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. * - * @param {bigint} a handle to decrypt + * @param {bigint} handle to decrypt * @returns {bigint} */ export const decrypt16 = async (handle: bigint): Promise => { @@ -160,7 +169,7 @@ export const decrypt16 = async (handle: bigint): Promise => { * It cannot be used in production code, since it requires the FHE private key for decryption. * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. * - * @param {bigint} a handle to decrypt + * @param {bigint} handle to decrypt * @returns {bigint} */ export const decrypt32 = async (handle: bigint): Promise => { @@ -180,7 +189,7 @@ export const decrypt32 = async (handle: bigint): Promise => { * It cannot be used in production code, since it requires the FHE private key for decryption. * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. * - * @param {bigint} a handle to decrypt + * @param {bigint} handle to decrypt * @returns {bigint} */ export const decrypt64 = async (handle: bigint): Promise => { @@ -200,7 +209,7 @@ export const decrypt64 = async (handle: bigint): Promise => { * It cannot be used in production code, since it requires the FHE private key for decryption. * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. * - * @param {bigint} a handle to decrypt + * @param {bigint} handle to decrypt * @returns {string} */ export const decryptAddress = async (handle: bigint): Promise => { diff --git a/test/reencrypt.ts b/test/reencrypt.ts index 643d526..abcca2c 100644 --- a/test/reencrypt.ts +++ b/test/reencrypt.ts @@ -22,7 +22,7 @@ export async function reencryptEbool( user: string, handle: bigint, contractAddress: string, -): Promise { +): Promise { verifyType(handle, EBOOL_T); return reencryptHandle(signers, instances, user, handle, contractAddress); } @@ -93,15 +93,17 @@ export async function reencryptEuint128( return reencryptHandle(signers, instances, user, handle, contractAddress); } -export async function reencryptEuint160( +export async function reencryptEAddress( signers: Signers, instances: FhevmInstances, user: string, handle: bigint, contractAddress: string, -): Promise { +): Promise { verifyType(handle, EUINT160_T); - return reencryptHandle(signers, instances, user, handle, contractAddress); + const addressAsUint160: bigint = await reencryptHandle(signers, instances, user, handle, contractAddress); + const handleStr = "0x" + addressAsUint160.toString(16).padStart(40, "0"); + return handleStr; } export async function reencryptEuint256( @@ -149,7 +151,8 @@ export async function reencryptEbytes256( } /** - * This function is to reencrypt handles. + * @dev This function is to reencrypt handles. + * It does not verify types. */ async function reencryptHandle( signers: Signers, @@ -157,7 +160,7 @@ async function reencryptHandle( user: string, handle: bigint, contractAddress: string, -): Promise { +): Promise { const { publicKey: publicKey, privateKey: privateKey } = instances[user as keyof FhevmInstances].generateKeypair(); const eip712 = instances[user as keyof FhevmInstances].createEIP712(publicKey, contractAddress); const signature = await signers[user as keyof Signers].signTypedData( From c1cd85d0ea5c391cedac7abd9399fa56a5094cff Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 24 Oct 2024 17:32:11 +0200 Subject: [PATCH 25/73] fix: Logic error --- test/handleTypeCheck.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/handleTypeCheck.ts b/test/handleTypeCheck.ts index cba7a73..dfe7ddc 100644 --- a/test/handleTypeCheck.ts +++ b/test/handleTypeCheck.ts @@ -16,7 +16,7 @@ export function verifyType(handle: bigint, expectedType: number) { throw "Handle is not initialized"; } - if (handle.toString(2).length === 34) { + if (handle.toString(2).length > 256) { throw "Handle is not a bytes32"; } From 0e99dceb65cf57a12d3962238864197c005bbdd7 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Fri, 25 Oct 2024 10:01:35 +0200 Subject: [PATCH 26/73] build: OZ fixed version --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 728a714..58cf553 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,7 +9,7 @@ importers: .: dependencies: '@openzeppelin/contracts': - specifier: ^5.0.2 + specifier: 5.0.2 version: 5.0.2 extra-bigint: specifier: ^1.1.18 From aba63078a19ab68260be1b49e3073ca4d58e6f02 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 28 Oct 2024 09:42:50 +0100 Subject: [PATCH 27/73] build: FHEVM 0.6 --- package.json | 7 +-- pnpm-lock.yaml | 142 +++++++++++++++++++++++++++++++------------------ 2 files changed, 93 insertions(+), 56 deletions(-) diff --git a/package.json b/package.json index 009daa5..4244c39 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,9 @@ "eslint": "^8.57.0", "eslint-config-prettier": "^8.10.0", "ethers": "^6.11.1", - "fhevm": "^0.5.9", - "fhevmjs": "^0.5.7", + "fhevm": "^0.6.0-0", + "fhevm-core-contracts": "0.1.0-2", + "fhevmjs": "^0.6.0-4", "fs-extra": "^10.1.0", "hardhat": "2.22.14", "hardhat-deploy": "^0.11.45", @@ -97,4 +98,4 @@ "extra-bigint": "^1.1.18", "sqlite3": "^5.1.7" } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 58cf553..d641840 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -79,11 +79,14 @@ importers: specifier: ^6.11.1 version: 6.11.1 fhevm: - specifier: ^0.5.9 - version: 0.5.9 + specifier: ^0.6.0-0 + version: 0.6.0-0 + fhevm-core-contracts: + specifier: 0.1.0-2 + version: 0.1.0-2 fhevmjs: - specifier: ^0.5.7 - version: 0.5.7(encoding@0.1.13) + specifier: ^0.6.0-4 + version: 0.6.0-4 fs-extra: specifier: ^10.1.0 version: 10.1.0 @@ -699,6 +702,9 @@ packages: '@types/fs-extra@9.0.13': resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + '@types/glob-to-regexp@0.4.4': + resolution: {integrity: sha512-nDKoaKJYbnn1MZxUY0cA1bPmmgZbg0cTq7Rh13d0KWYNOiKbqoR+2d89SnRPszGh7ROzSwZ/GOjZ4jPbmmZ6Eg==} + '@types/glob@7.2.0': resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} @@ -1278,6 +1284,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + detect-libc@2.0.3: resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} @@ -1497,12 +1507,24 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - fhevm@0.5.9: - resolution: {integrity: sha512-9cSfmAa4AJUuROd4kESvtNYJpnea1PUvjU7yaNnrJsaHqPkVGQvpnIDEnO4KTsJ36Etup1ksPs8PvyGNYwkatQ==} + fetch-mock@11.1.5: + resolution: {integrity: sha512-KHmZDnZ1ry0pCTrX4YG5DtThHi0MH+GNI9caESnzX/nMJBrvppUHMvLx47M0WY9oAtKOMiPfZDRpxhlHg89BOA==} + engines: {node: '>=8.0.0'} + peerDependencies: + node-fetch: '*' + peerDependenciesMeta: + node-fetch: + optional: true + + fhevm-core-contracts@0.1.0-2: + resolution: {integrity: sha512-lTUodggGV4+pZVFRKRb22t3rWyfR8iFZLgNxRBozgAEUSsIDe16PI9vn8PkfJzJJdOlPk9XsTY6/s1pACDbwfA==} + + fhevm@0.6.0-0: + resolution: {integrity: sha512-Gvd7a5T7JTU3OFHy2eRrvRTTmXWwSalSSsBdE0X0C0nTnTow5sYsQYkQqIZcYZNpZq1dCcoCgp/gYbeNDHUDNw==} engines: {node: '>=20.0.0'} - fhevmjs@0.5.7: - resolution: {integrity: sha512-HWVpV0pK4glaTVvSjAvo/FBreI9M+wfmyxau/GVwELuVMCDCChEu/EE8OpnVWt8UhgLtvBrkD5dbhbNYoFjDSQ==} + fhevmjs@0.6.0-4: + resolution: {integrity: sha512-gPnEHnkAwoJivP+K1KtOx7ZeBpZGtQW1QaAVC1zxDtMWQKCcqJMmNQOt0ur/2buw6WE4VfDIIWXneZ1hHCzLHQ==} engines: {node: '>=20'} hasBin: true @@ -1638,6 +1660,9 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + glob@5.0.15: resolution: {integrity: sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==} deprecated: Glob versions prior to v9 are no longer supported @@ -1916,6 +1941,9 @@ packages: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} + is-subset@0.1.1: + resolution: {integrity: sha512-6Ybun0IkarhmEqxXCNw/C0bna6Zb/TkfUX9UbwJtK6ObwAVCxmAP308WWTHviM/zAqXk05cdhYsUsZeGQh99iw==} + is-typed-array@1.1.13: resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} engines: {node: '>= 0.4'} @@ -2214,15 +2242,6 @@ packages: node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - node-gyp-build@4.8.0: resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==} hasBin: true @@ -2236,8 +2255,11 @@ packages: resolution: {integrity: sha512-bJ9zMDuNGzVQg1xv0bCPzyEDxHgbrx7/xGj6CDokvizZZmastPsOh0JJLuY8wA5q2SfX1TLNMk7XNV8WxbGxzA==} engines: {node: '>= 14.0.0'} - node-tfhe@0.6.4: - resolution: {integrity: sha512-V/SJjc5GPKIB/KcNGEFSDDQelIKvFIFiCgefeDARgxOnN69fyB+omV4e4j3tMDEz6aN7xRd/NqqQ0im17emXeA==} + node-tfhe@0.8.6: + resolution: {integrity: sha512-u9WHiD/vTQ/FIph+52l/jyKzyDh/vLnyw50oSdz0eb1CTs2lqbiA8l8MNxgMkBP1zDadR0qzg37VCt3UkoC2ig==} + + node-tkms@0.9.0-rc3: + resolution: {integrity: sha512-Jr3faNAudjBO2Up+Gc3QPF7Dq07fDR/n0NKCHGtS69qLKnoqqaKxGULdKg3gpbtdx0wnj/GaQjvprUIgnIm7yQ==} nofilter@3.1.0: resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} @@ -2486,6 +2508,10 @@ packages: resolution: {integrity: sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==} engines: {node: '>=6'} + regexparam@3.0.0: + resolution: {integrity: sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==} + engines: {node: '>=8'} + req-cwd@2.0.0: resolution: {integrity: sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==} engines: {node: '>=4'} @@ -2865,13 +2891,16 @@ packages: text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - tfhe@0.6.4: - resolution: {integrity: sha512-80fP2iJJQXrlhyC81u6/aUWMMMDoOXmlY5uqKka2CEd222xM96+z9+FTZc0MjlrR3U+NHja1WOte+A3nlvZkKw==} + tfhe@0.8.6: + resolution: {integrity: sha512-Mxa6ywC4fAayHK0xBPJfrVUt4Tt5+ozQyVQcAlj3gK1i5rJI/pcwCDvf27Xxtkb0fMyRYgKDwrETVfC51r1Fcw==} then-request@6.0.2: resolution: {integrity: sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==} engines: {node: '>=6.0.0'} + tkms@0.9.0-rc3: + resolution: {integrity: sha512-7ynaHiFnXS9Xok62vsi2GGeTUxmb1Ao7I5k9akE8lEQ5M9FERmaGLF3TapDLGsYMDz7Km7dFeTfrsjCg38OC/w==} + tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -2888,9 +2917,6 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - ts-command-line-args@2.5.1: resolution: {integrity: sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==} hasBin: true @@ -3060,12 +3086,6 @@ packages: resolution: {integrity: sha512-qn9id0/l1bWmvH4XfnG/JtGKKwut2Vokl6YXP5Kfg424npysmtRLe9DgiNBM9Op7QL/aSiaA0TVXibuIuWcizg==} engines: {node: '>=14', npm: '>=6.12.0'} - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - which-typed-array@1.1.15: resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} @@ -3940,6 +3960,8 @@ snapshots: dependencies: '@types/node': 18.19.23 + '@types/glob-to-regexp@0.4.4': {} + '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 @@ -4575,6 +4597,8 @@ snapshots: depd@2.0.0: {} + dequal@2.0.3: {} + detect-libc@2.0.3: {} diff@4.0.2: {} @@ -4915,23 +4939,40 @@ snapshots: dependencies: reusify: 1.0.4 - fhevm@0.5.9: + fetch-mock@11.1.5: + dependencies: + '@types/glob-to-regexp': 0.4.4 + dequal: 2.0.3 + glob-to-regexp: 0.4.1 + is-subset: 0.1.1 + regexparam: 3.0.0 + + fhevm-core-contracts@0.1.0-2: {} + + fhevm@0.6.0-0: dependencies: '@openzeppelin/contracts': 5.0.2 + extra-bigint: 1.2.0 + sqlite3: 5.1.7 + transitivePeerDependencies: + - bluebird + - supports-color - fhevmjs@0.5.7(encoding@0.1.13): + fhevmjs@0.6.0-4: dependencies: '@types/keccak': 3.0.5 bigint-buffer: 1.1.5 commander: 11.1.0 - node-fetch: 2.7.0(encoding@0.1.13) - node-tfhe: 0.6.4 + fetch-mock: 11.1.5 + node-tfhe: 0.8.6 + node-tkms: 0.9.0-rc3 sha3: 2.1.4 - tfhe: 0.6.4 + tfhe: 0.8.6 + tkms: 0.9.0-rc3 url: 0.11.4 web3-validator: 2.0.6 transitivePeerDependencies: - - encoding + - node-fetch file-entry-cache@6.0.1: dependencies: @@ -5073,6 +5114,8 @@ snapshots: dependencies: is-glob: 4.0.3 + glob-to-regexp@0.4.1: {} + glob@5.0.15: dependencies: inflight: 1.0.6 @@ -5466,6 +5509,8 @@ snapshots: is-plain-obj@2.1.0: {} + is-subset@0.1.1: {} + is-typed-array@1.1.13: dependencies: which-typed-array: 1.1.15 @@ -5770,12 +5815,6 @@ snapshots: dependencies: lodash: 4.17.21 - node-fetch@2.7.0(encoding@0.1.13): - dependencies: - whatwg-url: 5.0.0 - optionalDependencies: - encoding: 0.1.13 - node-gyp-build@4.8.0: {} node-gyp@8.4.1: @@ -5799,7 +5838,9 @@ snapshots: dependencies: shallowequal: 1.1.0 - node-tfhe@0.6.4: {} + node-tfhe@0.8.6: {} + + node-tkms@0.9.0-rc3: {} nofilter@3.1.0: {} @@ -6047,6 +6088,8 @@ snapshots: reduce-flatten@2.0.0: {} + regexparam@3.0.0: {} + req-cwd@2.0.0: dependencies: req-from: 2.0.0 @@ -6490,7 +6533,7 @@ snapshots: text-table@0.2.0: {} - tfhe@0.6.4: {} + tfhe@0.8.6: {} then-request@6.0.2: dependencies: @@ -6506,6 +6549,8 @@ snapshots: promise: 8.3.0 qs: 6.12.0 + tkms@0.9.0-rc3: {} + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 @@ -6518,8 +6563,6 @@ snapshots: toidentifier@1.0.1: {} - tr46@0.0.3: {} - ts-command-line-args@2.5.1: dependencies: chalk: 4.1.2 @@ -6697,13 +6740,6 @@ snapshots: web3-types: 1.8.1 zod: 3.23.8 - webidl-conversions@3.0.1: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - which-typed-array@1.1.15: dependencies: available-typed-arrays: 1.0.7 From d3156a5fedce8c587be21f380a7e6e2f63d42d22 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:09:42 +0100 Subject: [PATCH 28/73] build: FHEVM 0.6 --- .env.example | 22 +- hardhat.config.ts | 84 ++- package.json | 9 +- pnpm-lock.yaml | 499 +++++++++++-- remappings.txt | 1 - tasks/accounts.ts | 4 +- tasks/taskDeploy.ts | 179 +++-- tasks/taskGatewayRelayer.ts | 89 ++- tasks/taskOracleRelayer.ts | 145 ---- tasks/taskTFHE.ts | 263 +++++-- test/coprocessorUtils.ts | 1398 ++++++++++++++++++----------------- test/fhevmjsMocked.ts | 350 +++++++-- test/instance.ts | 144 +++- test/operatorsPrices.json | 530 +++++++++++++ test/reencrypt.ts | 50 +- test/signers.ts | 66 +- test/utils.ts | 14 +- tsconfig.json | 4 +- 18 files changed, 2654 insertions(+), 1197 deletions(-) delete mode 100644 remappings.txt delete mode 100644 tasks/taskOracleRelayer.ts create mode 100644 test/operatorsPrices.json diff --git a/.env.example b/.env.example index 84dba80..88ddfce 100644 --- a/.env.example +++ b/.env.example @@ -1,13 +1,11 @@ -export INFURA_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" -export MNEMONIC="adapt mosquito move limb mobile illegal tree voyage juice mosquito burger raise father hope layer" -export PRIVATE_KEY_GATEWAY_DEPLOYER="717fd99986df414889fd8b51069d4f90a50af72e542c58ee065f5883779099c6" -export PRIVATE_KEY_GATEWAY_OWNER="717fd99986df414889fd8b51069d4f90a50af72e542c58ee065f5883779099c6" -export PRIVATE_KEY_GATEWAY_RELAYER="7ec931411ad75a7c201469a385d6f18a325d4923f9f213bd882bbea87e160b67" +export MNEMONIC="exchange vintage ocean narrow danger return culture ignore trim solve clock hidden buddy wise emotion" +export PRIVATE_KEY_FHEVM_DEPLOYER="f2caf1b49a8f33e5a95fc55b0903daddd261d5a874ff154dc5d809a5f1c90449" +export PRIVATE_KEY_GATEWAY_DEPLOYER="e956ca0c96995551256523af64ac2f134c6b65d3e9d5c7b24ac4cd0a12f07bfd" +export PRIVATE_KEY_GATEWAY_RELAYER="049bdaae72bcc269f5edf17be5a01d61374e139b425984431242a3a74f73e92a" +export NUM_KMS_SIGNERS="1" +export PRIVATE_KEY_KMS_SIGNER_0="d5b160a52fe6015861d0a1bea9523aaab3699d52af8f3cede5fcdbdfdd4c77cc" +export PRIVATE_KEY_COPROCESSOR_ACCOUNT="83e0173b9d07abd53958da9f417df515b0957c4f8afd7171b518d192b52ae313" +export IS_COPROCESSOR="true" -# Block explorer API keys -export ARBISCAN_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" -export BSCSCAN_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" -export ETHERSCAN_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" -export OPTIMISM_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" -export POLYGONSCAN_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" -export SNOWTRACE_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" \ No newline at end of file +export SEPOLIA_RPC_URL="https://sepolia.infura.io/v3/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +export ETHERSCAN_API_KEY="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index 2b82be9..9dae56b 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,4 +1,5 @@ import "@nomicfoundation/hardhat-toolbox"; +import "@openzeppelin/hardhat-upgrades"; import dotenv from "dotenv"; import * as fs from "fs-extra"; import "hardhat-deploy"; @@ -44,8 +45,8 @@ if (!mnemonic) { const chainIds = { zama: 8009, local: 9000, - localNetwork1: 9000, - multipleValidatorTestnet: 8009, + localCoprocessor: 12345, + sepolia: 11155111, }; function getChainConfig(chain: keyof typeof chainIds): NetworkUserConfig { @@ -54,15 +55,14 @@ function getChainConfig(chain: keyof typeof chainIds): NetworkUserConfig { case "local": jsonRpcUrl = "http://localhost:8545"; break; - case "localNetwork1": - jsonRpcUrl = "http://127.0.0.1:9650/ext/bc/fhevm/rpc"; - break; - case "multipleValidatorTestnet": - jsonRpcUrl = "https://rpc.fhe-ethermint.zama.ai"; + case "localCoprocessor": + jsonRpcUrl = "http://localhost:8745"; break; case "zama": jsonRpcUrl = "https://devnet.zama.ai"; break; + case "sepolia": + jsonRpcUrl = process.env.SEPOLIA_RPC_URL!; } return { accounts: { @@ -81,38 +81,56 @@ task("coverage").setAction(async (taskArgs, hre, runSuper) => { await runSuper(taskArgs); }); +function replaceImportStatement(filePath: string, oldImport: string, newImport: string): void { + try { + let fileContent = fs.readFileSync(filePath, "utf-8"); + fileContent = fileContent.replace(oldImport, newImport); + fs.writeFileSync(filePath, fileContent, "utf-8"); + } catch (error) { + console.error(`Error updating file: ${error}`); + } +} + task("test", async (taskArgs, hre, runSuper) => { // Run modified test task if (hre.network.name === "hardhat") { // in fhevm mode all this block is done when launching the node via `pnmp fhevm:start` - const privKeyDeployer = process.env.PRIVATE_KEY_GATEWAY_DEPLOYER; - await hre.run("task:computePredeployAddress", { privateKey: privKeyDeployer }); - await hre.run("task:computeACLAddress"); - await hre.run("task:computeTFHEExecutorAddress"); - await hre.run("task:computeKMSVerifierAddress"); - - await hre.run("compile:specific", { contract: "contracts" }); - const sourceDir = path.resolve(__dirname, "node_modules/fhevm/"); + const privKeyGatewayDeployer = process.env.PRIVATE_KEY_GATEWAY_DEPLOYER; + const privKeyFhevmDeployer = process.env.PRIVATE_KEY_FHEVM_DEPLOYER; + await hre.run("task:computeGatewayAddress", { privateKey: privKeyGatewayDeployer }); + await hre.run("task:computeACLAddress", { privateKey: privKeyFhevmDeployer }); + await hre.run("task:computeTFHEExecutorAddress", { privateKey: privKeyFhevmDeployer }); + await hre.run("task:computeKMSVerifierAddress", { privateKey: privKeyFhevmDeployer }); + await hre.run("task:computeInputVerifierAddress", { privateKey: privKeyFhevmDeployer, useAddress: false }); + await hre.run("task:computeFHEPaymentAddress", { privateKey: privKeyFhevmDeployer }); + await hre.run("compile:specific", { contract: "contracts/" }); + const sourceDir = path.resolve(__dirname, "node_modules/fhevm-core-contracts/"); const destinationDir = path.resolve(__dirname, "fhevmTemp/"); fs.copySync(sourceDir, destinationDir, { dereference: true }); - await hre.run("compile:specific", { contract: "fhevmTemp/lib" }); - await hre.run("compile:specific", { contract: "fhevmTemp/gateway" }); - const abiDir = path.resolve(__dirname, "abi"); - fs.ensureDirSync(abiDir); - const sourceFile = path.resolve(__dirname, "artifacts/fhevmTemp/lib/TFHEExecutor.sol/TFHEExecutor.json"); - const destinationFile = path.resolve(abiDir, "TFHEExecutor.json"); - fs.copyFileSync(sourceFile, destinationFile); - const targetAddress = "0x000000000000000000000000000000000000005d"; - const MockedPrecompile = await hre.artifacts.readArtifact("MockedPrecompile"); - const bytecode = MockedPrecompile.deployedBytecode; - await hre.network.provider.send("hardhat_setCode", [targetAddress, bytecode]); - console.log(`Code of Mocked Pre-compile set at address: ${targetAddress}`); + const sourceDir2 = path.resolve("./node_modules/fhevm/gateway/GatewayContract.sol"); + const destinationFilePath = path.join(destinationDir, "GatewayContract.sol"); + fs.copySync(sourceDir2, destinationFilePath, { dereference: true }); + const oldImport = `import "../lib/TFHE.sol";`; + const newImport = `import "fhevm/lib/TFHE.sol";`; + replaceImportStatement(destinationFilePath, oldImport, newImport); + const sourceDir3 = path.resolve("./node_modules/fhevm/gateway/IKMSVerifier.sol"); + const destinationFilePath3 = path.join(destinationDir, "IKMSVerifier.sol"); + fs.copySync(sourceDir3, destinationFilePath3, { dereference: true }); - await hre.run("task:deployACL"); - await hre.run("task:deployTFHEExecutor"); - await hre.run("task:deployKMSVerifier"); - await hre.run("task:launchFhevm", { skipGetCoin: false }); + await hre.run("compile:specific", { contract: "fhevmTemp/" }); + await hre.run("task:faucetToPrivate", { privateKey: privKeyFhevmDeployer }); + await hre.run("task:deployACL", { privateKey: privKeyFhevmDeployer }); + await hre.run("task:deployTFHEExecutor", { privateKey: privKeyFhevmDeployer }); + await hre.run("task:deployKMSVerifier", { privateKey: privKeyFhevmDeployer }); + await hre.run("task:deployInputVerifier", { privateKey: privKeyFhevmDeployer }); + await hre.run("task:deployFHEPayment", { privateKey: privKeyFhevmDeployer }); + await hre.run("task:addSigners", { + numSigners: process.env.NUM_KMS_SIGNERS!, + privateKey: privKeyFhevmDeployer, + useAddress: false, + }); + await hre.run("task:launchFhevm", { skipGetCoin: false, useAddress: false }); } await runSuper(); }); @@ -139,11 +157,11 @@ const config: HardhatUserConfig = { path: "m/44'/60'/0'/0", }, }, + sepolia: getChainConfig("sepolia"), zama: getChainConfig("zama"), localDev: getChainConfig("local"), local: getChainConfig("local"), - localNetwork1: getChainConfig("localNetwork1"), - multipleValidatorTestnet: getChainConfig("multipleValidatorTestnet"), + localCoprocessor: getChainConfig("localCoprocessor"), }, paths: { artifacts: "./artifacts", diff --git a/package.json b/package.json index 4244c39..47fe958 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "fhEVM contracts", "version": "0.1.0", "author": { - "name": "Zama", + "name": "zama-ai", "url": "https://github.com/zama-ai" }, "license": "BSD-3-Clause", @@ -13,13 +13,14 @@ "@nomicfoundation/hardhat-network-helpers": "^1.0.10", "@nomicfoundation/hardhat-toolbox": "^3.0.0", "@nomicfoundation/hardhat-verify": "^1.1.1", + "@openzeppelin/hardhat-upgrades": "^3.5.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@typechain/ethers-v6": "^0.4.3", "@typechain/hardhat": "^8.0.3", "@types/chai": "^4.3.12", "@types/fs-extra": "^9.0.13", "@types/mocha": "^10.0.6", - "@types/node": "^18.19.23", + "@types/node": "^18.19.59", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "chai": "^4.4.1", @@ -68,8 +69,7 @@ "access": "public" }, "scripts": { - "clean": "rimraf ./artifacts ./cache ./coverage ./types ./coverage.json && npm run typechain", - "compile": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat compile", + "clean": "rimraf ./fhevmTemp ./artifacts ./cache ./coverage ./types ./coverage.json && pnpm typechain", "compile": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat compile", "deploy:contracts": "hardhat deploy", "docgen": "hardhat docgen", "lint": "npm run lint:sol && npm run lint:ts && npm run prettier:check", @@ -94,6 +94,7 @@ "fhevm:faucet:eve": "docker exec -i fhevm faucet $(npx hardhat task:getEthereumAddressEve)" }, "dependencies": { + "@openzeppelin/contracts-upgradeable": "5.0.2", "@openzeppelin/contracts": "5.0.2", "extra-bigint": "^1.1.18", "sqlite3": "^5.1.7" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d641840..bde31ed 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@openzeppelin/contracts': specifier: 5.0.2 version: 5.0.2 + '@openzeppelin/contracts-upgradeable': + specifier: 5.0.2 + version: 5.0.2(@openzeppelin/contracts@5.0.2) extra-bigint: specifier: ^1.1.18 version: 1.2.0 @@ -20,19 +23,22 @@ importers: devDependencies: '@nomicfoundation/hardhat-chai-matchers': specifier: ^2.0.6 - version: 2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + version: 2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) '@nomicfoundation/hardhat-ethers': specifier: ^3.0.5 - version: 3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + version: 3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) '@nomicfoundation/hardhat-network-helpers': specifier: ^1.0.10 - version: 1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + version: 1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) '@nomicfoundation/hardhat-toolbox': specifier: ^3.0.0 - version: 3.0.0(ugreflrcgmhzqdan7c47drajhi) + version: 3.0.0(sziado6kyyqqr3qor4olybdgcq) '@nomicfoundation/hardhat-verify': specifier: ^1.1.1 - version: 1.1.1(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + version: 1.1.1(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) + '@openzeppelin/hardhat-upgrades': + specifier: ^3.5.0 + version: 3.5.0(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)))(@nomicfoundation/hardhat-verify@1.1.1(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)))(encoding@0.1.13)(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) '@trivago/prettier-plugin-sort-imports': specifier: ^4.3.0 version: 4.3.0(prettier@2.8.8) @@ -41,7 +47,7 @@ importers: version: 0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2) '@typechain/hardhat': specifier: ^8.0.3 - version: 8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2)) + version: 8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2)) '@types/chai': specifier: ^4.3.12 version: 4.3.12 @@ -52,8 +58,8 @@ importers: specifier: ^10.0.6 version: 10.0.6 '@types/node': - specifier: ^18.19.23 - version: 18.19.23 + specifier: ^18.19.59 + version: 18.19.59 '@typescript-eslint/eslint-plugin': specifier: ^5.62.0 version: 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@5.4.2))(eslint@8.57.0)(typescript@5.4.2) @@ -92,19 +98,19 @@ importers: version: 10.1.0 hardhat: specifier: 2.22.14 - version: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + version: 2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2) hardhat-deploy: specifier: ^0.11.45 version: 0.11.45 hardhat-gas-reporter: specifier: ^1.0.10 - version: 1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + version: 1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) hardhat-ignore-warnings: specifier: ^0.2.11 version: 0.2.11 hardhat-preprocessor: specifier: ^0.1.5 - version: 0.1.5(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + version: 0.1.5(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) lodash: specifier: ^4.17.21 version: 4.17.21 @@ -128,13 +134,13 @@ importers: version: 0.0.5(prettier-plugin-solidity@1.3.1(prettier@2.8.8))(prettier@2.8.8) solidity-coverage: specifier: 0.8.12 - version: 0.8.12(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + version: 0.8.12(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) ts-generator: specifier: ^0.1.1 version: 0.1.1 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@18.19.23)(typescript@5.4.2) + version: 10.9.2(@types/node@18.19.59)(typescript@5.4.2) typechain: specifier: ^8.3.2 version: 8.3.2(typescript@5.4.2) @@ -151,6 +157,19 @@ packages: '@adraffy/ens-normalize@1.10.1': resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==} + '@aws-crypto/sha256-js@1.2.2': + resolution: {integrity: sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g==} + + '@aws-crypto/util@1.2.2': + resolution: {integrity: sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg==} + + '@aws-sdk/types@3.679.0': + resolution: {integrity: sha512-NwVq8YvInxQdJ47+zz4fH3BRRLC6lL+WLkvr242PVBbUOLRyK/lkwHlfiKUoeVIMyK5NF+up6TRg71t/8Bny6Q==} + engines: {node: '>=16.0.0'} + + '@aws-sdk/util-utf8-browser@3.259.0': + resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} + '@babel/code-frame@7.23.5': resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} engines: {node: '>=6.9.0'} @@ -511,6 +530,46 @@ packages: peerDependencies: hardhat: ^2.0.4 + '@nomicfoundation/slang-darwin-arm64@0.17.0': + resolution: {integrity: sha512-O0q94EUtoWy9A5kOTOa9/khtxXDYnLqmuda9pQELurSiwbQEVCPQL8kb34VbOW+ifdre66JM/05Xw9JWhIZ9sA==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-darwin-x64@0.17.0': + resolution: {integrity: sha512-IaDbHzvT08sBK2HyGzonWhq1uu8IxdjmTqAWHr25Oh/PYnamdi8u4qchZXXYKz/DHLoYN3vIpBXoqLQIomhD/g==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-linux-arm64-gnu@0.17.0': + resolution: {integrity: sha512-Lj4anvOsQZxs1SycG8VyT2Rl2oqIhyLSUCgGepTt3CiJ/bM+8r8bLJIgh8vKkki4BWz49YsYIgaJB2IPv8FFTw==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-linux-arm64-musl@0.17.0': + resolution: {integrity: sha512-/xkTCa9d5SIWUBQE3BmLqDFfJRr4yUBwbl4ynPiGUpRXrD69cs6pWKkwjwz/FdBpXqVo36I+zY95qzoTj/YhOA==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-linux-x64-gnu@0.17.0': + resolution: {integrity: sha512-oe5IO5vntOqYvTd67deCHPIWuSuWm6aYtT2/0Kqz2/VLtGz4ClEulBSRwfnNzBVtw2nksWipE1w8BzhImI7Syg==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-linux-x64-musl@0.17.0': + resolution: {integrity: sha512-PpYCI5K/kgLAMXaPY0V4VST5gCDprEOh7z/47tbI8kJQumI5odjsj/Cs8MpTo7/uRH6flKYbVNgUzcocWVYrAQ==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-win32-arm64-msvc@0.17.0': + resolution: {integrity: sha512-u/Mkf7OjokdBilP7QOJj6QYJU4/mjkbKnTX21wLyCIzeVWS7yafRPYpBycKIBj2pRRZ6ceAY5EqRpb0aiCq+0Q==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-win32-ia32-msvc@0.17.0': + resolution: {integrity: sha512-XJBVQfNnZQUv0tP2JSJ573S+pmgrLWgqSZOGaMllnB/TL1gRci4Z7dYRJUF2s82GlRJE+FHSI2Ro6JISKmlXCg==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang-win32-x64-msvc@0.17.0': + resolution: {integrity: sha512-zPGsAeiTfqfPNYHD8BfrahQmYzA78ZraoHKTGraq/1xwJwzBK4bu/NtvVA4pJjBV+B4L6DCxVhSbpn40q26JQA==} + engines: {node: '>= 10'} + + '@nomicfoundation/slang@0.17.0': + resolution: {integrity: sha512-1GlkGRcGpVnjFw9Z1vvDKOKo2mzparFt7qrl2pDxWp+jrVtlvej98yCMX52pVyrYE7ZeOSZFnx/DtsSgoukStQ==} + engines: {node: '>= 10'} + '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1': resolution: {integrity: sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==} engines: {node: '>= 10'} @@ -583,9 +642,39 @@ packages: engines: {node: '>=10'} deprecated: This functionality has been moved to @npmcli/fs + '@openzeppelin/contracts-upgradeable@5.0.2': + resolution: {integrity: sha512-0MmkHSHiW2NRFiT9/r5Lu4eJq5UJ4/tzlOgYXNAIj/ONkQTVnz22pLxDvp4C4uZ9he7ZFvGn3Driptn1/iU7tQ==} + peerDependencies: + '@openzeppelin/contracts': 5.0.2 + '@openzeppelin/contracts@5.0.2': resolution: {integrity: sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA==} + '@openzeppelin/defender-sdk-base-client@1.15.0': + resolution: {integrity: sha512-nuf/xegMIuKCO0hMrxI1KQKTzQw1iCl/9kew2nJM9MrFIohhfEXItc5rbJRoV/jehmK/Jhi9ATF9OHH09StEsQ==} + + '@openzeppelin/defender-sdk-deploy-client@1.15.0': + resolution: {integrity: sha512-2ODMN4j5pPYWyIOvA/zRQmJ0tJyqi6NV3S/PyvufBXa3oj/MDnVO5bMGSQFH0M2VE3bg+i/rcUb0hdbX9Rtm5Q==} + + '@openzeppelin/defender-sdk-network-client@1.15.0': + resolution: {integrity: sha512-tNynCqFB1XYancq/8yGuj0HCSIyNLSRSuH53Hp2Tl+DpM7W5vIkzSRfvJJxC+8Sld83bVavyNJzTN9xid992Ag==} + + '@openzeppelin/hardhat-upgrades@3.5.0': + resolution: {integrity: sha512-Ju/JnT7NRiOMi5m5Y0dGiz37d8wnjVBep1v5Vr7+6+MFNuQa1yddUEVWhWhoEw4udI3/mYwyw4Sfz3sq7vhicQ==} + hasBin: true + peerDependencies: + '@nomicfoundation/hardhat-ethers': ^3.0.0 + '@nomicfoundation/hardhat-verify': ^2.0.0 + ethers: ^6.6.0 + hardhat: ^2.0.2 + peerDependenciesMeta: + '@nomicfoundation/hardhat-verify': + optional: true + + '@openzeppelin/upgrades-core@1.40.0': + resolution: {integrity: sha512-4bPSXdEqHsNRL5T1ybPLneWGYjzGl6XWGWkv7aUoFFgz8mOdarstRBX1Wi4XJFw6IeHPUI7mMSQr2jdz8Y2ypQ==} + hasBin: true + '@scure/base@1.1.5': resolution: {integrity: sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==} @@ -629,6 +718,10 @@ packages: resolution: {integrity: sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==} engines: {node: '>=6'} + '@smithy/types@3.6.0': + resolution: {integrity: sha512-8VXK/KzOHefoC65yRgCn5vG1cysPJjHnOVt9d0ybFQSmJgQj152vMn4EkYhGuaOmnnZvCPav/KnYyE6/KsNZ2w==} + engines: {node: '>=16.0.0'} + '@solidity-parser/parser@0.14.5': resolution: {integrity: sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==} @@ -732,8 +825,8 @@ packages: '@types/node@18.15.13': resolution: {integrity: sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==} - '@types/node@18.19.23': - resolution: {integrity: sha512-wtE3d0OUfNKtZYAqZb8HAWGxxXsImJcPUAgZNw+dWFxO6s5tIwIjyKnY76tsTatsNCLJPkVYwUpq15D38ng9Aw==} + '@types/node@18.19.59': + resolution: {integrity: sha512-vizm2EqwV/7Zay+A6J3tGl9Lhr7CjZe2HmWS988sefiEmsyP9CeXEleho6i4hJk/8UtZAo0bWN4QPZZr83RxvQ==} '@types/node@8.10.66': resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} @@ -862,6 +955,9 @@ packages: ajv@8.12.0: resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + amazon-cognito-identity-js@6.3.12: + resolution: {integrity: sha512-s7NKDZgx336cp+oDeUtB2ZzT8jWJp/v2LWuYl+LQtMEODe22RF1IJ4nRiDATp+rp1pTffCZcm44Quw4jx2bqNg==} + amdefine@1.0.1: resolution: {integrity: sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==} engines: {node: '>=0.4.2'} @@ -954,6 +1050,9 @@ packages: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} + async-retry@1.3.3: + resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + async@1.5.2: resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} @@ -974,6 +1073,9 @@ packages: axios@1.6.7: resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==} + axios@1.7.7: + resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -1047,6 +1149,9 @@ packages: buffer-xor@1.0.3: resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + buffer@4.9.2: + resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} + buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} @@ -1080,6 +1185,10 @@ packages: resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} engines: {node: '>=12.19'} + cbor@9.0.2: + resolution: {integrity: sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ==} + engines: {node: '>=16'} + chai-as-promised@7.1.1: resolution: {integrity: sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==} peerDependencies: @@ -1191,6 +1300,9 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} + compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -1488,6 +1600,9 @@ packages: extra-bigint@1.2.0: resolution: {integrity: sha512-F9T/pcT5xPZTjlFMKGCZgBY2/jKqEPxXHT4kLSwsa7gp7D05nQq8z9NzRTzVy5Z4AOO1E/iD9r9OBz4csGD7nw==} + fast-base64-decode@1.0.0: + resolution: {integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1574,6 +1689,15 @@ packages: debug: optional: true + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -1958,9 +2082,15 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isomorphic-unfetch@3.1.0: + resolution: {integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==} + javascript-natural-sort@0.7.1: resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} + js-cookie@2.2.1: + resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==} + js-sha3@0.8.0: resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} @@ -2141,6 +2271,10 @@ packages: resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==} engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -2242,6 +2376,15 @@ packages: node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + node-gyp-build@4.8.0: resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==} hasBin: true @@ -2446,6 +2589,9 @@ packages: promise@8.3.0: resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -2550,6 +2696,10 @@ packages: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -2696,6 +2846,9 @@ packages: resolution: {integrity: sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ==} hasBin: true + solidity-ast@0.4.59: + resolution: {integrity: sha512-I+CX0wrYUN9jDfYtcgWSe+OAowaXy8/1YQy7NS4ni5IBDmIYBq7ZzaP/7QqouLjzZapmQtvGLqCaYgoUWqBo5g==} + solidity-comments-darwin-arm64@0.0.2: resolution: {integrity: sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==} engines: {node: '>= 10'} @@ -2917,6 +3070,9 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + ts-command-line-args@2.5.1: resolution: {integrity: sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==} hasBin: true @@ -2953,6 +3109,9 @@ packages: tslib@2.4.0: resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + tslib@2.8.0: + resolution: {integrity: sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==} + tsort@0.0.1: resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} @@ -3029,6 +3188,13 @@ packages: resolution: {integrity: sha512-3ItfzbrhDlINjaP0duwnNsKpDQk3acHI3gVJ1z4fmwMK31k5G9OVIAMLSIaP6w4FaGkaAkN6zaQO9LUvZ1t7VA==} engines: {node: '>=14.0'} + undici@6.20.1: + resolution: {integrity: sha512-AjQF1QsmqfJys+LXfGTNum+qw4S88CojRInG/6t31W/1fk6G59s92bnAvGz5Cmur+kQv2SURXEvvudLmbrE8QA==} + engines: {node: '>=18.17'} + + unfetch@4.2.0: + resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} + unique-filename@1.1.1: resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} @@ -3086,6 +3252,12 @@ packages: resolution: {integrity: sha512-qn9id0/l1bWmvH4XfnG/JtGKKwut2Vokl6YXP5Kfg424npysmtRLe9DgiNBM9Op7QL/aSiaA0TVXibuIuWcizg==} engines: {node: '>=14', npm: '>=6.12.0'} + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + which-typed-array@1.1.15: resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} engines: {node: '>= 0.4'} @@ -3205,6 +3377,27 @@ snapshots: '@adraffy/ens-normalize@1.10.1': {} + '@aws-crypto/sha256-js@1.2.2': + dependencies: + '@aws-crypto/util': 1.2.2 + '@aws-sdk/types': 3.679.0 + tslib: 1.14.1 + + '@aws-crypto/util@1.2.2': + dependencies: + '@aws-sdk/types': 3.679.0 + '@aws-sdk/util-utf8-browser': 3.259.0 + tslib: 1.14.1 + + '@aws-sdk/types@3.679.0': + dependencies: + '@smithy/types': 3.6.0 + tslib: 2.8.0 + + '@aws-sdk/util-utf8-browser@3.259.0': + dependencies: + tslib: 2.4.0 + '@babel/code-frame@7.23.5': dependencies: '@babel/highlight': 7.23.4 @@ -3693,59 +3886,59 @@ snapshots: '@nomicfoundation/ethereumjs-rlp': 5.0.4 ethereum-cryptography: 0.1.3 - '@nomicfoundation/hardhat-chai-matchers@2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': + '@nomicfoundation/hardhat-chai-matchers@2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2))': dependencies: - '@nomicfoundation/hardhat-ethers': 3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-ethers': 3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) '@types/chai-as-promised': 7.1.8 chai: 4.4.1 chai-as-promised: 7.1.1(chai@4.4.1) deep-eql: 4.1.3 ethers: 6.11.1 - hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2) ordinal: 1.0.3 - '@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': + '@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2))': dependencies: debug: 4.3.4(supports-color@8.1.1) ethers: 6.11.1 - hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2) lodash.isequal: 4.5.0 transitivePeerDependencies: - supports-color - '@nomicfoundation/hardhat-network-helpers@1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': + '@nomicfoundation/hardhat-network-helpers@1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2))': dependencies: ethereumjs-util: 7.1.5 - hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2) - '@nomicfoundation/hardhat-toolbox@3.0.0(ugreflrcgmhzqdan7c47drajhi)': + '@nomicfoundation/hardhat-toolbox@3.0.0(sziado6kyyqqr3qor4olybdgcq)': dependencies: - '@nomicfoundation/hardhat-chai-matchers': 2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) - '@nomicfoundation/hardhat-ethers': 3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) - '@nomicfoundation/hardhat-network-helpers': 1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) - '@nomicfoundation/hardhat-verify': 1.1.1(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-chai-matchers': 2.0.6(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)))(chai@4.4.1)(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-ethers': 3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-network-helpers': 1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) + '@nomicfoundation/hardhat-verify': 1.1.1(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) '@typechain/ethers-v6': 0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2) - '@typechain/hardhat': 8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2)) + '@typechain/hardhat': 8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2)) '@types/chai': 4.3.12 '@types/mocha': 10.0.6 - '@types/node': 18.19.23 + '@types/node': 18.19.59 chai: 4.4.1 ethers: 6.11.1 - hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) - hardhat-gas-reporter: 1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) - solidity-coverage: 0.8.12(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)) - ts-node: 10.9.2(@types/node@18.19.23)(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2) + hardhat-gas-reporter: 1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) + solidity-coverage: 0.8.12(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) + ts-node: 10.9.2(@types/node@18.19.59)(typescript@5.4.2) typechain: 8.3.2(typescript@5.4.2) typescript: 5.4.2 - '@nomicfoundation/hardhat-verify@1.1.1(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))': + '@nomicfoundation/hardhat-verify@1.1.1(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2))': dependencies: '@ethersproject/abi': 5.7.0 '@ethersproject/address': 5.7.0 cbor: 8.1.0 chalk: 2.4.2 debug: 4.3.4(supports-color@8.1.1) - hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2) lodash.clonedeep: 4.5.0 semver: 6.3.1 table: 6.8.1 @@ -3753,6 +3946,36 @@ snapshots: transitivePeerDependencies: - supports-color + '@nomicfoundation/slang-darwin-arm64@0.17.0': {} + + '@nomicfoundation/slang-darwin-x64@0.17.0': {} + + '@nomicfoundation/slang-linux-arm64-gnu@0.17.0': {} + + '@nomicfoundation/slang-linux-arm64-musl@0.17.0': {} + + '@nomicfoundation/slang-linux-x64-gnu@0.17.0': {} + + '@nomicfoundation/slang-linux-x64-musl@0.17.0': {} + + '@nomicfoundation/slang-win32-arm64-msvc@0.17.0': {} + + '@nomicfoundation/slang-win32-ia32-msvc@0.17.0': {} + + '@nomicfoundation/slang-win32-x64-msvc@0.17.0': {} + + '@nomicfoundation/slang@0.17.0': + dependencies: + '@nomicfoundation/slang-darwin-arm64': 0.17.0 + '@nomicfoundation/slang-darwin-x64': 0.17.0 + '@nomicfoundation/slang-linux-arm64-gnu': 0.17.0 + '@nomicfoundation/slang-linux-arm64-musl': 0.17.0 + '@nomicfoundation/slang-linux-x64-gnu': 0.17.0 + '@nomicfoundation/slang-linux-x64-musl': 0.17.0 + '@nomicfoundation/slang-win32-arm64-msvc': 0.17.0 + '@nomicfoundation/slang-win32-ia32-msvc': 0.17.0 + '@nomicfoundation/slang-win32-x64-msvc': 0.17.0 + '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1': optional: true @@ -3808,8 +4031,72 @@ snapshots: rimraf: 3.0.2 optional: true + '@openzeppelin/contracts-upgradeable@5.0.2(@openzeppelin/contracts@5.0.2)': + dependencies: + '@openzeppelin/contracts': 5.0.2 + '@openzeppelin/contracts@5.0.2': {} + '@openzeppelin/defender-sdk-base-client@1.15.0(encoding@0.1.13)': + dependencies: + amazon-cognito-identity-js: 6.3.12(encoding@0.1.13) + async-retry: 1.3.3 + transitivePeerDependencies: + - encoding + + '@openzeppelin/defender-sdk-deploy-client@1.15.0(debug@4.3.4)(encoding@0.1.13)': + dependencies: + '@openzeppelin/defender-sdk-base-client': 1.15.0(encoding@0.1.13) + axios: 1.7.7(debug@4.3.4) + lodash: 4.17.21 + transitivePeerDependencies: + - debug + - encoding + + '@openzeppelin/defender-sdk-network-client@1.15.0(debug@4.3.4)(encoding@0.1.13)': + dependencies: + '@openzeppelin/defender-sdk-base-client': 1.15.0(encoding@0.1.13) + axios: 1.7.7(debug@4.3.4) + lodash: 4.17.21 + transitivePeerDependencies: + - debug + - encoding + + '@openzeppelin/hardhat-upgrades@3.5.0(@nomicfoundation/hardhat-ethers@3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)))(@nomicfoundation/hardhat-verify@1.1.1(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)))(encoding@0.1.13)(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2))': + dependencies: + '@nomicfoundation/hardhat-ethers': 3.0.5(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) + '@openzeppelin/defender-sdk-base-client': 1.15.0(encoding@0.1.13) + '@openzeppelin/defender-sdk-deploy-client': 1.15.0(debug@4.3.4)(encoding@0.1.13) + '@openzeppelin/defender-sdk-network-client': 1.15.0(debug@4.3.4)(encoding@0.1.13) + '@openzeppelin/upgrades-core': 1.40.0 + chalk: 4.1.2 + debug: 4.3.4(supports-color@8.1.1) + ethereumjs-util: 7.1.5 + ethers: 6.11.1 + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2) + proper-lockfile: 4.1.2 + undici: 6.20.1 + optionalDependencies: + '@nomicfoundation/hardhat-verify': 1.1.1(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)) + transitivePeerDependencies: + - encoding + - supports-color + + '@openzeppelin/upgrades-core@1.40.0': + dependencies: + '@nomicfoundation/slang': 0.17.0 + cbor: 9.0.2 + chalk: 4.1.2 + compare-versions: 6.1.1 + debug: 4.3.4(supports-color@8.1.1) + ethereumjs-util: 7.1.5 + minimatch: 9.0.5 + minimist: 1.2.8 + proper-lockfile: 4.1.2 + solidity-ast: 0.4.59 + transitivePeerDependencies: + - supports-color + '@scure/base@1.1.5': {} '@scure/bip32@1.1.5': @@ -3883,6 +4170,10 @@ snapshots: '@sentry/types': 5.30.0 tslib: 1.14.1 + '@smithy/types@3.6.0': + dependencies: + tslib: 2.8.0 + '@solidity-parser/parser@0.14.5': dependencies: antlr4ts: 0.5.0-alpha.4 @@ -3926,21 +4217,21 @@ snapshots: typechain: 8.3.2(typescript@5.4.2) typescript: 5.4.2 - '@typechain/hardhat@8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2))': + '@typechain/hardhat@8.0.3(@typechain/ethers-v6@0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2))(ethers@6.11.1)(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2))(typechain@8.3.2(typescript@5.4.2))': dependencies: '@typechain/ethers-v6': 0.4.3(ethers@6.11.1)(typechain@8.3.2(typescript@5.4.2))(typescript@5.4.2) ethers: 6.11.1 fs-extra: 9.1.0 - hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2) typechain: 8.3.2(typescript@5.4.2) '@types/bn.js@4.11.6': dependencies: - '@types/node': 18.19.23 + '@types/node': 18.19.59 '@types/bn.js@5.1.5': dependencies: - '@types/node': 18.19.23 + '@types/node': 18.19.59 '@types/chai-as-promised@7.1.8': dependencies: @@ -3950,28 +4241,28 @@ snapshots: '@types/concat-stream@1.6.1': dependencies: - '@types/node': 18.19.23 + '@types/node': 18.19.59 '@types/form-data@0.0.33': dependencies: - '@types/node': 18.19.23 + '@types/node': 18.19.59 '@types/fs-extra@9.0.13': dependencies: - '@types/node': 18.19.23 + '@types/node': 18.19.59 '@types/glob-to-regexp@0.4.4': {} '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 18.19.23 + '@types/node': 18.19.59 '@types/json-schema@7.0.15': {} '@types/keccak@3.0.5': dependencies: - '@types/node': 18.19.23 + '@types/node': 18.19.59 '@types/lru-cache@5.1.1': {} @@ -3979,7 +4270,7 @@ snapshots: '@types/mkdirp@0.5.2': dependencies: - '@types/node': 18.19.23 + '@types/node': 18.19.59 '@types/mocha@10.0.6': {} @@ -3987,7 +4278,7 @@ snapshots: '@types/node@18.15.13': {} - '@types/node@18.19.23': + '@types/node@18.19.59': dependencies: undici-types: 5.26.5 @@ -3995,7 +4286,7 @@ snapshots: '@types/pbkdf2@3.1.2': dependencies: - '@types/node': 18.19.23 + '@types/node': 18.19.59 '@types/prettier@2.7.3': {} @@ -4003,11 +4294,11 @@ snapshots: '@types/resolve@0.0.8': dependencies: - '@types/node': 18.19.23 + '@types/node': 18.19.59 '@types/secp256k1@4.0.6': dependencies: - '@types/node': 18.19.23 + '@types/node': 18.19.59 '@types/semver@7.5.8': {} @@ -4143,6 +4434,16 @@ snapshots: require-from-string: 2.0.2 uri-js: 4.4.1 + amazon-cognito-identity-js@6.3.12(encoding@0.1.13): + dependencies: + '@aws-crypto/sha256-js': 1.2.2 + buffer: 4.9.2 + fast-base64-decode: 1.0.0 + isomorphic-unfetch: 3.1.0(encoding@0.1.13) + js-cookie: 2.2.1 + transitivePeerDependencies: + - encoding + amdefine@1.0.1: optional: true @@ -4212,6 +4513,10 @@ snapshots: astral-regex@2.0.0: {} + async-retry@1.3.3: + dependencies: + retry: 0.13.1 + async@1.5.2: {} asynckit@0.4.0: {} @@ -4236,6 +4541,14 @@ snapshots: transitivePeerDependencies: - debug + axios@1.7.7(debug@4.3.4): + dependencies: + follow-redirects: 1.15.9(debug@4.3.4) + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + balanced-match@1.0.2: {} base-x@3.0.9: @@ -4321,6 +4634,12 @@ snapshots: buffer-xor@1.0.3: {} + buffer@4.9.2: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + isarray: 1.0.0 + buffer@5.7.1: dependencies: base64-js: 1.5.1 @@ -4375,6 +4694,10 @@ snapshots: dependencies: nofilter: 3.1.0 + cbor@9.0.2: + dependencies: + nofilter: 3.1.0 + chai-as-promised@7.1.1(chai@4.4.1): dependencies: chai: 4.4.1 @@ -4506,6 +4829,8 @@ snapshots: commander@8.3.0: {} + compare-versions@6.1.1: {} + concat-map@0.0.1: {} concat-stream@1.6.2: @@ -4919,6 +5244,8 @@ snapshots: extra-bigint@1.2.0: {} + fast-base64-decode@1.0.0: {} + fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} @@ -5015,6 +5342,10 @@ snapshots: optionalDependencies: debug: 4.3.4(supports-color@8.1.1) + follow-redirects@1.15.9(debug@4.3.4): + optionalDependencies: + debug: 4.3.4(supports-color@8.1.1) + for-each@0.3.3: dependencies: is-callable: 1.2.7 @@ -5250,11 +5581,11 @@ snapshots: - supports-color - utf-8-validate - hardhat-gas-reporter@1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): + hardhat-gas-reporter@1.0.10(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)): dependencies: array-uniq: 1.0.3 eth-gas-reporter: 0.2.27 - hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2) sha1: 1.1.1 transitivePeerDependencies: - '@codechecks/client' @@ -5268,12 +5599,12 @@ snapshots: node-interval-tree: 2.1.2 solidity-comments: 0.0.2 - hardhat-preprocessor@0.1.5(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): + hardhat-preprocessor@0.1.5(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)): dependencies: - hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2) murmur-128: 0.2.1 - hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2): + hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2): dependencies: '@ethersproject/abi': 5.7.0 '@metamask/eth-sig-util': 4.0.1 @@ -5320,7 +5651,7 @@ snapshots: uuid: 8.3.2 ws: 7.5.9 optionalDependencies: - ts-node: 10.9.2(@types/node@18.19.23)(typescript@5.4.2) + ts-node: 10.9.2(@types/node@18.19.59)(typescript@5.4.2) typescript: 5.4.2 transitivePeerDependencies: - bufferutil @@ -5521,8 +5852,17 @@ snapshots: isexe@2.0.0: {} + isomorphic-unfetch@3.1.0(encoding@0.1.13): + dependencies: + node-fetch: 2.7.0(encoding@0.1.13) + unfetch: 4.2.0 + transitivePeerDependencies: + - encoding + javascript-natural-sort@0.7.1: {} + js-cookie@2.2.1: {} + js-sha3@0.8.0: {} js-tokens@4.0.0: {} @@ -5701,6 +6041,10 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + minimist@1.2.8: {} minipass-collect@1.0.2: @@ -5815,6 +6159,12 @@ snapshots: dependencies: lodash: 4.17.21 + node-fetch@2.7.0(encoding@0.1.13): + dependencies: + whatwg-url: 5.0.0 + optionalDependencies: + encoding: 0.1.13 + node-gyp-build@4.8.0: {} node-gyp@8.4.1: @@ -6017,6 +6367,12 @@ snapshots: dependencies: asap: 2.0.6 + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + proxy-from-env@1.1.0: {} pump@3.0.2: @@ -6118,8 +6474,9 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - retry@0.12.0: - optional: true + retry@0.12.0: {} + + retry@0.13.1: {} reusify@1.0.4: {} @@ -6238,8 +6595,7 @@ snapshots: get-intrinsic: 1.2.4 object-inspect: 1.13.1 - signal-exit@3.0.7: - optional: true + signal-exit@3.0.7: {} simple-concat@1.0.1: {} @@ -6317,6 +6673,8 @@ snapshots: transitivePeerDependencies: - typescript + solidity-ast@0.4.59: {} + solidity-comments-darwin-arm64@0.0.2: optional: true @@ -6362,7 +6720,7 @@ snapshots: solidity-comments-win32-ia32-msvc: 0.0.2 solidity-comments-win32-x64-msvc: 0.0.2 - solidity-coverage@0.8.12(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2)): + solidity-coverage@0.8.12(hardhat@2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2)): dependencies: '@ethersproject/abi': 5.7.0 '@solidity-parser/parser': 0.18.0 @@ -6373,7 +6731,7 @@ snapshots: ghost-testrpc: 0.0.2 global-modules: 2.0.0 globby: 10.0.2 - hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2))(typescript@5.4.2) + hardhat: 2.22.14(ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2))(typescript@5.4.2) jsonschema: 1.4.1 lodash: 4.17.21 mocha: 10.3.0 @@ -6563,6 +6921,8 @@ snapshots: toidentifier@1.0.1: {} + tr46@0.0.3: {} + ts-command-line-args@2.5.1: dependencies: chalk: 4.1.2 @@ -6588,14 +6948,14 @@ snapshots: resolve: 1.22.8 ts-essentials: 1.0.4 - ts-node@10.9.2(@types/node@18.19.23)(typescript@5.4.2): + ts-node@10.9.2(@types/node@18.19.59)(typescript@5.4.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.9 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 18.19.23 + '@types/node': 18.19.59 acorn: 8.11.3 acorn-walk: 8.3.2 arg: 4.1.3 @@ -6610,6 +6970,8 @@ snapshots: tslib@2.4.0: {} + tslib@2.8.0: {} + tsort@0.0.1: {} tsutils@3.21.0(typescript@5.4.2): @@ -6674,6 +7036,10 @@ snapshots: dependencies: '@fastify/busboy': 2.1.1 + undici@6.20.1: {} + + unfetch@4.2.0: {} + unique-filename@1.1.1: dependencies: unique-slug: 2.0.2 @@ -6740,6 +7106,13 @@ snapshots: web3-types: 1.8.1 zod: 3.23.8 + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + which-typed-array@1.1.15: dependencies: available-typed-arrays: 1.0.7 diff --git a/remappings.txt b/remappings.txt deleted file mode 100644 index 038a557..0000000 --- a/remappings.txt +++ /dev/null @@ -1 +0,0 @@ -lib/TFHE=mocks/TFHE \ No newline at end of file diff --git a/tasks/accounts.ts b/tasks/accounts.ts index 866b83a..b206222 100644 --- a/tasks/accounts.ts +++ b/tasks/accounts.ts @@ -1,9 +1,9 @@ import { task } from "hardhat/config"; -task("task:accounts", "Prints the list of accounts", async (_taskArgs, hre) => { +task("accounts", "Prints the list of accounts", async (_taskArgs, hre) => { const accounts = await hre.ethers.getSigners(); for (const account of accounts) { - console.log(account.address); + console.info(account.address); } }); diff --git a/tasks/taskDeploy.ts b/tasks/taskDeploy.ts index 86888ce..3b2e9a6 100644 --- a/tasks/taskDeploy.ts +++ b/tasks/taskDeploy.ts @@ -1,18 +1,18 @@ import dotenv from "dotenv"; import fs from "fs"; -import { task } from "hardhat/config"; +import { task, types } from "hardhat/config"; import type { TaskArguments } from "hardhat/types"; task("task:deployGateway") .addParam("privateKey", "The deployer private key") .addParam("ownerAddress", "The owner address") - .setAction(async function (taskArguments: TaskArguments, { ethers }) { + .setAction(async function (taskArguments: TaskArguments, { ethers, upgrades }) { const deployer = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); - const envConfig2 = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.kmsverifier")); - const gatewayFactory = await ethers.getContractFactory("fhevm/gateway/GatewayContract.sol:GatewayContract"); - const Gateway = await gatewayFactory - .connect(deployer) - .deploy(taskArguments.ownerAddress, envConfig2.KMS_VERIFIER_CONTRACT_ADDRESS); + const factory = await ethers.getContractFactory("GatewayContract", deployer); + const Gateway = await upgrades.deployProxy(factory, [taskArguments.ownerAddress], { + initializer: "initialize", + kind: "uups", + }); await Gateway.waitForDeployment(); const GatewayContractAddress = await Gateway.getAddress(); const envConfig = dotenv.parse(fs.readFileSync("node_modules/fhevm/gateway/.env.gateway")); @@ -24,42 +24,133 @@ task("task:deployGateway") console.log("GatewayContract was deployed at address: ", GatewayContractAddress); }); -task("task:deployACL").setAction(async function (taskArguments: TaskArguments, { ethers }) { - const deployer = (await ethers.getSigners())[9]; - const factory = await ethers.getContractFactory("fhevm/lib/ACL.sol:ACL"); - const envConfigExec = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.exec")); - const acl = await factory.connect(deployer).deploy(envConfigExec.TFHE_EXECUTOR_CONTRACT_ADDRESS); - await acl.waitForDeployment(); - const address = await acl.getAddress(); - const envConfigAcl = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.acl")); - if (address !== envConfigAcl.ACL_CONTRACT_ADDRESS) { - throw new Error(`The nonce of the deployer account is not corret. Please relaunch a clean instance of the fhEVM`); - } - console.log("ACL was deployed at address:", address); -}); +task("task:deployACL") + .addParam("privateKey", "The deployer private key") + .setAction(async function (taskArguments: TaskArguments, { ethers, upgrades }) { + const deployer = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); + const factory = await ethers.getContractFactory("fhevmTemp/contracts/ACL.sol:ACL", deployer); + const acl = await upgrades.deployProxy(factory, [deployer.address], { initializer: "initialize", kind: "uups" }); + await acl.waitForDeployment(); + const address = await acl.getAddress(); + const envConfigAcl = dotenv.parse(fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.acl")); + if (address !== envConfigAcl.ACL_CONTRACT_ADDRESS) { + throw new Error( + `The nonce of the deployer account is not correct. Please relaunch a clean instance of the fhEVM`, + ); + } + console.log("ACL was deployed at address:", address); + }); + +task("task:deployTFHEExecutor") + .addParam("privateKey", "The deployer private key") + .setAction(async function (taskArguments: TaskArguments, { ethers, upgrades }) { + const deployer = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); + const factory = await ethers.getContractFactory( + "fhevmTemp/contracts/TFHEExecutor.events.sol:TFHEExecutor", + deployer, + ); + const exec = await upgrades.deployProxy(factory, [deployer.address], { initializer: "initialize", kind: "uups" }); + await exec.waitForDeployment(); + const address = await exec.getAddress(); + const envConfig = dotenv.parse(fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.exec")); + if (address !== envConfig.TFHE_EXECUTOR_CONTRACT_ADDRESS) { + throw new Error( + `The nonce of the deployer account is not correct. Please relaunch a clean instance of the fhEVM`, + ); + } + console.log("TFHEExecutor was deployed at address:", address); + }); + +task("task:deployKMSVerifier") + .addParam("privateKey", "The deployer private key") + .setAction(async function (taskArguments: TaskArguments, { ethers, upgrades }) { + const deployer = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); + const factory = await ethers.getContractFactory("fhevmTemp/contracts/KMSVerifier.sol:KMSVerifier", deployer); + const kms = await upgrades.deployProxy(factory, [deployer.address], { initializer: "initialize", kind: "uups" }); + await kms.waitForDeployment(); + const address = await kms.getAddress(); + const envConfig = dotenv.parse(fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.kmsverifier")); + if (address !== envConfig.KMS_VERIFIER_CONTRACT_ADDRESS) { + throw new Error( + `The nonce of the deployer account is not correct. Please relaunch a clean instance of the fhEVM`, + ); + } + console.log("KMSVerifier was deployed at address:", address); + }); + +task("task:deployInputVerifier") + .addParam("privateKey", "The deployer private key") + .setAction(async function (taskArguments: TaskArguments, { ethers, upgrades }) { + const deployer = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); + let factory; + if (process.env.IS_COPROCESSOR === "true") { + factory = await ethers.getContractFactory( + "fhevmTemp/contracts/InputVerifier.coprocessor.sol:InputVerifier", + deployer, + ); + } else { + factory = await ethers.getContractFactory("fhevmTemp/contracts/InputVerifier.native.sol:InputVerifier", deployer); + } + const kms = await upgrades.deployProxy(factory, [deployer.address], { initializer: "initialize", kind: "uups" }); + await kms.waitForDeployment(); + const address = await kms.getAddress(); + const envConfig = dotenv.parse(fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.inputverifier")); + if (address !== envConfig.INPUT_VERIFIER_CONTRACT_ADDRESS) { + throw new Error( + `The nonce of the deployer account is not correct. Please relaunch a clean instance of the fhEVM`, + ); + } + console.log("InputVerifier was deployed at address:", address); + }); -task("task:deployTFHEExecutor").setAction(async function (taskArguments: TaskArguments, { ethers }) { - const deployer = (await ethers.getSigners())[9]; - const factory = await ethers.getContractFactory("TFHEExecutor"); - const exec = await factory.connect(deployer).deploy(); - await exec.waitForDeployment(); - const address = await exec.getAddress(); - const envConfig = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.exec")); - if (address !== envConfig.TFHE_EXECUTOR_CONTRACT_ADDRESS) { - throw new Error(`The nonce of the deployer account is not corret. Please relaunch a clean instance of the fhEVM`); - } - console.log("TFHEExecutor was deployed at address:", address); -}); +task("task:deployFHEPayment") + .addParam("privateKey", "The deployer private key") + .setAction(async function (taskArguments: TaskArguments, { ethers, upgrades }) { + const deployer = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); + const factory = await ethers.getContractFactory("fhevmTemp/contracts/FHEPayment.sol:FHEPayment", deployer); + const payment = await upgrades.deployProxy(factory, [deployer.address], { + initializer: "initialize", + kind: "uups", + }); + await payment.waitForDeployment(); + const address = await payment.getAddress(); + const envConfig = dotenv.parse(fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.fhepayment")); + if (address !== envConfig.FHE_PAYMENT_CONTRACT_ADDRESS) { + throw new Error( + `The nonce of the deployer account is not correct. Please relaunch a clean instance of the fhEVM`, + ); + } + console.log("FHEPayment was deployed at address:", address); + }); -task("task:deployKMSVerifier").setAction(async function (taskArguments: TaskArguments, { ethers }) { - const deployer = (await ethers.getSigners())[9]; - const factory = await ethers.getContractFactory("fhevm/lib/KMSVerifier.sol:KMSVerifier"); - const exec = await factory.connect(deployer).deploy(); - await exec.waitForDeployment(); - const address = await exec.getAddress(); - const envConfig = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.kmsverifier")); - if (address !== envConfig.KMS_VERIFIER_CONTRACT_ADDRESS) { - throw new Error(`The nonce of the deployer account is not corret. Please relaunch a clean instance of the fhEVM`); - } - console.log("KMSVerifier was deployed at address:", address); -}); +task("task:addSigners") + .addParam("privateKey", "The deployer private key") + .addParam("numSigners", "Number of KMS signers to add") + .addOptionalParam( + "useAddress", + "Use addresses instead of private keys env variables for kms signers", + false, + types.boolean, + ) + .setAction(async function (taskArguments: TaskArguments, { ethers }) { + const deployer = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); + const factory = await ethers.getContractFactory("fhevmTemp/contracts/KMSVerifier.sol:KMSVerifier", deployer); + const kmsAdd = dotenv.parse( + fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.kmsverifier"), + ).KMS_VERIFIER_CONTRACT_ADDRESS; + const kmsVerifier = await factory.attach(kmsAdd); + for (let idx = 0; idx < taskArguments.numSigners; idx++) { + if (!taskArguments.useAddress) { + const privKeySigner = process.env[`PRIVATE_KEY_KMS_SIGNER_${idx}`]; + const kmsSigner = new ethers.Wallet(privKeySigner).connect(ethers.provider); + const tx = await kmsVerifier.addSigner(kmsSigner.address); + await tx.wait(); + console.log(`KMS signer no${idx} (${kmsSigner.address}) was added to KMSVerifier contract`); + } else { + const kmsSignerAddress = process.env[`ADDRESS_KMS_SIGNER_${idx}`]; + const tx = await kmsVerifier.addSigner(kmsSignerAddress); + await tx.wait(); + console.log(`KMS signer no${idx} (${kmsSignerAddress}) was added to KMSVerifier contract`); + } + } + }); \ No newline at end of file diff --git a/tasks/taskGatewayRelayer.ts b/tasks/taskGatewayRelayer.ts index fb22ce9..22ae85b 100644 --- a/tasks/taskGatewayRelayer.ts +++ b/tasks/taskGatewayRelayer.ts @@ -9,25 +9,25 @@ import { promisify } from "util"; const exec = promisify(oldExec); const getCoin = async (address: string) => { - const containerName = process.env["TEST_CONTAINER_NAME"] || "zama-kms-validator-1"; + const containerName = process.env["TEST_CONTAINER_NAME"] || "fhevm"; const response = await exec(`docker exec -i ${containerName} faucet ${address} | grep height`); const res = JSON.parse(response.stdout); if (res.raw_log.match("account sequence mismatch")) await getCoin(address); }; -task("task:computePredeployAddress") +task("task:computeGatewayAddress") .addParam("privateKey", "The deployer private key") .setAction(async function (taskArguments: TaskArguments, { ethers }) { const deployerAddress = new ethers.Wallet(taskArguments.privateKey).address; const gatewayContractAddressPrecomputed = ethers.getCreateAddress({ from: deployerAddress, - nonce: 0, // deployer is supposed to have nonce 0 when deploying GatewayContract + nonce: 1, // deployer is supposed to have nonce 0 when deploying GatewayContract (0 nonce for implementation, +1 for UUPS) }); const envFilePath = path.join(__dirname, "../node_modules/fhevm/gateway/.env.gateway"); - const content = `GATEWAY_CONTRACT_PREDEPLOY_ADDRESS=${gatewayContractAddressPrecomputed}\n`; + const content = `GATEWAY_CONTRACT_PREDEPLOY_ADDRESS=${gatewayContractAddressPrecomputed}`; try { fs.writeFileSync(envFilePath, content, { flag: "w" }); - console.log("gatewayContractAddress written to gateway/.env.gateway successfully!"); + console.log("gatewayContractAddress written to node_modules/fhevm/gateway/.env.gateway successfully!"); } catch (err) { console.error("Failed to write to node_modules/fhevm/gateway/.env.gateway:", err); } @@ -37,16 +37,16 @@ task("task:computePredeployAddress") pragma solidity ^0.8.24; address constant GATEWAY_CONTRACT_PREDEPLOY_ADDRESS = ${gatewayContractAddressPrecomputed}; - `; +`; try { - fs.writeFileSync("./node_modules/fhevm/gateway/lib/PredeployAddress.sol", solidityTemplate, { + fs.writeFileSync("./node_modules/fhevm/gateway/lib/GatewayContractAddress.sol", solidityTemplate, { encoding: "utf8", flag: "w", }); - console.log("node_modules/fhevm/gateway/lib/PredeployAddress.sol file has been generated successfully."); + console.log("node_modules/fhevm/gateway/lib/GatewayContractAddress.sol file has been generated successfully."); } catch (error) { - console.error("Failed to write node_modules/fhevm/gateway/lib/PredeployAddress.sol", error); + console.error("Failed to write node_modules/fhevm/gateway/lib/GatewayContractAddress.sol", error); } }); @@ -60,11 +60,7 @@ task("task:addRelayer") throw Error(`${taskArguments.gatewayAddress} is not a smart contract`); } const owner = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); - const gateway = await ethers.getContractAt( - "fhevm/gateway/GatewayContract.sol:GatewayContract", - taskArguments.gatewayAddress, - owner, - ); + const gateway = await ethers.getContractAt("GatewayContract", taskArguments.gatewayAddress, owner); const tx = await gateway.addRelayer(taskArguments.relayerAddress); const rcpt = await tx.wait(); if (rcpt!.status === 1) { @@ -84,11 +80,7 @@ task("task:removeRelayer") throw Error(`${taskArguments.gatewayAddress} is not a smart contract`); } const owner = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); - const gateway = await ethers.getContractAt( - "fhevm/gateway/GatewayContract.sol:GatewayContract", - taskArguments.gatewayAddress, - owner, - ); + const gateway = await ethers.getContractAt("GatewayContract", taskArguments.gatewayAddress, owner); const tx = await gateway.removeRelayer(taskArguments.relayerAddress); const rcpt = await tx.wait(); if (rcpt!.status === 1) { @@ -100,37 +92,37 @@ task("task:removeRelayer") task("task:launchFhevm") .addOptionalParam("skipGetCoin", "Skip calling getCoin()", false, types.boolean) + .addOptionalParam("useAddress", "Use address instead of privte key for the Gateway Relayer", false, types.boolean) .setAction(async function (taskArgs, hre) { const privKeyDeployer = process.env.PRIVATE_KEY_GATEWAY_DEPLOYER; - const privKeyOwner = process.env.PRIVATE_KEY_GATEWAY_OWNER; - const privKeyRelayer = process.env.PRIVATE_KEY_GATEWAY_RELAYER; const deployerAddress = new hre.ethers.Wallet(privKeyDeployer!).address; - const ownerAddress = new hre.ethers.Wallet(privKeyOwner!).address; - const relayerAddress = new hre.ethers.Wallet(privKeyRelayer!).address; + let relayerAddress; + if (!taskArgs.useAddress) { + const privKeyRelayer = process.env.PRIVATE_KEY_GATEWAY_RELAYER; + relayerAddress = new hre.ethers.Wallet(privKeyRelayer!).address; + } else { + relayerAddress = process.env.ADDRESS_GATEWAY_RELAYER; + } if (!taskArgs.skipGetCoin) { if (hre.network.name === "hardhat") { const bal = "0x1000000000000000000000000000000000000000"; const p1 = hre.network.provider.send("hardhat_setBalance", [deployerAddress, bal]); - const p2 = hre.network.provider.send("hardhat_setBalance", [ownerAddress, bal]); - const p3 = hre.network.provider.send("hardhat_setBalance", [relayerAddress, bal]); - await Promise.all([p1, p2, p3]); + const p2 = hre.network.provider.send("hardhat_setBalance", [relayerAddress, bal]); + await Promise.all([p1, p2]); } else { const p1 = getCoin(deployerAddress); - const p2 = getCoin(ownerAddress); - const p3 = getCoin(relayerAddress); - await Promise.all([p1, p2, p3]); + const p2 = getCoin(relayerAddress); + await Promise.all([p1, p2]); await new Promise((res) => setTimeout(res, 5000)); // wait 5 seconds } } - console.log(`privateKey ${privKeyDeployer}`); - console.log(`ownerAddress ${ownerAddress}`); - await hre.run("task:deployGateway", { privateKey: privKeyDeployer, ownerAddress: ownerAddress }); + await hre.run("task:deployGateway", { privateKey: privKeyDeployer, ownerAddress: deployerAddress }); const parsedEnv = dotenv.parse(fs.readFileSync("node_modules/fhevm/gateway/.env.gateway")); const gatewayContractAddress = parsedEnv.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS; await hre.run("task:addRelayer", { - privateKey: privKeyOwner, + privateKey: privKeyDeployer, gatewayAddress: gatewayContractAddress, relayerAddress: relayerAddress, }); @@ -138,12 +130,37 @@ task("task:launchFhevm") task("task:getBalances").setAction(async function (taskArgs, hre) { const privKeyDeployer = process.env.PRIVATE_KEY_GATEWAY_DEPLOYER; - const privKeyOwner = process.env.PRIVATE_KEY_GATEWAY_OWNER; const privKeyRelayer = process.env.PRIVATE_KEY_GATEWAY_RELAYER; const deployerAddress = new hre.ethers.Wallet(privKeyDeployer!).address; - const ownerAddress = new hre.ethers.Wallet(privKeyOwner!).address; const relayerAddress = new hre.ethers.Wallet(privKeyRelayer!).address; console.log(await hre.ethers.provider.getBalance(deployerAddress)); - console.log(await hre.ethers.provider.getBalance(ownerAddress)); console.log(await hre.ethers.provider.getBalance(relayerAddress)); }); + +task("task:faucetToPrivate") + .addParam("privateKey", "The receiver private key") + .setAction(async function (taskArgs, hre) { + const receiverAddress = new hre.ethers.Wallet(taskArgs.privateKey).address; + + if (hre.network.name === "hardhat") { + const bal = "0x1000000000000000000000000000000000000000"; + await hre.network.provider.send("hardhat_setBalance", [receiverAddress, bal]); + } else { + await getCoin(receiverAddress); + await new Promise((res) => setTimeout(res, 5000)); // wait 5 seconds + } + }); + +task("task:faucetToAddress") + .addParam("address", "The receiver address") + .setAction(async function (taskArgs, hre) { + const receiverAddress = taskArgs.address; + + if (hre.network.name === "hardhat") { + const bal = "0x1000000000000000000000000000000000000000"; + await hre.network.provider.send("hardhat_setBalance", [receiverAddress, bal]); + } else { + await getCoin(receiverAddress); + await new Promise((res) => setTimeout(res, 5000)); // wait 5 seconds + } + }); \ No newline at end of file diff --git a/tasks/taskOracleRelayer.ts b/tasks/taskOracleRelayer.ts deleted file mode 100644 index f4ac15f..0000000 --- a/tasks/taskOracleRelayer.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { exec as oldExec } from "child_process"; -import dotenv from "dotenv"; -import fs from "fs"; -import { task } from "hardhat/config"; -import type { TaskArguments } from "hardhat/types"; -import path from "path"; -import { promisify } from "util"; - -const exec = promisify(oldExec); - -task("task:deployOracle") - .addParam("privateKey", "The deployer private key") - .addParam("ownerAddress", "The owner address") - .setAction(async function (taskArguments: TaskArguments, { ethers }) { - const deployer = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); - const oracleFactory = await ethers.getContractFactory("OraclePredeploy"); - const oracle = await oracleFactory.connect(deployer).deploy(taskArguments.ownerAddress); - await oracle.waitForDeployment(); - const oraclePredeployAddress = await oracle.getAddress(); - const envConfig = dotenv.parse(fs.readFileSync("node_modules/fhevm/oracle/.env.oracle")); - if (oraclePredeployAddress !== envConfig.ORACLE_CONTRACT_PREDEPLOY_ADDRESS) { - throw new Error( - `The nonce of the deployer account is not null. Please use another deployer private key or relaunch a clean instance of the fhEVM`, - ); - } - console.log("OraclePredeploy was deployed at address: ", oraclePredeployAddress); - }); - -const getCoin = async (address: string) => { - const containerName = process.env["TEST_CONTAINER_NAME"] || "fhevm"; - const response = await exec(`docker exec -i ${containerName} faucet ${address} | grep height`); - const res = JSON.parse(response.stdout); - if (res.raw_log.match("account sequence mismatch")) await getCoin(address); -}; - -task("task:computePredeployAddress") - .addParam("privateKey", "The deployer private key") - .setAction(async function (taskArguments: TaskArguments, { ethers }) { - const deployerAddress = new ethers.Wallet(taskArguments.privateKey).address; - const oraclePredeployAddressPrecomputed = ethers.getCreateAddress({ - from: deployerAddress, - nonce: 0, // deployer is supposed to have nonce 0 when deploying OraclePredeploy - }); - const envFilePath = path.join(__dirname, "../node_modules/fhevm/oracle/.env.oracle"); - const content = `ORACLE_CONTRACT_PREDEPLOY_ADDRESS=${oraclePredeployAddressPrecomputed}\n`; - try { - fs.writeFileSync(envFilePath, content, { flag: "w" }); - console.log("oraclePredeployAddress written to node_modules/fhevm/oracle/.env.oracle successfully!"); - } catch (err) { - console.error("Failed to write to node_modules/fhevm/oracle/.env.oracle:", err); - } - - const solidityTemplate = `// SPDX-License-Identifier: BSD-3-Clause-Clear - -pragma solidity ^0.8.24; - -address constant ORACLE_CONTRACT_PREDEPLOY_ADDRESS = ${oraclePredeployAddressPrecomputed}; - `; - - try { - fs.writeFileSync("./node_modules/fhevm/oracle/lib/PredeployAddress.sol", solidityTemplate, { - encoding: "utf8", - flag: "w", - }); - console.log("node_modules/fhevm/oracle/lib/PredeployAddress.sol file has been generated successfully."); - } catch (error) { - console.error("Failed to write node_modules/fhevm/oracle/lib/PredeployAddress.sol", error); - } - }); - -task("task:addRelayer") - .addParam("privateKey", "The owner private key") - .addParam("oracleAddress", "The OraclePredeploy address") - .addParam("relayerAddress", "The relayer address") - .setAction(async function (taskArguments: TaskArguments, { ethers }) { - const codeAtAddress = await ethers.provider.getCode(taskArguments.oracleAddress); - if (codeAtAddress === "0x") { - throw Error(`${taskArguments.oracleAddress} is not a smart contract`); - } - const owner = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); - const oracle = await ethers.getContractAt("OraclePredeploy", taskArguments.oracleAddress, owner); - const tx = await oracle.addRelayer(taskArguments.relayerAddress); - const rcpt = await tx.wait(); - if (rcpt!.status === 1) { - console.log(`Account ${taskArguments.relayerAddress} was succesfully added as an oracle relayer`); - } else { - console.log("Adding relayer failed"); - } - }); - -task("task:removeRelayer") - .addParam("privateKey", "The owner private key") - .addParam("oracleAddress", "The OraclePredeploy address") - .addParam("relayerAddress", "The relayer address") - .setAction(async function (taskArguments: TaskArguments, { ethers }) { - const codeAtAddress = await ethers.provider.getCode(taskArguments.oracleAddress); - if (codeAtAddress === "0x") { - throw Error(`${taskArguments.oracleAddress} is not a smart contract`); - } - const owner = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); - const oracle = await ethers.getContractAt("OraclePredeploy", taskArguments.oracleAddress, owner); - const tx = await oracle.removeRelayer(taskArguments.relayerAddress); - const rcpt = await tx.wait(); - if (rcpt!.status === 1) { - console.log(`Account ${taskArguments.relayerAddress} was succesfully removed from authorized relayers`); - } else { - console.log("Removing relayer failed"); - } - }); - -task("task:launchFhevm").setAction(async function (taskArgs, hre) { - const privKeyDeployer = process.env.PRIVATE_KEY_ORACLE_DEPLOYER; - const privKeyOwner = process.env.PRIVATE_KEY_ORACLE_OWNER; - const privKeyRelayer = process.env.PRIVATE_KEY_ORACLE_RELAYER; - const deployerAddress = new hre.ethers.Wallet(privKeyDeployer!).address; - const ownerAddress = new hre.ethers.Wallet(privKeyOwner!).address; - const relayerAddress = new hre.ethers.Wallet(privKeyRelayer!).address; - const p1 = getCoin(deployerAddress); - const p2 = getCoin(ownerAddress); - const p3 = getCoin(relayerAddress); - await Promise.all([p1, p2, p3]); - await new Promise((res) => setTimeout(res, 5000)); // wait 5 seconds - await hre.run("task:deployOracle", { privateKey: privKeyDeployer, ownerAddress: ownerAddress }); - - const parsedEnv = dotenv.parse(fs.readFileSync("node_modules/fhevm/oracle/.env.oracle")); - const oraclePredeployAddress = parsedEnv.ORACLE_CONTRACT_PREDEPLOY_ADDRESS; - - await hre.run("task:addRelayer", { - privateKey: privKeyOwner, - oracleAddress: oraclePredeployAddress, - relayerAddress: relayerAddress, - }); -}); - -task("task:getBalances").setAction(async function (taskArgs, hre) { - const privKeyDeployer = process.env.PRIVATE_KEY_ORACLE_DEPLOYER; - const privKeyOwner = process.env.PRIVATE_KEY_ORACLE_OWNER; - const privKeyRelayer = process.env.PRIVATE_KEY_ORACLE_RELAYER; - const deployerAddress = new hre.ethers.Wallet(privKeyDeployer!).address; - const ownerAddress = new hre.ethers.Wallet(privKeyOwner!).address; - const relayerAddress = new hre.ethers.Wallet(privKeyRelayer!).address; - console.log(await hre.ethers.provider.getBalance(deployerAddress)); - console.log(await hre.ethers.provider.getBalance(ownerAddress)); - console.log(await hre.ethers.provider.getBalance(relayerAddress)); -}); diff --git a/tasks/taskTFHE.ts b/tasks/taskTFHE.ts index 15ee0ef..1ddc6c7 100644 --- a/tasks/taskTFHE.ts +++ b/tasks/taskTFHE.ts @@ -1,97 +1,214 @@ import fs from "fs"; -import { task } from "hardhat/config"; +import { task, types } from "hardhat/config"; import type { TaskArguments } from "hardhat/types"; import path from "path"; -task("task:computeACLAddress").setAction(async function (taskArguments: TaskArguments, { ethers }) { - const deployer = (await ethers.getSigners())[9].address; - const aclAddress = ethers.getCreateAddress({ - from: deployer, - nonce: 0, // using nonce of 0 for the ACL contract - }); - const envFilePath = path.join(__dirname, "../node_modules/fhevm/lib/.env.acl"); - const content = `ACL_CONTRACT_ADDRESS=${aclAddress}\n`; - try { - fs.writeFileSync(envFilePath, content, { flag: "w" }); - console.log(`ACL address ${aclAddress} written successfully!`); - } catch (err) { - console.error("Failed to write ACL address:", err); - } +task("task:computeACLAddress") + .addParam("privateKey", "The deployer private key") + .setAction(async function (taskArguments: TaskArguments, { ethers }) { + const deployer = new ethers.Wallet(taskArguments.privateKey).address; + const aclAddress = ethers.getCreateAddress({ + from: deployer, + nonce: 1, // using nonce of 1 for the ACL contract (0 for original implementation, +1 for proxy) + }); + const envFilePath = path.join(__dirname, "../node_modules/fhevm-core-contracts/addresses/.env.acl"); + const content = `ACL_CONTRACT_ADDRESS=${aclAddress}\n`; + try { + fs.writeFileSync(envFilePath, content, { flag: "w" }); + console.log(`ACL address ${aclAddress} written successfully!`); + } catch (err) { + console.error("Failed to write ACL address:", err); + } - const solidityTemplate = `// SPDX-License-Identifier: BSD-3-Clause-Clear + const solidityTemplate = `// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity ^0.8.24; address constant aclAdd = ${aclAddress};\n`; - try { - fs.writeFileSync("node_modules/fhevm/lib/ACLAddress.sol", solidityTemplate, { encoding: "utf8", flag: "w" }); - console.log("node_modules/fhevm/lib/ACLAddress.sol file generated successfully!"); - } catch (error) { - console.error("Failed to write node_modules/fhevm/lib/ACLAddress.sol", error); - } -}); - -task("task:computeTFHEExecutorAddress").setAction(async function (taskArguments: TaskArguments, { ethers }) { - const deployer = (await ethers.getSigners())[9].address; - const execAddress = ethers.getCreateAddress({ - from: deployer, - nonce: 1, // using nonce of 1 for the TFHEExecutor contract + try { + fs.writeFileSync("./node_modules/fhevm-core-contracts/addresses/ACLAddress.sol", solidityTemplate, { + encoding: "utf8", + flag: "w", + }); + console.log("./node_modules/fhevm-core-contracts/addresses/ACLAddress.sol file generated successfully!"); + } catch (error) { + console.error("Failed to write ./node_modules/fhevm-core-contracts/addresses/ACLAddress.sol", error); + } }); - const envFilePath = path.join(__dirname, "../node_modules/fhevm/lib/.env.exec"); - const content = `TFHE_EXECUTOR_CONTRACT_ADDRESS=${execAddress}\n`; - try { - fs.writeFileSync(envFilePath, content, { flag: "w" }); - console.log(`TFHE Executor address ${execAddress} written successfully!`); - } catch (err) { - console.error("Failed to write TFHE Executor address:", err); - } - const solidityTemplateCoprocessor = `// SPDX-License-Identifier: BSD-3-Clause-Clear +task("task:computeTFHEExecutorAddress") + .addParam("privateKey", "The deployer private key") + .setAction(async function (taskArguments: TaskArguments, { ethers }) { + const deployer = new ethers.Wallet(taskArguments.privateKey).address; + const execAddress = ethers.getCreateAddress({ + from: deployer, + nonce: 3, // using nonce of 3 for the TFHEExecutor contract (2 for original implementation, +1 for proxy) + }); + const envFilePath = path.join(__dirname, "../node_modules/fhevm-core-contracts/addresses/.env.exec"); + const content = `TFHE_EXECUTOR_CONTRACT_ADDRESS=${execAddress}\n`; + try { + fs.writeFileSync(envFilePath, content, { flag: "w" }); + console.log(`TFHEExecutor address ${execAddress} written successfully!`); + } catch (err) { + console.error("Failed to write TFHEExecutor address:", err); + } + + const solidityTemplateCoprocessor = `// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity ^0.8.24; -address constant fhevmCoprocessorAdd = ${execAddress};\n`; +address constant tfheExecutorAdd = ${execAddress};\n`; - try { - fs.writeFileSync("node_modules/fhevm/lib/FHEVMCoprocessorAddress.sol", solidityTemplateCoprocessor, { - encoding: "utf8", - flag: "w", + try { + fs.writeFileSync( + "./node_modules/fhevm-core-contracts/addresses/TFHEExecutorAddress.sol", + solidityTemplateCoprocessor, + { encoding: "utf8", flag: "w" }, + ); + console.log("./node_modules/fhevm-core-contracts/addresses/TFHEExecutorAddress.sol file generated successfully!"); + } catch (error) { + console.error("Failed to write ./node_modules/fhevm-core-contracts/addresses/TFHEExecutorAddress.sol", error); + } + }); + +task("task:computeKMSVerifierAddress") + .addParam("privateKey", "The deployer private key") + .setAction(async function (taskArguments: TaskArguments, { ethers }) { + const deployer = new ethers.Wallet(taskArguments.privateKey).address; + const kmsVerfierAddress = ethers.getCreateAddress({ + from: deployer, + nonce: 5, // using nonce of 5 for the KMSVerifier contract (4 for original implementation, +1 for proxy) }); - console.log("node_modules/fhevm/lib/FHEVMCoprocessorAddress.sol file generated successfully!"); - } catch (error) { - console.error("Failed to write node_modules/fhevm/lib/FHEVMCoprocessorAddress.sol", error); - } -}); - -task("task:computeKMSVerifierAddress").setAction(async function (taskArguments: TaskArguments, { ethers }) { - const deployer = (await ethers.getSigners())[9].address; - const kmsVerifierAddress = ethers.getCreateAddress({ - from: deployer, - nonce: 2, // using nonce of 2 for the Kms Verifier contract + const envFilePath = path.join(__dirname, "../node_modules/fhevm-core-contracts/addresses/.env.kmsverifier"); + const content = `KMS_VERIFIER_CONTRACT_ADDRESS=${kmsVerfierAddress}\n`; + try { + fs.writeFileSync(envFilePath, content, { flag: "w" }); + console.log(`KMSVerifier address ${kmsVerfierAddress} written successfully!`); + } catch (err) { + console.error("Failed to write KMSVerifier address:", err); + } + + const solidityTemplate = `// SPDX-License-Identifier: BSD-3-Clause-Clear + +pragma solidity ^0.8.24; + +address constant kmsVerifierAdd = ${kmsVerfierAddress};\n`; + + try { + fs.writeFileSync("./node_modules/fhevm-core-contracts/addresses/KMSVerifierAddress.sol", solidityTemplate, { + encoding: "utf8", + flag: "w", + }); + console.log("./node_modules/fhevm-core-contracts/addresses/KMSVerifierAddress.sol file generated successfully!"); + } catch (error) { + console.error("Failed to write ./node_modules/fhevm-core-contracts/addresses/KMSVerifierAddress.sol", error); + } }); - const envFilePath = path.join(__dirname, "../node_modules/fhevm/lib/.env.kmsverifier"); - const content = `KMS_VERIFIER_CONTRACT_ADDRESS=${kmsVerifierAddress}\n`; - try { - fs.writeFileSync(envFilePath, content, { flag: "w" }); - console.log(`KMS Verifier address ${kmsVerifierAddress} written successfully!`); - } catch (err) { - console.error("Failed to write KMS Verifier address:", err); - } - const solidityTemplate = `// SPDX-License-Identifier: BSD-3-Clause-Clear +task("task:computeInputVerifierAddress") + .addParam("privateKey", "The deployer private key") + .addOptionalParam( + "useAddress", + "Use addresses instead of private key env variable for coprocessor", + false, + types.boolean, + ) + .setAction(async function (taskArguments: TaskArguments, { ethers }) { + // this script also compute the coprocessor address from its private key + const deployer = new ethers.Wallet(taskArguments.privateKey).address; + const inputVerfierAddress = ethers.getCreateAddress({ + from: deployer, + nonce: 7, // using nonce of 7 for the InputVerifier contract (6 for original implementation, +1 for proxy) + }); + const envFilePath = path.join(__dirname, "../node_modules/fhevm-core-contracts/addresses/.env.inputverifier"); + const content = `INPUT_VERIFIER_CONTRACT_ADDRESS=${inputVerfierAddress}\n`; + try { + fs.writeFileSync(envFilePath, content, { flag: "w" }); + console.log(`InputVerifier address ${inputVerfierAddress} written successfully!`); + } catch (err) { + console.error("Failed to write InputVerifier address:", err); + } + + const solidityTemplate = `// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity ^0.8.24; -address constant KMS_VERIFIER_CONTRACT_ADDRESS = ${kmsVerifierAddress};\n`; +address constant inputVerifierAdd = ${inputVerfierAddress};\n`; - try { - fs.writeFileSync("node_modules/fhevm/lib/KMSVerifierAddress.sol", solidityTemplate, { - encoding: "utf8", - flag: "w", + try { + fs.writeFileSync("./node_modules/fhevm-core-contracts/addresses/InputVerifierAddress.sol", solidityTemplate, { + encoding: "utf8", + flag: "w", + }); + console.log( + "./node_modules/fhevm-core-contracts/addresses/InputVerifierAddress.sol file generated successfully!", + ); + } catch (error) { + console.error("Failed to write ./node_modules/fhevm-core-contracts/addresses/InputVerifierAddress.sol", error); + } + let coprocAddress; + if (!taskArguments.useAddress) { + coprocAddress = new ethers.Wallet(process.env.PRIVATE_KEY_COPROCESSOR_ACCOUNT!).address; + } else { + coprocAddress = process.env.ADDRESS_COPROCESSOR_ACCOUNT; + } + const envFilePath2 = path.join(__dirname, "../node_modules/fhevm-core-contracts/addresses/.env.coprocessor"); + const content2 = `COPROCESSOR_ADDRESS=${coprocAddress}\n`; + try { + fs.writeFileSync(envFilePath2, content2, { flag: "w" }); + console.log(`Coprocessor address ${coprocAddress} written successfully!`); + } catch (err) { + console.error("Failed to write InputVerifier address:", err); + } + + const solidityTemplate2 = `// SPDX-License-Identifier: BSD-3-Clause-Clear + +pragma solidity ^0.8.24; + +address constant coprocessorAdd = ${coprocAddress};\n`; + + try { + fs.writeFileSync("./node_modules/fhevm-core-contracts/addresses/CoprocessorAddress.sol", solidityTemplate2, { + encoding: "utf8", + flag: "w", + }); + console.log("./node_modules/fhevm-core-contracts/addresses/CoprocessorAddress.sol file generated successfully!"); + } catch (error) { + console.error("Failed to write ./node_modules/fhevm-core-contracts/addresses/CoprocessorAddress.sol", error); + } + }); + +task("task:computeFHEPaymentAddress") + .addParam("privateKey", "The deployer private key") + .setAction(async function (taskArguments: TaskArguments, { ethers }) { + const deployer = new ethers.Wallet(taskArguments.privateKey).address; + const fhePaymentAddress = ethers.getCreateAddress({ + from: deployer, + nonce: 9, // using nonce of 9 for the FHEPayment contract (8 for original implementation, +1 for proxy) }); - console.log("node_modules/fhevm/lib/KMSVerifierAddress.sol file generated successfully!"); - } catch (error) { - console.error("Failed to write node_modules/fhevm/lib/KMSVerifierAddress.sol", error); - } -}); + const envFilePath = path.join(__dirname, "../node_modules/fhevm-core-contracts/addresses/.env.fhepayment"); + const content = `FHE_PAYMENT_CONTRACT_ADDRESS=${fhePaymentAddress}\n`; + try { + fs.writeFileSync(envFilePath, content, { flag: "w" }); + console.log(`FHEPayment address ${fhePaymentAddress} written successfully!`); + } catch (err) { + console.error("Failed to write FHEPayment address:", err); + } + + const solidityTemplate = `// SPDX-License-Identifier: BSD-3-Clause-Clear + +pragma solidity ^0.8.24; + +address constant fhePaymentAdd = ${fhePaymentAddress};\n`; + + try { + fs.writeFileSync("./node_modules/fhevm-core-contracts/addresses/FHEPaymentAddress.sol", solidityTemplate, { + encoding: "utf8", + flag: "w", + }); + console.log("./node_modules/fhevm-core-contracts/addresses/FHEPaymentAddress.sol file generated successfully!"); + } catch (error) { + console.error("Failed to write ./node_modules/fhevm-core-contracts/addresses/FHEPaymentAddress.sol", error); + } + }); \ No newline at end of file diff --git a/test/coprocessorUtils.ts b/test/coprocessorUtils.ts index 12bab6b..d082313 100644 --- a/test/coprocessorUtils.ts +++ b/test/coprocessorUtils.ts @@ -5,32 +5,20 @@ import { ethers } from "hardhat"; import hre from "hardhat"; import { Database } from "sqlite3"; -const parsedEnvCoprocessor = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.exec")); -const coprocAdd = parsedEnvCoprocessor.TFHE_EXECUTOR_CONTRACT_ADDRESS.replace(/^0x/, "") - .replace(/^0+/, "") - .toLowerCase(); +import operatorsPrices from "./operatorsPrices.json"; + +const parsedEnvCoprocessor = dotenv.parse(fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.exec")); +const coprocAddress = parsedEnvCoprocessor.TFHE_EXECUTOR_CONTRACT_ADDRESS; let firstBlockListening = 0; let lastBlockSnapshot = 0; let lastCounterRand = 0; let counterRand = 0; -const contractABI = JSON.parse(fs.readFileSync("abi/TFHEExecutor.json").toString()).abi; - -const iface = new ethers.Interface(contractABI); - -const functions = iface.fragments.filter((fragment) => fragment.type === "function"); - -const selectors = functions.reduce((acc, func) => { - const signature = `${func.name}(${func.inputs.map((input) => input.type).join(",")})`; - acc[func.selector] = signature; - return acc; -}, {}); - //const db = new Database('./sql.db'); // on-disk db for debugging const db = new Database(":memory:"); -function insertSQL(handle: string, clearText: bigint, replace: boolean = false) { +export function insertSQL(handle: string, clearText: BigInt, replace: boolean = false) { if (replace) { // this is useful if using snapshots while sampling different random numbers on each revert db.run("INSERT OR REPLACE INTO ciphertexts (handle, clearText) VALUES (?, ?)", [handle, clearText.toString()]); @@ -41,12 +29,12 @@ function insertSQL(handle: string, clearText: bigint, replace: boolean = false) // Decrypt any handle, bypassing ACL // WARNING : only for testing or internal use -export const getClearText = async (handle: bigint): Promise => { +export const getClearText = async (handle: BigInt): Promise => { const handleStr = "0x" + handle.toString(16).padStart(64, "0"); return new Promise((resolve, reject) => { let attempts = 0; - const maxRetries = 10; + const maxRetries = 100; function executeQuery() { db.get("SELECT clearText FROM ciphertexts WHERE handle = ?", [handleStr], (err, row) => { @@ -69,70 +57,11 @@ export const getClearText = async (handle: bigint): Promise => { db.serialize(() => db.run("CREATE TABLE IF NOT EXISTS ciphertexts (handle BINARY PRIMARY KEY,clearText TEXT)")); -enum Operators { - fheAdd = 0, - fheSub, - fheMul, - fheDiv, - fheRem, - fheBitAnd, - fheBitOr, - fheBitXor, - fheShl, - fheShr, - fheRotl, - fheRotr, - fheEq, - fheNe, - fheGe, - fheGt, - fheLe, - fheLt, - fheMin, - fheMax, - fheNeg, - fheNot, - verifyCiphertext, - cast, - trivialEncrypt, - fheIfThenElse, - fheRand, - fheRandBounded, +interface FHEVMEvent { + eventName: string; + args: object; } -interface EvmState { - stack: string[]; - memory: string[]; -} - -function extractCalldata(memory: string[], offset: number, size: number): string { - const startIndex = Math.floor(offset / 32); - const endIndex = Math.ceil((offset + size) / 32); - const memorySegments = memory.slice(startIndex, endIndex); - let calldata = ""; - for (let i = 0; i < memorySegments.length; i++) { - calldata += memorySegments[i]; - } - const calldataStart = (offset % 32) * 2; - const calldataEnd = calldataStart + size * 2; - return calldata.slice(calldataStart, calldataEnd); -} - -const TypesBytesSize = { - 0: 1, //ebool - 1: 1, //euint4 - 2: 1, //euint8 - 3: 2, //euint16 - 4: 4, //euint32 - 5: 8, //euint64 - 6: 16, //euint128 - 7: 20, //eaddress - 8: 32, //euint256 - 9: 64, //ebytes64 - 10: 128, //ebytes128 - 11: 256, //ebytes256 -}; - const NumBits = { 0: 1n, //ebool 1: 4n, //euint4 @@ -148,8 +77,6 @@ const NumBits = { 11: 2048n, //ebytes256 }; -const HANDLE_VERSION = 0; - export function numberToEvenHexString(num: number) { if (typeof num !== "number" || num < 0) { throw new Error("Input should be a non-negative number."); @@ -161,10 +88,6 @@ export function numberToEvenHexString(num: number) { return hexString; } -function appendType(handle: string, type: number): string { - return handle.slice(0, -4) + numberToEvenHexString(type) + numberToEvenHexString(HANDLE_VERSION); -} - function getRandomBigInt(numBits: number): bigint { if (numBits <= 0) { throw new Error("Number of bits must be greater than 0"); @@ -181,713 +104,800 @@ function getRandomBigInt(numBits: number): bigint { return randomBigInt; } -async function insertHandle(obj2: EvmState, validIdxes: [number]) { - const obj = obj2.value; - if (isCoprocAdd(obj!.stack.at(-2))) { - const argsOffset = Number(`0x${obj!.stack.at(-4)}`); - const argsSize = Number(`0x${obj!.stack.at(-5)}`); - const calldata = extractCalldata(obj.memory, argsOffset, argsSize); - const currentSelector = "0x" + calldata.slice(0, 8); - const decodedData = iface.decodeFunctionData(currentSelector, "0x" + calldata); +function bitwiseNotUintBits(value: BigInt, numBits: number) { + if (typeof value !== "bigint") { + throw new TypeError("The input value must be a BigInt."); + } + if (typeof numBits !== "number" || numBits <= 0) { + throw new TypeError("The numBits parameter must be a positive integer."); + } + // Create the mask with numBits bits set to 1 + const BIT_MASK = (BigInt(1) << BigInt(numBits)) - BigInt(1); + return ~value & BIT_MASK; +} + +export const awaitCoprocessor = async (): Promise => { + await processAllPastTFHEExecutorEvents(); +}; + +const abi = [ + "event FheAdd(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheSub(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheMul(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheDiv(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheRem(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheBitAnd(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheBitOr(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheBitXor(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheShl(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheShr(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheRotl(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheRotr(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheEq(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheEqBytes(uint256 lhs, bytes rhs, bytes1 scalarByte, uint256 result)", + "event FheNe(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheNeBytes(uint256 lhs, bytes rhs, bytes1 scalarByte, uint256 result)", + "event FheGe(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheGt(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheLe(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheLt(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheMin(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheMax(uint256 lhs, uint256 rhs, bytes1 scalarByte, uint256 result)", + "event FheNeg(uint256 ct, uint256 result)", + "event FheNot(uint256 ct, uint256 result)", + "event VerifyCiphertext(bytes32 inputHandle,address userAddress,bytes inputProof,bytes1 inputType,uint256 result)", + "event Cast(uint256 ct, bytes1 toType, uint256 result)", + "event TrivialEncrypt(uint256 pt, bytes1 toType, uint256 result)", + "event TrivialEncryptBytes(bytes pt, bytes1 toType, uint256 result)", + "event FheIfThenElse(uint256 control, uint256 ifTrue, uint256 ifFalse, uint256 result)", + "event FheRand(bytes1 randType, uint256 result)", + "event FheRandBounded(uint256 upperBound, bytes1 randType, uint256 result)", +]; + +async function processAllPastTFHEExecutorEvents() { + const provider = ethers.provider; + const latestBlockNumber = await provider.getBlockNumber(); + + if (hre.__SOLIDITY_COVERAGE_RUNNING !== true) { + // evm_snapshot is not supported in coverage mode + [lastBlockSnapshot, lastCounterRand] = await provider.send("get_lastBlockSnapshot"); + if (lastBlockSnapshot < firstBlockListening) { + firstBlockListening = lastBlockSnapshot + 1; + counterRand = Number(lastCounterRand); + } + } + + const contract = new ethers.Contract(coprocAddress, abi, provider); + + // Fetch all events emitted by the contract + const filter = { + address: coprocAddress, + fromBlock: firstBlockListening, + toBlock: latestBlockNumber, + }; + + const logs = await provider.getLogs(filter); + + const events = logs + .map((log) => { + try { + const parsedLog = contract.interface.parseLog(log); + return { + eventName: parsedLog.name, + args: parsedLog.args, + }; + } catch (e) { + // If the log cannot be parsed, skip it + return null; + } + }) + .filter((event) => event !== null); + + firstBlockListening = latestBlockNumber + 1; + if (hre.__SOLIDITY_COVERAGE_RUNNING !== true) { + // evm_snapshot is not supported in coverage mode + await provider.send("set_lastBlockSnapshot", [firstBlockListening]); + } + events.map(async (event) => await insertHandleFromEvent(event)); +} + +async function insertHandleFromEvent(event: FHEVMEvent) { + let handle; + let clearText; + let clearLHS; + let clearRHS; + let resultType; + let shift; + + switch (event.eventName) { + case "TrivialEncrypt": + clearText = event.args[0]; + handle = ethers.toBeHex(event.args[2], 32); + insertSQL(handle, clearText); + break; + + case "TrivialEncryptBytes": + clearText = event.args[0]; + handle = ethers.toBeHex(event.args[2], 32); + insertSQL(handle, clearText); + break; + + case "FheAdd": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) + event.args[1]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) + BigInt(clearRHS); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(ethers.toBeHex(handle, 32), clearText); + break; + + case "FheSub": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) - event.args[1]; + if (clearText < 0n) clearText = clearText + 2n ** NumBits[resultType]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) - BigInt(clearRHS); + if (clearText < 0n) clearText = clearText + 2n ** NumBits[resultType]; + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "FheMul": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) * event.args[1]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) * BigInt(clearRHS); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "FheDiv": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) / event.args[1]; + } else { + throw new Error("Non-scalar div not implemented yet"); + } + insertSQL(handle, clearText); + break; + + case "FheRem": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) % event.args[1]; + } else { + throw new Error("Non-scalar rem not implemented yet"); + } + insertSQL(handle, clearText); + break; + + case "FheBitAnd": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) & event.args[1]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) & BigInt(clearRHS); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "FheBitOr": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) | event.args[1]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) | BigInt(clearRHS); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "FheBitXor": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) ^ event.args[1]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) ^ BigInt(clearRHS); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "FheShl": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) << event.args[1] % NumBits[resultType]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) << BigInt(clearRHS) % NumBits[resultType]; + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "FheShr": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) >> event.args[1] % NumBits[resultType]; + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) >> BigInt(clearRHS) % NumBits[resultType]; + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "FheRotl": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + shift = event.args[1] % NumBits[resultType]; + clearText = (BigInt(clearLHS) << shift) | (BigInt(clearLHS) >> (NumBits[resultType] - shift)); + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(event.args[1]); + shift = BigInt(clearRHS) % NumBits[resultType]; + clearText = (BigInt(clearLHS) << shift) | (BigInt(clearLHS) >> (NumBits[resultType] - shift)); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "FheRotr": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + shift = event.args[1] % NumBits[resultType]; + clearText = (BigInt(clearLHS) >> shift) | (BigInt(clearLHS) << (NumBits[resultType] - shift)); + clearText = clearText % 2n ** NumBits[resultType]; + } else { + clearRHS = await getClearText(event.args[1]); + shift = BigInt(clearRHS) % NumBits[resultType]; + clearText = (BigInt(clearLHS) >> shift) | (BigInt(clearLHS) << (NumBits[resultType] - shift)); + clearText = clearText % 2n ** NumBits[resultType]; + } + insertSQL(handle, clearText); + break; + + case "FheEq": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) === event.args[1] ? 1n : 0n; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) === BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "FheEqBytes": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) === BigInt(event.args[1]) ? 1n : 0n; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) === BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "FheNe": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) !== event.args[1] ? 1n : 0n; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) !== BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "FheNeBytes": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) !== BigInt(event.args[1]) ? 1n : 0n; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) !== BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "FheGe": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) >= event.args[1] ? 1n : 0n; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) >= BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "FheGt": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) > event.args[1] ? 1n : 0n; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) > BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "FheLe": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) <= event.args[1] ? 1n : 0n; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) <= BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "FheLt": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) < event.args[1] ? 1n : 0n; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) < BigInt(clearRHS) ? 1n : 0n; + } + insertSQL(handle, clearText); + break; + + case "FheMax": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) > event.args[1] ? clearLHS : event.args[1]; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) > BigInt(clearRHS) ? clearLHS : clearRHS; + } + insertSQL(handle, clearText); + break; + + case "FheMin": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearLHS = await getClearText(event.args[0]); + if (event.args[2] === "0x01") { + clearText = BigInt(clearLHS) < event.args[1] ? clearLHS : event.args[1]; + } else { + clearRHS = await getClearText(event.args[1]); + clearText = BigInt(clearLHS) < BigInt(clearRHS) ? clearLHS : clearRHS; + } + insertSQL(handle, clearText); + break; + + case "Cast": + resultType = parseInt(event.args[1]); + handle = ethers.toBeHex(event.args[2], 32); + clearText = BigInt(await getClearText(event.args[0])) % 2n ** NumBits[resultType]; + insertSQL(handle, clearText); + break; + + case "FheNot": + handle = ethers.toBeHex(event.args[1], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearText = BigInt(await getClearText(event.args[0])); + clearText = bitwiseNotUintBits(clearText, Number(NumBits[resultType])); + insertSQL(handle, clearText); + break; + + case "FheNeg": + handle = ethers.toBeHex(event.args[1], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + clearText = BigInt(await getClearText(event.args[0])); + clearText = bitwiseNotUintBits(clearText, Number(NumBits[resultType])); + clearText = (clearText + 1n) % 2n ** NumBits[resultType]; + insertSQL(handle, clearText); + break; + + case "VerifyCiphertext": + handle = event.args[0]; + try { + await getClearText(BigInt(handle)); + } catch { + throw Error("User input was not found in DB"); + } + break; + + case "FheIfThenElse": + handle = ethers.toBeHex(event.args[3], 32); + resultType = parseInt(handle.slice(-4, -2), 16); + handle = ethers.toBeHex(event.args[3], 32); + const clearControl = BigInt(await getClearText(event.args[0])); + const clearIfTrue = BigInt(await getClearText(event.args[1])); + const clearIfFalse = BigInt(await getClearText(event.args[2])); + if (clearControl === 1n) { + clearText = clearIfTrue; + } else { + clearText = clearIfFalse; + } + insertSQL(handle, clearText); + break; + + case "FheRand": + resultType = parseInt(event.args[0], 16); + handle = ethers.toBeHex(event.args[1], 32); + clearText = getRandomBigInt(Number(NumBits[resultType])); + insertSQL(handle, clearText, true); + counterRand++; + break; + + case "FheRandBounded": + resultType = parseInt(event.args[1], 16); + handle = ethers.toBeHex(event.args[2], 32); + clearText = getRandomBigInt(Number(log2(BigInt(event.args[0])))); + insertSQL(handle, clearText, true); + counterRand++; + break; + } +} +export function getFHEGasFromTxReceipt(receipt: ethers.TransactionReceipt): number { + if (hre.network.name !== "hardhat") { + throw Error("FHEGas tracking is currently implemented only in mocked mode"); + } + if (receipt.status === 0) { + throw new Error("Transaction reverted"); + } + const contract = new ethers.Contract(coprocAddress, abi, ethers.provider); + const relevantLogs = receipt.logs.filter((log: ethers.Log) => { + if (log.address.toLowerCase() !== coprocAddress.toLowerCase()) { + return false; + } + try { + const parsedLog = contract.interface.parseLog({ + topics: log.topics, + data: log.data, + }); + return abi.some((item) => item.startsWith(`event ${parsedLog.name}`) && parsedLog.name !== "VerifyCiphertext"); + } catch { + return false; + } + }); + const FHELogs = relevantLogs.map((log: ethers.Log) => { + const parsedLog = contract.interface.parseLog({ + topics: log.topics, + data: log.data, + }); + return { + name: parsedLog.name, + args: parsedLog.args, + }; + }); + let FHEGasConsumed = 0; + for (const event of FHELogs) { + let type; let handle; - let clearText; - let clearLHS; - let clearRHS; - let lhsType; - let resultType; - let shift; - - switch (selectors[currentSelector]) { - case "trivialEncrypt(uint256,bytes1)": - resultType = Number(decodedData[1]); - clearText = decodedData[0]; - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "bytes1"], - [Operators.trivialEncrypt, decodedData[0], decodedData[1]], - ), - ); - handle = appendType(handle, resultType); - insertSQL(handle, clearText); + switch (event.name) { + case "TrivialEncrypt": + type = parseInt(event.args[1], 16); + FHEGasConsumed += operatorsPrices["trivialEncrypt"].types[type]; break; - case "fheAdd(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheAdd, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) + decodedData[1]; - clearText = clearText % 2n ** NumBits[resultType]; + case "TrivialEncryptBytes": + type = parseInt(event.args[1], 16); + FHEGasConsumed += operatorsPrices["trivialEncrypt"].types[type]; + break; + + case "FheAdd": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheAdd"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) + BigInt(clearRHS); - clearText = clearText % 2n ** NumBits[resultType]; + FHEGasConsumed += operatorsPrices["fheAdd"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheSub(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheSub, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) - decodedData[1]; - if (clearText < 0n) clearText = clearText + 2n ** NumBits[resultType]; - clearText = clearText % 2n ** NumBits[resultType]; + case "FheSub": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheSub"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) - BigInt(clearRHS); - if (clearText < 0n) clearText = clearText + 2n ** NumBits[resultType]; - clearText = clearText % 2n ** NumBits[resultType]; + FHEGasConsumed += operatorsPrices["fheSub"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheMul(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheMul, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) * decodedData[1]; - clearText = clearText % 2n ** NumBits[resultType]; + case "FheMul": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheMul"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) * BigInt(clearRHS); - clearText = clearText % 2n ** NumBits[resultType]; + FHEGasConsumed += operatorsPrices["fheMul"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheDiv(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheDiv, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) / decodedData[1]; + case "FheDiv": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheDiv"].scalar[type]; } else { throw new Error("Non-scalar div not implemented yet"); } - insertSQL(handle, clearText); break; - case "fheRem(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheRem, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) % decodedData[1]; + case "FheRem": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheRem"].scalar[type]; } else { throw new Error("Non-scalar rem not implemented yet"); } - insertSQL(handle, clearText); break; - case "fheBitAnd(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheBitAnd, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) & decodedData[1]; - clearText = clearText % 2n ** NumBits[resultType]; + case "FheBitAnd": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheBitAnd"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) & BigInt(clearRHS); - clearText = clearText % 2n ** NumBits[resultType]; + FHEGasConsumed += operatorsPrices["fheBitAnd"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheBitOr(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheBitOr, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) | decodedData[1]; - clearText = clearText % 2n ** NumBits[resultType]; + case "FheBitOr": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheBitOr"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) | BigInt(clearRHS); - clearText = clearText % 2n ** NumBits[resultType]; + FHEGasConsumed += operatorsPrices["fheBitOr"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheBitXor(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheBitXor, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) ^ decodedData[1]; - clearText = clearText % 2n ** NumBits[resultType]; + case "FheBitXor": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheBitXor"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) ^ BigInt(clearRHS); - clearText = clearText % 2n ** NumBits[resultType]; + FHEGasConsumed += operatorsPrices["fheBitXor"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheShl(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheShl, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) << decodedData[1] % NumBits[resultType]; - clearText = clearText % 2n ** NumBits[resultType]; + case "FheShl": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheBitShl"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) << BigInt(clearRHS) % NumBits[resultType]; - clearText = clearText % 2n ** NumBits[resultType]; + FHEGasConsumed += operatorsPrices["fheBitShl"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheShr(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheShr, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) >> decodedData[1] % NumBits[resultType]; - clearText = clearText % 2n ** NumBits[resultType]; + case "FheShr": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheBitShr"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) >> BigInt(clearRHS) % NumBits[resultType]; - clearText = clearText % 2n ** NumBits[resultType]; + FHEGasConsumed += operatorsPrices["fheBitShr"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheRotl(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheRotl, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - - if (decodedData[2] === "0x01") { - shift = decodedData[1] % NumBits[resultType]; - clearText = (BigInt(clearLHS) << shift) | (BigInt(clearLHS) >> (NumBits[resultType] - shift)); - clearText = clearText % 2n ** NumBits[resultType]; + case "FheRotl": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheRotl"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - shift = BigInt(clearRHS) % NumBits[resultType]; - clearText = (BigInt(clearLHS) << shift) | (BigInt(clearLHS) >> (NumBits[resultType] - shift)); - clearText = clearText % 2n ** NumBits[resultType]; + FHEGasConsumed += operatorsPrices["fheRotl"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheRotr(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheRotr, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - - if (decodedData[2] === "0x01") { - shift = decodedData[1] % NumBits[resultType]; - clearText = (BigInt(clearLHS) >> shift) | (BigInt(clearLHS) << (NumBits[resultType] - shift)); - clearText = clearText % 2n ** NumBits[resultType]; + case "FheRotr": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheRotr"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - shift = BigInt(clearRHS) % NumBits[resultType]; - clearText = (BigInt(clearLHS) >> shift) | (BigInt(clearLHS) << (NumBits[resultType] - shift)); - clearText = clearText % 2n ** NumBits[resultType]; + FHEGasConsumed += operatorsPrices["fheRotr"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheEq(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheEq, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - handle = appendType(handle, 0); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) === decodedData[1] ? 1n : 0n; + case "FheEq": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheEq"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) === BigInt(clearRHS) ? 1n : 0n; + FHEGasConsumed += operatorsPrices["fheEq"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheNe(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheNe, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - handle = appendType(handle, 0); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) !== decodedData[1] ? 1n : 0n; + case "FheEqBytes": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheEq"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) !== BigInt(clearRHS) ? 1n : 0n; + FHEGasConsumed += operatorsPrices["fheEq"].nonScalar[type]; } - insertSQL(handle, clearText); - break; - case "fheGe(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheGe, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - handle = appendType(handle, 0); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) >= decodedData[1] ? 1n : 0n; + case "FheNe": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheNe"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) >= BigInt(clearRHS) ? 1n : 0n; + FHEGasConsumed += operatorsPrices["fheNe"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheGt(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheGt, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - handle = appendType(handle, 0); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) > decodedData[1] ? 1n : 0n; + case "FheNeBytes": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheNe"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) > BigInt(clearRHS) ? 1n : 0n; + FHEGasConsumed += operatorsPrices["fheNe"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheLe(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheLe, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - handle = appendType(handle, 0); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) <= decodedData[1] ? 1n : 0n; + case "FheGe": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheGe"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) <= BigInt(clearRHS) ? 1n : 0n; + FHEGasConsumed += operatorsPrices["fheGe"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheLt(uint256,uint256,bytes1)": - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheLt, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - handle = appendType(handle, 0); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) < decodedData[1] ? 1n : 0n; + case "FheGt": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheGt"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) < BigInt(clearRHS) ? 1n : 0n; + FHEGasConsumed += operatorsPrices["fheGt"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheMax(uint256,uint256,bytes1)": - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheMax, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) > decodedData[1] ? clearLHS : decodedData[1]; + case "FheLe": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheLe"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) > BigInt(clearRHS) ? clearLHS : clearRHS; + FHEGasConsumed += operatorsPrices["fheLe"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "fheMin(uint256,uint256,bytes1)": - lhsType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - resultType = lhsType; - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "bytes1"], - [Operators.fheMin, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - handle = appendType(handle, resultType); - clearLHS = await getClearText(decodedData[0]); - if (decodedData[2] === "0x01") { - clearText = BigInt(clearLHS) < decodedData[1] ? clearLHS : decodedData[1]; + case "FheLt": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheLt"].scalar[type]; } else { - clearRHS = await getClearText(decodedData[1]); - clearText = BigInt(clearLHS) < BigInt(clearRHS) ? clearLHS : clearRHS; + FHEGasConsumed += operatorsPrices["fheLt"].nonScalar[type]; } - insertSQL(handle, clearText); break; - case "cast(uint256,bytes1)": - resultType = parseInt(decodedData[1]); - handle = ethers.keccak256( - ethers.solidityPacked(["uint8", "uint256", "bytes1"], [Operators.cast, decodedData[0], decodedData[1]]), - ); - clearText = BigInt(await getClearText(decodedData[0])) % 2n ** NumBits[resultType]; - handle = appendType(handle, resultType); - insertSQL(handle, clearText); - break; - - case "fheNot(uint256)": - resultType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - handle = ethers.keccak256(ethers.solidityPacked(["uint8", "uint256"], [Operators.fheNot, decodedData[0]])); - handle = appendType(handle, resultType); - clearText = BigInt(await getClearText(decodedData[0])); - clearText = bitwiseNotUintBits(clearText, Number(NumBits[resultType])); - insertSQL(handle, clearText); - break; - - case "fheNeg(uint256)": - resultType = parseInt(decodedData[0].toString(16).slice(-4, -2), 16); - handle = ethers.keccak256(ethers.solidityPacked(["uint8", "uint256"], [Operators.fheNeg, decodedData[0]])); - handle = appendType(handle, resultType); - clearText = BigInt(await getClearText(decodedData[0])); - clearText = bitwiseNotUintBits(clearText, Number(NumBits[resultType])); - clearText = (clearText + 1n) % 2n ** NumBits[resultType]; - insertSQL(handle, clearText); - break; - - case "verifyCiphertext(bytes32,address,bytes,bytes1)": - { - handle = decodedData[0]; - const type = parseInt(handle.slice(-4, -2), 16); - if (type !== 11) { - //not an ebytes256 - const typeSize = TypesBytesSize[type]; - const idx = parseInt(handle.slice(-6, -4), 16); - const inputProof = decodedData[2].replace(/^0x/, ""); - clearText = BigInt("0x" + inputProof.slice(2 + 2 * 53 * idx, 2 + 2 * typeSize + 2 * 53 * idx)); - insertSQL(handle, clearText); - } else { - const inputProof = decodedData[2].replace(/^0x/, ""); - clearText = BigInt("0x" + inputProof.slice(2, 2 + 2 * 256)); - insertSQL(handle, clearText); - } + case "FheMax": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheMax"].scalar[type]; + } else { + FHEGasConsumed += operatorsPrices["fheMax"].nonScalar[type]; } break; - case "fheIfThenElse(uint256,uint256,uint256)": - { - resultType = parseInt(decodedData[1].toString(16).slice(-4, -2), 16); - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "uint256", "uint256"], - [Operators.fheIfThenElse, decodedData[0], decodedData[1], decodedData[2]], - ), - ); - handle = appendType(handle, resultType); - const clearControl = BigInt(await getClearText(decodedData[0])); - const clearIfTrue = BigInt(await getClearText(decodedData[1])); - const clearIfFalse = BigInt(await getClearText(decodedData[2])); - if (clearControl === 1n) { - clearText = clearIfTrue; - } else { - clearText = clearIfFalse; - } - insertSQL(handle, clearText); + case "FheMin": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + if (event.args[2] === "0x01") { + FHEGasConsumed += operatorsPrices["fheMin"].scalar[type]; + } else { + FHEGasConsumed += operatorsPrices["fheMin"].nonScalar[type]; } break; - case "fheRand(bytes1)": - if (validIdxes.includes(obj2.index)) { - resultType = parseInt(decodedData[0], 16); - handle = ethers.keccak256( - ethers.solidityPacked(["uint8", "bytes1", "uint256"], [Operators.fheRand, decodedData[0], counterRand]), - ); - handle = appendType(handle, resultType); - clearText = getRandomBigInt(Number(NumBits[resultType])); - insertSQL(handle, clearText, true); - counterRand++; - } + case "Cast": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + FHEGasConsumed += operatorsPrices["cast"].types[type]; break; - case "fheRandBounded(uint256,bytes1)": - if (validIdxes.includes(obj2.index)) { - resultType = parseInt(decodedData[1], 16); - handle = ethers.keccak256( - ethers.solidityPacked( - ["uint8", "uint256", "bytes1", "uint256"], - [Operators.fheRandBounded, decodedData[0], decodedData[1], counterRand], - ), - ); - handle = appendType(handle, resultType); - clearText = getRandomBigInt(Number(log2(BigInt(decodedData[0])))); - insertSQL(handle, clearText, true); - counterRand++; - } + case "FheNot": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + FHEGasConsumed += operatorsPrices["fheNot"].types[type]; break; - } - } -} - -function bitwiseNotUintBits(value: bigint, numBits: number) { - if (typeof value !== "bigint") { - throw new TypeError("The input value must be a BigInt."); - } - if (typeof numBits !== "number" || numBits <= 0) { - throw new TypeError("The numBits parameter must be a positive integer."); - } - - // Create the mask with numBits bits set to 1 - const BIT_MASK = (BigInt(1) << BigInt(numBits)) - BigInt(1); - - return ~value & BIT_MASK; -} - -function isCoprocAdd(longString: string): boolean { - const strippedLongString = longString.replace(/^0+/, ""); - const normalizedLongString = strippedLongString.toLowerCase(); - return normalizedLongString === coprocAdd; -} - -async function processLogs(trace, validSubcallsIndexes) { - for (const obj of trace.structLogs - .map((value, index) => ({ value, index })) - .filter((obj) => obj.value.op === "CALL")) { - await insertHandle(obj, validSubcallsIndexes); - } -} - -export const awaitCoprocessor = async (): Promise => { - const pastTxHashes = await getAllPastTransactionHashes(); - for (const txHash of pastTxHashes) { - const trace = await ethers.provider.send("debug_traceTransaction", [txHash[0]]); - - if (!trace.failed) { - const callTree = await buildCallTree(trace, txHash[1]); - const validSubcallsIndexes = getValidSubcallsIds(callTree)[1]; - await processLogs(trace, validSubcallsIndexes); - } - } -}; - -async function getAllPastTransactionHashes() { - const provider = ethers.provider; - const latestBlockNumber = await provider.getBlockNumber(); - const txHashes = []; - if (hre.__SOLIDITY_COVERAGE_RUNNING !== true) { - // evm_snapshot is not supported in coverage mode - [lastBlockSnapshot, lastCounterRand] = await provider.send("get_lastBlockSnapshot"); - if (lastBlockSnapshot < firstBlockListening) { - firstBlockListening = lastBlockSnapshot + 1; - counterRand = Number(lastCounterRand); - } - } - - // Iterate through all blocks and collect transaction hashes - for (let i = firstBlockListening; i <= latestBlockNumber; i++) { - const block = await provider.getBlock(i, true); - block!.transactions.forEach((tx, index) => { - const rcpt = block?.prefetchedTransactions[index]; - txHashes.push([tx, { to: rcpt.to, status: rcpt.status }]); - }); - } - firstBlockListening = latestBlockNumber + 1; - if (hre.__SOLIDITY_COVERAGE_RUNNING !== true) { - // evm_snapshot is not supported in coverage mode - await provider.send("set_lastBlockSnapshot", [firstBlockListening]); - } - return txHashes; -} - -async function buildCallTree(trace, receipt) { - const structLogs = trace.structLogs; - - const callStack = []; - const callTree = { - id: 0, - type: receipt.to ? "TOPCALL" : "TOPCREATE", - revert: receipt.status === 1 ? false : true, - to: receipt.to ? receipt.to : null, - calls: [], - indexTrace: 0, - }; - let currentNode = callTree; - const lenStructLogs = structLogs.length; - let index = 1; - for (const [i, log] of structLogs.entries()) { - if (i < lenStructLogs - 1) { - if (structLogs[i].depth - structLogs[i + 1].depth === 1) { - if (!["RETURN", "SELFDESTRUCT", "STOP", "REVERT", "INVALID"].includes(structLogs[i].op)) { - currentNode.outofgasOrOther = true; - currentNode = callStack.pop(); - } - } - } - - switch (log.op) { - case "CALL": - case "DELEGATECALL": - case "CALLCODE": - case "STATICCALL": - case "CREATE": - case "CREATE2": - if (i < lenStructLogs - 1) { - if (structLogs[i + 1].depth - structLogs[i].depth === 1) { - const newNode = { - id: index, - type: log.op, - to: log.stack[log.stack.length - 2], - calls: [], - revert: true, - outofgasOrOther: false, - indexTrace: i, - }; - currentNode.calls.push(newNode); - callStack.push(currentNode); - currentNode = newNode; - index += 1; - } - } - break; - case "RETURN": // some edge case probably not handled well : if memory expansion cost on RETURN exceeds the remaining gas in current subcall, but it's OK for a mocked mode - case "SELFDESTRUCT": // some edge case probably not handled well : if there is not enough gas remaining on SELFDESTRUCT, but it's OK for a mocked mode - case "STOP": - currentNode.revert = false; - currentNode = callStack.pop(); + case "FheNeg": + handle = ethers.toBeHex(event.args[0], 32); + type = parseInt(handle.slice(-4, -2), 16); + FHEGasConsumed += operatorsPrices["fheNeg"].types[type]; break; - case "REVERT": - case "INVALID": - currentNode = callStack.pop(); - break; - } - switch (log.op) { - case "CREATE": - case "CREATE2": - currentNode.to = null; + case "FheIfThenElse": + handle = ethers.toBeHex(event.args[3], 32); + type = parseInt(handle.slice(-4, -2), 16); + FHEGasConsumed += operatorsPrices["ifThenElse"].types[type]; break; - } - } - return callTree; -} -function getValidSubcallsIds(tree) { - const result = []; - const resultIndexes = []; + case "FheRand": + type = parseInt(event.args[0], 16); + FHEGasConsumed += operatorsPrices["fheRand"].types[type]; + break; - function traverse(node, ancestorReverted) { - if (ancestorReverted || node.revert) { - ancestorReverted = true; - } else { - result.push(node.id); - resultIndexes.push(node.indexTrace); - } - for (const child of node.calls) { - traverse(child, ancestorReverted); + case "FheRandBounded": + type = parseInt(event.args[1], 16); + FHEGasConsumed += operatorsPrices["fheRandBounded"].types[type]; + break; } } - - traverse(tree, false); - - return [result, resultIndexes]; + return FHEGasConsumed; } diff --git a/test/fhevmjsMocked.ts b/test/fhevmjsMocked.ts index 42ee6d2..8a553db 100644 --- a/test/fhevmjsMocked.ts +++ b/test/fhevmjsMocked.ts @@ -1,17 +1,19 @@ -import { toBigIntLE } from "bigint-buffer"; +import { toBigIntBE } from "bigint-buffer"; import { toBufferBE } from "bigint-buffer"; import crypto from "crypto"; import dotenv from "dotenv"; -import { ethers } from "ethers"; +import { Wallet, ethers } from "ethers"; import * as fs from "fs"; -import hre from "hardhat"; import { Keccak } from "sha3"; import { isAddress } from "web3-validator"; +import { insertSQL } from "./coprocessorUtils"; import { awaitCoprocessor, getClearText } from "./coprocessorUtils"; -const parsedEnvACL = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.acl")); -const aclAdd = parsedEnvACL.ACL_CONTRACT_ADDRESS.replace(/^0x/, "").replace(/^0+/, "").toLowerCase(); +const hre = require("hardhat"); + +const parsedEnvACL = dotenv.parse(fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.acl")); +const aclAdd = parsedEnvACL.ACL_CONTRACT_ADDRESS; enum Types { ebool = 0, @@ -28,12 +30,14 @@ enum Types { ebytes256, } +const sum = (arr: number[]) => arr.reduce((acc, val) => acc + val, 0); + function bytesToBigInt(byteArray: Uint8Array): bigint { if (!byteArray || byteArray?.length === 0) { return BigInt(0); } const buffer = Buffer.from(byteArray); - const result = toBigIntLE(buffer); + const result = toBigIntBE(buffer); return result; } @@ -48,37 +52,52 @@ function createUintToUint8ArrayFunction(numBits: number) { let byteBuffer; let totalBuffer; - const padBuffer = numBytes <= 20 ? Buffer.alloc(20 - numBytes) : Buffer.alloc(0); // to fit it in an E160List switch (numBits) { - case 1: + case 2: // ebool takes 2 bits byteBuffer = Buffer.from([Types.ebool]); - totalBuffer = Buffer.concat([byteBuffer, combinedBuffer, padBuffer]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); break; case 4: byteBuffer = Buffer.from([Types.euint4]); - totalBuffer = Buffer.concat([byteBuffer, combinedBuffer, padBuffer]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); break; case 8: byteBuffer = Buffer.from([Types.euint8]); - totalBuffer = Buffer.concat([byteBuffer, combinedBuffer, padBuffer]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); break; case 16: byteBuffer = Buffer.from([Types.euint16]); - totalBuffer = Buffer.concat([byteBuffer, combinedBuffer, padBuffer]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); break; case 32: byteBuffer = Buffer.from([Types.euint32]); - totalBuffer = Buffer.concat([byteBuffer, combinedBuffer, padBuffer]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); break; case 64: byteBuffer = Buffer.from([Types.euint64]); - totalBuffer = Buffer.concat([byteBuffer, combinedBuffer, padBuffer]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); + break; + case 128: + byteBuffer = Buffer.from([Types.euint128]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); break; case 160: byteBuffer = Buffer.from([Types.eaddress]); totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); break; + case 256: + byteBuffer = Buffer.from([Types.euint256]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); + break; + case 512: + byteBuffer = Buffer.from([Types.ebytes64]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); + break; + case 1024: + byteBuffer = Buffer.from([Types.ebytes128]); + totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); + break; case 2048: byteBuffer = Buffer.from([Types.ebytes256]); totalBuffer = Buffer.concat([byteBuffer, combinedBuffer]); @@ -120,24 +139,27 @@ export const reencryptRequestMocked = async ( } // ACL checking - const aclFactory = await hre.ethers.getContractFactory("fhevm/lib/ACL.sol:ACL"); - const acl = aclFactory.attach(`0x${aclAdd}`); + const aclFactory = await hre.ethers.getContractFactory("fhevmTemp/contracts/ACL.sol:ACL"); + const acl = aclFactory.attach(aclAdd); const userAllowed = await acl.persistAllowed(handle, userAddress); const contractAllowed = await acl.persistAllowed(handle, contractAddress); const isAllowed = userAllowed && contractAllowed; if (!isAllowed) { throw new Error("User is not authorized to reencrypt this handle!"); } + if (userAddress === contractAddress) { + throw new Error("userAddress should not be equal to contractAddress when requesting reencryption!"); + } await awaitCoprocessor(); return BigInt(await getClearText(handle)); }; -export const createEncryptedInputMocked = (contractAddress: string, callerAddress: string) => { +export const createEncryptedInputMocked = (contractAddress: string, userAddress: string) => { if (!isAddress(contractAddress)) { throw new Error("Contract address is not a valid address."); } - if (!isAddress(callerAddress)) { + if (!isAddress(userAddress)) { throw new Error("User address is not a valid address."); } @@ -151,43 +173,57 @@ export const createEncryptedInputMocked = (contractAddress: string, callerAddres if ((typeof value !== "bigint" || typeof value !== "number") && Number(value) > 1) throw new Error("The value must be 1 or 0."); values.push(BigInt(value)); - bits.push(1); + bits.push(2); // ebool takes 2 bits instead of one: only exception in TFHE-rs + if (sum(bits) > 2048) throw Error("Packing more than 2048 bits in a single input ciphertext is unsupported"); + if (bits.length > 256) throw Error("Packing more than 256 variables in a single input ciphertext is unsupported"); return this; }, add4(value: number | bigint) { checkEncryptedValue(value, 4); values.push(BigInt(value)); bits.push(4); + if (sum(bits) > 2048) throw Error("Packing more than 2048 bits in a single input ciphertext is unsupported"); + if (bits.length > 256) throw Error("Packing more than 256 variables in a single input ciphertext is unsupported"); return this; }, add8(value: number | bigint) { checkEncryptedValue(value, 8); values.push(BigInt(value)); bits.push(8); + if (sum(bits) > 2048) throw Error("Packing more than 2048 bits in a single input ciphertext is unsupported"); + if (bits.length > 256) throw Error("Packing more than 256 variables in a single input ciphertext is unsupported"); return this; }, add16(value: number | bigint) { checkEncryptedValue(value, 16); values.push(BigInt(value)); bits.push(16); + if (sum(bits) > 2048) throw Error("Packing more than 2048 bits in a single input ciphertext is unsupported"); + if (bits.length > 256) throw Error("Packing more than 256 variables in a single input ciphertext is unsupported"); return this; }, add32(value: number | bigint) { checkEncryptedValue(value, 32); values.push(BigInt(value)); bits.push(32); + if (sum(bits) > 2048) throw Error("Packing more than 2048 bits in a single input ciphertext is unsupported"); + if (bits.length > 256) throw Error("Packing more than 256 variables in a single input ciphertext is unsupported"); return this; }, add64(value: number | bigint) { checkEncryptedValue(value, 64); values.push(BigInt(value)); bits.push(64); + if (sum(bits) > 2048) throw Error("Packing more than 2048 bits in a single input ciphertext is unsupported"); + if (bits.length > 256) throw Error("Packing more than 256 variables in a single input ciphertext is unsupported"); return this; }, add128(value: number | bigint) { checkEncryptedValue(value, 128); values.push(BigInt(value)); bits.push(128); + if (sum(bits) > 2048) throw Error("Packing more than 2048 bits in a single input ciphertext is unsupported"); + if (bits.length > 256) throw Error("Packing more than 256 variables in a single input ciphertext is unsupported"); return this; }, addAddress(value: string) { @@ -196,13 +232,46 @@ export const createEncryptedInputMocked = (contractAddress: string, callerAddres } values.push(BigInt(value)); bits.push(160); + if (sum(bits) > 2048) throw Error("Packing more than 2048 bits in a single input ciphertext is unsupported"); + if (bits.length > 256) throw Error("Packing more than 256 variables in a single input ciphertext is unsupported"); + return this; + }, + add256(value: number | bigint) { + checkEncryptedValue(value, 256); + values.push(BigInt(value)); + bits.push(256); + if (sum(bits) > 2048) throw Error("Packing more than 2048 bits in a single input ciphertext is unsupported"); + if (bits.length > 256) throw Error("Packing more than 256 variables in a single input ciphertext is unsupported"); + return this; + }, + addBytes64(value: Uint8Array) { + if (value.length !== 64) throw Error("Uncorrect length of input Uint8Array, should be 64 for an ebytes64"); + const bigIntValue = bytesToBigInt(value); + checkEncryptedValue(bigIntValue, 512); + values.push(bigIntValue); + bits.push(512); + if (sum(bits) > 2048) throw Error("Packing more than 2048 bits in a single input ciphertext is unsupported"); + if (bits.length > 256) throw Error("Packing more than 256 variables in a single input ciphertext is unsupported"); + return this; + }, + addBytes128(value: Uint8Array) { + if (value.length !== 128) throw Error("Uncorrect length of input Uint8Array, should be 128 for an ebytes128"); + const bigIntValue = bytesToBigInt(value); + checkEncryptedValue(bigIntValue, 1024); + values.push(bigIntValue); + bits.push(1024); + if (sum(bits) > 2048) throw Error("Packing more than 2048 bits in a single input ciphertext is unsupported"); + if (bits.length > 256) throw Error("Packing more than 256 variables in a single input ciphertext is unsupported"); return this; }, addBytes256(value: Uint8Array) { + if (value.length !== 256) throw Error("Uncorrect length of input Uint8Array, should be 256 for an ebytes256"); const bigIntValue = bytesToBigInt(value); checkEncryptedValue(bigIntValue, 2048); values.push(bigIntValue); bits.push(2048); + if (sum(bits) > 2048) throw Error("Packing more than 2048 bits in a single input ciphertext is unsupported"); + if (bits.length > 256) throw Error("Packing more than 256 variables in a single input ciphertext is unsupported"); return this; }, getValues() { @@ -216,26 +285,15 @@ export const createEncryptedInputMocked = (contractAddress: string, callerAddres bits.length = 0; return this; }, - encrypt() { - const listType = getListType(bits); - + async encrypt() { let encrypted = Buffer.alloc(0); - switch (listType) { - case 160: { - bits.map((v, i) => { - encrypted = Buffer.concat([encrypted, createUintToUint8ArrayFunction(v)(values[i])]); - }); - break; - } - case 2048: { - encrypted = createUintToUint8ArrayFunction(2048)(values[0]); - break; - } - } + bits.map((v, i) => { + encrypted = Buffer.concat([encrypted, createUintToUint8ArrayFunction(v)(values[i])]); + }); - const inputProof = new Uint8Array(encrypted); - const hash = new Keccak(256).update(Buffer.from(inputProof)).digest(); + const encryptedArray = new Uint8Array(encrypted); + const hash = new Keccak(256).update(Buffer.from(encryptedArray)).digest(); const handles = bits.map((v, i) => { const dataWithIndex = new Uint8Array(hash.length + 1); @@ -247,6 +305,47 @@ export const createEncryptedInputMocked = (contractAddress: string, callerAddres dataInput.set([i, ENCRYPTION_TYPES[v], 0], 29); return dataInput; }); + let inputProof = "0x" + numberToHex(handles.length); // for coprocessor : numHandles + numSignersKMS + hashCT + list_handles + signatureCopro + signatureKMSSigners (total len : 1+1+32+NUM_HANDLES*32+65+65*numSignersKMS) + // for native : numHandles + numSignersKMS + list_handles + signatureKMSSigners + bundleCiphertext (total len : 1+1+NUM_HANDLES*32+65*numSignersKMS+bundleCiphertext.length) + const numSigners = +process.env.NUM_KMS_SIGNERS!; + inputProof += numberToHex(numSigners); + if (process.env.IS_COPROCESSOR === "true") { + // coprocessor + inputProof += hash.toString("hex"); + + const listHandlesStr = handles.map((i) => uint8ArrayToHexString(i)); + listHandlesStr.map((handle) => (inputProof += handle)); + const listHandles = listHandlesStr.map((i) => BigInt("0x" + i)); + const sigCoproc = await computeInputSignatureCopro( + "0x" + hash.toString("hex"), + listHandles, + userAddress, + contractAddress, + ); + inputProof += sigCoproc.slice(2); + + const signaturesKMS = await computeInputSignaturesKMS( + "0x" + hash.toString("hex"), + userAddress, + contractAddress, + ); + signaturesKMS.map((sigKMS) => (inputProof += sigKMS.slice(2))); + listHandlesStr.map((handle, i) => insertSQL("0x" + handle, values[i])); + } else { + // native + const listHandlesStr = handles.map((i) => uint8ArrayToHexString(i)); + listHandlesStr.map((handle) => (inputProof += handle)); + const signaturesKMS = await computeInputSignaturesKMS( + "0x" + hash.toString("hex"), + userAddress, + contractAddress, + ); + signaturesKMS.map((sigKMS) => (inputProof += sigKMS.slice(2))); + listHandlesStr.map((handle, i) => insertSQL("0x" + handle, values[i])); + + inputProof += encrypted.toString("hex"); + } + return { handles, inputProof, @@ -255,6 +354,17 @@ export const createEncryptedInputMocked = (contractAddress: string, callerAddres }; }; +function uint8ArrayToHexString(uint8Array: Uint8Array) { + return Array.from(uint8Array) + .map((byte) => byte.toString(16).padStart(2, "0")) + .join(""); +} + +function numberToHex(num: number) { + let hex = num.toString(16); + return hex.length % 2 ? "0" + hex : hex; +} + const checkEncryptedValue = (value: number | bigint, bits: number) => { if (value == null) throw new Error("Missing value"); let limit; @@ -270,7 +380,7 @@ const checkEncryptedValue = (value: number | bigint, bits: number) => { }; export const ENCRYPTION_TYPES = { - 1: 0, + 2: 0, // ebool takes 2 bits 4: 1, 8: 2, 16: 3, @@ -284,19 +394,161 @@ export const ENCRYPTION_TYPES = { 2048: 11, }; -const getListType = (bits: (keyof typeof ENCRYPTION_TYPES)[]) => { - // We limit to 12 items because for now we are using FheUint160List - if (bits.length > 12) { - throw new Error("You can't pack more than 12 values."); +async function computeInputSignatureCopro( + hash: string, + handlesList: bigint[], + userAddress: string, + contractAddress: string, +): Promise { + let signature: string; + const privKeySigner = process.env["PRIVATE_KEY_COPROCESSOR_ACCOUNT"]; + if (privKeySigner) { + const coprocSigner = new Wallet(privKeySigner).connect(ethers.provider); + signature = await coprocSign(hash, handlesList, userAddress, contractAddress, coprocSigner); + } else { + throw new Error(`Private key for coprocessor not found in environment variables`); } + return signature; +} - if (bits.reduce((total, v) => total + v, 0) > 2048) { - throw new Error("Too many bits in provided values. Maximum is 2048."); +async function computeInputSignaturesKMS( + hash: string, + userAddress: string, + contractAddress: string, +): Promise { + const signatures: string[] = []; + const numSigners = +process.env.NUM_KMS_SIGNERS!; + for (let idx = 0; idx < numSigners; idx++) { + const privKeySigner = process.env[`PRIVATE_KEY_KMS_SIGNER_${idx}`]; + if (privKeySigner) { + const kmsSigner = new ethers.Wallet(privKeySigner).connect(ethers.provider); + const signature = await kmsSign(hash, userAddress, contractAddress, kmsSigner); + signatures.push(signature); + } else { + throw new Error(`Private key for signer ${idx} not found in environment variables`); + } } + return signatures; +} - if (bits.some((v) => v === 2048)) { - return 2048; - } else { - return 160; - } -}; +async function coprocSign( + hashOfCiphertext: string, + handlesList: bigint[], + userAddress: string, + contractAddress: string, + signer: Wallet, +): Promise { + const inputAdd = dotenv.parse( + fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.inputverifier"), + ).INPUT_VERIFIER_CONTRACT_ADDRESS; + const chainId = hre.__SOLIDITY_COVERAGE_RUNNING ? 31337 : network.config.chainId; + const aclAdd = dotenv.parse( + fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.acl"), + ).ACL_CONTRACT_ADDRESS; + + const domain = { + name: "InputVerifier", + version: "1", + chainId: chainId, + verifyingContract: inputAdd, + }; + + const types = { + CiphertextVerificationForCopro: [ + { + name: "aclAddress", + type: "address", + }, + { + name: "hashOfCiphertext", + type: "bytes32", + }, + { + name: "handlesList", + type: "uint256[]", + }, + { + name: "userAddress", + type: "address", + }, + { + name: "contractAddress", + type: "address", + }, + ], + }; + const message = { + aclAddress: aclAdd, + hashOfCiphertext: hashOfCiphertext, + handlesList: handlesList, + userAddress: userAddress, + contractAddress: contractAddress, + }; + + const signature = await signer.signTypedData(domain, types, message); + const sigRSV = ethers.Signature.from(signature); + const v = 27 + sigRSV.yParity; + const r = sigRSV.r; + const s = sigRSV.s; + + const result = r + s.substring(2) + v.toString(16); + return result; +} + +async function kmsSign( + hashOfCiphertext: string, + userAddress: string, + contractAddress: string, + signer: Wallet, +): Promise { + const kmsVerifierAdd = dotenv.parse( + fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.kmsverifier"), + ).KMS_VERIFIER_CONTRACT_ADDRESS; + const chainId = hre.__SOLIDITY_COVERAGE_RUNNING ? 31337 : network.config.chainId; + const aclAdd = dotenv.parse( + fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.acl"), + ).ACL_CONTRACT_ADDRESS; + + const domain = { + name: "KMSVerifier", + version: "1", + chainId: chainId, + verifyingContract: kmsVerifierAdd, + }; + + const types = { + CiphertextVerificationForKMS: [ + { + name: "aclAddress", + type: "address", + }, + { + name: "hashOfCiphertext", + type: "bytes32", + }, + { + name: "userAddress", + type: "address", + }, + { + name: "contractAddress", + type: "address", + }, + ], + }; + const message = { + aclAddress: aclAdd, + hashOfCiphertext: hashOfCiphertext, + userAddress: userAddress, + contractAddress: contractAddress, + }; + + const signature = await signer.signTypedData(domain, types, message); + const sigRSV = ethers.Signature.from(signature); + const v = 27 + sigRSV.yParity; + const r = sigRSV.r; + const s = sigRSV.s; + + const result = r + s.substring(2) + v.toString(16); + return result; +} diff --git a/test/instance.ts b/test/instance.ts index 07d90d2..0f687a0 100644 --- a/test/instance.ts +++ b/test/instance.ts @@ -1,5 +1,11 @@ import dotenv from "dotenv"; -import { clientKeyDecryptor, createInstance as createFhevmInstance, getCiphertextCallParams } from "fhevmjs"; +import { + clientKeyDecryptor, + createEIP712, + createInstance as createFhevmInstance, + generateKeypair, + getCiphertextCallParams, +} from "fhevmjs"; import { readFileSync } from "fs"; import * as fs from "fs"; import { ethers, ethers as hethers, network } from "hardhat"; @@ -10,12 +16,17 @@ import { awaitCoprocessor, getClearText } from "./coprocessorUtils"; import { createEncryptedInputMocked, reencryptRequestMocked } from "./fhevmjsMocked"; import { EBOOL_T, + EBYTES64_T, + EBYTES128_T, + EBYTES256_T, EUINT4_T, EUINT8_T, EUINT16_T, EUINT32_T, EUINT64_T, + EUINT128_T, EUINT160_T, + EUINT256_T, verifyType, } from "./handleTypeCheck"; import type { Signers } from "./signers"; @@ -25,16 +36,23 @@ const FHE_CLIENT_KEY_PATH = process.env.FHE_CLIENT_KEY_PATH; let clientKey: Uint8Array | undefined; -const parsedEnvACL = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.acl")); -const aclAdd = parsedEnvACL.ACL_CONTRACT_ADDRESS; +const kmsAdd = dotenv.parse( + fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.kmsverifier"), +).KMS_VERIFIER_CONTRACT_ADDRESS; + +const aclAdd = dotenv.parse( + fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.acl"), +).ACL_CONTRACT_ADDRESS; const createInstanceMocked = async () => { - const instance = await createFhevmInstance({ - chainId: network.config.chainId, - }); - instance.reencrypt = reencryptRequestMocked; - instance.createEncryptedInput = createEncryptedInputMocked; - instance.getPublicKey = () => "0xFFAA44433"; + const instance = { + reencrypt: reencryptRequestMocked, + createEncryptedInput: createEncryptedInputMocked, + getPublicKey: () => "0xFFAA44433", + generateKeypair: generateKeypair, + createEIP712: createEIP712(network.config.chainId), + }; + return instance; }; @@ -60,8 +78,9 @@ export const createInstances = async (accounts: Signers): Promise { const instance = await createFhevmInstance({ networkUrl: network.config.url, + kmsContractAddress: kmsAdd, + aclContractAddress: aclAdd, gatewayUrl: "http://localhost:7077", - aclAddress: aclAdd, }); return instance; }; @@ -203,6 +222,47 @@ export const decrypt64 = async (handle: bigint): Promise => { } }; +/** + * @debug + * This function is intended for debugging purposes only. + * It cannot be used in production code, since it requires the FHE private key for decryption. + * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. + * + * @param {bigint} handle to decrypt + * @returns {bigint} + */ + +export const decrypt128 = async (handle: bigint): Promise => { + verifyType(handle, EUINT128_T); + if (network.name === "hardhat") { + await awaitCoprocessor(); + return BigInt(await getClearText(handle)); + } else { + return getDecryptor().decrypt128(await getCiphertext(handle, ethers)); + } +}; + +/** + * @debug + * This function is intended for debugging purposes only. + * It cannot be used in production code, since it requires the FHE private key for decryption. + * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. + * + * @param {bigint} handle to decrypt + * @returns {bigint} + */ + +export const decrypt256 = async (handle: bigint): Promise => { + verifyType(handle, EUINT256_T); + if (network.name === "hardhat") { + await awaitCoprocessor(); + + return BigInt(await getClearText(handle)); + } else { + return getDecryptor().decrypt256(await getCiphertext(handle, ethers)); + } +}; + /** * @debug * This function is intended for debugging purposes only. @@ -224,3 +284,67 @@ export const decryptAddress = async (handle: bigint): Promise => { return getDecryptor().decryptAddress(await getCiphertext(handle, ethers)); } }; + +/** + * @debug + * This function is intended for debugging purposes only. + * It cannot be used in production code, since it requires the FHE private key for decryption. + * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. + * + * @param {bigint} a handle to decrypt + * @returns {bigint} + */ + +export const decryptEbytes64 = async (handle: bigint): Promise => { + verifyType(handle, EBYTES64_T); + + if (network.name === "hardhat") { + await awaitCoprocessor(); + + return BigInt(await getClearText(handle)); + } else { + return getDecryptor().decryptEbytes64(await getCiphertext(handle, ethers)); + } +}; + +/** + * @debug + * This function is intended for debugging purposes only. + * It cannot be used in production code, since it requires the FHE private key for decryption. + * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. + * + * @param {bigint} handle to decrypt + * @returns {bigint} + */ +export const decryptEbytes128 = async (handle: bigint): Promise => { + verifyType(handle, EBYTES128_T); + + if (network.name === "hardhat") { + await awaitCoprocessor(); + + return BigInt(await getClearText(handle)); + } else { + return getDecryptor().decryptEbytes128(await getCiphertext(handle, ethers)); + } +}; + +/** + * @debug + * This function is intended for debugging purposes only. + * It cannot be used in production code, since it requires the FHE private key for decryption. + * In production, decryption is only possible via an asyncronous on-chain call to the Gateway. + * + * @param {bigint} handle to decrypt + * @returns {bigint} + */ +export const decryptEbytes256 = async (handle: bigint): Promise => { + verifyType(handle, EBYTES256_T); + + if (network.name === "hardhat") { + await awaitCoprocessor(); + + return BigInt(await getClearText(handle)); + } else { + return getDecryptor().decryptEbytes256(await getCiphertext(handle, ethers)); + } +}; diff --git a/test/operatorsPrices.json b/test/operatorsPrices.json new file mode 100644 index 0000000..dcf4897 --- /dev/null +++ b/test/operatorsPrices.json @@ -0,0 +1,530 @@ +{ + "fheAdd": { + "binary": true, + "scalar": { + "1": 65000, + "2": 94000, + "3": 133000, + "4": 162000, + "5": 188000, + "6": 218000, + "8": 253000 + }, + "nonScalar": { + "1": 65000, + "2": 94000, + "3": 133000, + "4": 162000, + "5": 188000, + "6": 218000, + "8": 253000 + } + }, + "fheSub": { + "binary": true, + "scalar": { + "1": 65000, + "2": 94000, + "3": 133000, + "4": 162000, + "5": 188000, + "6": 218000, + "8": 253000 + }, + "nonScalar": { + "1": 65000, + "2": 94000, + "3": 133000, + "4": 162000, + "5": 188000, + "6": 218000, + "8": 253000 + } + }, + "fheMul": { + "binary": true, + "scalar": { + "1": 88000, + "2": 159000, + "3": 208000, + "4": 264000, + "5": 356000, + "6": 480000, + "8": 647000 + }, + "nonScalar": { + "1": 150000, + "2": 197000, + "3": 262000, + "4": 359000, + "5": 641000, + "6": 1145000, + "8": 2045000 + } + }, + "fheDiv": { + "binary": true, + "scalar": { + "1": 139000, + "2": 238000, + "3": 314000, + "4": 398000, + "5": 584000, + "6": 857000, + "8": 1258000 + } + }, + "fheRem": { + "binary": true, + "scalar": { + "1": 286000, + "2": 460000, + "3": 622000, + "4": 805000, + "5": 1095000, + "6": 1499000, + "8": 2052000 + } + }, + "fheBitAnd": { + "binary": true, + "scalar": { + "0": 26000, + "1": 32000, + "2": 34000, + "3": 34000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 + }, + "nonScalar": { + "0": 26000, + "1": 32000, + "2": 34000, + "3": 34000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 + } + }, + "fheBitOr": { + "binary": true, + "scalar": { + "0": 26000, + "1": 32000, + "2": 34000, + "3": 34000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 + }, + "nonScalar": { + "0": 26000, + "1": 32000, + "2": 34000, + "3": 34000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 + } + }, + "fheBitXor": { + "binary": true, + "scalar": { + "0": 26000, + "1": 32000, + "2": 34000, + "3": 34000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 + }, + "nonScalar": { + "0": 26000, + "1": 32000, + "2": 34000, + "3": 34000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 + } + }, + "fheShl": { + "binary": true, + "scalar": { + "1": 35000, + "2": 35000, + "3": 35000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 + }, + "nonScalar": { + "1": 116000, + "2": 133000, + "3": 153000, + "4": 183000, + "5": 227000, + "6": 282000, + "8": 350000 + } + }, + "fheShr": { + "binary": true, + "scalar": { + "1": 35000, + "2": 35000, + "3": 35000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 + }, + "nonScalar": { + "1": 116000, + "2": 133000, + "3": 153000, + "4": 183000, + "5": 227000, + "6": 282000, + "8": 350000 + } + }, + "fheRotl": { + "binary": true, + "scalar": { + "1": 35000, + "2": 35000, + "3": 35000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 + }, + "nonScalar": { + "1": 116000, + "2": 133000, + "3": 153000, + "4": 183000, + "5": 227000, + "6": 282000, + "8": 350000 + } + }, + "fheRotr": { + "binary": true, + "scalar": { + "1": 35000, + "2": 35000, + "3": 35000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 + }, + "nonScalar": { + "1": 116000, + "2": 133000, + "3": 153000, + "4": 183000, + "5": 227000, + "6": 282000, + "8": 350000 + } + }, + "fheEq": { + "binary": true, + "scalar": { + "0": 49000, + "1": 51000, + "2": 53000, + "3": 54000, + "4": 82000, + "5": 86000, + "6": 88000, + "7": 90000, + "8": 100000, + "9": 150000, + "10": 200000, + "11": 300000 + }, + "nonScalar": { + "0": 49000, + "1": 51000, + "2": 53000, + "3": 54000, + "4": 82000, + "5": 86000, + "6": 88000, + "7": 90000, + "8": 100000, + "9": 150000, + "10": 200000, + "11": 300000 + } + }, + "fheNe": { + "binary": true, + "scalar": { + "0": 49000, + "1": 51000, + "2": 53000, + "3": 54000, + "4": 82000, + "5": 86000, + "6": 88000, + "7": 90000, + "8": 100000, + "9": 150000, + "10": 200000, + "11": 300000 + }, + "nonScalar": { + "0": 49000, + "1": 51000, + "2": 53000, + "3": 54000, + "4": 82000, + "5": 86000, + "6": 88000, + "7": 90000, + "8": 100000, + "9": 150000, + "10": 200000, + "11": 300000 + } + }, + "fheGe": { + "binary": true, + "scalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 + }, + "nonScalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 + } + }, + "fheGt": { + "binary": true, + "scalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 + }, + "nonScalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 + } + }, + "fheLe": { + "binary": true, + "scalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 + }, + "nonScalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 + } + }, + "fheLt": { + "binary": true, + "scalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 + }, + "nonScalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 + } + }, + "fheMin": { + "binary": true, + "scalar": { + "1": 121000, + "2": 128000, + "3": 150000, + "4": 164000, + "5": 192000, + "6": 225000, + "8": 264000 + }, + "nonScalar": { + "1": 121000, + "2": 128000, + "3": 153000, + "4": 183000, + "5": 210000, + "6": 241000, + "8": 277000 + } + }, + "fheMax": { + "binary": true, + "scalar": { + "1": 121000, + "2": 128000, + "3": 150000, + "4": 164000, + "5": 192000, + "6": 225000, + "8": 264000 + }, + "nonScalar": { + "1": 121000, + "2": 128000, + "3": 153000, + "4": 183000, + "5": 210000, + "6": 241000, + "8": 277000 + } + }, + "fheNeg": { + "binary": false, + "types": { + "1": 60000, + "2": 95000, + "3": 131000, + "4": 160000, + "5": 199000, + "6": 248000, + "8": 309000 + } + }, + "fheNot": { + "binary": false, + "types": { + "0": 30000, + "1": 33000, + "2": 34000, + "3": 35000, + "4": 36000, + "5": 37000, + "6": 38000, + "8": 39000 + } + }, + "cast": { + "binary": false, + "types": { + "0": 200, + "1": 200, + "2": 200, + "3": 200, + "4": 200, + "5": 200, + "6": 200, + "8": 200 + } + }, + "trivialEncrypt": { + "binary": false, + "types": { + "0": 100, + "1": 100, + "2": 100, + "3": 200, + "4": 300, + "5": 600, + "6": 650, + "7": 700, + "8": 800, + "9": 1600, + "10": 3200, + "11": 6400 + } + }, + "ifThenElse": { + "binary": false, + "types": { + "0": 43000, + "1": 45000, + "2": 47000, + "3": 47000, + "4": 50000, + "5": 53000, + "6": 70000, + "7": 80000, + "8": 90000, + "9": 150000, + "10": 200000, + "11": 300000 + } + }, + "fheRand": { + "binary": false, + "types": { + "0": 100000, + "1": 100000, + "2": 100000, + "3": 100000, + "4": 100000, + "5": 100000, + "6": 100000, + "8": 100000, + "9": 200000, + "10": 300000, + "11": 400000 + } + }, + "fheRandBounded": { + "binary": false, + "types": { + "1": 100000, + "2": 100000, + "3": 100000, + "4": 100000, + "5": 100000, + "6": 100000, + "8": 100000 + } + } +} \ No newline at end of file diff --git a/test/reencrypt.ts b/test/reencrypt.ts index abcca2c..8c79e63 100644 --- a/test/reencrypt.ts +++ b/test/reencrypt.ts @@ -1,20 +1,34 @@ -import { - EBOOL_T, - EBYTES64_T, - EBYTES128_T, - EBYTES256_T, - EUINT4_T, - EUINT8_T, - EUINT16_T, - EUINT32_T, - EUINT64_T, - EUINT128_T, - EUINT160_T, - EUINT256_T, - verifyType, -} from "./handleTypeCheck"; import { Signers } from "./signers"; -import { FhevmInstances } from "./types"; +import type { FhevmInstances } from "./types"; + +const EBOOL_T = 0; +const EUINT4_T = 1; +const EUINT8_T = 2; +const EUINT16_T = 3; +const EUINT32_T = 4; +const EUINT64_T = 5; +const EUINT128_T = 6; +const EUINT160_T = 7; // @dev It is the one for eaddresses. +const EUINT256_T = 8; +const EBYTES64_T = 9; +const EBYTES128_T = 10; +const EBYTES256_T = 11; + +export function verifyType(handle: bigint, expectedType: number) { + if (handle === 0n) { + throw "Handle is not initialized"; + } + + if (handle.toString(2).length > 256) { + throw "Handle is not a bytes32"; + } + + const typeCt = handle >> 8n; + + if (Number(typeCt % 256n) !== expectedType) { + throw "Wrong encrypted type for the handle"; + } +} export async function reencryptEbool( signers: Signers, @@ -24,7 +38,7 @@ export async function reencryptEbool( contractAddress: string, ): Promise { verifyType(handle, EBOOL_T); - return reencryptHandle(signers, instances, user, handle, contractAddress); + return (await reencryptHandle(signers, instances, user, handle, contractAddress)) === 1n; } export async function reencryptEuint4( @@ -93,7 +107,7 @@ export async function reencryptEuint128( return reencryptHandle(signers, instances, user, handle, contractAddress); } -export async function reencryptEAddress( +export async function reencryptEaddress( signers: Signers, instances: FhevmInstances, user: string, diff --git a/test/signers.ts b/test/signers.ts index 4715592..8b017d1 100644 --- a/test/signers.ts +++ b/test/signers.ts @@ -1,5 +1,11 @@ import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; -import { ethers } from "hardhat"; +import { exec as oldExec } from "child_process"; +import { config, ethers } from "hardhat"; +import { promisify } from "util"; + +import { waitForBalance } from "./utils"; + +const exec = promisify(oldExec); export interface Signers { alice: HardhatEthersSigner; @@ -11,19 +17,59 @@ export interface Signers { let signers: Signers; -export const initSigners = async (): Promise => { +const keys: (keyof Signers)[] = ["alice", "bob", "carol", "dave", "eve"]; + +const getCoin = async (address: string) => { + const containerName = process.env["TEST_CONTAINER_NAME"] || "zama-dev-fhevm-validator-1"; + const response = await exec(`docker exec -i ${containerName} faucet ${address} | grep height`); + const res = JSON.parse(response.stdout); + if (res.raw_log.match("account sequence mismatch")) await getCoin(address); +}; + +const faucet = async (address: string) => { + const balance = await ethers.provider.getBalance(address); + if (balance > 0) return; + await getCoin(address); + await waitForBalance(address); +}; + +export const initSigners = async (quantity: number): Promise => { + const q = process.env.HARDHAT_PARALLEL ? Math.min(quantity, 5) : 5; if (!signers) { - const eSigners = await ethers.getSigners(); - signers = { - alice: eSigners[0], - bob: eSigners[1], - carol: eSigners[2], - dave: eSigners[3], - eve: eSigners[4], - }; + if (process.env.HARDHAT_PARALLEL && config.defaultNetwork === "local") { + signers = { + alice: ethers.Wallet.createRandom().connect(ethers.provider), + bob: ethers.Wallet.createRandom().connect(ethers.provider), + carol: ethers.Wallet.createRandom().connect(ethers.provider), + dave: ethers.Wallet.createRandom().connect(ethers.provider), + eve: ethers.Wallet.createRandom().connect(ethers.provider), + }; + } else if (!process.env.HARDHAT_PARALLEL) { + const eSigners = await ethers.getSigners(); + signers = { + alice: eSigners[0], + bob: eSigners[1], + carol: eSigners[2], + dave: eSigners[3], + eve: eSigners[4], + }; + } else { + throw new Error("Can't run parallel mode if network is not 'local'"); + } + + if (config.defaultNetwork === "local") { + const faucetP: Promise[] = []; + for (let i = 0; i < q; i += 1) { + const account = signers[keys[i]]; + faucetP.push(faucet(account.address)); + } + await Promise.all(faucetP); + } } }; export const getSigners = async (): Promise => { return signers; }; + +export const requestFaucet = faucet; diff --git a/test/utils.ts b/test/utils.ts index 5af310b..ae071be 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,4 +1,4 @@ -import { toBufferLE } from "bigint-buffer"; +import { toBufferBE } from "bigint-buffer"; import { ContractMethodArgs, Typed } from "ethers"; import { ethers, network } from "hardhat"; @@ -91,6 +91,18 @@ export const mineNBlocks = async (n: number) => { } }; +export const bigIntToBytes64 = (value: bigint) => { + return new Uint8Array(toBufferBE(value, 64)); +}; + +export const bigIntToBytes128 = (value: bigint) => { + return new Uint8Array(toBufferBE(value, 128)); +}; + +export const bigIntToBytes256 = (value: bigint) => { + return new Uint8Array(toBufferBE(value, 256)); +}; + export const bigIntToBytes = (value: bigint) => { const byteArrayLength = Math.ceil(value.toString(2).length / 8); return new Uint8Array(toBufferLE(value, byteArrayLength)); diff --git a/tsconfig.json b/tsconfig.json index 734e21a..31a8f3a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,7 @@ "esModuleInterop": true, "experimentalDecorators": true, "forceConsistentCasingInFileNames": true, - "lib": ["es2020"], + "lib": ["es2020", "dom"], "module": "commonjs", "moduleResolution": "node", "noImplicitAny": true, @@ -19,4 +19,4 @@ "exclude": ["node_modules"], "files": ["./hardhat.config.ts"], "include": ["src/**/*", "tasks/**/*", "test/**/*", "deploy/**/*", "types/"] -} +} \ No newline at end of file From e095408dc6c10231606b8db727bae4ca3c12bb1c Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:12:15 +0100 Subject: [PATCH 29/73] build: FHEVM 0.6 --- test/asyncDecrypt.ts | 133 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 108 insertions(+), 25 deletions(-) diff --git a/test/asyncDecrypt.ts b/test/asyncDecrypt.ts index 7dff151..b683543 100644 --- a/test/asyncDecrypt.ts +++ b/test/asyncDecrypt.ts @@ -1,4 +1,5 @@ import dotenv from "dotenv"; +import { Wallet } from "ethers"; import fs from "fs"; import { ethers, network } from "hardhat"; @@ -8,8 +9,8 @@ import { waitNBlocks } from "./utils"; const networkName = network.name; -const parsedEnvACL = dotenv.parse(fs.readFileSync("node_modules/fhevm/lib/.env.acl")); -const aclAdd = parsedEnvACL.ACL_CONTRACT_ADDRESS.replace(/^0x/, "").replace(/^0+/, "").toLowerCase(); +const parsedEnvACL = dotenv.parse(fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.acl")); +const aclAdd = parsedEnvACL.ACL_CONTRACT_ADDRESS; const CiphertextType = { 0: "bool", @@ -20,6 +21,9 @@ const CiphertextType = { 5: "uint64", 6: "uint128", 7: "address", + 8: "uint256", + 9: "bytes", + 10: "bytes", 11: "bytes", }; @@ -29,8 +33,11 @@ const currentTime = (): string => { }; const parsedEnv = dotenv.parse(fs.readFileSync("node_modules/fhevm/gateway/.env.gateway")); -const privKeyRelayer = process.env.PRIVATE_KEY_GATEWAY_RELAYER; -const relayer = new ethers.Wallet(privKeyRelayer!, ethers.provider); +let relayer: Wallet; +if (networkName === "hardhat") { + const privKeyRelayer = process.env.PRIVATE_KEY_GATEWAY_RELAYER; + relayer = new ethers.Wallet(privKeyRelayer!, ethers.provider); +} const argEvents = "(uint256 indexed requestID, uint256[] cts, address contractCaller, bytes4 callbackSelector, uint256 msgValue, uint256 maxTimestamp, bool passSignaturesToCaller)"; @@ -43,35 +50,29 @@ let gateway: GatewayContract; let firstBlockListening: number; let lastBlockSnapshotForDecrypt: number; -export const asyncDecrypt = async (): Promise => { +export const initGateway = async (): Promise => { firstBlockListening = await ethers.provider.getBlockNumber(); if (networkName === "hardhat" && hre.__SOLIDITY_COVERAGE_RUNNING !== true) { // evm_snapshot is not supported in coverage mode await ethers.provider.send("set_lastBlockSnapshotForDecrypt", [firstBlockListening]); } // this function will emit logs for every request and fulfilment of a decryption - gateway = await ethers.getContractAt( - "fhevm/gateway/GatewayContract.sol:GatewayContract", - parsedEnv.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS, - ); - await gateway.on( + gateway = await ethers.getContractAt("GatewayContract", parsedEnv.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS); + gateway.on( "EventDecryption", async (requestID, cts, contractCaller, callbackSelector, msgValue, maxTimestamp, eventData) => { const blockNumber = eventData.log.blockNumber; console.log(`${await currentTime()} - Requested decrypt on block ${blockNumber} (requestID ${requestID})`); }, ); - await gateway.on("ResultCallback", async (requestID, success, result, eventData) => { + gateway.on("ResultCallback", async (requestID, success, result, eventData) => { const blockNumber = eventData.log.blockNumber; console.log(`${await currentTime()} - Fulfilled decrypt on block ${blockNumber} (requestID ${requestID})`); }); }; export const awaitAllDecryptionResults = async (): Promise => { - gateway = await ethers.getContractAt( - "fhevm/gateway/GatewayContract.sol:GatewayContract", - parsedEnv.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS, - ); + gateway = await ethers.getContractAt("GatewayContract", parsedEnv.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS); const provider = ethers.provider; if (networkName === "hardhat" && hre.__SOLIDITY_COVERAGE_RUNNING !== true) { // evm_snapshot is not supported in coverage mode @@ -92,7 +93,7 @@ const getAlreadyFulfilledDecryptions = async (): Promise<[bigint]> => { let results = []; const eventDecryptionResult = await gateway.filters.ResultCallback().getTopicFilter(); const filterDecryptionResult = { - address: process.env.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS, + address: parsedEnv.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS, fromBlock: firstBlockListening, toBlock: "latest", topics: eventDecryptionResult, @@ -109,7 +110,7 @@ const fulfillAllPastRequestsIds = async (mocked: boolean) => { const eventDecryption = await gateway.filters.EventDecryption().getTopicFilter(); const results = await getAlreadyFulfilledDecryptions(); const filterDecryption = { - address: process.env.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS, + address: parsedEnv.GATEWAY_CONTRACT_PREDEPLOY_ADDRESS, fromBlock: firstBlockListening, toBlock: "latest", topics: eventDecryption, @@ -121,6 +122,7 @@ const fulfillAllPastRequestsIds = async (mocked: boolean) => { const handles = event.args[1]; const typesList = handles.map((handle) => parseInt(handle.toString(16).slice(-4, -2), 16)); const msgValue = event.args[4]; + const passSignaturesToCaller = event.args[6]; if (!results.includes(requestID)) { // if request is not already fulfilled if (mocked) { @@ -128,27 +130,43 @@ const fulfillAllPastRequestsIds = async (mocked: boolean) => { await awaitCoprocessor(); // first check tat all handles are allowed for decryption - const aclFactory = await ethers.getContractFactory("fhevm/lib/ACL.sol:ACL"); - const acl = aclFactory.attach(`0x${aclAdd}`); - const isAllowedForDec = await Promise.all(handles.map(async (handle) => acl.allowedForDecryption(handle))); + const aclFactory = await ethers.getContractFactory("fhevmTemp/contracts/ACL.sol:ACL"); + const acl = aclFactory.attach(aclAdd); + const isAllowedForDec = await Promise.all(handles.map(async (handle) => acl.isAllowedForDecryption(handle))); if (!allTrue(isAllowedForDec)) { throw new Error("Some handle is not authorized for decryption"); } - const types = typesList.map((num) => CiphertextType[num]); const values = await Promise.all(handles.map(async (handle) => BigInt(await getClearText(handle)))); const valuesFormatted = values.map((value, index) => types[index] === "address" ? "0x" + value.toString(16).padStart(40, "0") : value, ); const valuesFormatted2 = valuesFormatted.map((value, index) => - types[index] === "bytes" ? "0x" + value.toString(16).padStart(512, "0") : value, + typesList[index] === 9 ? "0x" + value.toString(16).padStart(128, "0") : value, + ); + const valuesFormatted3 = valuesFormatted2.map((value, index) => + typesList[index] === 10 ? "0x" + value.toString(16).padStart(256, "0") : value, + ); + const valuesFormatted4 = valuesFormatted3.map((value, index) => + typesList[index] === 11 ? "0x" + value.toString(16).padStart(512, "0") : value, ); const abiCoder = new ethers.AbiCoder(); - const encodedData = abiCoder.encode(["uint256", ...types], [31, ...valuesFormatted2]); // 31 is just a dummy uint256 requestID to get correct abi encoding for the remaining arguments (i.e everything except the requestID) - const calldata = "0x" + encodedData.slice(66); // we just pop the dummy requestID to get the correct value to pass for `decryptedCts` + let encodedData; + let calldata; + if (!passSignaturesToCaller) { + encodedData = abiCoder.encode(["uint256", ...types], [31, ...valuesFormatted4]); // 31 is just a dummy uint256 requestID to get correct abi encoding for the remaining arguments (i.e everything except the requestID) + calldata = "0x" + encodedData.slice(66); // we just pop the dummy requestID to get the correct value to pass for `decryptedCts` + } else { + encodedData = abiCoder.encode(["uint256", ...types, "bytes[]"], [31, ...valuesFormatted4, []]); // adding also a dummy empty array of bytes for correct abi-encoding when used with signatures + calldata = "0x" + encodedData.slice(66).slice(0, -64); // we also pop the last 32 bytes (empty bytes[]) + } - const tx = await gateway.connect(relayer).fulfillRequest(requestID, calldata, [], { value: msgValue }); + const numSigners = +process.env.NUM_KMS_SIGNERS!; + const decryptResultsEIP712signatures = await computeDecryptSignatures(handles, calldata, numSigners); + const tx = await gateway + .connect(relayer) + .fulfillRequest(requestID, calldata, decryptResultsEIP712signatures, { value: msgValue }); await tx.wait(); } else { // in fhEVM mode we must wait until the gateway service relayer submits the decryption fulfillment tx @@ -158,3 +176,68 @@ const fulfillAllPastRequestsIds = async (mocked: boolean) => { } } }; + +async function computeDecryptSignatures( + handlesList: bigint[], + decryptedResult: string, + numSigners: number, +): Promise { + const signatures: string[] = []; + + for (let idx = 0; idx < numSigners; idx++) { + const privKeySigner = process.env[`PRIVATE_KEY_KMS_SIGNER_${idx}`]; + if (privKeySigner) { + const kmsSigner = new ethers.Wallet(privKeySigner).connect(ethers.provider); + const signature = await kmsSign(handlesList, decryptedResult, kmsSigner); + signatures.push(signature); + } else { + throw new Error(`Private key for signer ${idx} not found in environment variables`); + } + } + return signatures; +} + +async function kmsSign(handlesList: bigint[], decryptedResult: string, kmsSigner: Wallet) { + const kmsAdd = dotenv.parse( + fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.kmsverifier"), + ).KMS_VERIFIER_CONTRACT_ADDRESS; + const chainId = (await ethers.provider.getNetwork()).chainId; + + const domain = { + name: "KMSVerifier", + version: "1", + chainId: chainId, + verifyingContract: kmsAdd, + }; + + const types = { + DecryptionResult: [ + { + name: "aclAddress", + type: "address", + }, + { + name: "handlesList", + type: "uint256[]", + }, + { + name: "decryptedResult", + type: "bytes", + }, + ], + }; + const message = { + aclAddress: aclAdd, + handlesList: handlesList, + decryptedResult: decryptedResult, + }; + + const signature = await kmsSigner.signTypedData(domain, types, message); + const sigRSV = ethers.Signature.from(signature); + const v = 27 + sigRSV.yParity; + const r = sigRSV.r; + const s = sigRSV.s; + + const result = r + s.substring(2) + v.toString(16); + return result; +} From 53265840615b9edd3436a70e5ab0426f3ac93c48 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:12:37 +0100 Subject: [PATCH 30/73] refactor: EncryptedERC20 for FHEVM 0.6 --- contracts/token/ERC20/EncryptedERC20.sol | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contracts/token/ERC20/EncryptedERC20.sol b/contracts/token/ERC20/EncryptedERC20.sol index 48358f3..c36bced 100644 --- a/contracts/token/ERC20/EncryptedERC20.sol +++ b/contracts/token/ERC20/EncryptedERC20.sol @@ -38,6 +38,7 @@ abstract contract EncryptedERC20 is IEncryptedERC20 { * @param symbol_ Symbol. */ constructor(string memory name_, string memory symbol_) { + TFHE.setFHEVM(FHEVMConfig.defaultConfig()); _name = name_; _symbol = symbol_; } @@ -149,7 +150,7 @@ abstract contract EncryptedERC20 is IEncryptedERC20 { function _approve(address owner, address spender, euint64 amount) internal virtual { _allowances[owner][spender] = amount; - TFHE.allow(amount, address(this)); + TFHE.allowThis(amount); TFHE.allow(amount, owner); TFHE.allow(amount, spender); } @@ -159,11 +160,11 @@ abstract contract EncryptedERC20 is IEncryptedERC20 { euint64 transferValue = TFHE.select(isTransferable, amount, TFHE.asEuint64(0)); euint64 newBalanceTo = TFHE.add(_balances[to], transferValue); _balances[to] = newBalanceTo; - TFHE.allow(newBalanceTo, address(this)); + TFHE.allowThis(newBalanceTo); TFHE.allow(newBalanceTo, to); euint64 newBalanceFrom = TFHE.sub(_balances[from], transferValue); _balances[from] = newBalanceFrom; - TFHE.allow(newBalanceFrom, address(this)); + TFHE.allowThis(newBalanceFrom); TFHE.allow(newBalanceFrom, from); emit Transfer(from, to); } From 4d0ecf3b17dbfd4bbe7213b62e891583bb2f3bd7 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:13:03 +0100 Subject: [PATCH 31/73] test: Adjustments for FHEVM 0.6 --- test/encryptedERC20/EncryptedERC20.test.ts | 40 ++++++++++++---------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/test/encryptedERC20/EncryptedERC20.test.ts b/test/encryptedERC20/EncryptedERC20.test.ts index 1374404..11fb213 100644 --- a/test/encryptedERC20/EncryptedERC20.test.ts +++ b/test/encryptedERC20/EncryptedERC20.test.ts @@ -6,7 +6,7 @@ import { deployEncryptedERC20Fixture, reencryptAllowance, reencryptBalance } fro describe("EncryptedERC20", function () { before(async function () { - await initSigners(); + await initSigners(2); this.signers = await getSigners(); }); @@ -25,7 +25,7 @@ describe("EncryptedERC20", function () { it("should mint the contract", async function () { const mintAmount = 1000; - const tx = await this.encryptedERC20.mint(mintAmount); + const tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); await tx.wait(); expect( @@ -39,13 +39,14 @@ describe("EncryptedERC20", function () { const mintAmount = 10_000; const transferAmount = 1337; - let tx = await this.encryptedERC20.mint(mintAmount); + let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); const t1 = await tx.wait(); expect(t1?.status).to.eq(1); const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(transferAmount); - const encryptedTransferAmount = input.encrypt(); + const encryptedTransferAmount = await input.encrypt(); tx = await this.encryptedERC20["transfer(address,bytes32,bytes)"]( this.signers.bob.address, @@ -78,7 +79,7 @@ describe("EncryptedERC20", function () { const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); input.add64(transferAmount); - const encryptedTransferAmount = input.encrypt(); + const encryptedTransferAmount = await input.encrypt(); tx = await this.encryptedERC20["transfer(address,bytes32,bytes)"]( this.signers.bob.address, encryptedTransferAmount.handles[0], @@ -103,7 +104,7 @@ describe("EncryptedERC20", function () { const mintAmount = 10_000; const transferAmount = 1337; - let tx = await this.encryptedERC20.mint(mintAmount); + let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); await tx.wait(); const inputAlice = this.instances.alice.createEncryptedInput( @@ -111,7 +112,8 @@ describe("EncryptedERC20", function () { this.signers.alice.address, ); inputAlice.add64(transferAmount); - const encryptedAllowanceAmount = inputAlice.encrypt(); + const encryptedAllowanceAmount = await inputAlice.encrypt(); + tx = await this.encryptedERC20["approve(address,bytes32,bytes)"]( this.signers.bob.address, encryptedAllowanceAmount.handles[0], @@ -134,7 +136,8 @@ describe("EncryptedERC20", function () { const bobErc20 = this.encryptedERC20.connect(this.signers.bob); const inputBob1 = this.instances.bob.createEncryptedInput(this.encryptedERC20Address, this.signers.bob.address); inputBob1.add64(transferAmount + 1); // above allowance so next tx should actually not send any token - const encryptedTransferAmount = inputBob1.encrypt(); + const encryptedTransferAmount = await inputBob1.encrypt(); + const tx2 = await bobErc20["transferFrom(address,address,bytes32,bytes)"]( this.signers.alice.address, this.signers.bob.address, @@ -155,7 +158,8 @@ describe("EncryptedERC20", function () { const inputBob2 = this.instances.bob.createEncryptedInput(this.encryptedERC20Address, this.signers.bob.address); inputBob2.add64(transferAmount); // below allowance so next tx should send token - const encryptedTransferAmount2 = inputBob2.encrypt(); + const encryptedTransferAmount2 = await inputBob2.encrypt(); + const tx3 = await bobErc20["transferFrom(address,address,bytes32,bytes)"]( this.signers.alice.address, this.signers.bob.address, @@ -195,7 +199,7 @@ describe("EncryptedERC20", function () { this.signers.alice.address, ); inputAlice.add64(amount); - const encryptedAllowanceAmount = inputAlice.encrypt(); + const encryptedAllowanceAmount = await inputAlice.encrypt(); const tx = await this.encryptedERC20 .connect(this.signers.alice) @@ -268,7 +272,7 @@ describe("EncryptedERC20", function () { } }); - it("Sender who is not allowed cannot transfer using a handle from another account", async function () { + it("sender who is not allowed cannot transfer using a handle from another account", async function () { const mintAmount = 100_000; const transferAmount = 50_000; let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); @@ -276,7 +280,7 @@ describe("EncryptedERC20", function () { const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); input.add64(transferAmount); - const encryptedTransferAmount = input.encrypt(); + const encryptedTransferAmount = await input.encrypt(); tx = await this.encryptedERC20 .connect(this.signers.alice) @@ -295,7 +299,7 @@ describe("EncryptedERC20", function () { ).to.be.revertedWithCustomError(this.encryptedERC20, "TFHESenderNotAllowed"); }); - it("Sender who is not allowed cannot transferFrom using a handle from another account", async function () { + it("sender who is not allowed cannot transferFrom using a handle from another account", async function () { const mintAmount = 100_000; const transferAmount = 50_000; @@ -304,7 +308,7 @@ describe("EncryptedERC20", function () { let input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); input.add64(mintAmount); - const encryptedAllowanceAmount = input.encrypt(); + const encryptedAllowanceAmount = await input.encrypt(); tx = await this.encryptedERC20 .connect(this.signers.alice) @@ -314,9 +318,9 @@ describe("EncryptedERC20", function () { encryptedAllowanceAmount.inputProof, ); - input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input = this.instances.carol.createEncryptedInput(this.encryptedERC20Address, this.signers.carol.address); input.add64(transferAmount); - const encryptedTransferAmount = input.encrypt(); + const encryptedTransferAmount = await input.encrypt(); tx = await this.encryptedERC20 .connect(this.signers.carol) @@ -339,11 +343,11 @@ describe("EncryptedERC20", function () { ).to.be.revertedWithCustomError(this.encryptedERC20, "TFHESenderNotAllowed"); }); - it("Sender who is not allowed cannot approve using a handle from another account", async function () { + it("sender who is not allowed cannot approve using a handle from another account", async function () { const amount = 100_000; const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); input.add64(amount); - const encryptedAllowanceAmount = input.encrypt(); + const encryptedAllowanceAmount = await input.encrypt(); const tx = await this.encryptedERC20 .connect(this.signers.alice) From 904df243dcad8ae8d438d52b1db8cab9f5e61fce Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:17:17 +0100 Subject: [PATCH 32/73] style: Prettier --- .env.example | 2 +- package.json | 5 +++-- tsconfig.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 88ddfce..a7105e0 100644 --- a/.env.example +++ b/.env.example @@ -8,4 +8,4 @@ export PRIVATE_KEY_COPROCESSOR_ACCOUNT="83e0173b9d07abd53958da9f417df515b0957c4f export IS_COPROCESSOR="true" export SEPOLIA_RPC_URL="https://sepolia.infura.io/v3/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -export ETHERSCAN_API_KEY="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \ No newline at end of file +export ETHERSCAN_API_KEY="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" diff --git a/package.json b/package.json index 47fe958..ea68d3e 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,8 @@ "access": "public" }, "scripts": { - "clean": "rimraf ./fhevmTemp ./artifacts ./cache ./coverage ./types ./coverage.json && pnpm typechain", "compile": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat compile", + "clean": "rimraf ./fhevmTemp ./artifacts ./cache ./coverage ./types ./coverage.json && pnpm typechain", + "compile": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat compile", "deploy:contracts": "hardhat deploy", "docgen": "hardhat docgen", "lint": "npm run lint:sol && npm run lint:ts && npm run prettier:check", @@ -99,4 +100,4 @@ "extra-bigint": "^1.1.18", "sqlite3": "^5.1.7" } -} \ No newline at end of file +} diff --git a/tsconfig.json b/tsconfig.json index 31a8f3a..f5ef6d3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,4 +19,4 @@ "exclude": ["node_modules"], "files": ["./hardhat.config.ts"], "include": ["src/**/*", "tasks/**/*", "test/**/*", "deploy/**/*", "types/"] -} \ No newline at end of file +} From 2d61656b115236ecbbe222c002121cdc9d19cb4f Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:19:26 +0100 Subject: [PATCH 33/73] chore: Remove TestAsyncDecrypt.sol and test --- contracts/test/TestAsyncDecrypt.sol | 354 ------------------------- test/oracleDecrypt/testAsyncDecrypt.ts | 234 ---------------- 2 files changed, 588 deletions(-) delete mode 100644 contracts/test/TestAsyncDecrypt.sol delete mode 100644 test/oracleDecrypt/testAsyncDecrypt.ts diff --git a/contracts/test/TestAsyncDecrypt.sol b/contracts/test/TestAsyncDecrypt.sol deleted file mode 100644 index 8110011..0000000 --- a/contracts/test/TestAsyncDecrypt.sol +++ /dev/null @@ -1,354 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause-Clear -pragma solidity ^0.8.24; - -import "fhevm/lib/TFHE.sol"; -import "fhevm/gateway/GatewayCaller.sol"; - -/** - * @title TestAsyncDecrypt - * @notice This test contract is used to test the Gateway. - */ -contract TestAsyncDecrypt is GatewayCaller { - ebool internal xBool; - euint4 internal xUint4; - euint8 internal xUint8; - euint16 internal xUint16; - euint32 internal xUint32; - euint64 internal xUint64; - euint64 internal xUint64_2; - euint64 internal xUint64_3; - eaddress internal xAddress; - eaddress internal xAddress2; - - bool public yBool; - uint8 public yUint4; - uint8 public yUint8; - uint16 public yUint16; - uint32 public yUint32; - uint64 public yUint64; - uint64 public yUint64_2; - uint64 public yUint64_3; - address public yAddress; - address public yAddress2; - bytes public yBytes256; - - uint256 public latestRequestID; - - constructor() { - xBool = TFHE.asEbool(true); - TFHE.allow(xBool, address(this)); - xUint4 = TFHE.asEuint4(4); - TFHE.allow(xUint4, address(this)); - xUint8 = TFHE.asEuint8(42); - TFHE.allow(xUint8, address(this)); - xUint16 = TFHE.asEuint16(16); - TFHE.allow(xUint16, address(this)); - xUint32 = TFHE.asEuint32(32); - TFHE.allow(xUint32, address(this)); - xUint64 = TFHE.asEuint64(18446744073709551600); - TFHE.allow(xUint64, address(this)); - xUint64_2 = TFHE.asEuint64(76575465786); - TFHE.allow(xUint64_2, address(this)); - xUint64_3 = TFHE.asEuint64(6400); - TFHE.allow(xUint64_3, address(this)); - xAddress = TFHE.asEaddress(0x8ba1f109551bD432803012645Ac136ddd64DBA72); - TFHE.allow(xAddress, address(this)); - xAddress2 = TFHE.asEaddress(0xf48b8840387ba3809DAE990c930F3b4766A86ca3); - TFHE.allow(xAddress2, address(this)); - } - - function requestBoolInfinite() public { - uint256[] memory cts = new uint256[](1); - cts[0] = Gateway.toUint256(xBool); - Gateway.requestDecryption(cts, this.callbackBoolInfinite.selector, 0, block.timestamp + 100, false); - } - - function callbackBoolInfinite(uint256 /*requestID*/, bool decryptedInput) public onlyGateway returns (bool) { - uint256 i = 0; - while (true) { - i++; - } - yBool = decryptedInput; - return yBool; - } - - function requestBoolAboveDelay() public { - // should revert - uint256[] memory cts = new uint256[](1); - cts[0] = Gateway.toUint256(xBool); - Gateway.requestDecryption(cts, this.callbackBool.selector, 0, block.timestamp + 2 days, false); - } - - function requestBool() public { - uint256[] memory cts = new uint256[](1); - cts[0] = Gateway.toUint256(xBool); - Gateway.requestDecryption(cts, this.callbackBool.selector, 0, block.timestamp + 100, false); - } - - function requestBoolTrustless() public { - uint256[] memory cts = new uint256[](1); - cts[0] = Gateway.toUint256(xBool); - uint256 requestID = Gateway.requestDecryption( - cts, - this.callbackBoolTrustless.selector, - 0, - block.timestamp + 100, - true - ); - latestRequestID = requestID; - saveRequestedHandles(requestID, cts); - } - - function requestFakeBool() public { - uint256[] memory cts = new uint256[](1); - cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000000); - // this should revert because previous ebool is not honestly obtained - Gateway.requestDecryption(cts, this.callbackBool.selector, 0, block.timestamp + 100, false); - } - - function callbackBool(uint256, bool decryptedInput) public onlyGateway returns (bool) { - yBool = decryptedInput; - return yBool; - } - - function callbackBoolTrustless( - uint256 requestID, - bool decryptedInput, - bytes[] memory signatures - ) public onlyGateway returns (bool) { - require(latestRequestID == requestID, "wrong requestID passed by Gateway"); - uint256[] memory requestedHandles = loadRequestedHandles(latestRequestID); - bool isKMSVerified = Gateway.verifySignatures(requestedHandles, signatures); - require(isKMSVerified, "KMS did not verify this decryption result"); - yBool = decryptedInput; - return yBool; - } - - function requestUint4() public { - uint256[] memory cts = new uint256[](1); - cts[0] = Gateway.toUint256(xUint4); - Gateway.requestDecryption(cts, this.callbackUint4.selector, 0, block.timestamp + 100, false); - } - - function requestFakeUint4() public { - uint256[] memory cts = new uint256[](1); - cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000100); - // this should revert because previous handle is not honestly obtained - Gateway.requestDecryption(cts, this.callbackUint4.selector, 0, block.timestamp + 100, false); - } - - function callbackUint4(uint256, uint8 decryptedInput) public onlyGateway returns (uint8) { - yUint4 = decryptedInput; - return decryptedInput; - } - - function requestUint8() public { - uint256[] memory cts = new uint256[](1); - cts[0] = Gateway.toUint256(xUint8); - Gateway.requestDecryption(cts, this.callbackUint8.selector, 0, block.timestamp + 100, false); - } - - function requestFakeUint8() public { - uint256[] memory cts = new uint256[](1); - cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000200); - // this should revert because previous handle is not honestly obtained - Gateway.requestDecryption(cts, this.callbackUint8.selector, 0, block.timestamp + 100, false); - } - - function callbackUint8(uint256, uint8 decryptedInput) public onlyGateway returns (uint8) { - yUint8 = decryptedInput; - return decryptedInput; - } - - function requestUint16() public { - uint256[] memory cts = new uint256[](1); - cts[0] = Gateway.toUint256(xUint16); - Gateway.requestDecryption(cts, this.callbackUint16.selector, 0, block.timestamp + 100, false); - } - - function requestFakeUint16() public { - uint256[] memory cts = new uint256[](1); - cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000300); - // this should revert because previous handle is not honestly obtained - Gateway.requestDecryption(cts, this.callbackUint16.selector, 0, block.timestamp + 100, false); - } - - function callbackUint16(uint256, uint16 decryptedInput) public onlyGateway returns (uint16) { - yUint16 = decryptedInput; - return decryptedInput; - } - - function requestUint32(uint32 input1, uint32 input2) public { - uint256[] memory cts = new uint256[](1); - cts[0] = Gateway.toUint256(xUint32); - uint256 requestID = Gateway.requestDecryption( - cts, - this.callbackUint32.selector, - 0, - block.timestamp + 100, - false - ); - addParamsUint256(requestID, input1); - addParamsUint256(requestID, input2); - } - - function requestFakeUint32() public { - uint256[] memory cts = new uint256[](1); - cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000400); - // this should revert because previous handle is not honestly obtained - Gateway.requestDecryption(cts, this.callbackUint32.selector, 0, block.timestamp + 100, false); - } - - function callbackUint32(uint256 requestID, uint32 decryptedInput) public onlyGateway returns (uint32) { - uint256[] memory params = getParamsUint256(requestID); - unchecked { - uint32 result = uint32(params[0]) + uint32(params[1]) + decryptedInput; - yUint32 = result; - return result; - } - } - - function requestUint64() public { - uint256[] memory cts = new uint256[](1); - cts[0] = Gateway.toUint256(xUint64); - Gateway.requestDecryption(cts, this.callbackUint64.selector, 0, block.timestamp + 100, false); - } - - function requestFakeUint64() public { - uint256[] memory cts = new uint256[](1); - cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000500); - // this should revert because previous handle is not honestly obtained - Gateway.requestDecryption(cts, this.callbackUint64.selector, 0, block.timestamp + 100, false); - } - - function requestUint64NonTrivial(einput inputHandle, bytes calldata inputProof) public { - euint64 inputNonTrivial = TFHE.asEuint64(inputHandle, inputProof); - uint256[] memory cts = new uint256[](1); - cts[0] = Gateway.toUint256(inputNonTrivial); - Gateway.requestDecryption(cts, this.callbackUint64.selector, 0, block.timestamp + 100, false); - } - - function callbackUint64(uint256, uint64 decryptedInput) public onlyGateway returns (uint64) { - yUint64 = decryptedInput; - return decryptedInput; - } - - function requestEbytes256NonTrivial(einput inputHandle, bytes calldata inputProof) public { - ebytes256 inputNonTrivial = TFHE.asEbytes256(inputHandle, inputProof); - uint256[] memory cts = new uint256[](1); - cts[0] = Gateway.toUint256(inputNonTrivial); - Gateway.requestDecryption(cts, this.callbackBytes256.selector, 0, block.timestamp + 100, false); - } - - function callbackBytes256(uint256, bytes calldata decryptedInput) public onlyGateway returns (bytes memory) { - yBytes256 = decryptedInput; - return decryptedInput; - } - - function requestAddress() public { - uint256[] memory cts = new uint256[](1); - cts[0] = Gateway.toUint256(xAddress); - Gateway.requestDecryption(cts, this.callbackAddress.selector, 0, block.timestamp + 100, false); - } - - function requestSeveralAddresses() public { - uint256[] memory cts = new uint256[](2); - cts[0] = Gateway.toUint256(xAddress); - cts[1] = Gateway.toUint256(xAddress2); - Gateway.requestDecryption(cts, this.callbackAddresses.selector, 0, block.timestamp + 100, false); - } - - function callbackAddresses( - uint256 /*requestID*/, - address decryptedInput1, - address decryptedInput2 - ) public onlyGateway returns (address) { - yAddress = decryptedInput1; - yAddress2 = decryptedInput2; - return decryptedInput1; - } - - function requestFakeAddress() public { - uint256[] memory cts = new uint256[](1); - cts[0] = uint256(0x4200000000000000000000000000000000000000000000000000000000000700); - // this should revert because previous handle is not honestly obtained - Gateway.requestDecryption(cts, this.callbackAddress.selector, 0, block.timestamp + 100, false); - } - - function callbackAddress(uint256, address decryptedInput) public onlyGateway returns (address) { - yAddress = decryptedInput; - return decryptedInput; - } - - function requestMixed(uint32 input1, uint32 input2) public { - uint256[] memory cts = new uint256[](10); - cts[0] = Gateway.toUint256(xBool); - cts[1] = Gateway.toUint256(xBool); - cts[2] = Gateway.toUint256(xUint4); - cts[3] = Gateway.toUint256(xUint8); - cts[4] = Gateway.toUint256(xUint16); - cts[5] = Gateway.toUint256(xUint32); - cts[6] = Gateway.toUint256(xUint64); - cts[7] = Gateway.toUint256(xUint64); - cts[8] = Gateway.toUint256(xUint64); - cts[9] = Gateway.toUint256(xAddress); - uint256 requestID = Gateway.requestDecryption( - cts, - this.callbackMixed.selector, - 0, - block.timestamp + 100, - false - ); - addParamsUint256(requestID, input1); - addParamsUint256(requestID, input2); - } - - function callbackMixed( - uint256 requestID, - bool decBool_1, - bool decBool_2, - uint8 decUint4, - uint8 decUint8, - uint16 decUint16, - uint32 decUint32, - uint64 decUint64_1, - uint64 decUint64_2, - uint64 decUint64_3, - address decAddress - ) public onlyGateway returns (uint8) { - yBool = decBool_1; - require(decBool_1 == decBool_2, "Wrong decryption"); - yUint4 = decUint4; - yUint8 = decUint8; - yUint16 = decUint16; - uint256[] memory params = getParamsUint256(requestID); - unchecked { - uint32 result = uint32(params[0]) + uint32(params[1]) + decUint32; - yUint32 = result; - } - yUint64 = decUint64_1; - require(decUint64_1 == decUint64_2 && decUint64_2 == decUint64_3, "Wrong decryption"); - yAddress = decAddress; - return yUint4; - } - - function requestMixedBytes256(einput inputHandle, bytes calldata inputProof) public { - ebytes256 xBytes256 = TFHE.asEbytes256(inputHandle, inputProof); - uint256[] memory cts = new uint256[](3); - cts[0] = Gateway.toUint256(xBool); - cts[1] = Gateway.toUint256(xAddress); - cts[2] = Gateway.toUint256(xBytes256); - Gateway.requestDecryption(cts, this.callbackMixedBytes256.selector, 0, block.timestamp + 100, false); - } - - function callbackMixedBytes256( - uint256, - bool decBool, - address decAddress, - bytes memory bytesRes - ) public onlyGateway { - yBool = decBool; - yAddress = decAddress; - yBytes256 = bytesRes; - } -} diff --git a/test/oracleDecrypt/testAsyncDecrypt.ts b/test/oracleDecrypt/testAsyncDecrypt.ts deleted file mode 100644 index 9eb7435..0000000 --- a/test/oracleDecrypt/testAsyncDecrypt.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { expect } from "chai"; -import { ethers, network } from "hardhat"; - -import { asyncDecrypt, awaitAllDecryptionResults } from "../asyncDecrypt"; -import { getSigners, initSigners } from "../signers"; - -describe("TestAsyncDecrypt", function () { - before(async function () { - await asyncDecrypt(); - await initSigners(3); - this.signers = await getSigners(); - }); - - beforeEach(async function () { - const contractFactory = await ethers.getContractFactory("TestAsyncDecrypt"); - this.contract = await contractFactory.connect(this.signers.alice).deploy(); - }); - - it("test async decrypt bool would fail if maxTimestamp is above 1 day", async function () { - if (network.name === "hardhat") { - // mocked mode - await expect(this.contract.connect(this.signers.carol).requestBoolAboveDelay()).to.be.revertedWith( - "maxTimestamp exceeded MAX_DELAY", - ); - } else { - // fhevm-mode - const tx = await this.contract.connect(this.signers.carol).requestBoolAboveDelay({ gasLimit: 1_000_000 }); - await expect(tx.wait()).to.throw; - } - }); - - it("test async decrypt bool", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestBool({ gasLimit: 500_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yBool(); - expect(y).to.equal(true); - }); - - it("test async decrypt FAKE bool", async function () { - if (network.name !== "hardhat") { - // only in fhevm mode - const txObject = await this.contract - .connect(this.signers.carol) - .requestFakeBool.populateTransaction({ gasLimit: 5_000_000 }); - const tx = await this.signers.carol.sendTransaction(txObject); - let receipt = null; - let waitTime = 0; - while (receipt === null && waitTime < 15000) { - receipt = await ethers.provider.getTransactionReceipt(tx.hash); - if (receipt === null) { - console.log("Trying again to fetch txn receipt...."); - await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait for 5 seconds - waitTime += 5000; - } - } - expect(waitTime >= 15000).to.be.true; - } - }); - - it("test async decrypt uint4", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint4({ gasLimit: 500_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yUint4(); - expect(y).to.equal(4); - }); - - it("test async decrypt FAKE uint4", async function () { - if (network.name !== "hardhat") { - // only in fhevm mode - const txObject = await this.contract - .connect(this.signers.carol) - .requestFakeUint4.populateTransaction({ gasLimit: 5_000_000 }); - const tx = await this.signers.carol.sendTransaction(txObject); - let receipt = null; - let waitTime = 0; - while (receipt === null && waitTime < 15000) { - receipt = await ethers.provider.getTransactionReceipt(tx.hash); - if (receipt === null) { - console.log("Trying again to fetch txn receipt...."); - await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait for 5 seconds - waitTime += 5000; - } - } - expect(waitTime >= 15000).to.be.true; - } - }); - - it("test async decrypt uint8", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint8({ gasLimit: 500_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yUint8(); - expect(y).to.equal(42); - }); - - it("test async decrypt FAKE uint8", async function () { - if (network.name !== "hardhat") { - // only in fhevm mode - const txObject = await this.contract - .connect(this.signers.carol) - .requestFakeUint8.populateTransaction({ gasLimit: 5_000_000 }); - const tx = await this.signers.carol.sendTransaction(txObject); - let receipt = null; - let waitTime = 0; - while (receipt === null && waitTime < 15000) { - receipt = await ethers.provider.getTransactionReceipt(tx.hash); - if (receipt === null) { - console.log("Trying again to fetch txn receipt...."); - await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait for 5 seconds - waitTime += 5000; - } - } - expect(waitTime >= 15000).to.be.true; - } - }); - - it("test async decrypt uint16", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint16({ gasLimit: 500_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yUint16(); - expect(y).to.equal(16); - }); - - it("test async decrypt FAKE uint16", async function () { - if (network.name !== "hardhat") { - // only in fhevm mode - const txObject = await this.contract - .connect(this.signers.carol) - .requestFakeUint16.populateTransaction({ gasLimit: 5_000_000 }); - const tx = await this.signers.carol.sendTransaction(txObject); - let receipt = null; - let waitTime = 0; - while (receipt === null && waitTime < 15000) { - receipt = await ethers.provider.getTransactionReceipt(tx.hash); - if (receipt === null) { - console.log("Trying again to fetch txn receipt...."); - await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait for 5 seconds - waitTime += 5000; - } - } - expect(waitTime >= 15000).to.be.true; - } - }); - - it("test async decrypt uint32", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint32(5, 15, { gasLimit: 500_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yUint32(); - expect(y).to.equal(52); // 5+15+32 - }); - - it("test async decrypt FAKE uint32", async function () { - if (network.name !== "hardhat") { - // only in fhevm mode - const txObject = await this.contract - .connect(this.signers.carol) - .requestFakeUint32.populateTransaction({ gasLimit: 5_000_000 }); - const tx = await this.signers.carol.sendTransaction(txObject); - let receipt = null; - let waitTime = 0; - while (receipt === null && waitTime < 15000) { - receipt = await ethers.provider.getTransactionReceipt(tx.hash); - if (receipt === null) { - console.log("Trying again to fetch txn receipt...."); - await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait for 5 seconds - waitTime += 5000; - } - } - expect(waitTime >= 15000).to.be.true; - } - }); - - it("test async decrypt uint64", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint64({ gasLimit: 500_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yUint64(); - expect(y).to.equal(64); - }); - - it("test async decrypt FAKE uint64", async function () { - if (network.name !== "hardhat") { - // only in fhevm mode - const txObject = await this.contract - .connect(this.signers.carol) - .requestFakeUint64.populateTransaction({ gasLimit: 5_000_000 }); - const tx = await this.signers.carol.sendTransaction(txObject); - let receipt = null; - let waitTime = 0; - while (receipt === null && waitTime < 15000) { - receipt = await ethers.provider.getTransactionReceipt(tx.hash); - if (receipt === null) { - console.log("Trying again to fetch txn receipt...."); - await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait for 5 seconds - waitTime += 5000; - } - } - expect(waitTime >= 15000).to.be.true; - } - }); - - it("test async decrypt address", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestAddress({ gasLimit: 500_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yAddress(); - expect(y).to.equal("0x8ba1f109551bD432803012645Ac136ddd64DBA72"); - }); - - it("test async decrypt FAKE address", async function () { - if (network.name !== "hardhat") { - // only in fhevm mode - const txObject = await this.contract - .connect(this.signers.carol) - .requestFakeAddress.populateTransaction({ gasLimit: 5_000_000 }); - const tx = await this.signers.carol.sendTransaction(txObject); - let receipt = null; - let waitTime = 0; - while (receipt === null && waitTime < 15000) { - receipt = await ethers.provider.getTransactionReceipt(tx.hash); - if (receipt === null) { - console.log("Trying again to fetch txn receipt...."); - await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait for 5 seconds - waitTime += 5000; - } - } - expect(waitTime >= 15000).to.be.true; - } - }); -}); From 4d60dac2e895b416675c38d1dda53cbfc1cf2a9d Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:21:52 +0100 Subject: [PATCH 34/73] chore: Remove old test --- test/gatewayDecrypt/testAsyncDecrypt.ts | 217 ------------------------ 1 file changed, 217 deletions(-) delete mode 100644 test/gatewayDecrypt/testAsyncDecrypt.ts diff --git a/test/gatewayDecrypt/testAsyncDecrypt.ts b/test/gatewayDecrypt/testAsyncDecrypt.ts deleted file mode 100644 index 8ae7ef4..0000000 --- a/test/gatewayDecrypt/testAsyncDecrypt.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { expect } from "chai"; -import { ethers, network } from "hardhat"; - -import { asyncDecrypt, awaitAllDecryptionResults } from "../asyncDecrypt"; -import { createInstances } from "../instance"; -import { getSigners, initSigners } from "../signers"; -import { bigIntToBytes, waitNBlocks } from "../utils"; - -describe("TestAsyncDecrypt", function () { - before(async function () { - - await initSigners(); - this.signers = await getSigners(); - this.relayerAddress = "0x97F272ccfef4026A1F3f0e0E879d514627B84E69"; - - // very first request of decryption always fail at the moment due to a gateway bug - // TODO: remove following 8 lines when the gateway bug will be fixed - const contractFactory = await ethers.getContractFactory("TestAsyncDecrypt"); - - this.contract = await contractFactory.connect(this.signers.alice).deploy(); - - await this.contract.waitForDeployment(); - - this.contractAddress = await this.contract.getAddress(); - this.instances = await createInstances(this.signers); - const tx = await this.contract.connect(this.signers.carol).requestUint8({ gasLimit: 5_000_000 }); - await tx.wait(); // this first request is here just to silence the current gateway bug at the moment - await waitNBlocks(1); - - await asyncDecrypt(); - - }); - - beforeEach(async function () { - const contractFactory = await ethers.getContractFactory("TestAsyncDecrypt"); - this.contract = await contractFactory.connect(this.signers.alice).deploy(); - await this.contract.waitForDeployment(); - this.contractAddress = await this.contract.getAddress(); - this.instances = await createInstances(this.signers); - }); - - it("test async decrypt bool", async function () { - const balanceBeforeR = await ethers.provider.getBalance(this.relayerAddress); - const balanceBeforeU = await ethers.provider.getBalance(this.signers.carol.address); - const tx2 = await this.contract.connect(this.signers.carol).requestBool({ gasLimit: 5_000_000 }); - await tx2.wait(); - const balanceAfterU = await ethers.provider.getBalance(this.signers.carol.address); - await awaitAllDecryptionResults(); - const y = await this.contract.yBool(); - expect(y).to.equal(true); - const balanceAfterR = await ethers.provider.getBalance(this.relayerAddress); - console.log("gas paid by relayer (fulfil tx) : ", balanceBeforeR - balanceAfterR); - console.log("gas paid by user (request tx) : ", balanceBeforeU - balanceAfterU); - }); - - it("test async decrypt uint4", async function () { - const balanceBefore = await ethers.provider.getBalance(this.relayerAddress); - const tx2 = await this.contract.connect(this.signers.carol).requestUint4({ gasLimit: 5_000_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yUint4(); - expect(y).to.equal(4); - const balanceAfter = await ethers.provider.getBalance(this.relayerAddress); - console.log(balanceBefore - balanceAfter); - }); - - it("test async decrypt uint8", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint8({ gasLimit: 5_000_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yUint8(); - expect(y).to.equal(42); - }); - - it("test async decrypt uint16", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint16({ gasLimit: 5_000_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yUint16(); - expect(y).to.equal(16); - }); - - it("test async decrypt uint32", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint32(5, 15, { gasLimit: 5_000_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yUint32(); - expect(y).to.equal(52); // 5+15+32 - }); - - it("test async decrypt uint64", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint64({ gasLimit: 5_000_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yUint64(); - expect(y).to.equal(18446744073709551600n); - }); - - it("test async decrypt address", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestAddress({ gasLimit: 5_000_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yAddress(); - expect(y).to.equal("0x8ba1f109551bD432803012645Ac136ddd64DBA72"); - }); - - it("test async decrypt several addresses", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestSeveralAddresses({ gasLimit: 5_000_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yAddress(); - const y2 = await this.contract.yAddress2(); - expect(y).to.equal("0x8ba1f109551bD432803012645Ac136ddd64DBA72"); - expect(y2).to.equal("0xf48b8840387ba3809DAE990c930F3b4766A86ca3"); - }); - - it("test async decrypt mixed", async function () { - const contractFactory = await ethers.getContractFactory("TestAsyncDecrypt"); - const contract2 = await contractFactory.connect(this.signers.alice).deploy(); - const tx2 = await contract2.connect(this.signers.carol).requestMixed(5, 15, { gasLimit: 5_000_000 }); - await tx2.wait(); - await awaitAllDecryptionResults(); - const yB = await contract2.yBool(); - expect(yB).to.equal(true); - let y = await contract2.yUint4(); - expect(y).to.equal(4); - y = await contract2.yUint8(); - expect(y).to.equal(42); - y = await contract2.yUint16(); - expect(y).to.equal(16); - const yAdd = await contract2.yAddress(); - expect(yAdd).to.equal("0x8ba1f109551bD432803012645Ac136ddd64DBA72"); - y = await contract2.yUint32(); - expect(y).to.equal(52); // 5+15+32 - y = await contract2.yUint64(); - expect(y).to.equal(18446744073709551600n); - }); - - it("test async decrypt uint64 non-trivial", async function () { - // console.log(this.instances.alice) - // console.log(this.instances.alice.address) - const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); - inputAlice.add64(18446744073709550042n); - const encryptedAmount = inputAlice.encrypt(); - const tx = await this.contract.requestUint64NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof, { - gasLimit: 5_000_000, - }); - await tx.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yUint64(); - expect(y).to.equal(18446744073709550042n); - }); - - it("test async decrypt ebytes256 non-trivial", async function () { - const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); - inputAlice.addBytes256(bigIntToBytes(18446744073709550022n)); - const encryptedAmount = inputAlice.encrypt(); - const tx = await await this.contract.requestEbytes256NonTrivial( - encryptedAmount.handles[0], - encryptedAmount.inputProof, - { gasLimit: 5_000_000 }, - ); - await tx.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yBytes256(); - expect(y).to.equal(ethers.toBeHex(18446744073709550022n, 256)); - }); - - it("test async decrypt ebytes256 non-trivial with snapshot [skip-on-coverage]", async function () { - if (network.name === "hardhat") { - this.snapshotId = await ethers.provider.send("evm_snapshot"); - const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); - inputAlice.addBytes256(bigIntToBytes(18446744073709550022n)); - const encryptedAmount = inputAlice.encrypt(); - const tx = await await this.contract.requestEbytes256NonTrivial( - encryptedAmount.handles[0], - encryptedAmount.inputProof, - { gasLimit: 5_000_000 }, - ); - await tx.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yBytes256(); - expect(y).to.equal(ethers.toBeHex(18446744073709550022n, 256)); - - await ethers.provider.send("evm_revert", [this.snapshotId]); - const inputAlice2 = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); - inputAlice2.addBytes256(bigIntToBytes(424242n)); - const encryptedAmount2 = inputAlice2.encrypt(); - const tx2 = await await this.contract.requestEbytes256NonTrivial( - encryptedAmount2.handles[0], - encryptedAmount2.inputProof, - { gasLimit: 5_000_000 }, - ); - await tx2.wait(); - await awaitAllDecryptionResults(); - const y2 = await this.contract.yBytes256(); - expect(y2).to.equal(ethers.toBeHex(424242n, 256)); - } - }); - - it("test async decrypt mixed with ebytes256", async function () { - const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); - inputAlice.addBytes256(bigIntToBytes(18446744073709550032n)); - const encryptedAmount = inputAlice.encrypt(); - const tx = await await this.contract.requestMixedBytes256(encryptedAmount.handles[0], encryptedAmount.inputProof, { - gasLimit: 5_000_000, - }); - await tx.wait(); - await awaitAllDecryptionResults(); - const y = await this.contract.yBytes256(); - expect(y).to.equal(ethers.toBeHex(18446744073709550032n, 256)); - const yb = await this.contract.yBool(); - expect(yb).to.equal(true); - const yAdd = await this.contract.yAddress(); - expect(yAdd).to.equal("0x8ba1f109551bD432803012645Ac136ddd64DBA72"); - }); -}); From 054c9289899eb94808746e80499c1bc8c3936639 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:22:27 +0100 Subject: [PATCH 35/73] style: Prettier --- tasks/taskDeploy.ts | 2 +- tasks/taskGatewayRelayer.ts | 2 +- tasks/taskTFHE.ts | 2 +- test/operatorsPrices.json | 1020 +++++++++++++++++------------------ 4 files changed, 513 insertions(+), 513 deletions(-) diff --git a/tasks/taskDeploy.ts b/tasks/taskDeploy.ts index 3b2e9a6..f7395ce 100644 --- a/tasks/taskDeploy.ts +++ b/tasks/taskDeploy.ts @@ -153,4 +153,4 @@ task("task:addSigners") console.log(`KMS signer no${idx} (${kmsSignerAddress}) was added to KMSVerifier contract`); } } - }); \ No newline at end of file + }); diff --git a/tasks/taskGatewayRelayer.ts b/tasks/taskGatewayRelayer.ts index 22ae85b..581d508 100644 --- a/tasks/taskGatewayRelayer.ts +++ b/tasks/taskGatewayRelayer.ts @@ -163,4 +163,4 @@ task("task:faucetToAddress") await getCoin(receiverAddress); await new Promise((res) => setTimeout(res, 5000)); // wait 5 seconds } - }); \ No newline at end of file + }); diff --git a/tasks/taskTFHE.ts b/tasks/taskTFHE.ts index 1ddc6c7..e5c3e37 100644 --- a/tasks/taskTFHE.ts +++ b/tasks/taskTFHE.ts @@ -211,4 +211,4 @@ address constant fhePaymentAdd = ${fhePaymentAddress};\n`; } catch (error) { console.error("Failed to write ./node_modules/fhevm-core-contracts/addresses/FHEPaymentAddress.sol", error); } - }); \ No newline at end of file + }); diff --git a/test/operatorsPrices.json b/test/operatorsPrices.json index dcf4897..8c861dc 100644 --- a/test/operatorsPrices.json +++ b/test/operatorsPrices.json @@ -1,530 +1,530 @@ { - "fheAdd": { - "binary": true, - "scalar": { - "1": 65000, - "2": 94000, - "3": 133000, - "4": 162000, - "5": 188000, - "6": 218000, - "8": 253000 - }, - "nonScalar": { - "1": 65000, - "2": 94000, - "3": 133000, - "4": 162000, - "5": 188000, - "6": 218000, - "8": 253000 - } + "fheAdd": { + "binary": true, + "scalar": { + "1": 65000, + "2": 94000, + "3": 133000, + "4": 162000, + "5": 188000, + "6": 218000, + "8": 253000 }, - "fheSub": { - "binary": true, - "scalar": { - "1": 65000, - "2": 94000, - "3": 133000, - "4": 162000, - "5": 188000, - "6": 218000, - "8": 253000 - }, - "nonScalar": { - "1": 65000, - "2": 94000, - "3": 133000, - "4": 162000, - "5": 188000, - "6": 218000, - "8": 253000 - } - }, - "fheMul": { - "binary": true, - "scalar": { - "1": 88000, - "2": 159000, - "3": 208000, - "4": 264000, - "5": 356000, - "6": 480000, - "8": 647000 - }, - "nonScalar": { - "1": 150000, - "2": 197000, - "3": 262000, - "4": 359000, - "5": 641000, - "6": 1145000, - "8": 2045000 - } - }, - "fheDiv": { - "binary": true, - "scalar": { - "1": 139000, - "2": 238000, - "3": 314000, - "4": 398000, - "5": 584000, - "6": 857000, - "8": 1258000 - } - }, - "fheRem": { - "binary": true, - "scalar": { - "1": 286000, - "2": 460000, - "3": 622000, - "4": 805000, - "5": 1095000, - "6": 1499000, - "8": 2052000 - } - }, - "fheBitAnd": { - "binary": true, - "scalar": { - "0": 26000, - "1": 32000, - "2": 34000, - "3": 34000, - "4": 35000, - "5": 38000, - "6": 41000, - "8": 44000 - }, - "nonScalar": { - "0": 26000, - "1": 32000, - "2": 34000, - "3": 34000, - "4": 35000, - "5": 38000, - "6": 41000, - "8": 44000 - } - }, - "fheBitOr": { - "binary": true, - "scalar": { - "0": 26000, - "1": 32000, - "2": 34000, - "3": 34000, - "4": 35000, - "5": 38000, - "6": 41000, - "8": 44000 - }, - "nonScalar": { - "0": 26000, - "1": 32000, - "2": 34000, - "3": 34000, - "4": 35000, - "5": 38000, - "6": 41000, - "8": 44000 - } - }, - "fheBitXor": { - "binary": true, - "scalar": { - "0": 26000, - "1": 32000, - "2": 34000, - "3": 34000, - "4": 35000, - "5": 38000, - "6": 41000, - "8": 44000 - }, - "nonScalar": { - "0": 26000, - "1": 32000, - "2": 34000, - "3": 34000, - "4": 35000, - "5": 38000, - "6": 41000, - "8": 44000 - } - }, - "fheShl": { - "binary": true, - "scalar": { - "1": 35000, - "2": 35000, - "3": 35000, - "4": 35000, - "5": 38000, - "6": 41000, - "8": 44000 - }, - "nonScalar": { - "1": 116000, - "2": 133000, - "3": 153000, - "4": 183000, - "5": 227000, - "6": 282000, - "8": 350000 - } - }, - "fheShr": { - "binary": true, - "scalar": { - "1": 35000, - "2": 35000, - "3": 35000, - "4": 35000, - "5": 38000, - "6": 41000, - "8": 44000 - }, - "nonScalar": { - "1": 116000, - "2": 133000, - "3": 153000, - "4": 183000, - "5": 227000, - "6": 282000, - "8": 350000 - } + "nonScalar": { + "1": 65000, + "2": 94000, + "3": 133000, + "4": 162000, + "5": 188000, + "6": 218000, + "8": 253000 + } + }, + "fheSub": { + "binary": true, + "scalar": { + "1": 65000, + "2": 94000, + "3": 133000, + "4": 162000, + "5": 188000, + "6": 218000, + "8": 253000 }, - "fheRotl": { - "binary": true, - "scalar": { - "1": 35000, - "2": 35000, - "3": 35000, - "4": 35000, - "5": 38000, - "6": 41000, - "8": 44000 - }, - "nonScalar": { - "1": 116000, - "2": 133000, - "3": 153000, - "4": 183000, - "5": 227000, - "6": 282000, - "8": 350000 - } + "nonScalar": { + "1": 65000, + "2": 94000, + "3": 133000, + "4": 162000, + "5": 188000, + "6": 218000, + "8": 253000 + } + }, + "fheMul": { + "binary": true, + "scalar": { + "1": 88000, + "2": 159000, + "3": 208000, + "4": 264000, + "5": 356000, + "6": 480000, + "8": 647000 }, - "fheRotr": { - "binary": true, - "scalar": { - "1": 35000, - "2": 35000, - "3": 35000, - "4": 35000, - "5": 38000, - "6": 41000, - "8": 44000 - }, - "nonScalar": { - "1": 116000, - "2": 133000, - "3": 153000, - "4": 183000, - "5": 227000, - "6": 282000, - "8": 350000 - } + "nonScalar": { + "1": 150000, + "2": 197000, + "3": 262000, + "4": 359000, + "5": 641000, + "6": 1145000, + "8": 2045000 + } + }, + "fheDiv": { + "binary": true, + "scalar": { + "1": 139000, + "2": 238000, + "3": 314000, + "4": 398000, + "5": 584000, + "6": 857000, + "8": 1258000 + } + }, + "fheRem": { + "binary": true, + "scalar": { + "1": 286000, + "2": 460000, + "3": 622000, + "4": 805000, + "5": 1095000, + "6": 1499000, + "8": 2052000 + } + }, + "fheBitAnd": { + "binary": true, + "scalar": { + "0": 26000, + "1": 32000, + "2": 34000, + "3": 34000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 }, - "fheEq": { - "binary": true, - "scalar": { - "0": 49000, - "1": 51000, - "2": 53000, - "3": 54000, - "4": 82000, - "5": 86000, - "6": 88000, - "7": 90000, - "8": 100000, - "9": 150000, - "10": 200000, - "11": 300000 - }, - "nonScalar": { - "0": 49000, - "1": 51000, - "2": 53000, - "3": 54000, - "4": 82000, - "5": 86000, - "6": 88000, - "7": 90000, - "8": 100000, - "9": 150000, - "10": 200000, - "11": 300000 - } + "nonScalar": { + "0": 26000, + "1": 32000, + "2": 34000, + "3": 34000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 + } + }, + "fheBitOr": { + "binary": true, + "scalar": { + "0": 26000, + "1": 32000, + "2": 34000, + "3": 34000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 }, - "fheNe": { - "binary": true, - "scalar": { - "0": 49000, - "1": 51000, - "2": 53000, - "3": 54000, - "4": 82000, - "5": 86000, - "6": 88000, - "7": 90000, - "8": 100000, - "9": 150000, - "10": 200000, - "11": 300000 - }, - "nonScalar": { - "0": 49000, - "1": 51000, - "2": 53000, - "3": 54000, - "4": 82000, - "5": 86000, - "6": 88000, - "7": 90000, - "8": 100000, - "9": 150000, - "10": 200000, - "11": 300000 - } + "nonScalar": { + "0": 26000, + "1": 32000, + "2": 34000, + "3": 34000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 + } + }, + "fheBitXor": { + "binary": true, + "scalar": { + "0": 26000, + "1": 32000, + "2": 34000, + "3": 34000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 }, - "fheGe": { - "binary": true, - "scalar": { - "1": 70000, - "2": 82000, - "3": 105000, - "4": 128000, - "5": 156000, - "6": 190000, - "8": 231000 - }, - "nonScalar": { - "1": 70000, - "2": 82000, - "3": 105000, - "4": 128000, - "5": 156000, - "6": 190000, - "8": 231000 - } + "nonScalar": { + "0": 26000, + "1": 32000, + "2": 34000, + "3": 34000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 + } + }, + "fheShl": { + "binary": true, + "scalar": { + "1": 35000, + "2": 35000, + "3": 35000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 }, - "fheGt": { - "binary": true, - "scalar": { - "1": 70000, - "2": 82000, - "3": 105000, - "4": 128000, - "5": 156000, - "6": 190000, - "8": 231000 - }, - "nonScalar": { - "1": 70000, - "2": 82000, - "3": 105000, - "4": 128000, - "5": 156000, - "6": 190000, - "8": 231000 - } + "nonScalar": { + "1": 116000, + "2": 133000, + "3": 153000, + "4": 183000, + "5": 227000, + "6": 282000, + "8": 350000 + } + }, + "fheShr": { + "binary": true, + "scalar": { + "1": 35000, + "2": 35000, + "3": 35000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 }, - "fheLe": { - "binary": true, - "scalar": { - "1": 70000, - "2": 82000, - "3": 105000, - "4": 128000, - "5": 156000, - "6": 190000, - "8": 231000 - }, - "nonScalar": { - "1": 70000, - "2": 82000, - "3": 105000, - "4": 128000, - "5": 156000, - "6": 190000, - "8": 231000 - } + "nonScalar": { + "1": 116000, + "2": 133000, + "3": 153000, + "4": 183000, + "5": 227000, + "6": 282000, + "8": 350000 + } + }, + "fheRotl": { + "binary": true, + "scalar": { + "1": 35000, + "2": 35000, + "3": 35000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 }, - "fheLt": { - "binary": true, - "scalar": { - "1": 70000, - "2": 82000, - "3": 105000, - "4": 128000, - "5": 156000, - "6": 190000, - "8": 231000 - }, - "nonScalar": { - "1": 70000, - "2": 82000, - "3": 105000, - "4": 128000, - "5": 156000, - "6": 190000, - "8": 231000 - } + "nonScalar": { + "1": 116000, + "2": 133000, + "3": 153000, + "4": 183000, + "5": 227000, + "6": 282000, + "8": 350000 + } + }, + "fheRotr": { + "binary": true, + "scalar": { + "1": 35000, + "2": 35000, + "3": 35000, + "4": 35000, + "5": 38000, + "6": 41000, + "8": 44000 }, - "fheMin": { - "binary": true, - "scalar": { - "1": 121000, - "2": 128000, - "3": 150000, - "4": 164000, - "5": 192000, - "6": 225000, - "8": 264000 - }, - "nonScalar": { - "1": 121000, - "2": 128000, - "3": 153000, - "4": 183000, - "5": 210000, - "6": 241000, - "8": 277000 - } + "nonScalar": { + "1": 116000, + "2": 133000, + "3": 153000, + "4": 183000, + "5": 227000, + "6": 282000, + "8": 350000 + } + }, + "fheEq": { + "binary": true, + "scalar": { + "0": 49000, + "1": 51000, + "2": 53000, + "3": 54000, + "4": 82000, + "5": 86000, + "6": 88000, + "7": 90000, + "8": 100000, + "9": 150000, + "10": 200000, + "11": 300000 }, - "fheMax": { - "binary": true, - "scalar": { - "1": 121000, - "2": 128000, - "3": 150000, - "4": 164000, - "5": 192000, - "6": 225000, - "8": 264000 - }, - "nonScalar": { - "1": 121000, - "2": 128000, - "3": 153000, - "4": 183000, - "5": 210000, - "6": 241000, - "8": 277000 - } + "nonScalar": { + "0": 49000, + "1": 51000, + "2": 53000, + "3": 54000, + "4": 82000, + "5": 86000, + "6": 88000, + "7": 90000, + "8": 100000, + "9": 150000, + "10": 200000, + "11": 300000 + } + }, + "fheNe": { + "binary": true, + "scalar": { + "0": 49000, + "1": 51000, + "2": 53000, + "3": 54000, + "4": 82000, + "5": 86000, + "6": 88000, + "7": 90000, + "8": 100000, + "9": 150000, + "10": 200000, + "11": 300000 }, - "fheNeg": { - "binary": false, - "types": { - "1": 60000, - "2": 95000, - "3": 131000, - "4": 160000, - "5": 199000, - "6": 248000, - "8": 309000 - } + "nonScalar": { + "0": 49000, + "1": 51000, + "2": 53000, + "3": 54000, + "4": 82000, + "5": 86000, + "6": 88000, + "7": 90000, + "8": 100000, + "9": 150000, + "10": 200000, + "11": 300000 + } + }, + "fheGe": { + "binary": true, + "scalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 }, - "fheNot": { - "binary": false, - "types": { - "0": 30000, - "1": 33000, - "2": 34000, - "3": 35000, - "4": 36000, - "5": 37000, - "6": 38000, - "8": 39000 - } + "nonScalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 + } + }, + "fheGt": { + "binary": true, + "scalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 }, - "cast": { - "binary": false, - "types": { - "0": 200, - "1": 200, - "2": 200, - "3": 200, - "4": 200, - "5": 200, - "6": 200, - "8": 200 - } + "nonScalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 + } + }, + "fheLe": { + "binary": true, + "scalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 }, - "trivialEncrypt": { - "binary": false, - "types": { - "0": 100, - "1": 100, - "2": 100, - "3": 200, - "4": 300, - "5": 600, - "6": 650, - "7": 700, - "8": 800, - "9": 1600, - "10": 3200, - "11": 6400 - } + "nonScalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 + } + }, + "fheLt": { + "binary": true, + "scalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 }, - "ifThenElse": { - "binary": false, - "types": { - "0": 43000, - "1": 45000, - "2": 47000, - "3": 47000, - "4": 50000, - "5": 53000, - "6": 70000, - "7": 80000, - "8": 90000, - "9": 150000, - "10": 200000, - "11": 300000 - } + "nonScalar": { + "1": 70000, + "2": 82000, + "3": 105000, + "4": 128000, + "5": 156000, + "6": 190000, + "8": 231000 + } + }, + "fheMin": { + "binary": true, + "scalar": { + "1": 121000, + "2": 128000, + "3": 150000, + "4": 164000, + "5": 192000, + "6": 225000, + "8": 264000 }, - "fheRand": { - "binary": false, - "types": { - "0": 100000, - "1": 100000, - "2": 100000, - "3": 100000, - "4": 100000, - "5": 100000, - "6": 100000, - "8": 100000, - "9": 200000, - "10": 300000, - "11": 400000 - } + "nonScalar": { + "1": 121000, + "2": 128000, + "3": 153000, + "4": 183000, + "5": 210000, + "6": 241000, + "8": 277000 + } + }, + "fheMax": { + "binary": true, + "scalar": { + "1": 121000, + "2": 128000, + "3": 150000, + "4": 164000, + "5": 192000, + "6": 225000, + "8": 264000 }, - "fheRandBounded": { - "binary": false, - "types": { - "1": 100000, - "2": 100000, - "3": 100000, - "4": 100000, - "5": 100000, - "6": 100000, - "8": 100000 - } + "nonScalar": { + "1": 121000, + "2": 128000, + "3": 153000, + "4": 183000, + "5": 210000, + "6": 241000, + "8": 277000 + } + }, + "fheNeg": { + "binary": false, + "types": { + "1": 60000, + "2": 95000, + "3": 131000, + "4": 160000, + "5": 199000, + "6": 248000, + "8": 309000 + } + }, + "fheNot": { + "binary": false, + "types": { + "0": 30000, + "1": 33000, + "2": 34000, + "3": 35000, + "4": 36000, + "5": 37000, + "6": 38000, + "8": 39000 + } + }, + "cast": { + "binary": false, + "types": { + "0": 200, + "1": 200, + "2": 200, + "3": 200, + "4": 200, + "5": 200, + "6": 200, + "8": 200 + } + }, + "trivialEncrypt": { + "binary": false, + "types": { + "0": 100, + "1": 100, + "2": 100, + "3": 200, + "4": 300, + "5": 600, + "6": 650, + "7": 700, + "8": 800, + "9": 1600, + "10": 3200, + "11": 6400 + } + }, + "ifThenElse": { + "binary": false, + "types": { + "0": 43000, + "1": 45000, + "2": 47000, + "3": 47000, + "4": 50000, + "5": 53000, + "6": 70000, + "7": 80000, + "8": 90000, + "9": 150000, + "10": 200000, + "11": 300000 + } + }, + "fheRand": { + "binary": false, + "types": { + "0": 100000, + "1": 100000, + "2": 100000, + "3": 100000, + "4": 100000, + "5": 100000, + "6": 100000, + "8": 100000, + "9": 200000, + "10": 300000, + "11": 400000 + } + }, + "fheRandBounded": { + "binary": false, + "types": { + "1": 100000, + "2": 100000, + "3": 100000, + "4": 100000, + "5": 100000, + "6": 100000, + "8": 100000 } -} \ No newline at end of file + } +} From 6742fa14314cf32c5f7e73028980ac371d5af3ac Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Tue, 29 Oct 2024 12:08:59 +0100 Subject: [PATCH 36/73] refactor: EncryptedErrors for EncryptedERC20 --- contracts/token/ERC20/IEncryptedERC20.sol | 2 +- .../extensions/EncryptedERC20WithErrors.sol | 154 ++++++++++++++++++ .../EncryptedERC20WithErrorsMintable.sol | 44 +++++ contracts/utils/EncryptedErrors.sol | 145 +++-------------- 4 files changed, 226 insertions(+), 119 deletions(-) create mode 100644 contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol create mode 100644 contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol diff --git a/contracts/token/ERC20/IEncryptedERC20.sol b/contracts/token/ERC20/IEncryptedERC20.sol index 08c2631..6841d57 100644 --- a/contracts/token/ERC20/IEncryptedERC20.sol +++ b/contracts/token/ERC20/IEncryptedERC20.sol @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: UNLICENSED +// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; diff --git a/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol b/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol new file mode 100644 index 0000000..43beb8c --- /dev/null +++ b/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import "fhevm/lib/TFHE.sol"; +import { EncryptedERC20 } from "../EncryptedERC20.sol"; +import { EncryptedErrors } from "../../../utils/EncryptedErrors.sol"; + +/** + * @title EncryptedERC20WithErrors + * @notice This contract implements an encrypted ERC20-like token with confidential balances using + * Zama's FHE (Fully Homomorphic Encryption) library. + * @dev It supports standard ERC20 functions such as transferring tokens, minting, + * and setting allowances, but uses encrypted data types. + * The total supply is not encrypted. + * It also supports error handling for encrypted errors. + */ + +abstract contract EncryptedERC20WithErrors is EncryptedERC20, EncryptedErrors { + /** + * @notice Emitted when tokens are moved from one account (`from`) to + * another (`to`). + */ + event TransferWithErrorHandling(address indexed from, address indexed to, uint256 transferId); + + /** + * @notice Error codes allow tracking (in the storage) whether a transfer worked. + * @dev NO_ERROR: the transfer worked as expected + * UNSUFFICIENT_BALANCE: the transfer failed because the + * from balances were strictly inferior to the amount to transfer. + * UNSUFFICIENT_APPROVAL: the transfer failed because the sender allowance + * was strictly lower than the amount to transfer. + */ + enum ErrorCodes { + NO_ERROR, + UNSUFFICIENT_BALANCE, + UNSUFFICIENT_APPROVAL + } + + /// @notice Keeps track of the current transferId. + uint256 private _transferIdCounter; + + /// @notice A mapping from transferId to the error code. + mapping(uint256 transferId => euint8 errorCode) internal _errorCodeForTransferId; + + /** + * @param name_ Name of the token. + * @param symbol_ Symbol. + */ + constructor( + string memory name_, + string memory symbol_ + ) EncryptedERC20(name_, symbol_) EncryptedErrors(uint8(type(ErrorCodes).max)) {} + + /** + * @notice See {IEncryptedERC20-transfer}. + */ + function transfer(address to, euint64 amount) public virtual override returns (bool) { + _isSenderAllowedForAmount(amount); + + // Make sure the owner has enough tokens + ebool canTransfer = TFHE.le(amount, _balances[msg.sender]); + + euint8 errorCode = TFHE.select( + canTransfer, + _errorCodes[uint8(ErrorCodes.NO_ERROR)], + _errorCodes[uint8(ErrorCodes.UNSUFFICIENT_BALANCE)] + ); + + _transferWithErrorCode(msg.sender, to, amount, canTransfer, errorCode); + return true; + } + + /** + * @notice See {IEncryptedERC20-transferFrom}. + */ + function transferFrom(address from, address to, euint64 amount) public virtual override returns (bool) { + _isSenderAllowedForAmount(amount); + address spender = msg.sender; + (ebool isTransferable, euint8 errorCode) = _updateAllowanceWithErrorCode(from, spender, amount); + _transferWithErrorCode(from, to, amount, isTransferable, errorCode); + return true; + } + + /** + * @notice Returns the error code corresponding to `transferId`. + */ + function getErrorCodeForTransferId(uint256 transferId) external view virtual returns (euint8 errorCode) { + return _errorCodeForTransferId[transferId]; + } + + function _transferWithErrorCode( + address from, + address to, + euint64 amount, + ebool isTransferable, + euint8 errorCode + ) internal virtual { + // Add to the balance of `to` and subract from the balance of `from`. + euint64 transferValue = TFHE.select(isTransferable, amount, TFHE.asEuint64(0)); + euint64 newBalanceTo = TFHE.add(_balances[to], transferValue); + _balances[to] = newBalanceTo; + + TFHE.allow(newBalanceTo, address(this)); + TFHE.allow(newBalanceTo, to); + + euint64 newBalanceFrom = TFHE.sub(_balances[from], transferValue); + _balances[from] = newBalanceFrom; + + TFHE.allow(newBalanceFrom, address(this)); + TFHE.allow(newBalanceFrom, from); + + emit TransferWithErrorHandling(from, to, _transferIdCounter); + + // Set error code in the storage and increment + _errorCodeForTransferId[_transferIdCounter++] = errorCode; + + TFHE.allowThis(errorCode); + TFHE.allow(errorCode, from); + TFHE.allow(errorCode, to); + } + + function _updateAllowanceWithErrorCode( + address owner, + address spender, + euint64 amount + ) internal virtual returns (ebool isTransferable, euint8 errorCode) { + euint64 currentAllowance = _allowance(owner, spender); + + // Make sure sure the allowance suffices + ebool allowedTransfer = TFHE.le(amount, currentAllowance); + + errorCode = TFHE.select( + allowedTransfer, + _errorCodes[uint8(ErrorCodes.UNSUFFICIENT_APPROVAL)], + _errorCodes[uint8(ErrorCodes.NO_ERROR)] + ); + + // Make sure the owner has enough tokens + ebool canTransfer = TFHE.le(amount, _balances[owner]); + + errorCode = TFHE.select( + TFHE.eq(errorCode, 0), + TFHE.select( + canTransfer, + _errorCodes[uint8(ErrorCodes.UNSUFFICIENT_BALANCE)], + _errorCodes[uint8(ErrorCodes.NO_ERROR)] + ), + errorCode + ); + + isTransferable = TFHE.and(canTransfer, allowedTransfer); + _approve(owner, spender, TFHE.select(isTransferable, TFHE.sub(currentAllowance, amount), currentAllowance)); + } +} diff --git a/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol b/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol new file mode 100644 index 0000000..20c1926 --- /dev/null +++ b/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import "fhevm/lib/TFHE.sol"; +import { Ownable2Step, Ownable } from "@openzeppelin/contracts/access/Ownable2Step.sol"; + +import { EncryptedERC20WithErrors } from "./EncryptedERC20WithErrors.sol"; + +/** + * @title EncryptedERC20WithErrorsMintable + * @notice This contract inherits EncryptedERC20WithErrors. + * @dev It allows an owner to mint tokens. Mint amounts are public. + */ +contract EncryptedERC20WithErrorsMintable is Ownable2Step, EncryptedERC20WithErrors { + /** + * @notice Emitted when `amount` tokens are minted to one account (`to`). + */ + event Mint(address indexed to, uint64 amount); + + /** + * @param name_ Name of the token. + * @param symbol_ Symbol. + * @param owner_ Owner address. + */ + constructor( + string memory name_, + string memory symbol_, + address owner_ + ) Ownable(owner_) EncryptedERC20WithErrors(name_, symbol_) {} + + /** + * @notice Mint tokens. + * @param amount Amount of tokens to mint. + */ + function mint(uint64 amount) public onlyOwner { + _balances[msg.sender] = TFHE.add(_balances[msg.sender], amount); + TFHE.allow(_balances[msg.sender], address(this)); + TFHE.allow(_balances[msg.sender], msg.sender); + /// @dev Since _totalSupply is not encrypted and _totalSupply >= balances[msg.sender], + /// the next line contains an overflow check for the encrypted operation above. + _totalSupply = _totalSupply + amount; + emit Mint(msg.sender, amount); + } +} diff --git a/contracts/utils/EncryptedErrors.sol b/contracts/utils/EncryptedErrors.sol index b9347d8..f415790 100644 --- a/contracts/utils/EncryptedErrors.sol +++ b/contracts/utils/EncryptedErrors.sol @@ -1,140 +1,49 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear - pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; /** - * This abstract contract is used for error handling in the fhEVM. - * - * Error codes are trivially encrypted during construction inside the `errorCodes` array. - * - * WARNING: `errorCodes[0]` should always refer to the `NO_ERROR` code, by default. - * + * @notice This abstract contract is used for error handling in the fhEVM. + * Error codes are encrypted in the constructor inside the `errorCodes` mapping. + * @dev `errorCodes[0]` should always refer to the `NO_ERROR` code, by default. */ abstract contract EncryptedErrors { - uint8 private immutable totalNumErrors; - euint8[] private errorCodes; - uint256 private counterErrors; // used to keep track of each error index + /// @notice The total number of errors is equal to zero. + error TotalNumberErrorsEqualToZero(); + + /// @notice Total number of errors. + uint8 private immutable _TOTAL_NUMBER_ERRORS; - // A mapping from errorId to the errorCode - mapping(uint256 => euint8) private errorCodesMapping; + /// @notice Mapping of error codes. + /// @dev It does not use arrays they are more expensive than mappings. + mapping(uint8 errorCode => euint8 encryptedErrorCode) internal _errorCodes; /** * @notice Sets the non-null value for `numErrors` corresponding to the total number of errors. - * @param numErrors the total number of different errors. - * @dev `numErrors` must be non-null, note that `errorCodes[0]` corresponds to the `NO_ERROR` code. + * @param totalNumberErrors_ total number of different errors. + * @dev `numErrors` must be non-null (`errorCodes[0]` corresponds to the `NO_ERROR` code). */ - constructor(uint8 numErrors) { - require(numErrors != 0, "numErrors must be greater than 0"); - for (uint256 i = 0; i <= numErrors; i++) { - errorCodes.push(TFHE.asEuint8(i)); + constructor(uint8 totalNumberErrors_) { + if (totalNumberErrors_ == 0) { + revert TotalNumberErrorsEqualToZero(); } - totalNumErrors = numErrors; - } - /** - * @notice Returns the encrypted error code at index `indexCode`. - * @param indexCode the index of the requested error code. - * @return the encrypted error code located at `indexCode`. - */ - function getErrorCode(uint8 indexCode) internal view returns (euint8) { - return errorCodes[indexCode]; - } - - /** - * @notice Returns the total number of error codes currently stored in `errorCodesMapping`. - * @return the number of error codes stored in the `errorCodesMapping` mapping. - */ - function getErrorCounter() internal view returns (uint256) { - return counterErrors; - } - - /** - * @notice Returns the total number of the possible errors. - * @return the total number of the different possible errors. - */ - function getNumErrors() internal view returns (uint8) { - return totalNumErrors; - } - - /** - * @notice Returns the encrypted error code which was stored in the mapping at key `errorId`. - * @param errorId the requested key stored in the `errorCodesMapping` mapping. - * @return the encrypted error code located at the `errorId` key. - * @dev `errorId` must be a valid id, i.e below the error counter. - */ - function getError(uint256 errorId) internal view returns (euint8) { - require(errorId < counterErrors, "errorId must be a valid id"); - return errorCodesMapping[errorId]; - } - - /** - * @notice Computes an encrypted error code, result will be either a reencryption of - * `errorCodes[indexCode]` if `condition` is an encrypted `true` or of `NO_ERROR` otherwise. - * @param condition the encrypted boolean used in the cmux. - * @param indexCode the index of the selected error code if `condition` encrypts `true`. - * @return the reencrypted error code depending on `condition` value. - * @dev `indexCode` must be non-null and below the total number of error codes. - */ - function defineErrorIf(ebool condition, uint8 indexCode) internal view returns (euint8) { - require(indexCode != 0, "indexCode must be greater than 0"); - require(indexCode <= totalNumErrors, "indexCode must be a valid error code"); - euint8 errorCode = TFHE.select(condition, errorCodes[indexCode], errorCodes[0]); - return errorCode; - } - - /** - * @notice Does the opposite of `defineErrorIf`, i.e result will be either a reencryption of - * `errorCodes[indexCode]` if `condition` is an encrypted `false` or of `NO_ERROR` otherwise. - * @param condition the encrypted boolean used in the cmux. - * @param indexCode the index of the selected error code if `condition` encrypts `false`. - * @return the reencrypted error code depending on `condition` value. - * @dev `indexCode` must be non-null and below the total number of error codes. - */ - function defineErrorIfNot(ebool condition, uint8 indexCode) internal view returns (euint8) { - require(indexCode != 0, "indexCode must be greater than 0"); - require(indexCode <= totalNumErrors, "indexCode must be a valid error code"); - euint8 errorCode = TFHE.select(condition, errorCodes[0], errorCodes[indexCode]); - return errorCode; - } - - /** - * @notice Computes an encrypted error code, result will be either a reencryption of - * `errorCodes[indexCode]` if `condition` is an encrypted `true` or of `errorCode` otherwise. - * @param condition the encrypted boolean used in the cmux. - * @param errorCode the selected error code if `condition` encrypts `true`. - * @return the reencrypted error code depending on `condition` value. - * @dev `indexCode` must be below the total number of error codes. - */ - function changeErrorIf(ebool condition, uint8 indexCode, euint8 errorCode) internal view returns (euint8) { - require(indexCode <= totalNumErrors, "indexCode must be a valid error code"); - return TFHE.select(condition, errorCodes[indexCode], errorCode); - } + for (uint8 i; i <= totalNumberErrors_; i++) { + euint8 errorCode = TFHE.asEuint8(i); + _errorCodes[i] = errorCode; + TFHE.allowThis(errorCode); + } - /** - * @notice Does the opposite of `changeErrorIf`, i.e result will be either a reencryption of - * `errorCodes[indexCode]` if `condition` is an encrypted `false` or of `errorCode` otherwise. - * @param condition the encrypted boolean used in the cmux. - * @param errorCode the selected error code if `condition` encrypts `false`. - * @return the reencrypted error code depending on `condition` value. - * @dev `indexCode` must be below the total number of error codes. - */ - function changeErrorIfNot(ebool condition, uint8 indexCode, euint8 errorCode) internal view returns (euint8) { - require(indexCode <= totalNumErrors, "indexCode must be a valid error code"); - return TFHE.select(condition, errorCode, errorCodes[indexCode]); + _TOTAL_NUMBER_ERRORS = totalNumberErrors_; } /** - * @notice Saves `errorCode` in storage, in the `errorCodesMapping` mapping, at the lowest unused key. - * This is the only stateful function of `EncryptedErrors` abstract contract. - * @param errorCode the encrypted error code to be saved in storage. - * @return the `errorId` key in `errorCodesMapping` where `errorCode` is stored. + * @notice Returns the total number of errors. + * @return totalNumberErrors total number of errors. + * @dev It does not count `NO_ERROR` as one of the errors. */ - function saveError(euint8 errorCode) internal returns (uint256) { - uint256 errorId = counterErrors; - counterErrors++; - errorCodesMapping[errorId] = errorCode; - return errorId; + function getTotalNumberErrors() external view returns (uint8 totalNumberErrors) { + return _TOTAL_NUMBER_ERRORS; } } From b095982b2c6ae34aa9328c59147a623cc1e73fa3 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Tue, 29 Oct 2024 12:11:59 +0100 Subject: [PATCH 37/73] test: EncryptedERC20WithErrors --- test/encryptedERC20/EncryptedERC20.test.ts | 10 +- .../EncryptedERC20WithErrors.fixture.ts | 46 ++ .../EncryptedERC20WithErrors.test.ts | 483 ++++++++++++++++++ test/fhevmjsMocked.ts | 1 + 4 files changed, 534 insertions(+), 6 deletions(-) create mode 100644 test/encryptedERC20/EncryptedERC20WithErrors.fixture.ts create mode 100644 test/encryptedERC20/EncryptedERC20WithErrors.test.ts diff --git a/test/encryptedERC20/EncryptedERC20.test.ts b/test/encryptedERC20/EncryptedERC20.test.ts index 11fb213..8536dfa 100644 --- a/test/encryptedERC20/EncryptedERC20.test.ts +++ b/test/encryptedERC20/EncryptedERC20.test.ts @@ -21,6 +21,7 @@ describe("EncryptedERC20", function () { expect(await this.encryptedERC20.totalSupply()).to.equal(0); expect(await this.encryptedERC20.name()).to.equal("Naraggara"); expect(await this.encryptedERC20.symbol()).to.equal("NARA"); + expect(await this.encryptedERC20.decimals()).to.be.eq(BigInt(6)); }); it("should mint the contract", async function () { @@ -40,11 +41,9 @@ describe("EncryptedERC20", function () { const transferAmount = 1337; let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); - const t1 = await tx.wait(); - expect(t1?.status).to.eq(1); + await tx.wait(); const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); - input.add64(transferAmount); const encryptedTransferAmount = await input.encrypt(); @@ -54,8 +53,7 @@ describe("EncryptedERC20", function () { encryptedTransferAmount.inputProof, ); - const t2 = await tx.wait(); - expect(t2?.status).to.eq(1); + await tx.wait(); // Decrypt Alice's balance expect( @@ -74,7 +72,7 @@ describe("EncryptedERC20", function () { const mintAmount = 1000; const transferAmount = 1337; - let tx = await this.encryptedERC20.mint(mintAmount); + let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); await tx.wait(); const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); diff --git a/test/encryptedERC20/EncryptedERC20WithErrors.fixture.ts b/test/encryptedERC20/EncryptedERC20WithErrors.fixture.ts new file mode 100644 index 0000000..14d1519 --- /dev/null +++ b/test/encryptedERC20/EncryptedERC20WithErrors.fixture.ts @@ -0,0 +1,46 @@ +import { ethers } from "hardhat"; + +import type { EncryptedERC20WithErrorsMintable } from "../../types"; +import { reencryptEuint8 } from "../reencrypt"; +import { Signers } from "../signers"; +import { FhevmInstances } from "../types"; + +export async function deployEncryptedERC20WithErrorsFixture( + signers: Signers, + name: string, + symbol: string, + owner: string, +): Promise { + const contractFactory = await ethers.getContractFactory("EncryptedERC20WithErrorsMintable"); + const contract = await contractFactory + .connect(signers[owner as keyof Signers]) + .deploy(name, symbol, signers[owner as keyof Signers].address); + await contract.waitForDeployment(); + return contract; +} + +export async function checkErrorCode( + signers: Signers, + instances: FhevmInstances, + user: string, + transferId: bigint, + token: EncryptedERC20WithErrorsMintable, + tokenAddress: string, +): Promise { + const errorCodeHandle = await token.getErrorCodeForTransferId(transferId); + const errorCode = await reencryptEuint8(signers, instances, user, errorCodeHandle, tokenAddress); + switch (errorCode) { + case BigInt(0): { + return "NO_ERROR"; + } + case BigInt(1): { + return "UNSUFFICIENT_BALANCE"; + } + case BigInt(2): { + return "UNSUFFICIENT_APPROVAL"; + } + default: { + throw "Error code is invalid"; + } + } +} diff --git a/test/encryptedERC20/EncryptedERC20WithErrors.test.ts b/test/encryptedERC20/EncryptedERC20WithErrors.test.ts new file mode 100644 index 0000000..a244c93 --- /dev/null +++ b/test/encryptedERC20/EncryptedERC20WithErrors.test.ts @@ -0,0 +1,483 @@ +import { expect } from "chai"; + +import { createInstances } from "../instance"; +import { getSigners, initSigners } from "../signers"; +import { reencryptAllowance, reencryptBalance } from "./EncryptedERC20.fixture"; +import { checkErrorCode, deployEncryptedERC20WithErrorsFixture } from "./EncryptedERC20WithErrors.fixture"; + +describe("EncryptedERC20WithErrors", function () { + const DEFAULT_TRANSFER_ID = BigInt(0); + const DEFAULT_SECOND_TRANSFER_ID = BigInt(1); + + before(async function () { + await initSigners(2); + this.signers = await getSigners(); + }); + + beforeEach(async function () { + const contract = await deployEncryptedERC20WithErrorsFixture(this.signers, "Naraggara", "NARA", "alice"); + this.encryptedERC20Address = await contract.getAddress(); + this.encryptedERC20 = contract; + this.instances = await createInstances(this.signers); + }); + + it("post-deployment state", async function () { + expect(await this.encryptedERC20.totalSupply()).to.equal(0); + expect(await this.encryptedERC20.name()).to.equal("Naraggara"); + expect(await this.encryptedERC20.symbol()).to.equal("NARA"); + expect(await this.encryptedERC20.decimals()).to.be.eq(BigInt(6)); + expect(await this.encryptedERC20.getTotalNumberErrors()).to.be.eq(BigInt(2)); + }); + + it("should mint the contract", async function () { + const mintAmount = 1000; + const tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); + await tx.wait(); + + expect( + await reencryptBalance(this.signers, this.instances, "alice", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(mintAmount); + + expect(await this.encryptedERC20.totalSupply()).to.equal(mintAmount); + }); + + it("should transfer tokens between two users", async function () { + const mintAmount = 10_000; + const transferAmount = 1337; + + let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); + await tx.wait(); + + const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = await input.encrypt(); + + tx = await this.encryptedERC20 + .connect(this.signers.alice) + ["transfer(address,bytes32,bytes)"]( + this.signers.bob.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + + await tx.wait(); + + // Decrypt Alice's balance + expect( + await reencryptBalance(this.signers, this.instances, "alice", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(mintAmount - transferAmount); + + // Decrypt Bob's balance + expect( + await reencryptBalance(this.signers, this.instances, "bob", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(transferAmount); + + // Check the error code matches no error + expect( + await checkErrorCode( + this.signers, + this.instances, + "alice", + DEFAULT_TRANSFER_ID, + this.encryptedERC20, + this.encryptedERC20Address, + ), + ).to.equal("NO_ERROR"); + + // Check that both the from/to address can read the error code + expect( + await checkErrorCode( + this.signers, + this.instances, + "bob", + DEFAULT_TRANSFER_ID, + this.encryptedERC20, + this.encryptedERC20Address, + ), + ).to.equal("NO_ERROR"); + }); + + it("should not transfer tokens between two users if transfer amount is higher than balance", async function () { + // @dev There is no transfer done since the mint amount is smaller than the transfer + // amount. + const mintAmount = 1000; + const transferAmount = 1337; + + let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); + await tx.wait(); + + const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = await input.encrypt(); + tx = await this.encryptedERC20["transfer(address,bytes32,bytes)"]( + this.signers.bob.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + await tx.wait(); + + // Decrypt Alice's balance + expect( + await reencryptBalance(this.signers, this.instances, "alice", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(mintAmount); + + // Decrypt Bob's balance + expect( + await reencryptBalance(this.signers, this.instances, "bob", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(0); + + // Check that the error code matches if balance is not sufficient + expect( + await checkErrorCode( + this.signers, + this.instances, + "bob", + DEFAULT_TRANSFER_ID, + this.encryptedERC20, + this.encryptedERC20Address, + ), + ).to.equal("UNSUFFICIENT_BALANCE"); + }); + + it("should be able to transferFrom only if allowance is sufficient", async function () { + // @dev There is no transfer done since the mint amount is smaller than the transfer + // amount. + const mintAmount = 10_000; + const transferAmount = 1337; + + let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); + await tx.wait(); + + const inputAlice = this.instances.alice.createEncryptedInput( + this.encryptedERC20Address, + this.signers.alice.address, + ); + inputAlice.add64(transferAmount); + const encryptedAllowanceAmount = await inputAlice.encrypt(); + + tx = await this.encryptedERC20["approve(address,bytes32,bytes)"]( + this.signers.bob.address, + encryptedAllowanceAmount.handles[0], + encryptedAllowanceAmount.inputProof, + ); + await tx.wait(); + + // @dev The allowance amount is set to be equal to the transfer amount. + expect( + await reencryptAllowance( + this.signers, + this.instances, + "alice", + "bob", + this.encryptedERC20, + this.encryptedERC20Address, + ), + ).to.equal(transferAmount); + + const bobErc20 = this.encryptedERC20.connect(this.signers.bob); + const inputBob1 = this.instances.bob.createEncryptedInput(this.encryptedERC20Address, this.signers.bob.address); + inputBob1.add64(transferAmount + 1); // above allowance so next tx should actually not send any token + const encryptedTransferAmount = await inputBob1.encrypt(); + + const tx2 = await bobErc20["transferFrom(address,address,bytes32,bytes)"]( + this.signers.alice.address, + this.signers.bob.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + await tx2.wait(); + + // Decrypt Alice's balance + expect( + await reencryptBalance(this.signers, this.instances, "alice", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(mintAmount); // check that transfer did not happen, as expected + + // Decrypt Bob's balance + expect( + await reencryptBalance(this.signers, this.instances, "bob", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(0); // check that transfer did not happen, as expected + + // Check that the error code matches if balance is not sufficient + expect( + await checkErrorCode( + this.signers, + this.instances, + "bob", + DEFAULT_TRANSFER_ID, + this.encryptedERC20, + this.encryptedERC20Address, + ), + ).to.equal("UNSUFFICIENT_BALANCE"); + + const inputBob2 = this.instances.bob.createEncryptedInput(this.encryptedERC20Address, this.signers.bob.address); + inputBob2.add64(transferAmount); // below allowance so next tx should send token + const encryptedTransferAmount2 = await inputBob2.encrypt(); + + const tx3 = await bobErc20["transferFrom(address,address,bytes32,bytes)"]( + this.signers.alice.address, + this.signers.bob.address, + encryptedTransferAmount2.handles[0], + encryptedTransferAmount2.inputProof, + ); + await tx3.wait(); + + // Decrypt Alice's balance + expect( + await reencryptBalance(this.signers, this.instances, "alice", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(mintAmount - transferAmount); // check that transfer did happen this time + + // Decrypt Bob's balance + expect( + await reencryptBalance(this.signers, this.instances, "bob", this.encryptedERC20, this.encryptedERC20Address), + ).to.equal(transferAmount); // check that transfer did happen this time + + // Verify Alice's allowance is 0 + expect( + await reencryptAllowance( + this.signers, + this.instances, + "alice", + "bob", + this.encryptedERC20, + this.encryptedERC20Address, + ), + ).to.equal(0); + + // Check that the error code matches if allowance is not sufficient + expect( + await checkErrorCode( + this.signers, + this.instances, + "bob", + DEFAULT_SECOND_TRANSFER_ID, + this.encryptedERC20, + this.encryptedERC20Address, + ), + ).to.equal("UNSUFFICIENT_APPROVAL"); + }); + + it("should not be able to read the allowance if not spender/owner after initialization", async function () { + const amount = 10_000; + + const inputAlice = this.instances.alice.createEncryptedInput( + this.encryptedERC20Address, + this.signers.alice.address, + ); + inputAlice.add64(amount); + const encryptedAllowanceAmount = await inputAlice.encrypt(); + + const tx = await this.encryptedERC20 + .connect(this.signers.alice) + ["approve(address,bytes32,bytes)"]( + this.signers.bob.address, + encryptedAllowanceAmount.handles[0], + encryptedAllowanceAmount.inputProof, + ); + + await tx.wait(); + + const allowanceHandleAlice = await this.encryptedERC20.allowance(this.signers.alice, this.signers.bob); + + const { publicKey: publicKeyCarol, privateKey: privateKeyCarol } = this.instances.carol.generateKeypair(); + const eip712Carol = this.instances.carol.createEIP712(publicKeyCarol, this.encryptedERC20Address); + const signatureCarol = await this.signers.carol.signTypedData( + eip712Carol.domain, + { Reencrypt: eip712Carol.types.Reencrypt }, + eip712Carol.message, + ); + + try { + await this.instances.bob.reencrypt( + allowanceHandleAlice, + privateKeyCarol, + publicKeyCarol, + signatureCarol.replace("0x", ""), + this.encryptedERC20Address, + this.signers.carol.address, + ); + + expect.fail("Expected an error to be thrown - Carol should not be able to reencrypt Bob's allowance for Alice"); + } catch (error) { + if (error instanceof Error) { + expect(error.message).to.equal("User is not authorized to reencrypt this handle!"); + } + } + }); + + it("should not be able to read the balance if not user after initialization", async function () { + // Mint is used to initialize the balanceOf(alice) + const amount = 10_000; + const tx = await this.encryptedERC20.connect(this.signers.alice).mint(amount); + await tx.wait(); + + const balanceHandleAlice = await this.encryptedERC20.balanceOf(this.signers.alice); + + const { publicKey: publicKeyBob, privateKey: privateKeyBob } = this.instances.bob.generateKeypair(); + const eip712Bob = this.instances.bob.createEIP712(publicKeyBob, this.encryptedERC20Address); + const signatureBob = await this.signers.bob.signTypedData( + eip712Bob.domain, + { Reencrypt: eip712Bob.types.Reencrypt }, + eip712Bob.message, + ); + + try { + await this.instances.bob.reencrypt( + balanceHandleAlice, + privateKeyBob, + publicKeyBob, + signatureBob.replace("0x", ""), + this.encryptedERC20Address, + this.signers.bob.address, + ); + expect.fail("Expected an error to be thrown - Bob should not be able to reencrypt Alice's balance"); + } catch (error) { + if (error instanceof Error) { + expect(error.message).to.equal("User is not authorized to reencrypt this handle!"); + } + } + }); + + it("sender who is not allowed cannot transfer using a handle from another account", async function () { + const mintAmount = 100_000; + const transferAmount = 50_000; + let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); + await tx.wait(); + + const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = await input.encrypt(); + + tx = await this.encryptedERC20 + .connect(this.signers.alice) + ["transfer(address,bytes32,bytes)"]( + this.signers.carol.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + + await tx.wait(); + + const balanceHandleAlice = await this.encryptedERC20.balanceOf(this.signers.alice.address); + + await expect( + this.encryptedERC20.connect(this.signers.bob).transfer(this.signers.carol.address, balanceHandleAlice), + ).to.be.revertedWithCustomError(this.encryptedERC20, "TFHESenderNotAllowed"); + }); + + it("sender who is not allowed cannot transferFrom using a handle from another account", async function () { + const mintAmount = 100_000; + const transferAmount = 50_000; + + let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); + await tx.wait(); + + let input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(mintAmount); + const encryptedAllowanceAmount = await input.encrypt(); + + tx = await this.encryptedERC20 + .connect(this.signers.alice) + ["approve(address,bytes32,bytes)"]( + this.signers.carol.address, + encryptedAllowanceAmount.handles[0], + encryptedAllowanceAmount.inputProof, + ); + + input = this.instances.carol.createEncryptedInput(this.encryptedERC20Address, this.signers.carol.address); + input.add64(transferAmount); + const encryptedTransferAmount = await input.encrypt(); + + tx = await this.encryptedERC20 + .connect(this.signers.carol) + ["transferFrom(address,address,bytes32,bytes)"]( + this.signers.alice.address, + this.signers.carol.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + + const allowanceHandleAlice = await this.encryptedERC20.allowance( + this.signers.alice.address, + this.signers.carol.address, + ); + + await expect( + this.encryptedERC20 + .connect(this.signers.bob) + .transferFrom(this.signers.alice.address, this.signers.bob.address, allowanceHandleAlice), + ).to.be.revertedWithCustomError(this.encryptedERC20, "TFHESenderNotAllowed"); + }); + + it("cannot reencrypt errors if the account is not a participant of the transfer", async function () { + const mintAmount = 10_000; + const transferAmount = 1337; + let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); + await tx.wait(); + + const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = await input.encrypt(); + + tx = await this.encryptedERC20 + .connect(this.signers.alice) + ["transfer(address,bytes32,bytes)"]( + this.signers.bob.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + + const errorCodeHandle = await this.encryptedERC20.getErrorCodeForTransferId(DEFAULT_TRANSFER_ID); + + const { publicKey: publicKeyCarol, privateKey: privateKeyCarol } = this.instances.carol.generateKeypair(); + const eip712Carol = this.instances.carol.createEIP712(publicKeyCarol, this.encryptedERC20Address); + const signatureCarol = await this.signers.carol.signTypedData( + eip712Carol.domain, + { Reencrypt: eip712Carol.types.Reencrypt }, + eip712Carol.message, + ); + + try { + await this.instances.bob.reencrypt( + errorCodeHandle, + privateKeyCarol, + publicKeyCarol, + signatureCarol.replace("0x", ""), + this.encryptedERC20Address, + this.signers.carol.address, + ); + expect.fail( + "Expected an error to be thrown - Carol should not be able to read the error message from the transaction between Alice and Bob", + ); + } catch (error) { + if (error instanceof Error) { + expect(error.message).to.equal("User is not authorized to reencrypt this handle!"); + } + } + }); + + it("sender who is not allowed cannot approve using a handle from another account", async function () { + const amount = 100_000; + const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(amount); + const encryptedAllowanceAmount = await input.encrypt(); + + const tx = await this.encryptedERC20 + .connect(this.signers.alice) + ["approve(address,bytes32,bytes)"]( + this.signers.carol.address, + encryptedAllowanceAmount.handles[0], + encryptedAllowanceAmount.inputProof, + ); + + await tx.wait(); + + const allowanceHandleAlice = await this.encryptedERC20.allowance( + this.signers.alice.address, + this.signers.carol.address, + ); + + await expect( + this.encryptedERC20.connect(this.signers.bob).approve(this.signers.carol.address, allowanceHandleAlice), + ).to.be.revertedWithCustomError(this.encryptedERC20, "TFHESenderNotAllowed"); + }); +}); diff --git a/test/fhevmjsMocked.ts b/test/fhevmjsMocked.ts index 8a553db..0b19d1f 100644 --- a/test/fhevmjsMocked.ts +++ b/test/fhevmjsMocked.ts @@ -143,6 +143,7 @@ export const reencryptRequestMocked = async ( const acl = aclFactory.attach(aclAdd); const userAllowed = await acl.persistAllowed(handle, userAddress); const contractAllowed = await acl.persistAllowed(handle, contractAddress); + const isAllowed = userAllowed && contractAllowed; if (!isAllowed) { throw new Error("User is not authorized to reencrypt this handle!"); From 290517db5cfa7189a7ea92be1ee18f8e40a2c380 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:36:01 +0100 Subject: [PATCH 38/73] feat: Add mint function --- contracts/token/ERC20/EncryptedERC20.sol | 11 +++++++++++ .../token/ERC20/extensions/EncryptedERC20Mintable.sol | 4 +--- .../extensions/EncryptedERC20WithErrorsMintable.sol | 4 +--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/contracts/token/ERC20/EncryptedERC20.sol b/contracts/token/ERC20/EncryptedERC20.sol index c36bced..b4bc0f2 100644 --- a/contracts/token/ERC20/EncryptedERC20.sol +++ b/contracts/token/ERC20/EncryptedERC20.sol @@ -155,6 +155,17 @@ abstract contract EncryptedERC20 is IEncryptedERC20 { TFHE.allow(amount, spender); } + /** + * @dev It does not incorporate any overflow check. It must be implemented + * by the function calling it. + */ + function _unsafeMint(address account, euint64 amount) internal virtual { + _balances[msg.sender] = TFHE.add(_balances[account], amount); + TFHE.allowThis(_balances[account]); + TFHE.allow(_balances[account], account); + emit Transfer(address(0), account); + } + function _transfer(address from, address to, euint64 amount, ebool isTransferable) internal virtual { // Add to the balance of `to` and subract from the balance of `from`. euint64 transferValue = TFHE.select(isTransferable, amount, TFHE.asEuint64(0)); diff --git a/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol b/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol index 737b4ac..c9f1208 100644 --- a/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol +++ b/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol @@ -33,9 +33,7 @@ contract EncryptedERC20Mintable is Ownable2Step, EncryptedERC20 { * @param amount Amount of tokens to mint. */ function mint(uint64 amount) public onlyOwner { - _balances[msg.sender] = TFHE.add(_balances[msg.sender], amount); - TFHE.allow(_balances[msg.sender], address(this)); - TFHE.allow(_balances[msg.sender], msg.sender); + _unsafeMint(msg.sender, TFHE.asEuint64(amount)); /// @dev Since _totalSupply is not encrypted and _totalSupply >= balances[msg.sender], /// the next line contains an overflow check for the encrypted operation above. _totalSupply = _totalSupply + amount; diff --git a/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol b/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol index 20c1926..0317b54 100644 --- a/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol +++ b/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol @@ -33,9 +33,7 @@ contract EncryptedERC20WithErrorsMintable is Ownable2Step, EncryptedERC20WithErr * @param amount Amount of tokens to mint. */ function mint(uint64 amount) public onlyOwner { - _balances[msg.sender] = TFHE.add(_balances[msg.sender], amount); - TFHE.allow(_balances[msg.sender], address(this)); - TFHE.allow(_balances[msg.sender], msg.sender); + _unsafeMint(msg.sender, TFHE.asEuint64(amount)); /// @dev Since _totalSupply is not encrypted and _totalSupply >= balances[msg.sender], /// the next line contains an overflow check for the encrypted operation above. _totalSupply = _totalSupply + amount; From 11207a052e57e40668a94136dd2b00332d7832a7 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 30 Oct 2024 16:04:17 +0100 Subject: [PATCH 39/73] refactor: Comp.sol --- contracts/DAO/Comp.sol | 349 ++++++++---------- contracts/DAO/CompInterface.sol | 8 + .../{Timelock.sol => CompoundTimelock.sol} | 4 +- contracts/DAO/ICompoundTimelock.sol | 36 ++ 4 files changed, 209 insertions(+), 188 deletions(-) create mode 100644 contracts/DAO/CompInterface.sol rename contracts/DAO/{Timelock.sol => CompoundTimelock.sol} (97%) create mode 100644 contracts/DAO/ICompoundTimelock.sol diff --git a/contracts/DAO/Comp.sol b/contracts/DAO/Comp.sol index 8a23432..072898b 100644 --- a/contracts/DAO/Comp.sol +++ b/contracts/DAO/Comp.sol @@ -1,259 +1,234 @@ // SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.24; -import "fhevm/abstracts/Reencrypt.sol"; import "fhevm/lib/TFHE.sol"; -import "../token/ERC20/EncryptedERC20.sol"; -import "@openzeppelin/contracts/access/Ownable2Step.sol"; - +import { Ownable2Step, Ownable } from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import { EncryptedERC20 } from "../token/ERC20/EncryptedERC20.sol"; + +/** + * @title Comp + * @notice This contract inherits EncryptedERC20. + * This is based on the Comp.sol contract written by Compound Labs. + * It uses encrypted votes to delegate the voting power associated + * with an account's balance. + * @dev The delegation of votes leaks information about the account's encrypted balance to the delegate. + */ contract Comp is EncryptedERC20, Ownable2Step { - /// @notice allowed smart contract - address public allowedContract; + /// @notice Emitted when an account changes its delegate. + event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); - /// @notice A record of each accounts delegate - mapping(address => address) public delegates; + /// @notice Emitted when a delegate account's vote balance changes. + event DelegateVotesChanged(address indexed delegate); - /// @notice A checkpoint for marking number of votes from a given block + /// @notice Emitted when the contract that can reencrypt changes. + event NewAllowedContract(address indexed allowedContract); + + /// @notice A checkpoint for marking number of votes from a given block. + /// @param fromBlock Block from where the checkpoint applies. + /// @param votes Total number of votes for the account power. + /// @dev In Compound's implementation, `fromBlock` is defined as uint32 to allow tight-packing + /// However, in this implementations `votes` is uint256-based. + /// `fromBlock`'s type is set to uint256, which simplifies the codebase. struct Checkpoint { - uint32 fromBlock; + uint256 fromBlock; euint64 votes; } - /// @notice A record of votes checkpoints for each account, by index - mapping(address => mapping(uint32 => Checkpoint)) internal checkpoints; - - /// @notice The number of checkpoints for each account - mapping(address => uint32) public numCheckpoints; - - /// @notice The EIP-712 typehash for the contract's domain + /// @notice The EIP-712 typehash for the contract's domain. bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); - /// @notice The EIP-712 typehash for the delegation struct used by the contract + /// @notice The EIP-712 typehash for the `Delegation` struct. bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); - /// @notice A record of states for signing / validating signatures - mapping(address => uint256) public nonces; - - /// @notice An event thats emitted when an account changes its delegate - event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); + /// @notice The smart contract that can access votes. + address public allowedContract; - /// @notice An event thats emitted when a delegate account's vote balance changes - event DelegateVotesChanged(address indexed delegate); + /// @notice A record of each account's delegate. + mapping(address account => address delegate) public delegates; - /** - * @notice Construct a new Comp token - */ - constructor(address account) EncryptedERC20("Compound", "COMP") Ownable(account) { - _mint(10000000e6, account); // 10 million Comp - } + /// @notice A record of states for signing/validating signatures. + mapping(address account => uint256 nonce) public nonces; - /** - * @notice Set allowed contract that can access votes - * @param contractAddress The address of the smart contract which may access votes - */ - function setAllowedContract(address contractAddress) public onlyOwner { - allowedContract = contractAddress; - } + /// @notice The number of checkpoints for each account. + mapping(address account => uint32 checkpoints) public numCheckpoints; - function _moveDelegates(address srcRep, address dstRep, euint64 amount) internal { - if (srcRep != dstRep) { - if (srcRep != address(0)) { - uint32 srcRepNum = numCheckpoints[srcRep]; - euint64 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : TFHE.asEuint64(0); - euint64 srcRepNew = srcRepOld - amount; - _writeCheckpoint(srcRep, srcRepNum, srcRepNew); - } + /// @notice A record of votes checkpoints for an `account` using incremental indices. + mapping(address account => mapping(uint32 index => Checkpoint checkpoint)) internal checkpoints; - if (dstRep != address(0)) { - uint32 dstRepNum = numCheckpoints[dstRep]; - euint64 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : TFHE.asEuint64(0); - euint64 dstRepNew = dstRepOld + amount; - _writeCheckpoint(dstRep, dstRepNum, dstRepNew); - } - } - } + /// @notice Constant for zero using TFHE + /// @dev Since it is expensive to compute 0, it is stored instead. + /// However, is not possible to define it as constant due to TFHE constraints. + /* solhint-disable var-name-mixedcase*/ + euint64 private _EUINT_64_ZERO; - function _writeCheckpoint(address delegatee, uint32 nCheckpoints, euint64 newVotes) internal { - uint32 blockNumber = safe32(block.number, "Comp::_writeCheckpoint: block number exceeds 32 bits"); + /** + * @param owner Owner address + */ + constructor(address owner) EncryptedERC20("Compound", "COMP") Ownable(owner) { + _unsafeMint(owner, TFHE.asEuint64(10000000e6)); // 10 million Comp + _totalSupply = 10000000e6; - if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) { - checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; - } else { - checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes); - numCheckpoints[delegatee] = nCheckpoints + 1; - } + // @dev Define the constant in the storage. + _EUINT_64_ZERO = TFHE.asEuint64(0); - emit DelegateVotesChanged(delegatee); + TFHE.allowThis(_EUINT_64_ZERO); } /** - * @notice Delegate votes from `msg.sender` to `delegatee` - * @param delegatee The address to delegate votes to + * @notice Delegate votes from `msg.sender` to `delegatee`. + * @param delegatee The address to delegate votes to. */ function delegate(address delegatee) public { return _delegate(msg.sender, delegatee); } - function _transfer( - address from, - address to, - euint64 amount, - ebool isTransferable, - euint8 errorCode - ) internal override { - require(from != address(0), "Comp::_transferTokens: cannot transfer from the zero address"); - require(to != address(0), "Comp::_transferTokens: cannot transfer to the zero address"); - // Add to the balance of `to` and subract from the balance of `from`. - euint64 amountTransferred = TFHE.select(isTransferable, amount, TFHE.asEuint64(0)); - balances[to] = balances[to] + amountTransferred; - balances[from] = balances[from] - amountTransferred; - uint256 transferId = saveError(errorCode); - emit Transfer(transferId, from, to); - AllowedErrorReencryption memory allowedErrorReencryption = AllowedErrorReencryption( - msg.sender, - getError(transferId) - ); - allowedErrorReencryptions[transferId] = allowedErrorReencryption; - _moveDelegates(delegates[from], delegates[to], amountTransferred); - } - /** - * @notice Delegates votes from signatory to `delegatee` - * @param delegatee The address to delegate votes to - * @param nonce The contract state required to match the signature - * @param expiry The time at which to expire the signature - * @param v The recovery byte of the signature - * @param r Half of the ECDSA signature pair - * @param s Half of the ECDSA signature pair + * @notice Delegate votes from signatory to `delegatee`. + * @param delegatee The address to delegate votes to. + * @param nonce The contract state required to match the signature. + * @param expiry The time at which to expire the signature. + * @param v The recovery byte of the signature. + * @param r Half of the ECDSA signature pair. + * @param s Half of the ECDSA signature pair. */ function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) public { bytes32 domainSeparator = keccak256( - abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name())), getChainId(), address(this)) + abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name())), block.chainid, address(this)) ); bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); address signatory = ecrecover(digest, v, r, s); + require(signatory != address(0), "Comp::delegateBySig: invalid signature"); require(nonce == nonces[signatory]++, "Comp::delegateBySig: invalid nonce"); require(block.timestamp <= expiry, "Comp::delegateBySig: signature expired"); return _delegate(signatory, delegatee); } - function getMyCurrentVotes( - bytes32 publicKey, - bytes calldata signature - ) external view onlySignedPublicKey(publicKey, signature) returns (bytes memory) { - uint32 nCheckpoints = numCheckpoints[msg.sender]; - euint64 result = nCheckpoints > 0 ? checkpoints[msg.sender][nCheckpoints - 1].votes : TFHE.asEuint64(0); - return TFHE.reencrypt(result, publicKey, 0); - } - /** - * @notice Determine the prior number of votes for an account as of a block number - * @dev Block number must be a finalized block or else this function will revert to prevent misinformation. - * @param account The address of the account to check - * @param blockNumber The block number to get the vote balance at - * @return The number of votes the account had as of the given block + * @notice Determine the prior number of votes for an account as of a block number. + * @dev Block number must be a finalized block or else this function will revert. + * This function can change the state since the allowedContract needs access in the ACL + * contract. + * @param account Account address. + * @param blockNumber The block number to get the vote balance at. + * @return votes Number of votes the account as of the given block number. */ - function getPriorVotes(address account, uint256 blockNumber) external view onlyAllowedContract returns (euint64) { + function getPriorVotesForAllowedContract(address account, uint256 blockNumber) external returns (euint64 votes) { + require(msg.sender == allowedContract, "Caller not allowed to call this function"); require(blockNumber < block.number, "Comp::getPriorVotes: not yet determined"); + votes = _getPriorVote(account, blockNumber); + TFHE.allow(votes, msg.sender); + } + /** + * @notice Get current votes of account. + * @param account Account address + * @return votes Current votes. + */ + function getCurrentVotes(address account) external view returns (euint64 votes) { uint32 nCheckpoints = numCheckpoints[account]; - if (nCheckpoints == 0) { - return TFHE.asEuint64(0); - } - - // First check most recent balance - if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { - return checkpoints[account][nCheckpoints - 1].votes; - } - - // Next check implicit zero balance - if (checkpoints[account][0].fromBlock > blockNumber) { - return TFHE.asEuint64(0); - } - - uint32 lower = 0; - uint32 upper = nCheckpoints - 1; - while (upper > lower) { - uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow - Checkpoint memory cp = checkpoints[account][center]; - if (cp.fromBlock == blockNumber) { - return cp.votes; - } else if (cp.fromBlock < blockNumber) { - lower = center; - } else { - upper = center - 1; - } - } - return checkpoints[account][lower].votes; + votes = nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : _EUINT_64_ZERO; } - function getMyPriorVotes( - uint256 blockNumber, - bytes32 publicKey, - bytes calldata signature - ) public view onlySignedPublicKey(publicKey, signature) returns (bytes memory) { + /** + * @notice Get the prior number of votes for an account as of a block number. + * @dev Block number must be a finalized block or else this function will revert. + * @param account Account address. + * @param blockNumber The block number to get the vote balance at. + * @return votes Number of votes the account as of the given block. + */ + function getPriorVotes(address account, uint256 blockNumber) external view returns (euint64 votes) { require(blockNumber < block.number, "Comp::getPriorVotes: not yet determined"); + return _getPriorVote(account, blockNumber); + } - uint32 nCheckpoints = numCheckpoints[msg.sender]; - euint64 result; - if (nCheckpoints == 0) { - return TFHE.reencrypt(result, publicKey, 0); - } - - // First check most recent balance - if (checkpoints[msg.sender][nCheckpoints - 1].fromBlock <= blockNumber) { - result = checkpoints[msg.sender][nCheckpoints - 1].votes; - return TFHE.reencrypt(result, publicKey, 0); - } - - // Next check implicit zero balance - if (checkpoints[msg.sender][0].fromBlock > blockNumber) { - return TFHE.reencrypt(result, publicKey, 0); - } - - uint32 lower = 0; - uint32 upper = nCheckpoints - 1; - while (upper > lower) { - uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow - Checkpoint memory cp = checkpoints[msg.sender][center]; - if (cp.fromBlock == blockNumber) { - result = cp.votes; - return TFHE.reencrypt(result, publicKey, 0); - } else if (cp.fromBlock < blockNumber) { - lower = center; - } else { - upper = center - 1; - } - } - result = checkpoints[msg.sender][lower].votes; - return TFHE.reencrypt(result, publicKey, 0); + /** + * @notice Set an allowed contract that can access votes. + * @param contractAddress The address of the smart contract that may access votes. + */ + function setAllowedContract(address contractAddress) public onlyOwner { + allowedContract = contractAddress; + emit NewAllowedContract(contractAddress); } function _delegate(address delegator, address delegatee) internal { address currentDelegate = delegates[delegator]; - euint64 delegatorBalance = balances[delegator]; + euint64 delegatorBalance = _balances[delegator]; + TFHE.allowThis(delegatorBalance); + TFHE.allow(delegatorBalance, msg.sender); delegates[delegator] = delegatee; emit DelegateChanged(delegator, currentDelegate, delegatee); - _moveDelegates(currentDelegate, delegatee, delegatorBalance); } - function safe32(uint256 n, string memory errorMessage) internal pure returns (uint32) { - require(n < 2 ** 32, errorMessage); - return uint32(n); + function _getPriorVote(address account, uint256 blockNumber) internal view returns (euint64 votes) { + uint32 nCheckpoints = numCheckpoints[account]; + + if (nCheckpoints == 0) { + votes = _EUINT_64_ZERO; + } else if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { + // First check most recent balance + votes = checkpoints[account][nCheckpoints - 1].votes; + } else if (checkpoints[account][0].fromBlock > blockNumber) { + // Next check implicit zero balance + votes = _EUINT_64_ZERO; + } else { + // Search for the voting power at the block number + uint32 lower = 0; + uint32 upper = nCheckpoints - 1; + while (upper > lower) { + uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow + Checkpoint memory cp = checkpoints[account][center]; + if (cp.fromBlock == blockNumber) { + return cp.votes; + } else if (cp.fromBlock < blockNumber) { + lower = center; + } else { + upper = center - 1; + } + } + votes = checkpoints[account][lower].votes; + } } - function getChainId() internal view returns (uint256) { - return block.chainid; + function _moveDelegates(address srcRep, address dstRep, euint64 amount) internal { + if (srcRep != dstRep) { + if (srcRep != address(0)) { + uint32 srcRepNum = numCheckpoints[srcRep]; + euint64 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : _EUINT_64_ZERO; + euint64 srcRepNew = TFHE.sub(srcRepOld, amount); // srcRepOld - amount; + _writeCheckpoint(srcRep, srcRepNum, srcRepNew); + } + + if (dstRep != address(0)) { + uint32 dstRepNum = numCheckpoints[dstRep]; + euint64 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : _EUINT_64_ZERO; + euint64 dstRepNew = TFHE.add(dstRepOld, amount); // dstRepOld + amount; + _writeCheckpoint(dstRep, dstRepNum, dstRepNew); + } + } } - modifier onlyAllowedContract() { - require(msg.sender == allowedContract, "Caller not allowed to call this function"); - _; + /// @dev Original restrictions to transfer from/to address(0) are removed + function _transfer(address from, address to, euint64 amount, ebool isTransferable) internal override { + super._transfer(from, to, amount, isTransferable); + _moveDelegates(delegates[from], delegates[to], amount); + } + + function _writeCheckpoint(address delegatee, uint32 nCheckpoints, euint64 newVotes) internal { + if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == block.number) { + checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; + } else { + checkpoints[delegatee][nCheckpoints] = Checkpoint(block.number, newVotes); + numCheckpoints[delegatee] = nCheckpoints + 1; + } + + TFHE.allowThis(newVotes); + TFHE.allow(newVotes, delegatee); + emit DelegateVotesChanged(delegatee); } } diff --git a/contracts/DAO/CompInterface.sol b/contracts/DAO/CompInterface.sol new file mode 100644 index 0000000..03a1c27 --- /dev/null +++ b/contracts/DAO/CompInterface.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity ^0.8.24; + +import "fhevm/lib/TFHE.sol"; + +interface CompInterface { + function getPriorVotes(address account, uint256 blockNumber) external view returns (euint64 votes); +} diff --git a/contracts/DAO/Timelock.sol b/contracts/DAO/CompoundTimelock.sol similarity index 97% rename from contracts/DAO/Timelock.sol rename to contracts/DAO/CompoundTimelock.sol index f0979a7..21fdf6a 100644 --- a/contracts/DAO/Timelock.sol +++ b/contracts/DAO/CompoundTimelock.sol @@ -1,7 +1,9 @@ // SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.24; -contract Timelock { +import { ICompoundTimelock } from "./ICompoundTimelock.sol"; + +contract CompoundTimelock is ICompoundTimelock { event NewAdmin(address indexed newAdmin); event NewPendingAdmin(address indexed newPendingAdmin); event NewDelay(uint256 indexed newDelay); diff --git a/contracts/DAO/ICompoundTimelock.sol b/contracts/DAO/ICompoundTimelock.sol new file mode 100644 index 0000000..20f17de --- /dev/null +++ b/contracts/DAO/ICompoundTimelock.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity ^0.8.24; + +interface ICompoundTimelock { + function delay() external view returns (uint256); + + function GRACE_PERIOD() external view returns (uint256); + + function acceptAdmin() external; + + function queuedTransactions(bytes32 hash) external view returns (bool); + + function queueTransaction( + address target, + uint256 value, + string calldata signature, + bytes calldata data, + uint256 eta + ) external returns (bytes32); + + function cancelTransaction( + address target, + uint256 value, + string calldata signature, + bytes calldata data, + uint256 eta + ) external; + + function executeTransaction( + address target, + uint256 value, + string calldata signature, + bytes calldata data, + uint256 eta + ) external payable returns (bytes memory); +} From 1ff5f4df308028fa17c8353d56af17884787b1fd Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 30 Oct 2024 16:16:40 +0100 Subject: [PATCH 40/73] refactor: Contract names and natspec --- contracts/DAO/Comp.sol | 3 ++- contracts/DAO/CompInterface.sol | 8 -------- contracts/DAO/CompoundTimelock.sol | 3 +++ contracts/DAO/IComp.sol | 12 ++++++++++++ contracts/DAO/ICompoundTimelock.sol | 3 +++ 5 files changed, 20 insertions(+), 9 deletions(-) delete mode 100644 contracts/DAO/CompInterface.sol create mode 100644 contracts/DAO/IComp.sol diff --git a/contracts/DAO/Comp.sol b/contracts/DAO/Comp.sol index 072898b..63cb5ff 100644 --- a/contracts/DAO/Comp.sol +++ b/contracts/DAO/Comp.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.24; import "fhevm/lib/TFHE.sol"; import { Ownable2Step, Ownable } from "@openzeppelin/contracts/access/Ownable2Step.sol"; import { EncryptedERC20 } from "../token/ERC20/EncryptedERC20.sol"; +import { IComp } from "./IComp.sol"; /** * @title Comp @@ -13,7 +14,7 @@ import { EncryptedERC20 } from "../token/ERC20/EncryptedERC20.sol"; * with an account's balance. * @dev The delegation of votes leaks information about the account's encrypted balance to the delegate. */ -contract Comp is EncryptedERC20, Ownable2Step { +contract Comp is IComp, EncryptedERC20, Ownable2Step { /// @notice Emitted when an account changes its delegate. event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); diff --git a/contracts/DAO/CompInterface.sol b/contracts/DAO/CompInterface.sol deleted file mode 100644 index 03a1c27..0000000 --- a/contracts/DAO/CompInterface.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -pragma solidity ^0.8.24; - -import "fhevm/lib/TFHE.sol"; - -interface CompInterface { - function getPriorVotes(address account, uint256 blockNumber) external view returns (euint64 votes); -} diff --git a/contracts/DAO/CompoundTimelock.sol b/contracts/DAO/CompoundTimelock.sol index 21fdf6a..69ff8b4 100644 --- a/contracts/DAO/CompoundTimelock.sol +++ b/contracts/DAO/CompoundTimelock.sol @@ -3,6 +3,9 @@ pragma solidity ^0.8.24; import { ICompoundTimelock } from "./ICompoundTimelock.sol"; +/** + * @title CompoundTimelock + */ contract CompoundTimelock is ICompoundTimelock { event NewAdmin(address indexed newAdmin); event NewPendingAdmin(address indexed newPendingAdmin); diff --git a/contracts/DAO/IComp.sol b/contracts/DAO/IComp.sol new file mode 100644 index 0000000..8dd470b --- /dev/null +++ b/contracts/DAO/IComp.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity ^0.8.24; + +import "fhevm/lib/TFHE.sol"; + +/** + * @title IComp + * @dev The GovernorZama relies on this interface. + */ +interface IComp { + function getPriorVotesForAllowedContract(address account, uint256 blockNumber) external returns (euint64 votes); +} diff --git a/contracts/DAO/ICompoundTimelock.sol b/contracts/DAO/ICompoundTimelock.sol index 20f17de..bceaedb 100644 --- a/contracts/DAO/ICompoundTimelock.sol +++ b/contracts/DAO/ICompoundTimelock.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: BSD-3-Clause pragma solidity ^0.8.24; +/** + * @title ICompoundTimelock + */ interface ICompoundTimelock { function delay() external view returns (uint256); From 1be227f9b1e802c629c7cb24f60d722986f5e61b Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 31 Oct 2024 12:05:02 +0100 Subject: [PATCH 41/73] feat: Add checks for address(0) --- contracts/token/ERC20/EncryptedERC20.sol | 14 +++++++++++- contracts/token/ERC20/IEncryptedERC20.sol | 10 +++++++++ .../extensions/EncryptedERC20WithErrors.sol | 17 ++------------ test/encryptedERC20/EncryptedERC20.test.ts | 22 +++++++++++++++++++ .../EncryptedERC20WithErrors.test.ts | 22 +++++++++++++++++++ 5 files changed, 69 insertions(+), 16 deletions(-) diff --git a/contracts/token/ERC20/EncryptedERC20.sol b/contracts/token/ERC20/EncryptedERC20.sol index b4bc0f2..417f865 100644 --- a/contracts/token/ERC20/EncryptedERC20.sol +++ b/contracts/token/ERC20/EncryptedERC20.sol @@ -167,6 +167,19 @@ abstract contract EncryptedERC20 is IEncryptedERC20 { } function _transfer(address from, address to, euint64 amount, ebool isTransferable) internal virtual { + _transferNoEvent(from, to, amount, isTransferable); + emit Transfer(from, to); + } + + function _transferNoEvent(address from, address to, euint64 amount, ebool isTransferable) internal virtual { + if (from == address(0)) { + revert SenderAddressNull(); + } + + if (to == address(0)) { + revert ReceiverAddressNull(); + } + // Add to the balance of `to` and subract from the balance of `from`. euint64 transferValue = TFHE.select(isTransferable, amount, TFHE.asEuint64(0)); euint64 newBalanceTo = TFHE.add(_balances[to], transferValue); @@ -177,7 +190,6 @@ abstract contract EncryptedERC20 is IEncryptedERC20 { _balances[from] = newBalanceFrom; TFHE.allowThis(newBalanceFrom); TFHE.allow(newBalanceFrom, from); - emit Transfer(from, to); } function _updateAllowance(address owner, address spender, euint64 amount) internal virtual returns (ebool) { diff --git a/contracts/token/ERC20/IEncryptedERC20.sol b/contracts/token/ERC20/IEncryptedERC20.sol index 6841d57..bad4deb 100644 --- a/contracts/token/ERC20/IEncryptedERC20.sol +++ b/contracts/token/ERC20/IEncryptedERC20.sol @@ -20,6 +20,16 @@ interface IEncryptedERC20 { */ event Transfer(address indexed from, address indexed to); + /** + * @notice Emitted when receiver is address(0). + */ + error ReceiverAddressNull(); + + /** + * @notice Emitted when sender is address(0). + */ + error SenderAddressNull(); + /** * @notice Sets the `encryptedAmount` as the allowance of `spender` over the caller's tokens. */ diff --git a/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol b/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol index 43beb8c..376fb37 100644 --- a/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol +++ b/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol @@ -6,7 +6,7 @@ import { EncryptedERC20 } from "../EncryptedERC20.sol"; import { EncryptedErrors } from "../../../utils/EncryptedErrors.sol"; /** - * @title EncryptedERC20WithErrors + * @title EncryptedERC20WithErrors * @notice This contract implements an encrypted ERC20-like token with confidential balances using * Zama's FHE (Fully Homomorphic Encryption) library. * @dev It supports standard ERC20 functions such as transferring tokens, minting, @@ -95,20 +95,7 @@ abstract contract EncryptedERC20WithErrors is EncryptedERC20, EncryptedErrors { ebool isTransferable, euint8 errorCode ) internal virtual { - // Add to the balance of `to` and subract from the balance of `from`. - euint64 transferValue = TFHE.select(isTransferable, amount, TFHE.asEuint64(0)); - euint64 newBalanceTo = TFHE.add(_balances[to], transferValue); - _balances[to] = newBalanceTo; - - TFHE.allow(newBalanceTo, address(this)); - TFHE.allow(newBalanceTo, to); - - euint64 newBalanceFrom = TFHE.sub(_balances[from], transferValue); - _balances[from] = newBalanceFrom; - - TFHE.allow(newBalanceFrom, address(this)); - TFHE.allow(newBalanceFrom, from); - + _transferNoEvent(from, to, amount, isTransferable); emit TransferWithErrorHandling(from, to, _transferIdCounter); // Set error code in the storage and increment diff --git a/test/encryptedERC20/EncryptedERC20.test.ts b/test/encryptedERC20/EncryptedERC20.test.ts index 8536dfa..1665f9d 100644 --- a/test/encryptedERC20/EncryptedERC20.test.ts +++ b/test/encryptedERC20/EncryptedERC20.test.ts @@ -270,6 +270,28 @@ describe("EncryptedERC20", function () { } }); + it("receiver cannot be null address", async function () { + const NULL_ADDRESS = "0x0000000000000000000000000000000000000000"; + const mintAmount = 100_000; + const transferAmount = 50_000; + let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); + await tx.wait(); + + const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = await input.encrypt(); + + await expect( + this.encryptedERC20 + .connect(this.signers.alice) + ["transfer(address,bytes32,bytes)"]( + NULL_ADDRESS, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ), + ).to.be.revertedWithCustomError(this.encryptedERC20, "ReceiverAddressNull"); + }); + it("sender who is not allowed cannot transfer using a handle from another account", async function () { const mintAmount = 100_000; const transferAmount = 50_000; diff --git a/test/encryptedERC20/EncryptedERC20WithErrors.test.ts b/test/encryptedERC20/EncryptedERC20WithErrors.test.ts index a244c93..9b10e09 100644 --- a/test/encryptedERC20/EncryptedERC20WithErrors.test.ts +++ b/test/encryptedERC20/EncryptedERC20WithErrors.test.ts @@ -337,6 +337,28 @@ describe("EncryptedERC20WithErrors", function () { } }); + it("receiver cannot be null address", async function () { + const NULL_ADDRESS = "0x0000000000000000000000000000000000000000"; + const mintAmount = 100_000; + const transferAmount = 50_000; + let tx = await this.encryptedERC20.connect(this.signers.alice).mint(mintAmount); + await tx.wait(); + + const input = this.instances.alice.createEncryptedInput(this.encryptedERC20Address, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = await input.encrypt(); + + await expect( + this.encryptedERC20 + .connect(this.signers.alice) + ["transfer(address,bytes32,bytes)"]( + NULL_ADDRESS, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ), + ).to.be.revertedWithCustomError(this.encryptedERC20, "ReceiverAddressNull"); + }); + it("sender who is not allowed cannot transfer using a handle from another account", async function () { const mintAmount = 100_000; const transferAmount = 50_000; From a868e163495a9a41a50d2ce4df312f6243f66fb4 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:47:44 +0100 Subject: [PATCH 42/73] test: Comp.sol tests --- test/dao/Comp.fixture.ts | 34 +++- test/dao/Comp.test.ts | 315 +++++++++++++++++++++++++++++++++++++ test/dao/Comp.ts | 327 --------------------------------------- 3 files changed, 344 insertions(+), 332 deletions(-) create mode 100644 test/dao/Comp.test.ts delete mode 100644 test/dao/Comp.ts diff --git a/test/dao/Comp.fixture.ts b/test/dao/Comp.fixture.ts index 8be962d..3d5e592 100644 --- a/test/dao/Comp.fixture.ts +++ b/test/dao/Comp.fixture.ts @@ -1,14 +1,38 @@ import { ethers } from "hardhat"; import type { Comp } from "../../types"; -import { getSigners } from "../signers"; - -export async function deployCompFixture(): Promise { - const signers = await getSigners(); +import { reencryptEuint64 } from "../reencrypt"; +import { Signers } from "../signers"; +import { FhevmInstances } from "../types"; +export async function deployCompFixture(signers: Signers): Promise { const contractFactory = await ethers.getContractFactory("Comp"); const contract = await contractFactory.connect(signers.alice).deploy(signers.alice.address); await contract.waitForDeployment(); - return contract; } + +export async function reencryptCurrentVotes( + signers: Signers, + instances: FhevmInstances, + user: string, + comp: Comp, + compAddress: string, +): Promise { + const voteHandle = await comp.getCurrentVotes(signers[user as keyof Signers].address); + const vote = await reencryptEuint64(signers, instances, user, voteHandle, compAddress); + return vote; +} + +export async function reencryptPriorVotes( + signers: Signers, + instances: FhevmInstances, + user: string, + blockNumber: number, + comp: Comp, + compAddress: string, +): Promise { + const voteHandle = await comp.getPriorVotes(signers[user as keyof Signers].address, blockNumber); + const vote = await reencryptEuint64(signers, instances, user, voteHandle, compAddress); + return vote; +} diff --git a/test/dao/Comp.test.ts b/test/dao/Comp.test.ts new file mode 100644 index 0000000..28de149 --- /dev/null +++ b/test/dao/Comp.test.ts @@ -0,0 +1,315 @@ +import { expect } from "chai"; +import { parseUnits } from "ethers"; +import { ethers, network } from "hardhat"; + +import type { Comp } from "../../types"; +import { reencryptBalance } from "../encryptedERC20/EncryptedERC20.fixture"; +import { createInstances } from "../instance"; +import { getSigners, initSigners } from "../signers"; +import { waitNBlocks } from "../utils"; +import { deployCompFixture, reencryptCurrentVotes, reencryptPriorVotes } from "./Comp.fixture"; +import { delegateBySig } from "./DelegateBySig"; + +describe("Comp", function () { + before(async function () { + await initSigners(3); + this.signers = await getSigners(); + }); + + beforeEach(async function () { + const contract = await deployCompFixture(this.signers); + this.compAddress = await contract.getAddress(); + (this.comp as Comp) = contract; + this.instances = await createInstances(this.signers); + }); + + it("should transfer tokens", async function () { + const transferAmount = parseUnits(String(2_000_000), 6); + + const input = this.instances.alice.createEncryptedInput(this.compAddress, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = await input.encrypt(); + + const tx = await this.comp["transfer(address,bytes32,bytes)"]( + this.signers.bob.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + + await tx.wait(); + + // Decrypt Alice's balance + expect(await reencryptBalance(this.signers, this.instances, "alice", this.comp, this.compAddress)).to.equal( + parseUnits(String(8_000_000), 6), + ); + + // Decrypt Bob's balance + expect(await reencryptBalance(this.signers, this.instances, "bob", this.comp, this.compAddress)).to.equal( + parseUnits(String(2_000_000), 6), + ); + }); + + it("can delegate tokens on-chain", async function () { + const tx = await this.comp.connect(this.signers.alice).delegate(this.signers.bob.address); + await tx.wait(); + + const latestBlockNumber = await ethers.provider.getBlockNumber(); + await waitNBlocks(1); + + expect( + await reencryptPriorVotes(this.signers, this.instances, "bob", latestBlockNumber, this.comp, this.compAddress), + ).to.equal(parseUnits(String(10_000_000), 6)); + + // Verify the two functions return the same. + expect( + await reencryptPriorVotes(this.signers, this.instances, "bob", latestBlockNumber, this.comp, this.compAddress), + ).to.equal(await reencryptCurrentVotes(this.signers, this.instances, "bob", this.comp, this.compAddress)); + }); + + it("can delegate votes via delegateBySig if signature is valid", async function () { + const delegatee = this.signers.bob; + const nonce = 0; + let latestBlockNumber = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(latestBlockNumber); + const expiry = block!.timestamp + 100; + const [v, r, s] = await delegateBySig(this.signers.alice, delegatee.address, this.comp, nonce, expiry); + + const tx = await this.comp.connect(this.signers.alice).delegateBySig(delegatee, nonce, expiry, v, r, s); + await tx.wait(); + + latestBlockNumber = await ethers.provider.getBlockNumber(); + await waitNBlocks(1); + + expect( + await reencryptPriorVotes(this.signers, this.instances, "bob", latestBlockNumber, this.comp, this.compAddress), + ).to.equal(parseUnits(String(10_000_000), 6)); + + // Verify the two functions return the same. + expect( + await reencryptPriorVotes(this.signers, this.instances, "bob", latestBlockNumber, this.comp, this.compAddress), + ).to.equal(await reencryptCurrentVotes(this.signers, this.instances, "bob", this.comp, this.compAddress)); + }); + + it("cannot delegate votes if nonce is invalid", async function () { + const delegatee = this.signers.bob; + const nonce = 0; + let latestBlockNumber = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(latestBlockNumber); + const expiry = block!.timestamp + 100; + const [v, r, s] = await delegateBySig(this.signers.alice, delegatee.address, this.comp, nonce, expiry); + + const tx = await this.comp.connect(this.signers.alice).delegateBySig(delegatee, nonce, expiry, v, r, s); + await tx.wait(); + + // Cannot reuse same nonce when delegating by sig + await expect(this.comp.delegateBySig(delegatee, nonce, expiry, v, r, s)).to.be.revertedWith( + "Comp::delegateBySig: invalid nonce", + ); + }); + + it("cannot delegate votes if signer is invalid", async function () { + const delegatee = this.signers.bob; + const nonce = 0; + let latestBlockNumber = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(latestBlockNumber); + const expiry = block!.timestamp + 100; + const [v, r, s] = await delegateBySig(this.signers.alice, delegatee.address, this.comp, nonce, expiry); + + // Cannot use invalid signature when delegating by sig + await expect(this.comp.delegateBySig(delegatee, nonce, expiry, 30, r, s)).to.be.revertedWith( + "Comp::delegateBySig: invalid signature", + ); + }); + + it("cannot delegate votes if signature has expired", async function () { + const delegatee = this.signers.bob; + const nonce = 0; + let latestBlockNumber = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(latestBlockNumber); + const expiry = block!.timestamp + 100; + const [v, r, s] = await delegateBySig(this.signers.alice, delegatee.address, this.comp, nonce, expiry); + + ethers.provider.send("evm_increaseTime", ["0xffff"]); + + await expect(this.comp.connect(delegatee).delegateBySig(delegatee, nonce, expiry, v, r, s)).to.be.revertedWith( + "Comp::delegateBySig: signature expired", + ); + }); + + it("cannot request votes if blocktime is equal to current blocktime", async function () { + let blockNumber = await ethers.provider.getBlockNumber(); + + await expect(this.comp.getPriorVotes(this.signers.alice, blockNumber + 1)).to.be.revertedWith( + "Comp::getPriorVotes: not yet determined", + ); + const newAllowedContract = "0x9d3e06a2952dc49EDCc73e41C76645797fC53967"; + + const tx = await this.comp.connect(this.signers.alice).setAllowedContract(this.signers.bob); + await tx.wait(); + + blockNumber = await ethers.provider.getBlockNumber(); + + await expect( + this.comp.connect(this.signers.bob).getPriorVotesForAllowedContract(this.signers.alice, blockNumber + 1), + ).to.be.revertedWith("Comp::getPriorVotes: not yet determined"); + }); + + it("users can request past votes getPriorVotes", async function () { + // Alice transfers 1M tokens to Bob, 1M tokens to Carol, 1M tokens to Dave + const transferAmount = parseUnits(String(1_000_000), 6); + + const input = this.instances.alice.createEncryptedInput(this.compAddress, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = await input.encrypt(); + + let tx = await this.comp["transfer(address,bytes32,bytes)"]( + this.signers.bob.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + + await tx.wait(); + + tx = await this.comp["transfer(address,bytes32,bytes)"]( + this.signers.carol.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + + await tx.wait(); + + tx = await this.comp["transfer(address,bytes32,bytes)"]( + this.signers.dave.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + + await tx.wait(); + + tx = await this.comp.connect(this.signers.bob).delegate(this.signers.dave.address); + await tx.wait(); + + const firstCheckPointBlockNumber = await ethers.provider.getBlockNumber(); + await waitNBlocks(1); + + tx = await this.comp.connect(this.signers.carol).delegate(this.signers.dave.address); + await tx.wait(); + + const secondCheckPointBlockNumber = await ethers.provider.getBlockNumber(); + await waitNBlocks(1); + + expect( + await reencryptPriorVotes( + this.signers, + this.instances, + "dave", + firstCheckPointBlockNumber, + this.comp, + this.compAddress, + ), + ).to.be.equal(parseUnits(String(1_000_000), 6)); + + expect( + await reencryptPriorVotes( + this.signers, + this.instances, + "dave", + secondCheckPointBlockNumber, + this.comp, + this.compAddress, + ), + ).to.be.equal(parseUnits(String(2_000_000), 6)); + }); + + it("only allowed contract can call getPriorVotes", async function () { + await expect( + this.comp.getPriorVotesForAllowedContract("0xE359a77c3bFE58792FB167D05720e37032A1e520", 0), + ).to.be.revertedWith("Caller not allowed to call this function"); + }); + + it("only owner could set allowed contract", async function () { + const newAllowedContract = "0x9d3e06a2952dc49EDCc73e41C76645797fC53967"; + + await expect(this.comp.connect(this.signers.bob).setAllowedContract(newAllowedContract)) + .to.be.revertedWithCustomError(this.comp, "OwnableUnauthorizedAccount") + .withArgs(this.signers.bob.address); + }); + + it("allowed address can access votes for any account", async function () { + // Bob becomes the allowed address. + let tx = await this.comp.connect(this.signers.alice).setAllowedContract(this.signers.bob.address); + await tx.wait(); + + // Alice delegates her votes to Carol. + tx = await this.comp.connect(this.signers.alice).delegate(this.signers.carol.address); + await tx.wait(); + + const latestBlockNumber = await ethers.provider.getBlockNumber(); + await waitNBlocks(1); + await waitNBlocks(1); + + // Bob, the allowed address, get the prior votes for allowed contract. + const voteHandle = await this.comp + .connect(this.signers.bob) + .getPriorVotesForAllowedContract(this.signers.carol.address, latestBlockNumber + 1); + + // It is not possible to catch the return value. + // TODO: Create a test helper contract to implement this. + }); + + it("different voters can delegate to same delegatee", async function () { + const transferAmount = parseUnits(String(2_000_000), 6); + + const input = this.instances.alice.createEncryptedInput(this.compAddress, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = await input.encrypt(); + + let tx = await this.comp["transfer(address,bytes32,bytes)"]( + this.signers.bob.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + + await tx.wait(); + + tx = await this.comp.connect(this.signers.alice).delegate(this.signers.carol); + await tx.wait(); + + tx = await this.comp.connect(this.signers.bob).delegate(this.signers.carol); + await tx.wait(); + + const latestBlockNumber = await ethers.provider.getBlockNumber(); + await waitNBlocks(1); + + expect(await reencryptCurrentVotes(this.signers, this.instances, "carol", this.comp, this.compAddress)).to.equal( + parseUnits(String(10_000_000), 6), + ); + + expect( + await reencryptPriorVotes(this.signers, this.instances, "carol", latestBlockNumber, this.comp, this.compAddress), + ).to.equal(await reencryptCurrentVotes(this.signers, this.instances, "carol", this.comp, this.compAddress)); + }); + + // TODO: fix issue with mining + it.skip("number of checkpoints is incremented once per block, even when written multiple times in same block", async function () { + await network.provider.send("evm_setAutomine", [false]); + await network.provider.send("evm_setIntervalMining", [0]); + + // do two checkpoints in same block + const tx1 = this.comp.connect(this.signers.alice).delegate(this.signers.bob); + const tx2 = this.comp.connect(this.signers.alice).delegate(this.signers.carol); + + await network.provider.send("evm_mine"); + await network.provider.send("evm_setAutomine", [true]); + + expect(await this.comp.numCheckpoints(this.signers.alice.address)).to.be.equal(0n); + expect(await this.comp.numCheckpoints(this.signers.bob.address)).to.be.equal(1n); + expect(await this.comp.numCheckpoints(this.signers.carol.address)).to.be.equal(1n); + + expect(await reencryptCurrentVotes(this.signers, this.instances, "bob", this.comp, this.compAddress)).to.equal(0); + + expect(await reencryptCurrentVotes(this.signers, this.instances, "carol", this.comp, this.compAddress)).to.equal( + parseUnits(String(10_000_000), 6), + ); + }); +}); diff --git a/test/dao/Comp.ts b/test/dao/Comp.ts deleted file mode 100644 index 1f6800d..0000000 --- a/test/dao/Comp.ts +++ /dev/null @@ -1,327 +0,0 @@ -import { expect } from "chai"; -import { ethers, network } from "hardhat"; - -import { createInstances } from "../instance"; -import { getSigners, initSigners } from "../signers"; -import { createTransaction, mineNBlocks, waitNBlocks } from "../utils"; -import { deployCompFixture } from "./Comp.fixture"; -import { delegateBySigSignature } from "./DelegateBySig"; - -describe("Comp", function () { - before(async function () { - await initSigners(); - this.signers = await getSigners(); - }); - - beforeEach(async function () { - const contract = await deployCompFixture(); - this.contractAddress = await contract.getAddress(); - this.comp = contract; - this.instances = await createInstances(this.contractAddress, ethers, this.signers); - }); - - // 9000n , 31337n - - it("only owner could set allowed contract", async function () { - const tx = await this.comp.setAllowedContract("0xE359a77c3bFE58792FB167D05720e37032A1e520"); - await tx.wait(); - - if (network.name === "hardhat") { - // mocked mode - await expect(this.comp.connect(this.signers.bob).setAllowedContract("0x9d3e06a2952dc49EDCc73e41C76645797fC53967")) - .to.be.revertedWithCustomError(this.comp, "OwnableUnauthorizedAccount") - .withArgs(this.signers.bob.address); - } else { - // fhevm-mode - const tx = await this.comp - .connect(this.signers.bob) - .setAllowedContract("0x9d3e06a2952dc49EDCc73e41C76645797fC53967", { gasLimit: 1_000_000 }); - await expect(tx.wait()).to.throw; - } - }); - - it("only allowed contract can call getPriorVotes", async function () { - await expect(this.comp.getPriorVotes("0xE359a77c3bFE58792FB167D05720e37032A1e520", 0)).to.be.revertedWith( - "Caller not allowed to call this function", - ); - }); - - it("should transfer tokens", async function () { - const encryptedAmountToTransfer = this.instances.alice.encrypt64(2_000_000n * 10n ** 6n); - const transferTransac = await this.comp["transfer(address,bytes)"]( - this.signers.bob.address, - encryptedAmountToTransfer, - ); - - await transferTransac.wait(); - - const aliceToken = this.instances.alice.getPublicKey(this.contractAddress); - const encryptedAliceBalance = await this.comp.balanceOf( - this.signers.alice.address, - aliceToken.publicKey, - aliceToken.signature, - ); - // Decrypt Alice's balance - const aliceBalance = this.instances.alice.decrypt(this.contractAddress, encryptedAliceBalance); - expect(aliceBalance).to.equal(8_000_000n * 10n ** 6n); - - let encryptedAliceVotes = await this.comp.getMyCurrentVotes(aliceToken.publicKey, aliceToken.signature); - // Decrypt Alice's current votes - let aliceCurrentVotes = this.instances.alice.decrypt(this.contractAddress, encryptedAliceVotes); - expect(aliceCurrentVotes).to.equal(0n); - - // Bob should not be able to decrypt Alice's votes - await expect( - this.comp.connect(this.signers.bob).getMyCurrentVotes(aliceToken.publicKey, aliceToken.signature), - ).to.be.revertedWith("EIP712 signer and transaction signer do not match"); - - const tx = await this.comp.delegate(this.signers.alice); - await tx.wait(); - encryptedAliceVotes = await this.comp.getMyCurrentVotes(aliceToken.publicKey, aliceToken.signature); - // Decrypt Alice's current votes - aliceCurrentVotes = this.instances.alice.decrypt(this.contractAddress, encryptedAliceVotes); - expect(aliceCurrentVotes).to.equal(8_000_000n * 10n ** 6n); - - const tx2 = await createTransaction(this.comp.delegate, this.signers.bob); - await tx2.wait(); - encryptedAliceVotes = await this.comp.getMyCurrentVotes(aliceToken.publicKey, aliceToken.signature); - // Decrypt Alice's current votes - aliceCurrentVotes = this.instances.alice.decrypt(this.contractAddress, encryptedAliceVotes); - expect(aliceCurrentVotes).to.equal(0n); - - const bobToken = this.instances.bob.getPublicKey(this.contractAddress); - const encryptedBobBalance = await this.comp - .connect(this.signers.bob) - .balanceOf(this.signers.bob.address, bobToken.publicKey, bobToken.signature); - // Decrypt Bob's balance - const bobBalance = this.instances.bob.decrypt(this.contractAddress, encryptedBobBalance); - expect(bobBalance).to.equal(2_000_000n * 10n ** 6n); - }); - - it("can't transfer to nor from null address", async function () { - const nullAddress = "0x0000000000000000000000000000000000000000"; - const encryptedAmountToTransfer = this.instances.alice.encrypt64(1n * 10n ** 6n); - const encryptedAmountToTransferNull = this.instances.alice.encrypt64(0n); - if (network.name === "hardhat") { - // mocked mode - await expect(this.comp["transfer(address,bytes)"](nullAddress, encryptedAmountToTransfer)).to.be.revertedWith( - "Comp::_transferTokens: cannot transfer to the zero address", - ); - await expect( - this.comp["transferFrom(address,address,bytes)"]( - nullAddress, - this.signers.bob.address, - encryptedAmountToTransfer, - ), - ).to.be.revertedWith("Comp::_transferTokens: cannot transfer from the zero address"); - } else { - // fhevm-mode - const tx = await this.comp["transfer(address,bytes)"](nullAddress, encryptedAmountToTransferNull, { - gasLimit: 1_000_000, - }); - - await expect(tx.wait()).to.throw; - const tx2 = await this.comp["transferFrom(address,address,bytes)"]( - nullAddress, - this.signers.bob.address, - encryptedAmountToTransferNull, - { gasLimit: 1_000_000 }, - ); - await expect(tx2.wait()).to.throw; - } - }); - - it("can't transfer from null address", async function () { - const tx = await this.comp.setAllowedContract("0xE359a77c3bFE58792FB167D05720e37032A1e520"); - await tx.wait(); - - if (network.name === "hardhat") { - // mocked mode - await expect(this.comp.connect(this.signers.bob).setAllowedContract("0x9d3e06a2952dc49EDCc73e41C76645797fC53967")) - .to.be.revertedWithCustomError(this.comp, "OwnableUnauthorizedAccount") - .withArgs(this.signers.bob.address); - } else { - // fhevm-mode - const tx = await this.comp - .connect(this.signers.bob) - .setAllowedContract("0x9d3e06a2952dc49EDCc73e41C76645797fC53967", { gasLimit: 1_000_000 }); - await expect(tx.wait()).to.throw; - } - }); - - it("can delegate votes via delegateBySig if signature is valid", async function () { - const delegatee = this.signers.bob.address; - const nonce = 0; - const latestBlockNumber = await ethers.provider.getBlockNumber(); - const block = await ethers.provider.getBlock(latestBlockNumber); - const expiry = block!.timestamp + 100; - const [v, r, s] = await delegateBySigSignature(this.signers.alice, delegatee, this.comp, nonce, expiry); - - const tx = await this.comp.delegateBySig(delegatee, nonce, expiry, v, r, s); - await tx.wait(); - - const tokenBob = this.instances.bob.getPublicKey(this.contractAddress); - const encryptedCurrentVotes = await this.comp - .connect(this.signers.bob) - .getMyCurrentVotes(tokenBob.publicKey, tokenBob.signature); - const currentVotes = this.instances.bob.decrypt(this.contractAddress, encryptedCurrentVotes); - expect(currentVotes).to.equal(10_000_000n * 10n ** 6n); - - if (network.name === "hardhat") { - // can't reuse same nonce when delegating by sig - await expect(this.comp.delegateBySig(delegatee, nonce, expiry, v, r, s)).to.be.revertedWith( - "Comp::delegateBySig: invalid nonce", - ); - - // can't use invalid signature when delegating by sig - await expect(this.comp.delegateBySig(delegatee, nonce, expiry, 30, r, s)).to.be.revertedWith( - "Comp::delegateBySig: invalid signature", - ); - - // can't use signature after expiry - ethers.provider.send("evm_increaseTime", ["0xffff"]); - const [v2, r2, s2] = await delegateBySigSignature(this.signers.alice, delegatee, this.comp, 1, expiry); - await expect(this.comp.delegateBySig(delegatee, nonce, expiry, v2, r2, s2)).to.be.revertedWith( - "Comp::delegateBySig: signature expired", - ); - } - }); - - it("comp becomes obsolete after max(uint32) blocks", async function () { - if (network.name === "hardhat") { - // mocked mode - const tx = await this.comp.delegate(this.signers.bob.address); - await tx.wait(); - const idSnapshot = await ethers.provider.send("evm_snapshot"); - - await mineNBlocks(2 ** 32); - const encryptedAmountToTransfer = this.instances.alice.encrypt64(2_000_000n * 10n ** 6n); - await expect( - this.comp["transfer(address,bytes)"](this.signers.carol.address, encryptedAmountToTransfer), - ).to.be.revertedWith("Comp::_writeCheckpoint: block number exceeds 32 bits"); - await ethers.provider.send("evm_revert", [idSnapshot]); - } - }); - - it("user can request his past votes via getMyPriorVotes", async function () { - const aliceToken = this.instances.alice.getPublicKey(this.contractAddress); - const initBlock = await ethers.provider.getBlockNumber(); - let aliceMyPriorVotesEnc = await this.comp.getMyPriorVotes( - initBlock - 1, - aliceToken.publicKey, - aliceToken.signature, - ); - let aliceMyPriorVotes = this.instances.alice.decrypt(this.contractAddress, aliceMyPriorVotesEnc); - expect(aliceMyPriorVotes).to.be.equal(0n); - - const tx = await this.comp.delegate(this.signers.alice.address); - await tx.wait(); - const firstCheckPointBlockNumber = await ethers.provider.getBlockNumber(); - await waitNBlocks(1); - - aliceMyPriorVotesEnc = await this.comp.getMyPriorVotes( - firstCheckPointBlockNumber, - aliceToken.publicKey, - aliceToken.signature, - ); - aliceMyPriorVotes = this.instances.alice.decrypt(this.contractAddress, aliceMyPriorVotesEnc); - expect(aliceMyPriorVotes).to.be.equal(10000000000000n); - - aliceMyPriorVotesEnc = await this.comp.getMyPriorVotes( - firstCheckPointBlockNumber - 1, - aliceToken.publicKey, - aliceToken.signature, - ); - aliceMyPriorVotes = this.instances.alice.decrypt(this.contractAddress, aliceMyPriorVotesEnc); - expect(aliceMyPriorVotes).to.be.equal(0n); - - await expect( - this.comp.getMyPriorVotes(firstCheckPointBlockNumber + 1, aliceToken.publicKey, aliceToken.signature), - ).to.be.revertedWith("Comp::getPriorVotes: not yet determined"); - - // Bob cannot decrypt Alice's prior votes - await expect( - this.comp - .connect(this.signers.bob) - .getMyPriorVotes(firstCheckPointBlockNumber - 1, aliceToken.publicKey, aliceToken.signature), - ).to.be.revertedWith("EIP712 signer and transaction signer do not match"); - - const encryptedAmountToTransfer = this.instances.alice.encrypt64(2_000_000n * 10n ** 6n); - const transferTransac = await this.comp["transfer(address,bytes)"]( - this.signers.bob.address, - encryptedAmountToTransfer, - ); - await transferTransac.wait(); - const secondCheckPointBlockNumber = await ethers.provider.getBlockNumber(); - await waitNBlocks(1); - - aliceMyPriorVotesEnc = await this.comp.getMyPriorVotes( - firstCheckPointBlockNumber, - aliceToken.publicKey, - aliceToken.signature, - ); - aliceMyPriorVotes = this.instances.alice.decrypt(this.contractAddress, aliceMyPriorVotesEnc); - expect(aliceMyPriorVotes).to.be.equal(10000000000000n); - - const encryptedAmountToTransfer2 = this.instances.alice.encrypt64(2_000_000n * 10n ** 6n); - const transferTransac2 = await this.comp["transfer(address,bytes)"]( - this.signers.carol.address, - encryptedAmountToTransfer2, - ); - await transferTransac2.wait(); - await ethers.provider.getBlockNumber(); // third CheckPoint - await waitNBlocks(1); - - aliceMyPriorVotesEnc = await this.comp.getMyPriorVotes( - secondCheckPointBlockNumber, - aliceToken.publicKey, - aliceToken.signature, - ); - aliceMyPriorVotes = this.instances.alice.decrypt(this.contractAddress, aliceMyPriorVotesEnc); - expect(aliceMyPriorVotes).to.be.equal(8000000000000n); - - aliceMyPriorVotesEnc = await this.comp.getMyPriorVotes( - secondCheckPointBlockNumber + 1, - aliceToken.publicKey, - aliceToken.signature, - ); - aliceMyPriorVotes = this.instances.alice.decrypt(this.contractAddress, aliceMyPriorVotesEnc); - expect(aliceMyPriorVotes).to.be.equal(8000000000000n); - }); - - it("different voters can delegate to same delegatee", async function () { - const encryptedAmountToTransfer = this.instances.alice.encrypt64(2_000_000n * 10n ** 6n); - const tx1 = await this.comp["transfer(address,bytes)"](this.signers.bob.address, encryptedAmountToTransfer); - await tx1.wait(); - - const tx2 = await this.comp.delegate(this.signers.carol); - await tx2.wait(); - - const tx3 = await createTransaction(this.comp.connect(this.signers.bob).delegate, this.signers.carol); - await tx3.wait(); - - const carolToken = this.instances.carol.getPublicKey(this.contractAddress); - let encryptedCarolVotes = await this.comp - .connect(this.signers.carol) - .getMyCurrentVotes(carolToken.publicKey, carolToken.signature); - // Decrypt Alice's current votes - let carolCurrentVotes = this.instances.carol.decrypt(this.contractAddress, encryptedCarolVotes); - expect(carolCurrentVotes).to.equal(10000000000000n); - }); - - it("number of checkpoints is incremented once per block, even when written multiple times in same block", async function () { - if (network.name === "hardhat") { - // mocked mode - await network.provider.send("evm_setAutomine", [false]); - await network.provider.send("evm_setIntervalMining", [0]); - // do two checkpoints in same block - await this.comp.delegate(this.signers.bob); - await this.comp.delegate(this.signers.carol); - await network.provider.send("evm_mine"); - await network.provider.send("evm_setAutomine", [true]); - expect(await this.comp.numCheckpoints(this.signers.alice)).to.be.equal(0n); - expect(await this.comp.numCheckpoints(this.signers.bob)).to.be.equal(1n); - expect(await this.comp.numCheckpoints(this.signers.carol)).to.be.equal(1n); - } - }); -}); From 5c45281d910ec64939702f50be188f59ad2ca6c0 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:58:11 +0100 Subject: [PATCH 43/73] ci: Change workflows --- .github/workflows/test.yml | 2 +- .github/workflows/testmock.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3e91e59..d7a17a0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,7 +5,7 @@ on: - main jobs: build: - runs-on: large_ubuntu_16 + runs-on: ubuntu-latest strategy: matrix: node-version: diff --git a/.github/workflows/testmock.yml b/.github/workflows/testmock.yml index bb5670f..2f75408 100644 --- a/.github/workflows/testmock.yml +++ b/.github/workflows/testmock.yml @@ -1,11 +1,11 @@ name: Pull request tests with mocks on: - pull_request: + push: branches: - main jobs: build: - runs-on: large_ubuntu_16 + runs-on: ubuntu-latest strategy: matrix: node-version: From bbedd9ff0b4e7047fca4a9dd19c25bd0c7853466 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:58:57 +0100 Subject: [PATCH 44/73] fix: Workflow --- .github/workflows/test.yml | 2 +- .github/workflows/testmock.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d7a17a0..7a487b4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,6 @@ name: Pull request tests on: - pull_request: + push: branches: - main jobs: diff --git a/.github/workflows/testmock.yml b/.github/workflows/testmock.yml index 2f75408..b1c36f0 100644 --- a/.github/workflows/testmock.yml +++ b/.github/workflows/testmock.yml @@ -1,6 +1,6 @@ name: Pull request tests with mocks on: - push: + pull_request: branches: - main jobs: From d9a81aa98922b5ecef2431287fd1f45345a0a25c Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 4 Nov 2024 17:50:02 +0100 Subject: [PATCH 45/73] fix: Minor changes --- contracts/DAO/Comp.sol | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/contracts/DAO/Comp.sol b/contracts/DAO/Comp.sol index 63cb5ff..6d22a30 100644 --- a/contracts/DAO/Comp.sol +++ b/contracts/DAO/Comp.sol @@ -10,6 +10,7 @@ import { IComp } from "./IComp.sol"; * @title Comp * @notice This contract inherits EncryptedERC20. * This is based on the Comp.sol contract written by Compound Labs. + * see: compound-finance/compound-protocol/blob/master/contracts/Governance/Comp.sol * It uses encrypted votes to delegate the voting power associated * with an account's balance. * @dev The delegation of votes leaks information about the account's encrypted balance to the delegate. @@ -58,11 +59,11 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { /// @notice A record of votes checkpoints for an `account` using incremental indices. mapping(address account => mapping(uint32 index => Checkpoint checkpoint)) internal checkpoints; - /// @notice Constant for zero using TFHE + /// @notice Constant for zero using TFHE. /// @dev Since it is expensive to compute 0, it is stored instead. /// However, is not possible to define it as constant due to TFHE constraints. /* solhint-disable var-name-mixedcase*/ - euint64 private _EUINT_64_ZERO; + euint64 private _EUINT64_ZERO; /** * @param owner Owner address @@ -72,9 +73,8 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { _totalSupply = 10000000e6; // @dev Define the constant in the storage. - _EUINT_64_ZERO = TFHE.asEuint64(0); - - TFHE.allowThis(_EUINT_64_ZERO); + _EUINT64_ZERO = TFHE.asEuint64(0); + TFHE.allowThis(_EUINT64_ZERO); } /** @@ -131,7 +131,7 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { */ function getCurrentVotes(address account) external view returns (euint64 votes) { uint32 nCheckpoints = numCheckpoints[account]; - votes = nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : _EUINT_64_ZERO; + votes = nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : votes; } /** @@ -169,14 +169,11 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { function _getPriorVote(address account, uint256 blockNumber) internal view returns (euint64 votes) { uint32 nCheckpoints = numCheckpoints[account]; - if (nCheckpoints == 0) { - votes = _EUINT_64_ZERO; - } else if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { + if (nCheckpoints == 0) {} else if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { // First check most recent balance votes = checkpoints[account][nCheckpoints - 1].votes; } else if (checkpoints[account][0].fromBlock > blockNumber) { // Next check implicit zero balance - votes = _EUINT_64_ZERO; } else { // Search for the voting power at the block number uint32 lower = 0; @@ -200,21 +197,22 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { if (srcRep != dstRep) { if (srcRep != address(0)) { uint32 srcRepNum = numCheckpoints[srcRep]; - euint64 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : _EUINT_64_ZERO; + euint64 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : _EUINT64_ZERO; euint64 srcRepNew = TFHE.sub(srcRepOld, amount); // srcRepOld - amount; _writeCheckpoint(srcRep, srcRepNum, srcRepNew); } if (dstRep != address(0)) { uint32 dstRepNum = numCheckpoints[dstRep]; - euint64 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : _EUINT_64_ZERO; + euint64 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : _EUINT64_ZERO; euint64 dstRepNew = TFHE.add(dstRepOld, amount); // dstRepOld + amount; _writeCheckpoint(dstRep, dstRepNum, dstRepNew); } } } - /// @dev Original restrictions to transfer from/to address(0) are removed + /// @dev Original restrictions to transfer from/to address(0) are removed since they + /// are inherited. function _transfer(address from, address to, euint64 amount, ebool isTransferable) internal override { super._transfer(from, to, amount, isTransferable); _moveDelegates(delegates[from], delegates[to], amount); From cb31d7b05f8b4a5f5af644190700118e01eb03e9 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Mon, 4 Nov 2024 17:50:32 +0100 Subject: [PATCH 46/73] feat: WIP updates GovernorZama --- contracts/DAO/GovernorAlphaZama.sol | 614 ++++++++++++++++++++++++++++ contracts/DAO/GovernorZama.sol | 466 --------------------- contracts/DAO/IComp.sol | 2 +- 3 files changed, 615 insertions(+), 467 deletions(-) create mode 100644 contracts/DAO/GovernorAlphaZama.sol delete mode 100644 contracts/DAO/GovernorZama.sol diff --git a/contracts/DAO/GovernorAlphaZama.sol b/contracts/DAO/GovernorAlphaZama.sol new file mode 100644 index 0000000..9789a05 --- /dev/null +++ b/contracts/DAO/GovernorAlphaZama.sol @@ -0,0 +1,614 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity ^0.8.24; + +import "fhevm/lib/TFHE.sol"; +import "fhevm/gateway/GatewayCaller.sol"; + +import { Ownable2Step, Ownable } from "@openzeppelin/contracts/access/Ownable2Step.sol"; +import { IComp } from "./IComp.sol"; +import { ICompoundTimelock } from "./ICompoundTimelock.sol"; + +/** + * @title GovernorAlphaZama + * @notice This is based on the GovernorAlpha.sol contract written by Compound Labs. + * see: compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol + */ +contract GovernorAlphaZama is Ownable2Step, GatewayCaller { + /// @notice Emitted when a proposal is now active. + event ProposalActive(uint256 id); + + /// @notice Emitted when a proposal has been canceled. + event ProposalCanceled(uint256 id); + + /// @notice Emitted when a new proposal is created. + event ProposalCreated( + uint256 id, + address proposer, + address[] targets, + uint256[] values, + string[] signatures, + bytes[] calldatas, + uint256 startBlock, + uint256 endBlock, + string description + ); + + /// @notice Emitted when a proposal is defeated either by lack of votes or by + /// more votes against. + event ProposalDefeated(uint256 id); + + /// @notice Emitted when a proposal has been executed in the Timelock. + event ProposalExecuted(uint256 id); + + /// @notice Emitted when a proposal has been queued in the Timelock. + event ProposalQueued(uint256 id, uint256 eta); + + /// @notice Emitted when a proposal has been rejected since the number of votes is lower + /// than the required threshold. + event ProposalRejected(uint256 id); + + /// @notice Emitted when a proposal has been rejected since the number of votes is lower + /// than the required threshold. + event ProposalSucceeded(uint256 id); + + /// @notice Emitted when a vote has been cast on a proposal. + event VoteCast(address voter, uint256 proposalId); + + /// @notice Possible states that a proposal may be in. + enum ProposalState { + Pending, /// Proposal does not exist. + PendingThresholdVerification, /// Proposal is created but token threshold verification is pending. + Rejected, /// Proposal was rejected because the proposer did not match the token threshold required. + Active, /// Proposal is active and voters can cast their votes. + PendingResults, /// Proposal is active but the decryption of the result is in progress. + Canceled, /// Proposal has been canceled by the proposer. + Defeated, /// Proposal has been defeated (either by not reaching the quorum or votesAgainst > votesFor). + Succeeded, /// Proposal has succeeded. + Queued, /// Proposal has been queued in the timelock. + Expired, /// Proposal has expired (@dev This state is used for read-only operations). + Executed /// Proposal has been executed. + } + + /** + * @param proposer Proposal creator. + * @param eta The timestamp that the proposal will be available for execution, + * it is set automatically once the vote succeeds. + * @param targets The ordered list of target addresses for calls to be made. + * @param values The ordered list of values (i.e. msg.value) to be passed to the calls to be made. + * @param signatures The ordered list of function signatures to be called. + * @param calldatas The ordered list of calldata to be passed to each call. + * @param startBlock The block at which voting begins: holders must delegate their votes prior + * to this block. + * @param endBlock The block at which voting ends: votes must be cast prior to this block. + * @param forVotes Current number of votes in opposition to this proposal. + * @param againstVotes Current number of votes in opposition to this proposal. + * @param forVotesDecrypted For votes once decrypted by the gateway. + * @param againstVotesDecrypted Against votes once decrypted by the gateway. + */ + + struct Proposal { + address proposer; + ProposalState state; + uint256 eta; + address[] targets; + uint256[] values; + string[] signatures; + bytes[] calldatas; + uint256 startBlock; + uint256 endBlock; + euint64 forVotes; + euint64 againstVotes; + uint64 forVotesDecrypted; + uint64 againstVotesDecrypted; + } + + /** + * @param proposer Proposal creator. + * @param state State of the proposal. + * @param eta The timestamp when the proposal will be available for execution, set once the vote succeeds. + * @param targets The ordered list of target addresses for calls to be made. + * @param values The ordered list of values (i.e. msg.value) to be passed to the calls to be made. + * @param signatures The ordered list of function signatures to be called. + * @param calldatas The ordered list of calldata to be passed to each call. + * @param startBlock The block at which voting begins: holders must delegate their votes prior to this block. + * @param endBlock The block at which voting ends: votes must be cast prior to this block. + * @param forVotes Current number of votes in opposition to this proposal. + * @param againstVotes Current number of votes in opposition to this proposal. + */ + struct ProposalInfo { + address proposer; + ProposalState state; + uint256 eta; + address[] targets; + uint256[] values; + string[] signatures; + bytes[] calldatas; + uint256 startBlock; + uint256 endBlock; + } + + /** + * @notice Ballot receipt record for a voter. + * @param hasVoted Whether or not a vote has been cast. + * @param support Whether or not the voter supports the proposal. + * @param votes The number of votes cast by the voter. + */ + struct Receipt { + bool hasVoted; + ebool support; + euint64 votes; + } + + /// @notice The maximum number of actions that can be included in a proposal. + /// @dev It is 10 actions per proposal. + uint256 public constant PROPOSAL_MAX_OPERATIONS = 10; + + /// @notice The number of votes required for a voter to become a proposer. + /// @dev It is set at 100,000, which is 1% of the total supply of the Comp token. + uint256 public constant PROPOSAL_THRESHOLD = 100000e6; + + /// @notice The number of votes in support of a proposal required in order for a quorum to be reached + /// and for a vote to succeed. + /// @dev It is set at 400,000, which is 4% of the total supply of the Comp token. + uint64 public constant QUORUM_VOTES = 400000e6; + + /// @notice The delay before voting on a proposal may take place once proposed. + /// It is 1 block. + uint256 public constant VOTING_DELAY = 1; + + /// @notice The duration of voting on a proposal, in blocks + /// @dev It is recommended to be set at 3 days in blocks + /// (i.e 21,600 for 12-second blocks). + uint256 public immutable VOTING_PERIOD; + + /// @notice Comp governance token. + IComp public immutable COMP; + + /// @notice Compound Timelock. + ICompoundTimelock public immutable TIMELOCK; + + /// @notice Constant for zero using TFHE. + /// @dev Since it is expensive to compute 0, it is stored instead. + /// However, is not possible to define it as constant due to TFHE constraints. + /* solhint-disable var-name-mixedcase*/ + euint64 private _EUINT64_ZERO; + + /// @notice Constant for PROPOSAL_THRESHOLD using TFHE. + /// @dev Since it is expensive to compute 0, it is stored instead. + /// However, is not possible to define it as constant due to TFHE constraints. + /* solhint-disable var-name-mixedcase*/ + euint64 private _EUINT64_PROPOSAL_THRESHOLD; + + /// @notice The total number of proposals made. + /// It includes all proposals, including the ones that + /// were rejected/canceled/defeated. + uint256 public proposalCount; + + /// @notice The latest proposal for each proposer. + mapping(address proposer => uint256 proposalId) public latestProposalIds; + + /// @notice Ballot receipt for an account for a proposal id. + mapping(uint256 proposalId => mapping(address => Receipt)) internal _accountReceiptForProposalId; + + /// @notice The official record of all _proposals ever proposed. + mapping(uint256 proposalId => Proposal proposal) internal _proposals; + + /// @notice Returns the proposal id associated with the request id. + /// @dev This mapping is used for decryption. + mapping(uint256 requestId => uint256 proposalId) internal _requestIdToProposalId; + + /** + * @param owner_ Owner address. + * @param timelock_ Timelock contract. + * @param comp_ Comp token. + * @param votingPeriod_ Voting period. + * @dev Do not use a small value in production such as 5 or 20 to avoid security issues + * unless for testing purpose. It should by at least a few days,. + * For instance, 3 days would have a votingPeriod = 21,600 blocks if 12s per block. + */ + constructor(address owner_, address timelock_, address comp_, uint256 votingPeriod_) Ownable(owner_) { + TFHE.setFHEVM(FHEVMConfig.defaultConfig()); + Gateway.setGateway(Gateway.defaultGatewayAddress()); + + TIMELOCK = ICompoundTimelock(timelock_); + COMP = IComp(comp_); + VOTING_PERIOD = votingPeriod_; + + // @dev Store these constants in the storage. + _EUINT64_ZERO = TFHE.asEuint64(0); + _EUINT64_PROPOSAL_THRESHOLD = TFHE.asEuint64(PROPOSAL_THRESHOLD); + + TFHE.allowThis(_EUINT64_ZERO); + TFHE.allowThis(_EUINT64_PROPOSAL_THRESHOLD); + } + + /** + * @notice Cancel the proposal. + * @param proposalId Proposal id. + * @dev Only the owner address or the proposer can cancel. + * In the original GovernorAlpha, the proposer can cancel only if the votes are still + * above the threshold. + */ + function cancel(uint256 proposalId) external { + Proposal storage proposal = _proposals[proposalId]; + require(proposal.state != ProposalState.Executed, "GovernorAlpha::cancel: cannot cancel executed proposal"); + require(proposal.state != ProposalState.Canceled, "GovernorAlpha::cancel: cannot cancel canceled proposal"); + + if (msg.sender != proposal.proposer) { + _checkOwner(); + } + + /// @dev It is not necessary to cancel the transaction in the timelock + /// unless the proposal has been queued. + if (proposal.state == ProposalState.Queued) { + for (uint256 i = 0; i < proposal.targets.length; i++) { + TIMELOCK.cancelTransaction( + proposal.targets[i], + proposal.values[i], + proposal.signatures[i], + proposal.calldatas[i], + proposal.eta + ); + } + } + + proposal.state = ProposalState.Canceled; + + emit ProposalCanceled(proposalId); + } + + /** + * @notice Cast a vote. + * @param proposalId Proposal id. + * @param value Encrypted value. + * @param inputProof Input proof. + */ + function castVote(uint256 proposalId, einput value, bytes calldata inputProof) external { + return _castVote(msg.sender, proposalId, TFHE.asEbool(value, inputProof)); + } + + /** + * @notice Cast a vote. + * @param proposalId Proposal id. + * @param support Support (true ==> votesFor, false ==> votesAgainst) + */ + function castVote(uint256 proposalId, ebool support) external { + return _castVote(msg.sender, proposalId, support); + } + + /** + * @notice Execute the proposal id. + * @dev Anyone can execute a proposal once it has been queued and the + * delay in the timelock is sufficient. + */ + function execute(uint256 proposalId) external payable { + Proposal memory proposal = _proposals[proposalId]; + + require( + proposal.state == ProposalState.Queued, + "GovernorAlpha::execute: proposal can only be executed if it is queued" + ); + + // proposal.executed = true; + for (uint256 i = 0; i < proposal.targets.length; i++) { + TIMELOCK.executeTransaction{ value: proposal.values[i] }( + proposal.targets[i], + proposal.values[i], + proposal.signatures[i], + proposal.calldatas[i], + proposal.eta + ); + } + + emit ProposalExecuted(proposalId); + } + + /** + * @notice Start a new proposal. + * @param targets Target addresses. + * @param values Values. + * @param signatures Signatures. + * @param calldatas Calldatas. + * @param description Plain text description of the proposal. + * @return proposalId Proposal id. + */ + function propose( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description + ) external returns (uint256 proposalId) { + { + uint256 length = targets.length; + require( + length == values.length && length == signatures.length && length == calldatas.length, + "GovernorAlpha::propose: proposal function information arity mismatch" + ); + require(length != 0, "GovernorAlpha::propose: must provide actions"); + require(length <= PROPOSAL_MAX_OPERATIONS, "GovernorAlpha::propose: too many actions"); + } + + uint256 latestProposalId = latestProposalIds[msg.sender]; + + if (latestProposalId != 0) { + ProposalState proposerLatestProposalState = _proposals[latestProposalId].state; + + // TODO: Fix require statement + require( + proposerLatestProposalState == ProposalState.Queued || + proposerLatestProposalState == ProposalState.Rejected || + proposerLatestProposalState == ProposalState.Defeated || + proposerLatestProposalState == ProposalState.Canceled || + proposerLatestProposalState == ProposalState.Executed + ); + } + + uint256 startBlock = block.number + VOTING_DELAY; + uint256 endBlock = startBlock + VOTING_PERIOD; + uint256 thisProposalId = proposalCount++; + + _proposals[thisProposalId] = Proposal({ + proposer: msg.sender, + state: ProposalState.PendingThresholdVerification, + eta: 0, + targets: targets, + values: values, + signatures: signatures, + calldatas: calldatas, + startBlock: startBlock, + endBlock: endBlock, + forVotes: _EUINT64_ZERO, + againstVotes: _EUINT64_ZERO, + forVotesDecrypted: 0, + againstVotesDecrypted: 0 + }); + + latestProposalIds[msg.sender] = thisProposalId; + + emit ProposalCreated( + thisProposalId, + msg.sender, + targets, + values, + signatures, + calldatas, + startBlock, + endBlock, + description + ); + + ebool canPropose = TFHE.lt( + _EUINT64_PROPOSAL_THRESHOLD, + COMP.getPriorVotesForAllowedContract(msg.sender, block.number - 1) + ); + + uint256[] memory cts = new uint256[](1); + cts[0] = Gateway.toUint256(canPropose); + + uint256 requestId = Gateway.requestDecryption( + cts, + this.callbackInitiateProposal.selector, + 0, + block.timestamp + 100, + false + ); + + _requestIdToProposalId[requestId] = thisProposalId; + + return thisProposalId; + } + + /** + * @notice Queue a new proposal. + * @dev It can be done only if the proposal is adopted. + * @param proposalId Proposal id. + */ + function queue(uint256 proposalId) external { + Proposal storage proposal = _proposals[proposalId]; + + require( + proposal.state == ProposalState.Succeeded, + "GovernorAlpha::queue: proposal can only be queued if it is succeeded" + ); + + uint256 eta = block.timestamp + TIMELOCK.delay(); + + for (uint256 i = 0; i < proposal.targets.length; i++) { + _queueOrRevert(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], eta); + } + + proposal.eta = eta; + + emit ProposalQueued(proposalId, eta); + } + + /** + * @notice Request the vote results to be decrypted. + * @param proposalId Proposal id. + */ + function requestVoteDecryption(uint256 proposalId) external { + require(_proposals[proposalId].state == ProposalState.Active, "GovernorAlpha::_castVote: voting is closed"); + require(_proposals[proposalId].endBlock < block.number); + uint256[] memory cts = new uint256[](2); + cts[0] = Gateway.toUint256(_proposals[proposalId].forVotes); + cts[1] = Gateway.toUint256(_proposals[proposalId].againstVotes); + + uint256 requestId = Gateway.requestDecryption( + cts, + this.callbackVoteDecryption.selector, + 0, + block.timestamp + 100, + false + ); + + _requestIdToProposalId[requestId] = proposalId; + _proposals[proposalId].state = ProposalState.PendingResults; + } + + /** + * @dev Only callable by the gateway. + */ + function callbackInitiateProposal(uint256 requestId, bool canInitiate) public onlyGateway { + uint256 proposalId = _requestIdToProposalId[requestId]; + + if (canInitiate) { + _proposals[proposalId].state = ProposalState.Active; + emit ProposalActive(proposalId); + } else { + _proposals[proposalId].state = ProposalState.Rejected; + emit ProposalRejected(proposalId); + } + } + + /** + * @dev Only callable by the gateway. + * @param forVotesDecrypted For votes. + * @param againstVotesDecrypted Against votes. + */ + function callbackVoteDecryption( + uint256 requestId, + uint256 forVotesDecrypted, + uint256 againstVotesDecrypted + ) public onlyGateway { + uint256 proposalId = _requestIdToProposalId[requestId]; + + /// @dev It is safe to downcast since the original values were euint64. + _proposals[proposalId].forVotesDecrypted = uint64(forVotesDecrypted); + _proposals[proposalId].againstVotesDecrypted = uint64(againstVotesDecrypted); + + if (forVotesDecrypted > againstVotesDecrypted && forVotesDecrypted >= QUORUM_VOTES) { + _proposals[proposalId].state = ProposalState.Succeeded; + emit ProposalSucceeded(proposalId); + } else { + _proposals[proposalId].state = ProposalState.Defeated; + + emit ProposalDefeated(proposalId); + } + } + + /** + * @dev Only callable by owner. + */ + function acceptTimelockAdmin() external onlyOwner { + TIMELOCK.acceptAdmin(); + } + + /** + * @dev Only callable by owner. + * @param newPendingAdmin Address of the new pending admin for the timelock. + * @param eta Eta for executing the transaction in the timelock. + */ + function executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) external onlyOwner { + TIMELOCK.executeTransaction(address(TIMELOCK), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta); + } + + /** + * @dev Only callable by owner. + * @param newPendingAdmin Address of the new pending admin for the timelock. + * @param eta Eta for queuing the transaction in the timelock. + */ + function queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) external onlyOwner { + TIMELOCK.queueTransaction(address(TIMELOCK), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta); + } + + /** + * @dev Returns the actions for a proposal id. + * @return targets Target addresses. + * @return values Values. + * @return signatures Signatures. + * @return calldatas Calldatas. + */ + function getActions( + uint256 proposalId + ) + external + view + returns ( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas + ) + { + Proposal storage p = _proposals[proposalId]; + return (p.targets, p.values, p.signatures, p.calldatas); + } + + /** + * @notice Returns proposal information for a proposal id. + * @param proposalId Proposal id. + * @return propInfo Proposal information. + */ + function getProposalInfo(uint256 proposalId) external view returns (ProposalInfo memory propInfo) { + Proposal memory proposal = _proposals[proposalId]; + propInfo.proposer = proposal.proposer; + propInfo.state = proposal.state; + propInfo.eta = proposal.eta; + propInfo.targets = proposal.targets; + propInfo.values = proposal.values; + propInfo.signatures = proposal.signatures; + propInfo.calldatas = proposal.calldatas; + propInfo.startBlock = proposal.startBlock; + propInfo.endBlock = proposal.endBlock; + + if ((propInfo.state == ProposalState.Queued) && (block.timestamp > propInfo.eta + TIMELOCK.GRACE_PERIOD())) { + propInfo.state == ProposalState.Expired; + } + } + + /** + * @notice Returns the vote receipt information for the account for a proposal id. + * @param proposalId Proposal id. + * @param account Account address. + * @return hasVoted Whether the account has voted. + * @return support The support for the account (true ==> vote for, false ==> vote against). + * @return votes The number of votes cast. + */ + function getReceipt(uint256 proposalId, address account) external view returns (bool, ebool, euint64) { + Receipt memory myReceipt = _accountReceiptForProposalId[proposalId][account]; + return (myReceipt.hasVoted, myReceipt.support, myReceipt.votes); + } + + function _queueOrRevert( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) internal { + require( + !TIMELOCK.queuedTransactions(keccak256(abi.encode(target, value, signature, data, eta))), + "GovernorAlpha::_queueOrRevert: proposal action already queued at eta" + ); + TIMELOCK.queueTransaction(target, value, signature, data, eta); + } + + function _castVote(address voter, uint256 proposalId, ebool support) internal { + Proposal storage proposal = _proposals[proposalId]; + // TODO: fix require + require(_proposals[proposalId].endBlock <= block.number); + require(proposal.state == ProposalState.Active, "GovernorAlpha::_castVote: voting is closed"); + + Receipt storage receipt = _accountReceiptForProposalId[proposalId][voter]; + require(!receipt.hasVoted, "GovernorAlpha::_castVote: voter already voted"); + + euint64 votes = COMP.getPriorVotesForAllowedContract(voter, proposal.startBlock); + proposal.forVotes = TFHE.select(support, TFHE.add(proposal.forVotes, votes), proposal.forVotes); + proposal.againstVotes = TFHE.select(support, proposal.againstVotes, TFHE.add(proposal.againstVotes, votes)); + + receipt.hasVoted = true; + receipt.support = support; + receipt.votes = votes; + + TFHE.allowThis(proposal.forVotes); + TFHE.allowThis(proposal.againstVotes); + TFHE.allowThis(receipt.support); + TFHE.allowThis(receipt.votes); + TFHE.allow(receipt.support, msg.sender); + TFHE.allow(receipt.votes, msg.sender); + + // `support` and `votes` are encrypted values, no need to include them in the event. + emit VoteCast(voter, proposalId); + } +} diff --git a/contracts/DAO/GovernorZama.sol b/contracts/DAO/GovernorZama.sol deleted file mode 100644 index e668713..0000000 --- a/contracts/DAO/GovernorZama.sol +++ /dev/null @@ -1,466 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -pragma solidity ^0.8.24; - -import "fhevm/abstracts/Reencrypt.sol"; -import "fhevm/lib/TFHE.sol"; - -contract GovernorZama is Reencrypt { - /// @notice The name of this contract - string public constant name = "Compound Governor Zama"; - - uint32 public immutable VOTING_PERIOD; // Duration of voting in number of blocks, typically should by at least a few days, default was 3 days originally ~21600 blocks if 12s per block - // WARNING: do not use too small value in production such as 5 or a few dozens to avoid security issues, unless for testing purpose - - /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed - function quorumVotes() public pure returns (uint256) { - return 400000e6; - } // 400,000 = 4% of Comp - - /// @notice The number of votes required in order for a voter to become a proposer - function proposalThreshold() public pure returns (uint64) { - return 100000e6; - } // 100,000 = 1% of Comp - - /// @notice The maximum number of actions that can be included in a proposal - function proposalMaxOperations() public pure returns (uint32) { - return 10; - } // 10 actions - - /// @notice The delay before voting on a proposal may take place, once proposed - function votingDelay() public pure returns (uint32) { - return 1; - } // 1 block - - /// @notice The duration of voting on a proposal, in blocks - function votingPeriod() public view virtual returns (uint32) { - return VOTING_PERIOD; - } // recommended 3 days in blocks, i.e 21600 (assuming 12s blocks) - - /// @notice The address of the Compound Protocol Timelock - TimelockInterface public timelock; - - /// @notice The address of the Compound governance token - CompInterface public comp; - - /// @notice The address of the Governor Guardian - address public guardian; - - /// @notice The total number of proposals - uint256 public proposalCount; - - struct Proposal { - /// @notice Unique id for looking up a proposal - uint256 id; - /// @notice Creator of the proposal - address proposer; - /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds - uint256 eta; - /// @notice the ordered list of target addresses for calls to be made - address[] targets; - /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made - uint256[] values; - /// @notice The ordered list of function signatures to be called - string[] signatures; - /// @notice The ordered list of calldata to be passed to each call - bytes[] calldatas; - /// @notice The block at which voting begins: holders must delegate their votes prior to this block - uint256 startBlock; - /// @notice The block at which voting ends: votes must be cast prior to this block - uint256 endBlock; - /// @notice Current number of votes in favor of this proposal - euint64 forVotes; - /// @notice Current number of votes in opposition to this proposal - euint64 againstVotes; - /// @notice Flag marking whether the proposal has been canceled - bool canceled; - /// @notice Flag marking whether the proposal has been executed - bool executed; - /// @notice Receipts of ballots for the entire set of voters - mapping(address => Receipt) receipts; - } - - struct ProposalInfo { - /// @notice Unique id for looking up a proposal - uint256 id; - /// @notice Creator of the proposal - address proposer; - /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds - uint256 eta; - /// @notice the ordered list of target addresses for calls to be made - address[] targets; - /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made - uint256[] values; - /// @notice The ordered list of function signatures to be called - string[] signatures; - /// @notice The ordered list of calldata to be passed to each call - bytes[] calldatas; - /// @notice The block at which voting begins: holders must delegate their votes prior to this block - uint256 startBlock; - /// @notice The block at which voting ends: votes must be cast prior to this block - uint256 endBlock; - /// @notice Flag marking whether the proposal has been canceled - bool canceled; - /// @notice Flag marking whether the proposal has been executed - bool executed; - } - - /// @notice Ballot receipt record for a voter - struct Receipt { - /// @notice Whether or not a vote has been cast - bool hasVoted; - /// @notice Whether or not the voter supports the proposal - ebool support; - /// @notice The number of votes the voter had, which were cast - euint64 votes; - } - - /// @notice Possible states that a proposal may be in - enum ProposalState { - Pending, - Active, - Canceled, - Defeated, - Succeeded, - Queued, - Expired, - Executed - } - - /// @notice The official record of all proposals ever proposed - mapping(uint256 => Proposal) internal proposals; - - /// @notice The latest proposal for each proposer - mapping(address => uint256) public latestProposalIds; - - /// @notice An event emitted when a new proposal is created - event ProposalCreated( - uint256 id, - address proposer, - address[] targets, - uint256[] values, - string[] signatures, - bytes[] calldatas, - uint256 startBlock, - uint256 endBlock, - string description - ); - - /// @notice An event emitted when a vote has been cast on a proposal - event VoteCast(address voter, uint256 proposalId); - - /// @notice An event emitted when a proposal has been canceled - event ProposalCanceled(uint256 id); - - /// @notice An event emitted when a proposal has been queued in the Timelock - event ProposalQueued(uint256 id, uint256 eta); - - /// @notice An event emitted when a proposal has been executed in the Timelock - event ProposalExecuted(uint256 id); - - constructor(address timelock_, address comp_, address guardian_, uint32 _votingPeriod) { - timelock = TimelockInterface(timelock_); - comp = CompInterface(comp_); - guardian = guardian_; - VOTING_PERIOD = _votingPeriod; // WARNING: do not use too small value in production such as 5 or a few dozens to avoid security issues, unless for testing purpose, typically should by at least a few days, default was 3 days originally i.e votingPeriod=21600 blocks if 12s per block - } - - function propose( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas, - string memory description - ) public returns (uint256) { - require( - TFHE.decrypt(TFHE.lt(proposalThreshold(), comp.getPriorVotes(msg.sender, block.number - 1))), - "GovernorAlpha::propose: proposer votes below proposal threshold" - ); - require( - targets.length == values.length && - targets.length == signatures.length && - targets.length == calldatas.length, - "GovernorAlpha::propose: proposal function information arity mismatch" - ); - require(targets.length != 0, "GovernorAlpha::propose: must provide actions"); - require(targets.length <= proposalMaxOperations(), "GovernorAlpha::propose: too many actions"); - - uint256 latestProposalId = latestProposalIds[msg.sender]; - if (latestProposalId != 0) { - ProposalState proposersLatestProposalState = state(latestProposalId); - require( - proposersLatestProposalState != ProposalState.Active, - "GovernorAlpha::propose: one live proposal per proposer, found an already active proposal" - ); - require( - proposersLatestProposalState != ProposalState.Pending, - "GovernorAlpha::propose: one live proposal per proposer, found an already pending proposal" - ); - } - - uint256 startBlock = block.number + votingDelay(); - uint256 endBlock = startBlock + votingPeriod(); - - proposalCount++; - uint256 proposalId = proposalCount; - Proposal storage newProposal = proposals[proposalId]; - - newProposal.id = proposalId; - newProposal.proposer = msg.sender; - newProposal.eta = 0; - newProposal.targets = targets; - newProposal.values = values; - newProposal.signatures = signatures; - newProposal.forVotes = TFHE.asEuint64(0); - newProposal.againstVotes = TFHE.asEuint64(0); - newProposal.calldatas = calldatas; - newProposal.startBlock = startBlock; - newProposal.endBlock = endBlock; - newProposal.canceled = false; - newProposal.executed = false; - - latestProposalIds[newProposal.proposer] = newProposal.id; - - emit ProposalCreated( - newProposal.id, - msg.sender, - targets, - values, - signatures, - calldatas, - startBlock, - endBlock, - description - ); - return newProposal.id; - } - - function queue(uint256 proposalId) public { - require( - state(proposalId) == ProposalState.Succeeded, - "GovernorAlpha::queue: proposal can only be queued if it is succeeded" - ); - Proposal storage proposal = proposals[proposalId]; - uint256 eta = block.timestamp + timelock.delay(); - - for (uint256 i = 0; i < proposal.targets.length; i++) { - _queueOrRevert(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], eta); - } - proposal.eta = eta; - emit ProposalQueued(proposalId, eta); - } - - function _queueOrRevert( - address target, - uint256 value, - string memory signature, - bytes memory data, - uint256 eta - ) internal { - require( - !timelock.queuedTransactions(keccak256(abi.encode(target, value, signature, data, eta))), - "GovernorAlpha::_queueOrRevert: proposal action already queued at eta" - ); - timelock.queueTransaction(target, value, signature, data, eta); - } - - function execute(uint256 proposalId) public payable { - require( - state(proposalId) == ProposalState.Queued, - "GovernorAlpha::execute: proposal can only be executed if it is queued" - ); - Proposal storage proposal = proposals[proposalId]; - proposal.executed = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.executeTransaction{ value: proposal.values[i] }( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } - emit ProposalExecuted(proposalId); - } - - function cancel(uint256 proposalId) public { - ProposalState proposalState = state(proposalId); - require(proposalState != ProposalState.Executed, "GovernorAlpha::cancel: cannot cancel executed proposal"); - - Proposal storage proposal = proposals[proposalId]; - - ebool proposerAboveThreshold = TFHE.lt(proposalThreshold(), comp.getPriorVotes(msg.sender, block.number - 1)); - - require(msg.sender == guardian || TFHE.decrypt(proposerAboveThreshold)); - - proposal.canceled = true; - for (uint256 i = 0; i < proposal.targets.length; i++) { - timelock.cancelTransaction( - proposal.targets[i], - proposal.values[i], - proposal.signatures[i], - proposal.calldatas[i], - proposal.eta - ); - } - - emit ProposalCanceled(proposalId); - } - - function getActions( - uint256 proposalId - ) - public - view - returns ( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas - ) - { - Proposal storage p = proposals[proposalId]; - return (p.targets, p.values, p.signatures, p.calldatas); - } - - function getMyReceipt( - uint256 proposalId, - bytes32 publicKey, - bytes calldata signature - ) external view onlySignedPublicKey(publicKey, signature) returns (bool, bytes memory, bytes memory) { - Receipt memory myReceipt = proposals[proposalId].receipts[msg.sender]; - return ( - myReceipt.hasVoted, - TFHE.reencrypt(myReceipt.support, publicKey, false), - TFHE.reencrypt(myReceipt.votes, publicKey, 0) - ); - } - - function getProposalInfo(uint256 proposalId) external view returns (ProposalInfo memory propInfo) { - require(proposalId <= proposalCount && proposalId != 0, "Invalid proposalId"); - Proposal storage proposal = proposals[proposalId]; - propInfo.id = proposal.id; - propInfo.proposer = proposal.proposer; - propInfo.eta = proposal.eta; - propInfo.targets = proposal.targets; - propInfo.values = proposal.values; - propInfo.signatures = proposal.signatures; - propInfo.calldatas = proposal.calldatas; - propInfo.startBlock = proposal.startBlock; - propInfo.endBlock = proposal.endBlock; - propInfo.canceled = proposal.canceled; - propInfo.executed = proposal.executed; - } - - function isDefeated(Proposal storage proposal) private view returns (bool) { - ebool defeated = TFHE.le(proposal.forVotes, proposal.againstVotes); - ebool notReachedQuorum = TFHE.lt(proposal.forVotes, uint64(quorumVotes())); - - return TFHE.decrypt(TFHE.or(notReachedQuorum, defeated)); - } - - function state(uint256 proposalId) public view returns (ProposalState) { - require(proposalCount >= proposalId && proposalId > 0, "GovernorAlpha::state: invalid proposal id"); - Proposal storage proposal = proposals[proposalId]; - if (proposal.canceled) { - return ProposalState.Canceled; - } else if (block.number <= proposal.startBlock) { - return ProposalState.Pending; - } else if (block.number <= proposal.endBlock) { - return ProposalState.Active; - } else if (isDefeated(proposal)) { - return ProposalState.Defeated; - } else if (proposal.eta == 0) { - return ProposalState.Succeeded; - } else if (proposal.executed) { - return ProposalState.Executed; - } else if (block.timestamp >= proposal.eta + timelock.GRACE_PERIOD()) { - return ProposalState.Expired; - } else { - return ProposalState.Queued; - } - } - - function castVote(uint256 proposalId, bytes calldata support) public { - return castVote(proposalId, TFHE.asEbool(support)); - } - - function castVote(uint256 proposalId, ebool support) public { - return _castVote(msg.sender, proposalId, support); - } - - function _castVote(address voter, uint256 proposalId, ebool support) internal { - require(state(proposalId) == ProposalState.Active, "GovernorAlpha::_castVote: voting is closed"); - Proposal storage proposal = proposals[proposalId]; - Receipt storage receipt = proposal.receipts[voter]; - require(receipt.hasVoted == false, "GovernorAlpha::_castVote: voter already voted"); - euint64 votes = comp.getPriorVotes(voter, proposal.startBlock); - - proposal.forVotes = TFHE.select(support, proposal.forVotes + votes, proposal.forVotes); - proposal.againstVotes = TFHE.select(support, proposal.againstVotes, proposal.againstVotes + votes); - - receipt.hasVoted = true; - receipt.support = support; - receipt.votes = votes; - - // `support` and `votes` are encrypted values, no need to include them in the event. - emit VoteCast(voter, proposalId); - } - - function __acceptAdmin() public { - require(msg.sender == guardian, "GovernorAlpha::__acceptAdmin: sender must be gov guardian"); - timelock.acceptAdmin(); - } - - function __abdicate() public { - require(msg.sender == guardian, "GovernorAlpha::__abdicate: sender must be gov guardian"); - guardian = address(0); - } - - function __queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public { - require(msg.sender == guardian, "GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian"); - timelock.queueTransaction(address(timelock), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta); - } - - function __executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public { - require(msg.sender == guardian, "GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian"); - timelock.executeTransaction(address(timelock), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta); - } -} - -interface TimelockInterface { - function delay() external view returns (uint256); - - function GRACE_PERIOD() external view returns (uint256); - - function acceptAdmin() external; - - function queuedTransactions(bytes32 hash) external view returns (bool); - - function queueTransaction( - address target, - uint256 value, - string calldata signature, - bytes calldata data, - uint256 eta - ) external returns (bytes32); - - function cancelTransaction( - address target, - uint256 value, - string calldata signature, - bytes calldata data, - uint256 eta - ) external; - - function executeTransaction( - address target, - uint256 value, - string calldata signature, - bytes calldata data, - uint256 eta - ) external payable returns (bytes memory); -} - -interface CompInterface { - function getPriorVotes(address account, uint256 blockNumber) external view returns (euint64); -} diff --git a/contracts/DAO/IComp.sol b/contracts/DAO/IComp.sol index 8dd470b..e8866ad 100644 --- a/contracts/DAO/IComp.sol +++ b/contracts/DAO/IComp.sol @@ -5,7 +5,7 @@ import "fhevm/lib/TFHE.sol"; /** * @title IComp - * @dev The GovernorZama relies on this interface. + * @dev The GovernorAlphaZama relies on this interface. */ interface IComp { function getPriorVotesForAllowedContract(address account, uint256 blockNumber) external returns (euint64 votes); From dfbbde10dca594dee8584c5441ddadcaedeedb9e Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 6 Nov 2024 09:52:38 +0100 Subject: [PATCH 47/73] fix: Comp.sol --- contracts/DAO/Comp.sol | 7 +++++-- test/dao/Comp.fixture.ts | 12 ++++++------ test/dao/DelegateBySig.ts | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/contracts/DAO/Comp.sol b/contracts/DAO/Comp.sol index 6d22a30..e79e41a 100644 --- a/contracts/DAO/Comp.sol +++ b/contracts/DAO/Comp.sol @@ -8,7 +8,7 @@ import { IComp } from "./IComp.sol"; /** * @title Comp - * @notice This contract inherits EncryptedERC20. + * @notice This contract inherits EncryptedERC20 and Ownable2Step. * This is based on the Comp.sol contract written by Compound Labs. * see: compound-finance/compound-protocol/blob/master/contracts/Governance/Comp.sol * It uses encrypted votes to delegate the voting power associated @@ -169,11 +169,14 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { function _getPriorVote(address account, uint256 blockNumber) internal view returns (euint64 votes) { uint32 nCheckpoints = numCheckpoints[account]; - if (nCheckpoints == 0) {} else if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { + if (nCheckpoints == 0) { + return _EUINT64_ZERO; + } else if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { // First check most recent balance votes = checkpoints[account][nCheckpoints - 1].votes; } else if (checkpoints[account][0].fromBlock > blockNumber) { // Next check implicit zero balance + return _EUINT64_ZERO; } else { // Search for the voting power at the block number uint32 lower = 0; diff --git a/test/dao/Comp.fixture.ts b/test/dao/Comp.fixture.ts index 3d5e592..d045615 100644 --- a/test/dao/Comp.fixture.ts +++ b/test/dao/Comp.fixture.ts @@ -15,24 +15,24 @@ export async function deployCompFixture(signers: Signers): Promise { export async function reencryptCurrentVotes( signers: Signers, instances: FhevmInstances, - user: string, + account: string, comp: Comp, compAddress: string, ): Promise { - const voteHandle = await comp.getCurrentVotes(signers[user as keyof Signers].address); - const vote = await reencryptEuint64(signers, instances, user, voteHandle, compAddress); + const voteHandle = await comp.getCurrentVotes(signers[account as keyof Signers].address); + const vote = await reencryptEuint64(signers, instances, account, voteHandle, compAddress); return vote; } export async function reencryptPriorVotes( signers: Signers, instances: FhevmInstances, - user: string, + account: string, blockNumber: number, comp: Comp, compAddress: string, ): Promise { - const voteHandle = await comp.getPriorVotes(signers[user as keyof Signers].address, blockNumber); - const vote = await reencryptEuint64(signers, instances, user, voteHandle, compAddress); + const voteHandle = await comp.getPriorVotes(signers[account as keyof Signers].address, blockNumber); + const vote = await reencryptEuint64(signers, instances, account, voteHandle, compAddress); return vote; } diff --git a/test/dao/DelegateBySig.ts b/test/dao/DelegateBySig.ts index 62ef43d..bc0fe7c 100644 --- a/test/dao/DelegateBySig.ts +++ b/test/dao/DelegateBySig.ts @@ -4,7 +4,7 @@ import { Address } from "hardhat-deploy/types"; import type { Comp } from "../../types"; -export const delegateBySigSignature = async ( +export const delegateBySig = async ( _signer: HardhatEthersSigner, _delegatee: Address, _comp: Comp, From 76495c7840cde2b79728b7054756c3eb910ecf27 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 6 Nov 2024 09:53:47 +0100 Subject: [PATCH 48/73] docs: Natspec --- contracts/token/ERC20/IEncryptedERC20.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/token/ERC20/IEncryptedERC20.sol b/contracts/token/ERC20/IEncryptedERC20.sol index bad4deb..16c9a2d 100644 --- a/contracts/token/ERC20/IEncryptedERC20.sol +++ b/contracts/token/ERC20/IEncryptedERC20.sol @@ -21,12 +21,12 @@ interface IEncryptedERC20 { event Transfer(address indexed from, address indexed to); /** - * @notice Emitted when receiver is address(0). + * @notice Returned when receiver is address(0). */ error ReceiverAddressNull(); /** - * @notice Emitted when sender is address(0). + * @notice Returned when sender is address(0). */ error SenderAddressNull(); From 5000265fe5747737a31ab37e97e1b3c992d8c712 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 6 Nov 2024 09:54:11 +0100 Subject: [PATCH 49/73] refactor: Custom errors GovernorAlphaZama.sol --- contracts/DAO/GovernorAlphaZama.sol | 202 ++++++++++++++++++---------- 1 file changed, 133 insertions(+), 69 deletions(-) diff --git a/contracts/DAO/GovernorAlphaZama.sol b/contracts/DAO/GovernorAlphaZama.sol index 9789a05..59fdc92 100644 --- a/contracts/DAO/GovernorAlphaZama.sol +++ b/contracts/DAO/GovernorAlphaZama.sol @@ -14,6 +14,33 @@ import { ICompoundTimelock } from "./ICompoundTimelock.sol"; * see: compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol */ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { + /// @notice Returned if proposal contains too many changes. + error LengthAboveMaxOperations(); + + /// @notice Returned if the array length is equal to 0. + error LengthIsNull(); + + /// @notice Returned if array lengths are not equal. + error LengthsDoNotMatch(); + + /// @notice Returned if proposal's actions have already been queued. + error ProposalActionsAlreadyQueued(); + + /// @notice Returned if the proposal state is invalid for this operation. + /// @dev It is returned for any proposal state not matching the expected + /// state to conduct the operation. + error ProposalStateInvalid(); + + /// @notice Returned if the proposal's state is active but `block.number` > `endBlock`. + error ProposalStateNotActive(); + + /// @notice Returned if the proposal state is still active. + error ProposalStateStillActive(); + + /// @notice Returned if the voter has already cast a vote + /// for this proposal. + error VoterHasAlreadyVoted(); + /// @notice Emitted when a proposal is now active. event ProposalActive(uint256 id); @@ -62,7 +89,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { Active, /// Proposal is active and voters can cast their votes. PendingResults, /// Proposal is active but the decryption of the result is in progress. Canceled, /// Proposal has been canceled by the proposer. - Defeated, /// Proposal has been defeated (either by not reaching the quorum or votesAgainst > votesFor). + Defeated, /// Proposal has been defeated (either by not reaching the quorum or `votesAgainst` > `votesFor`). Succeeded, /// Proposal has succeeded. Queued, /// Proposal has been queued in the timelock. Expired, /// Proposal has expired (@dev This state is used for read-only operations). @@ -74,14 +101,14 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param eta The timestamp that the proposal will be available for execution, * it is set automatically once the vote succeeds. * @param targets The ordered list of target addresses for calls to be made. - * @param values The ordered list of values (i.e. msg.value) to be passed to the calls to be made. + * @param values The ordered list of values (i.e. `msg.value`) to be passed to the calls to be made. * @param signatures The ordered list of function signatures to be called. * @param calldatas The ordered list of calldata to be passed to each call. * @param startBlock The block at which voting begins: holders must delegate their votes prior * to this block. * @param endBlock The block at which voting ends: votes must be cast prior to this block. - * @param forVotes Current number of votes in opposition to this proposal. - * @param againstVotes Current number of votes in opposition to this proposal. + * @param forVotes Current encrypted number of votes for to this proposal. + * @param againstVotes Current encrypted number of votes in opposition to this proposal. * @param forVotesDecrypted For votes once decrypted by the gateway. * @param againstVotesDecrypted Against votes once decrypted by the gateway. */ @@ -107,13 +134,13 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param state State of the proposal. * @param eta The timestamp when the proposal will be available for execution, set once the vote succeeds. * @param targets The ordered list of target addresses for calls to be made. - * @param values The ordered list of values (i.e. msg.value) to be passed to the calls to be made. + * @param values The ordered list of values (i.e. `msg.value`) to be passed to the calls to be made. * @param signatures The ordered list of function signatures to be called. * @param calldatas The ordered list of calldata to be passed to each call. * @param startBlock The block at which voting begins: holders must delegate their votes prior to this block. * @param endBlock The block at which voting ends: votes must be cast prior to this block. - * @param forVotes Current number of votes in opposition to this proposal. - * @param againstVotes Current number of votes in opposition to this proposal. + * @param forVotes Number of votes for this proposal once decrypted. + * @param againstVotes Number of votes in opposition to this proposal once decrypted. */ struct ProposalInfo { address proposer; @@ -125,6 +152,8 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { bytes[] calldatas; uint256 startBlock; uint256 endBlock; + uint64 forVotes; + uint64 againstVotes; } /** @@ -190,10 +219,10 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /// @notice Ballot receipt for an account for a proposal id. mapping(uint256 proposalId => mapping(address => Receipt)) internal _accountReceiptForProposalId; - /// @notice The official record of all _proposals ever proposed. + /// @notice The official record of all proposals that have been created. mapping(uint256 proposalId => Proposal proposal) internal _proposals; - /// @notice Returns the proposal id associated with the request id. + /// @notice Returns the proposal id associated with the request id from the Gateway. /// @dev This mapping is used for decryption. mapping(uint256 requestId => uint256 proposalId) internal _requestIdToProposalId; @@ -214,7 +243,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { COMP = IComp(comp_); VOTING_PERIOD = votingPeriod_; - // @dev Store these constants in the storage. + // @dev Store these constant-like variables in the storage. _EUINT64_ZERO = TFHE.asEuint64(0); _EUINT64_PROPOSAL_THRESHOLD = TFHE.asEuint64(PROPOSAL_THRESHOLD); @@ -226,13 +255,19 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @notice Cancel the proposal. * @param proposalId Proposal id. * @dev Only the owner address or the proposer can cancel. - * In the original GovernorAlpha, the proposer can cancel only if the votes are still - * above the threshold. + * In the original GovernorAlpha, the proposer can cancel only if + * her votes are still above the threshold. */ function cancel(uint256 proposalId) external { Proposal storage proposal = _proposals[proposalId]; - require(proposal.state != ProposalState.Executed, "GovernorAlpha::cancel: cannot cancel executed proposal"); - require(proposal.state != ProposalState.Canceled, "GovernorAlpha::cancel: cannot cancel canceled proposal"); + + if ( + proposal.state == ProposalState.Executed || + proposal.state == ProposalState.Canceled || + proposal.state == ProposalState.Defeated + ) { + revert ProposalStateInvalid(); + } if (msg.sender != proposal.proposer) { _checkOwner(); @@ -284,10 +319,9 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { function execute(uint256 proposalId) external payable { Proposal memory proposal = _proposals[proposalId]; - require( - proposal.state == ProposalState.Queued, - "GovernorAlpha::execute: proposal can only be executed if it is queued" - ); + if (proposal.state != ProposalState.Queued) { + revert ProposalStateInvalid(); + } // proposal.executed = true; for (uint256 i = 0; i < proposal.targets.length; i++) { @@ -321,12 +355,18 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { ) external returns (uint256 proposalId) { { uint256 length = targets.length; - require( - length == values.length && length == signatures.length && length == calldatas.length, - "GovernorAlpha::propose: proposal function information arity mismatch" - ); - require(length != 0, "GovernorAlpha::propose: must provide actions"); - require(length <= PROPOSAL_MAX_OPERATIONS, "GovernorAlpha::propose: too many actions"); + + if (length != values.length || length != signatures.length || length != calldatas.length) { + revert LengthsDoNotMatch(); + } + + if (length == 0) { + revert LengthIsNull(); + } + + if (length > PROPOSAL_MAX_OPERATIONS) { + revert LengthAboveMaxOperations(); + } } uint256 latestProposalId = latestProposalIds[msg.sender]; @@ -334,14 +374,15 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { if (latestProposalId != 0) { ProposalState proposerLatestProposalState = _proposals[latestProposalId].state; - // TODO: Fix require statement - require( - proposerLatestProposalState == ProposalState.Queued || - proposerLatestProposalState == ProposalState.Rejected || - proposerLatestProposalState == ProposalState.Defeated || - proposerLatestProposalState == ProposalState.Canceled || - proposerLatestProposalState == ProposalState.Executed - ); + if ( + proposerLatestProposalState != ProposalState.Queued && + proposerLatestProposalState != ProposalState.Rejected && + proposerLatestProposalState != ProposalState.Defeated && + proposerLatestProposalState != ProposalState.Canceled && + proposerLatestProposalState != ProposalState.Executed + ) { + revert ProposalStateInvalid(); + } } uint256 startBlock = block.number + VOTING_DELAY; @@ -407,10 +448,9 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { function queue(uint256 proposalId) external { Proposal storage proposal = _proposals[proposalId]; - require( - proposal.state == ProposalState.Succeeded, - "GovernorAlpha::queue: proposal can only be queued if it is succeeded" - ); + if (proposal.state != ProposalState.Succeeded) { + revert ProposalStateInvalid(); + } uint256 eta = block.timestamp + TIMELOCK.delay(); @@ -428,8 +468,14 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param proposalId Proposal id. */ function requestVoteDecryption(uint256 proposalId) external { - require(_proposals[proposalId].state == ProposalState.Active, "GovernorAlpha::_castVote: voting is closed"); - require(_proposals[proposalId].endBlock < block.number); + if (_proposals[proposalId].state != ProposalState.Active) { + revert ProposalStateInvalid(); + } + + if (_proposals[proposalId].endBlock >= block.number) { + revert ProposalStateStillActive(); + } + uint256[] memory cts = new uint256[](2); cts[0] = Gateway.toUint256(_proposals[proposalId].forVotes); cts[1] = Gateway.toUint256(_proposals[proposalId].againstVotes); @@ -447,7 +493,9 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { } /** - * @dev Only callable by the gateway. + * @dev Only callable by the gateway. + * @param requestId Request id (from the Gateway) + * @param canInitiate Whether the proposal can be initiated. */ function callbackInitiateProposal(uint256 requestId, bool canInitiate) public onlyGateway { uint256 proposalId = _requestIdToProposalId[requestId]; @@ -482,20 +530,19 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { emit ProposalSucceeded(proposalId); } else { _proposals[proposalId].state = ProposalState.Defeated; - emit ProposalDefeated(proposalId); } } /** - * @dev Only callable by owner. + * @dev Only callable by `owner`. */ function acceptTimelockAdmin() external onlyOwner { TIMELOCK.acceptAdmin(); } /** - * @dev Only callable by owner. + * @dev Only callable by `owner`. * @param newPendingAdmin Address of the new pending admin for the timelock. * @param eta Eta for executing the transaction in the timelock. */ @@ -504,7 +551,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { } /** - * @dev Only callable by owner. + * @dev Only callable by `owner`. * @param newPendingAdmin Address of the new pending admin for the timelock. * @param eta Eta for queuing the transaction in the timelock. */ @@ -514,6 +561,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /** * @dev Returns the actions for a proposal id. + * @param proposalId Proposal id. * @return targets Target addresses. * @return values Values. * @return signatures Signatures. @@ -536,24 +584,32 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { } /** - * @notice Returns proposal information for a proposal id. - * @param proposalId Proposal id. - * @return propInfo Proposal information. + * @notice Returns proposal information for a proposal id. + * @dev It returns decrypted `forVotes`/`againstVotes`. + * These are only available after the decryption. + * @param proposalId Proposal id. + * @return proposalInfo Proposal information. */ - function getProposalInfo(uint256 proposalId) external view returns (ProposalInfo memory propInfo) { + function getProposalInfo(uint256 proposalId) external view returns (ProposalInfo memory proposalInfo) { Proposal memory proposal = _proposals[proposalId]; - propInfo.proposer = proposal.proposer; - propInfo.state = proposal.state; - propInfo.eta = proposal.eta; - propInfo.targets = proposal.targets; - propInfo.values = proposal.values; - propInfo.signatures = proposal.signatures; - propInfo.calldatas = proposal.calldatas; - propInfo.startBlock = proposal.startBlock; - propInfo.endBlock = proposal.endBlock; - - if ((propInfo.state == ProposalState.Queued) && (block.timestamp > propInfo.eta + TIMELOCK.GRACE_PERIOD())) { - propInfo.state == ProposalState.Expired; + proposalInfo.proposer = proposal.proposer; + proposalInfo.state = proposal.state; + proposalInfo.eta = proposal.eta; + proposalInfo.targets = proposal.targets; + proposalInfo.values = proposal.values; + proposalInfo.signatures = proposal.signatures; + proposalInfo.calldatas = proposal.calldatas; + proposalInfo.startBlock = proposal.startBlock; + proposalInfo.endBlock = proposal.endBlock; + proposalInfo.forVotes = proposal.forVotesDecrypted; + proposalInfo.againstVotes = proposal.againstVotesDecrypted; + + // The state is adjusted but not closed. + if ( + (proposalInfo.state == ProposalState.Queued) && + (block.timestamp > proposalInfo.eta + TIMELOCK.GRACE_PERIOD()) + ) { + proposalInfo.state == ProposalState.Expired; } } @@ -566,8 +622,8 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @return votes The number of votes cast. */ function getReceipt(uint256 proposalId, address account) external view returns (bool, ebool, euint64) { - Receipt memory myReceipt = _accountReceiptForProposalId[proposalId][account]; - return (myReceipt.hasVoted, myReceipt.support, myReceipt.votes); + Receipt memory receipt = _accountReceiptForProposalId[proposalId][account]; + return (receipt.hasVoted, receipt.support, receipt.votes); } function _queueOrRevert( @@ -577,21 +633,29 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { bytes memory data, uint256 eta ) internal { - require( - !TIMELOCK.queuedTransactions(keccak256(abi.encode(target, value, signature, data, eta))), - "GovernorAlpha::_queueOrRevert: proposal action already queued at eta" - ); + if (TIMELOCK.queuedTransactions(keccak256(abi.encode(target, value, signature, data, eta)))) { + revert ProposalActionsAlreadyQueued(); + } + TIMELOCK.queueTransaction(target, value, signature, data, eta); } function _castVote(address voter, uint256 proposalId, ebool support) internal { Proposal storage proposal = _proposals[proposalId]; - // TODO: fix require - require(_proposals[proposalId].endBlock <= block.number); - require(proposal.state == ProposalState.Active, "GovernorAlpha::_castVote: voting is closed"); + + if (proposal.state != ProposalState.Active) { + revert ProposalStateInvalid(); + } + + if (block.number > _proposals[proposalId].endBlock) { + revert ProposalStateNotActive(); + } Receipt storage receipt = _accountReceiptForProposalId[proposalId][voter]; - require(!receipt.hasVoted, "GovernorAlpha::_castVote: voter already voted"); + + if (receipt.hasVoted) { + revert VoterHasAlreadyVoted(); + } euint64 votes = COMP.getPriorVotesForAllowedContract(voter, proposal.startBlock); proposal.forVotes = TFHE.select(support, TFHE.add(proposal.forVotes, votes), proposal.forVotes); From c996867e90230c371982d1e340af877771a317c8 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 6 Nov 2024 09:55:31 +0100 Subject: [PATCH 50/73] test: Rename file --- .../{Timelock.ts => CompoundTimelock.test.ts} | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) rename test/dao/{Timelock.ts => CompoundTimelock.test.ts} (94%) diff --git a/test/dao/Timelock.ts b/test/dao/CompoundTimelock.test.ts similarity index 94% rename from test/dao/Timelock.ts rename to test/dao/CompoundTimelock.test.ts index 432edda..5b7f6c1 100644 --- a/test/dao/Timelock.ts +++ b/test/dao/CompoundTimelock.test.ts @@ -1,28 +1,29 @@ import { expect } from "chai"; import { ethers, network } from "hardhat"; -import { createInstances } from "../instance"; import { getSigners, initSigners } from "../signers"; -import { createTransaction, waitNBlocks } from "../utils"; -import { deployCompFixture } from "./Comp.fixture"; -import { deployGovernorZamaFixture, deployTimelockFixture } from "./GovernorZama.fixture"; +import { deployTimelockFixture } from "./GovernorAlphaZama.fixture"; -describe("Timelock", function () { +describe("CompoundTimelock", function () { before(async function () { - await initSigners(); + await initSigners(3); this.signers = await getSigners(); }); beforeEach(async function () { - this.timelock = await deployTimelockFixture(this.signers.alice); + this.timelock = await deployTimelockFixture(this.signers.alice.address); }); it("non-timelock account could not call setPendingAdmin", async function () { - await expect(this.timelock.setPendingAdmin(this.signers.bob)).to.throw; + await expect(this.timelock.setPendingAdmin(this.signers.bob)).to.be.revertedWith( + "Timelock::setPendingAdmin: Call must come from Timelock.", + ); }); it("non-timelock account could not call setDelay", async function () { - await expect(this.timelock.setDelay(60 * 60 * 24 * 3)).to.throw; + await expect(this.timelock.setDelay(60 * 60 * 24 * 3)).to.be.revertedWith( + "Timelock::setDelay: Call must come from Timelock.", + ); }); it("setDelay could only be called with a delay between MINIMUM_DELAY and MAXIMUM_DELAY", async function () { From 56ad0431d70c26ad5666a8c16d001fa94ed9779b Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 6 Nov 2024 09:56:07 +0100 Subject: [PATCH 51/73] test: Minor changes --- test/encryptedERC20/EncryptedERC20.fixture.ts | 12 ++++++------ .../EncryptedERC20WithErrors.fixture.ts | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/encryptedERC20/EncryptedERC20.fixture.ts b/test/encryptedERC20/EncryptedERC20.fixture.ts index 9b43c25..28e70dd 100644 --- a/test/encryptedERC20/EncryptedERC20.fixture.ts +++ b/test/encryptedERC20/EncryptedERC20.fixture.ts @@ -22,24 +22,24 @@ export async function deployEncryptedERC20Fixture( export async function reencryptAllowance( signers: Signers, instances: FhevmInstances, - user: string, + account: string, spender: string, token: IEncryptedERC20, tokenAddress: string, ): Promise { - const allowanceHandle = await token.allowance(signers[user as keyof Signers], signers[spender as keyof Signers]); - const allowance = await reencryptEuint64(signers, instances, user, allowanceHandle, tokenAddress); + const allowanceHandle = await token.allowance(signers[account as keyof Signers], signers[spender as keyof Signers]); + const allowance = await reencryptEuint64(signers, instances, account, allowanceHandle, tokenAddress); return allowance; } export async function reencryptBalance( signers: Signers, instances: FhevmInstances, - user: string, + account: string, token: IEncryptedERC20, tokenAddress: string, ): Promise { - const balanceHandle = await token.balanceOf(signers[user as keyof Signers]); - const balance = await reencryptEuint64(signers, instances, user, balanceHandle, tokenAddress); + const balanceHandle = await token.balanceOf(signers[account as keyof Signers]); + const balance = await reencryptEuint64(signers, instances, account, balanceHandle, tokenAddress); return balance; } diff --git a/test/encryptedERC20/EncryptedERC20WithErrors.fixture.ts b/test/encryptedERC20/EncryptedERC20WithErrors.fixture.ts index 14d1519..9d2c424 100644 --- a/test/encryptedERC20/EncryptedERC20WithErrors.fixture.ts +++ b/test/encryptedERC20/EncryptedERC20WithErrors.fixture.ts @@ -22,13 +22,13 @@ export async function deployEncryptedERC20WithErrorsFixture( export async function checkErrorCode( signers: Signers, instances: FhevmInstances, - user: string, + account: string, transferId: bigint, token: EncryptedERC20WithErrorsMintable, tokenAddress: string, ): Promise { const errorCodeHandle = await token.getErrorCodeForTransferId(transferId); - const errorCode = await reencryptEuint8(signers, instances, user, errorCodeHandle, tokenAddress); + const errorCode = await reencryptEuint8(signers, instances, account, errorCodeHandle, tokenAddress); switch (errorCode) { case BigInt(0): { return "NO_ERROR"; From 04a117f6d51aed0373dbb1b3c4ad6ed63dec1a13 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 6 Nov 2024 09:57:01 +0100 Subject: [PATCH 52/73] test: Refactor fixture for GovernorAlphaZama --- test/dao/GovernorAlphaZama.fixture.ts | 48 +++++++++++++++++++++++++++ test/dao/GovernorZama.fixture.ts | 28 ---------------- 2 files changed, 48 insertions(+), 28 deletions(-) create mode 100644 test/dao/GovernorAlphaZama.fixture.ts delete mode 100644 test/dao/GovernorZama.fixture.ts diff --git a/test/dao/GovernorAlphaZama.fixture.ts b/test/dao/GovernorAlphaZama.fixture.ts new file mode 100644 index 0000000..fa9374e --- /dev/null +++ b/test/dao/GovernorAlphaZama.fixture.ts @@ -0,0 +1,48 @@ +import { ethers } from "hardhat"; + +import type { CompoundTimelock, GovernorAlphaZama } from "../../types"; +import { reencryptEbool, reencryptEuint64 } from "../reencrypt"; +import { Signers, getSigners } from "../signers"; +import { FhevmInstances } from "../types"; + +export async function deployTimelockFixture(admin: string): Promise { + const signers = await getSigners(); + const timelockFactory = await ethers.getContractFactory("CompoundTimelock"); + const timelock = await timelockFactory.connect(signers.alice).deploy(admin, 60 * 60 * 24 * 2); + await timelock.waitForDeployment(); + return timelock; +} + +export async function deployGovernorAlphaZamaFixture( + signers: Signers, + compAddress: string, + timelockAddress: string, +): Promise { + // @dev We use 5 only for testing purpose. + // DO NOT use this value in production. + const votingPeriod = 5; + const governorFactory = await ethers.getContractFactory("GovernorAlphaZama"); + const governor = await governorFactory + .connect(signers.alice) + .deploy(signers.alice.address, timelockAddress, compAddress, votingPeriod); + await governor.waitForDeployment(); + return governor; +} + +export async function reencryptVoteReceipt( + signers: Signers, + instances: FhevmInstances, + proposalId: bigint, + account: string, + governor: GovernorAlphaZama, + governorAddress: string, +): Promise<[boolean, boolean, bigint]> { + const [hasVoted, supportHandle, voteHandle] = await governor.getReceipt( + proposalId, + signers[account as keyof Signers].address, + ); + const support = await reencryptEbool(signers, instances, account, supportHandle, governorAddress); + const vote = await reencryptEuint64(signers, instances, account, voteHandle, governorAddress); + + return [hasVoted, support, vote]; +} diff --git a/test/dao/GovernorZama.fixture.ts b/test/dao/GovernorZama.fixture.ts deleted file mode 100644 index c0f8e06..0000000 --- a/test/dao/GovernorZama.fixture.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ethers } from "hardhat"; - -import { Comp } from "../../types"; -import type { GovernorZama, Timelock } from "../../types"; -import { getSigners } from "../signers"; - -export async function deployTimelockFixture(admin: string): Promise { - const signers = await getSigners(); - - const timelockFactory = await ethers.getContractFactory("Timelock"); - const timelock = await timelockFactory.connect(signers.alice).deploy(admin, 60 * 60 * 24 * 2); - - await timelock.waitForDeployment(); - - return timelock; -} - -export async function deployGovernorZamaFixture(compContract: Comp, timelock: Timelock): Promise { - const signers = await getSigners(); - const votingPeriod = 5; // WARNING: We use 5 only for testing purpose, DO NOT use this value in production, typically it should be at least a few days, default was 3 days originally i.e votingPeriod=21600 blocks if 12s per block - const governorFactory = await ethers.getContractFactory("GovernorZama"); - const governor = await governorFactory - .connect(signers.alice) - .deploy(timelock.getAddress(), compContract.getAddress(), signers.alice.address, votingPeriod); - await governor.waitForDeployment(); - - return governor; -} From 1dfe2458636c404d5941d4768016ded5152339eb Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 6 Nov 2024 11:29:35 +0100 Subject: [PATCH 53/73] refactor: Optimizations --- contracts/DAO/GovernorAlphaZama.sol | 39 +++++++---------------------- 1 file changed, 9 insertions(+), 30 deletions(-) diff --git a/contracts/DAO/GovernorAlphaZama.sol b/contracts/DAO/GovernorAlphaZama.sol index 59fdc92..49f1e8f 100644 --- a/contracts/DAO/GovernorAlphaZama.sol +++ b/contracts/DAO/GovernorAlphaZama.sol @@ -259,7 +259,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * her votes are still above the threshold. */ function cancel(uint256 proposalId) external { - Proposal storage proposal = _proposals[proposalId]; + Proposal memory proposal = _proposals[proposalId]; if ( proposal.state == ProposalState.Executed || @@ -287,7 +287,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { } } - proposal.state = ProposalState.Canceled; + _proposals[proposalId].state = ProposalState.Canceled; emit ProposalCanceled(proposalId); } @@ -334,6 +334,8 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { ); } + _proposals[proposalId].state = ProposalState.Executed; + emit ProposalExecuted(proposalId); } @@ -371,7 +373,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { uint256 latestProposalId = latestProposalIds[msg.sender]; - if (latestProposalId != 0) { + if (latestProposalId != 0 && proposalCount != 0) { ProposalState proposerLatestProposalState = _proposals[latestProposalId].state; if ( @@ -446,7 +448,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param proposalId Proposal id. */ function queue(uint256 proposalId) external { - Proposal storage proposal = _proposals[proposalId]; + Proposal memory proposal = _proposals[proposalId]; if (proposal.state != ProposalState.Succeeded) { revert ProposalStateInvalid(); @@ -458,7 +460,8 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { _queueOrRevert(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], eta); } - proposal.eta = eta; + _proposals[proposalId].eta = eta; + _proposals[proposalId].state = ProposalState.Queued; emit ProposalQueued(proposalId, eta); } @@ -559,30 +562,6 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { TIMELOCK.queueTransaction(address(TIMELOCK), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta); } - /** - * @dev Returns the actions for a proposal id. - * @param proposalId Proposal id. - * @return targets Target addresses. - * @return values Values. - * @return signatures Signatures. - * @return calldatas Calldatas. - */ - function getActions( - uint256 proposalId - ) - external - view - returns ( - address[] memory targets, - uint256[] memory values, - string[] memory signatures, - bytes[] memory calldatas - ) - { - Proposal storage p = _proposals[proposalId]; - return (p.targets, p.values, p.signatures, p.calldatas); - } - /** * @notice Returns proposal information for a proposal id. * @dev It returns decrypted `forVotes`/`againstVotes`. @@ -647,7 +626,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { revert ProposalStateInvalid(); } - if (block.number > _proposals[proposalId].endBlock) { + if (block.number > proposal.endBlock) { revert ProposalStateNotActive(); } From 7fa85c90f5942189c671396fb6ff41926da09e35 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 6 Nov 2024 17:18:36 +0100 Subject: [PATCH 54/73] fix: Minor fixes GovernorAlphaZama.sol --- contracts/DAO/GovernorAlphaZama.sol | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/contracts/DAO/GovernorAlphaZama.sol b/contracts/DAO/GovernorAlphaZama.sol index 49f1e8f..ff8f79d 100644 --- a/contracts/DAO/GovernorAlphaZama.sol +++ b/contracts/DAO/GovernorAlphaZama.sol @@ -37,6 +37,9 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /// @notice Returned if the proposal state is still active. error ProposalStateStillActive(); + /// @notice Returned if the proposer has another proposal in progress. + error ProposerHasAnotherProposal(); + /// @notice Returned if the voter has already cast a vote /// for this proposal. error VoterHasAlreadyVoted(); @@ -262,6 +265,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { Proposal memory proposal = _proposals[proposalId]; if ( + proposal.state == ProposalState.Pending || proposal.state == ProposalState.Executed || proposal.state == ProposalState.Canceled || proposal.state == ProposalState.Defeated @@ -373,7 +377,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { uint256 latestProposalId = latestProposalIds[msg.sender]; - if (latestProposalId != 0 && proposalCount != 0) { + if (latestProposalId != 0) { ProposalState proposerLatestProposalState = _proposals[latestProposalId].state; if ( @@ -383,13 +387,13 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { proposerLatestProposalState != ProposalState.Canceled && proposerLatestProposalState != ProposalState.Executed ) { - revert ProposalStateInvalid(); + revert ProposerHasAnotherProposal(); } } uint256 startBlock = block.number + VOTING_DELAY; uint256 endBlock = startBlock + VOTING_PERIOD; - uint256 thisProposalId = proposalCount++; + uint256 thisProposalId = ++proposalCount; _proposals[thisProposalId] = Proposal({ proposer: msg.sender, @@ -588,7 +592,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { (proposalInfo.state == ProposalState.Queued) && (block.timestamp > proposalInfo.eta + TIMELOCK.GRACE_PERIOD()) ) { - proposalInfo.state == ProposalState.Expired; + proposalInfo.state = ProposalState.Expired; } } From 5de66490e2db3d0da734fe2c9d733927b7dc07a6 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 6 Nov 2024 17:19:06 +0100 Subject: [PATCH 55/73] test: GovernorAlphaZama --- test/dao/Comp.fixture.ts | 26 + test/dao/GovernorAlphaZama.test.ts | 750 +++++++++++++++++++++++++++++ test/dao/GovernorZama.ts | 521 -------------------- 3 files changed, 776 insertions(+), 521 deletions(-) create mode 100644 test/dao/GovernorAlphaZama.test.ts delete mode 100644 test/dao/GovernorZama.ts diff --git a/test/dao/Comp.fixture.ts b/test/dao/Comp.fixture.ts index d045615..ab895c7 100644 --- a/test/dao/Comp.fixture.ts +++ b/test/dao/Comp.fixture.ts @@ -12,6 +12,32 @@ export async function deployCompFixture(signers: Signers): Promise { return contract; } +export async function transferTokensAndDelegate( + signers: Signers, + instances: FhevmInstances, + transferAmount: bigint, + account: string, + delegate: string, + comp: Comp, + compAddress: string, +): Promise { + const input = instances.alice.createEncryptedInput(compAddress, signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = await input.encrypt(); + + let tx = await comp + .connect(signers.alice) + ["transfer(address,bytes32,bytes)"]( + signers[account as keyof Signers], + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + await tx.wait(); + + tx = await comp.connect(signers[account as keyof Signers]).delegate(signers[delegate as keyof Signers].address); + await tx.wait(); +} + export async function reencryptCurrentVotes( signers: Signers, instances: FhevmInstances, diff --git a/test/dao/GovernorAlphaZama.test.ts b/test/dao/GovernorAlphaZama.test.ts new file mode 100644 index 0000000..1787f40 --- /dev/null +++ b/test/dao/GovernorAlphaZama.test.ts @@ -0,0 +1,750 @@ +import { expect } from "chai"; +import { parseUnits } from "ethers"; +import { ethers, network } from "hardhat"; + +import { awaitAllDecryptionResults } from "../asyncDecrypt"; +import { createInstances } from "../instance"; +import { getSigners, initSigners } from "../signers"; +import { mineNBlocks } from "../utils"; +import { deployCompFixture, transferTokensAndDelegate } from "./Comp.fixture"; +import { + deployGovernorAlphaZamaFixture, + deployTimelockFixture, + reencryptVoteReceipt, +} from "./GovernorAlphaZama.fixture"; + +describe("GovernorAlphaZama", function () { + before(async function () { + await initSigners(4); + this.signers = await getSigners(); + }); + + beforeEach(async function () { + const contract = await deployCompFixture(this.signers); + this.comp = contract; + this.compAddress = await contract.getAddress(); + this.instances = await createInstances(this.signers); + + const precomputedGovernorAddress = ethers.getCreateAddress({ + from: this.signers.alice.address, + nonce: (await this.signers.alice.getNonce()) + 1, + }); + + const timelock = await deployTimelockFixture(precomputedGovernorAddress); + this.timelock = timelock; + this.timelockAddress = await timelock.getAddress(); + + const governor = await deployGovernorAlphaZamaFixture(this.signers, this.compAddress, this.timelockAddress); + this.governor = governor; + this.governorAddress = await governor.getAddress(); + + const tx = await this.comp.setAllowedContract(this.governorAddress); + await tx.wait(); + }); + + it("can propose a vote that becomes active if votes match the token threshold", async function () { + const transferAmount = parseUnits(String(500_000), 6); + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + const tx = await this.governor + .connect(this.signers.bob) + .propose(targets, values, signatures, calldatas, description); + + await tx.wait(); + + const proposalId = await this.governor.latestProposalIds(this.signers.bob.address); + let proposalInfo = await this.governor.getProposalInfo(proposalId); + + // @dev .to.eql is used to compare array elements + expect(proposalInfo.proposer).to.equal(this.signers.bob.address); + expect(proposalInfo.targets).to.eql(targets); + expect(proposalInfo.signatures).to.eql(signatures); + expect(proposalInfo.calldatas).to.eql(calldatas); + // 1 ==> PendingThresholdVerification + expect(proposalInfo.state).to.equal(1); + + await awaitAllDecryptionResults(); + + proposalInfo = await this.governor.getProposalInfo(proposalId); + // 3 ==> Active + expect(proposalInfo.state).to.equal(3); + }); + + it("anyone can propose a vote but it is rejected if votes are below the token threshold", async function () { + const transferAmount = (await this.governor.PROPOSAL_THRESHOLD()) - BigInt(1); + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + let tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + + const proposalId = await this.governor.latestProposalIds(this.signers.bob.address); + let proposalInfo = await this.governor.getProposalInfo(proposalId); + expect(proposalInfo.proposer).to.equal(this.signers.bob.address); + + // 1 ==> PendingThresholdVerification + expect(proposalInfo.state).to.equal(1); + await awaitAllDecryptionResults(); + + proposalInfo = await this.governor.getProposalInfo(proposalId); + + await awaitAllDecryptionResults(); + + // 2 ==> Rejected + expect(proposalInfo.state).to.equal(2); + }); + + it("multiple users can vote and the vote succeeds if forVotes > quorum", async function () { + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + const transferAmount = parseUnits(String(200_000), 6); + + // Bob and Carol receive 200k tokens and delegate to themselves. + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "carol", + "carol", + this.comp, + this.compAddress, + ); + + // INITIATE A PROPOSAL + let tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + + // DECRYPTION FOR THE TOKEN THRESHOLD + await awaitAllDecryptionResults(); + const proposalId = await this.governor.latestProposalIds(this.signers.bob.address); + + // VOTE + // Bob and Carol vote for + let input = this.instances.bob.createEncryptedInput(this.governorAddress, this.signers.bob.address); + input.addBool(true); + let encryptedVote = await input.encrypt(); + tx = await this.governor + .connect(this.signers.bob) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof); + await tx.wait(); + + input = this.instances.carol.createEncryptedInput(this.governorAddress, this.signers.carol.address); + input.addBool(true); + encryptedVote = await input.encrypt(); + tx = await this.governor + .connect(this.signers.carol) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof); + await tx.wait(); + + // Bob/Carol can reeencrypt his/her receipt + let [hasVoted, support, votes] = await reencryptVoteReceipt( + this.signers, + this.instances, + proposalId, + "bob", + this.governor, + this.governorAddress, + ); + + expect(hasVoted).to.be.eq(true); + expect(support).to.be.eq(true); + expect(votes).to.be.eq(transferAmount); + + [hasVoted, support, votes] = await reencryptVoteReceipt( + this.signers, + this.instances, + proposalId, + "carol", + this.governor, + this.governorAddress, + ); + + expect(hasVoted).to.be.eq(true); + expect(support).to.be.eq(true); + expect(votes).to.be.eq(transferAmount); + + // Mine blocks + await mineNBlocks(3); + + // REQUEST DECRYPTION + tx = await this.governor.requestVoteDecryption(proposalId); + await tx.wait(); + let proposalInfo = await this.governor.getProposalInfo(proposalId); + expect(proposalInfo.forVotes).to.be.eq(parseUnits(String(0), 6)); + expect(proposalInfo.againstVotes).to.be.eq(parseUnits(String(0), 6)); + // 4 ==> Succeeded + expect(proposalInfo.state).to.equal(4); + + // POST-DECRYPTION RESULTS + await awaitAllDecryptionResults(); + proposalInfo = await this.governor.getProposalInfo(proposalId); + expect(proposalInfo.forVotes).to.be.eq(transferAmount * BigInt(2)); + expect(proposalInfo.againstVotes).to.be.eq(parseUnits(String(0), 6)); + // 7 ==> Succeeded + expect(proposalInfo.state).to.equal(7); + + // QUEUING + tx = await this.governor.queue(proposalId); + await tx.wait(); + + proposalInfo = await this.governor.getProposalInfo(proposalId); + // 8 ==> Queued + expect(proposalInfo.state).to.equal(8); + const eta = proposalInfo.eta; + + // EXECUTE + await ethers.provider.send("evm_setNextBlockTimestamp", [eta.toString()]); + tx = await this.governor.execute(proposalId); + await tx.wait(); + + proposalInfo = await this.governor.getProposalInfo(proposalId); + // 10 ==> Executed + expect(proposalInfo.state).to.equal(10); + }); + + it("the vote is defeated if forVotes < quorum", async function () { + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + const transferAmount = (await this.governor.QUORUM_VOTES()) - BigInt(1); + + // Bob receives enough to create a proposal but not enough to match the quorum. + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + // INITIATE A PROPOSAL + let tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + + // DECRYPTION FOR THE TOKEN THRESHOLD + await awaitAllDecryptionResults(); + const proposalId = await this.governor.latestProposalIds(this.signers.bob.address); + + // VOTE + let input = this.instances.bob.createEncryptedInput(this.governorAddress, this.signers.bob.address); + input.addBool(true); + let encryptedVote = await input.encrypt(); + tx = await this.governor + .connect(this.signers.bob) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof); + await tx.wait(); + + // Bob reeencrypts his receipt + let [hasVoted, support, votes] = await reencryptVoteReceipt( + this.signers, + this.instances, + proposalId, + "bob", + this.governor, + this.governorAddress, + ); + + expect(hasVoted).to.be.eq(true); + expect(support).to.be.eq(true); + expect(votes).to.be.eq(transferAmount); + + // Mine blocks + await mineNBlocks(4); + + // REQUEST DECRYPTION + tx = await this.governor.requestVoteDecryption(proposalId); + await tx.wait(); + let proposalInfo = await this.governor.getProposalInfo(proposalId); + expect(proposalInfo.forVotes).to.be.eq(parseUnits(String(0), 6)); + expect(proposalInfo.againstVotes).to.be.eq(parseUnits(String(0), 6)); + // 4 ==> Succeeded + expect(proposalInfo.state).to.equal(4); + + // POST-DECRYPTION RESULTS + await awaitAllDecryptionResults(); + proposalInfo = await this.governor.getProposalInfo(proposalId); + expect(proposalInfo.forVotes).to.be.eq(transferAmount); + expect(proposalInfo.againstVotes).to.be.eq(parseUnits(String(0), 6)); + + // 6 ==> Defeated + expect(proposalInfo.state).to.equal(6); + }); + + it("the vote is rejected if forVotes < againstVotes", async function () { + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + const transferAmountFor = parseUnits(String(200_000), 6); + const transferAmountAgainst = parseUnits(String(200_000), 6) + BigInt(1); + + // Bob and Carol receive 200k tokens and delegate to themselves. + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmountFor, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmountAgainst, + "carol", + "carol", + this.comp, + this.compAddress, + ); + + // INITIATE A PROPOSAL + let tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + + // DECRYPTION FOR THE TOKEN THRESHOLD + await awaitAllDecryptionResults(); + const proposalId = await this.governor.latestProposalIds(this.signers.bob.address); + + // VOTE + // Bob votes for but Carol votes against + let input = this.instances.bob.createEncryptedInput(this.governorAddress, this.signers.bob.address); + input.addBool(true); + let encryptedVote = await input.encrypt(); + tx = await this.governor + .connect(this.signers.bob) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof); + await tx.wait(); + + input = this.instances.carol.createEncryptedInput(this.governorAddress, this.signers.carol.address); + input.addBool(false); + encryptedVote = await input.encrypt(); + tx = await this.governor + .connect(this.signers.carol) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof); + await tx.wait(); + + // Bob/Carol can reeencrypt his/her receipt + let [hasVoted, support, votes] = await reencryptVoteReceipt( + this.signers, + this.instances, + proposalId, + "bob", + this.governor, + this.governorAddress, + ); + + expect(hasVoted).to.be.eq(true); + expect(support).to.be.eq(true); + expect(votes).to.be.eq(transferAmountFor); + + [hasVoted, support, votes] = await reencryptVoteReceipt( + this.signers, + this.instances, + proposalId, + "carol", + this.governor, + this.governorAddress, + ); + + expect(hasVoted).to.be.eq(true); + expect(support).to.be.eq(false); + expect(votes).to.be.eq(transferAmountAgainst); + + // Mine blocks + await mineNBlocks(3); + + // REQUEST DECRYPTION + tx = await this.governor.requestVoteDecryption(proposalId); + await tx.wait(); + let proposalInfo = await this.governor.getProposalInfo(proposalId); + expect(proposalInfo.forVotes).to.be.eq(parseUnits(String(0), 6)); + expect(proposalInfo.againstVotes).to.be.eq(parseUnits(String(0), 6)); + // 4 ==> Succeeded + expect(proposalInfo.state).to.equal(4); + + // POST-DECRYPTION RESULTS + await awaitAllDecryptionResults(); + proposalInfo = await this.governor.getProposalInfo(proposalId); + expect(proposalInfo.forVotes).to.be.eq(transferAmountFor); + expect(proposalInfo.againstVotes).to.be.eq(transferAmountAgainst); + // 6 ==> Defeated + expect(proposalInfo.state).to.equal(6); + }); + + it("could not deploy timelock contract if delay is below 2 days or above 31 days", async function () { + const timelockFactory = await ethers.getContractFactory("CompoundTimelock"); + + if (network.name === "hardhat") { + await expect( + timelockFactory.connect(this.signers.alice).deploy(this.signers.alice.address, 60 * 60 * 24 * 1), + ).to.be.revertedWith("Timelock::constructor: Delay must exceed minimum delay."); // 1 day < 2 days + await expect( + timelockFactory.connect(this.signers.alice).deploy(this.signers.alice.address, 60 * 60 * 24 * 31), + ).to.be.revertedWith("Timelock::setDelay: Delay must not exceed maximum delay."); // 31 days > 30 days + } else { + // fhevm-mode + await expect(timelockFactory.connect(this.signers.alice).deploy(this.signers.alice.address, 60 * 60 * 24 * 1)).to + .throw; + await expect(timelockFactory.connect(this.signers.alice).deploy(this.signers.alice.address, 60 * 60 * 24 * 31)).to + .throw; + } + }); + + it("only owner could queue setTimelockPendingAdmin then execute it, and then acceptTimelockAdmin", async function () { + const latestBlockNumber = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(latestBlockNumber); + const expiry = block!.timestamp + 60 * 60 * 24 * 2 + 60; + + const tx = await this.governor.queueSetTimelockPendingAdmin(this.signers.bob, expiry); + await tx.wait(); + + if (network.name === "hardhat") { + // hardhat cheatcodes are available only in mocked mode + await expect(this.governor.executeSetTimelockPendingAdmin(this.signers.bob, expiry)).to.be.revertedWith( + "Timelock::executeTransaction: Transaction hasn't surpassed time lock.", + ); + + await expect( + this.governor.connect(this.signers.carol).queueSetTimelockPendingAdmin(this.signers.bob, expiry), + ).to.be.revertedWithCustomError(this.governor, "OwnableUnauthorizedAccount"); + + await ethers.provider.send("evm_increaseTime", ["0x2a33c"]); + + await expect( + this.governor.connect(this.signers.carol).executeSetTimelockPendingAdmin(this.signers.bob, expiry), + ).to.be.revertedWithCustomError(this.governor, "OwnableUnauthorizedAccount"); + + const tx3 = await this.governor.executeSetTimelockPendingAdmin(this.signers.bob, expiry); + await tx3.wait(); + + await expect(this.timelock.acceptAdmin()).to.be.revertedWith( + "Timelock::acceptAdmin: Call must come from pendingAdmin.", + ); + + const tx4 = await this.timelock.connect(this.signers.bob).acceptAdmin(); + await tx4.wait(); + + const latestBlockNumber = await ethers.provider.getBlockNumber(); + const block = await ethers.provider.getBlock(latestBlockNumber); + const expiry2 = block!.timestamp + 60 * 60 * 24 * 2 + 60; + const timeLockAdd = await this.timelock.getAddress(); + const callData = ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.governorAddress]); + const tx5 = await this.timelock + .connect(this.signers.bob) + .queueTransaction(timeLockAdd, 0, "setPendingAdmin(address)", callData, expiry2); + await tx5.wait(); + await ethers.provider.send("evm_increaseTime", ["0x2a33c"]); + + const tx6 = await this.timelock + .connect(this.signers.bob) + .executeTransaction(timeLockAdd, 0, "setPendingAdmin(address)", callData, expiry2); + await tx6.wait(); + + await expect(this.governor.connect(this.signers.bob).acceptTimelockAdmin()).to.be.revertedWithCustomError( + this.governor, + "OwnableUnauthorizedAccount", + ); + + const tx7 = await this.governor.acceptTimelockAdmin(); + await tx7.wait(); + expect(await this.timelock.admin()).to.eq(this.governorAddress); + } + }); + + it("all arrays of a proposal should be of same length, non null and less than max operations", async function () { + let targets = [this.signers.bob.address]; + let values = ["0"]; + let signatures = ["getBalanceOf(address)"]; + let calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + let description = "description"; + + const invalidTargets = [this.signers.bob.address, this.signers.carol.address]; + await expect( + this.governor.connect(this.signers.alice).propose(invalidTargets, values, signatures, calldatas, description), + ).to.be.revertedWithCustomError(this.governor, "LengthsDoNotMatch"); + + const invalidValues = ["0", "0"]; + await expect( + this.governor.connect(this.signers.alice).propose(targets, invalidValues, signatures, calldatas, description), + ).to.be.revertedWithCustomError(this.governor, "LengthsDoNotMatch"); + + const invalidSignatures = ["getBalanceOf(address)", "getBalanceOf(address)"]; + await expect( + this.governor.connect(this.signers.alice).propose(targets, values, invalidSignatures, calldatas, description), + ).to.be.revertedWithCustomError(this.governor, "LengthsDoNotMatch"); + + const invalidCalldatas = [ + ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address]), + ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address]), + ]; + + await expect( + this.governor.connect(this.signers.alice).propose(targets, values, signatures, invalidCalldatas, description), + ).to.be.revertedWithCustomError(this.governor, "LengthsDoNotMatch"); + + await expect( + this.governor.connect(this.signers.alice).propose([], [], [], [], description), + ).to.be.revertedWithCustomError(this.governor, "LengthIsNull"); + + await expect( + this.governor + .connect(this.signers.alice) + .propose( + new Array(11).fill(this.signers.alice), + new Array(11).fill("0"), + new Array(11).fill("getBalanceOf(address)"), + new Array(11).fill(calldatas[0]), + description, + ), + ).to.be.revertedWithCustomError(this.governor, "LengthAboveMaxOperations"); + }); + + it("only gateway can call gateway functions", async function () { + await expect(this.governor.connect(this.signers.bob).callbackInitiateProposal(1, true)).to.be.reverted; + await expect(this.governor.connect(this.signers.bob).callbackVoteDecryption(1, 10, 10)).to.be.reverted; + }); + + it("only owner can call owner functions", async function () { + await expect(this.governor.connect(this.signers.bob).acceptTimelockAdmin()).to.be.revertedWithCustomError( + this.governor, + "OwnableUnauthorizedAccount", + ); + + await expect( + this.governor.connect(this.signers.bob).executeSetTimelockPendingAdmin(this.signers.bob.address, 1111), + ).to.be.revertedWithCustomError(this.governor, "OwnableUnauthorizedAccount"); + + await expect( + this.governor.connect(this.signers.bob).queueSetTimelockPendingAdmin(this.signers.bob.address, 1111), + ).to.be.revertedWithCustomError(this.governor, "OwnableUnauthorizedAccount"); + }); + + it("only owner or proposer can cancel proposal", async function () { + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + const transferAmount = await this.governor.QUORUM_VOTES(); + + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + let tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + + // @dev ProposalId starts at 1. + await expect(this.governor.connect(this.signers.carol).cancel(1)).to.be.revertedWithCustomError( + this.governor, + "OwnableUnauthorizedAccount", + ); + }); + + it("proposer cannot make a new proposal while he still has an already pending or active proposal", async function () { + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + const transferAmount = await this.governor.QUORUM_VOTES(); + + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + let tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + + await expect( + this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description), + ).to.be.revertedWithCustomError(this.governor, "ProposerHasAnotherProposal"); + }); + + it("cannot queue twice or execute before queuing", async function () { + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + const transferAmount = parseUnits(String(400_000), 6); + + // Bob receives 400k tokens and delegates to himself. + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + // INITIATE A PROPOSAL + let tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + + // DECRYPTION FOR THE TOKEN THRESHOLD + await awaitAllDecryptionResults(); + const proposalId = await this.governor.latestProposalIds(this.signers.bob.address); + + // VOTE + // Bob casts a vote + let input = this.instances.bob.createEncryptedInput(this.governorAddress, this.signers.bob.address); + input.addBool(true); + let encryptedVote = await input.encrypt(); + tx = await this.governor + .connect(this.signers.bob) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof); + await tx.wait(); + + // Mine blocks + await mineNBlocks(4); + + // REQUEST DECRYPTION + tx = await this.governor.requestVoteDecryption(proposalId); + await tx.wait(); + + // POST-DECRYPTION RESULTS + await awaitAllDecryptionResults(); + + // QUEUING + // @dev Cannot execute before queuing. + await expect(this.governor.execute(proposalId)).to.be.revertedWithCustomError( + this.governor, + "ProposalStateInvalid", + ); + + tx = await this.governor.queue(proposalId); + await tx.wait(); + + // @dev Cannot queue twice. + await expect(this.governor.queue(proposalId)).to.be.revertedWithCustomError(this.governor, "ProposalStateInvalid"); + }); + + it("proposal expires after grace period", async function () { + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + const transferAmount = parseUnits(String(400_000), 6); + + // Bob receives 400k tokens and delegates to himself. + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + // INITIATE A PROPOSAL + let tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + + // DECRYPTION FOR THE TOKEN THRESHOLD + await awaitAllDecryptionResults(); + const proposalId = await this.governor.latestProposalIds(this.signers.bob.address); + + // VOTE + // Bob casts a vote + let input = this.instances.bob.createEncryptedInput(this.governorAddress, this.signers.bob.address); + input.addBool(true); + let encryptedVote = await input.encrypt(); + tx = await this.governor + .connect(this.signers.bob) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof); + await tx.wait(); + + // Mine blocks + await mineNBlocks(4); + + // REQUEST DECRYPTION + tx = await this.governor.requestVoteDecryption(proposalId); + await tx.wait(); + + // POST-DECRYPTION RESULTS + await awaitAllDecryptionResults(); + + // Proposal is queued + tx = await this.governor.queue(proposalId); + await tx.wait(); + + let proposalInfo = await this.governor.getProposalInfo(proposalId); + const eta = proposalInfo.eta; + const deadlineExecutionTransaction = eta + (await this.timelock.GRACE_PERIOD()); + + await ethers.provider.send("evm_setNextBlockTimestamp", [deadlineExecutionTransaction.toString()]); + await mineNBlocks(1); + + await expect(this.governor.execute(proposalId)).to.be.revertedWith( + "Timelock::executeTransaction: Transaction is stale.", + ); + + proposalInfo = await this.governor.getProposalInfo(proposalId); + // 9 ==> Expired + expect(proposalInfo.state).to.equal(9); + }); +}); diff --git a/test/dao/GovernorZama.ts b/test/dao/GovernorZama.ts deleted file mode 100644 index b1fec9d..0000000 --- a/test/dao/GovernorZama.ts +++ /dev/null @@ -1,521 +0,0 @@ -import { expect } from "chai"; -import { ethers, network } from "hardhat"; - -import { createInstances } from "../instance"; -import { getSigners, initSigners } from "../signers"; -import { createTransaction, waitNBlocks } from "../utils"; -import { deployCompFixture } from "./Comp.fixture"; -import { deployGovernorZamaFixture, deployTimelockFixture } from "./GovernorZama.fixture"; - -describe("GovernorZama", function () { - before(async function () { - await initSigners(); - this.signers = await getSigners(); - }); - - beforeEach(async function () { - this.comp = await deployCompFixture(); - const instancesComp = await createInstances(await this.comp.getAddress(), ethers, this.signers); - const encryptedAmountToTransfer = instancesComp.alice.encrypt64(500_000n * 10n ** 6n); - const transfer1 = await this.comp["transfer(address,bytes)"](this.signers.bob.address, encryptedAmountToTransfer); - await transfer1.wait(); - const transfer2 = await this.comp["transfer(address,bytes)"](this.signers.carol.address, encryptedAmountToTransfer); - await transfer2.wait(); - - const delegate1 = await this.comp.delegate(this.signers.alice); - const delegate2 = await this.comp.connect(this.signers.bob).delegate(this.signers.bob); - const delegate3 = await this.comp.connect(this.signers.carol).delegate(this.signers.carol); - await Promise.all([delegate1, delegate2, delegate3]); - await waitNBlocks(1); - - const precomputedGovernorAddress = ethers.getCreateAddress({ - from: this.signers.alice.address, - nonce: (await this.signers.alice.getNonce()) + 1, - }); - - this.timelock = await deployTimelockFixture(precomputedGovernorAddress); - - const governor = await deployGovernorZamaFixture(this.comp, this.timelock); - this.contractAddress = await governor.getAddress(); - - this.governor = governor; - this.instances = await createInstances(this.contractAddress, ethers, this.signers); - - const transaction = await this.comp.setAllowedContract(this.contractAddress); - await transaction.wait(); - }); - - it("could not deploy timelock contract if delay is below 2 days or above 31 days", async function () { - const timelockFactory = await ethers.getContractFactory("Timelock"); - - if (network.name === "hardhat") { - await expect( - timelockFactory.connect(this.signers.alice).deploy(this.signers.alice.address, 60 * 60 * 24 * 1), - ).to.be.revertedWith("Timelock::constructor: Delay must exceed minimum delay."); // 1 day < 2 days - await expect( - timelockFactory.connect(this.signers.alice).deploy(this.signers.alice.address, 60 * 60 * 24 * 31), - ).to.be.revertedWith("Timelock::setDelay: Delay must not exceed maximum delay."); // 31 days > 30 days - } else { - // fhevm-mode - await expect(timelockFactory.connect(this.signers.alice).deploy(this.signers.alice.address, 60 * 60 * 24 * 1)).to - .throw; - await expect(timelockFactory.connect(this.signers.alice).deploy(this.signers.alice.address, 60 * 60 * 24 * 31)).to - .throw; - } - }); - - it("should propose a vote", async function () { - const callDatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.alice.address])]; - const tx = await createTransaction( - this.governor.propose, - [this.signers.alice], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ); - const txproposal = await tx.wait(); - expect(txproposal?.status).to.equal(1); - const proposalId = await this.governor.latestProposalIds(this.signers.alice.address); - const proposals = await this.governor.getProposalInfo(proposalId); - expect(proposals.id).to.equal(proposalId); - expect(proposals.proposer).to.equal(this.signers.alice.address); - - const actions = await this.governor.getActions(1); - expect(actions[0][0]).to.equal(this.signers.alice.address); - expect(actions[1][0]).to.equal(0); - expect(actions[2][0]).to.equal("getBalanceOf(address)"); - expect(actions[3][0]).to.equal(callDatas[0]); - }); - - it("should vote and return a Succeed", async function () { - const callDatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.alice.address])]; - const tx = await createTransaction( - this.governor.propose, - [this.signers.alice], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ); - const txproposal = await tx.wait(); - expect(txproposal?.status).to.equal(1); - - const proposalId = await this.governor.latestProposalIds(this.signers.alice.address); - - await waitNBlocks(2); - // Cast some votes - const encryptedSupportBob = this.instances.bob.encryptBool(true); - const txVoteBob = await createTransaction( - this.governor.connect(this.signers.bob)["castVote(uint256,bytes)"], - proposalId, - encryptedSupportBob, - ); - // bob can get his receipt - - const encryptedSupportCarol = this.instances.carol.encryptBool(true); - const txVoteCarol = await createTransaction( - this.governor.connect(this.signers.carol)["castVote(uint256,bytes)"], - proposalId, - encryptedSupportCarol, - ); - - const [bobResults, carolResults] = await Promise.all([txVoteBob.wait(), txVoteCarol.wait()]); - expect(bobResults?.status).to.equal(1); - expect(carolResults?.status).to.equal(1); - - await waitNBlocks(4); - - const state = await this.governor.state(proposalId); - expect(state).to.equal(4n); - }); - - it("should vote and return a Defeated ", async function () { - const callDatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.alice.address])]; - const tx = await createTransaction( - this.governor.propose, - [this.signers.alice], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ); - const proposal = await tx.wait(); - expect(proposal?.status).to.equal(1); - const proposalId = await this.governor.latestProposalIds(this.signers.alice.address); - await waitNBlocks(2); - - // Cast some votes - const encryptedSupportBob = this.instances.bob.encryptBool(false); - const txVoteBob = await createTransaction( - this.governor.connect(this.signers.bob)["castVote(uint256,bytes)"], - proposalId, - encryptedSupportBob, - ); - - const encryptedSupportCarol = this.instances.carol.encryptBool(true); - const txVoteCarol = await createTransaction( - this.governor.connect(this.signers.carol)["castVote(uint256,bytes)"], - proposalId, - encryptedSupportCarol, - ); - - const [bobResults, aliceResults] = await Promise.all([txVoteBob.wait(), txVoteCarol.wait()]); - expect(bobResults?.status).to.equal(1); - expect(aliceResults?.status).to.equal(1); - await waitNBlocks(4); - - const state = await this.governor.state(proposalId); - expect(state).to.equal(3n); - - // cannot queue defeated proposal - await expect(this.governor.queue(1)).to.throw; - }); - - it("should cancel", async function () { - const callDatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.alice.address])]; - const tx = await createTransaction( - this.governor.propose, - [this.signers.alice], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ); - const proposal = await tx.wait(); - expect(proposal?.status).to.equal(1); - const proposalId = await this.governor.latestProposalIds(this.signers.alice.address); - await waitNBlocks(2); - - const state = await this.governor.state(proposalId); - expect(state).to.equal(1n); - - await expect(this.governor.connect(this.signers.dave).cancel(proposalId)).to.throw; // non-guardian or non-proposer is unable to cancel - - const txCancel = await this.governor.cancel(proposalId); - await txCancel.wait(); - const newState = await this.governor.state(proposalId); - expect(newState).to.equal(2n); - }); - - it("only guardian could queue setTimelockPendingAdmin then execute it, and then acceptAdmin", async function () { - const latestBlockNumber = await ethers.provider.getBlockNumber(); - const block = await ethers.provider.getBlock(latestBlockNumber); - const expiry = block!.timestamp + 60 * 60 * 24 * 2 + 60; - - const tx = await this.governor.__queueSetTimelockPendingAdmin(this.signers.bob, expiry); - await tx.wait(); - if (network.name === "hardhat") { - // hardhat cheatcodes are available only in mocked mode - await expect(this.governor.__executeSetTimelockPendingAdmin(this.signers.bob, expiry)).to.be.revertedWith( - "Timelock::executeTransaction: Transaction hasn't surpassed time lock.", - ); - await expect( - this.governor.connect(this.signers.carol).__queueSetTimelockPendingAdmin(this.signers.bob, expiry), - ).to.be.revertedWith("GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian"); - - await ethers.provider.send("evm_increaseTime", ["0x2a33c"]); - await expect( - this.governor.connect(this.signers.carol).__executeSetTimelockPendingAdmin(this.signers.bob, expiry), - ).to.be.revertedWith("GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian"); - const tx3 = await this.governor.__executeSetTimelockPendingAdmin(this.signers.bob, expiry); - await tx3.wait(); - - await expect(this.timelock.acceptAdmin()).to.be.revertedWith( - "Timelock::acceptAdmin: Call must come from pendingAdmin.", - ); - const tx4 = await this.timelock.connect(this.signers.bob).acceptAdmin(); - await tx4.wait(); - - const latestBlockNumber = await ethers.provider.getBlockNumber(); - const block = await ethers.provider.getBlock(latestBlockNumber); - const expiry2 = block!.timestamp + 60 * 60 * 24 * 2 + 60; - const timeLockAdd = await this.timelock.getAddress(); - const callData = ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.contractAddress]); - const tx5 = await this.timelock - .connect(this.signers.bob) - .queueTransaction(timeLockAdd, 0, "setPendingAdmin(address)", callData, expiry2); - await tx5.wait(); - await ethers.provider.send("evm_increaseTime", ["0x2a33c"]); - const tx6 = await this.timelock - .connect(this.signers.bob) - .executeTransaction(timeLockAdd, 0, "setPendingAdmin(address)", callData, expiry2); - await tx6.wait(); - await expect(this.governor.connect(this.signers.bob).__acceptAdmin()).to.be.revertedWith( - "GovernorAlpha::__acceptAdmin: sender must be gov guardian", - ); - const tx7 = await this.governor.__acceptAdmin(); - await tx7.wait(); - expect(await this.timelock.admin()).to.eq(this.contractAddress); - } - }); - - it("only guardian can call __abdicate", async function () { - await expect(this.governor.connect(this.signers.bob).__abdicate()).to.throw; - const tx = await this.governor.__abdicate(); - await tx.wait(); - }); - - it("user can't propose if his votes are below the minimal threshold", async function () { - const callDatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.alice.address])]; - if (network.name === "hardhat") { - await expect( - createTransaction( - this.governor.connect(this.signers.dave).propose, - [this.signers.alice], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ), - ).to.be.revertedWith("GovernorAlpha::propose: proposer votes below proposal threshold"); - } else { - await expect( - createTransaction( - this.governor.connect(this.signers.dave).propose, - [this.signers.alice], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ), - ).to.throw; - } - }); - - it("all arrays of a proposal should be of same length, non null and less than max operations", async function () { - const callDatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.alice.address])]; - await expect( - createTransaction( - this.governor.propose, - [this.signers.alice, this.signers.bob], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ), - ).to.throw; - - await expect(createTransaction(this.governor.propose, [], [], [], [], "do nothing")).to.throw; - - await expect( - createTransaction( - this.governor.propose, - new Array(11).fill(this.signers.alice), - new Array(11).fill("0"), - new Array(11).fill("getBalanceOf(address)"), - new Array(11).fill(callDatas[0]), - "do nothing", - ), - ).to.throw; - }); - - it("proposer cannot make a new proposal while he still has an already pending or active proposal", async function () { - const callDatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.alice.address])]; - const tx = await createTransaction( - this.governor.propose, - [this.signers.alice], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ); - await tx.wait(); - - await expect( - createTransaction( - this.governor.propose, - [this.signers.bob], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ), - ).to.throw; - - await waitNBlocks(1); - - await expect( - createTransaction( - this.governor.propose, - [this.signers.bob], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ), - ).to.throw; - - const tx2 = await createTransaction(this.governor.connect(this.signers.bob).cancel, 1); - await tx2.wait(); - - await waitNBlocks(1); - - const tx3 = await createTransaction( - this.governor.propose, - [this.signers.alice], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ); - await tx3.wait(); - - expect(await this.governor.latestProposalIds(this.signers.alice)).to.equal(2); - - await expect(this.governor.state(0)).to.be.revertedWith("GovernorAlpha::state: invalid proposal id"); - await expect(this.governor.state(10)).to.be.revertedWith("GovernorAlpha::state: invalid proposal id"); - expect(await this.governor.state(1)).to.equal(2); - expect(await this.governor.state(2)).to.equal(0); - }); - - it("can propose, then vote once, then queue, then execute", async function () { - const callDatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.alice.address])]; - const tx = await createTransaction( - this.governor.propose, - [this.signers.alice], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ); - - await tx.wait(); - - await waitNBlocks(2); - const encryptedSupportBob = this.instances.bob.encryptBool(true); - const txVoteBob = await createTransaction( - this.governor.connect(this.signers.bob)["castVote(uint256,bytes)"], - 1, - encryptedSupportBob, - ); - await txVoteBob.wait(); - - await expect( - createTransaction(this.governor.connect(this.signers.bob)["castVote(uint256,bytes)"], 1, encryptedSupportBob), - ).to.throw; // cannot vote twice - - await waitNBlocks(5); - - const encryptedSupportAlice = this.instances.alice.encryptBool(true); - await expect( - createTransaction(this.governor.connect(this.signers.alice)["castVote(uint256,bytes)"], 1, encryptedSupportAlice), - ).to.throw; // voting is closed after voting period - - if (network.name === "hardhat") { - const txQueue = await this.governor.queue(1); - await txQueue.wait(); - await ethers.provider.send("evm_increaseTime", ["0x2a33c"]); - const txExecute = await this.governor.execute(1); - await txExecute.wait(); - - // cannot cancel executed proposal - await expect(this.governor.cancel(1)).to.be.revertedWith( - "GovernorAlpha::cancel: cannot cancel executed proposal", - ); - - await expect(this.governor.getProposalInfo(2)).to.be.revertedWith("Invalid proposalId"); - } - }); - - it("cannot queue two identical transactions at same eta", async function () { - const callDatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.alice.address])]; - - if (network.name === "hardhat") { - // mocked mode - const tx1 = await this.governor.propose( - [this.signers.alice, this.signers.alice], - ["0", "0"], - ["getBalanceOf(address)", "getBalanceOf(address)"], - new Array(2).fill(callDatas[0]), - "do nothing", - { - gasLimit: 500_000, - }, - ); - await tx1.wait(); - - await waitNBlocks(1); - const encryptedSupportBob = this.instances.bob.encryptBool(true); - const txVoteBob = await createTransaction( - this.governor.connect(this.signers.bob)["castVote(uint256,bytes)"], - 1, - encryptedSupportBob, - ); - await txVoteBob.wait(); - - await waitNBlocks(5); - - await expect(this.governor.queue(1)).to.be.revertedWith( - "GovernorAlpha::_queueOrRevert: proposal action already queued at eta", - ); - await expect(this.governor.execute(1)).to.be.revertedWith( - "GovernorAlpha::execute: proposal can only be executed if it is queued", - ); // cannot execute non-queued proposal - } - }); - - it("proposal expires after grace period", async function () { - const callDatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.alice.address])]; - const tx = await createTransaction( - this.governor.propose, - [this.signers.alice], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ); - - await tx.wait(); - - await waitNBlocks(2); - const encryptedSupportBob = this.instances.bob.encryptBool(true); - const txVoteBob = await createTransaction( - this.governor.connect(this.signers.bob)["castVote(uint256,bytes)"], - 1, - encryptedSupportBob, - ); - await txVoteBob.wait(); - - if (network.name === "hardhat") { - await waitNBlocks(5); - const txQueue = await this.governor.queue(1); - await txQueue.wait(); - await ethers.provider.send("evm_increaseTime", ["0xffffff"]); - await waitNBlocks(1); - await expect(this.governor.execute(1)).to.be.revertedWith( - "GovernorAlpha::execute: proposal can only be executed if it is queued", - ); - expect(await this.governor.state(1)).to.equal(6); - } - }); - - it("voter can get his receipt via reencryption", async function () { - const aliceToken = this.instances.alice.getPublicKey(this.contractAddress); - const callDatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.alice.address])]; - const tx = await createTransaction( - this.governor.propose, - [this.signers.alice], - ["0"], - ["getBalanceOf(address)"], - callDatas, - "do nothing", - ); - await tx.wait(); - - await waitNBlocks(2); - // Cast some votes - const encryptedSupportAlice = this.instances.alice.encryptBool(true); - const tx2 = await createTransaction(this.governor["castVote(uint256,bytes)"], 1, encryptedSupportAlice); - await tx2.wait(); - - const encryptedAliceVotes = await this.governor.getMyReceipt(1, aliceToken.publicKey, aliceToken.signature); - // Decrypt Alice's balance - const aliceVotes = this.instances.alice.decrypt(this.contractAddress, encryptedAliceVotes[2]); - expect(aliceVotes).to.equal(9_000_000n * 10n ** 6n); - - await expect( - this.governor.connect(this.signers.bob).getMyReceipt(1, aliceToken.publicKey, aliceToken.signature), - ).to.be.revertedWith("EIP712 signer and transaction signer do not match"); - }); -}); From 30b7560bc81664b766a6ae74e426cb01219b9c1b Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Wed, 6 Nov 2024 17:19:20 +0100 Subject: [PATCH 56/73] chore: Updates for solhint --- .solhint.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.solhint.json b/.solhint.json index 08cba13..c80271f 100644 --- a/.solhint.json +++ b/.solhint.json @@ -4,10 +4,16 @@ "rules": { "code-complexity": ["error", 8], "compiler-version": ["error", ">=0.8.24"], - "func-visibility": ["error", { "ignoreConstructors": true }], + "func-visibility": [ + "error", + { + "ignoreConstructors": true + } + ], "max-line-length": ["error", 120], "named-parameters-mapping": "warn", "no-console": "off", + "no-global-import": "off", "not-rely-on-time": "off", "prettier/prettier": [ "error", From e13d374b5d133e3cdd9b0a6be3ec84f40f8cdb36 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 7 Nov 2024 10:24:01 +0100 Subject: [PATCH 57/73] refactor: Contracts --- contracts/DAO/Comp.sol | 48 ++++++++++++++++++++--------- contracts/DAO/CompoundTimelock.sol | 33 +++----------------- contracts/DAO/GovernorAlphaZama.sol | 10 ++++-- contracts/DAO/IComp.sol | 2 +- contracts/DAO/ICompoundTimelock.sol | 28 +++++++++++++++++ 5 files changed, 76 insertions(+), 45 deletions(-) diff --git a/contracts/DAO/Comp.sol b/contracts/DAO/Comp.sol index e79e41a..4bdf381 100644 --- a/contracts/DAO/Comp.sol +++ b/contracts/DAO/Comp.sol @@ -11,24 +11,34 @@ import { IComp } from "./IComp.sol"; * @notice This contract inherits EncryptedERC20 and Ownable2Step. * This is based on the Comp.sol contract written by Compound Labs. * see: compound-finance/compound-protocol/blob/master/contracts/Governance/Comp.sol + * It is a governance token used to delegate votes, which can be used by contracts such as + * GovernorAlphaZama.sol. * It uses encrypted votes to delegate the voting power associated * with an account's balance. * @dev The delegation of votes leaks information about the account's encrypted balance to the delegate. */ contract Comp is IComp, EncryptedERC20, Ownable2Step { + /// @notice Returned if the `blockNumber` is higher or equal to the (current) `block.number`. + /// @dev It is returned for requests to access votes. + error BlockNumberEqualOrHigherThanCurrentBlock(); + + /// @notice Returned if the `msg.sender` is not the `governor` contract. + error GovernorInvalid(); + /// @notice Emitted when an account changes its delegate. event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); /// @notice Emitted when a delegate account's vote balance changes. event DelegateVotesChanged(address indexed delegate); - /// @notice Emitted when the contract that can reencrypt changes. - event NewAllowedContract(address indexed allowedContract); + /// @notice Emitted when the governor contract that can reencrypt votes changes. + /// @dev It can be set to a malicious contract, which could reencrypt all user votes. + event NewGovernor(address indexed governor); /// @notice A checkpoint for marking number of votes from a given block. /// @param fromBlock Block from where the checkpoint applies. /// @param votes Total number of votes for the account power. - /// @dev In Compound's implementation, `fromBlock` is defined as uint32 to allow tight-packing + /// @dev In Compound's implementation, `fromBlock` is defined as uint32 to allow tight-packing. /// However, in this implementations `votes` is uint256-based. /// `fromBlock`'s type is set to uint256, which simplifies the codebase. struct Checkpoint { @@ -44,8 +54,9 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); - /// @notice The smart contract that can access votes. - address public allowedContract; + /// @notice The smart contract that can access encrypted votes. + /// @dev The contract is expected to be a governor contract. + address public governor; /// @notice A record of each account's delegate. mapping(address account => address delegate) public delegates; @@ -111,15 +122,21 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { /** * @notice Determine the prior number of votes for an account as of a block number. * @dev Block number must be a finalized block or else this function will revert. - * This function can change the state since the allowedContract needs access in the ACL + * This function can change the state since the governor needs access in the ACL * contract. * @param account Account address. * @param blockNumber The block number to get the vote balance at. * @return votes Number of votes the account as of the given block number. */ - function getPriorVotesForAllowedContract(address account, uint256 blockNumber) external returns (euint64 votes) { - require(msg.sender == allowedContract, "Caller not allowed to call this function"); - require(blockNumber < block.number, "Comp::getPriorVotes: not yet determined"); + function getPriorVotesForGovernor(address account, uint256 blockNumber) external returns (euint64 votes) { + if (msg.sender != governor) { + revert GovernorInvalid(); + } + + if (blockNumber >= block.number) { + revert BlockNumberEqualOrHigherThanCurrentBlock(); + } + votes = _getPriorVote(account, blockNumber); TFHE.allow(votes, msg.sender); } @@ -142,17 +159,20 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { * @return votes Number of votes the account as of the given block. */ function getPriorVotes(address account, uint256 blockNumber) external view returns (euint64 votes) { - require(blockNumber < block.number, "Comp::getPriorVotes: not yet determined"); + if (blockNumber >= block.number) { + revert BlockNumberEqualOrHigherThanCurrentBlock(); + } + return _getPriorVote(account, blockNumber); } /** * @notice Set an allowed contract that can access votes. - * @param contractAddress The address of the smart contract that may access votes. + * @param newGovernor New governor contract that can reencrypt/access votes. */ - function setAllowedContract(address contractAddress) public onlyOwner { - allowedContract = contractAddress; - emit NewAllowedContract(contractAddress); + function setGovernor(address newGovernor) public onlyOwner { + governor = newGovernor; + emit NewGovernor(newGovernor); } function _delegate(address delegator, address delegatee) internal { diff --git a/contracts/DAO/CompoundTimelock.sol b/contracts/DAO/CompoundTimelock.sol index 69ff8b4..900b96f 100644 --- a/contracts/DAO/CompoundTimelock.sol +++ b/contracts/DAO/CompoundTimelock.sol @@ -5,36 +5,13 @@ import { ICompoundTimelock } from "./ICompoundTimelock.sol"; /** * @title CompoundTimelock + * @notice This contract allows the admin to set a delay period before executing transactions. + * Transactions must be queued before execution. No transaction can be executed during this period, + * which offers time to verify the validity of pending transactions. + * It also has a grace period to allow for transactions + * not to be executed after a specific period following the queuing. */ contract CompoundTimelock is ICompoundTimelock { - event NewAdmin(address indexed newAdmin); - event NewPendingAdmin(address indexed newPendingAdmin); - event NewDelay(uint256 indexed newDelay); - event CancelTransaction( - bytes32 indexed txHash, - address indexed target, - uint256 value, - string signature, - bytes data, - uint256 eta - ); - event ExecuteTransaction( - bytes32 indexed txHash, - address indexed target, - uint256 value, - string signature, - bytes data, - uint256 eta - ); - event QueueTransaction( - bytes32 indexed txHash, - address indexed target, - uint256 value, - string signature, - bytes data, - uint256 eta - ); - uint256 public constant GRACE_PERIOD = 14 days; uint256 public constant MINIMUM_DELAY = 2 days; uint256 public constant MAXIMUM_DELAY = 30 days; diff --git a/contracts/DAO/GovernorAlphaZama.sol b/contracts/DAO/GovernorAlphaZama.sol index ff8f79d..065d5e1 100644 --- a/contracts/DAO/GovernorAlphaZama.sol +++ b/contracts/DAO/GovernorAlphaZama.sol @@ -12,6 +12,12 @@ import { ICompoundTimelock } from "./ICompoundTimelock.sol"; * @title GovernorAlphaZama * @notice This is based on the GovernorAlpha.sol contract written by Compound Labs. * see: compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol + * This decentralized governance system allows users to propose and vote on changes to the protocol. + * The contract is responsible for: + * - Proposal: A new proposal is made to introduce a change. + * - Voting: Users can vote on the proposal, either in favor or against it. + * - Quorum: A minimum number of votes (quorum) must be reached for the proposal to pass. + * - Execution: Once a proposal passes, it is executed and takes effect on the Compound protocol. */ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /// @notice Returned if proposal contains too many changes. @@ -427,7 +433,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { ebool canPropose = TFHE.lt( _EUINT64_PROPOSAL_THRESHOLD, - COMP.getPriorVotesForAllowedContract(msg.sender, block.number - 1) + COMP.getPriorVotesForGovernor(msg.sender, block.number - 1) ); uint256[] memory cts = new uint256[](1); @@ -640,7 +646,7 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { revert VoterHasAlreadyVoted(); } - euint64 votes = COMP.getPriorVotesForAllowedContract(voter, proposal.startBlock); + euint64 votes = COMP.getPriorVotesForGovernor(voter, proposal.startBlock); proposal.forVotes = TFHE.select(support, TFHE.add(proposal.forVotes, votes), proposal.forVotes); proposal.againstVotes = TFHE.select(support, proposal.againstVotes, TFHE.add(proposal.againstVotes, votes)); diff --git a/contracts/DAO/IComp.sol b/contracts/DAO/IComp.sol index e8866ad..e74b73e 100644 --- a/contracts/DAO/IComp.sol +++ b/contracts/DAO/IComp.sol @@ -8,5 +8,5 @@ import "fhevm/lib/TFHE.sol"; * @dev The GovernorAlphaZama relies on this interface. */ interface IComp { - function getPriorVotesForAllowedContract(address account, uint256 blockNumber) external returns (euint64 votes); + function getPriorVotesForGovernor(address account, uint256 blockNumber) external returns (euint64 votes); } diff --git a/contracts/DAO/ICompoundTimelock.sol b/contracts/DAO/ICompoundTimelock.sol index bceaedb..46287da 100644 --- a/contracts/DAO/ICompoundTimelock.sol +++ b/contracts/DAO/ICompoundTimelock.sol @@ -5,6 +5,34 @@ pragma solidity ^0.8.24; * @title ICompoundTimelock */ interface ICompoundTimelock { + event NewAdmin(address indexed newAdmin); + event NewPendingAdmin(address indexed newPendingAdmin); + event NewDelay(uint256 indexed newDelay); + event CancelTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event ExecuteTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event QueueTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + function delay() external view returns (uint256); function GRACE_PERIOD() external view returns (uint256); From 02b08e0d0fa47f86aa10e36ea83fa533548c9cc6 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 7 Nov 2024 10:26:09 +0100 Subject: [PATCH 58/73] test: Adjustments --- test/dao/Comp.test.ts | 39 +++++++++++++++--------------- test/dao/GovernorAlphaZama.test.ts | 2 +- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/test/dao/Comp.test.ts b/test/dao/Comp.test.ts index 28de149..ee169fa 100644 --- a/test/dao/Comp.test.ts +++ b/test/dao/Comp.test.ts @@ -139,19 +139,21 @@ describe("Comp", function () { it("cannot request votes if blocktime is equal to current blocktime", async function () { let blockNumber = await ethers.provider.getBlockNumber(); - await expect(this.comp.getPriorVotes(this.signers.alice, blockNumber + 1)).to.be.revertedWith( - "Comp::getPriorVotes: not yet determined", + await expect(this.comp.getPriorVotes(this.signers.alice, blockNumber + 1)).to.be.revertedWithCustomError( + this.comp, + "BlockNumberEqualOrHigherThanCurrentBlock", ); + const newAllowedContract = "0x9d3e06a2952dc49EDCc73e41C76645797fC53967"; - const tx = await this.comp.connect(this.signers.alice).setAllowedContract(this.signers.bob); + const tx = await this.comp.connect(this.signers.alice).setGovernor(this.signers.bob); await tx.wait(); blockNumber = await ethers.provider.getBlockNumber(); await expect( - this.comp.connect(this.signers.bob).getPriorVotesForAllowedContract(this.signers.alice, blockNumber + 1), - ).to.be.revertedWith("Comp::getPriorVotes: not yet determined"); + this.comp.connect(this.signers.bob).getPriorVotesForGovernor(this.signers.alice, blockNumber + 1), + ).to.be.revertedWithCustomError(this.comp, "BlockNumberEqualOrHigherThanCurrentBlock"); }); it("users can request past votes getPriorVotes", async function () { @@ -221,23 +223,23 @@ describe("Comp", function () { ).to.be.equal(parseUnits(String(2_000_000), 6)); }); - it("only allowed contract can call getPriorVotes", async function () { + it("only governor contract can call getPriorVotes", async function () { await expect( - this.comp.getPriorVotesForAllowedContract("0xE359a77c3bFE58792FB167D05720e37032A1e520", 0), - ).to.be.revertedWith("Caller not allowed to call this function"); + this.comp.getPriorVotesForGovernor("0xE359a77c3bFE58792FB167D05720e37032A1e520", 0), + ).to.be.revertedWithCustomError(this.comp, "GovernorInvalid"); }); - it("only owner could set allowed contract", async function () { + it("only owner can set governor contract", async function () { const newAllowedContract = "0x9d3e06a2952dc49EDCc73e41C76645797fC53967"; - await expect(this.comp.connect(this.signers.bob).setAllowedContract(newAllowedContract)) + await expect(this.comp.connect(this.signers.bob).setGovernor(newAllowedContract)) .to.be.revertedWithCustomError(this.comp, "OwnableUnauthorizedAccount") .withArgs(this.signers.bob.address); }); - it("allowed address can access votes for any account", async function () { - // Bob becomes the allowed address. - let tx = await this.comp.connect(this.signers.alice).setAllowedContract(this.signers.bob.address); + it("governor address can access votes for any account", async function () { + // Bob becomes the governor address. + let tx = await this.comp.connect(this.signers.alice).setGovernor(this.signers.bob.address); await tx.wait(); // Alice delegates her votes to Carol. @@ -248,13 +250,12 @@ describe("Comp", function () { await waitNBlocks(1); await waitNBlocks(1); - // Bob, the allowed address, get the prior votes for allowed contract. - const voteHandle = await this.comp + // Bob, the governor address, gets the prior votes of Carol. + // @dev It is not possible to catch the return value since it is not a view function. + // GovernorAlpha.test.ts contains tests that use this function. + await this.comp .connect(this.signers.bob) - .getPriorVotesForAllowedContract(this.signers.carol.address, latestBlockNumber + 1); - - // It is not possible to catch the return value. - // TODO: Create a test helper contract to implement this. + .getPriorVotesForGovernor(this.signers.carol.address, latestBlockNumber + 1); }); it("different voters can delegate to same delegatee", async function () { diff --git a/test/dao/GovernorAlphaZama.test.ts b/test/dao/GovernorAlphaZama.test.ts index 1787f40..25ad948 100644 --- a/test/dao/GovernorAlphaZama.test.ts +++ b/test/dao/GovernorAlphaZama.test.ts @@ -38,7 +38,7 @@ describe("GovernorAlphaZama", function () { this.governor = governor; this.governorAddress = await governor.getAddress(); - const tx = await this.comp.setAllowedContract(this.governorAddress); + const tx = await this.comp.setGovernor(this.governorAddress); await tx.wait(); }); From 32b38ae57eca8a74fe4b975fed589bab4b7be873 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 7 Nov 2024 10:29:37 +0100 Subject: [PATCH 59/73] refactor: Change folder name --- contracts/{DAO => governance}/Comp.sol | 0 contracts/{DAO => governance}/CompoundTimelock.sol | 0 contracts/{DAO => governance}/GovernorAlphaZama.sol | 0 contracts/{DAO => governance}/IComp.sol | 0 contracts/{DAO => governance}/ICompoundTimelock.sol | 0 test/{dao => governance}/Comp.fixture.ts | 0 test/{dao => governance}/Comp.test.ts | 0 test/{dao => governance}/CompoundTimelock.test.ts | 0 test/{dao => governance}/DelegateBySig.ts | 0 test/{dao => governance}/GovernorAlphaZama.fixture.ts | 0 test/{dao => governance}/GovernorAlphaZama.test.ts | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename contracts/{DAO => governance}/Comp.sol (100%) rename contracts/{DAO => governance}/CompoundTimelock.sol (100%) rename contracts/{DAO => governance}/GovernorAlphaZama.sol (100%) rename contracts/{DAO => governance}/IComp.sol (100%) rename contracts/{DAO => governance}/ICompoundTimelock.sol (100%) rename test/{dao => governance}/Comp.fixture.ts (100%) rename test/{dao => governance}/Comp.test.ts (100%) rename test/{dao => governance}/CompoundTimelock.test.ts (100%) rename test/{dao => governance}/DelegateBySig.ts (100%) rename test/{dao => governance}/GovernorAlphaZama.fixture.ts (100%) rename test/{dao => governance}/GovernorAlphaZama.test.ts (100%) diff --git a/contracts/DAO/Comp.sol b/contracts/governance/Comp.sol similarity index 100% rename from contracts/DAO/Comp.sol rename to contracts/governance/Comp.sol diff --git a/contracts/DAO/CompoundTimelock.sol b/contracts/governance/CompoundTimelock.sol similarity index 100% rename from contracts/DAO/CompoundTimelock.sol rename to contracts/governance/CompoundTimelock.sol diff --git a/contracts/DAO/GovernorAlphaZama.sol b/contracts/governance/GovernorAlphaZama.sol similarity index 100% rename from contracts/DAO/GovernorAlphaZama.sol rename to contracts/governance/GovernorAlphaZama.sol diff --git a/contracts/DAO/IComp.sol b/contracts/governance/IComp.sol similarity index 100% rename from contracts/DAO/IComp.sol rename to contracts/governance/IComp.sol diff --git a/contracts/DAO/ICompoundTimelock.sol b/contracts/governance/ICompoundTimelock.sol similarity index 100% rename from contracts/DAO/ICompoundTimelock.sol rename to contracts/governance/ICompoundTimelock.sol diff --git a/test/dao/Comp.fixture.ts b/test/governance/Comp.fixture.ts similarity index 100% rename from test/dao/Comp.fixture.ts rename to test/governance/Comp.fixture.ts diff --git a/test/dao/Comp.test.ts b/test/governance/Comp.test.ts similarity index 100% rename from test/dao/Comp.test.ts rename to test/governance/Comp.test.ts diff --git a/test/dao/CompoundTimelock.test.ts b/test/governance/CompoundTimelock.test.ts similarity index 100% rename from test/dao/CompoundTimelock.test.ts rename to test/governance/CompoundTimelock.test.ts diff --git a/test/dao/DelegateBySig.ts b/test/governance/DelegateBySig.ts similarity index 100% rename from test/dao/DelegateBySig.ts rename to test/governance/DelegateBySig.ts diff --git a/test/dao/GovernorAlphaZama.fixture.ts b/test/governance/GovernorAlphaZama.fixture.ts similarity index 100% rename from test/dao/GovernorAlphaZama.fixture.ts rename to test/governance/GovernorAlphaZama.fixture.ts diff --git a/test/dao/GovernorAlphaZama.test.ts b/test/governance/GovernorAlphaZama.test.ts similarity index 100% rename from test/dao/GovernorAlphaZama.test.ts rename to test/governance/GovernorAlphaZama.test.ts From 3c986c47fef63470c68e86a4696747900a09ddbc Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 7 Nov 2024 11:38:44 +0100 Subject: [PATCH 60/73] docs: NatSpec updates --- contracts/governance/Comp.sol | 54 ++++++++++------------ contracts/governance/CompoundTimelock.sol | 52 ++++++++++++++++++--- contracts/governance/GovernorAlphaZama.sol | 2 +- contracts/governance/IComp.sol | 9 ++++ contracts/governance/ICompoundTimelock.sol | 52 ++++++++++++++++++++- 5 files changed, 130 insertions(+), 39 deletions(-) diff --git a/contracts/governance/Comp.sol b/contracts/governance/Comp.sol index 4bdf381..7d1affb 100644 --- a/contracts/governance/Comp.sol +++ b/contracts/governance/Comp.sol @@ -15,7 +15,7 @@ import { IComp } from "./IComp.sol"; * GovernorAlphaZama.sol. * It uses encrypted votes to delegate the voting power associated * with an account's balance. - * @dev The delegation of votes leaks information about the account's encrypted balance to the delegate. + * @dev The delegation of votes leaks information about the account's encrypted balance to the `delegatee`. */ contract Comp is IComp, EncryptedERC20, Ownable2Step { /// @notice Returned if the `blockNumber` is higher or equal to the (current) `block.number`. @@ -25,14 +25,14 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { /// @notice Returned if the `msg.sender` is not the `governor` contract. error GovernorInvalid(); - /// @notice Emitted when an account changes its delegate. + /// @notice Emitted when an `account` (i.e. `delegator`) changes its delegate. event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); - /// @notice Emitted when a delegate account's vote balance changes. + /// @notice Emitted when a `delegate` account's vote balance changes. event DelegateVotesChanged(address indexed delegate); /// @notice Emitted when the governor contract that can reencrypt votes changes. - /// @dev It can be set to a malicious contract, which could reencrypt all user votes. + /// @dev WARNING: it can be set to a malicious contract, which could reencrypt all user votes. event NewGovernor(address indexed governor); /// @notice A checkpoint for marking number of votes from a given block. @@ -58,17 +58,17 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { /// @dev The contract is expected to be a governor contract. address public governor; - /// @notice A record of each account's delegate. + /// @notice A record of each account's `delegate`. mapping(address account => address delegate) public delegates; /// @notice A record of states for signing/validating signatures. mapping(address account => uint256 nonce) public nonces; - /// @notice The number of checkpoints for each account. - mapping(address account => uint32 checkpoints) public numCheckpoints; + /// @notice The number of checkpoints for an `account`. + mapping(address account => uint32 _checkpoints) public numCheckpoints; - /// @notice A record of votes checkpoints for an `account` using incremental indices. - mapping(address account => mapping(uint32 index => Checkpoint checkpoint)) internal checkpoints; + /// @notice A record of votes _checkpoints for an `account` using incremental indices. + mapping(address account => mapping(uint32 index => Checkpoint checkpoint)) internal _checkpoints; /// @notice Constant for zero using TFHE. /// @dev Since it is expensive to compute 0, it is stored instead. @@ -120,13 +120,7 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { } /** - * @notice Determine the prior number of votes for an account as of a block number. - * @dev Block number must be a finalized block or else this function will revert. - * This function can change the state since the governor needs access in the ACL - * contract. - * @param account Account address. - * @param blockNumber The block number to get the vote balance at. - * @return votes Number of votes the account as of the given block number. + * @notice See {IComp-getPriorVotesForGovernor}. */ function getPriorVotesForGovernor(address account, uint256 blockNumber) external returns (euint64 votes) { if (msg.sender != governor) { @@ -144,11 +138,13 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { /** * @notice Get current votes of account. * @param account Account address - * @return votes Current votes. + * @return votes Current (encrypted) votes. */ function getCurrentVotes(address account) external view returns (euint64 votes) { uint32 nCheckpoints = numCheckpoints[account]; - votes = nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : votes; + if (nCheckpoints > 0) { + votes = _checkpoints[account][nCheckpoints - 1].votes; + } } /** @@ -167,7 +163,7 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { } /** - * @notice Set an allowed contract that can access votes. + * @notice Set a governor contract. * @param newGovernor New governor contract that can reencrypt/access votes. */ function setGovernor(address newGovernor) public onlyOwner { @@ -191,10 +187,10 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { if (nCheckpoints == 0) { return _EUINT64_ZERO; - } else if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { + } else if (_checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { // First check most recent balance - votes = checkpoints[account][nCheckpoints - 1].votes; - } else if (checkpoints[account][0].fromBlock > blockNumber) { + votes = _checkpoints[account][nCheckpoints - 1].votes; + } else if (_checkpoints[account][0].fromBlock > blockNumber) { // Next check implicit zero balance return _EUINT64_ZERO; } else { @@ -203,7 +199,7 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { uint32 upper = nCheckpoints - 1; while (upper > lower) { uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow - Checkpoint memory cp = checkpoints[account][center]; + Checkpoint memory cp = _checkpoints[account][center]; if (cp.fromBlock == blockNumber) { return cp.votes; } else if (cp.fromBlock < blockNumber) { @@ -212,7 +208,7 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { upper = center - 1; } } - votes = checkpoints[account][lower].votes; + votes = _checkpoints[account][lower].votes; } } @@ -220,14 +216,14 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { if (srcRep != dstRep) { if (srcRep != address(0)) { uint32 srcRepNum = numCheckpoints[srcRep]; - euint64 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : _EUINT64_ZERO; + euint64 srcRepOld = srcRepNum > 0 ? _checkpoints[srcRep][srcRepNum - 1].votes : _EUINT64_ZERO; euint64 srcRepNew = TFHE.sub(srcRepOld, amount); // srcRepOld - amount; _writeCheckpoint(srcRep, srcRepNum, srcRepNew); } if (dstRep != address(0)) { uint32 dstRepNum = numCheckpoints[dstRep]; - euint64 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : _EUINT64_ZERO; + euint64 dstRepOld = dstRepNum > 0 ? _checkpoints[dstRep][dstRepNum - 1].votes : _EUINT64_ZERO; euint64 dstRepNew = TFHE.add(dstRepOld, amount); // dstRepOld + amount; _writeCheckpoint(dstRep, dstRepNum, dstRepNew); } @@ -242,10 +238,10 @@ contract Comp is IComp, EncryptedERC20, Ownable2Step { } function _writeCheckpoint(address delegatee, uint32 nCheckpoints, euint64 newVotes) internal { - if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == block.number) { - checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; + if (nCheckpoints > 0 && _checkpoints[delegatee][nCheckpoints - 1].fromBlock == block.number) { + _checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; } else { - checkpoints[delegatee][nCheckpoints] = Checkpoint(block.number, newVotes); + _checkpoints[delegatee][nCheckpoints] = Checkpoint(block.number, newVotes); numCheckpoints[delegatee] = nCheckpoints + 1; } diff --git a/contracts/governance/CompoundTimelock.sol b/contracts/governance/CompoundTimelock.sol index 900b96f..b716fdd 100644 --- a/contracts/governance/CompoundTimelock.sol +++ b/contracts/governance/CompoundTimelock.sol @@ -12,16 +12,36 @@ import { ICompoundTimelock } from "./ICompoundTimelock.sol"; * not to be executed after a specific period following the queuing. */ contract CompoundTimelock is ICompoundTimelock { + /** + * @notice See {ICompoundTimelock-GRACE_PERIOD}. + */ uint256 public constant GRACE_PERIOD = 14 days; + + /// @notice Minimum delay that can be set in the setDelay function. uint256 public constant MINIMUM_DELAY = 2 days; + + /// @notice Maximum delay that can be set in the setDelay function. uint256 public constant MAXIMUM_DELAY = 30 days; + /// @notice Admin address. address public admin; + + /// @notice Pending admin address. + /// @dev The transer of the admin is a two-step process. address public pendingAdmin; + + /** + * @notice See {ICompoundTimelock-delay}. + */ uint256 public delay; + /// @notice Return whether the transaction is queued based on its hash. mapping(bytes32 => bool) public queuedTransactions; + /** + * @param admin_ Admin address. + * @param delay_ Delay (in timestamp). + */ constructor(address admin_, uint256 delay_) { require(delay_ >= MINIMUM_DELAY, "Timelock::constructor: Delay must exceed minimum delay."); require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay."); @@ -32,6 +52,11 @@ contract CompoundTimelock is ICompoundTimelock { receive() external payable {} + /** + * @notice Set the delay. + * @dev This transaction must be queued. + * @param delay_ Delay (in timestamp). + */ function setDelay(uint256 delay_) public { require(msg.sender == address(this), "Timelock::setDelay: Call must come from Timelock."); require(delay_ >= MINIMUM_DELAY, "Timelock::setDelay: Delay must exceed minimum delay."); @@ -41,6 +66,9 @@ contract CompoundTimelock is ICompoundTimelock { emit NewDelay(delay); } + /** + * @notice See {ICompoundTimelock-acceptAdmin}. + */ function acceptAdmin() public { require(msg.sender == pendingAdmin, "Timelock::acceptAdmin: Call must come from pendingAdmin."); admin = msg.sender; @@ -49,6 +77,11 @@ contract CompoundTimelock is ICompoundTimelock { emit NewAdmin(admin); } + /** + * @notice Set the pending admin. + * @dev This transaction must be queued. + * @param pendingAdmin_ Pending admin address. + */ function setPendingAdmin(address pendingAdmin_) public { require(msg.sender == address(this), "Timelock::setPendingAdmin: Call must come from Timelock."); pendingAdmin = pendingAdmin_; @@ -56,6 +89,9 @@ contract CompoundTimelock is ICompoundTimelock { emit NewPendingAdmin(pendingAdmin); } + /** + * @notice See {ICompoundTimelock-queueTransaction}. + */ function queueTransaction( address target, uint256 value, @@ -65,7 +101,7 @@ contract CompoundTimelock is ICompoundTimelock { ) public returns (bytes32) { require(msg.sender == admin, "Timelock::queueTransaction: Call must come from admin."); require( - eta >= getBlockTimestamp() + delay, + eta >= block.timestamp + delay, "Timelock::queueTransaction: Estimated execution block must satisfy delay." ); @@ -76,6 +112,9 @@ contract CompoundTimelock is ICompoundTimelock { return txHash; } + /** + * @notice See {ICompoundTimelock-cancelTransaction}. + */ function cancelTransaction( address target, uint256 value, @@ -91,6 +130,9 @@ contract CompoundTimelock is ICompoundTimelock { emit CancelTransaction(txHash, target, value, signature, data, eta); } + /** + * @notice See {ICompoundTimelock-executeTransaction}. + */ function executeTransaction( address target, uint256 value, @@ -102,8 +144,8 @@ contract CompoundTimelock is ICompoundTimelock { bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); require(queuedTransactions[txHash], "Timelock::executeTransaction: Transaction hasn't been queued."); - require(getBlockTimestamp() >= eta, "Timelock::executeTransaction: Transaction hasn't surpassed time lock."); - require(getBlockTimestamp() <= eta + GRACE_PERIOD, "Timelock::executeTransaction: Transaction is stale."); + require(block.timestamp >= eta, "Timelock::executeTransaction: Transaction hasn't surpassed time lock."); + require(block.timestamp <= eta + GRACE_PERIOD, "Timelock::executeTransaction: Transaction is stale."); queuedTransactions[txHash] = false; @@ -122,8 +164,4 @@ contract CompoundTimelock is ICompoundTimelock { return returnData; } - - function getBlockTimestamp() internal view returns (uint256) { - return block.timestamp; - } } diff --git a/contracts/governance/GovernorAlphaZama.sol b/contracts/governance/GovernorAlphaZama.sol index 065d5e1..95ba7d2 100644 --- a/contracts/governance/GovernorAlphaZama.sol +++ b/contracts/governance/GovernorAlphaZama.sol @@ -17,7 +17,7 @@ import { ICompoundTimelock } from "./ICompoundTimelock.sol"; * - Proposal: A new proposal is made to introduce a change. * - Voting: Users can vote on the proposal, either in favor or against it. * - Quorum: A minimum number of votes (quorum) must be reached for the proposal to pass. - * - Execution: Once a proposal passes, it is executed and takes effect on the Compound protocol. + * - Execution: Once a proposal passes, it is executed and takes effect on the taregt protocol. */ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /// @notice Returned if proposal contains too many changes. diff --git a/contracts/governance/IComp.sol b/contracts/governance/IComp.sol index e74b73e..a93e0a7 100644 --- a/contracts/governance/IComp.sol +++ b/contracts/governance/IComp.sol @@ -8,5 +8,14 @@ import "fhevm/lib/TFHE.sol"; * @dev The GovernorAlphaZama relies on this interface. */ interface IComp { + /** + * @notice Determine the prior number of votes for an account as of a block number. + * @dev Block number must be a finalized block or else this function will revert. + * This function can change the state since the governor needs access in the ACL + * contract. + * @param account Account address. + * @param blockNumber The block number to get the vote balance at. + * @return votes Number of votes the account as of the given block number. + */ function getPriorVotesForGovernor(address account, uint256 blockNumber) external returns (euint64 votes); } diff --git a/contracts/governance/ICompoundTimelock.sol b/contracts/governance/ICompoundTimelock.sol index 46287da..ff3bb3f 100644 --- a/contracts/governance/ICompoundTimelock.sol +++ b/contracts/governance/ICompoundTimelock.sol @@ -5,9 +5,16 @@ pragma solidity ^0.8.24; * @title ICompoundTimelock */ interface ICompoundTimelock { + /// @notice Emitted when there is a change of admin. event NewAdmin(address indexed newAdmin); + + /// @notice Emtited when there is a change of pending admin. event NewPendingAdmin(address indexed newPendingAdmin); + + /// @notice Emitted when there is a new delay set. event NewDelay(uint256 indexed newDelay); + + /// @notice Emitted when the queued transaction is canceled. event CancelTransaction( bytes32 indexed txHash, address indexed target, @@ -16,6 +23,8 @@ interface ICompoundTimelock { bytes data, uint256 eta ); + + /// @notice Emitted when the queued transaction is executed. event ExecuteTransaction( bytes32 indexed txHash, address indexed target, @@ -24,6 +33,8 @@ interface ICompoundTimelock { bytes data, uint256 eta ); + + /// @notice Emitted when a transaction is queued. event QueueTransaction( bytes32 indexed txHash, address indexed target, @@ -33,22 +44,51 @@ interface ICompoundTimelock { uint256 eta ); + /** + * @notice Returns the delay (in timestamp) for a queued transaction before it can be executed. + */ function delay() external view returns (uint256); + /** + * @notice Returns the grace period (in timestamp). + * The grace period indicates how long a transaction can remain queued before it cannot be + * executed again. + */ function GRACE_PERIOD() external view returns (uint256); + /** + * @notice Accept admin role. + */ function acceptAdmin() external; + /** + * @notice Returns whether the transactions are queued. + */ function queuedTransactions(bytes32 hash) external view returns (bool); + /** + * @notice Queue a transaction. + * @param target Target address to execute the transaction. + * @param signature Function signature to execute. + * @param data The data to include in the transaction. + * @param eta The earliest eta to queue the transaction. + * @return hashTransaction The transaction's hash. + */ function queueTransaction( address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta - ) external returns (bytes32); + ) external returns (bytes32 hashTransaction); + /** + * @notice Cancel a queued transaction. + * @param target Target address to execute the transaction. + * @param signature Function signature to execute. + * @param data The data to include in the transaction. + * @param eta The earliest eta to queue the transaction. + */ function cancelTransaction( address target, uint256 value, @@ -57,11 +97,19 @@ interface ICompoundTimelock { uint256 eta ) external; + /** + * @notice Cancel a queued transaction. + * @param target Target address to execute the transaction. + * @param signature Function signature to execute. + * @param data The data to include in the transaction. + * @param eta The earliest eta to queue the transaction. + * @return response The response from the transaction once executed. + */ function executeTransaction( address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta - ) external payable returns (bytes memory); + ) external payable returns (bytes memory response); } From d06396e9419c82c85a29914a3e982bb173908a44 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 7 Nov 2024 15:22:39 +0100 Subject: [PATCH 61/73] chore: Config updates --- .npmignore | 1 + .solcover.js | 18 ++++++++---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.npmignore b/.npmignore index 469a7e6..d341f51 100644 --- a/.npmignore +++ b/.npmignore @@ -1,5 +1,6 @@ * !contracts/** +contracts/mocks/** !package.json !README.md !LICENSE diff --git a/.solcover.js b/.solcover.js index 938b911..a7a7000 100644 --- a/.solcover.js +++ b/.solcover.js @@ -1,11 +1,9 @@ -module.exports = { - istanbulReporter: ["html", "lcov"], - providerOptions: { - mnemonic: process.env.MNEMONIC, - }, - skipFiles: ["test", "fhevmTemp"], - mocha: { - fgrep: "[skip-on-coverage]", - invert: true, - }, +export const istanbulReporter = ["html", "lcov"]; +export const providerOptions = { + mnemonic: process.env.MNEMONIC, +}; +export const skipFiles = ["mocks", "test", "fhevmTemp"]; +export const mocha = { + fgrep: "[skip-on-coverage]", + invert: true, }; From 75e5aba91c5e1734039e1312d850c099dafacccc Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 7 Nov 2024 15:23:09 +0100 Subject: [PATCH 62/73] refactor: Set functions for FHEVM/Gateway --- .solcover.js | 2 +- contracts/governance/GovernorAlphaZama.sol | 5 +---- contracts/test/DefaultFHEVMConfig.sol | 10 ++++++++++ contracts/test/DefaultGatewayConfig.sol | 10 ++++++++++ contracts/test/governance/TestComp.sol | 11 +++++++++++ .../test/governance/TestGovernorAlphaZama.sol | 17 +++++++++++++++++ .../token/ERC20/TestEncryptedERC20Mintable.sol | 15 +++++++++++++++ .../TestEncryptedERC20WithErrorsMintable.sol | 15 +++++++++++++++ contracts/token/ERC20/EncryptedERC20.sol | 1 - test/encryptedERC20/EncryptedERC20.fixture.ts | 6 +++--- .../EncryptedERC20WithErrors.fixture.ts | 8 ++++---- test/governance/Comp.fixture.ts | 12 ++++++------ test/governance/GovernorAlphaZama.fixture.ts | 8 ++++---- 13 files changed, 97 insertions(+), 23 deletions(-) create mode 100644 contracts/test/DefaultFHEVMConfig.sol create mode 100644 contracts/test/DefaultGatewayConfig.sol create mode 100644 contracts/test/governance/TestComp.sol create mode 100644 contracts/test/governance/TestGovernorAlphaZama.sol create mode 100644 contracts/test/token/ERC20/TestEncryptedERC20Mintable.sol create mode 100644 contracts/test/token/ERC20/TestEncryptedERC20WithErrorsMintable.sol diff --git a/.solcover.js b/.solcover.js index a7a7000..1834226 100644 --- a/.solcover.js +++ b/.solcover.js @@ -2,7 +2,7 @@ export const istanbulReporter = ["html", "lcov"]; export const providerOptions = { mnemonic: process.env.MNEMONIC, }; -export const skipFiles = ["mocks", "test", "fhevmTemp"]; +export const skipFiles = ["test", "fhevmTemp"]; export const mocha = { fgrep: "[skip-on-coverage]", invert: true, diff --git a/contracts/governance/GovernorAlphaZama.sol b/contracts/governance/GovernorAlphaZama.sol index 95ba7d2..47d73c7 100644 --- a/contracts/governance/GovernorAlphaZama.sol +++ b/contracts/governance/GovernorAlphaZama.sol @@ -17,7 +17,7 @@ import { ICompoundTimelock } from "./ICompoundTimelock.sol"; * - Proposal: A new proposal is made to introduce a change. * - Voting: Users can vote on the proposal, either in favor or against it. * - Quorum: A minimum number of votes (quorum) must be reached for the proposal to pass. - * - Execution: Once a proposal passes, it is executed and takes effect on the taregt protocol. + * - Execution: Once a proposal passes, it is executed and takes effect on the protocol. */ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /// @notice Returned if proposal contains too many changes. @@ -245,9 +245,6 @@ contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * For instance, 3 days would have a votingPeriod = 21,600 blocks if 12s per block. */ constructor(address owner_, address timelock_, address comp_, uint256 votingPeriod_) Ownable(owner_) { - TFHE.setFHEVM(FHEVMConfig.defaultConfig()); - Gateway.setGateway(Gateway.defaultGatewayAddress()); - TIMELOCK = ICompoundTimelock(timelock_); COMP = IComp(comp_); VOTING_PERIOD = votingPeriod_; diff --git a/contracts/test/DefaultFHEVMConfig.sol b/contracts/test/DefaultFHEVMConfig.sol new file mode 100644 index 0000000..07dc36a --- /dev/null +++ b/contracts/test/DefaultFHEVMConfig.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import "fhevm/lib/TFHE.sol"; + +contract DefaultFHEVMConfig { + constructor() { + TFHE.setFHEVM(FHEVMConfig.defaultConfig()); + } +} diff --git a/contracts/test/DefaultGatewayConfig.sol b/contracts/test/DefaultGatewayConfig.sol new file mode 100644 index 0000000..75c87d1 --- /dev/null +++ b/contracts/test/DefaultGatewayConfig.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import "fhevm/gateway/GatewayCaller.sol"; + +contract DefaultGatewayConfig { + constructor() { + Gateway.setGateway(Gateway.defaultGatewayAddress()); + } +} diff --git a/contracts/test/governance/TestComp.sol b/contracts/test/governance/TestComp.sol new file mode 100644 index 0000000..a4c4f11 --- /dev/null +++ b/contracts/test/governance/TestComp.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import { Comp } from "../../governance/Comp.sol"; +import { DefaultFHEVMConfig } from "../DefaultFHEVMConfig.sol"; + +contract TestComp is DefaultFHEVMConfig, Comp { + constructor(address owner_) Comp(owner_) { + // + } +} diff --git a/contracts/test/governance/TestGovernorAlphaZama.sol b/contracts/test/governance/TestGovernorAlphaZama.sol new file mode 100644 index 0000000..724ac71 --- /dev/null +++ b/contracts/test/governance/TestGovernorAlphaZama.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import { GovernorAlphaZama } from "../../governance/GovernorAlphaZama.sol"; +import { DefaultFHEVMConfig } from "../DefaultFHEVMConfig.sol"; +import { DefaultGatewayConfig } from "../DefaultGatewayConfig.sol"; + +contract TestGovernorAlphaZama is DefaultFHEVMConfig, DefaultGatewayConfig, GovernorAlphaZama { + constructor( + address owner_, + address timelock_, + address comp_, + uint256 votingPeriod_ + ) GovernorAlphaZama(owner_, timelock_, comp_, votingPeriod_) { + // + } +} diff --git a/contracts/test/token/ERC20/TestEncryptedERC20Mintable.sol b/contracts/test/token/ERC20/TestEncryptedERC20Mintable.sol new file mode 100644 index 0000000..2f0968b --- /dev/null +++ b/contracts/test/token/ERC20/TestEncryptedERC20Mintable.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import { EncryptedERC20Mintable } from "../../../token/ERC20/extensions/EncryptedERC20Mintable.sol"; +import { DefaultFHEVMConfig } from "../../DefaultFHEVMConfig.sol"; + +contract TestEncryptedERC20Mintable is DefaultFHEVMConfig, EncryptedERC20Mintable { + constructor( + string memory name_, + string memory symbol_, + address owner_ + ) EncryptedERC20Mintable(name_, symbol_, owner_) { + // + } +} diff --git a/contracts/test/token/ERC20/TestEncryptedERC20WithErrorsMintable.sol b/contracts/test/token/ERC20/TestEncryptedERC20WithErrorsMintable.sol new file mode 100644 index 0000000..e415a20 --- /dev/null +++ b/contracts/test/token/ERC20/TestEncryptedERC20WithErrorsMintable.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +pragma solidity ^0.8.24; + +import { EncryptedERC20WithErrorsMintable } from "../../../token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol"; +import { DefaultFHEVMConfig } from "../../DefaultFHEVMConfig.sol"; + +contract TestEncryptedERC20WithErrorsMintable is DefaultFHEVMConfig, EncryptedERC20WithErrorsMintable { + constructor( + string memory name_, + string memory symbol_, + address owner_ + ) EncryptedERC20WithErrorsMintable(name_, symbol_, owner_) { + // + } +} diff --git a/contracts/token/ERC20/EncryptedERC20.sol b/contracts/token/ERC20/EncryptedERC20.sol index 417f865..a77eec3 100644 --- a/contracts/token/ERC20/EncryptedERC20.sol +++ b/contracts/token/ERC20/EncryptedERC20.sol @@ -38,7 +38,6 @@ abstract contract EncryptedERC20 is IEncryptedERC20 { * @param symbol_ Symbol. */ constructor(string memory name_, string memory symbol_) { - TFHE.setFHEVM(FHEVMConfig.defaultConfig()); _name = name_; _symbol = symbol_; } diff --git a/test/encryptedERC20/EncryptedERC20.fixture.ts b/test/encryptedERC20/EncryptedERC20.fixture.ts index 28e70dd..8e0782e 100644 --- a/test/encryptedERC20/EncryptedERC20.fixture.ts +++ b/test/encryptedERC20/EncryptedERC20.fixture.ts @@ -1,6 +1,6 @@ import { ethers } from "hardhat"; -import type { EncryptedERC20Mintable, IEncryptedERC20 } from "../../types"; +import type { IEncryptedERC20, TestEncryptedERC20Mintable } from "../../types"; import { reencryptEuint64 } from "../reencrypt"; import { Signers } from "../signers"; import { FhevmInstances } from "../types"; @@ -10,8 +10,8 @@ export async function deployEncryptedERC20Fixture( name: string, symbol: string, owner: string, -): Promise { - const contractFactory = await ethers.getContractFactory("EncryptedERC20Mintable"); +): Promise { + const contractFactory = await ethers.getContractFactory("TestEncryptedERC20Mintable"); const contract = await contractFactory .connect(signers[owner as keyof Signers]) .deploy(name, symbol, signers[owner as keyof Signers].address); diff --git a/test/encryptedERC20/EncryptedERC20WithErrors.fixture.ts b/test/encryptedERC20/EncryptedERC20WithErrors.fixture.ts index 9d2c424..d438d7e 100644 --- a/test/encryptedERC20/EncryptedERC20WithErrors.fixture.ts +++ b/test/encryptedERC20/EncryptedERC20WithErrors.fixture.ts @@ -1,6 +1,6 @@ import { ethers } from "hardhat"; -import type { EncryptedERC20WithErrorsMintable } from "../../types"; +import type { TestEncryptedERC20WithErrorsMintable } from "../../types"; import { reencryptEuint8 } from "../reencrypt"; import { Signers } from "../signers"; import { FhevmInstances } from "../types"; @@ -10,8 +10,8 @@ export async function deployEncryptedERC20WithErrorsFixture( name: string, symbol: string, owner: string, -): Promise { - const contractFactory = await ethers.getContractFactory("EncryptedERC20WithErrorsMintable"); +): Promise { + const contractFactory = await ethers.getContractFactory("TestEncryptedERC20WithErrorsMintable"); const contract = await contractFactory .connect(signers[owner as keyof Signers]) .deploy(name, symbol, signers[owner as keyof Signers].address); @@ -24,7 +24,7 @@ export async function checkErrorCode( instances: FhevmInstances, account: string, transferId: bigint, - token: EncryptedERC20WithErrorsMintable, + token: TestEncryptedERC20WithErrorsMintable, tokenAddress: string, ): Promise { const errorCodeHandle = await token.getErrorCodeForTransferId(transferId); diff --git a/test/governance/Comp.fixture.ts b/test/governance/Comp.fixture.ts index ab895c7..ef6d4c7 100644 --- a/test/governance/Comp.fixture.ts +++ b/test/governance/Comp.fixture.ts @@ -1,12 +1,12 @@ import { ethers } from "hardhat"; -import type { Comp } from "../../types"; +import type { TestComp } from "../../types"; import { reencryptEuint64 } from "../reencrypt"; import { Signers } from "../signers"; import { FhevmInstances } from "../types"; -export async function deployCompFixture(signers: Signers): Promise { - const contractFactory = await ethers.getContractFactory("Comp"); +export async function deployCompFixture(signers: Signers): Promise { + const contractFactory = await ethers.getContractFactory("TestComp"); const contract = await contractFactory.connect(signers.alice).deploy(signers.alice.address); await contract.waitForDeployment(); return contract; @@ -18,7 +18,7 @@ export async function transferTokensAndDelegate( transferAmount: bigint, account: string, delegate: string, - comp: Comp, + comp: TestComp, compAddress: string, ): Promise { const input = instances.alice.createEncryptedInput(compAddress, signers.alice.address); @@ -42,7 +42,7 @@ export async function reencryptCurrentVotes( signers: Signers, instances: FhevmInstances, account: string, - comp: Comp, + comp: TestComp, compAddress: string, ): Promise { const voteHandle = await comp.getCurrentVotes(signers[account as keyof Signers].address); @@ -55,7 +55,7 @@ export async function reencryptPriorVotes( instances: FhevmInstances, account: string, blockNumber: number, - comp: Comp, + comp: TestComp, compAddress: string, ): Promise { const voteHandle = await comp.getPriorVotes(signers[account as keyof Signers].address, blockNumber); diff --git a/test/governance/GovernorAlphaZama.fixture.ts b/test/governance/GovernorAlphaZama.fixture.ts index fa9374e..ac27117 100644 --- a/test/governance/GovernorAlphaZama.fixture.ts +++ b/test/governance/GovernorAlphaZama.fixture.ts @@ -1,6 +1,6 @@ import { ethers } from "hardhat"; -import type { CompoundTimelock, GovernorAlphaZama } from "../../types"; +import type { CompoundTimelock, TestGovernorAlphaZama } from "../../types"; import { reencryptEbool, reencryptEuint64 } from "../reencrypt"; import { Signers, getSigners } from "../signers"; import { FhevmInstances } from "../types"; @@ -17,11 +17,11 @@ export async function deployGovernorAlphaZamaFixture( signers: Signers, compAddress: string, timelockAddress: string, -): Promise { +): Promise { // @dev We use 5 only for testing purpose. // DO NOT use this value in production. const votingPeriod = 5; - const governorFactory = await ethers.getContractFactory("GovernorAlphaZama"); + const governorFactory = await ethers.getContractFactory("TestGovernorAlphaZama"); const governor = await governorFactory .connect(signers.alice) .deploy(signers.alice.address, timelockAddress, compAddress, votingPeriod); @@ -34,7 +34,7 @@ export async function reencryptVoteReceipt( instances: FhevmInstances, proposalId: bigint, account: string, - governor: GovernorAlphaZama, + governor: TestGovernorAlphaZama, governorAddress: string, ): Promise<[boolean, boolean, bigint]> { const [hasVoted, supportHandle, voteHandle] = await governor.getReceipt( From 36a79eb4834ba682cf1922ba3096bd10c338e372 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 7 Nov 2024 15:50:33 +0100 Subject: [PATCH 63/73] test: EncryptedERC20 onlyOwner --- test/encryptedERC20/EncryptedERC20.test.ts | 7 +++++++ test/encryptedERC20/EncryptedERC20WithErrors.test.ts | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/test/encryptedERC20/EncryptedERC20.test.ts b/test/encryptedERC20/EncryptedERC20.test.ts index 1665f9d..89fd400 100644 --- a/test/encryptedERC20/EncryptedERC20.test.ts +++ b/test/encryptedERC20/EncryptedERC20.test.ts @@ -388,4 +388,11 @@ describe("EncryptedERC20", function () { this.encryptedERC20.connect(this.signers.bob).approve(this.signers.carol.address, allowanceHandleAlice), ).to.be.revertedWithCustomError(this.encryptedERC20, "TFHESenderNotAllowed"); }); + + it("EncryptedERC20Mintable - only owner can mint", async function () { + await expect(this.encryptedERC20.connect(this.signers.bob).mint(1)).to.be.revertedWithCustomError( + this.encryptedERC20, + "OwnableUnauthorizedAccount", + ); + }); }); diff --git a/test/encryptedERC20/EncryptedERC20WithErrors.test.ts b/test/encryptedERC20/EncryptedERC20WithErrors.test.ts index 9b10e09..f604129 100644 --- a/test/encryptedERC20/EncryptedERC20WithErrors.test.ts +++ b/test/encryptedERC20/EncryptedERC20WithErrors.test.ts @@ -502,4 +502,11 @@ describe("EncryptedERC20WithErrors", function () { this.encryptedERC20.connect(this.signers.bob).approve(this.signers.carol.address, allowanceHandleAlice), ).to.be.revertedWithCustomError(this.encryptedERC20, "TFHESenderNotAllowed"); }); + + it("EncryptedERC20WithErrorsMintable - only owner can mint", async function () { + await expect(this.encryptedERC20.connect(this.signers.bob).mint(1)).to.be.revertedWithCustomError( + this.encryptedERC20, + "OwnableUnauthorizedAccount", + ); + }); }); From e63271eabfc918c2274787c5ea4c5c71c9f19513 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:08:35 +0100 Subject: [PATCH 64/73] chore: NPM release config --- .npmignore | 2 -- package.json | 11 +++++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.npmignore b/.npmignore index d341f51..581c0be 100644 --- a/.npmignore +++ b/.npmignore @@ -1,6 +1,4 @@ * -!contracts/** -contracts/mocks/** !package.json !README.md !LICENSE diff --git a/package.json b/package.json index ea68d3e..076d82b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "fhevm-contracts", - "description": "fhEVM contracts", + "name": "@zama-ai/fhevm-contracts", + "description": "fhEVM contracts is a Solidity library for secure smart-contract development using fhEVM and TFHE.", "version": "0.1.0", "author": { "name": "zama-ai", @@ -52,7 +52,9 @@ "typescript": "^5.4.2" }, "files": [ - "contracts" + "contracts/governance/", + "contracts/token/", + "contracts/utils/" ], "keywords": [ "blockchain", @@ -63,7 +65,8 @@ "solidity", "template", "typescript", - "typechain" + "typechain", + "tfhe" ], "publishConfig": { "access": "public" From 0f5ca08f29acc3914404d3ac4911b2d0d112069a Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:15:50 +0100 Subject: [PATCH 65/73] refactor: Make contracts that require TFHE/Gateway to be set abstract --- contracts/governance/Comp.sol | 2 +- contracts/governance/GovernorAlphaZama.sol | 2 +- contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol | 2 +- .../token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/governance/Comp.sol b/contracts/governance/Comp.sol index 7d1affb..824adba 100644 --- a/contracts/governance/Comp.sol +++ b/contracts/governance/Comp.sol @@ -17,7 +17,7 @@ import { IComp } from "./IComp.sol"; * with an account's balance. * @dev The delegation of votes leaks information about the account's encrypted balance to the `delegatee`. */ -contract Comp is IComp, EncryptedERC20, Ownable2Step { +abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { /// @notice Returned if the `blockNumber` is higher or equal to the (current) `block.number`. /// @dev It is returned for requests to access votes. error BlockNumberEqualOrHigherThanCurrentBlock(); diff --git a/contracts/governance/GovernorAlphaZama.sol b/contracts/governance/GovernorAlphaZama.sol index 47d73c7..52fe05d 100644 --- a/contracts/governance/GovernorAlphaZama.sol +++ b/contracts/governance/GovernorAlphaZama.sol @@ -19,7 +19,7 @@ import { ICompoundTimelock } from "./ICompoundTimelock.sol"; * - Quorum: A minimum number of votes (quorum) must be reached for the proposal to pass. * - Execution: Once a proposal passes, it is executed and takes effect on the protocol. */ -contract GovernorAlphaZama is Ownable2Step, GatewayCaller { +abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /// @notice Returned if proposal contains too many changes. error LengthAboveMaxOperations(); diff --git a/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol b/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol index c9f1208..20bcad0 100644 --- a/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol +++ b/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol @@ -11,7 +11,7 @@ import { EncryptedERC20 } from "../EncryptedERC20.sol"; * @notice This contract inherits EncryptedERC20. * @dev It allows an owner to mint tokens. Mint amounts are public. */ -contract EncryptedERC20Mintable is Ownable2Step, EncryptedERC20 { +abstract contract EncryptedERC20Mintable is Ownable2Step, EncryptedERC20 { /** * @notice Emitted when `amount` tokens are minted to one account (`to`). */ diff --git a/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol b/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol index 0317b54..5923092 100644 --- a/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol +++ b/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol @@ -11,7 +11,7 @@ import { EncryptedERC20WithErrors } from "./EncryptedERC20WithErrors.sol"; * @notice This contract inherits EncryptedERC20WithErrors. * @dev It allows an owner to mint tokens. Mint amounts are public. */ -contract EncryptedERC20WithErrorsMintable is Ownable2Step, EncryptedERC20WithErrors { +abstract contract EncryptedERC20WithErrorsMintable is Ownable2Step, EncryptedERC20WithErrors { /** * @notice Emitted when `amount` tokens are minted to one account (`to`). */ From 333510262936eaaf93d3ff4af1e20f86de48e93e Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 7 Nov 2024 17:35:41 +0100 Subject: [PATCH 66/73] docs: Comp NatSpec --- contracts/governance/Comp.sol | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/contracts/governance/Comp.sol b/contracts/governance/Comp.sol index 824adba..d4042d5 100644 --- a/contracts/governance/Comp.sol +++ b/contracts/governance/Comp.sol @@ -19,7 +19,7 @@ import { IComp } from "./IComp.sol"; */ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { /// @notice Returned if the `blockNumber` is higher or equal to the (current) `block.number`. - /// @dev It is returned for requests to access votes. + /// @dev It is returned in requests to access votes. error BlockNumberEqualOrHigherThanCurrentBlock(); /// @notice Returned if the `msg.sender` is not the `governor` contract. @@ -186,20 +186,25 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { uint32 nCheckpoints = numCheckpoints[account]; if (nCheckpoints == 0) { - return _EUINT64_ZERO; + /// If there is no checkpoint for the `account`, return encrypted zero. + /// @dev It will not be possible to reencrypt it by the `account`. + votes = _EUINT64_ZERO; } else if (_checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) { - // First check most recent balance + /// First, check the most recent balance. votes = _checkpoints[account][nCheckpoints - 1].votes; } else if (_checkpoints[account][0].fromBlock > blockNumber) { - // Next check implicit zero balance - return _EUINT64_ZERO; + /// Then, check if there is zero balance. + /// @dev It will not be possible to reencrypt it by the `account`. + votes = _EUINT64_ZERO; } else { - // Search for the voting power at the block number + /// Else, search for the voting power at the `blockNumber`. uint32 lower = 0; uint32 upper = nCheckpoints - 1; while (upper > lower) { - uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow + // Ceil to avoid overflow. + uint32 center = upper - (upper - lower) / 2; Checkpoint memory cp = _checkpoints[account][center]; + if (cp.fromBlock == blockNumber) { return cp.votes; } else if (cp.fromBlock < blockNumber) { From 47579fae5a97395af97eef008cf3ab871c91e97a Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 7 Nov 2024 17:36:16 +0100 Subject: [PATCH 67/73] test: Comp.sol --- test/governance/Comp.test.ts | 81 +++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/test/governance/Comp.test.ts b/test/governance/Comp.test.ts index ee169fa..05178bf 100644 --- a/test/governance/Comp.test.ts +++ b/test/governance/Comp.test.ts @@ -2,9 +2,9 @@ import { expect } from "chai"; import { parseUnits } from "ethers"; import { ethers, network } from "hardhat"; -import type { Comp } from "../../types"; import { reencryptBalance } from "../encryptedERC20/EncryptedERC20.fixture"; import { createInstances } from "../instance"; +import { reencryptEuint64 } from "../reencrypt"; import { getSigners, initSigners } from "../signers"; import { waitNBlocks } from "../utils"; import { deployCompFixture, reencryptCurrentVotes, reencryptPriorVotes } from "./Comp.fixture"; @@ -19,7 +19,7 @@ describe("Comp", function () { beforeEach(async function () { const contract = await deployCompFixture(this.signers); this.compAddress = await contract.getAddress(); - (this.comp as Comp) = contract; + this.comp = contract; this.instances = await createInstances(this.signers); }); @@ -90,6 +90,40 @@ describe("Comp", function () { ).to.equal(await reencryptCurrentVotes(this.signers, this.instances, "bob", this.comp, this.compAddress)); }); + it("cannot delegate votes to self but it gets removed once the tokens are transferred", async function () { + let tx = await this.comp.connect(this.signers.alice).delegate(this.signers.alice.address); + await tx.wait(); + + let latestBlockNumber = await ethers.provider.getBlockNumber(); + await waitNBlocks(1); + + expect( + await reencryptPriorVotes(this.signers, this.instances, "alice", latestBlockNumber, this.comp, this.compAddress), + ).to.equal(parseUnits(String(10_000_000), 6)); + + const transferAmount = parseUnits(String(10_000_000), 6); + const input = this.instances.alice.createEncryptedInput(this.compAddress, this.signers.alice.address); + input.add64(transferAmount); + const encryptedTransferAmount = await input.encrypt(); + + tx = await this.comp + .connect(this.signers.alice) + ["transfer(address,bytes32,bytes)"]( + this.signers.bob.address, + encryptedTransferAmount.handles[0], + encryptedTransferAmount.inputProof, + ); + + await tx.wait(); + + latestBlockNumber = await ethers.provider.getBlockNumber(); + await waitNBlocks(1); + + expect( + await reencryptPriorVotes(this.signers, this.instances, "alice", latestBlockNumber, this.comp, this.compAddress), + ).to.equal(0); + }); + it("cannot delegate votes if nonce is invalid", async function () { const delegatee = this.signers.bob; const nonce = 0; @@ -237,6 +271,49 @@ describe("Comp", function () { .withArgs(this.signers.bob.address); }); + it("getCurrentVote/getPriorVotes without any vote cannot be decrypted", async function () { + // 1. If no checkpoint exists using getCurrentVotes + let currentVoteHandle = await this.comp.connect(this.signers.bob).getCurrentVotes(this.signers.bob.address); + expect(currentVoteHandle).to.be.eq(BigInt(0)); + + await expect( + reencryptEuint64(this.signers, this.instances, "bob", currentVoteHandle, this.comp), + ).to.be.rejectedWith("Handle is not initialized"); + + // 2. If no checkpoint exists using getPriorVotes + let latestBlockNumber = await ethers.provider.getBlockNumber(); + await waitNBlocks(1); + + currentVoteHandle = await this.comp + .connect(this.signers.bob) + .getPriorVotes(this.signers.bob.address, latestBlockNumber); + + // It is an encrypted constant that is not reencryptable by Bob. + expect(currentVoteHandle).not.to.be.eq(BigInt(0)); + + await expect( + reencryptEuint64(this.signers, this.instances, "bob", currentVoteHandle, this.comp), + ).to.be.rejectedWith("Invalid contract address."); + + // 3. If a checkpoint exists using getPriorVotes but block.number < block of first checkpoint + latestBlockNumber = await ethers.provider.getBlockNumber(); + await waitNBlocks(1); + + const tx = await this.comp.connect(this.signers.alice).delegate(this.signers.bob.address); + await tx.wait(); + + currentVoteHandle = await this.comp + .connect(this.signers.bob) + .getPriorVotes(this.signers.bob.address, latestBlockNumber); + + // It is an encrypted constant that is not reencryptable by Bob. + expect(currentVoteHandle).not.to.be.eq(BigInt(0)); + + await expect( + reencryptEuint64(this.signers, this.instances, "bob", currentVoteHandle, this.comp), + ).to.be.rejectedWith("Invalid contract address."); + }); + it("governor address can access votes for any account", async function () { // Bob becomes the governor address. let tx = await this.comp.connect(this.signers.alice).setGovernor(this.signers.bob.address); From af186d7c8fdd04e71262ac591212f976985219a5 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 7 Nov 2024 18:19:02 +0100 Subject: [PATCH 68/73] refactor: External functions set to public --- contracts/governance/Comp.sol | 6 ++--- contracts/governance/GovernorAlphaZama.sol | 28 +++++++++++----------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/contracts/governance/Comp.sol b/contracts/governance/Comp.sol index d4042d5..1f02162 100644 --- a/contracts/governance/Comp.sol +++ b/contracts/governance/Comp.sol @@ -122,7 +122,7 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { /** * @notice See {IComp-getPriorVotesForGovernor}. */ - function getPriorVotesForGovernor(address account, uint256 blockNumber) external returns (euint64 votes) { + function getPriorVotesForGovernor(address account, uint256 blockNumber) public returns (euint64 votes) { if (msg.sender != governor) { revert GovernorInvalid(); } @@ -140,7 +140,7 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { * @param account Account address * @return votes Current (encrypted) votes. */ - function getCurrentVotes(address account) external view returns (euint64 votes) { + function getCurrentVotes(address account) public view returns (euint64 votes) { uint32 nCheckpoints = numCheckpoints[account]; if (nCheckpoints > 0) { votes = _checkpoints[account][nCheckpoints - 1].votes; @@ -154,7 +154,7 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { * @param blockNumber The block number to get the vote balance at. * @return votes Number of votes the account as of the given block. */ - function getPriorVotes(address account, uint256 blockNumber) external view returns (euint64 votes) { + function getPriorVotes(address account, uint256 blockNumber) public view returns (euint64 votes) { if (blockNumber >= block.number) { revert BlockNumberEqualOrHigherThanCurrentBlock(); } diff --git a/contracts/governance/GovernorAlphaZama.sol b/contracts/governance/GovernorAlphaZama.sol index 52fe05d..7dd7608 100644 --- a/contracts/governance/GovernorAlphaZama.sol +++ b/contracts/governance/GovernorAlphaZama.sol @@ -264,7 +264,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * In the original GovernorAlpha, the proposer can cancel only if * her votes are still above the threshold. */ - function cancel(uint256 proposalId) external { + function cancel(uint256 proposalId) public { Proposal memory proposal = _proposals[proposalId]; if ( @@ -305,8 +305,8 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param value Encrypted value. * @param inputProof Input proof. */ - function castVote(uint256 proposalId, einput value, bytes calldata inputProof) external { - return _castVote(msg.sender, proposalId, TFHE.asEbool(value, inputProof)); + function castVote(uint256 proposalId, einput value, bytes calldata inputProof) public { + return castVote(proposalId, TFHE.asEbool(value, inputProof)); } /** @@ -314,7 +314,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param proposalId Proposal id. * @param support Support (true ==> votesFor, false ==> votesAgainst) */ - function castVote(uint256 proposalId, ebool support) external { + function castVote(uint256 proposalId, ebool support) public { return _castVote(msg.sender, proposalId, support); } @@ -323,7 +323,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @dev Anyone can execute a proposal once it has been queued and the * delay in the timelock is sufficient. */ - function execute(uint256 proposalId) external payable { + function execute(uint256 proposalId) public payable { Proposal memory proposal = _proposals[proposalId]; if (proposal.state != ProposalState.Queued) { @@ -361,7 +361,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { string[] memory signatures, bytes[] memory calldatas, string memory description - ) external returns (uint256 proposalId) { + ) public returns (uint256 proposalId) { { uint256 length = targets.length; @@ -454,7 +454,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @dev It can be done only if the proposal is adopted. * @param proposalId Proposal id. */ - function queue(uint256 proposalId) external { + function queue(uint256 proposalId) public { Proposal memory proposal = _proposals[proposalId]; if (proposal.state != ProposalState.Succeeded) { @@ -477,7 +477,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @notice Request the vote results to be decrypted. * @param proposalId Proposal id. */ - function requestVoteDecryption(uint256 proposalId) external { + function requestVoteDecryption(uint256 proposalId) public { if (_proposals[proposalId].state != ProposalState.Active) { revert ProposalStateInvalid(); } @@ -547,7 +547,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /** * @dev Only callable by `owner`. */ - function acceptTimelockAdmin() external onlyOwner { + function acceptTimelockAdmin() public onlyOwner { TIMELOCK.acceptAdmin(); } @@ -556,7 +556,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param newPendingAdmin Address of the new pending admin for the timelock. * @param eta Eta for executing the transaction in the timelock. */ - function executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) external onlyOwner { + function executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public onlyOwner { TIMELOCK.executeTransaction(address(TIMELOCK), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta); } @@ -565,7 +565,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param newPendingAdmin Address of the new pending admin for the timelock. * @param eta Eta for queuing the transaction in the timelock. */ - function queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) external onlyOwner { + function queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public onlyOwner { TIMELOCK.queueTransaction(address(TIMELOCK), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta); } @@ -576,7 +576,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param proposalId Proposal id. * @return proposalInfo Proposal information. */ - function getProposalInfo(uint256 proposalId) external view returns (ProposalInfo memory proposalInfo) { + function getProposalInfo(uint256 proposalId) public view returns (ProposalInfo memory proposalInfo) { Proposal memory proposal = _proposals[proposalId]; proposalInfo.proposer = proposal.proposer; proposalInfo.state = proposal.state; @@ -607,7 +607,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @return support The support for the account (true ==> vote for, false ==> vote against). * @return votes The number of votes cast. */ - function getReceipt(uint256 proposalId, address account) external view returns (bool, ebool, euint64) { + function getReceipt(uint256 proposalId, address account) public view returns (bool, ebool, euint64) { Receipt memory receipt = _accountReceiptForProposalId[proposalId][account]; return (receipt.hasVoted, receipt.support, receipt.votes); } @@ -626,7 +626,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { TIMELOCK.queueTransaction(target, value, signature, data, eta); } - function _castVote(address voter, uint256 proposalId, ebool support) internal { + function _castVote(address voter, uint256 proposalId, ebool support) private { Proposal storage proposal = _proposals[proposalId]; if (proposal.state != ProposalState.Active) { From 3bcb0d6ecd480202f2b5e0ccb0b30b999be6460f Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Thu, 7 Nov 2024 18:32:40 +0100 Subject: [PATCH 69/73] docs: NatSpec --- contracts/governance/Comp.sol | 10 +++++----- contracts/governance/GovernorAlphaZama.sol | 9 +++++---- contracts/token/ERC20/EncryptedERC20.sol | 8 ++++---- .../ERC20/extensions/EncryptedERC20WithErrors.sol | 8 ++++---- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/contracts/governance/Comp.sol b/contracts/governance/Comp.sol index 1f02162..66ee0af 100644 --- a/contracts/governance/Comp.sol +++ b/contracts/governance/Comp.sol @@ -80,10 +80,10 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { * @param owner Owner address */ constructor(address owner) EncryptedERC20("Compound", "COMP") Ownable(owner) { - _unsafeMint(owner, TFHE.asEuint64(10000000e6)); // 10 million Comp + _unsafeMint(owner, TFHE.asEuint64(10000000e6)); /// 10 million Comp _totalSupply = 10000000e6; - // @dev Define the constant in the storage. + /// @dev Define the constant in the storage. _EUINT64_ZERO = TFHE.asEuint64(0); TFHE.allowThis(_EUINT64_ZERO); } @@ -201,7 +201,7 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { uint32 lower = 0; uint32 upper = nCheckpoints - 1; while (upper > lower) { - // Ceil to avoid overflow. + /// Ceil to avoid overflow. uint32 center = upper - (upper - lower) / 2; Checkpoint memory cp = _checkpoints[account][center]; @@ -222,14 +222,14 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { if (srcRep != address(0)) { uint32 srcRepNum = numCheckpoints[srcRep]; euint64 srcRepOld = srcRepNum > 0 ? _checkpoints[srcRep][srcRepNum - 1].votes : _EUINT64_ZERO; - euint64 srcRepNew = TFHE.sub(srcRepOld, amount); // srcRepOld - amount; + euint64 srcRepNew = TFHE.sub(srcRepOld, amount); /// srcRepOld - amount; _writeCheckpoint(srcRep, srcRepNum, srcRepNew); } if (dstRep != address(0)) { uint32 dstRepNum = numCheckpoints[dstRep]; euint64 dstRepOld = dstRepNum > 0 ? _checkpoints[dstRep][dstRepNum - 1].votes : _EUINT64_ZERO; - euint64 dstRepNew = TFHE.add(dstRepOld, amount); // dstRepOld + amount; + euint64 dstRepNew = TFHE.add(dstRepOld, amount); /// dstRepOld + amount; _writeCheckpoint(dstRep, dstRepNum, dstRepNew); } } diff --git a/contracts/governance/GovernorAlphaZama.sol b/contracts/governance/GovernorAlphaZama.sol index 7dd7608..f2adf6a 100644 --- a/contracts/governance/GovernorAlphaZama.sol +++ b/contracts/governance/GovernorAlphaZama.sol @@ -249,7 +249,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { COMP = IComp(comp_); VOTING_PERIOD = votingPeriod_; - // @dev Store these constant-like variables in the storage. + /// @dev Store these constant-like variables in the storage. _EUINT64_ZERO = TFHE.asEuint64(0); _EUINT64_PROPOSAL_THRESHOLD = TFHE.asEuint64(PROPOSAL_THRESHOLD); @@ -330,7 +330,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { revert ProposalStateInvalid(); } - // proposal.executed = true; + /// proposal.executed = true; for (uint256 i = 0; i < proposal.targets.length; i++) { TIMELOCK.executeTransaction{ value: proposal.values[i] }( proposal.targets[i], @@ -590,7 +590,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { proposalInfo.forVotes = proposal.forVotesDecrypted; proposalInfo.againstVotes = proposal.againstVotesDecrypted; - // The state is adjusted but not closed. + /// The state is adjusted but not closed. if ( (proposalInfo.state == ProposalState.Queued) && (block.timestamp > proposalInfo.eta + TIMELOCK.GRACE_PERIOD()) @@ -658,7 +658,8 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { TFHE.allow(receipt.support, msg.sender); TFHE.allow(receipt.votes, msg.sender); - // `support` and `votes` are encrypted values, no need to include them in the event. + /// @dev `support` and `votes` are encrypted values. + /// There is no need to include them in the event. emit VoteCast(voter, proposalId); } } diff --git a/contracts/token/ERC20/EncryptedERC20.sol b/contracts/token/ERC20/EncryptedERC20.sol index a77eec3..cf6689b 100644 --- a/contracts/token/ERC20/EncryptedERC20.sol +++ b/contracts/token/ERC20/EncryptedERC20.sol @@ -75,7 +75,7 @@ abstract contract EncryptedERC20 is IEncryptedERC20 { function transfer(address to, euint64 amount) public virtual returns (bool) { _isSenderAllowedForAmount(amount); - // Make sure the owner has enough tokens + /// Make sure the owner has enough tokens. ebool canTransfer = TFHE.le(amount, _balances[msg.sender]); _transfer(msg.sender, to, amount, canTransfer); return true; @@ -179,7 +179,7 @@ abstract contract EncryptedERC20 is IEncryptedERC20 { revert ReceiverAddressNull(); } - // Add to the balance of `to` and subract from the balance of `from`. + /// Add to the balance of `to` and subract from the balance of `from`. euint64 transferValue = TFHE.select(isTransferable, amount, TFHE.asEuint64(0)); euint64 newBalanceTo = TFHE.add(_balances[to], transferValue); _balances[to] = newBalanceTo; @@ -193,9 +193,9 @@ abstract contract EncryptedERC20 is IEncryptedERC20 { function _updateAllowance(address owner, address spender, euint64 amount) internal virtual returns (ebool) { euint64 currentAllowance = _allowance(owner, spender); - // Make sure sure the allowance suffices + /// Make sure sure the allowance suffices. ebool allowedTransfer = TFHE.le(amount, currentAllowance); - // Make sure the owner has enough tokens + /// Make sure the owner has enough tokens. ebool canTransfer = TFHE.le(amount, _balances[owner]); ebool isTransferable = TFHE.and(canTransfer, allowedTransfer); _approve(owner, spender, TFHE.select(isTransferable, TFHE.sub(currentAllowance, amount), currentAllowance)); diff --git a/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol b/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol index 376fb37..53691a7 100644 --- a/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol +++ b/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol @@ -57,7 +57,7 @@ abstract contract EncryptedERC20WithErrors is EncryptedERC20, EncryptedErrors { function transfer(address to, euint64 amount) public virtual override returns (bool) { _isSenderAllowedForAmount(amount); - // Make sure the owner has enough tokens + /// Check whether the owner has enough tokens. ebool canTransfer = TFHE.le(amount, _balances[msg.sender]); euint8 errorCode = TFHE.select( @@ -98,7 +98,7 @@ abstract contract EncryptedERC20WithErrors is EncryptedERC20, EncryptedErrors { _transferNoEvent(from, to, amount, isTransferable); emit TransferWithErrorHandling(from, to, _transferIdCounter); - // Set error code in the storage and increment + /// Set the error code in the storage and increment. _errorCodeForTransferId[_transferIdCounter++] = errorCode; TFHE.allowThis(errorCode); @@ -113,7 +113,7 @@ abstract contract EncryptedERC20WithErrors is EncryptedERC20, EncryptedErrors { ) internal virtual returns (ebool isTransferable, euint8 errorCode) { euint64 currentAllowance = _allowance(owner, spender); - // Make sure sure the allowance suffices + /// Make sure sure the allowance suffices. ebool allowedTransfer = TFHE.le(amount, currentAllowance); errorCode = TFHE.select( @@ -122,7 +122,7 @@ abstract contract EncryptedERC20WithErrors is EncryptedERC20, EncryptedErrors { _errorCodes[uint8(ErrorCodes.NO_ERROR)] ); - // Make sure the owner has enough tokens + /// Make sure the owner has enough tokens. ebool canTransfer = TFHE.le(amount, _balances[owner]); errorCode = TFHE.select( From 722411aa9d2dd531e06f81d8998e33b8bbcf914b Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:22:12 +0100 Subject: [PATCH 70/73] fix: GovernorAlphaZama --- contracts/governance/GovernorAlphaZama.sol | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/contracts/governance/GovernorAlphaZama.sol b/contracts/governance/GovernorAlphaZama.sol index f2adf6a..abd16bb 100644 --- a/contracts/governance/GovernorAlphaZama.sol +++ b/contracts/governance/GovernorAlphaZama.sol @@ -268,10 +268,10 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { Proposal memory proposal = _proposals[proposalId]; if ( - proposal.state == ProposalState.Pending || - proposal.state == ProposalState.Executed || + proposal.state == ProposalState.Rejected || proposal.state == ProposalState.Canceled || - proposal.state == ProposalState.Defeated + proposal.state == ProposalState.Defeated || + proposal.state == ProposalState.Executed ) { revert ProposalStateInvalid(); } @@ -330,7 +330,6 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { revert ProposalStateInvalid(); } - /// proposal.executed = true; for (uint256 i = 0; i < proposal.targets.length; i++) { TIMELOCK.executeTransaction{ value: proposal.values[i] }( proposal.targets[i], @@ -384,7 +383,6 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { ProposalState proposerLatestProposalState = _proposals[latestProposalId].state; if ( - proposerLatestProposalState != ProposalState.Queued && proposerLatestProposalState != ProposalState.Rejected && proposerLatestProposalState != ProposalState.Defeated && proposerLatestProposalState != ProposalState.Canceled && From 6325371d275f83a851e6427b0539b8f9bdd049c9 Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:22:36 +0100 Subject: [PATCH 71/73] test: GovernorAlphaZama --- test/governance/Comp.test.ts | 56 +++- test/governance/GovernorAlphaZama.test.ts | 354 +++++++++++++++++++++- 2 files changed, 396 insertions(+), 14 deletions(-) diff --git a/test/governance/Comp.test.ts b/test/governance/Comp.test.ts index 05178bf..9f046a0 100644 --- a/test/governance/Comp.test.ts +++ b/test/governance/Comp.test.ts @@ -265,7 +265,6 @@ describe("Comp", function () { it("only owner can set governor contract", async function () { const newAllowedContract = "0x9d3e06a2952dc49EDCc73e41C76645797fC53967"; - await expect(this.comp.connect(this.signers.bob).setGovernor(newAllowedContract)) .to.be.revertedWithCustomError(this.comp, "OwnableUnauthorizedAccount") .withArgs(this.signers.bob.address); @@ -314,6 +313,58 @@ describe("Comp", function () { ).to.be.rejectedWith("Invalid contract address."); }); + it("can do multiple checkpoints and access the values when needed", async function () { + let i = 0; + + const blockNumbers = []; + + while (i < 20) { + let tx = await this.comp.connect(this.signers.alice).delegate(this.signers.alice.address); + await tx.wait(); + blockNumbers.push(await ethers.provider.getBlockNumber()); + + tx = await this.comp.connect(this.signers.alice).delegate(this.signers.carol.address); + await tx.wait(); + blockNumbers.push(await ethers.provider.getBlockNumber()); + i++; + } + + waitNBlocks(1); + + // There are 40 checkpoints for Alice and 39 checkpoints for Carol + expect(await this.comp.numCheckpoints(this.signers.alice.address)).to.eq(BigInt(40)); + expect(await this.comp.numCheckpoints(this.signers.carol.address)).to.eq(BigInt(39)); + + i = 0; + + while (i < 40) { + if (blockNumbers[i] % 2 === 0) { + expect( + await reencryptPriorVotes( + this.signers, + this.instances, + "alice", + blockNumbers[i], + this.comp, + this.compAddress, + ), + ).to.be.eq(parseUnits(String(10_000_000), 6)); + } else { + expect( + await reencryptPriorVotes( + this.signers, + this.instances, + "carol", + blockNumbers[i], + this.comp, + this.compAddress, + ), + ).to.be.eq(parseUnits(String(10_000_000), 6)); + } + i++; + } + }); + it("governor address can access votes for any account", async function () { // Bob becomes the governor address. let tx = await this.comp.connect(this.signers.alice).setGovernor(this.signers.bob.address); @@ -329,7 +380,7 @@ describe("Comp", function () { // Bob, the governor address, gets the prior votes of Carol. // @dev It is not possible to catch the return value since it is not a view function. - // GovernorAlpha.test.ts contains tests that use this function. + // GovernorAlphaZama.test.ts contains tests that use this function. await this.comp .connect(this.signers.bob) .getPriorVotesForGovernor(this.signers.carol.address, latestBlockNumber + 1); @@ -379,6 +430,7 @@ describe("Comp", function () { await network.provider.send("evm_mine"); await network.provider.send("evm_setAutomine", [true]); + await Promise.all([tx1, tx2]); expect(await this.comp.numCheckpoints(this.signers.alice.address)).to.be.equal(0n); expect(await this.comp.numCheckpoints(this.signers.bob.address)).to.be.equal(1n); diff --git a/test/governance/GovernorAlphaZama.test.ts b/test/governance/GovernorAlphaZama.test.ts index 25ad948..ba41492 100644 --- a/test/governance/GovernorAlphaZama.test.ts +++ b/test/governance/GovernorAlphaZama.test.ts @@ -242,7 +242,7 @@ describe("GovernorAlphaZama", function () { expect(proposalInfo.state).to.equal(10); }); - it("the vote is defeated if forVotes < quorum", async function () { + it("vote is defeated if forVotes < quorum", async function () { const targets = [this.signers.bob.address]; const values = ["0"]; const signatures = ["getBalanceOf(address)"]; @@ -314,14 +314,14 @@ describe("GovernorAlphaZama", function () { expect(proposalInfo.state).to.equal(6); }); - it("the vote is rejected if forVotes < againstVotes", async function () { + it("vote is rejected if forVotes < againstVotes", async function () { const targets = [this.signers.bob.address]; const values = ["0"]; const signatures = ["getBalanceOf(address)"]; const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; const description = "description"; - const transferAmountFor = parseUnits(String(200_000), 6); - const transferAmountAgainst = parseUnits(String(200_000), 6) + BigInt(1); + const transferAmountFor = parseUnits(String(500_000), 6); + const transferAmountAgainst = parseUnits(String(500_000), 6) + BigInt(1); // Bob and Carol receive 200k tokens and delegate to themselves. await transferTokensAndDelegate( @@ -428,12 +428,6 @@ describe("GovernorAlphaZama", function () { await expect( timelockFactory.connect(this.signers.alice).deploy(this.signers.alice.address, 60 * 60 * 24 * 31), ).to.be.revertedWith("Timelock::setDelay: Delay must not exceed maximum delay."); // 31 days > 30 days - } else { - // fhevm-mode - await expect(timelockFactory.connect(this.signers.alice).deploy(this.signers.alice.address, 60 * 60 * 24 * 1)).to - .throw; - await expect(timelockFactory.connect(this.signers.alice).deploy(this.signers.alice.address, 60 * 60 * 24 * 31)).to - .throw; } }); @@ -626,7 +620,7 @@ describe("GovernorAlphaZama", function () { const signatures = ["getBalanceOf(address)"]; const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; const description = "description"; - const transferAmount = parseUnits(String(400_000), 6); + const transferAmount = await this.governor.QUORUM_VOTES(); // Bob receives 400k tokens and delegates to himself. await transferTokensAndDelegate( @@ -681,13 +675,349 @@ describe("GovernorAlphaZama", function () { await expect(this.governor.queue(proposalId)).to.be.revertedWithCustomError(this.governor, "ProposalStateInvalid"); }); + it("cannot cancel if state is Rejected/Defeated/Executed/Canceled", async function () { + let transferAmount = (await this.governor.PROPOSAL_THRESHOLD()) - BigInt(1); + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + + // CANNOT CANCEL IF REJECTED + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + let tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + await awaitAllDecryptionResults(); + + let proposalId = await this.governor.latestProposalIds(this.signers.bob.address); + + await expect(this.governor.connect(this.signers.bob).cancel(proposalId)).to.be.revertedWithCustomError( + this.governor, + "ProposalStateInvalid", + ); + + // CANNOT CANCEL IF DEFEATED + transferAmount = (await this.governor.QUORUM_VOTES()) - BigInt(1); + + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "carol", + "carol", + this.comp, + this.compAddress, + ); + + tx = await this.governor.connect(this.signers.carol).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + await awaitAllDecryptionResults(); + + proposalId = await this.governor.latestProposalIds(this.signers.carol.address); + + let input = this.instances.carol.createEncryptedInput(this.governorAddress, this.signers.carol.address); + input.addBool(true); + let encryptedVote = await input.encrypt(); + tx = await this.governor + .connect(this.signers.carol) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof); + await tx.wait(); + + // Mine blocks + await mineNBlocks(4); + + // REQUEST DECRYPTION + tx = await this.governor.requestVoteDecryption(proposalId); + await tx.wait(); + await awaitAllDecryptionResults(); + await expect(this.governor.connect(this.signers.carol).cancel(proposalId)).to.be.revertedWithCustomError( + this.governor, + "ProposalStateInvalid", + ); + + // CANNOT CANCEL IF EXECUTED + transferAmount = await this.governor.QUORUM_VOTES(); + + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "dave", + "dave", + this.comp, + this.compAddress, + ); + + tx = await this.governor.connect(this.signers.dave).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + await awaitAllDecryptionResults(); + + proposalId = await this.governor.latestProposalIds(this.signers.dave.address); + + input = this.instances.dave.createEncryptedInput(this.governorAddress, this.signers.dave.address); + input.addBool(true); + encryptedVote = await input.encrypt(); + tx = await this.governor + .connect(this.signers.dave) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof); + await tx.wait(); + + // Mine blocks + await mineNBlocks(4); + + // REQUEST DECRYPTION + tx = await this.governor.requestVoteDecryption(proposalId); + await tx.wait(); + await awaitAllDecryptionResults(); + + tx = await this.governor.queue(proposalId); + await tx.wait(); + + const eta = (await this.governor.getProposalInfo(proposalId)).eta; + + // EXECUTE + await ethers.provider.send("evm_setNextBlockTimestamp", [eta.toString()]); + tx = await this.governor.execute(proposalId); + await tx.wait(); + + await expect(this.governor.connect(this.signers.dave).cancel(proposalId)).to.be.revertedWithCustomError( + this.governor, + "ProposalStateInvalid", + ); + + // CANNOT CANCEL TWICE + tx = await this.governor.connect(this.signers.carol).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + + proposalId = await this.governor.latestProposalIds(this.signers.carol.address); + + tx = await this.governor.connect(this.signers.carol).cancel(proposalId); + await tx.wait(); + await expect(this.governor.connect(this.signers.carol).cancel(proposalId)).to.be.revertedWithCustomError( + this.governor, + "ProposalStateInvalid", + ); + }); + + it("cancel function clears the timelock if the proposal is queued", async function () { + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + const transferAmount = await this.governor.QUORUM_VOTES(); + + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + // INITIATE A PROPOSAL + let tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + + // DECRYPTION FOR THE TOKEN THRESHOLD + await awaitAllDecryptionResults(); + const proposalId = await this.governor.latestProposalIds(this.signers.bob.address); + + // VOTE + // Bob votes for + let input = this.instances.bob.createEncryptedInput(this.governorAddress, this.signers.bob.address); + input.addBool(true); + let encryptedVote = await input.encrypt(); + tx = await this.governor + .connect(this.signers.bob) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof); + await tx.wait(); + + // Mine blocks + await mineNBlocks(4); + + // REQUEST DECRYPTION + tx = await this.governor.requestVoteDecryption(proposalId); + await tx.wait(); + + // POST-DECRYPTION RESULTS + await awaitAllDecryptionResults(); + + // QUEUING + tx = await this.governor.queue(proposalId); + await tx.wait(); + + // @dev Alice is the governor's owner. + tx = await this.governor.connect(this.signers.alice).cancel(proposalId); + await tx.wait(); + + // 5 ==> Canceled + expect((await this.governor.getProposalInfo(proposalId)).state).to.equal(5); + }); + + it("cannot request vote decryption if state is not Active or if endBlock >= block.number", async function () { + await expect(this.governor.connect(this.signers.dave).requestVoteDecryption(0)).to.be.revertedWithCustomError( + this.governor, + "ProposalStateInvalid", + ); + + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + const transferAmount = await this.governor.QUORUM_VOTES(); + + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + // INITIATE A PROPOSAL + let tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + + // DECRYPTION FOR THE TOKEN THRESHOLD + await awaitAllDecryptionResults(); + const proposalId = await this.governor.latestProposalIds(this.signers.bob.address); + + // VOTE + // Bob votes for + let input = this.instances.bob.createEncryptedInput(this.governorAddress, this.signers.bob.address); + input.addBool(true); + let encryptedVote = await input.encrypt(); + tx = await this.governor + .connect(this.signers.bob) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof); + await tx.wait(); + + // Mine blocks but not enough + await mineNBlocks(3); + + await expect( + this.governor.connect(this.signers.dave).requestVoteDecryption(proposalId), + ).to.be.revertedWithCustomError(this.governor, "ProposalStateStillActive"); + }); + + it("cannot cast a vote if state is not Active or if endBlock > block.number", async function () { + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + const transferAmount = await this.governor.QUORUM_VOTES(); + + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + let tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + const proposalId = await this.governor.latestProposalIds(this.signers.bob.address); + + let input = this.instances.bob.createEncryptedInput(this.governorAddress, this.signers.bob.address); + input.addBool(true); + let encryptedVote = await input.encrypt(); + + await expect( + this.governor + .connect(this.signers.bob) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof), + ).to.be.revertedWithCustomError(this.governor, "ProposalStateInvalid"); + + tx = await this.governor.connect(this.signers.bob).cancel(proposalId); + await tx.wait(); + + tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + await awaitAllDecryptionResults(); + + const newProposalId = await this.governor.latestProposalIds(this.signers.bob.address); + // 3 --> Active + expect((await this.governor.getProposalInfo(newProposalId)).state).to.equal(3); + + // Mine too many blocks so that it becomes too late to cast vote + await mineNBlocks(5); + + await expect( + this.governor + .connect(this.signers.bob) + ["castVote(uint256,bytes32,bytes)"](newProposalId, encryptedVote.handles[0], encryptedVote.inputProof), + ).to.be.revertedWithCustomError(this.governor, "ProposalStateNotActive"); + }); + + it("cannot cast a vote twice", async function () { + const targets = [this.signers.bob.address]; + const values = ["0"]; + const signatures = ["getBalanceOf(address)"]; + const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; + const description = "description"; + const transferAmount = await this.governor.QUORUM_VOTES(); + + // Bob receives 400k tokens and delegates to himself. + await transferTokensAndDelegate( + this.signers, + this.instances, + transferAmount, + "bob", + "bob", + this.comp, + this.compAddress, + ); + + // INITIATE A PROPOSAL + let tx = await this.governor.connect(this.signers.bob).propose(targets, values, signatures, calldatas, description); + await tx.wait(); + + // DECRYPTION FOR THE TOKEN THRESHOLD + await awaitAllDecryptionResults(); + const proposalId = await this.governor.latestProposalIds(this.signers.bob.address); + + // VOTE + // Bob casts a vote + let input = this.instances.bob.createEncryptedInput(this.governorAddress, this.signers.bob.address); + input.addBool(true); + let encryptedVote = await input.encrypt(); + tx = await this.governor + .connect(this.signers.bob) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof); + await tx.wait(); + + await expect( + this.governor + .connect(this.signers.bob) + ["castVote(uint256,bytes32,bytes)"](proposalId, encryptedVote.handles[0], encryptedVote.inputProof), + ).to.be.revertedWithCustomError(this.governor, "VoterHasAlreadyVoted"); + }); + it("proposal expires after grace period", async function () { const targets = [this.signers.bob.address]; const values = ["0"]; const signatures = ["getBalanceOf(address)"]; const calldatas = [ethers.AbiCoder.defaultAbiCoder().encode(["address"], [this.signers.bob.address])]; const description = "description"; - const transferAmount = parseUnits(String(400_000), 6); + const transferAmount = await this.governor.QUORUM_VOTES(); // Bob receives 400k tokens and delegates to himself. await transferTokensAndDelegate( From 69c363620beef7d2ceba77346db55ee5a7eaf6ab Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:21:54 +0100 Subject: [PATCH 72/73] refactor: Virtual functions --- contracts/governance/Comp.sol | 27 +++++--- contracts/governance/GovernorAlphaZama.sol | 62 ++++++++++--------- .../extensions/EncryptedERC20Mintable.sol | 2 +- .../extensions/EncryptedERC20WithErrors.sol | 2 +- .../EncryptedERC20WithErrorsMintable.sol | 2 +- 5 files changed, 52 insertions(+), 43 deletions(-) diff --git a/contracts/governance/Comp.sol b/contracts/governance/Comp.sol index 66ee0af..49499f4 100644 --- a/contracts/governance/Comp.sol +++ b/contracts/governance/Comp.sol @@ -92,7 +92,7 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { * @notice Delegate votes from `msg.sender` to `delegatee`. * @param delegatee The address to delegate votes to. */ - function delegate(address delegatee) public { + function delegate(address delegatee) public virtual { return _delegate(msg.sender, delegatee); } @@ -105,7 +105,14 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { * @param r Half of the ECDSA signature pair. * @param s Half of the ECDSA signature pair. */ - function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) public { + function delegateBySig( + address delegatee, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual { bytes32 domainSeparator = keccak256( abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name())), block.chainid, address(this)) ); @@ -122,7 +129,7 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { /** * @notice See {IComp-getPriorVotesForGovernor}. */ - function getPriorVotesForGovernor(address account, uint256 blockNumber) public returns (euint64 votes) { + function getPriorVotesForGovernor(address account, uint256 blockNumber) public virtual returns (euint64 votes) { if (msg.sender != governor) { revert GovernorInvalid(); } @@ -140,7 +147,7 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { * @param account Account address * @return votes Current (encrypted) votes. */ - function getCurrentVotes(address account) public view returns (euint64 votes) { + function getCurrentVotes(address account) public view virtual returns (euint64 votes) { uint32 nCheckpoints = numCheckpoints[account]; if (nCheckpoints > 0) { votes = _checkpoints[account][nCheckpoints - 1].votes; @@ -154,7 +161,7 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { * @param blockNumber The block number to get the vote balance at. * @return votes Number of votes the account as of the given block. */ - function getPriorVotes(address account, uint256 blockNumber) public view returns (euint64 votes) { + function getPriorVotes(address account, uint256 blockNumber) public view virtual returns (euint64 votes) { if (blockNumber >= block.number) { revert BlockNumberEqualOrHigherThanCurrentBlock(); } @@ -166,12 +173,12 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { * @notice Set a governor contract. * @param newGovernor New governor contract that can reencrypt/access votes. */ - function setGovernor(address newGovernor) public onlyOwner { + function setGovernor(address newGovernor) public virtual onlyOwner { governor = newGovernor; emit NewGovernor(newGovernor); } - function _delegate(address delegator, address delegatee) internal { + function _delegate(address delegator, address delegatee) internal virtual { address currentDelegate = delegates[delegator]; euint64 delegatorBalance = _balances[delegator]; TFHE.allowThis(delegatorBalance); @@ -217,7 +224,7 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { } } - function _moveDelegates(address srcRep, address dstRep, euint64 amount) internal { + function _moveDelegates(address srcRep, address dstRep, euint64 amount) internal virtual { if (srcRep != dstRep) { if (srcRep != address(0)) { uint32 srcRepNum = numCheckpoints[srcRep]; @@ -237,12 +244,12 @@ abstract contract Comp is IComp, EncryptedERC20, Ownable2Step { /// @dev Original restrictions to transfer from/to address(0) are removed since they /// are inherited. - function _transfer(address from, address to, euint64 amount, ebool isTransferable) internal override { + function _transfer(address from, address to, euint64 amount, ebool isTransferable) internal virtual override { super._transfer(from, to, amount, isTransferable); _moveDelegates(delegates[from], delegates[to], amount); } - function _writeCheckpoint(address delegatee, uint32 nCheckpoints, euint64 newVotes) internal { + function _writeCheckpoint(address delegatee, uint32 nCheckpoints, euint64 newVotes) internal virtual { if (nCheckpoints > 0 && _checkpoints[delegatee][nCheckpoints - 1].fromBlock == block.number) { _checkpoints[delegatee][nCheckpoints - 1].votes = newVotes; } else { diff --git a/contracts/governance/GovernorAlphaZama.sol b/contracts/governance/GovernorAlphaZama.sol index abd16bb..14c441e 100644 --- a/contracts/governance/GovernorAlphaZama.sol +++ b/contracts/governance/GovernorAlphaZama.sol @@ -264,7 +264,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * In the original GovernorAlpha, the proposer can cancel only if * her votes are still above the threshold. */ - function cancel(uint256 proposalId) public { + function cancel(uint256 proposalId) public virtual { Proposal memory proposal = _proposals[proposalId]; if ( @@ -305,7 +305,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param value Encrypted value. * @param inputProof Input proof. */ - function castVote(uint256 proposalId, einput value, bytes calldata inputProof) public { + function castVote(uint256 proposalId, einput value, bytes calldata inputProof) public virtual { return castVote(proposalId, TFHE.asEbool(value, inputProof)); } @@ -314,7 +314,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param proposalId Proposal id. * @param support Support (true ==> votesFor, false ==> votesAgainst) */ - function castVote(uint256 proposalId, ebool support) public { + function castVote(uint256 proposalId, ebool support) public virtual { return _castVote(msg.sender, proposalId, support); } @@ -323,7 +323,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @dev Anyone can execute a proposal once it has been queued and the * delay in the timelock is sufficient. */ - function execute(uint256 proposalId) public payable { + function execute(uint256 proposalId) public payable virtual { Proposal memory proposal = _proposals[proposalId]; if (proposal.state != ProposalState.Queued) { @@ -360,7 +360,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { string[] memory signatures, bytes[] memory calldatas, string memory description - ) public returns (uint256 proposalId) { + ) public virtual returns (uint256 proposalId) { { uint256 length = targets.length; @@ -449,10 +449,11 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /** * @notice Queue a new proposal. - * @dev It can be done only if the proposal is adopted. + * @dev It can be done only if the proposal has succeeded. + * Anyone can queue a proposal. * @param proposalId Proposal id. */ - function queue(uint256 proposalId) public { + function queue(uint256 proposalId) public virtual { Proposal memory proposal = _proposals[proposalId]; if (proposal.state != ProposalState.Succeeded) { @@ -473,9 +474,10 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /** * @notice Request the vote results to be decrypted. + * @dev Anyone can request the decryption of the vote. * @param proposalId Proposal id. */ - function requestVoteDecryption(uint256 proposalId) public { + function requestVoteDecryption(uint256 proposalId) public virtual { if (_proposals[proposalId].state != ProposalState.Active) { revert ProposalStateInvalid(); } @@ -505,7 +507,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param requestId Request id (from the Gateway) * @param canInitiate Whether the proposal can be initiated. */ - function callbackInitiateProposal(uint256 requestId, bool canInitiate) public onlyGateway { + function callbackInitiateProposal(uint256 requestId, bool canInitiate) public virtual onlyGateway { uint256 proposalId = _requestIdToProposalId[requestId]; if (canInitiate) { @@ -526,7 +528,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { uint256 requestId, uint256 forVotesDecrypted, uint256 againstVotesDecrypted - ) public onlyGateway { + ) public virtual onlyGateway { uint256 proposalId = _requestIdToProposalId[requestId]; /// @dev It is safe to downcast since the original values were euint64. @@ -545,7 +547,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /** * @dev Only callable by `owner`. */ - function acceptTimelockAdmin() public onlyOwner { + function acceptTimelockAdmin() public virtual onlyOwner { TIMELOCK.acceptAdmin(); } @@ -554,7 +556,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param newPendingAdmin Address of the new pending admin for the timelock. * @param eta Eta for executing the transaction in the timelock. */ - function executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public onlyOwner { + function executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public virtual onlyOwner { TIMELOCK.executeTransaction(address(TIMELOCK), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta); } @@ -563,7 +565,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param newPendingAdmin Address of the new pending admin for the timelock. * @param eta Eta for queuing the transaction in the timelock. */ - function queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public onlyOwner { + function queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public virtual onlyOwner { TIMELOCK.queueTransaction(address(TIMELOCK), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta); } @@ -574,7 +576,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @param proposalId Proposal id. * @return proposalInfo Proposal information. */ - function getProposalInfo(uint256 proposalId) public view returns (ProposalInfo memory proposalInfo) { + function getProposalInfo(uint256 proposalId) public view virtual returns (ProposalInfo memory proposalInfo) { Proposal memory proposal = _proposals[proposalId]; proposalInfo.proposer = proposal.proposer; proposalInfo.state = proposal.state; @@ -605,26 +607,12 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { * @return support The support for the account (true ==> vote for, false ==> vote against). * @return votes The number of votes cast. */ - function getReceipt(uint256 proposalId, address account) public view returns (bool, ebool, euint64) { + function getReceipt(uint256 proposalId, address account) public view virtual returns (bool, ebool, euint64) { Receipt memory receipt = _accountReceiptForProposalId[proposalId][account]; return (receipt.hasVoted, receipt.support, receipt.votes); } - function _queueOrRevert( - address target, - uint256 value, - string memory signature, - bytes memory data, - uint256 eta - ) internal { - if (TIMELOCK.queuedTransactions(keccak256(abi.encode(target, value, signature, data, eta)))) { - revert ProposalActionsAlreadyQueued(); - } - - TIMELOCK.queueTransaction(target, value, signature, data, eta); - } - - function _castVote(address voter, uint256 proposalId, ebool support) private { + function _castVote(address voter, uint256 proposalId, ebool support) internal virtual { Proposal storage proposal = _proposals[proposalId]; if (proposal.state != ProposalState.Active) { @@ -660,4 +648,18 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /// There is no need to include them in the event. emit VoteCast(voter, proposalId); } + + function _queueOrRevert( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) internal virtual { + if (TIMELOCK.queuedTransactions(keccak256(abi.encode(target, value, signature, data, eta)))) { + revert ProposalActionsAlreadyQueued(); + } + + TIMELOCK.queueTransaction(target, value, signature, data, eta); + } } diff --git a/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol b/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol index 20bcad0..ec9ee0a 100644 --- a/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol +++ b/contracts/token/ERC20/extensions/EncryptedERC20Mintable.sol @@ -32,7 +32,7 @@ abstract contract EncryptedERC20Mintable is Ownable2Step, EncryptedERC20 { * @notice Mint tokens. * @param amount Amount of tokens to mint. */ - function mint(uint64 amount) public onlyOwner { + function mint(uint64 amount) public virtual onlyOwner { _unsafeMint(msg.sender, TFHE.asEuint64(amount)); /// @dev Since _totalSupply is not encrypted and _totalSupply >= balances[msg.sender], /// the next line contains an overflow check for the encrypted operation above. diff --git a/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol b/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol index 53691a7..ee11059 100644 --- a/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol +++ b/contracts/token/ERC20/extensions/EncryptedERC20WithErrors.sol @@ -84,7 +84,7 @@ abstract contract EncryptedERC20WithErrors is EncryptedERC20, EncryptedErrors { /** * @notice Returns the error code corresponding to `transferId`. */ - function getErrorCodeForTransferId(uint256 transferId) external view virtual returns (euint8 errorCode) { + function getErrorCodeForTransferId(uint256 transferId) public view virtual returns (euint8 errorCode) { return _errorCodeForTransferId[transferId]; } diff --git a/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol b/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol index 5923092..316f381 100644 --- a/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol +++ b/contracts/token/ERC20/extensions/EncryptedERC20WithErrorsMintable.sol @@ -32,7 +32,7 @@ abstract contract EncryptedERC20WithErrorsMintable is Ownable2Step, EncryptedERC * @notice Mint tokens. * @param amount Amount of tokens to mint. */ - function mint(uint64 amount) public onlyOwner { + function mint(uint64 amount) public virtual onlyOwner { _unsafeMint(msg.sender, TFHE.asEuint64(amount)); /// @dev Since _totalSupply is not encrypted and _totalSupply >= balances[msg.sender], /// the next line contains an overflow check for the encrypted operation above. From 31a03c8b91f5f20daa176f31712ac22e8b387bac Mon Sep 17 00:00:00 2001 From: PacificYield <173040337+PacificYield@users.noreply.github.com> Date: Tue, 12 Nov 2024 10:11:22 +0100 Subject: [PATCH 73/73] docs: NatSpec for Enum --- contracts/governance/GovernorAlphaZama.sol | 43 +++++++++++++++------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/contracts/governance/GovernorAlphaZama.sol b/contracts/governance/GovernorAlphaZama.sol index 14c441e..74ec0e5 100644 --- a/contracts/governance/GovernorAlphaZama.sol +++ b/contracts/governance/GovernorAlphaZama.sol @@ -90,19 +90,33 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /// @notice Emitted when a vote has been cast on a proposal. event VoteCast(address voter, uint256 proposalId); - /// @notice Possible states that a proposal may be in. + /** + * @notice Possible states that a proposal may be in. + * @param Pending Proposal does not exist. + * @param PendingThresholdVerification Proposal is created but token threshold verification is pending. + * @param Rejected Proposal was rejected as the proposer did not meet the token threshold. + * @param Active Proposal is active and voters can cast their votes. + * @param PendingResults Proposal is not active and the result decryption is in progress. + * @param Canceled Proposal has been canceled by the proposer or by this contract's owner. + * @param Defeated Proposal has been defeated + * (either not reaching the quorum or `againstVotes` > `forVotes`). + * @param Succeeded Proposal has succeeded (`forVotes` > `againstVotes`). + * @param Queued Proposal has been queued in the `Timelock`. + * @param Expired Proposal has expired (@dev This state exists only in read-only functions). + * @param Executed Proposal has been executed in the `Timelock`. + */ enum ProposalState { - Pending, /// Proposal does not exist. - PendingThresholdVerification, /// Proposal is created but token threshold verification is pending. - Rejected, /// Proposal was rejected because the proposer did not match the token threshold required. - Active, /// Proposal is active and voters can cast their votes. - PendingResults, /// Proposal is active but the decryption of the result is in progress. - Canceled, /// Proposal has been canceled by the proposer. - Defeated, /// Proposal has been defeated (either by not reaching the quorum or `votesAgainst` > `votesFor`). - Succeeded, /// Proposal has succeeded. - Queued, /// Proposal has been queued in the timelock. - Expired, /// Proposal has expired (@dev This state is used for read-only operations). - Executed /// Proposal has been executed. + Pending, + PendingThresholdVerification, + Rejected, + Active, + PendingResults, + Canceled, + Defeated, + Succeeded, + Queued, + Expired, + Executed } /** @@ -260,7 +274,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /** * @notice Cancel the proposal. * @param proposalId Proposal id. - * @dev Only the owner address or the proposer can cancel. + * @dev Only this contract's owner or the proposer can cancel. * In the original GovernorAlpha, the proposer can cancel only if * her votes are still above the threshold. */ @@ -312,7 +326,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /** * @notice Cast a vote. * @param proposalId Proposal id. - * @param support Support (true ==> votesFor, false ==> votesAgainst) + * @param support Support (true ==> `forVotes`, false ==> `againstVotes`) */ function castVote(uint256 proposalId, ebool support) public virtual { return _castVote(msg.sender, proposalId, support); @@ -521,6 +535,7 @@ abstract contract GovernorAlphaZama is Ownable2Step, GatewayCaller { /** * @dev Only callable by the gateway. + * If `forVotesDecrypted` == `againstVotesDecrypted`, proposal is defeated. * @param forVotesDecrypted For votes. * @param againstVotesDecrypted Against votes. */