Skip to main content

Documentation Index

Fetch the complete documentation index at: https://fhenix-docs-hardhat-3-plugin.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

@cofhe/hardhat-3-plugin is the Hardhat 3 counterpart to @cofhe/hardhat-plugin. It deploys the CoFHE mock contracts to an in-process Hardhat network on every network.connect() call and exposes a cofhe namespace on the connection object — ready to use immediately, no boilerplate required.
Use this plugin if you’ve adopted the Hardhat 3 plugin/hook model. For Hardhat v2 projects, use @cofhe/hardhat-plugin instead.

What the plugin provides

  • Auto-deploys mocks on every network.connect()MockTaskManager, MockACL, MockZkVerifier, MockThresholdNetwork, and TestBed.
  • conn.cofhe namespace on the Hardhat 3 connection object (sits alongside conn.viem from @nomicfoundation/hardhat-viem).
  • cofhe.createClientWithBatteries() — one-call SDK client setup with a pre-signed self permit.
  • Mock helpers — Viem contract descriptors for every mock, plaintext inspection (getPlaintext / expectPlaintext), and logging control.

Installation

1

Install the package

npm install @cofhe/hardhat-3-plugin @cofhe/sdk @fhenixprotocol/cofhe-contracts
2

Register the plugin

hardhat.config.ts
import { defineConfig } from 'hardhat/config';
import cofhePlugin from '@cofhe/hardhat-3-plugin';
import hardhatViem from '@nomicfoundation/hardhat-viem';
import hardhatNodeTestRunner from '@nomicfoundation/hardhat-node-test-runner';

export default defineConfig({
  plugins: [cofhePlugin, hardhatViem, hardhatNodeTestRunner],
});

Configuration

The plugin adds an optional cofhe key to your Hardhat 3 config. All values shown below are their defaults:
hardhat.config.ts
export default defineConfig({
  plugins: [cofhePlugin, hardhatViem, hardhatNodeTestRunner],

  cofhe: {
    gasWarning: true,           // warn that mock gas costs differ from live FHE
    logMocks: true,             // enable event-based logging in mock contracts
    mocksDeployVerbosity: 'v',  // '' silent | 'v' summary | 'vv' full per-contract
  },
});
OptionTypeDefaultDescription
gasWarningbooleantruePrint a one-line warning after mock deployment reminding that mock gas costs differ from live FHE.
logMocksbooleantrueEnable event-based logging inside mock contracts.
mocksDeployVerbosity'' | 'v' | 'vv''v'How much output to print while deploying mocks. '' silent, 'v' one summary line per mock, 'vv' full per-contract deployment log.

How auto-deployment works

Every call to network.connect() automatically:
  1. Deploys all CoFHE mock contracts to the fresh in-process EVM.
  2. Attaches a cofhe namespace to the returned connection object.
Because network.connect() is awaitable at the top level of an async describe, you can set everything up without lifecycle hooks:
import { describe, it } from 'node:test';
import { network } from 'hardhat';

describe('My FHE contract', async () => {
  const { viem, cofhe } = await network.connect();
  const publicClient = await viem.getPublicClient();
  const [walletClient] = await viem.getWalletClients();

  it('encrypts and decrypts a value', async () => {
    const client = await cofhe.createClientWithBatteries(walletClient);
    // ... test logic
  });
});
Why async describe? Hardhat 3’s node:test runner supports top-level await inside the describe callback. This lets you resolve the connection (and deploy mocks) exactly once per test file without needing a before() hook.

Mock contracts deployed

ContractAddressDescription
MockTaskManager0xeA30c4B8b44078Bbf8a6ef5b9f1eC1626C7848D9Coordinates FHE operations and ACL
MockACLdynamicAccess Control List — address resolved from TaskManager
MockZkVerifier0x0000000000000000000000000000000000005001Verifies ZK proofs for encrypted inputs
MockThresholdNetwork0x0000000000000000000000000000000000005002Simulates the threshold decryption network
TestBed0x0000000000000000000000000000000000005003Utility contract for storing and retrieving encrypted values in tests
Fixed-address contracts are deployed via hardhat_setCode, so they are always at the same address regardless of deployment order. MockACL is deployed as a normal contract (so its EIP-712 domain constructor runs correctly) and its address is registered in MockTaskManager.

Differences from @cofhe/hardhat-plugin

Concern@cofhe/hardhat-plugin (v2)@cofhe/hardhat-3-plugin
Entry pointhre.cofhe (global)conn.cofhe (per network.connect() call)
LifecyclePre-task hook (npx hardhat test / node)network.connect() returns a fresh deployment
Test runner expectationMocha-style (before, it)node:test with async describe
Mock compilation for custom-error decodingOverrides TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHSRuns hre.solidity.build() during the hre.created hook
Bytecode sourcinghre.artifacts.readArtifact()hre.artifacts.readArtifact() (same — for variable-address mocks like MockACL)
The Solidity surface (mock contracts, plaintext semantics, FHE.verifyDecryptResult acceptance) is identical between the two plugins; the differences are all in how Hardhat hosts the plugin.

Next steps

  • Clientconn.cofhe.createConfig, createClient, createClientWithBatteries.
  • Mock Contracts — Viem contract descriptors and plaintext inspection helpers.
  • LoggingenableLogs, disableLogs, withLogs.
  • Testing — end-to-end test patterns.