wagmi Tempo `policy.create` 完全指南:用白名单/黑名单策略为 Token 转账做访问控制
2026/9/17 7:12:19 网站建设 项目流程

wagmi Tempopolicy.create完全指南:用白名单/黑名单策略为 Token 转账做访问控制

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

本文是 wagmi 仓库中 Tempo 模块policy.create动作(Action)的深度实战指南。policy.create用于创建一条全新的转账策略(transfer policy),实现 Token 层面的访问控制:白名单策略只允许被列入的地址转账,黑名单策略则允许除列入地址外的所有地址转账。读完本文,你将掌握create/createSync两种调用形态的完整用法、全部参数语义、返回值结构,以及它在核心包源码中的底层调用链与测试验证,并了解与之配套的setAdminmodifyWhitelistmodifyBlacklistgetDataisAuthorizedwatchCreate等策略生命周期操作。

1.policy.create是什么

在 Tempo 协议(TIP-403 相关规范)中,转账策略是一种用于 Token 访问控制的可编程规则。每条策略都有一个唯一 ID(policyId),并归属于一个管理员(admin)。策略决定了哪些地址被允许或禁止进行 Token 转账操作。

policy.create是创建该策略的入口动作,它支持两种策略类型:

类型行为
'whitelist'仅允许被列入addresses的地址进行转账
'blacklist'允许所有地址转账,但被列入addresses的地址除外

从源码结构看,策略创建只是整个policy模块的一部分。在 packages/core/src/tempo/actions/policy.ts 中,与create并列的还有setAdmin(设置管理员)、modifyWhitelist(增删白名单成员)、modifyBlacklist(增删黑名单成员)、getData(读取策略数据)、isAuthorized(校验地址是否被授权)以及watchCreate/watchAdminUpdated/watchWhitelistUpdated/watchBlacklistUpdated等事件监听函数,共同构成策略的完整生命周期。

本文对应仓库文档:site/tempo/actions/policy.create.md。

2. 环境准备:创建 Tempo 链的 wagmi Config

在调用任何 Tempo 动作之前,需要先构造一个连接到 Tempo 链的 wagmi Config。仓库中的标准示例位于 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(), }, })

要点说明:

  • tempoWallet()是仓库packages/connectors中提供的 Tempo 钱包连接器,负责提供签名账户;
  • chains: [tempo]指定应用运行在 Tempo 链上;
  • multiInjectedProviderDiscovery: false关闭多注入 Provider 探测,避免与 Tempo 钱包之外的浏览器钱包冲突;
  • transports中为 Tempo 链配置http()传输层,用于读写链上数据。

3. 同步用法:Actions.policy.createSync

createSynccreate的同步变体:它会等待交易被打包上链后再返回结果。适合对响应延迟不敏感、希望一步拿到策略 ID 和交易收据的场景。

import { Actions } from 'wagmi/tempo' import { config } from './config' const { policyId, policyType, receipt } = await Actions.policy.createSync(config, { addresses: [ '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb', '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', ], type: 'whitelist', }) console.log('Policy ID:', policyId) // @log: Policy ID: 1n

返回值中的receipt是完整的TransactionReceipt,可用于进一步确认交易状态(如receipt.transactionHash)。

从源码看,createSync的实现位于 packages/core/src/tempo/actions/policy.ts:

export async function createSync<config extends Config>( config: config, parameters: createSync.Parameters<config>, ): Promise<Actions.policy.createSync.ReturnValue> { const { account, chainId, connector } = parameters const client = await getConnectorClient(config, { account, assertChainId: false, chainId, connector, }) return Actions.policy.createSync(client, parameters as never) }

关键点:

  • 它先通过getConnectorClient从 wagmi Config 中解析出连接器客户端(支持account/chainId/connector覆盖);
  • assertChainId: false表示不强制校验当前链 ID,允许调用方显式指定目标链;
  • 随后将底层执行委托给 viem 的Actions.policy.createSync,也就是说 wagmi 的 Tempo 动作是建立在 viem Tempo 动作之上的一层框架适配(获取连接器客户端、注入 wagmi Config 上下文)。

4. 异步用法:Actions.policy.create+ 手动等待

如果你更关注性能,不希望动作阻塞到交易确认,则应使用非 Sync 版本policy.create。它只返回交易哈希,随后由你手动等待交易收据,并通过事件解析出policyId

import { Actions as viem_Actions } from 'viem/tempo' import { Actions } from 'wagmi/tempo' import { waitForTransactionReceipt } from 'wagmi/actions' const hash = await Actions.policy.create(config, { addresses: [ '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb', '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', ], type: 'whitelist', }) const receipt = await waitForTransactionReceipt(config, { hash }) const { args: { policyId } } = viem_Actions.policy.create.extractEvent(receipt.logs)

这种“先拿 hash、后查收据”的模式,可以在交易在途(pending)期间继续做其他事情,例如同时发起多笔策略操作或展示交易进度。extractEvent是 viem Tempo 动作提供的事件解析工具,可从收据日志中精确提取PolicyCreated事件的参数。

两种形态的选择建议:

  • 需要尽快拿到policyId或对后续逻辑强依赖收据 → 用createSync
  • 需要并发执行多笔交易、优化吞吐 → 用create+waitForTransactionReceipt

5. 返回值结构(Return Type)

无论create还是createSync,最终返回的数据形状如下:

type ReturnType = { /** ID of the created policy */ policyId: bigint /** Type of the policy (0 = whitelist, 1 = blacklist) */ policyType: number /** Transaction receipt */ receipt: TransactionReceipt /** Address that created the policy */ updater: Address }

字段含义:

  • policyId:新建策略的唯一 ID(bigint),后续setAdminmodifyWhitelistmodifyBlacklistgetDataisAuthorized等动作都需要它作为入参;
  • policyType:策略类型的数值编码,0表示白名单、1表示黑名单;
  • receipt:交易收据,Sync 变体返回已确认的收据;
  • updater:发起创建操作的地址,通常即当前连接的账户地址。

上述数值编码(0 = whitelist, 1 = blacklist)在仓库测试中也有印证:见 packages/core/src/tempo/actions/policy.test.ts,其中断言createSync创建白名单策略后policyType0、黑名单策略后为1,且updater等于当前连接的账户地址。

6. 参数详解

6.1 type(必填)

  • 类型:'whitelist' | 'blacklist'

要创建的策略类型。白名单策略只允许被列入的地址,黑名单策略允许除被列入地址之外的所有地址。这也是policyType返回值(0 / 1)对应的语义来源。

6.2 addresses(可选)

  • 类型:Address[]

用于初始化策略的地址数组。创建时即把一批地址写入白名单或黑名单,省去创建后再逐条modifyWhitelist/modifyBlacklist的步骤。

6.3 通用写交易参数(optional)

以下参数来自仓库中共享的参数说明文档 site/shared/tempo-write-parameters.md,适用于包括policy.create在内的所有 Tempo 写动作:

参数类型说明
accountAccount \| Address用于发送交易的账户,默认使用已连接的 wagmi 账户
feeTokenAddress \| bigint交易的费用 Token,可以是 TIP-20 Token 地址或 ID
feePayerAccount \| true代付费用的账户;可传 Viem Account,若使用 Fee Payer Service 则传true
gasbigint交易的 Gas 上限
maxFeePerGasbigint交易的每单位 Gas 最高费用
maxPriorityFeePerGasbigint交易的每单位 Gas 最高优先费(小费)
noncenumber交易的 nonce
nonceKey'expiring' \| bigint交易的 nonce key
validBeforenumber交易必须被包含进区块的 Unix 时间戳上限
validAfternumber交易可以被包含进区块的 Unix 时间戳下限
throwOnReceiptRevertboolean(默认true收据显示回滚时是否抛错,仅对*Sync动作生效

这些参数通过源码中的OptionalTransactionOverrides类型(见 packages/core/src/tempo/actions/utils.ts)被声明为可选,从而在保持类型安全的同时让调用保持简洁。需要特别说明的是:

  • feeToken/feePayer体现了 Tempo 链的**代付(sponsored transaction)**能力:应用可以为用户代付 Gas,从而改善新用户的上手体验;
  • validBefore/validAfter是时间有效性窗口,超出窗口交易将无法被打包;
  • throwOnReceiptRevert默认true,意味着 Sync 变体在遇到链上回滚时会直接抛错,避免拿到“已入块但失败”的静默结果。

7. 源码级实现:从 wagmi 到 viem 的委托链路

policy.createpolicy.createSync的实现非常简洁,核心逻辑完全复用 viem 的 Tempo 动作:

  • create(见 packages/core/src/tempo/actions/policy.ts):解析account/chainId/connectorgetConnectorClient获取客户端 → 委托Actions.policy.create(client, parameters)
  • createSync(见 packages/core/src/tempo/actions/policy.ts):同样的链路,只是委托给 viem 的createSync变体;
  • 两者的Parameters类型均通过ChainIdParameterConnectorParameterOptionalTransactionOverrides组合而来,并剔除了底层 viem 参数中的'chain' | 'admin'admin由创建时的调用账户决定)。

这一层抽象的收益在于:wagmi 负责框架集成(Config、连接器、账户解析),viem 负责链上协议细节(交易组装、事件解析),两者的分工清晰。

8. 测试验证:策略行为与特殊策略 ID

仓库为策略模块提供了完整的集成测试,见 packages/core/src/tempo/actions/policy.test.ts。与create直接相关的验证包括:

  • 白名单创建(第 15-35 行):createSync(config, { type: 'whitelist' })返回的policyType === 0,随后用getData读取到admin为当前账户、type'whitelist',证明策略确实上链生效;
  • 黑名单创建(第 37-57 行):policyType === 1getData返回type: 'blacklist'
  • 特殊策略 ID(第 287-302 行):测试还揭示了两个内置的特殊策略——policyId: 0n恒为拒绝(always-reject),policyId: 1n恒为允许(always-allow)。这意味着即使尚未创建任何策略,也可以通过固定 ID 快速引用“全局禁止/全局放行”的语义。

测试流程统一为:connect(config, { connector: config.connectors[0] })连接测试账户 → 执行createSync→ 用getData/isAuthorized反向验证结果,形成一个完整的“创建-验证”闭环。

9. React 声明式用法:Hooks.policy.useCreate/useCreateSync

如果你使用 React 框架,仓库在wagmi/tempo入口中同时提供了对应的 Hooks 封装,位于 packages/react/src/tempo/hooks/policy.ts:

import { Hooks } from 'wagmi/tempo' function App() { const { mutate, isPending } = Hooks.policy.useCreateSync() return ( <button onClick={() => mutate({ type: 'whitelist' })} disabled={isPending} > Create Policy </button> ) }

实现要点(见 policy.ts):

  • useCreateSync内部通过useMutation封装Actions.policy.createSyncmutationKey['createSync']
  • useCreate对应非同步版本的Actions.policy.createmutationKey['create']
  • 返回的是标准的 TanStack QueryUseMutationResult,因此天然支持isPendingisErrorerroronSuccess等状态管理;
  • 同文件还提供了useSetAdminuseModifyWhitelistuseModifyBlacklistuseDatauseIsAuthorized以及useWatchCreate等系列 Hook,可与useCreate组合成完整的策略管理界面。

10. 相关动作与文档索引

创建策略只是起点,完整的策略生命周期还需要配合以下动作(全部基于policyId操作):

动作用途文档
policy.setAdmin更换策略管理员(需当前管理员权限)policy.setAdmin
policy.modifyWhitelist增删白名单成员(allowed: true/falsepolicy.modifyWhitelist
policy.modifyBlacklist增删黑名单成员(restricted: true/falsepolicy.modifyBlacklist
policy.getData读取策略数据(admin、type 等)policy.getData
policy.isAuthorized校验某个地址是否被策略授权policy.isAuthorized
policy.watchCreate监听策略创建事件policy.watchCreate

典型组合流程为:

  1. policy.createSync(config, { type: 'whitelist', addresses: [...] })创建策略并拿到policyId
  2. policy.modifyWhitelist动态增删成员;
  3. policy.isAuthorized在转账前校验地址权限;
  4. 需要转移管理权时调用policy.setAdmin

11. 注意事项与最佳实践

  • *Sync与性能的权衡createSync会阻塞到交易上链,在高频场景下优先使用非同步版本并配合waitForTransactionReceipt
  • 不要丢失policyId:它是后续所有策略操作的唯一凭证,建议创建成功后立即持久化(例如关联到业务实体存储);
  • 善用addresses初始化:一次性初始化成员列表,比创建后逐条 modify 更省 Gas;
  • 理解throwOnReceiptRevert:默认开启意味着 Sync 变体对链上回滚零容忍,若你的业务希望宽容处理回滚,可显式传入false
  • 特殊策略 ID0n(恒拒绝)与1n(恒允许)是内置策略,可用来表达全局开关语义,无需实际创建。

延伸阅读

  • Tempo 模块总览:site/tempo/index.md、site/tempo/actions/index.md
  • 核心实现:packages/core/src/tempo/actions/policy.ts
  • 集成测试:packages/core/src/tempo/actions/policy.test.ts
  • React Hooks 实现:packages/react/src/tempo/hooks/policy.ts
  • 共享写交易参数:site/shared/tempo-write-parameters.md

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

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

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

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

立即咨询