Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Quick Start

Set up a Hardhat project with @cofhe/hardhat-plugin, write a contract that stores an encrypted uint32, and test the encrypt → store → decrypt flow.

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
npm install @cofhe/hardhat-plugin@^0.4.0 @cofhe/sdk@^0.4.0 @fhenixprotocol/cofhe-contracts@^0.1.0
PackageVersionPurpose
@cofhe/hardhat-plugin^0.4.0Extends Hardhat with hre.cofhe, deploys mock contracts automatically
@cofhe/sdk^0.4.0Client-side encryption, decryption, and permit management
@fhenixprotocol/cofhe-contracts^0.1.0FHE.sol — the Solidity library imported by your contracts

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;

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

Now that you have a working setup, explore the full SDK and tooling:

  • Client — config options, adapters, and connection lifecycle.
  • Encrypting Inputs — the builder API, supported types, and progress callbacks.
  • Decrypting to View — reveal encrypted state in your UI with permits.
  • Decrypting to Transact — reveal values on-chain with a verifiable signature.
  • Permits — create, share, and manage decryption authorization.
  • Mock Contracts — read plaintext directly and assert encrypted state in tests.
  • Logging — inspect every FHE operation your contracts perform.
  • EncryptedCounter.sol — a more complete reference contract demonstrating all SDK features.