diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3e3b6004..932efd6d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -22,7 +22,7 @@ jobs: - run: source .env && npx hardhat task:computeTFHEExecutorAddress --private-key $PRIVATE_KEY_FHEVM_DEPLOYER - run: source .env && npx hardhat task:computeKMSVerifierAddress --private-key $PRIVATE_KEY_FHEVM_DEPLOYER - run: source .env && npx hardhat task:computeInputVerifierAddress --private-key $PRIVATE_KEY_FHEVM_DEPLOYER --use-address false - - run: source .env && npx hardhat task:computeFHEPaymentAddress --private-key $PRIVATE_KEY_FHEVM_DEPLOYER + - run: source .env && npx hardhat task:computeFHEGasLimitAddress --private-key $PRIVATE_KEY_FHEVM_DEPLOYER - run: npm run compile - uses: JS-DevTools/npm-publish@19c28f1ef146469e409470805ea4279d47c3d35c # v3.1.1 with: diff --git a/.github/workflows/publishprerelease.yml b/.github/workflows/publishprerelease.yml index 505b8d61..b52e624d 100644 --- a/.github/workflows/publishprerelease.yml +++ b/.github/workflows/publishprerelease.yml @@ -22,7 +22,7 @@ jobs: - run: source .env && npx hardhat task:computeTFHEExecutorAddress --private-key $PRIVATE_KEY_FHEVM_DEPLOYER - run: source .env && npx hardhat task:computeKMSVerifierAddress --private-key $PRIVATE_KEY_FHEVM_DEPLOYER - run: source .env && npx hardhat task:computeInputVerifierAddress --private-key $PRIVATE_KEY_FHEVM_DEPLOYER --use-address false - - run: source .env && npx hardhat task:computeFHEPaymentAddress --private-key $PRIVATE_KEY_FHEVM_DEPLOYER + - run: source .env && npx hardhat task:computeFHEGasLimitAddress --private-key $PRIVATE_KEY_FHEVM_DEPLOYER - run: npm run compile - uses: JS-DevTools/npm-publish@19c28f1ef146469e409470805ea4279d47c3d35c # v3.1.1 with: diff --git a/codegen/main.ts b/codegen/main.ts index 4f6bd15e..94799a8d 100644 --- a/codegen/main.ts +++ b/codegen/main.ts @@ -11,7 +11,6 @@ function generateAllFiles() { const ovShards = testgen.splitOverloadsToShards(overloads); writeFileSync('lib/Impl.sol', t.implSol(operators)); writeFileSync('lib/TFHE.sol', tfheSolSource); - writeFileSync('payment/Payment.sol', t.paymentSol()); mkdirSync('examples/tests', { recursive: true }); ovShards.forEach((os) => { writeFileSync(`examples/tests/TFHETestSuite${os.shardNumber}.sol`, testgen.generateSmartContract(os)); diff --git a/codegen/templates.ts b/codegen/templates.ts index bc05d2d4..2f460a9b 100644 --- a/codegen/templates.ts +++ b/codegen/templates.ts @@ -69,6 +69,7 @@ export function implSol(operators: Operator[]): string { const coprocessorInterface = generateImplCoprocessorInterface(operators); const aclInterface = generateACLInterface(); + const inputVerifierInterface = generateInputVerifierInterface(); res.push(` // SPDX-License-Identifier: BSD-3-Clause-Clear @@ -80,6 +81,8 @@ ${coprocessorInterface} ${aclInterface} +${inputVerifierInterface} + /** * @title Impl * @notice This library is the core implementation for computing FHE operations (e.g. add, sub, xor). @@ -98,8 +101,8 @@ library Impl { FHEVMConfigStruct storage $ = getFHEVMConfig(); $.ACLAddress = fhevmConfig.ACLAddress; $.TFHEExecutorAddress = fhevmConfig.TFHEExecutorAddress; - $.FHEPaymentAddress = fhevmConfig.FHEPaymentAddress; $.KMSVerifierAddress = fhevmConfig.KMSVerifierAddress; + $.InputVerifierAddress = fhevmConfig.InputVerifierAddress; } `); @@ -172,8 +175,8 @@ function generateImplCoprocessorInterface(operators: Operator[]): string { struct FHEVMConfigStruct { address ACLAddress; address TFHEExecutorAddress; - address FHEPaymentAddress; address KMSVerifierAddress; + address InputVerifierAddress; } /** @@ -242,6 +245,14 @@ function generateACLInterface(): string { `; } +function generateInputVerifierInterface(): string { + return ` + interface IInputVerifier { + function cleanTransientStorage() external; + } + `; +} + export function tfheSol( operators: Operator[], supportedBits: number[], @@ -746,9 +757,11 @@ function tfheAclMethods(supportedBits: number[]): string { res.push( ` // cleans the transient storage of ACL containing all the allowedTransient accounts + // also cleans transient storage of InputVerifier containing cached inputProofs // to be used for integration with Account Abstraction or when bundling UserOps calling the FHEVMCoprocessor function cleanTransientStorage() internal { - return Impl.cleanTransientStorage(); + Impl.cleanTransientStorageACL(); + Impl.cleanTransientStorageInputVerifier(); } function isAllowed(ebool value, address account) internal view returns (bool) { @@ -1518,63 +1531,19 @@ function implCustomMethods(): string { IACL($.ACLAddress).allow(handle, account); } - function cleanTransientStorage() internal { + function cleanTransientStorageACL() internal { FHEVMConfigStruct storage $ = getFHEVMConfig(); IACL($.ACLAddress).cleanTransientStorage(); } + function cleanTransientStorageInputVerifier() internal { + FHEVMConfigStruct storage $ = getFHEVMConfig(); + IInputVerifier($.InputVerifierAddress).cleanTransientStorage(); + } + function isAllowed(uint256 handle, address account) internal view returns (bool) { FHEVMConfigStruct storage $ = getFHEVMConfig(); return IACL($.ACLAddress).isAllowed(handle, account); } `; } - -export function paymentSol(): string { - const res: string = `// SPDX-License-Identifier: BSD-3-Clause-Clear - -pragma solidity ^0.8.24; - -import "../lib/Impl.sol"; - -interface IFHEPayment { - function depositETH(address account) external payable; - function withdrawETH(uint256 amount, address receiver) external; - function getAvailableDepositsETH(address account) external view returns(uint256); -} - -library Payment { - function depositForAccount(address account, uint256 amount) internal { - FHEVMConfigStruct storage $ = Impl.getFHEVMConfig(); - IFHEPayment($.FHEPaymentAddress).depositETH{value: amount}(account); - } - - function depositForThis(uint256 amount) internal { - FHEVMConfigStruct storage $ = Impl.getFHEVMConfig(); - IFHEPayment($.FHEPaymentAddress).depositETH{value: amount}(address(this)); - } - - function withdrawToAccount(address account, uint256 amount) internal { - FHEVMConfigStruct storage $ = Impl.getFHEVMConfig(); - IFHEPayment($.FHEPaymentAddress).withdrawETH(amount, account); - } - - function withdrawToThis(uint256 amount) internal { - FHEVMConfigStruct storage $ = Impl.getFHEVMConfig(); - IFHEPayment($.FHEPaymentAddress).withdrawETH(amount, address(this)); - } - - function getDepositedBalanceOfAccount(address account) internal view returns (uint256) { - FHEVMConfigStruct storage $ = Impl.getFHEVMConfig(); - return IFHEPayment($.FHEPaymentAddress).getAvailableDepositsETH(account); - } - - function getDepositedBalanceOfThis() internal view returns (uint256) { - FHEVMConfigStruct storage $ = Impl.getFHEVMConfig(); - return IFHEPayment($.FHEPaymentAddress).getAvailableDepositsETH(address(this)); - } - } - `; - - return res; -} diff --git a/config/ZamaFHEVMConfig.sol b/config/ZamaFHEVMConfig.sol index 62b95609..b563d213 100644 --- a/config/ZamaFHEVMConfig.sol +++ b/config/ZamaFHEVMConfig.sol @@ -8,7 +8,7 @@ import {FHEVMConfigStruct} from "../lib/Impl.sol"; * @title ZamaFHEVMConfig. * @notice This library returns the TFHE config for different networks * with the contract addresses for - * (1) ACL, (2) TFHEExecutor, (3) FHEPayment, (4) KMSVerifier, + * (1) ACL, (2) TFHEExecutor, (3) KMSVerifier, (4) InputVerifier * which are deployed & maintained by Zama. */ library ZamaFHEVMConfig { @@ -17,8 +17,8 @@ library ZamaFHEVMConfig { FHEVMConfigStruct({ ACLAddress: 0xFee8407e2f5e3Ee68ad77cAE98c434e637f516e5, TFHEExecutorAddress: 0x687408aB54661ba0b4aeF3a44156c616c6955E07, - FHEPaymentAddress: 0xFb03BE574d14C256D56F09a198B586bdfc0A9de2, - KMSVerifierAddress: 0x9D6891A6240D6130c54ae243d8005063D05fE14b + KMSVerifierAddress: 0x9D6891A6240D6130c54ae243d8005063D05fE14b, + InputVerifierAddress: 0x3a2DA6f1daE9eF988B48d9CF27523FA31a8eBE50 }); } diff --git a/docs/guides/gas.md b/docs/guides/gas.md index 89079dbc..03157014 100644 --- a/docs/guides/gas.md +++ b/docs/guides/gas.md @@ -14,7 +14,7 @@ FHE operations in fhEVM are computationally intensive, resulting in higher gas c 2. **FHEGas**: - Represents gas consumed by FHE-specific computations. - A new synthetic kind of gas consumed by FHE-specific computations. - - FHEGas is tracked in each block by the FHEPayment contract to prevent DDOS attacks. + - FHEGas is tracked in each block by the FHEGasLimit contract to prevent DDOS attacks. - If too many FHE operations are requested in the same block, the transaction will revert once the FHEGas block limit is reached. - FHEGas is consistent across both mocked and real fhEVM environments. diff --git a/examples/FHEVMConfig.sol b/examples/FHEVMConfig.sol index 21a70742..4f6c0999 100644 --- a/examples/FHEVMConfig.sol +++ b/examples/FHEVMConfig.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.24; import "fhevm-core-contracts/addresses/ACLAddress.sol"; -import "fhevm-core-contracts/addresses/FHEPaymentAddress.sol"; +import "fhevm-core-contracts/addresses/InputVerifierAddress.sol"; import "fhevm-core-contracts/addresses/KMSVerifierAddress.sol"; import "fhevm-core-contracts/addresses/TFHEExecutorAddress.sol"; import "../lib/Impl.sol"; /** * @title FHEVMConfig - * @notice This library returns all addresses for the ACL, TFHEExecutor, FHEPayment, + * @notice This library returns all addresses for the ACL, TFHEExecutor, InputVerifier, * and KMSVerifier contracts. */ library FHEVMConfig { @@ -22,8 +22,8 @@ library FHEVMConfig { FHEVMConfigStruct({ ACLAddress: aclAdd, TFHEExecutorAddress: tfheExecutorAdd, - FHEPaymentAddress: fhePaymentAdd, - KMSVerifierAddress: kmsVerifierAdd + KMSVerifierAddress: kmsVerifierAdd, + InputVerifierAddress: inputVerifierAdd }); } } diff --git a/examples/GatewayConfig.sol b/examples/GatewayConfig.sol index 842c2060..04b3b7bf 100644 --- a/examples/GatewayConfig.sol +++ b/examples/GatewayConfig.sol @@ -5,13 +5,11 @@ import "fhevm-core-contracts/addresses/GatewayContractAddress.sol"; /** * @title FHEVMConfig - * @notice This library returns all addresses for the ACL, TFHEExecutor, FHEPayment, - * and KMSVerifier contracts. + * @notice This library returns the GatewayContract address */ library GatewayConfig { /** - * @notice This function returns a struct containing all contract addresses. - * @dev It returns an immutable struct. + * @notice This function returns a the gateway contract address. */ function defaultGatewayContract() internal pure returns (address) { return GATEWAY_CONTRACT_PREDEPLOY_ADDRESS; diff --git a/examples/PaymentLimit.sol b/examples/PaymentLimit.sol index 9af13f1f..3286b8eb 100644 --- a/examples/PaymentLimit.sol +++ b/examples/PaymentLimit.sol @@ -4,17 +4,14 @@ pragma solidity ^0.8.24; import "../lib/TFHE.sol"; import "./FHEVMConfig.sol"; -import "@openzeppelin/contracts/access/Ownable2Step.sol"; -import "../payment/Payment.sol"; /// @title PaymentLimit /// @notice A contract to demonstrate FHE gas limits in different scenarios contract PaymentLimit { /// @notice Constructor that sets up FHE configuration and deposits initial value /// @dev Payable to allow initial deposit - constructor() payable { + constructor() { TFHE.setFHEVM(FHEVMConfig.defaultConfig()); - Payment.depositForThis(msg.value); } /// @notice Performs a small number of FHE operations diff --git a/hardhat.config.ts b/hardhat.config.ts index 177b8a73..8aa07169 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -103,7 +103,7 @@ task('test', async (_taskArgs, hre, runSuper) => { 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('task:computeFHEGasLimitAddress', { privateKey: privKeyFhevmDeployer }); const sourceDir = path.resolve(__dirname, 'node_modules/fhevm-core-contracts/contracts'); const destinationDir = path.resolve(__dirname, 'fhevmTemp/contracts'); fs.copySync(sourceDir, destinationDir, { dereference: true }); @@ -123,7 +123,7 @@ task('test', async (_taskArgs, hre, runSuper) => { 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:deployFHEGasLimit', { privateKey: privKeyFhevmDeployer }); await hre.run('task:addSigners', { numSigners: process.env.NUM_KMS_SIGNERS!, privateKey: privKeyFhevmDeployer, diff --git a/lib/Impl.sol b/lib/Impl.sol index f55640d7..feeda955 100644 --- a/lib/Impl.sol +++ b/lib/Impl.sol @@ -10,8 +10,8 @@ import "./TFHE.sol"; struct FHEVMConfigStruct { address ACLAddress; address TFHEExecutorAddress; - address FHEPaymentAddress; address KMSVerifierAddress; + address InputVerifierAddress; } /** @@ -70,6 +70,10 @@ interface IACL { function allowForDecryption(uint256[] memory handlesList) external; } +interface IInputVerifier { + function cleanTransientStorage() external; +} + /** * @title Impl * @notice This library is the core implementation for computing FHE operations (e.g. add, sub, xor). @@ -88,8 +92,8 @@ library Impl { FHEVMConfigStruct storage $ = getFHEVMConfig(); $.ACLAddress = fhevmConfig.ACLAddress; $.TFHEExecutorAddress = fhevmConfig.TFHEExecutorAddress; - $.FHEPaymentAddress = fhevmConfig.FHEPaymentAddress; $.KMSVerifierAddress = fhevmConfig.KMSVerifierAddress; + $.InputVerifierAddress = fhevmConfig.InputVerifierAddress; } function add(uint256 lhs, uint256 rhs, bool scalar) internal returns (uint256 result) { @@ -387,11 +391,16 @@ library Impl { IACL($.ACLAddress).allow(handle, account); } - function cleanTransientStorage() internal { + function cleanTransientStorageACL() internal { FHEVMConfigStruct storage $ = getFHEVMConfig(); IACL($.ACLAddress).cleanTransientStorage(); } + function cleanTransientStorageInputVerifier() internal { + FHEVMConfigStruct storage $ = getFHEVMConfig(); + IInputVerifier($.InputVerifierAddress).cleanTransientStorage(); + } + function isAllowed(uint256 handle, address account) internal view returns (bool) { FHEVMConfigStruct storage $ = getFHEVMConfig(); return IACL($.ACLAddress).isAllowed(handle, account); diff --git a/lib/TFHE.sol b/lib/TFHE.sol index de2f4e3d..1f59cc0d 100644 --- a/lib/TFHE.sol +++ b/lib/TFHE.sol @@ -10849,9 +10849,11 @@ library TFHE { } // cleans the transient storage of ACL containing all the allowedTransient accounts + // also cleans transient storage of InputVerifier containing cached inputProofs // to be used for integration with Account Abstraction or when bundling UserOps calling the FHEVMCoprocessor function cleanTransientStorage() internal { - return Impl.cleanTransientStorage(); + Impl.cleanTransientStorageACL(); + Impl.cleanTransientStorageInputVerifier(); } function isAllowed(ebool value, address account) internal view returns (bool) { diff --git a/package-lock.json b/package-lock.json index 345ac8c2..f82cbecb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", "ethers": "^6.8.0", - "fhevm-core-contracts": "0.6.1", + "fhevm-core-contracts": "0.7.0-0", "fhevmjs": "^0.6.0-8", "hardhat": "^2.22.10", "hardhat-deploy": "^0.11.29", @@ -6110,9 +6110,9 @@ } }, "node_modules/fhevm-core-contracts": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/fhevm-core-contracts/-/fhevm-core-contracts-0.6.1.tgz", - "integrity": "sha512-lZsnuEgLsGME5LPPhwAHyXUuURqP6Lp2orA7pH32ybSGo8ZJe9cmyL84uQk3bUGn2mGG+8rU8KZ8FGR5sWfhdA==", + "version": "0.7.0-0", + "resolved": "https://registry.npmjs.org/fhevm-core-contracts/-/fhevm-core-contracts-0.7.0-0.tgz", + "integrity": "sha512-iVQi1phRoX9Ht3NE7T+fcZ/N/sASuqsTWa25pKBSbzCIzZ6Reajp+t5/B1tmAsf+MIsaI/zFAv/79W3XlfybmA==", "dev": true }, "node_modules/fhevmjs": { diff --git a/package.json b/package.json index 2c8bd428..a717fe6b 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "eslint-config-prettier": "^8.5.0", "ethers": "^6.8.0", "fhevmjs": "^0.6.0-8", - "fhevm-core-contracts": "0.6.1", + "fhevm-core-contracts": "0.7.0-0", "hardhat": "^2.22.10", "hardhat-deploy": "^0.11.29", "hardhat-gas-reporter": "^1.0.2", diff --git a/payment/Payment.sol b/payment/Payment.sol deleted file mode 100644 index e68acb7c..00000000 --- a/payment/Payment.sol +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause-Clear - -pragma solidity ^0.8.24; - -import "../lib/Impl.sol"; - -interface IFHEPayment { - function depositETH(address account) external payable; - function withdrawETH(uint256 amount, address receiver) external; - function getAvailableDepositsETH(address account) external view returns (uint256); -} - -library Payment { - function depositForAccount(address account, uint256 amount) internal { - FHEVMConfigStruct storage $ = Impl.getFHEVMConfig(); - IFHEPayment($.FHEPaymentAddress).depositETH{value: amount}(account); - } - - function depositForThis(uint256 amount) internal { - FHEVMConfigStruct storage $ = Impl.getFHEVMConfig(); - IFHEPayment($.FHEPaymentAddress).depositETH{value: amount}(address(this)); - } - - function withdrawToAccount(address account, uint256 amount) internal { - FHEVMConfigStruct storage $ = Impl.getFHEVMConfig(); - IFHEPayment($.FHEPaymentAddress).withdrawETH(amount, account); - } - - function withdrawToThis(uint256 amount) internal { - FHEVMConfigStruct storage $ = Impl.getFHEVMConfig(); - IFHEPayment($.FHEPaymentAddress).withdrawETH(amount, address(this)); - } - - function getDepositedBalanceOfAccount(address account) internal view returns (uint256) { - FHEVMConfigStruct storage $ = Impl.getFHEVMConfig(); - return IFHEPayment($.FHEPaymentAddress).getAvailableDepositsETH(account); - } - - function getDepositedBalanceOfThis() internal view returns (uint256) { - FHEVMConfigStruct storage $ = Impl.getFHEVMConfig(); - return IFHEPayment($.FHEPaymentAddress).getAvailableDepositsETH(address(this)); - } -} diff --git a/tasks/taskDeploy.ts b/tasks/taskDeploy.ts index 03029ff5..d35faa7f 100644 --- a/tasks/taskDeploy.ts +++ b/tasks/taskDeploy.ts @@ -110,24 +110,24 @@ task('task:deployInputVerifier') console.log('InputVerifier was deployed at address:', address); }); -task('task:deployFHEPayment') +task('task:deployFHEGasLimit') .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 factory = await ethers.getContractFactory('fhevmTemp/contracts/FHEGasLimit.sol:FHEGasLimit', 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')); + const envConfig = dotenv.parse(fs.readFileSync('node_modules/fhevm-core-contracts/addresses/.env.fhegaslimit')); 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); + console.log('FHEGasLimit was deployed at address:', address); }); task('task:addSigners') diff --git a/tasks/taskTFHE.ts b/tasks/taskTFHE.ts index d27d5e26..16f1de25 100644 --- a/tasks/taskTFHE.ts +++ b/tasks/taskTFHE.ts @@ -179,36 +179,36 @@ address constant coprocessorAdd = ${coprocAddress};\n`; } }); -task('task:computeFHEPaymentAddress') +task('task:computeFHEGasLimitAddress') .addParam('privateKey', 'The deployer private key') .setAction(async function (taskArguments: TaskArguments, { ethers }) { const deployer = new ethers.Wallet(taskArguments.privateKey).address; - const fhePaymentAddress = ethers.getCreateAddress({ + const fheGasLimitAddress = ethers.getCreateAddress({ from: deployer, - nonce: 9, // using nonce of 9 for the FHEPayment contract (8 for original implementation, +1 for proxy) + nonce: 9, // using nonce of 9 for the FHEGasLimit 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`; + const envFilePath = path.join(__dirname, '../node_modules/fhevm-core-contracts/addresses/.env.fhegaslimit'); + const content = `FHE_PAYMENT_CONTRACT_ADDRESS=${fheGasLimitAddress}\n`; try { fs.writeFileSync(envFilePath, content, { flag: 'w' }); - console.log(`FHEPayment address ${fhePaymentAddress} written successfully!`); + console.log(`FHEGasLimit address ${fheGasLimitAddress} written successfully!`); } catch (err) { - console.error('Failed to write FHEPayment address:', err); + console.error('Failed to write FHEGasLimit address:', err); } const solidityTemplate = `// SPDX-License-Identifier: BSD-3-Clause-Clear pragma solidity ^0.8.24; -address constant fhePaymentAdd = ${fhePaymentAddress};\n`; +address constant fheGasLimitAdd = ${fheGasLimitAddress};\n`; try { - fs.writeFileSync('./node_modules/fhevm-core-contracts/addresses/FHEPaymentAddress.sol', solidityTemplate, { + fs.writeFileSync('./node_modules/fhevm-core-contracts/addresses/FHEGasLimitAddress.sol', solidityTemplate, { encoding: 'utf8', flag: 'w', }); - console.log('./node_modules/fhevm-core-contracts/addresses/FHEPaymentAddress.sol file generated successfully!'); + console.log('./node_modules/fhevm-core-contracts/addresses/FHEGasLimitAddress.sol file generated successfully!'); } catch (error) { - console.error('Failed to write ./node_modules/fhevm-core-contracts/addresses/FHEPaymentAddress.sol', error); + console.error('Failed to write ./node_modules/fhevm-core-contracts/addresses/FHEGasLimitAddress.sol', error); } }); diff --git a/test/coprocessorUtils.ts b/test/coprocessorUtils.ts index 114f2749..f1860a75 100644 --- a/test/coprocessorUtils.ts +++ b/test/coprocessorUtils.ts @@ -1012,8 +1012,8 @@ const abi = [ '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)', + 'event FheRand(bytes1 randType, bytes16 seed, uint256 result)', + 'event FheRandBounded(uint256 upperBound, bytes1 randType, bytes16 seed, uint256 result)', ]; async function processAllPastTFHEExecutorEvents() { @@ -1444,7 +1444,7 @@ async function insertHandleFromEvent(event: FHEVMEvent) { case 'FheRand': resultType = parseInt(event.args[0], 16); - handle = ethers.toBeHex(event.args[1], 32); + handle = ethers.toBeHex(event.args[2], 32); clearText = getRandomBigInt(Number(NumBits[resultType])); insertSQL(handle, clearText, true); counterRand++; @@ -1452,7 +1452,7 @@ async function insertHandleFromEvent(event: FHEVMEvent) { case 'FheRandBounded': resultType = parseInt(event.args[1], 16); - handle = ethers.toBeHex(event.args[2], 32); + handle = ethers.toBeHex(event.args[3], 32); clearText = getRandomBigInt(Number(log2(BigInt(event.args[0])))); insertSQL(handle, clearText, true); counterRand++; diff --git a/test/kmsVerifier/kmsVerifier.ts b/test/kmsVerifier/kmsVerifier.ts index eda8499c..2e998b83 100644 --- a/test/kmsVerifier/kmsVerifier.ts +++ b/test/kmsVerifier/kmsVerifier.ts @@ -44,8 +44,9 @@ describe('KMSVerifier', function () { expect(y).to.equal(true); // in this case, one signature still suffices to pass the decrypt (threshold is still 1) const kmsSignerDup = new ethers.Wallet(privKeySigner).connect(ethers.provider); - await expect(kmsVerifier.connect(deployer).addSigner(kmsSignerDup.address)).to.revertedWith( - 'KMSVerifier: Address is already a signer', + await expect(kmsVerifier.connect(deployer).addSigner(kmsSignerDup.address)).to.revertedWithCustomError( + kmsVerifier, + 'KMSAlreadySigner', ); // cannot add duplicated signer expect((await kmsVerifier.getSigners()).length).to.equal(2); @@ -61,9 +62,9 @@ describe('KMSVerifier', function () { const tx5 = await contract.requestUint4({ gasLimit: 5_000_000 }); await tx5.wait(); - await expect(awaitAllDecryptionResults()).to.revertedWith( - 'KmsVerifier: at least threshold number of signatures required', - ); // should revert because now we are below the threshold! (we receive only 1 signature but threshold is 2) + await expect(awaitAllDecryptionResults()) + .to.revertedWithCustomError(kmsVerifier, 'KMSSignatureThresholdNotReached') + .withArgs(1n); // should revert because now we are below the threshold! (we receive only 1 signature but threshold is 2) const y2 = await contract.yUint4(); expect(y2).to.equal(0); @@ -92,7 +93,9 @@ describe('KMSVerifier', function () { contract2.requestMixedBytes256Trustless(encryptedAmount2.handles[0], encryptedAmount2.inputProof, { gasLimit: 5_000_000, }), - ).to.revertedWith('KmsVerifier: at least threshold number of signatures required'); // this should fail because in this case the InputVerifier received only one KMS signature (instead of at least 2); + ) + .to.revertedWithCustomError(kmsVerifier, 'KMSSignatureThresholdNotReached') + .withArgs(1n); // this should fail because in this case the InputVerifier received only one KMS signature (instead of at least 2); if (process.env.IS_COPROCESSOR === 'true') { // different format of inputProof for native diff --git a/test/paymentUtils.ts b/test/paymentUtils.ts index 893a2233..66d7023a 100644 --- a/test/paymentUtils.ts +++ b/test/paymentUtils.ts @@ -2,11 +2,13 @@ import dotenv from 'dotenv'; import fs from 'fs'; import { ethers } from 'hardhat'; -export async function initializeFHEPayment() { - const fhePaymentFactory = await ethers.getContractFactory('fhevmTemp/contracts/FHEPayment.sol:FHEPayment'); - const parsedFHEPayment = dotenv.parse(fs.readFileSync('node_modules/fhevm-core-contracts/addresses/.env.fhepayment')); - const fhePayment = fhePaymentFactory.attach(parsedFHEPayment.FHE_PAYMENT_CONTRACT_ADDRESS); - return fhePayment; +export async function initializeFHEGasLimit() { + const fheGasLimitFactory = await ethers.getContractFactory('fhevmTemp/contracts/FHEGasLimit.sol:FHEGasLimit'); + const parsedFHEGasLimit = dotenv.parse( + fs.readFileSync('node_modules/fhevm-core-contracts/addresses/.env.fhegaslimit'), + ); + const fheGasLimit = fheGasLimitFactory.attach(parsedFHEGasLimit.FHE_PAYMENT_CONTRACT_ADDRESS); + return fheGasLimit; } export const FHE_GASPRICE_NATIVE_RATIO = 0n; // 1000n; diff --git a/test/payments/payments.ts b/test/payments/payments.ts index 435737f4..b509749c 100644 --- a/test/payments/payments.ts +++ b/test/payments/payments.ts @@ -2,14 +2,14 @@ import { expect } from 'chai'; import { ethers } from 'hardhat'; import { createInstances } from '../instance'; -import { FHE_GASPRICE_NATIVE_RATIO, MIN_FHE_GASPRICE, initializeFHEPayment } from '../paymentUtils'; +import { FHE_GASPRICE_NATIVE_RATIO, MIN_FHE_GASPRICE, initializeFHEGasLimit } from '../paymentUtils'; import { getSigners, initSigners } from '../signers'; -describe('TestFHEPayment', function () { +describe('TestFHEGasLimit', function () { before(async function () { await initSigners(2); this.signers = await getSigners(); - this.fhePayment = await initializeFHEPayment(); + this.fheGasLimit = await initializeFHEGasLimit(); }); beforeEach(async function () { @@ -24,7 +24,7 @@ describe('TestFHEPayment', function () { value: ethers.parseEther('0'), // don't fund contract }); await contract.waitForDeployment(); - await expect(contract.mint(1000)).to.be.revertedWithCustomError(this.fhePayment, 'AccountNotEnoughFunded'); + await expect(contract.mint(1000)).to.be.revertedWithCustomError(this.fheGasLimit, 'AccountNotEnoughFunded'); } }); @@ -35,13 +35,13 @@ describe('TestFHEPayment', function () { const contract = await contractFactory.connect(this.signers.alice).deploy('Naraggara', 'NARA', { value: ethers.parseEther('0.001'), }); - const initialDeposit = await this.fhePayment.getAvailableDepositsETH(await contract.getAddress()); + const initialDeposit = await this.fheGasLimit.getAvailableDepositsETH(await contract.getAddress()); await contract.waitForDeployment(); const tx = await contract.mint(1000n); const rcpt = await tx.wait(); const ratioGas = (rcpt!.gasPrice * FHE_GASPRICE_NATIVE_RATIO) / 1_000_000n; const effectiveFheGasPrice = ratioGas > MIN_FHE_GASPRICE ? ratioGas : MIN_FHE_GASPRICE; - const remainingDeposit = await this.fhePayment.getAvailableDepositsETH(await contract.getAddress()); + const remainingDeposit = await this.fheGasLimit.getAvailableDepositsETH(await contract.getAddress()); const consumedFheGas = (initialDeposit - remainingDeposit) / effectiveFheGasPrice; expect(consumedFheGas).to.equal(188000n + 600n); // scalarFheAdd(euint64) + trivialEncrypt(euint64) } @@ -55,16 +55,16 @@ describe('TestFHEPayment', function () { value: ethers.parseEther('0'), // don't fund contract }); await contract.waitForDeployment(); - const tx = await this.fhePayment.depositETH(this.signers.alice, { value: ethers.parseEther('0.001') }); + const tx = await this.fheGasLimit.depositETH(this.signers.alice, { value: ethers.parseEther('0.001') }); await tx.wait(); - const initialDeposit = await this.fhePayment.getAvailableDepositsETH(this.signers.alice); - const txbis = await this.fhePayment.whitelistContract(contract); + const initialDeposit = await this.fheGasLimit.getAvailableDepositsETH(this.signers.alice); + const txbis = await this.fheGasLimit.whitelistContract(contract); await txbis.wait(); const tx2 = await contract.mint(1000); const rcpt = await tx2.wait(); const ratioGas = (rcpt!.gasPrice * FHE_GASPRICE_NATIVE_RATIO) / 1_000_000n; const effectiveFheGasPrice = ratioGas > MIN_FHE_GASPRICE ? ratioGas : MIN_FHE_GASPRICE; - const remainingDeposit = await this.fhePayment.getAvailableDepositsETH(this.signers.alice); + const remainingDeposit = await this.fheGasLimit.getAvailableDepositsETH(this.signers.alice); const consumedFheGas = (initialDeposit - remainingDeposit) / effectiveFheGasPrice; expect(consumedFheGas).to.equal(188000n + 600n); // scalarFheAdd(euint64) + trivialEncrypt(euint64) } @@ -78,16 +78,16 @@ describe('TestFHEPayment', function () { value: ethers.parseEther('0'), // don't fund contract }); await contract.waitForDeployment(); - const tx = await this.fhePayment.depositETH(this.signers.alice, { value: ethers.parseEther('0.001') }); + const tx = await this.fheGasLimit.depositETH(this.signers.alice, { value: ethers.parseEther('0.001') }); await tx.wait(); - const initialDeposit = await this.fhePayment.getAvailableDepositsETH(this.signers.alice); - const txbis = await this.fhePayment.authorizeAllContracts(contract); + const initialDeposit = await this.fheGasLimit.getAvailableDepositsETH(this.signers.alice); + const txbis = await this.fheGasLimit.authorizeAllContracts(contract); await txbis.wait(); const tx2 = await contract.mint(1000); const rcpt = await tx2.wait(); const ratioGas = (rcpt!.gasPrice * FHE_GASPRICE_NATIVE_RATIO) / 1_000_000n; const effectiveFheGasPrice = ratioGas > MIN_FHE_GASPRICE ? ratioGas : MIN_FHE_GASPRICE; - const remainingDeposit = await this.fhePayment.getAvailableDepositsETH(this.signers.alice); + const remainingDeposit = await this.fheGasLimit.getAvailableDepositsETH(this.signers.alice); const consumedFheGas = (initialDeposit - remainingDeposit) / effectiveFheGasPrice; expect(consumedFheGas).to.equal(188000n + 600n); // scalarFheAdd(euint64) + trivialEncrypt(euint64) } @@ -101,13 +101,13 @@ describe('TestFHEPayment', function () { value: ethers.parseEther('0'), // don't fund contract }); await contract.waitForDeployment(); - const tx = await this.fhePayment.depositETH(this.signers.alice, { value: ethers.parseEther('0.001') }); + const tx = await this.fheGasLimit.depositETH(this.signers.alice, { value: ethers.parseEther('0.001') }); await tx.wait(); - const initialDeposit = await this.fhePayment.getAvailableDepositsETH(this.signers.alice); - const txbis = await this.fhePayment.removeAuthorizationAllContracts(); + const initialDeposit = await this.fheGasLimit.getAvailableDepositsETH(this.signers.alice); + const txbis = await this.fheGasLimit.removeAuthorizationAllContracts(); await txbis.wait(); - await expect(contract.mint(1000)).to.be.revertedWithCustomError(this.fhePayment, 'AccountNotEnoughFunded'); - const remainingDeposit = await this.fhePayment.getAvailableDepositsETH(this.signers.alice); + await expect(contract.mint(1000)).to.be.revertedWithCustomError(this.fheGasLimit, 'AccountNotEnoughFunded'); + const remainingDeposit = await this.fheGasLimit.getAvailableDepositsETH(this.signers.alice); expect(remainingDeposit).to.equal(initialDeposit); } }); @@ -118,14 +118,14 @@ describe('TestFHEPayment', function () { const contractFactory = await ethers.getContractFactory('PaymentLimit'); const contract = await contractFactory.connect(this.signers.alice).deploy(); await contract.waitForDeployment(); - const initialDeposit = await this.fhePayment.getAvailableDepositsETH(this.signers.alice); - const txbis = await this.fhePayment.authorizeAllContracts(); + const initialDeposit = await this.fheGasLimit.getAvailableDepositsETH(this.signers.alice); + const txbis = await this.fheGasLimit.authorizeAllContracts(); await txbis.wait(); const tx2 = await contract.underBlockFHEGasLimit(); const rcpt = await tx2.wait(); const ratioGas = (rcpt!.gasPrice * FHE_GASPRICE_NATIVE_RATIO) / 1_000_000n; const effectiveFheGasPrice = ratioGas > MIN_FHE_GASPRICE ? ratioGas : MIN_FHE_GASPRICE; - const remainingDeposit = await this.fhePayment.getAvailableDepositsETH(this.signers.alice); + const remainingDeposit = await this.fheGasLimit.getAvailableDepositsETH(this.signers.alice); const consumedFheGas = (initialDeposit - remainingDeposit) / effectiveFheGasPrice; expect(consumedFheGas).to.equal(15n * 641000n + 2n * 600n); // 15*FheMul(euint64) + 2*trivialEncrypt(euint64) } @@ -135,7 +135,10 @@ describe('TestFHEPayment', function () { const contractFactory = await ethers.getContractFactory('PaymentLimit'); const contract = await contractFactory.connect(this.signers.alice).deploy(); await contract.waitForDeployment(); - await expect(contract.aboveBlockFHEGasLimit()).revertedWithCustomError(this.fhePayment, 'FHEGasBlockLimitExceeded'); + await expect(contract.aboveBlockFHEGasLimit()).revertedWithCustomError( + this.fheGasLimit, + 'FHEGasBlockLimitExceeded', + ); }); it('a smart account becomes spender by calling becomeTransientSpender', async function () { @@ -144,12 +147,12 @@ describe('TestFHEPayment', function () { const contractFactory = await ethers.getContractFactory('SmartAccount'); const smartAccount = await contractFactory.connect(this.signers.bob).deploy(); await smartAccount.waitForDeployment(); - const tx = await this.fhePayment + const tx = await this.fheGasLimit .connect(this.signers.bob) .depositETH(await smartAccount.getAddress(), { value: ethers.parseEther('0.001') }); await tx.wait(); - const initialDeposit = await this.fhePayment.getAvailableDepositsETH(await smartAccount.getAddress()); + const initialDeposit = await this.fheGasLimit.getAvailableDepositsETH(await smartAccount.getAddress()); const contractFactory2 = await ethers.getContractFactory('PaymentLimit'); const contract = await contractFactory2.connect(this.signers.alice).deploy(); @@ -157,8 +160,8 @@ describe('TestFHEPayment', function () { const allowTx = [ { - target: await this.fhePayment.getAddress(), - data: this.fhePayment.interface.encodeFunctionData('authorizeAllContracts'), + target: await this.fheGasLimit.getAddress(), + data: this.fheGasLimit.interface.encodeFunctionData('authorizeAllContracts'), value: 0, }, ]; @@ -168,8 +171,8 @@ describe('TestFHEPayment', function () { const FHETx = [ { - target: await this.fhePayment.getAddress(), - data: this.fhePayment.interface.encodeFunctionData('becomeTransientSpender'), + target: await this.fheGasLimit.getAddress(), + data: this.fheGasLimit.interface.encodeFunctionData('becomeTransientSpender'), value: 0, }, { @@ -185,7 +188,7 @@ describe('TestFHEPayment', function () { const rcpt = await txSmartFHE.wait(); const ratioGas = (rcpt!.gasPrice * FHE_GASPRICE_NATIVE_RATIO) / 1_000_000n; const effectiveFheGasPrice = ratioGas > MIN_FHE_GASPRICE ? ratioGas : MIN_FHE_GASPRICE; - const remainingDeposit = await this.fhePayment.getAvailableDepositsETH(await smartAccount.getAddress()); + const remainingDeposit = await this.fheGasLimit.getAvailableDepositsETH(await smartAccount.getAddress()); const consumedFheGas = (initialDeposit - remainingDeposit) / effectiveFheGasPrice; expect(consumedFheGas).to.equal(15n * 641000n + 2n * 600n); // 15*FheMul(euint64) + 2*trivialEncrypt(euint64) } @@ -197,7 +200,7 @@ describe('TestFHEPayment', function () { const contractFactory = await ethers.getContractFactory('SmartAccount'); const smartAccount = await contractFactory.connect(this.signers.bob).deploy(); await smartAccount.waitForDeployment(); - const tx = await this.fhePayment + const tx = await this.fheGasLimit .connect(this.signers.bob) .depositETH(await smartAccount.getAddress(), { value: ethers.parseEther('0.001') }); await tx.wait(); @@ -211,13 +214,15 @@ describe('TestFHEPayment', function () { .deploy({ value: ethers.parseEther('0.001') }); // sponsored dApp await contract2.waitForDeployment(); - const initialDepositSmartAccount = await this.fhePayment.getAvailableDepositsETH(await smartAccount.getAddress()); - const initialDepositSponsoredDapp = await this.fhePayment.getAvailableDepositsETH(await contract2.getAddress()); + const initialDepositSmartAccount = await this.fheGasLimit.getAvailableDepositsETH( + await smartAccount.getAddress(), + ); + const initialDepositSponsoredDapp = await this.fheGasLimit.getAvailableDepositsETH(await contract2.getAddress()); const allowTx = [ { - target: await this.fhePayment.getAddress(), - data: this.fhePayment.interface.encodeFunctionData('authorizeAllContracts'), + target: await this.fheGasLimit.getAddress(), + data: this.fheGasLimit.interface.encodeFunctionData('authorizeAllContracts'), value: 0, }, ]; @@ -227,8 +232,8 @@ describe('TestFHEPayment', function () { const FHETx = [ { - target: await this.fhePayment.getAddress(), - data: this.fhePayment.interface.encodeFunctionData('becomeTransientSpender'), + target: await this.fheGasLimit.getAddress(), + data: this.fheGasLimit.interface.encodeFunctionData('becomeTransientSpender'), value: 0, }, { @@ -237,8 +242,8 @@ describe('TestFHEPayment', function () { value: 0, }, { - target: await this.fhePayment.getAddress(), - data: this.fhePayment.interface.encodeFunctionData('stopBeingTransientSpender'), + target: await this.fheGasLimit.getAddress(), + data: this.fheGasLimit.interface.encodeFunctionData('stopBeingTransientSpender'), value: 0, }, { @@ -254,10 +259,12 @@ describe('TestFHEPayment', function () { const rcpt = await txSmartFHE.wait(); const ratioGas = (rcpt!.gasPrice * FHE_GASPRICE_NATIVE_RATIO) / 1_000_000n; const effectiveFheGasPrice = ratioGas > MIN_FHE_GASPRICE ? ratioGas : MIN_FHE_GASPRICE; - const remainingDepositSmartAccount = await this.fhePayment.getAvailableDepositsETH( + const remainingDepositSmartAccount = await this.fheGasLimit.getAvailableDepositsETH( await smartAccount.getAddress(), ); - const remainingDepositSponsoredDapp = await this.fhePayment.getAvailableDepositsETH(await contract2.getAddress()); + const remainingDepositSponsoredDapp = await this.fheGasLimit.getAvailableDepositsETH( + await contract2.getAddress(), + ); const consumedFheGasSmartAccount = (initialDepositSmartAccount - remainingDepositSmartAccount) / effectiveFheGasPrice; @@ -270,10 +277,10 @@ describe('TestFHEPayment', function () { it('user can withdraw his unburnt deposited funds', async function () { if (FHE_GASPRICE_NATIVE_RATIO !== 0n || MIN_FHE_GASPRICE !== 0n) { - const depositValue = await this.fhePayment.getAvailableDepositsETH(this.signers.alice); + const depositValue = await this.fheGasLimit.getAvailableDepositsETH(this.signers.alice); expect(depositValue).to.be.greaterThan(0); const balBobBefore = await ethers.provider.getBalance(this.signers.bob); - const tx = await this.fhePayment.withdrawETH(depositValue, this.signers.bob); + const tx = await this.fheGasLimit.withdrawETH(depositValue, this.signers.bob); await tx.wait(); const balBobAfter = await ethers.provider.getBalance(this.signers.bob); expect(balBobAfter - balBobBefore).to.equal(depositValue);