AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Fhevm Skill

skill-zunmax-fhevm-skill-fhevm-skill · by zunmax

Builds, reviews, audits, tests, and deploys Zama FHEVM v0.11 confidential smart contracts and dApp frontends, on the new @zama-fhe/sdk@^3 / @zama-fhe/react-sdk@^3 (Token API, 59 hooks) or legacy @zama-fhe/relayer-sdk@^0.4 (primitives). Use when files import @fhevm/solidity, @fhevm/hardhat-plugin, @zama-fhe/relayer-sdk, @zama-fhe/sdk, @zama-fhe/react-sdk, or @openzeppelin/confidential-contracts; d…

No reviews yet
0 installs
28 views
0.0% view→install

Install

$ agentstack add skill-zunmax-fhevm-skill-fhevm-skill

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No 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.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-zunmax-fhevm-skill-fhevm-skill)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

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 →
Are you the author of Fhevm Skill? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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):

  1. overrides in the consumer package.json (single-package projects):

``json { "overrides": { "@zama-fhe/relayer-sdk": "0.4.1" } } ` Then rm -rf node_modules package-lock.json && npm install`.

  1. Workspace split (recommended for monorepos): keep the Hardhat package and the dApp / Node frontend in separate workspaces with separate node_modules. The toolchain workspace pins 0.4.1 exact; the frontend workspace lets @zama-fhe/sdk install 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 in review-modules/
  • Writing tests -> references/testing.md
  • Frontend / dApp integration (legacy @zama-fhe/relayer-sdk primitives 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 / ZamaSDK constructor -> 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 + matchZamaError patterns -> 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)

  1. userDecrypt returns a bare Record. publicDecrypt returns { clearValues }. The two are NOT the same shape - mixing them silently breaks readers.
  2. Browser SDK requires COOP same-origin + COEP require-corp (or credentialless if you also serve RainbowKit/WalletConnect). Without both, encryption fails at WASM init with no clear error.
  3. Vite users MUST exclude @zama-fhe/relayer-sdk from optimizeDeps AND set worker.format: "es" - otherwise WASM init throws.
  4. 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.md and references/frontend.md (Mainnet section).
  5. Empty handle = NoCiphertextError. Map to "Shield tokens to get started", NOT "0".
  6. useAllow once per session, then useUserDecrypt is silent (cached in IndexedDB). keypairTTL default 30d, max 365d, 0 rejected.

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
  1. 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
  1. Write the contract - for EVERY line, verify against anti-patterns:
  • ZamaEthereumConfig not SepoliaConfig (WHY: SepoliaConfig removed in v0.9 - #1)
  • FHE.fromExternal() not FHE.asEuintXX() (WHY: asEuintXX converts a Solidity literal or uint variable; user-submitted inputs arrive as externalEuintXX + inputProof - #2)
  • FHE.select() not require(encBool) and not if (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.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.