The contract
The examples use this contract. It accepts an encrypted input, increments the stored value, and can publish a decryption result onchain.contracts/Counter.sol
Encrypt, store, and decrypt
The core test loop encrypts a value, sends it to the contract, and decrypts the stored handle:test/Counter.test.ts
The output lists the
stores and decrypts an encrypted count test under Counter, and the summary reads 1 passing (1 nodejs).describe callback is async so that it can await network.create() at the top. Every it inside it shares that connection and its mocks, without a before hook.
Start each test from a clean chain
A connection is one chain, so tests in the samedescribe see each other’s state. When a test needs a clean chain, open a new connection inside it:
network.create() call starts a new simulated chain and deploys a new set of mocks. Contracts from other connections do not exist on it.
Assert on plaintext
Reading the plaintext from the mocks is faster than a decryption and needs no ACP:decryptForView when the SDK’s own behavior is under test. See Mock contracts for both plaintext helpers.
Named ACPs
createClientWithBatteries creates and selects a self ACP. For a test that needs a second ACP, create it and select it:
Decrypt for a transaction
decryptForTx resolves to { ctHash, decryptedValue, signature }. Choose the ACP mode before execute().
Public handles
After the contract callsFHE.allowPublic, anyone can decrypt the handle without an ACP:
withoutACP() rejects with mocks decryptForTx call failed: NotAllowed.
Handles restricted by the ACL
Pass an ACP, or callwithACP() with no argument to use the active one:
Publish the result onchain
Send the value and the signature to the contract, which verifies and stores them withFHE.publishDecryptResult:
decryptedValue is a bigint. viem expects a number for a uint32 argument, so convert it first.
Common pitfalls
Every test fails with HHE1000
Every test fails with HHE1000
HHE1000: Artifact for contract "MockTaskManager" not found means the mock contracts are missing from solidity.npmFilesToBuild. Add them as shown in Getting Started.TypeScript rejects the wallet client
TypeScript rejects the wallet client
Error
TS2345 on createClientWithBatteries(walletClient) or client.connect(...) means two copies of viem are installed. Add the viem override from Getting Started and reinstall from a clean node_modules.setCount reverts with 0x7ba5ffb5
setCount reverts with 0x7ba5ffb5
The input signature binds the encrypting account and the consuming contract. The call reverts when a different wallet sends the transaction, or when
setConsumingContract named a different contract. viem reports the revert by its selector, 0x7ba5ffb5, which is InvalidSigner(address,address).encryptInputs has no execute method
encryptInputs has no execute method
The SDK types only offer
execute() after setConsumingContract(), so TypeScript reports Property 'execute' does not exist. At runtime, the same omission throws CONSUMING_CONTRACT_UNINITIALIZED.A second operation reverts with 0x4d13139e
A second operation reverts with 0x4d13139e
The contract did not call
FHE.allowThis on a stored handle, so its next transaction cannot use it. viem reports the revert by its selector, 0x4d13139e, which is ACLNotAllowed(uint256,address). Wrap the call in withLogs to see which grants each operation made.Related
- Hardhat 2 plugin testing: the same patterns with Mocha and ethers.
- Decrypt to transact: the full
decryptForTxguide.