4. Test the FHEVM contract
Set up the FHEVM testing environment
1
Create a test script test/FHECounter.ts
test/FHECounter.tscd <your-project-root-directory>/testimport { FHECounter, FHECounter__factory } from "../types";
import { FhevmType } from "@fhevm/hardhat-plugin";
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
import { expect } from "chai";
import { ethers, fhevm } from "hardhat";
type Signers = {
deployer: HardhatEthersSigner;
alice: HardhatEthersSigner;
bob: HardhatEthersSigner;
};
async function deployFixture() {
const factory = (await ethers.getContractFactory("FHECounter")) as FHECounter__factory;
const fheCounterContract = (await factory.deploy()) as FHECounter;
const fheCounterContractAddress = await fheCounterContract.getAddress();
return { fheCounterContract, fheCounterContractAddress };
}
describe("FHECounter", function () {
let signers: Signers;
let fheCounterContract: FHECounter;
let fheCounterContractAddress: string;
before(async function () {
const ethSigners: HardhatEthersSigner[] = await ethers.getSigners();
signers = { deployer: ethSigners[0], alice: ethSigners[1], bob: ethSigners[2] };
});
beforeEach(async () => {
({ fheCounterContract, fheCounterContractAddress } = await deployFixture());
});
it("should be deployed", async function () {
console.log(`FHECounter has been deployed at address ${fheCounterContractAddress}`);
// Test the deployed address is valid
expect(ethers.isAddress(fheCounterContractAddress)).to.eq(true);
});
// it("count should be zero after deployment", async function () {
// const count = await counterContract.getCount();
// console.log(`Counter.getCount() === ${count}`);
// // Expect initial count to be 0 after deployment
// expect(count).to.eq(0);
// });
// it("increment the counter by 1", async function () {
// const countBeforeInc = await counterContract.getCount();
// const tx = await counterContract.connect(signers.alice).increment(1);
// await tx.wait();
// const countAfterInc = await counterContract.getCount();
// expect(countAfterInc).to.eq(countBeforeInc + 1n);
// });
// it("decrement the counter by 1", async function () {
// // First increment, count becomes 1
// let tx = await counterContract.connect(signers.alice).increment();
// await tx.wait();
// // Then decrement, count goes back to 0
// tx = await counterContract.connect(signers.alice).decrement(1);
// await tx.wait();
// const count = await counterContract.getCount();
// expect(count).to.eq(0);
// });
});What’s Different from Counter.ts?
Counter.ts?Test functions
1
Call the contract getCount() view function
getCount() view function// it("count should be zero after deployment", async function () {
// const count = await counterContract.getCount();
// console.log(`Counter.getCount() === ${count}`);
// // Expect initial count to be 0 after deployment
// expect(count).to.eq(0);
// });it("encrypted count should be uninitialized after deployment", async function () {
const encryptedCount = await fheCounterContract.getCount();
// Expect initial count to be bytes32(0) after deployment,
// (meaning the encrypted count value is uninitialized)
expect(encryptedCount).to.eq(ethers.ZeroHash);
});npx hardhat test Counter
Counter has been deployed at address 0x7553CB9124f974Ee475E5cE45482F90d5B6076BC
✔ should be deployed
✔ encrypted count should be uninitialized after deployment
2 passing (7ms)2
Setup the increment() function unit test
increment() function unit test// it("increment the counter by 1", async function () {
// const countBeforeInc = await counterContract.getCount();
// const tx = await counterContract.connect(signers.alice).increment(1);
// await tx.wait();
// const countAfterInc = await counterContract.getCount();
// expect(countAfterInc).to.eq(countBeforeInc + 1n);
// });it("increment the counter by 1", async function () {
const encryptedCountBeforeInc = await fheCounterContract.getCount();
expect(encryptedCountBeforeInc).to.eq(ethers.ZeroHash);
const clearCountBeforeInc = 0;
// const tx = await counterContract.connect(signers.alice).increment(1);
// await tx.wait();
// const countAfterInc = await counterContract.getCount();
// expect(countAfterInc).to.eq(countBeforeInc + 1n);
});3
Encrypt the increment() function argument
increment() function argumentit("increment the counter by 1", async function () {
const encryptedCountBeforeInc = await fheCounterContract.getCount();
expect(encryptedCountBeforeInc).to.eq(ethers.ZeroHash);
const clearCountBeforeInc = 0;
// const tx = await counterContract.connect(signers.alice).increment(1);
// await tx.wait();
// const countAfterInc = await counterContract.getCount();
// expect(countAfterInc).to.eq(countBeforeInc + 1n);
});it("increment the counter by 1", async function () {
const encryptedCountBeforeInc = await fheCounterContract.getCount();
expect(encryptedCountBeforeInc).to.eq(ethers.ZeroHash);
const clearCountBeforeInc = 0;
// Encrypt constant 1 as a euint32
const clearOne = 1;
const encryptedOne = await fhevm
.createEncryptedInput(fheCounterContractAddress, signers.alice.address)
.add32(clearOne)
.encrypt();
// const tx = await counterContract.connect(signers.alice).increment(1);
// await tx.wait();
// const countAfterInc = await counterContract.getCount();
// expect(countAfterInc).to.eq(countBeforeInc + 1n);
});4
Call the increment() function with the encrypted argument
increment() function with the encrypted argument// const tx = await counterContract.connect(signers.alice).increment(1);
// await tx.wait();const tx = await fheCounterContract.connect(signers.alice).increment(encryptedOne.handles[0], encryptedOne.inputProof);
await tx.wait();npx hardhat test FHECounter
FHECounter has been deployed at address 0x7553CB9124f974Ee475E5cE45482F90d5B6076BC
✔ should be deployed
✔ encrypted count should be uninitialized after deployment
✔ increment the counter by 1
3 passing (7ms)5
Call the getCount() function and Decrypt the value
getCount() function and Decrypt the value// const countAfterInc = await counterContract.getCount();
// expect(countAfterInc).to.eq(countBeforeInc + 1n);const encryptedCountAfterInc = await fheCounterContract.getCount();
const clearCountAfterInc = await fhevm.userDecryptEuint(
FhevmType.euint32,
encryptedCountAfterInc,
fheCounterContractAddress,
signers.alice,
);
expect(clearCountAfterInc).to.eq(clearCountBeforeInc + clearOne);npx hardhat test FHECounter
FHECounter has been deployed at address 0x7553CB9124f974Ee475E5cE45482F90d5B6076BC
✔ should be deployed
✔ encrypted count should be uninitialized after deployment
✔ increment the counter by 1
3 passing (7ms)6
Call the contract decrement() function
decrement() function// it("decrement the counter by 1", async function () {
// // First increment, count becomes 1
// let tx = await counterContract.connect(signers.alice).increment();
// await tx.wait();
// // Then decrement, count goes back to 0
// tx = await counterContract.connect(signers.alice).decrement(1);
// await tx.wait();
// const count = await counterContract.getCount();
// expect(count).to.eq(0);
// });it("decrement the counter by 1", async function () {
// Encrypt constant 1 as a euint32
const clearOne = 1;
const encryptedOne = await fhevm
.createEncryptedInput(fheCounterContractAddress, signers.alice.address)
.add32(clearOne)
.encrypt();
// First increment by 1, count becomes 1
let tx = await fheCounterContract.connect(signers.alice).increment(encryptedOne.handles[0], encryptedOne.inputProof);
await tx.wait();
// Then decrement by 1, count goes back to 0
tx = await fheCounterContract.connect(signers.alice).decrement(encryptedOne.handles[0], encryptedOne.inputProof);
await tx.wait();
const encryptedCountAfterDec = await fheCounterContract.getCount();
const clearCountAfterDec = await fhevm.userDecryptEuint(
FhevmType.euint32,
encryptedCountAfterDec,
fheCounterContractAddress,
signers.alice,
);
expect(clearCountAfterDec).to.eq(0);
});npx hardhat test FHECounter
FHECounter has been deployed at address 0x7553CB9124f974Ee475E5cE45482F90d5B6076BC
✔ should be deployed
✔ encrypted count should be uninitialized after deployment
✔ increment the counter by 1
✔ decrement the counter by 1
4 passing (7ms)Congratulations! You've completed the full tutorial.
Next step
Last updated