Skip to main content
Version: Nitrogen

Testing on Fhenix

During this phase, we will focus on deploying the contract, wrapping tokens, and executing transactions using the FhenixJS library and Hardhat.

FhenixJS is injected by the Fhenix Hardhat plugin and can be used automatically by tests.

We will break down each step, providing code snippets and explanations to ensure you understand how to test the contract effectively.

note

This section describes testing in a Hardhat project. For instructions on testing with Foundry, check this.

Step-by-Step Guide

1. Set Up the Test Environment

First, import the necessary modules and define the initial variables.

import { WrappingERC20 } from "../types/contracts/WrappingERC20";
import hre, { ethers } from 'hardhat';
import { Permit } from "fhenixjs";

describe('Test WERC20', () => {
let contractAddr: string;
let contract: WrappingERC20;
let permit: Permit;
let owner: string;
let destination: string = "0x1245dD4AdB920c460773a105e1B3345707B4834A";

const amountToSend = BigInt(1);

2. Test Contract Deployment

In this phase, we will deploy the WrappingERC20 contract and initialize the permit using FhenixJS.

  it(`Test Contract Deployment`, async () => {
const { ethers, fhenixjs } = hre;
const { deploy } = hre.deployments;
const [signer] = await ethers.getSigners();

// Set the owner to the signer's address
owner = signer.address;

// Deploy the WrappingERC20 contract
const token = await deploy("WrappingERC20", {
from: signer.address,
args: ["Test Token", "TST"],
log: true,
skipIfAlreadyDeployed: false,
});

// Get the deployed contract address
contractAddr = token.address;

// Generate the permit using FhenixJS
permit = await fhenixjs.generatePermit(contractAddr, undefined, signer);
contract = (await ethers.getContractAt("WrappingERC20", contractAddr)) as unknown as WrappingERC20;

console.log(`contractAddr: `, contractAddr);
});

Explanation:

  • FhenixJS Injection: The fhenixjs object is automatically available through Hardhat's runtime environment (hre). This means you don't need to explicitly import or initialize it.
  • Permit Generation: The generatePermit function from FhenixJS is used to create a permit for interacting with the contract. This permit is essential for performing private operations on the contract, such as viewing encrypted balances.

3. Wrap Tokens

Now, we will test the wrapping functionality of the contract.

  it(`Wrap Tokens`, async () => {
// Get the balance before wrapping
let balanceBefore = await contract.balanceOf(owner);
let privateBalanceBefore = await contract.getBalanceEncrypted(permit);
console.log(`Public Balance before wrapping: ${balanceBefore}`);
console.log(`Private Balance before wrapping: ${privateBalanceBefore}`);

// Wrap the tokens
await contract.wrap(amountToSend);

// Get the balance after wrapping
let balanceAfter = await contract.balanceOf(owner);
let privateBalanceAfter = await contract.getBalanceEncrypted(permit);
console.log(`Public Balance after wrapping: ${balanceAfter.toString()}`);
console.log(`Private Balance after wrapping: ${privateBalanceAfter.toString()}`);
});

Explanation:

  • Public and Private Balances: Before wrapping tokens, we check both the public balance (visible on the blockchain) and the private balance (encrypted and only visible with the permit).
  • Wrapping Tokens: The wrap function is called on the contract to wrap the specified amount of tokens.
  • Encrypted Balances: After wrapping, we again check both balances to ensure the wrapping process worked as expected.

4. Execute Transaction

Finally, we will test the transaction execution using encrypted amounts.

  it(`Execute Transaction`, async () => {
// Get the private balance before sending
let privateBalanceBefore = await contract.getBalanceEncrypted(permit);
console.log(`Private Balance before sending: ${privateBalanceBefore}`);

// Encrypt the amount to send
const encrypted = await hre.fhenixjs.encrypt_uint32(Number(amountToSend));

// Transfer the encrypted amount
await contract.transferEncrypted(destination, encrypted);

// Get the private balance after sending
let privateBalanceAfter = await contract.getBalanceEncrypted(permit);
console.log(`Private Balance after sending: ${privateBalanceAfter}`);
});
});

Explanation:

  • Private Balance Check: Before sending tokens, we check the private balance to verify the initial state.
  • Encryption: The amount to send is encrypted using the encrypt_uint32 function from FhenixJS. This ensures that the amount is securely transmitted.
  • Encrypted Transfer: The transferEncrypted function is called on the contract to transfer the encrypted amount to the destination address.
  • Balance Verification: After the transfer, we check the private balance again to confirm the transaction.

Conclusion

This guide provided a step-by-step explanation of how to test a contract on Fhenix using Hardhat. By following these steps, you should be able to deploy a contract, wrap tokens, and execute transactions using the FhenixJS library. FhenixJS simplifies handling encrypted operations and permits, making it easier to integrate privacy features into your smart contracts.