wagmi Tempo `zone.encryptedDeposit` 实战指南:向 Zone 加密存入 TIP-20 代币
2026/9/17 10:35:28 网站建设 项目流程

wagmi Tempozone.encryptedDeposit实战指南:向 Zone 加密存入 TIP-20 代币

【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi

导读

本文围绕 wagmi 的 Tempo 扩展模块中zone.encryptedDeposit这一核心 action 展开,讲解如何以「加密的接收方(recipient)与备注(memo)」向指定 Zone 的 Portal 合约存入 TIP-20 代币。你将掌握zone.encryptedDeposit(异步,返回交易哈希)与zone.encryptedDepositSync(同步,等待上链后返回回执)两种调用方式、完整参数语义、底层加密原理与交易构造细节,并了解其在 React 中的 Hook 用法,可直接用于 Tempo 网络的隐私存款类业务。

一、功能概览:什么是zone.encryptedDeposit

zone.encryptedDeposit是 wagmi Tempo 命名空间下针对「父链(parent Tempo chain)向 Zone 存入资产」提供的 action。与普通的zone.deposit不同,它在发送存款交易之前,会在客户端本地将目标接收方地址与 memo 备注加密,再通过 Zone Portal 合约的depositEncrypted函数提交密文,从而让存款内容对链上观察者不可见,只有持有对应解密能力的 sequencer 才能还原出真实的接收方与备注。

文档原意(见 zone.encryptedDeposit.md)明确指出:

  • 需要viem >= 2.48.0才能使用 Zone actions 与 hooks;
  • *Sync变体(zone.encryptedDepositSync)会等待交易被打包进区块后再返回,返回的是交易回执;
  • 非 sync 的zone.encryptedDeposit立即返回交易哈希,适合对性能敏感、希望自行管理「等待上链」流程的场景。

从源码 zone.ts 的 JSDoc 可以看到同一描述:Deposits tokens into a zone on the parent Tempo chain with an encrypted recipient and memo.,返回值为交易哈希;而encryptedDepositSync(zone.ts)则是「waits for the transaction to be included on a block before returning a response」,返回{ receipt }

二、快速上手:同步存入(encryptedDepositSync

文档给出的最简用法如下,使用*Sync变体,直接拿到回执并打印交易哈希:

import { Actions } from 'wagmi/tempo' import { parseUnits } from 'viem' import { config } from './config' const result = await Actions.zone.encryptedDepositSync(config, { amount: parseUnits('10', 6), token: '0x20c0000000000000000000000000000000000001', zoneId: 7, }) console.log('Transaction hash:', result.receipt.transactionHash)

其中config是标准的 wagmi 配置,需要包含 Tempo 网络与tempoWallet连接器(参考 site/snippets/react/config-tempo.ts):

import { createConfig, http } from 'wagmi' import { tempo } from 'wagmi/chains' import { tempoWallet } from 'wagmi/tempo' export const config = createConfig({ connectors: [tempoWallet()], chains: [tempo], multiInjectedProviderDiscovery: false, transports: { [tempo.id]: http(), }, })

要点说明:

  • amount使用parseUnits('10', 6)构造,即 10 个 6 位小数的代币单位,符合 TIP-20 代币常见精度;
  • token传入一个示例 TIP-20 代币地址;若使用代币 ID,则传bigint(见下文参数表);
  • zoneId: 7为目标 Zone 的 ID,Portal 地址会由框架根据该 ID 解析。

三、异步用法:自行等待上链

当你希望「发出交易后立即继续执行」,可以采用非 sync 版本zone.encryptedDeposit,它只返回交易哈希,之后再用waitForTransactionReceipt手动等待交易被包含进区块:

import { Actions } from 'wagmi/tempo' import { parseUnits } from 'viem' import { waitForTransactionReceipt } from 'wagmi/actions' const hash = await Actions.zone.encryptedDeposit(config, { amount: parseUnits('10', 6), token: '0x20c0000000000000000000000000000000000001', zoneId: 7, }) const receipt = await waitForTransactionReceipt(config, { hash }) console.log(receipt.status)

两种用法的取舍非常清晰:Sync 变体开箱即用、语义直观,但会阻塞到交易上链非 sync 变体让你可以把「发送」与「确认」解耦,适合批量提交、并行等待或对接自定义监听逻辑的性能敏感场景。

四、返回值

zone.encryptedDepositSync的返回类型(来自 zone.ts 的return { receipt })如下:

type ReturnType = { /** Transaction receipt */ receipt: TransactionReceipt }

即返回交易回执对象,可通过receipt.transactionHash拿到交易哈希、通过receipt.status判断交易是否成功;zone.encryptedDeposit则直接返回Promise<Hash>(交易哈希)。测试用例 zone.test.ts 中对encryptedDepositSync断言result.receipt.status === 'success',对encryptedDeposit断言hash已定义,印证了上述两种返回形态。

五、参数详解

amount

  • 类型:bigint
  • 含义:要存入的代币数量。建议使用parseUnits按代币精度换算,避免浮点精度问题。

token

  • 类型:Address | bigint
  • 含义:要存入的 TIP-20 代币的地址或 ID。源码中通过TokenId.toAddress(token)统一将代币 ID 归一化为地址(zone.ts),所以两种形式皆可。

zoneId

  • 类型:number
  • 含义:目标 Zone 的 ID。框架通过resolvePortal(config, resolvedChainId, zoneId)解析出该 Zone 对应的 Portal 合约地址(zone.ts)。

memo(可选)

  • 类型:Hex
  • 含义:可选备注,会与接收方地址一起被加密。若未传入,源码默认memo = zeroHash(zone.ts)。

recipient(可选)

  • 类型:Address
  • 含义:目标 Zone 内的接收方地址,默认在加密前回退为当前已连接账户的地址(recipient = accountAddress,见 zone.ts)。加密后该地址在链上不可见,起到隐私保护作用。

通用交易参数(可选)

以下参数由@shared/tempo-write-parameters.md(tempo-write-parameters.md)统一提供,适用于所有 Tempo 写入类 action:

参数类型说明
accountAccount \| Address发送交易使用的账户,默认使用已连接的 wagmi 账户
feeTokenAddress \| bigint交易手续费代币,可为 TIP-20 代币地址或 ID
feePayerAccount \| true手续费支付方;可为 viem Account,或设为true表示使用 Fee Payer Service
gasbigint交易的 gas 上限
maxFeePerGasbigint交易的最大每单位 gas 费用
maxPriorityFeePerGasbigint交易的最大优先费
noncenumber交易 nonce
nonceKey'expiring' \| bigint交易 nonce key
validBeforenumber交易必须在此 Unix 时间戳之前被打包
validAfternumber交易可被打包的时间点(Unix 时间戳)之后
throwOnReceiptRevertboolean(默认true仅对*Syncaction 生效;若回执显示 revert 则抛出错误

另外,参数类型还包含chainIdconnector(见encryptedDeposit.Parameters的定义,zone.ts):chainId用于显式指定父链 ID,connector用于指定使用的连接器;测试中即通过chainId: parentChain.id显式指定(zone.test.ts)。

六、底层原理:加密与交易是如何构造的

这一节结合 zone.ts 源码,梳理encryptedDeposit/encryptedDepositSync内部的完整调用链,帮助理解「加密存款」究竟做了什么。

6.1 Portal 地址与加密密钥的解析

resolvePortal(config, chainId, zoneId)(zone.ts)按以下优先级解析 Portal:

  1. 若链配置中chain.contracts.zonePortal是字符串,则直接作为 Portal 地址;
  2. zonePortal是按zoneId索引的对象,则取出对应 Zone 的 Portal 配置(可能附带encryptionKeyCountsequencerEncryptionKey,用于跳过链上读取);
  3. 否则回退到框架内置的portalAddresses映射表;
  4. 全部失败则抛出No portal address configured for zone ...错误。

得到 Portal 地址后,若链配置未提供加密密钥,框架会通过viem_readContract调用 Portal 的sequencerEncryptionKeyencryptionKeyCount两个 view 函数,获取 sequencer 的 secp256k1 公钥({ x, yParity })与当前加密密钥计数(zone.ts)。若keyIndex === 0n会抛出No sequencer encryption key configured.,表示该 Zone 尚未配置加密密钥,无法执行加密存款。

6.2 ECIES 风格的本地加密

encryptDepositPayload(publicKey, recipient, memo)(zone.ts)在客户端完成 ECIES 风格的加密流程:

  1. 用 sequencer 公钥与临时生成的 secp256k1 密钥对,通过Secp256k1.getSharedSecret计算共享密钥;
  2. 以 HKDF-SHA-256(盐为 12 字节零向量、info 为'ecies-aes-key')派生 256 位 AES 密钥;
  3. 生成 12 字节随机 nonce,将recipientaddress)与memobytes32)用 ABI 编码为明文(encodeAbiParameters);
  4. 用 AES-GCM(tagLength: 128)加密,输出ciphertexttag以及临时公钥的ephemeralPubkeyXephemeralPubkeyYParitynonce

这些字段最终作为depositEncrypted的密文载荷提交上链,只有持有对应私钥的 sequencer 才能解密还原接收方与备注。

6.3 两段式交易:approve + depositEncrypted

无论 sync 还是非 sync 版本,最终都会构造一条包含两个 call 的交易(zone.ts):

  1. 第一个 call 调用 TIP-20 代币的approve(portalAddress, amount),授权 Portal 划转代币;
  2. 第二个 call 调用 Zone Portal 的depositEncrypted(tokenAddress, amount, keyIndex - 1n, encrypted, bouncebackRecipient),完成加密存款。

其中keyIndex - 1n指向本次加密使用的密钥索引,bouncebackRecipient默认等于发送方账户地址,用于失败时的退回地址。整个流程可通过viem_sendTransaction(非 sync)或viem_sendTransactionSync(sync,配合throwOnReceiptRevert)发送。

从测试用例看,还支持「预生成好的加密载荷」直接传入:getPreparedEncryptedDeposit()返回含encrypted字段的参数,源码中if ('encrypted' in rest_)分支会直接把预加密载荷透传给 viem 的 Tempo action(zone.ts),测试断言其返回回执状态为success(zone.test.ts)。这为「离线/预加密再广播」的高级流程保留了扩展点。

七、React 中使用 Hook 版本

除了命令式 action,React 侧还提供了对应的 mutation hooks(见 packages/react/src/tempo/hooks/zone.ts):

import { Hooks } from 'wagmi/tempo' function App() { const { mutate, isPending } = Hooks.zone.useEncryptedDeposit() return ( <button onClick={() => mutate({ amount: 1_000_000n, token: '0x20c0000000000000000000000000000000000001', zoneId: 7, }) } disabled={isPending} > Encrypted Deposit </button> ) }
  • useEncryptedDeposit内部包装Actions.zone.encryptedDeposit,mutation key 为['encryptedDeposit'],返回{ hash }
  • useEncryptedDepositSync(zone.ts)包装Actions.zone.encryptedDepositSync,mutation key 为['encryptedDepositSync'],返回{ receipt }

两个 Hook 均支持通过mutation配置项透传 TanStack Query 的UseMutationParameters,可自定义onSuccessonErroronSettled等回调,参数类型与 action 一致。若使用同步 Hook,isPending会持续到交易确认上链为止。

八、注意事项与边界

  • 版本约束:zone.encryptedDeposit及其 hooks 需要viem >= 2.48.0,请确保项目依赖满足该版本;
  • 先连接后调用:action 内部通过getConnectorClient获取已连接客户端,并断言存在账户(account_缺失时抛出`account` is required.),因此调用前需先完成钱包连接(测试中也先connect(config, { connector }),见 zone.test.ts);
  • chainId必须可解析:若未显式传入chainId,会回退到client.chain?.id,两者皆无时抛出`chainId` is required.
  • 加密密钥缺失时无法使用:若 Zone Portal 未配置 sequencer 加密密钥(encryptionKeyCount === 0n),加密存款将报错,此时应考虑普通zone.deposit
  • 回执回滚:使用*Sync变体时默认throwOnReceiptRevert = true,交易回滚会直接抛错,如需自行处理可显式传throwOnReceiptRevert: false

相关文档与源码

  • zone.encryptedDeposit 文档
  • 通用 Tempo 写入参数
  • 核心实现:zone.ts
  • React Hook 实现:hooks/zone.ts
  • 测试用例:zone.test.ts
  • Tempo 配置示例

【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询