Skip to main content
Set up a Hardhat project with @cofhe/hardhat-plugin, write a contract that stores an encrypted uint32, and test the encrypt → store → decrypt flow.
Want to skip the setup? Clone the cofhe-hardhat-starter template to get a pre-configured project with everything ready to go.

Prerequisites

  • Node.js 18+
  • An existing Hardhat project (or run npx hardhat init to create one)
  • @nomicfoundation/hardhat-toolbox or @nomicfoundation/hardhat-ethers installed

1. Install dependencies

npm install @cofhe/hardhat-plugin@^0.4.0 @cofhe/sdk@^0.4.0 @fhenixprotocol/cofhe-contracts@^0.1.0

2. Configure Hardhat

Import the plugin and set evmVersion to cancun (required for the transient storage opcodes used by FHE contracts).
hardhat.config.ts
import { HardhatUserConfig } from 'hardhat/config';
import '@nomicfoundation/hardhat-toolbox';
import '@cofhe/hardhat-plugin';

const config: HardhatUserConfig = {
  solidity: {
    version: '0.8.28',
    settings: {
      evmVersion: 'cancun',
    },
  },
};

export default config;
Without evmVersion: 'cancun', compilation will fail with errors from @fhenixprotocol/cofhe-contracts.

3. Write a contract

Create a minimal contract that accepts an encrypted input and stores it on-chain.
contracts/MyContract.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import '@fhenixprotocol/cofhe-contracts/FHE.sol';

contract MyContract {
  euint32 public storedValue;

  function setValue(InEuint32 memory inValue) external {
    storedValue = FHE.asEuint32(inValue);
    FHE.allowThis(storedValue);
    FHE.allowSender(storedValue);
  }
}
  • euint32 — an encrypted uint32 stored on-chain as a ciphertext handle.
  • InEuint32 — the encrypted input struct produced by the SDK.
  • FHE.allowThis / FHE.allowSender — grant the contract and caller permission to read the encrypted value (required by the ACL).

4. Write a test

Use hre.cofhe.createClientWithBatteries to get a fully configured SDK client with a self-permit, then encrypt → send → decrypt.
test/MyContract.test.ts
import hre from 'hardhat';
import { CofheClient, Encryptable, FheTypes } from '@cofhe/sdk';
import { HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/signers';
import { expect } from 'chai';

describe('MyContract', () => {
  let cofheClient: CofheClient;
  let signer: HardhatEthersSigner;

  before(async () => {
    [signer] = await hre.ethers.getSigners();
    cofheClient = await hre.cofhe.createClientWithBatteries(signer);
  });

  it('stores and decrypts an encrypted value', async () => {
    const Factory = await hre.ethers.getContractFactory('MyContract');
    const contract = await Factory.deploy();

    // 1. Encrypt the input
    const [encrypted] = await cofheClient
      .encryptInputs([Encryptable.uint32(42n)])
      .execute();

    // 2. Send to contract
    await (await contract.setValue(encrypted)).wait();

    // 3. Read the stored handle and decrypt
    const ctHash = await contract.storedValue();
    const decrypted = await cofheClient
      .decryptForView(ctHash, FheTypes.Uint32)
      .execute();

    expect(decrypted).to.equal(42n);
  });
});

5. Run

npx hardhat test
The plugin deploys mock contracts automatically — no extra setup needed.
  MyContract
    ✓ stores and decrypts an encrypted value

  1 passing (1s)

What just happened?

  1. The Hardhat plugin deployed mock versions of the CoFHE coprocessor contracts (TaskManager, ACL, ZK verifier, threshold network) before the test ran.
  2. createClientWithBatteries created an SDK client connected to the Hardhat network, with a self-permit ready to go.
  3. encryptInputs encrypted the plaintext 42 into an FHE ciphertext with a ZK proof (simulated by the mock verifier).
  4. The contract stored the ciphertext handle on-chain and set ACL permissions.
  5. decryptForView used the permit to decrypt the handle back to 42n locally.

Next steps

  • Hardhat Plugin — full plugin configuration and features.
  • Mock Contracts — read plaintext directly and assert encrypted state in tests.
  • Logging — inspect every FHE operation your contracts perform.