diff --git a/CustomProvider.ts b/CustomProvider.ts index b60308e..c4fb241 100644 --- a/CustomProvider.ts +++ b/CustomProvider.ts @@ -19,11 +19,6 @@ class CustomProvider extends ProviderWrapper implements Test { } 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; diff --git a/hardhat.config.ts b/hardhat.config.ts index c462c9c..26a401b 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -8,16 +8,12 @@ import type { HardhatUserConfig, 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/mint"; -import "./tasks/taskDeploy"; -import "./tasks/taskGatewayRelayer"; -import "./tasks/taskTFHE"; +import { setCodeMocked } from "./test/mockedSetup"; extendProvider(async (provider, config, network) => { const newProvider = new CustomProvider(provider); @@ -92,43 +88,7 @@ function replaceImportStatement(filePath: string, oldImport: string, newImport: 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 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 }); - - 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("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 setCodeMocked(hre); } await runSuper(); }); diff --git a/tasks/getEthereumAddress.ts b/tasks/getEthereumAddress.ts deleted file mode 100644 index 4e3dda0..0000000 --- a/tasks/getEthereumAddress.ts +++ /dev/null @@ -1,34 +0,0 @@ -import dotenv from "dotenv"; -import { ethers } from "ethers"; -import { task } from "hardhat/config"; -import { HardhatRuntimeEnvironment } from "hardhat/types"; - -dotenv.config(); - -const getEthereumAddress = - (index: number = 0) => - async (_taskArgs: unknown, _: HardhatRuntimeEnvironment) => { - const words = process.env.MNEMONIC!; - const mnemonic = ethers.Mnemonic.fromPhrase(words); - if (!mnemonic) { - throw new Error("No MNEMONIC in .env file"); - } - const wallet = ethers.HDNodeWallet.fromMnemonic(mnemonic, `m/44'/60'/0'/0`); - console.log(wallet.deriveChild(index).address); - }; - -task( - "task:getEthereumAddress", - "Gets the first address derived from a mnemonic phrase defined in .env", - getEthereumAddress(0), -); - -const accounts = ["Alice", "Bob", "Carol", "Dave", "Eve"]; - -accounts.forEach((name, index) => { - task( - `task:getEthereumAddress${name}`, - "Gets the first address derived from a mnemonic phrase defined in .env", - getEthereumAddress(index), - ); -}); diff --git a/tasks/taskDeploy.ts b/tasks/taskDeploy.ts deleted file mode 100644 index 5a5c991..0000000 --- a/tasks/taskDeploy.ts +++ /dev/null @@ -1,156 +0,0 @@ -import dotenv from "dotenv"; -import fs from "fs"; -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, upgrades }) { - const deployer = new ethers.Wallet(taskArguments.privateKey).connect(ethers.provider); - 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")); - 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") - .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") { // @note: for now we support only the coprocessor mode, not native - 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: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: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`); - } - } - }); diff --git a/tasks/taskGatewayRelayer.ts b/tasks/taskGatewayRelayer.ts deleted file mode 100644 index 581d508..0000000 --- a/tasks/taskGatewayRelayer.ts +++ /dev/null @@ -1,166 +0,0 @@ -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"] || "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: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: 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}`; - try { - fs.writeFileSync(envFilePath, content, { flag: "w" }); - 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); - } - - 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/GatewayContractAddress.sol", solidityTemplate, { - encoding: "utf8", - flag: "w", - }); - 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/GatewayContractAddress.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("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("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) - .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 deployerAddress = new hre.ethers.Wallet(privKeyDeployer!).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", [relayerAddress, bal]); - await Promise.all([p1, p2]); - } else { - const p1 = getCoin(deployerAddress); - const p2 = getCoin(relayerAddress); - await Promise.all([p1, p2]); - await new Promise((res) => setTimeout(res, 5000)); // wait 5 seconds - } - } - 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: privKeyDeployer, - gatewayAddress: gatewayContractAddress, - relayerAddress: relayerAddress, - }); - }); - -task("task:getBalances").setAction(async function (taskArgs, hre) { - const privKeyDeployer = process.env.PRIVATE_KEY_GATEWAY_DEPLOYER; - const privKeyRelayer = process.env.PRIVATE_KEY_GATEWAY_RELAYER; - const deployerAddress = new hre.ethers.Wallet(privKeyDeployer!).address; - const relayerAddress = new hre.ethers.Wallet(privKeyRelayer!).address; - console.log(await hre.ethers.provider.getBalance(deployerAddress)); - 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 - } - }); diff --git a/tasks/taskTFHE.ts b/tasks/taskTFHE.ts deleted file mode 100644 index e5c3e37..0000000 --- a/tasks/taskTFHE.ts +++ /dev/null @@ -1,214 +0,0 @@ -import fs from "fs"; -import { task, types } from "hardhat/config"; -import type { TaskArguments } from "hardhat/types"; -import path from "path"; - -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 - -pragma solidity ^0.8.24; - -address constant aclAdd = ${aclAddress};\n`; - - 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); - } - }); - -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 tfheExecutorAdd = ${execAddress};\n`; - - 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) - }); - 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); - } - }); - -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 inputVerifierAdd = ${inputVerfierAddress};\n`; - - 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) - }); - 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); - } - }); diff --git a/test/asyncDecrypt.ts b/test/asyncDecrypt.ts index 5cb9f34..dc3c232 100644 --- a/test/asyncDecrypt.ts +++ b/test/asyncDecrypt.ts @@ -3,7 +3,7 @@ import { Wallet } from "ethers"; import fs from "fs"; import { ethers, network } from "hardhat"; -import { ACL_ADDRESS, GATEWAYCONTRACT_ADDRESS } from "./constants"; +import { ACL_ADDRESS, GATEWAYCONTRACT_ADDRESS, KMSVERIFIER_ADDRESS, PRIVATE_KEY_KMS_SIGNER } from "./constants"; import { awaitCoprocessor, getClearText } from "./coprocessorUtils"; import { waitNBlocks } from "./utils"; @@ -28,17 +28,30 @@ const CiphertextType = { 11: "bytes", }; +let initNull = false; +async function impersonateNullAddress() { + // for mocked mode + const nullAddress = "0x0000000000000000000000000000000000000000"; + await network.provider.request({ + method: "hardhat_impersonateAccount", + params: [nullAddress], + }); + if (!initNull) { + await network.provider.send("hardhat_setBalance", [ + nullAddress, + "0x56BC75E2D63100000", // 100 ETH in hex + ]); + initNull = true; + } + const nullSigner = await ethers.getSigner(nullAddress); + return nullSigner; +} + const currentTime = (): string => { const now = new Date(); return now.toLocaleTimeString("en-US", { hour12: true, hour: "numeric", minute: "numeric", second: "numeric" }); }; -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)"; const ifaceEventDecryption = new ethers.Interface(["event EventDecryption" + argEvents]); @@ -100,7 +113,6 @@ const getAlreadyFulfilledDecryptions = async (): Promise<[bigint]> => { }; const pastResults = await ethers.provider.getLogs(filterDecryptionResult); results = results.concat(pastResults.map((result) => ifaceResultCallback.parseLog(result).args[0])); - return results; }; @@ -130,8 +142,8 @@ const fulfillAllPastRequestsIds = async (mocked: boolean) => { await awaitCoprocessor(); // first check tat all handles are allowed for decryption - const aclFactory = await ethers.getContractFactory("fhevmTemp/contracts/ACL.sol:ACL"); - const acl = aclFactory.attach(aclAdd); + const aclArtifact = require("../node_modules/fhevm-core-contracts/artifacts/contracts/ACL.sol/ACL.json"); + const acl = await ethers.getContractAt(aclArtifact.abi, ACL_ADDRESS); 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"); @@ -162,12 +174,13 @@ const fulfillAllPastRequestsIds = async (mocked: boolean) => { calldata = "0x" + encodedData.slice(66).slice(0, -64); // we also pop the last 32 bytes (empty bytes[]) } - const numSigners = +process.env.NUM_KMS_SIGNERS!; + const numSigners = 1; // for the moment mocked mode only uses 1 signer const decryptResultsEIP712signatures = await computeDecryptSignatures(handles, calldata, numSigners); + const relayer = await impersonateNullAddress(); const tx = await gateway .connect(relayer) .fulfillRequest(requestID, calldata, decryptResultsEIP712signatures, { value: msgValue }); - await tx.wait(); + const rcpt = await tx.wait(); } else { // in non-mocked mode we must wait until the gateway service relayer submits the decryption fulfillment tx await waitNBlocks(1); @@ -185,7 +198,7 @@ async function computeDecryptSignatures( const signatures: string[] = []; for (let idx = 0; idx < numSigners; idx++) { - const privKeySigner = process.env[`PRIVATE_KEY_KMS_SIGNER_${idx}`]; + const privKeySigner = PRIVATE_KEY_KMS_SIGNER; if (privKeySigner) { const kmsSigner = new ethers.Wallet(privKeySigner).connect(ethers.provider); const signature = await kmsSign(handlesList, decryptedResult, kmsSigner); @@ -198,9 +211,7 @@ async function computeDecryptSignatures( } 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 kmsAdd = KMSVERIFIER_ADDRESS; const chainId = (await ethers.provider.getNetwork()).chainId; const domain = { diff --git a/test/constants.ts b/test/constants.ts index 61754dd..b0af0d2 100644 --- a/test/constants.ts +++ b/test/constants.ts @@ -5,6 +5,7 @@ export const KMSVERIFIER_ADDRESS = "0x9d6891a6240d6130c54ae243d8005063d05fe14b"; export const INPUTVERIFIER_ADDRESS = "0x3a2DA6f1daE9eF988B48d9CF27523FA31a8eBE50"; export const GATEWAYCONTRACT_ADDRESS = "0x33347831500f1e73f0cccbb95c9f86b94d7b1123"; export const PRIVATE_KEY_KMS_SIGNER = "388b7680e4e1afa06efbfd45cdd1fe39f3c6af381df6555a19661f283b97de91"; +export const ORIGINAL_COPROCESSOR_ADDRESS = "0xc9990FEfE0c27D31D0C2aa36196b085c0c4d456c"; export const PRIVATE_KEY_COPROCESSOR_ACCOUNT = "388b7680e4e1afa06efbfd45cdd1fe39f3c6af381df6555a19661f283b97de91"; export const GATEWAY_URL = "https://gateway-sepolia.kms-dev-v1.bc.zama.team/"; export const ACCOUNT_NAMES = ["alice", "bob", "carol", "dave", "eve", "fred", "greg", "hugo", "ian", "jane"]; diff --git a/test/encryptedERC20/EncryptedERC20.FHEGas.ts b/test/encryptedERC20/EncryptedERC20.FHEGas.ts index f2c42dd..6abc501 100644 --- a/test/encryptedERC20/EncryptedERC20.FHEGas.ts +++ b/test/encryptedERC20/EncryptedERC20.FHEGas.ts @@ -1,13 +1,13 @@ import { expect } from "chai"; import { getFHEGasFromTxReceipt } from "../coprocessorUtils"; -import { createInstances } from "../instance"; +import { createInstance } from "../instance"; import { getSigners, initSigners } from "../signers"; import { deployEncryptedERC20Fixture } from "./EncryptedERC20.fixture"; describe("EncryptedERC20:FHEGas", function () { before(async function () { - await initSigners(2); + await initSigners(); this.signers = await getSigners(); }); @@ -15,7 +15,7 @@ describe("EncryptedERC20:FHEGas", function () { const contract = await deployEncryptedERC20Fixture(); this.contractAddress = await contract.getAddress(); this.erc20 = contract; - this.instances = await createInstances(this.signers); + this.fhevm = await createInstance(); }); it("gas consumed during transfer", async function () { @@ -23,7 +23,7 @@ describe("EncryptedERC20:FHEGas", function () { const t1 = await transaction.wait(); expect(t1?.status).to.eq(1); - const input = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const input = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); input.add64(1337); const encryptedTransferAmount = await input.encrypt(); const tx = await this.erc20["transfer(address,bytes32,bytes)"]( @@ -35,6 +35,7 @@ describe("EncryptedERC20:FHEGas", function () { expect(t2?.status).to.eq(1); const FHEGasConsumedTransfer = getFHEGasFromTxReceipt(t2); console.log("FHEGas Consumed during transfer", FHEGasConsumedTransfer); + // @note: contrarily to the FHEGas, native gas in mocked mode slightly differs from the real gas consumption on fhevm (off by ~5%) console.log("Native Gas Consumed during transfer", t2.gasUsed); }); @@ -42,7 +43,7 @@ describe("EncryptedERC20:FHEGas", function () { const transaction = await this.erc20.mint(10000); await transaction.wait(); - const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const inputAlice = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); inputAlice.add64(1337); const encryptedAllowanceAmount = await inputAlice.encrypt(); const tx = await this.erc20["approve(address,bytes32,bytes)"]( @@ -53,7 +54,7 @@ describe("EncryptedERC20:FHEGas", function () { await tx.wait(); const bobErc20 = this.erc20.connect(this.signers.bob); - const inputBob2 = this.instances.bob.createEncryptedInput(this.contractAddress, this.signers.bob.address); + const inputBob2 = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.bob.address); inputBob2.add64(1337); // below allowance so next tx should send token const encryptedTransferAmount2 = await inputBob2.encrypt(); const tx3 = await bobErc20["transferFrom(address,address,bytes32,bytes)"]( @@ -65,6 +66,7 @@ describe("EncryptedERC20:FHEGas", function () { const t3 = await tx3.wait(); const FHEGasConsumedTransferFrom = getFHEGasFromTxReceipt(t3); console.log("FHEGas Consumed during transferFrom", FHEGasConsumedTransferFrom); - console.log("Native Gas Consumed during transferFrom", t3.gasUsed); + // @note: contrarily to the FHEGas, native gas in mocked mode slightly differs from the real gas consumption on fhevm (off by ~5%) + console.log("Native Gas Consumed during transfer", t3.gasUsed); }); }); diff --git a/test/encryptedERC20/EncryptedERC20.ts b/test/encryptedERC20/EncryptedERC20.ts index 14f2385..500a707 100644 --- a/test/encryptedERC20/EncryptedERC20.ts +++ b/test/encryptedERC20/EncryptedERC20.ts @@ -1,13 +1,13 @@ import { expect } from "chai"; -import { createInstances } from "../instance"; +import { createInstance } from "../instance"; import { reencryptEuint64 } from "../reencrypt"; import { getSigners, initSigners } from "../signers"; import { deployEncryptedERC20Fixture } from "./EncryptedERC20.fixture"; describe("EncryptedERC20", function () { before(async function () { - await initSigners(2); + await initSigners(); this.signers = await getSigners(); }); @@ -15,7 +15,7 @@ describe("EncryptedERC20", function () { const contract = await deployEncryptedERC20Fixture(); this.contractAddress = await contract.getAddress(); this.erc20 = contract; - this.instances = await createInstances(this.signers); + this.fhevm = await createInstance(); }); it("should mint the contract", async function () { @@ -26,7 +26,7 @@ describe("EncryptedERC20", function () { const balanceHandleAlice = await this.erc20.balanceOf(this.signers.alice); const balanceAlice = await reencryptEuint64( this.signers, - this.instances, + this.fhevm, "alice", balanceHandleAlice, this.contractAddress, @@ -43,7 +43,7 @@ describe("EncryptedERC20", function () { const t1 = await transaction.wait(); expect(t1?.status).to.eq(1); - const input = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const input = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); input.add64(1337); const encryptedTransferAmount = await input.encrypt(); const tx = await this.erc20["transfer(address,bytes32,bytes)"]( @@ -58,7 +58,7 @@ describe("EncryptedERC20", function () { const balanceHandleAlice = await this.erc20.balanceOf(this.signers.alice); const balanceAlice = await reencryptEuint64( this.signers, - this.instances, + this.fhevm, "alice", balanceHandleAlice, this.contractAddress, @@ -67,23 +67,17 @@ describe("EncryptedERC20", function () { // Reencrypt Bob's balance const balanceHandleBob = await this.erc20.balanceOf(this.signers.bob); - const balanceBob = await reencryptEuint64( - this.signers, - this.instances, - "bob", - balanceHandleBob, - this.contractAddress, - ); + const balanceBob = await reencryptEuint64(this.signers, this.fhevm, "bob", balanceHandleBob, this.contractAddress); expect(balanceBob).to.equal(1337); // on the other hand, Bob should be unable to read Alice's balance await expect( - reencryptEuint64(this.signers, this.instances, "bob", balanceHandleAlice, this.contractAddress), + reencryptEuint64(this.signers, this.fhevm, "bob", balanceHandleAlice, this.contractAddress), ).to.be.rejectedWith("User is not authorized to reencrypt this handle!"); // and should be impossible to call reencrypt if contractAddress === userAddress await expect( - reencryptEuint64(this.signers, this.instances, "alice", balanceHandleAlice, this.signers.alice.address), + reencryptEuint64(this.signers, this.fhevm, "alice", balanceHandleAlice, this.signers.alice.address), ).to.be.rejectedWith("userAddress should not be equal to contractAddress when requesting reencryption!"); }); @@ -91,7 +85,7 @@ describe("EncryptedERC20", function () { const transaction = await this.erc20.mint(1000); await transaction.wait(); - const input = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const input = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); input.add64(1337); const encryptedTransferAmount = await input.encrypt(); const tx = await this.erc20["transfer(address,bytes32,bytes)"]( @@ -104,7 +98,7 @@ describe("EncryptedERC20", function () { const balanceHandleAlice = await this.erc20.balanceOf(this.signers.alice); const balanceAlice = await reencryptEuint64( this.signers, - this.instances, + this.fhevm, "alice", balanceHandleAlice, this.contractAddress, @@ -113,13 +107,7 @@ describe("EncryptedERC20", function () { // Reencrypt Bob's balance const balanceHandleBob = await this.erc20.balanceOf(this.signers.bob); - const balanceBob = await reencryptEuint64( - this.signers, - this.instances, - "bob", - balanceHandleBob, - this.contractAddress, - ); + const balanceBob = await reencryptEuint64(this.signers, this.fhevm, "bob", balanceHandleBob, this.contractAddress); expect(balanceBob).to.equal(0); }); @@ -127,7 +115,7 @@ describe("EncryptedERC20", function () { const transaction = await this.erc20.mint(10000); await transaction.wait(); - const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const inputAlice = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); inputAlice.add64(1337); const encryptedAllowanceAmount = await inputAlice.encrypt(); const tx = await this.erc20["approve(address,bytes32,bytes)"]( @@ -138,7 +126,7 @@ describe("EncryptedERC20", function () { await tx.wait(); const bobErc20 = this.erc20.connect(this.signers.bob); - const inputBob1 = this.instances.bob.createEncryptedInput(this.contractAddress, this.signers.bob.address); + const inputBob1 = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.bob.address); inputBob1.add64(1338); // 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)"]( @@ -153,7 +141,7 @@ describe("EncryptedERC20", function () { const balanceHandleAlice = await this.erc20.balanceOf(this.signers.alice); const balanceAlice = await reencryptEuint64( this.signers, - this.instances, + this.fhevm, "alice", balanceHandleAlice, this.contractAddress, @@ -162,16 +150,10 @@ describe("EncryptedERC20", function () { // Decrypt Bob's balance const balanceHandleBob = await this.erc20.balanceOf(this.signers.bob); - const balanceBob = await reencryptEuint64( - this.signers, - this.instances, - "bob", - balanceHandleBob, - this.contractAddress, - ); + const balanceBob = await reencryptEuint64(this.signers, this.fhevm, "bob", balanceHandleBob, this.contractAddress); expect(balanceBob).to.equal(0); // check that transfer did not happen, as expected - const inputBob2 = this.instances.bob.createEncryptedInput(this.contractAddress, this.signers.bob.address); + const inputBob2 = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.bob.address); inputBob2.add64(1337); // below allowance so next tx should send token const encryptedTransferAmount2 = await inputBob2.encrypt(); const tx3 = await bobErc20["transferFrom(address,address,bytes32,bytes)"]( @@ -186,7 +168,7 @@ describe("EncryptedERC20", function () { const balanceHandleAlice2 = await this.erc20.balanceOf(this.signers.alice); const balanceAlice2 = await reencryptEuint64( this.signers, - this.instances, + this.fhevm, "alice", balanceHandleAlice2, this.contractAddress, @@ -197,7 +179,7 @@ describe("EncryptedERC20", function () { const balanceHandleBob2 = await this.erc20.balanceOf(this.signers.bob); const balanceBob2 = await reencryptEuint64( this.signers, - this.instances, + this.fhevm, "bob", balanceHandleBob2, this.contractAddress, diff --git a/test/fhevmjsMocked.ts b/test/fhevmjsMocked.ts index 96f2ea5..c8e837d 100644 --- a/test/fhevmjsMocked.ts +++ b/test/fhevmjsMocked.ts @@ -1,5 +1,4 @@ -import { toBigIntBE } from "bigint-buffer"; -import { toBufferBE } from "bigint-buffer"; +import { toBigIntBE, toBufferBE } from "bigint-buffer"; import crypto from "crypto"; import dotenv from "dotenv"; import { Wallet, ethers } from "ethers"; @@ -7,7 +6,13 @@ import * as fs from "fs"; import { Keccak } from "sha3"; import { isAddress } from "web3-validator"; -import { ACL_ADDRESS } from "./constants"; +import { + ACL_ADDRESS, + INPUTVERIFIER_ADDRESS, + KMSVERIFIER_ADDRESS, + PRIVATE_KEY_COPROCESSOR_ACCOUNT, + PRIVATE_KEY_KMS_SIGNER, +} from "./constants"; import { insertSQL } from "./coprocessorUtils"; import { awaitCoprocessor, getClearText } from "./coprocessorUtils"; @@ -139,8 +144,8 @@ export const reencryptRequestMocked = async ( } // ACL checking - const aclFactory = await hre.ethers.getContractFactory("fhevmTemp/contracts/ACL.sol:ACL"); - const acl = aclFactory.attach(aclAdd); + const aclArtifact = require("../node_modules/fhevm-core-contracts/artifacts/contracts/ACL.sol/ACL.json"); + const acl = await hre.ethers.getContractAt(aclArtifact.abi, ACL_ADDRESS); const userAllowed = await acl.persistAllowed(handle, userAddress); const contractAllowed = await acl.persistAllowed(handle, contractAddress); const isAllowed = userAllowed && contractAllowed; @@ -307,7 +312,7 @@ export const createEncryptedInputMocked = (contractAddress: string, userAddress: }); 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!; + const numSigners = 1; // @note: only 1 signer in mocked mode for the moment inputProof += numberToHex(numSigners); //if (process.env.IS_COPROCESSOR === "true") { // @note: for now we support only the coprocessor mode, not native // coprocessor @@ -397,13 +402,9 @@ async function computeInputSignatureCopro( 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`); - } + const privKeySigner = PRIVATE_KEY_COPROCESSOR_ACCOUNT; + const coprocSigner = new Wallet(privKeySigner).connect(ethers.provider); + signature = await coprocSign(hash, handlesList, userAddress, contractAddress, coprocSigner); return signature; } @@ -413,16 +414,12 @@ async function computeInputSignaturesKMS( contractAddress: string, ): Promise { const signatures: string[] = []; - const numSigners = +process.env.NUM_KMS_SIGNERS!; + const numSigners = 1; // @note: only 1 KMS signer in mocked mode for now 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`); - } + const privKeySigner = PRIVATE_KEY_KMS_SIGNER; + const kmsSigner = new ethers.Wallet(privKeySigner).connect(ethers.provider); + const signature = await kmsSign(hash, userAddress, contractAddress, kmsSigner); + signatures.push(signature); } return signatures; } @@ -434,9 +431,7 @@ async function coprocSign( contractAddress: string, signer: Wallet, ): Promise { - const inputAdd = dotenv.parse( - fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.inputverifier"), - ).INPUT_VERIFIER_CONTRACT_ADDRESS; + const inputAdd = INPUTVERIFIER_ADDRESS; const chainId = hre.__SOLIDITY_COVERAGE_RUNNING ? 31337 : network.config.chainId; const aclAdd = ACL_ADDRESS; @@ -495,9 +490,7 @@ async function kmsSign( contractAddress: string, signer: Wallet, ): Promise { - const kmsVerifierAdd = dotenv.parse( - fs.readFileSync("node_modules/fhevm-core-contracts/addresses/.env.kmsverifier"), - ).KMS_VERIFIER_CONTRACT_ADDRESS; + const kmsVerifierAdd = KMSVERIFIER_ADDRESS; const chainId = hre.__SOLIDITY_COVERAGE_RUNNING ? 31337 : network.config.chainId; const aclAdd = ACL_ADDRESS; diff --git a/test/gatewayDecrypt/testAsyncDecrypt.ts b/test/gatewayDecrypt/testAsyncDecrypt.ts index 7d60747..87696ce 100644 --- a/test/gatewayDecrypt/testAsyncDecrypt.ts +++ b/test/gatewayDecrypt/testAsyncDecrypt.ts @@ -2,13 +2,13 @@ import { expect } from "chai"; import { ethers, network } from "hardhat"; import { awaitAllDecryptionResults, initGateway } from "../asyncDecrypt"; -import { createInstances } from "../instance"; +import { createInstance } from "../instance"; import { getSigners, initSigners } from "../signers"; import { bigIntToBytes64, bigIntToBytes128, bigIntToBytes256 } from "../utils"; describe("TestAsyncDecrypt", function () { before(async function () { - await initSigners(2); + await initSigners(); this.signers = await getSigners(); await initGateway(); }); @@ -18,11 +18,11 @@ describe("TestAsyncDecrypt", function () { 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); + this.fhevm = await createInstance(); }); it("test async decrypt bool", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestBool({ gasLimit: 5_000_000 }); + const tx2 = await this.contract.connect(this.signers.carol).requestBool(); await tx2.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yBool(); @@ -33,7 +33,7 @@ describe("TestAsyncDecrypt", function () { const contractFactory = await ethers.getContractFactory("TestAsyncDecrypt"); const contract2 = await contractFactory.connect(this.signers.alice).deploy(); await contract2.waitForDeployment(); - const tx2 = await contract2.requestBoolTrustless({ gasLimit: 5_000_000 }); + const tx2 = await contract2.requestBoolTrustless(); await tx2.wait(); await awaitAllDecryptionResults(); const y = await contract2.yBool(); @@ -47,7 +47,7 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt uint4", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint4({ gasLimit: 5_000_000 }); + const tx2 = await this.contract.connect(this.signers.carol).requestUint4(); await tx2.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yUint4(); @@ -55,7 +55,7 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt uint8", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint8({ gasLimit: 5_000_000 }); + const tx2 = await this.contract.connect(this.signers.carol).requestUint8(); await tx2.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yUint8(); @@ -63,7 +63,7 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt uint16", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint16({ gasLimit: 5_000_000 }); + const tx2 = await this.contract.connect(this.signers.carol).requestUint16(); await tx2.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yUint16(); @@ -71,7 +71,7 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt uint32", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint32(5, 15, { gasLimit: 5_000_000 }); + const tx2 = await this.contract.connect(this.signers.carol).requestUint32(5, 15); await tx2.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yUint32(); @@ -79,7 +79,7 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt uint64", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint64({ gasLimit: 5_000_000 }); + const tx2 = await this.contract.connect(this.signers.carol).requestUint64(); await tx2.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yUint64(); @@ -87,7 +87,7 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt uint128", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint128({ gasLimit: 5_000_000 }); + const tx2 = await this.contract.connect(this.signers.carol).requestUint128(); await tx2.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yUint128(); @@ -95,12 +95,10 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt uint128 non-trivial", async function () { - const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const inputAlice = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); inputAlice.add128(184467440737095500429401496n); const encryptedAmount = await inputAlice.encrypt(); - const tx = await this.contract.requestUint128NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof, { - gasLimit: 5_000_000, - }); + const tx = await this.contract.requestUint128NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof); await tx.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yUint128(); @@ -108,7 +106,7 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt uint256", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestUint256({ gasLimit: 5_000_000 }); + const tx2 = await this.contract.connect(this.signers.carol).requestUint256(); await tx2.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yUint256(); @@ -116,12 +114,10 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt uint256 non-trivial", async function () { - const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const inputAlice = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); inputAlice.add256(6985387162255149739023449108101809804435888681546n); const encryptedAmount = await inputAlice.encrypt(); - const tx = await this.contract.requestUint256NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof, { - gasLimit: 5_000_000, - }); + const tx = await this.contract.requestUint256NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof); await tx.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yUint256(); @@ -129,7 +125,7 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt address", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestAddress({ gasLimit: 5_000_000 }); + const tx2 = await this.contract.connect(this.signers.carol).requestAddress(); await tx2.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yAddress(); @@ -137,7 +133,7 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt several addresses", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestSeveralAddresses({ gasLimit: 5_000_000 }); + const tx2 = await this.contract.connect(this.signers.carol).requestSeveralAddresses(); await tx2.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yAddress(); @@ -147,7 +143,7 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt mixed", async function () { - const tx2 = await this.contract.connect(this.signers.carol).requestMixed(5, 15, { gasLimit: 5_000_000 }); + const tx2 = await this.contract.connect(this.signers.carol).requestMixed(5, 15); await tx2.wait(); await awaitAllDecryptionResults(); let yB = await this.contract.yBool(); @@ -167,12 +163,10 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt uint64 non-trivial", async function () { - const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const inputAlice = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); inputAlice.add64(18446744073709550042n); const encryptedAmount = await inputAlice.encrypt(); - const tx = await this.contract.requestUint64NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof, { - gasLimit: 5_000_000, - }); + const tx = await this.contract.requestUint64NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof); await tx.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yUint64(); @@ -188,14 +182,12 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt ebytes64 non-trivial", async function () { - const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const inputAlice = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); inputAlice.addBytes64( bigIntToBytes64(98870780878070870878787887072921111299111111000000292928818818818818221112111n), ); const encryptedAmount = await inputAlice.encrypt(); - const tx = await this.contract.requestEbytes64NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof, { - gasLimit: 5_000_000, - }); + const tx = await this.contract.requestEbytes64NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof); await tx.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yBytes64(); @@ -222,16 +214,14 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt ebytes128 non-trivial", async function () { - const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const inputAlice = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); inputAlice.addBytes128( bigIntToBytes128( 9887078087807087087878788707292111129911111100000029292881881881881822111211198870780878070870878787887072921111299111111000000292928818818818818221112111n, ), ); const encryptedAmount = await inputAlice.encrypt(); - const tx = await this.contract.requestEbytes128NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof, { - gasLimit: 5_000_000, - }); + const tx = await this.contract.requestEbytes128NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof); await tx.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yBytes128(); @@ -252,12 +242,10 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt ebytes256 non-trivial", async function () { - const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const inputAlice = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); inputAlice.addBytes256(bigIntToBytes256(18446744073709550022n)); const encryptedAmount = await inputAlice.encrypt(); - const tx = await this.contract.requestEbytes256NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof, { - gasLimit: 5_000_000, - }); + const tx = await this.contract.requestEbytes256NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof); await tx.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yBytes256(); @@ -267,27 +255,22 @@ describe("TestAsyncDecrypt", function () { 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); + const inputAlice = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); inputAlice.addBytes256(bigIntToBytes256(18446744073709550022n)); const encryptedAmount = await inputAlice.encrypt(); - const tx = await this.contract.requestEbytes256NonTrivial( - encryptedAmount.handles[0], - encryptedAmount.inputProof, - { gasLimit: 5_000_000 }, - ); + const tx = await this.contract.requestEbytes256NonTrivial(encryptedAmount.handles[0], encryptedAmount.inputProof); 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); + const inputAlice2 = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); inputAlice2.addBytes256(bigIntToBytes256(424242n)); const encryptedAmount2 = await inputAlice2.encrypt(); const tx2 = await this.contract.requestEbytes256NonTrivial( encryptedAmount2.handles[0], encryptedAmount2.inputProof, - { gasLimit: 5_000_000 }, ); await tx2.wait(); await awaitAllDecryptionResults(); @@ -297,12 +280,10 @@ describe("TestAsyncDecrypt", function () { }); it("test async decrypt mixed with ebytes256", async function () { - const inputAlice = this.instances.alice.createEncryptedInput(this.contractAddress, this.signers.alice.address); + const inputAlice = this.fhevm.createEncryptedInput(this.contractAddress, this.signers.alice.address); inputAlice.addBytes256(bigIntToBytes256(18446744073709550032n)); const encryptedAmount = await inputAlice.encrypt(); - const tx = await this.contract.requestMixedBytes256(encryptedAmount.handles[0], encryptedAmount.inputProof, { - gasLimit: 5_000_000, - }); + const tx = await this.contract.requestMixedBytes256(encryptedAmount.handles[0], encryptedAmount.inputProof); await tx.wait(); await awaitAllDecryptionResults(); const y = await this.contract.yBytes256(); @@ -319,16 +300,12 @@ describe("TestAsyncDecrypt", function () { const contractFactory = await ethers.getContractFactory("TestAsyncDecrypt"); const contract2 = await contractFactory.connect(this.signers.alice).deploy(); await contract2.waitForDeployment(); - const inputAlice = this.instances.alice.createEncryptedInput( - await contract2.getAddress(), - this.signers.alice.address, - ); + const inputAlice = this.fhevm.createEncryptedInput(await contract2.getAddress(), this.signers.alice.address); inputAlice.addBytes256(bigIntToBytes256(18446744073709550022n)); const encryptedAmount = await inputAlice.encrypt(); const tx = await contract2.requestEbytes256NonTrivialTrustless( encryptedAmount.handles[0], encryptedAmount.inputProof, - { gasLimit: 5_000_000 }, ); await tx.wait(); await awaitAllDecryptionResults(); @@ -340,15 +317,10 @@ describe("TestAsyncDecrypt", function () { const contractFactory = await ethers.getContractFactory("TestAsyncDecrypt"); const contract2 = await contractFactory.connect(this.signers.alice).deploy(); await contract2.waitForDeployment(); - const inputAlice = this.instances.alice.createEncryptedInput( - await contract2.getAddress(), - this.signers.alice.address, - ); + const inputAlice = this.fhevm.createEncryptedInput(await contract2.getAddress(), this.signers.alice.address); inputAlice.addBytes256(bigIntToBytes256(18446744073709550032n)); const encryptedAmount = await inputAlice.encrypt(); - const tx = await contract2.requestMixedBytes256Trustless(encryptedAmount.handles[0], encryptedAmount.inputProof, { - gasLimit: 5_000_000, - }); + const tx = await contract2.requestMixedBytes256Trustless(encryptedAmount.handles[0], encryptedAmount.inputProof); await tx.wait(); await awaitAllDecryptionResults(); const y = await contract2.yBytes256(); diff --git a/test/instance.ts b/test/instance.ts index b245c7a..3a6e4a4 100644 --- a/test/instance.ts +++ b/test/instance.ts @@ -5,6 +5,7 @@ import { generateKeypair, getCiphertextCallParams, } from "fhevmjs"; +import { FhevmInstance } from "fhevmjs/node"; import { readFileSync } from "fs"; import { ethers, ethers as hethers, network } from "hardhat"; import { homedir } from "os"; @@ -13,8 +14,6 @@ import path from "path"; import { ACL_ADDRESS, GATEWAY_URL, KMSVERIFIER_ADDRESS } from "./constants"; import { awaitCoprocessor, getClearText } from "./coprocessorUtils"; import { createEncryptedInputMocked, reencryptRequestMocked } from "./fhevmjsMocked"; -import type { Signers } from "./signers"; -import { FhevmInstances } from "./types"; const FHE_CLIENT_KEY_PATH = process.env.FHE_CLIENT_KEY_PATH; @@ -23,44 +22,25 @@ let clientKey: Uint8Array | undefined; const kmsAdd = KMSVERIFIER_ADDRESS; const aclAdd = ACL_ADDRESS; -const createInstanceMocked = async () => { - const instance = { - reencrypt: reencryptRequestMocked, - createEncryptedInput: createEncryptedInputMocked, - getPublicKey: () => "0xFFAA44433", - generateKeypair: generateKeypair, - createEIP712: createEIP712(network.config.chainId), - }; - return instance; -}; - -export const createInstances = async (accounts: Signers): Promise => { - // Create instance - const instances: FhevmInstances = {} as FhevmInstances; +export const createInstance = async (): Promise => { if (network.name === "hardhat") { - await Promise.all( - Object.keys(accounts).map(async (k) => { - instances[k as keyof FhevmInstances] = await createInstanceMocked(); - }), - ); + const instance = { + reencrypt: reencryptRequestMocked, + createEncryptedInput: createEncryptedInputMocked, + getPublicKey: () => "0xFFAA44433", + generateKeypair: generateKeypair, + createEIP712: createEIP712(network.config.chainId), + }; + return instance; } else { - await Promise.all( - Object.keys(accounts).map(async (k) => { - instances[k as keyof FhevmInstances] = await createInstance(); - }), - ); + const instance = await createFhevmInstance({ + kmsContractAddress: kmsAdd, + aclContractAddress: aclAdd, + networkUrl: network.config.url, + gatewayUrl: GATEWAY_URL, + }); + return instance; } - return instances; -}; - -export const createInstance = async () => { - const instance = await createFhevmInstance({ - kmsContractAddress: kmsAdd, - aclContractAddress: aclAdd, - networkUrl: network.config.url, - gatewayUrl: GATEWAY_URL, - }); - return instance; }; const getCiphertext = async (handle: bigint, ethers: typeof hethers): Promise => { diff --git a/test/mockedSetup.ts b/test/mockedSetup.ts new file mode 100644 index 0000000..71b8bca --- /dev/null +++ b/test/mockedSetup.ts @@ -0,0 +1,96 @@ +import { + ACL_ADDRESS, + FHEPAYMENT_ADDRESS, + GATEWAYCONTRACT_ADDRESS, + INPUTVERIFIER_ADDRESS, + KMSVERIFIER_ADDRESS, + ORIGINAL_COPROCESSOR_ADDRESS, + PRIVATE_KEY_COPROCESSOR_ACCOUNT, + PRIVATE_KEY_KMS_SIGNER, + TFHEEXECUTOR_ADDRESS, +} from "./constants"; + +const nullAddress = "0x0000000000000000000000000000000000000000"; +const oneAddress = "0x0000000000000000000000000000000000000001"; + +export async function setCodeMocked(hre) { + const aclArtifact = require("../node_modules/fhevm-core-contracts/artifacts/contracts/ACL.sol/ACL.json"); + const aclBytecode = aclArtifact.deployedBytecode; + await hre.network.provider.send("hardhat_setCode", [ACL_ADDRESS, aclBytecode]); + const execArtifact = require("../node_modules/fhevm-core-contracts/artifacts/contracts/TFHEExecutorWithEvents.sol/TFHEExecutorWithEvents.json"); + const execBytecode = execArtifact.deployedBytecode; + await hre.network.provider.send("hardhat_setCode", [TFHEEXECUTOR_ADDRESS, execBytecode]); + const kmsArtifact = require("../node_modules/fhevm-core-contracts/artifacts/contracts/KMSVerifier.sol/KMSVerifier.json"); + const kmsBytecode = kmsArtifact.deployedBytecode; + await hre.network.provider.send("hardhat_setCode", [KMSVERIFIER_ADDRESS, kmsBytecode]); + const inputArtifact = require("../node_modules/fhevm-core-contracts/artifacts/contracts/InputVerifier.coprocessor.sol/InputVerifier.json"); + const inputBytecode = inputArtifact.deployedBytecode; + const coprocessorSigner = new hre.ethers.Wallet(PRIVATE_KEY_COPROCESSOR_ACCOUNT); + const newInputBytecode = replaceAddressInBytecode( + inputBytecode, + ORIGINAL_COPROCESSOR_ADDRESS, + coprocessorSigner.address, + ); + await hre.network.provider.send("hardhat_setCode", [INPUTVERIFIER_ADDRESS, newInputBytecode]); + const fhepaymentArtifact = require("../node_modules/fhevm-core-contracts/artifacts/contracts/FHEPayment.sol/FHEPayment.json"); + const fhepaymentBytecode = fhepaymentArtifact.deployedBytecode; + await hre.network.provider.send("hardhat_setCode", [FHEPAYMENT_ADDRESS, fhepaymentBytecode]); + const gatewayArtifact = require("../node_modules/fhevm-core-contracts/artifacts/gateway/GatewayContract.sol/GatewayContract.json"); + const gatewayBytecode = gatewayArtifact.deployedBytecode; + await hre.network.provider.send("hardhat_setCode", [GATEWAYCONTRACT_ADDRESS, gatewayBytecode]); + const zero = await impersonateNullAddress(hre); + const one = await impersonateOneAddress(hre); + const kmsSigner = new hre.ethers.Wallet(PRIVATE_KEY_KMS_SIGNER); + const kms = await hre.ethers.getContractAt(kmsArtifact.abi, KMSVERIFIER_ADDRESS); + await kms.connect(zero).initialize(oneAddress); + await kms.connect(one).addSigner(kmsSigner); + const input = await hre.ethers.getContractAt(inputArtifact.abi, INPUTVERIFIER_ADDRESS); + await input.connect(zero).initialize(oneAddress); + const gateway = await hre.ethers.getContractAt(gatewayArtifact.abi, GATEWAYCONTRACT_ADDRESS); + await gateway.connect(zero).addRelayer(nullAddress); +} + +let initNull = false; +async function impersonateNullAddress(hre) { + // for mocked mode + await hre.network.provider.request({ + method: "hardhat_impersonateAccount", + params: [nullAddress], + }); + if (!initNull) { + await hre.network.provider.send("hardhat_setBalance", [ + nullAddress, + "0x56BC75E2D63100000", // 100 ETH in hex + ]); + initNull = true; + } + const nullSigner = await hre.ethers.getSigner(nullAddress); + return nullSigner; +} + +let initOne = false; +async function impersonateOneAddress(hre) { + // for mocked mode + await hre.network.provider.request({ + method: "hardhat_impersonateAccount", + params: [oneAddress], + }); + if (!initOne) { + await hre.network.provider.send("hardhat_setBalance", [ + oneAddress, + "0x56BC75E2D63100000", // 100 ETH in hex + ]); + initOne = true; + } + const oneSigner = await hre.ethers.getSigner(oneAddress); + return oneSigner; +} + +function replaceAddressInBytecode(originalBytecode: string, originalAddress: string, newAddress: string): string { + // used to replace the coprocessor account address in the InputVerifier.coprocessor contract + const searchHex = originalAddress.slice(2).toLowerCase(); + const replaceHex = newAddress.slice(2).toLowerCase(); + const regex = new RegExp(searchHex, "gi"); + const newBytecode = originalBytecode.toLowerCase().replace(regex, replaceHex); + return newBytecode; +} diff --git a/test/reencrypt.ts b/test/reencrypt.ts index 8c79e63..b11a6c0 100644 --- a/test/reencrypt.ts +++ b/test/reencrypt.ts @@ -1,5 +1,6 @@ +import { FhevmInstance } from "fhevmjs/node"; + import { Signers } from "./signers"; -import type { FhevmInstances } from "./types"; const EBOOL_T = 0; const EUINT4_T = 1; @@ -32,7 +33,7 @@ export function verifyType(handle: bigint, expectedType: number) { export async function reencryptEbool( signers: Signers, - instances: FhevmInstances, + instances: FhevmInstance, user: string, handle: bigint, contractAddress: string, @@ -43,7 +44,7 @@ export async function reencryptEbool( export async function reencryptEuint4( signers: Signers, - instances: FhevmInstances, + instances: FhevmInstance, user: string, handle: bigint, contractAddress: string, @@ -54,7 +55,7 @@ export async function reencryptEuint4( export async function reencryptEuint8( signers: Signers, - instances: FhevmInstances, + instances: FhevmInstance, user: string, handle: bigint, contractAddress: string, @@ -65,7 +66,7 @@ export async function reencryptEuint8( export async function reencryptEuint16( signers: Signers, - instances: FhevmInstances, + instances: FhevmInstance, user: string, handle: bigint, contractAddress: string, @@ -76,7 +77,7 @@ export async function reencryptEuint16( export async function reencryptEuint32( signers: Signers, - instances: FhevmInstances, + instances: FhevmInstance, user: string, handle: bigint, contractAddress: string, @@ -87,7 +88,7 @@ export async function reencryptEuint32( export async function reencryptEuint64( signers: Signers, - instances: FhevmInstances, + instances: FhevmInstance, user: string, handle: bigint, contractAddress: string, @@ -98,7 +99,7 @@ export async function reencryptEuint64( export async function reencryptEuint128( signers: Signers, - instances: FhevmInstances, + instances: FhevmInstance, user: string, handle: bigint, contractAddress: string, @@ -109,7 +110,7 @@ export async function reencryptEuint128( export async function reencryptEaddress( signers: Signers, - instances: FhevmInstances, + instances: FhevmInstance, user: string, handle: bigint, contractAddress: string, @@ -122,7 +123,7 @@ export async function reencryptEaddress( export async function reencryptEuint256( signers: Signers, - instances: FhevmInstances, + instances: FhevmInstance, user: string, handle: bigint, contractAddress: string, @@ -133,7 +134,7 @@ export async function reencryptEuint256( export async function reencryptEbytes64( signers: Signers, - instances: FhevmInstances, + instances: FhevmInstance, user: string, handle: bigint, contractAddress: string, @@ -144,7 +145,7 @@ export async function reencryptEbytes64( export async function reencryptEbytes128( signers: Signers, - instances: FhevmInstances, + instances: FhevmInstance, user: string, handle: bigint, contractAddress: string, @@ -155,7 +156,7 @@ export async function reencryptEbytes128( export async function reencryptEbytes256( signers: Signers, - instances: FhevmInstances, + instances: FhevmInstance, user: string, handle: bigint, contractAddress: string, @@ -170,20 +171,20 @@ export async function reencryptEbytes256( */ async function reencryptHandle( signers: Signers, - instances: FhevmInstances, + instance: FhevmInstance, user: string, handle: bigint, contractAddress: string, ): Promise { - const { publicKey: publicKey, privateKey: privateKey } = instances[user as keyof FhevmInstances].generateKeypair(); - const eip712 = instances[user as keyof FhevmInstances].createEIP712(publicKey, contractAddress); + const { publicKey: publicKey, privateKey: privateKey } = instance.generateKeypair(); + const eip712 = instance.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( + const reencryptedHandle = await instance.reencrypt( handle, privateKey, publicKey, diff --git a/test/signers.ts b/test/signers.ts index 8b017d1..fb98a77 100644 --- a/test/signers.ts +++ b/test/signers.ts @@ -1,69 +1,22 @@ import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; -import { exec as oldExec } from "child_process"; -import { config, ethers } from "hardhat"; -import { promisify } from "util"; +import { ethers } from "hardhat"; -import { waitForBalance } from "./utils"; +import { ACCOUNT_NAMES } from "./constants"; -const exec = promisify(oldExec); +type AccountNames = (typeof ACCOUNT_NAMES)[number]; export interface Signers { - alice: HardhatEthersSigner; - bob: HardhatEthersSigner; - carol: HardhatEthersSigner; - dave: HardhatEthersSigner; - eve: HardhatEthersSigner; + [K in AccountNames]: HardhatEthersSigner; } -let signers: Signers; +let signers: Signers = {} as Signers; -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) { - 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 initSigners = async (): Promise => { + if (Object.entries(signers).length === 0) { + const eSigners = await ethers.getSigners(); + for (let index = 0; index < ACCOUNT_NAMES.length; index++) { + const name = ACCOUNT_NAMES[index]; + signers[name] = eSigners[index]; } } }; @@ -71,5 +24,3 @@ export const initSigners = async (quantity: number): Promise => { export const getSigners = async (): Promise => { return signers; }; - -export const requestFaucet = faucet; diff --git a/test/types.ts b/test/types.ts deleted file mode 100644 index 6bafa13..0000000 --- a/test/types.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { FhevmInstance } from "fhevmjs"; - -import { BlindAuction, Comp, EncryptedERC20, GovernorZama, IdentifiedERC20, IdentityRegistry, Rand } from "../types"; -import type { Signers } from "./signers"; - -declare module "mocha" { - export interface Context { - signers: Signers; - contractAddress: string; - instances: FhevmInstances; - erc20: EncryptedERC20; - blindAuction: BlindAuction; - rand: Rand; - identityRegistry: IdentityRegistry; - identifiedErc20: IdentifiedERC20; - comp: Comp; - governor: GovernorZama; - } -} - -export interface FhevmInstances { - alice: FhevmInstance; - bob: FhevmInstance; - carol: FhevmInstance; - dave: FhevmInstance; - eve: FhevmInstance; -}