fhEVM JavaScript SDK 客户端(Client)完全指南:工厂选择、生命周期与配置
【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm
fhEVM JavaScript SDK 将「链上读取 + 本地加密/解密」抽象为一个统一的Client(客户端)对象,它是所有加密、解密、公钥读取与解密许可签名操作的入口。本文围绕 sdk/js-sdk/docs/clients.md 展开,深入讲解四个工厂函数的取舍、ethers / viem 两种接入方式、按调用(而非按客户端)签名的设计,以及ready/init()生命周期与可选项配置,并辅以 SDK 源码实现作为佐证,帮助你为页面选择最小、最快的客户端实例。
什么是 Client
一个 Client 是你调用加密与解密操作的对象。它把一个 链定义(chain definition)(包含合约地址、Relayer URL 等 FHEVM 链信息)绑定到一个只读连接上,并在首次使用时懒加载所需的 WebAssembly 密码学模块。
关键点:
- 只读连接:Client 只通过连接读取链上数据,从不代表你发送交易;
- 懒加载 WASM:只有真正执行加密/解密时才下载并编译对应模块,普通读取不触发下载;
- 适配器统一:所有 Client 都来自两个适配器入口之一——
@fhevm/sdk/ethers或@fhevm/sdk/viem。两者 API 完全一致,唯一的差别是原生连接对象不同(ethers 用provider,viem 用publicClient)。
选择哪种 Client:四个工厂
SDK 提供了四个工厂函数,它们的区别仅在于加载哪些 WASM 模块、从而暴露哪些方法。基本原则是:选择页面需求最窄的那个——例如一个只读取公开值的页面,绝不应该下载约 4.9 MB 的加密模块。
| 工厂 | 加密 | 解密 | 加载的 WASM |
|---|---|---|---|
createFhevmClient | ✅ | ✅ | TFHE(约 4.9 MB)+ TKMS(约 600 KB) |
createFhevmEncryptClient | ✅ | — | TFHE(约 4.9 MB) |
createFhevmDecryptClient | — | ✅ | TKMS(约 600 KB) |
createFhevmBaseClient | — | — | 无 |
上表中的「解密」指私有解密(decryptValue)。而读取公开值(decryptPublicValue)以及签署解密许可(permit)在每一种Client 上都可用——包括 Base Client——因为它们不需要密码学 WASM。两者的区别详见 Decryption。
从源码看,这一设计通过「装饰器(decorator)叠加」实现:createFhevmClient.ts 中createFhevmClient在createFhevmBaseClient的基础上调用c.extend(decryptActions).extend(encryptActions);而 createFhevmEncryptClient.ts 只叠加encryptActions,createFhevmDecryptClient.ts 只叠加decryptActions。对应的类型定义在 fhevmClient.ts 中体现为BaseActions & DecryptActions & EncryptActions的排列组合,例如完整 Client 是Fhevm = Fhevm<chain, runtime, client> & BaseActions & DecryptActions & EncryptActions。
Base Client 已内置的方法
base.ts 中的BaseActions是所有 Client 的公共子集,包括:
decryptPublicValue/decryptPublicValues:读取链上已被TFHE.allowForDecryption放开的密文的明文值,无需许可或私钥;decryptPublicValuesWithSignatures:额外返回解密证明,可提交到链上由合约通过FHE.checkSignatures验证;signDecryptionPermit(已标记 deprecated,见源码注释)、signLegacyDecryptionPermit(V1 许可形态,跨协议升级保持稳定)、signUnifiedDecryptionPermit(V2 统一许可,要求协议 API v0.14.0+);parseTransportKeyPair/serializeTransportKeyPair:e2e 传输密钥对的序列化与反序列化;serializeSignedDecryptionPermit/parseSignedDecryptionPermit:已签署许可的存储与校验;fetchFheEncryptionKeyBytes:从 Relayer 拉取约 50 MB 的 FHE 公钥并缓存。
创建 Client:ethers 与 viem 两种写法
使用 ethers.js
provider可以是任意 ethers 的ContractRunner——JsonRpcProvider、BrowserProvider,或者已连接的Wallet/Signer。Client 只通过它读取数据,绝不会代替你发送交易。
import { createFhevmClient } from '@fhevm/sdk/ethers'; import { sepolia } from '@fhevm/sdk/chains'; import { ethers } from 'ethers'; const provider = new ethers.JsonRpcProvider('https://ethereum-sepolia-rpc.publicnode.com'); const client = createFhevmClient({ chain: sepolia, provider });使用 viem
import { createFhevmClient } from '@fhevm/sdk/viem'; import { sepolia } from '@fhevm/sdk/chains'; import { createPublicClient, http } from 'viem'; import { sepolia as viemSepolia } from 'viem/chains'; const publicClient = createPublicClient({ chain: viemSepolia, transport: http('https://ethereum-sepolia-rpc.publicnode.com'), }); const client = createFhevmClient({ chain: sepolia, publicClient });注意 viem 示例中出现了两个sepolia导入:@fhevm/sdk/chains提供的是FHEVM 链定义(合约地址、Relayer URL),而viem/chains提供的是 viem 自己的传输链。它们是不同的对象,两者都需要。
签名是「按调用」而不是「按客户端」
四个工厂都不接受signer或walletClient参数——Client 是只读的。当某个操作需要签名时(目前只有签署解密许可需要),把 signer 传给那个具体方法:
await client.signLegacyDecryptionPermit({ /* … */ signerAddress: await signer.getAddress(), signer, // ethers Signer,或 viem 的 Account / WalletClient });这保证了加密与公开读取完全无需钱包(wallet-free)。从类型定义看,Client 的只读性在 coreFhevmClient.ts 中被固化为readonly client字段(原生连接对象),配合FhevmBase接口中的readonly chain、readonly uid等不可变成员。
可选项(Options)
每个工厂都接受一个可选的options对象:
const client = createFhevmClient({ chain: sepolia, provider, options: { batchRpcCalls: true, // 把客户端的链上读取批量合并为 multicall }, });| 选项 | 类型 | 适用范围 | 作用 |
|---|---|---|---|
batchRpcCalls | boolean | 所有 Client | 把客户端的合约读取合并为批量 RPC 调用(multicall) |
fheEncryptionKey | FheEncryptionKeyBytes | encrypt / full | 提供预取的 FHE 公钥,跳过网络拉取 |
moduleVersions | FhevmModuleVersions | 因 Client 而异 | 固定 TFHE/TKMS WASM 的具体版本,而非使用默认值 |
从源码看,选项类型在 coreFhevmClient.ts 中被定义为分层结构:FhevmBaseOptions(仅batchRpcCalls)是所有 Client 的基础;FhevmEncryptOptions = FhevmBaseOptions & { fheEncryptionKey?, moduleVersions? };FhevmDecryptOptions = FhevmBaseOptions & { moduleVersions? };完整版FhevmOptions则同时包含前两者。
moduleVersions的取值定义在 moduleVersions.ts:可以是'auto',也可以显式指定tfhe/kms版本,并配合checkCompatibility: 'throw' | 'warn' | 'off'控制版本与协议兼容表的校验行为。模块版本固定与加密密钥缓存详见 Runtime configuration。
加载与生命周期
构造 Client 是瞬时操作,不产生任何 I/O。在加密或解密之前,需要await client.ready(或client.init())一次——它会解析协议版本,并下载、编译该 Client 所需的 WASM。encryptValues、decryptValue、generateTransportKeyPair都依赖这一步,未完成会直接抛错;唯一的例外是decryptPublicValues——它从 Relayer 解析所需内容,无需事先init()即可工作。
建议把await client.ready放在你能控制的时机——例如启动画面(splash screen)或路由切换时:
const client = createFhevmClient({ chain: sepolia, provider }); await client.ready; // 解析版本,下载 + 编译 WASM,仅一次每个 Client 暴露一组精简的生命周期成员:
| 成员 | 类型 | 说明 |
|---|---|---|
init() | () => Promise<void> | 预加载并编译该 Client 的 WASM 模块 |
ready | Promise<void> | 在 Client 可使用时 resolve |
uid | string | 该 Client 实例的稳定标识符 |
chain | FhevmChain | 创建 Client 时使用的链定义 |
protocolVersion | 解析结果对象 | 该链已解析的 FHEVM 协议版本 |
extend(actions) | 函数 | 附加额外 action 方法(高级/内部用途) |
重复调用init()是安全的——模块初始化按 WASM 版本缓存。某个 WASM 版本被一个 Client 实例独占;如果创建第二个尝试加载同一版本的 Client 会抛错。实践中建议:每个页面创建一个 Client 并复用。
从源码看,init()与ready的定义位于 coreFhevmClient.ts 的Fhevm接口(readonly init: () => Promise<void>、readonly ready: Promise<void>);基础初始化会调用ensureFrozenContext(见 base.ts 的_initBase),先解析并缓存冻结的版本基座;加密初始化则由 encrypt.ts 中的_initEncrypt负责。extend的类型签名也明确要求返回this & actions,印证了「装饰器叠加出能力」的架构。
实践中只加密 / 只解密的用法
一个常见模式是按路由拆分 dApp。例如一个只负责加密的「提交」页面:
import { createFhevmEncryptClient } from '@fhevm/sdk/ethers'; const client = createFhevmEncryptClient({ chain: sepolia, provider }); // 暴露 encryptValue / encryptValues(+ 公开解密 + 许可辅助方法)一个只回读私有值的「结果」页面:
import { createFhevmDecryptClient } from '@fhevm/sdk/ethers'; const client = createFhevmDecryptClient({ chain: sepolia, provider }); // 暴露 decryptValue / decryptValues / generateTransportKeyPair(+ 公开解密 + 许可辅助方法)每个页面只下载自己需要的 WASM。具体方法细节参见 Encryption 与 Decryption。
进一步阅读
- Encryption —— 加密值并构造输入证明;
- Decryption —— 私有解密、公开值、委托;
- Runtime configuration —— 线程、WASM 加载、版本固定;
- Chains —— FHEVM 链定义与内置链;
- API reference —— 完整的工厂与方法签名;
- Architecture —— 客户端与运行时架构;
- SDK 源码目录 sdk/js-sdk/src,其中
ethers/clients/与viem/clients/为两套适配器实现,core/clients/decorators/为共享的 actions 装饰器,core/types/为类型定义。
【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考