Install
$ agentstack add skill-zunmax-fhevm-skill-fhevm-skill ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
FHEVM Development Skill (v0.11)
Reference material ships alongside this SKILL.md in references/, templates/, and review-modules/. For API reference and type details, cross-check against the installed source in node_modules/@fhevm/solidity/ and node_modules/@zama-fhe/relayer-sdk/ - never trust docs or training knowledge alone.
This skill targets @fhevm/solidity@0.11.1 (Solidity Guides v0.11 on https://docs.zama.org/protocol/solidity-guides/). Generated code, templates, anti-patterns, and lint rules all assume v0.11. The skill also flags pre-v0.11 patterns surfaced from older codebases or out-of-date copilots (TFHE.*, FHE.requestDecryption, SepoliaConfig as Solidity base, FHE.neq / lte / gte, fhevmjs, @fhevm/sdk) so you can migrate them. v0.10 was a brief transitional release; treat any v0.10-specific advice in older docs as superseded by v0.11.
Architecture
FHEVM uses symbolic execution. Contracts operate on bytes32 handles, not on ciphertexts. A coprocessor performs the FHE computation off-chain. Encrypted values cannot be branched on - require(ebool) and if (ebool) are Solidity compile errors because ebool is a bytes32 UDVT.
Required Setup
pragma solidity ^0.8.28;
import { FHE, euint64, externalEuint64, ebool } from "@fhevm/solidity/lib/FHE.sol";
import { ZamaEthereumConfig } from "@fhevm/solidity/config/ZamaConfig.sol";
contract MyContract is ZamaEthereumConfig { }
Pragma Policy
| Case | Pragma | |---|---| | Default for new contracts | ^0.8.28 (matches reference template, hardhat.config.ts uses version: "0.8.28") | | Importing @openzeppelin/confidential-contracts (ERC-7984) | ^0.8.27 minimum (ERC7984.sol declares ^0.8.27) | | Absolute minimum for FHEVM | ^0.8.24 (only use if a dependency pins lower) |
EVM target: "cancun". Do not target a lower EVM version.
Dependencies
| Package | npm Name | |---------|----------| | Solidity lib | @fhevm/solidity (^0.11.1) | | Hardhat plugin | @fhevm/hardhat-plugin (^0.4.2) | | Mock utils | @fhevm/mock-utils (^0.4.2) | | Legacy primitive SDK | @zama-fhe/relayer-sdk (0.4.1 exact, no caret. Latest published is 0.4.3 (2026-05-06) but @fhevm/mock-utils@0.4.2 peers 0.4.1 exact and @fhevm/hardhat-plugin runtime-aborts on any other version. Still required as a transitive install even on the new SDK) | | New high-level SDK | @zama-fhe/sdk (^3.0.0) - ZamaSDK, Token, sessions, storage. Engines node >= 22. Optional - use only for confidential ERC-7984 dApps | | New React hooks | @zama-fhe/react-sdk (^3.0.0) - TanStack-Query hooks + ZamaProvider. Optional - React frontends only | | Hardhat ethers | @nomicfoundation/hardhat-ethers (^3.1.3) - bridges Hardhat 2 to ethers v6. Pin v3 line; v4 requires Hardhat 3 | | Hardhat-2 helpers | @nomicfoundation/hardhat-network-helpers (^1.1.2 - opt-in; only if tests use time.increase / mine / loadFixture / snapshots; v3 line requires Hardhat 3) | | Chai matchers | @nomicfoundation/hardhat-chai-matchers (^2.1.2) | | OZ Confidential | @openzeppelin/confidential-contracts (^0.4.0) |
Common install failure: Invalid @zama-fhe/relayer-sdk version
Triggered when @zama-fhe/sdk@3.0.0 (new SDK) and the Hardhat toolchain are installed in the same package.json. The new SDK depends on @zama-fhe/relayer-sdk: ~0.4.2; both @fhevm/hardhat-plugin@0.4.2 and @fhevm/mock-utils@0.4.2 peer-pin 0.4.1 exact. The constraint is unsatisfiable. If npm hoists 0.4.2 or 0.4.3, you see this on the first npx hardhat test or npx hardhat compile:
Error in plugin @fhevm/hardhat-plugin: Invalid @zama-fhe/relayer-sdk version. Expecting 0.4.1. Got 0.4.2 instead.
Two safe fixes (verified: 0.4.1, 0.4.2, 0.4.3 ship identical transitive deps, so forcing 0.4.1 does not break the new SDK at runtime):
overridesin the consumerpackage.json(single-package projects):
``json { "overrides": { "@zama-fhe/relayer-sdk": "0.4.1" } } ` Then rm -rf node_modules package-lock.json && npm install`.
- Workspace split (recommended for monorepos): keep the Hardhat package and the dApp / Node frontend in separate workspaces with separate
node_modules. The toolchain workspace pins0.4.1exact; the frontend workspace lets@zama-fhe/sdkinstall whatever it wants.
Latest published @zama-fhe/relayer-sdk is 0.4.3 (2026-05-06); the 0.4.1 exact pin is a Zama toolchain quirk, not a stale recommendation.
Loading Protocol
Tier 1 - ALWAYS load at the start of every FHEVM task (before writing, reviewing, auditing, testing, deploying, or integrating):
- This SKILL.md (core rules, verification protocol, checklist)
references/anti-patterns.md- verified mistakes agents repeat in FHEVM code; loaded by default so you know what NOT to do before your first line of output.references/code-style.md- comment syntax, file headers, section
dividers, NatSpec vs JSDoc tag tables, banned Unicode characters.
Tier 2 - Load based on task:
- Writing a new contract ->
templates/+references/types-operations.md - Quick review ->
references/finding-validation.md+references/report-format.md - Deploying ->
references/deployment.md+references/environment.md - FHE security audit ->
references/fhe-vulnerabilities.md+references/solidity-vulnerabilities.md+references/finding-validation.md+references/report-format.md+ all files inreview-modules/ - Writing tests ->
references/testing.md - Frontend / dApp integration (legacy
@zama-fhe/relayer-sdkprimitives or general WASM / COOP / COEP / Vite / Next.js setup) ->references/frontend.md - Token / ERC-7984 (Solidity layer) ->
templates/ConfidentialERC20.sol+references/erc7984.md - ACL questions ->
references/acl.md - Decryption flows (legacy primitives) ->
references/inputs-decryption.md - New SDK overview / package map /
ZamaSDKconstructor ->references/zama-sdk-overview.md - New SDK auth + relayer transports + signers + storage + web extensions ->
references/zama-sdk-auth-storage.md - New SDK shield / unshield / confidentialTransfer / balanceOf /
Token/ReadonlyToken->references/zama-sdk-tokens.md - New SDK session model + delegation + TTLs + decrypt cache ->
references/zama-sdk-session.md - New SDK React hooks (59 hooks,
ZamaProvider, Next.js SSR, Vite,zamaQueryKeys) ->references/zama-sdk-react.md - New SDK error taxonomy +
matchZamaErrorpatterns ->references/zama-sdk-errors.md - New SDK activity feeds + event decoders +
WrappersRegistry+ contract builders + operator approvals + FHE artifact cache ->references/zama-sdk-activity.md
Encrypt + Decrypt Quick Reference
Every confidential dApp uses the seven flows below. Match the runtime + use case to the right reference. All signatures verified against node_modules/@zama-fhe/sdk/dist/* (v3.0.0), node_modules/@zama-fhe/react-sdk/dist/* (v3.0.0), and the official guide https://docs.zama.org/protocol/sdk/guides/encrypt-decrypt.md.
1. Encrypt a user input (browser, new SDK, React)
/* "use client" required in Next.js. SharedArrayBuffer needs COOP same-origin + COEP require-corp. */
import { useEncrypt } from "@zama-fhe/react-sdk";
const { mutateAsync: encrypt } = useEncrypt();
const { handles, inputProof } = await encrypt({
values: [{ value: 1000n, type: "euint64" }],
contractAddress: contract.address,
userAddress: user.address,
});
/* Pass to the contract: handles[0] -> externalEuint64 arg, inputProof -> bytes calldata. */
await contract.deposit(toHex(handles[0]), toHex(inputProof));
Detail + multi-value batching: references/zama-sdk-react.md (useEncrypt) and references/zama-sdk-tokens.md.
2. Encrypt a user input (Hardhat test)
import { fhevm } from "hardhat";
const input = fhevm.createEncryptedInput(contract.address, signer.address);
input.add64(1000n);
const enc = await input.encrypt();
await contract.connect(signer).deposit(enc.handles[0], enc.inputProof);
Detail: references/testing.md and references/inputs-decryption.md. Tests auto-init; custom Hardhat tasks must call await fhevm.initializeCLIApi() first.
3. Decrypt a confidential token balance (the most common dApp call)
/* Vanilla TS (Node.js or browser). One EIP-712 prompt the first time. Subsequent calls silent. */
const balance = await token.balanceOf(); /* returns bigint, NOT a wrapper */
const handle = await token.confidentialBalanceOf(); /* returns the bytes32 handle (Hex) */
/* React. TanStack-Query under the hood. Auto re-fetches on transfer / shield / unshield. */
import { useConfidentialBalance, useConfidentialBalances } from "@zama-fhe/react-sdk";
const { data: balance, isLoading } = useConfidentialBalance(
{ tokenAddress: cUSDT },
{ refetchInterval: 5_000 },
);
const { data } = useConfidentialBalances({ tokenAddresses: [cUSDC, cUSDT, cWETH] });
Pre-authorize multiple tokens to skip prompts: await ReadonlyToken.allow(tokenA, tokenB); (static, not instance). Empty-account vs zero-balance: NoCiphertextError = "never shielded" (show empty state); 0n = "shielded but zero". Detail: references/zama-sdk-tokens.md ("Balances and the FHE credential session") + references/zama-sdk-errors.md.
4. Decrypt arbitrary handles from a custom contract (user decrypt)
/* New SDK: pre-authorize a contract set once, then decrypt any handle from it silently. */
await sdk.allow([contract.address]);
const values = await sdk.userDecrypt([{ handle, contractAddress: contract.address }]);
const cleartext = values[handle]; /* bare Record, NOT .clearValues */
import { useAllow, useIsAllowed, useUserDecrypt } from "@zama-fhe/react-sdk";
const { mutateAsync: allow } = useAllow();
const { data: isAllowed } = useIsAllowed({ contractAddress });
const { mutateAsync: userDecrypt } = useUserDecrypt();
if (!isAllowed) await allow({ contractAddresses: [contractAddress] });
const values = await userDecrypt({ handles: [{ handle, contractAddress }] });
Legacy primitive path (raw @zama-fhe/relayer-sdk, no session layer): references/inputs-decryption.md ("User Decryption (EIP-712)") and references/frontend.md.
5. Public decryption (3-step bound flow)
On-chain step 1: FHE.makePubliclyDecryptable(handle). Off-chain step 2 (browser/Node):
import { usePublicDecrypt } from "@zama-fhe/react-sdk"; /* React */
const { mutateAsync: publicDecrypt } = usePublicDecrypt();
const { clearValues } = await publicDecrypt({ handles: [handle] });
const cleartext = clearValues[handle];
On-chain step 3: FHE.checkSignatures(cts, abi.encode(clearValue), proof). The cts array order MUST match step 2's input order; swapping reverts with KMSInvalidSigner(address). Detail: references/inputs-decryption.md ("Public Decryption v0.9 Three-Step Flow").
6. Local development (no relayer key, no live KMS)
import { RelayerCleartext, hardhatCleartextConfig, hoodiCleartextConfig } from "@zama-fhe/sdk/cleartext";
const relayer = new RelayerCleartext(hardhatCleartextConfig); /* chainId 31337 */
/* Or hoodiCleartextConfig for the public Hoodi testnet without an API key. */
RelayerCleartext is BLOCKED on chain 1 (mainnet) and 11155111 (Sepolia) - it errors on construction. Detail: references/zama-sdk-auth-storage.md and references/zama-sdk-overview.md ("Network Presets").
7. Decrypt-someone-else's-balance (delegation)
await token.delegateDecryption({
delegateAddress,
expirationDate: Math.floor(Date.now() / 1000) + 3600, /* must be >= now + 1h */
});
/* Wait 1-2 minutes for gateway propagation, otherwise DelegationNotPropagatedError. */
const otherBalance = await token.decryptBalanceAs(otherAddress, delegateAddress);
Detail: references/zama-sdk-session.md ("Delegated Decryption") and references/zama-sdk-tokens.md.
Pitfalls (do not skip)
userDecryptreturns a bareRecord.publicDecryptreturns{ clearValues }. The two are NOT the same shape - mixing them silently breaks readers.- Browser SDK requires COOP
same-origin+ COEPrequire-corp(orcredentiallessif you also serve RainbowKit/WalletConnect). Without both, encryption fails at WASM init with no clear error. - Vite users MUST exclude
@zama-fhe/relayer-sdkfromoptimizeDepsAND setworker.format: "es"- otherwise WASM init throws. - Mainnet relayer needs an API key; the browser MUST route through a backend proxy (never
NEXT_PUBLIC_*/VITE_*). Three auth shapes:ApiKeyHeader,ApiKeyCookie,BearerToken. Detail:references/zama-sdk-auth-storage.mdandreferences/frontend.md(Mainnet section). - Empty handle =
NoCiphertextError. Map to "Shield tokens to get started", NOT "0". useAllowonce per session, thenuseUserDecryptis silent (cached in IndexedDB).keypairTTLdefault 30d, max 365d,0rejected.
2-Layer Verification Protocol
FHEVM had 32 documented breaking changes between v0.8 and v0.9, and v0.10 / v0.11 added further additive changes (event shapes, inferredTotalSupply, interface IDs). The skill targets v0.11. Training data frequently contains outdated patterns from v0.8 and earlier. Every technical value you write or flag must pass two layers:
- Layer 1 - Reference - Check
references/anti-patterns.md(always
loaded) plus the topic-specific reference for the task.
- Layer 2 - Source - Verify against the actual installed source:
node_modules/@fhevm/solidity/lib/FHE.sol, @zama-fhe/relayer-sdk/ type declarations, or GitHub source if not installed.
- If the two conflict -> source code wins. Update the reference if
the skill is wrong; never silently trust Layer 1 alone.
Trust hierarchy: source code > skill references > Zama docs > training knowledge. Zama's docs are now versioned (v0.10, v0.11, Latest under https://docs.zama.org/protocol/solidity-guides/), but search results, copilots, and older bookmarks still surface v0.6-v0.9 pages without obvious version labels. The skill targets v0.11 only - if a doc page predates v0.11 it is suspect. Treat every function name, signature, address, URL, and import path as suspect until you have confirmed it against installed source.
Confidence -> Severity mapping for findings (used in every review):
| Confidence | Label | Severity (combined with impact) | When to use | |-----------|-------|-------------------------------|-------------| | >=95 | DEFINITE BUG | Critical / High | Source-verified, will revert or lose data | | 80-94 | LIKELY ISSUE | High / Medium | Strong evidence, needs one more verification step | | 70-79 | PROBABLE ISSUE | Medium | Partial path, plausible exploit | | 40-69 | SUGGESTION | Low | May be intentional design choice | | Read templates/ConfidentialERC20.sol
- Private voting -> Read
templates/PrivateVoting.sol - Sealed auction -> Read
templates/SealedAuction.sol
- Load topic references as needed:
- Types and operations -> Read
references/types-operations.md - ACL patterns -> Read
references/acl.md - Input/decryption -> Read
references/inputs-decryption.md - ERC-7984 tokens -> Read
references/erc7984.md
- Write the contract - for EVERY line, verify against anti-patterns:
ZamaEthereumConfignotSepoliaConfig(WHY: SepoliaConfig removed in v0.9 - #1)FHE.fromExternal()notFHE.asEuintXX()(WHY: asEuintXX converts a Solidity literal or uint variable; user-submitted inputs arrive as externalEuintXX + inputProof - #2)FHE.select()notrequire(encBool)and notif (encBool)(WHY: encrypted bools cannot be branched on - #13)FHE.allowThis()after every STORED computation (WHY: contract loses access next tx without it - locals have transient ACL automatically)FHE.allow(result, user)for user-readable values (WHY: users cannot decrypt without ACL)
-
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: zunmax
- Source: zunmax/fhevm-skill
- License: MIT
- Homepage: https://zama-fhevm-skill.vercel.app
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.