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 initto create one) @nomicfoundation/hardhat-toolboxor@nomicfoundation/hardhat-ethersinstalled
1) Install dependencies
npm
npm install @cofhe/hardhat-plugin@^0.4.0 @cofhe/sdk@^0.4.0 @fhenixprotocol/cofhe-contracts@^0.1.0| Package | Version | Purpose |
|---|---|---|
@cofhe/hardhat-plugin | ^0.4.0 | Extends Hardhat with hre.cofhe, deploys mock contracts automatically |
@cofhe/sdk | ^0.4.0 | Client-side encryption, decryption, and permit management |
@fhenixprotocol/cofhe-contracts | ^0.1.0 | FHE.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 encrypteduint32stored 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 testThe plugin deploys mock contracts automatically — no extra setup needed.
MyContract
✓ stores and decrypts an encrypted value
1 passing (1s)What just happened?
- The Hardhat plugin deployed mock versions of the CoFHE coprocessor contracts (TaskManager, ACL, ZK verifier, threshold network) before the test ran.
createClientWithBatteriescreated an SDK client connected to the Hardhat network, with a self-permit ready to go.encryptInputsencrypted the plaintext42into an FHE ciphertext with a ZK proof (simulated by the mock verifier).- The contract stored the ciphertext handle on-chain and set ACL permissions.
decryptForViewused the permit to decrypt the handle back to42nlocally.
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.