wagmi Tempo 链上事件监听实战:`policy.watchCreate` 监听策略创建事件的完整指南
2026/9/18 8:49:45 网站建设 项目流程

wagmi Tempo 链上事件监听实战:policy.watchCreate监听策略创建事件的完整指南

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

本篇指南以 wagmi 仓库中site/tempo/actions/policy.watchCreate.md文档为核心,系统讲解 Tempo 链上 TIP403 策略(Policy)注册表中"策略创建事件"的实时监听方案。你将掌握Actions.policy.watchCreate的调用方式、完整参数语义、底层实现原理,以及如何在 React 应用中通过Hooks.policy.useWatchCreate声明式监听,并能结合仓库源码与测试用例验证监听行为。本文适用于需要在 Tempo 链上构建代币访问控制、合规风控或链上审计类应用的前端开发者。

背景:TIP403 策略注册表与事件监听的意义

Tempo 链引入了一套**传输策略(Transfer Policy)**机制,用于对 TIP-20 代币的转账进行访问控制。在site/tempo/actions/index.md中,Policy Actions 被定义为"Creates a new transfer policy for token access control"(创建用于代币访问控制的传输策略)。一个策略可以是白名单类型(whitelist)或黑名单类型(blacklist),管理员可以后续修改名单、更换管理员,最终通过policy.isAuthorized判断某个地址是否被授权。

这些策略统一登记在TIP403 Registry(策略注册表)合约中。当任何账户通过policy.create/policy.createSync创建新策略时,注册表会发出对应的事件。policy.watchCreate就是 wagmi 为 Tempo 提供的、监听该"策略创建事件"的响应式原语——它订阅事件流,在每次新策略创建时回调你的处理函数。

监听类 Action 在整个 Tempo Action 体系中是独立的成员,与查询类(policy.getDatapolicy.isAuthorized)、写入类(policy.createpolicy.setAdminpolicy.modifyWhitelistpolicy.modifyBlacklist)形成互补,让应用既能发起操作,也能实时感知链上状态变化。

快速上手:监听策略创建事件

Actions.policy.watchCreate接收config与参数对象,返回一个取消订阅函数。最简用法如下(取自site/tempo/actions/policy.watchCreate.md的 Usage 示例):

import { Actions } from 'wagmi/tempo' import { config } from './config' const unwatch = Actions.policy.watchCreate(config, { onPolicyCreated(args, log) { console.log('args:', args) }, }) // Later, stop watching unwatch()

其中config需要是配置了 Tempo 链的 wagmi 配置。仓库中的模板配置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(), }, })

要点:chains必须包含tempo链,transportstempo.id配置http()传输层,并通过tempoWallet()注入钱包连接器。config也支持通过chainId参数显式指定要监听的链,默认使用配置中的链。

返回类型:一个"取消订阅"函数

policy.watchCreate的返回类型为() => void

它返回一个用于取消订阅事件的函数。调用后,事件监听立即终止。在组件卸载、页面切换或业务不再需要监听时务必调用,避免内存泄漏与无效 RPC 订阅。

参数详解

Actions.policy.watchCreate(config, parameters)的参数对象完整语义如下。

onPolicyCreated(必填)

  • 类型:function
declare function onPolicyCreated(args: Args, log: Log): void type Args = { /** ID of the created policy */ policyId: bigint /** Type of policy */ type: PolicyType /** Address that created the policy */ updater: Address }

策略创建成功时调用。回调收到两个参数:

  • args:事件解码参数。policyId为新建策略的 ID(bigint);type为策略类型(PolicyType);updater为创建策略的地址(Address)。
  • log:对应的原始事件日志对象,可用于获取区块号、交易哈希等链上元信息。

PolicyType的取值可以从仓库测试中得到印证:在packages/core/src/tempo/actions/policy.test.ts中,createSynctype: 'whitelist'创建时返回policyType: 0,以type: 'blacklist'创建时返回policyType: 1;而getData校验的结果data.type分别为'whitelist''blacklist'

args(可选)

  • 类型:object
type Args = { /** Filter by policy ID */ policyId?: bigint | bigint[] | null /** Filter by updater address */ updater?: Address | Address[] | null }

可选过滤参数,用于缩小监听范围:

  • policyId:按策略 ID 过滤,可传单个bigintbigint[]。例如只关心某个特定策略是否被创建(注意创建事件产生的是新 ID,实际更常用于配合特定地址过滤)。
  • updater:按创建者地址过滤,可传单个AddressAddress[]。例如只监听当前用户或某组受信任地址发起的策略创建。

fromBlock(可选)

  • 类型:bigint

开始监听的起始区块。传入后将从该区块起扫描事件(含历史事件回放),不传则从最新区块开始监听。

onError(可选)

  • 类型:function
declare function onError(error: Error): void

当获取新区块时发生错误所调用的回调。订阅在运行期间可能因网络抖动、RPC 异常等原因出错,可通过该回调捕获Error并做日志记录或告警。

poll(可选)

  • 类型:true

启用轮询模式。默认情况下监听基于订阅推送,若你的环境(如某些不支持订阅的 RPC 端点)需要轮询,可传入poll: true

pollingInterval(可选)

  • 类型:number

轮询频率(毫秒)。仅在启用轮询模式时生效;未显式传入时,默认使用ClientpollingInterval配置。

源码级实现:从 wagmi 到 viem 的委托调用链

policy.watchCreate并不是重新实现的事件订阅逻辑,而是对底层viem/tempoAction 的类型安全封装。核心实现位于packages/core/src/tempo/actions/policy.tswatchCreate函数:

export function watchCreate<config extends Config>( config: config, parameters: watchCreate.Parameters<config>, ) { const { chainId, ...rest } = parameters const client = config.getClient({ chainId }) return Actions.policy.watchCreate(client, rest) } export declare namespace watchCreate { export type Parameters<config extends Config> = ChainIdParameter<config> & Actions.policy.watchCreate.Parameters }

调用链可以概括为三层:

  1. 参数拆分:从参数中解构出chainId,其余参数(onPolicyCreatedargsfromBlockonErrorpollpollingInterval等)原样透传。
  2. 客户端获取:通过config.getClient({ chainId })取得对应链的 viem 客户端——这与查询类 Action(如getDataisAuthorized使用config.getClient)一致;而写入类 Action(createsetAdmin)则使用getConnectorClient获取连接器客户端,因为写入需要钱包签名。
  3. 委托底层:将客户端与参数一并交给Actions.policy.watchCreate(client, rest)执行真实的事件监听,并把返回的取消订阅函数直接返回给调用方。

Parameters类型通过交叉类型合并了ChainIdParameter(可显式指定chainId)与 viem 底层的Actions.policy.watchCreate.Parameters,保证类型提示与底层完全对齐。这也解释了为何原文档在"Viem"一节标注了policy.watchCreate的 viem 对应关系:wagmi 的 Tempo Actions 本质上是 viem Tempo Actions 的配置感知封装。

测试验证:监听行为如何被确认

仓库在packages/core/src/tempo/actions/policy.test.ts中为watchCreate编写了端到端测试,可以直接印证文档描述的行为:

describe('watchCreate', () => { test('default', async () => { await connect(config, { connector: config.connectors[0]!, }) const events: any[] = [] const unwatch = policy.watchCreate(config, { onPolicyCreated: (args, log) => { events.push({ args, log }) }, }) // create policy await policy.createSync(config, { type: 'whitelist', }) await vi.waitFor(() => { expect(events.length).toBeGreaterThanOrEqual(1) }) unwatch() expect(events[0].args.policyId).toBeDefined() expect(events[0].args.updater).toBe(account.address) expect(events[0].args.type).toBe('whitelist') }) })

该测试完整还原了"先订阅、再触发、后断言"的标准流程:

  1. connect连接config.connectors[0]对应的测试账户;
  2. 调用watchCreate注册onPolicyCreated回调,将事件推入events数组;
  3. 通过createSync实际创建一条whitelist类型策略,触发注册表事件;
  4. vi.waitFor等待事件到达,断言args.policyId已定义、args.updater为发起创建的交易账户地址、args.type'whitelist'
  5. 最后调用unwatch()取消订阅。

这组断言与文档中Args的三个字段(policyIdtypeupdater)一一对应,是理解事件负载的最佳范例。同一测试文件中,watchAdminUpdatedwatchWhitelistUpdatedwatchBlacklistUpdated的测试采用了相同的模式,说明"watch 系列"Action 的参数与行为约定完全一致。

React 集成:Hooks.policy.useWatchCreate声明式监听

在 React 应用中无需手动管理unwatch,可直接使用Hooks.policy.useWatchCreate。其实现位于packages/react/src/tempo/hooks/policy.ts

import { Hooks } from 'wagmi/tempo' function App() { Hooks.policy.useWatchCreate({ onPolicyCreated(args) { console.log('Policy created:', args) }, }) return <div>Watching for policy creation...</div> }

Hook 内部通过useEffect封装了完整的订阅生命周期:

export function useWatchCreate< config extends Config = ResolvedRegister['config'], >(parameters: useWatchCreate.Parameters<config> = {}) { const { enabled = true, onPolicyCreated, ...rest } = parameters const config = useConfig({ config: parameters.config }) const configChainId = useChainId({ config }) const chainId = parameters.chainId ?? configChainId useEffect(() => { if (!enabled) return if (!onPolicyCreated) return return Actions.policy.watchCreate(config, { ...rest, chainId, onPolicyCreated, }) }, [ config, enabled, chainId, onPolicyCreated, rest.fromBlock, rest.onError, rest.poll, rest.pollingInterval, ]) }

值得注意的设计细节:

  • 自动清理useEffect的清理函数正是Actions.policy.watchCreate返回的unwatch,组件卸载时自动取消订阅;
  • enabled开关:额外提供的enabled?: boolean参数(默认true),置为false时可暂停监听而不卸载组件;
  • 响应式依赖chainId默认取自useChainId,链切换时自动重订阅;fromBlockonErrorpollpollingInterval等参数变化同样会触发重建订阅;
  • config透传:可通过parameters.config覆盖默认的 wagmi 配置。

Hook 的参数类型useWatchCreate.ParametersActions.policy.watchCreate.Parameters的 ExactPartial 版本,并额外合并了ConfigParameterenabled,因此核心参数语义与命令式版本完全一致。

与策略生命周期其他 Action 的配合

watchCreate不是孤立存在的,它是策略生命周期管理的一部分。完整的 Policy Actions 清单见site/tempo/actions/index.md,以下是与事件监听最常配合的相邻 Action:

Action作用配合场景
policy.create/createSync创建传输策略触发watchCreate事件的来源
policy.getData读取策略数据(管理员、类型)收到创建事件后用policyId反查策略详情
policy.isAuthorized判断地址是否被策略授权事件驱动的权限校验
policy.setAdmin更换策略管理员配合watchAdminUpdated监控管理变更
policy.modifyWhitelist修改白名单配合watchWhitelistUpdated监控名单变更
policy.modifyBlacklist修改黑名单配合watchBlacklistUpdated监控名单变更

一个典型的实战组合是:监听watchCreate获得policyId→ 调用getData获取策略类型与管理员 → 通过isAuthorized判断某个用户是否受该策略约束。另外注意,isAuthorized存在两个特殊策略 ID(见packages/core/src/tempo/actions/policy.test.ts):policyId 0n为"永远拒绝"、policyId 1n为"永远允许",在业务逻辑中可作为特殊分支处理。

最佳实践与注意事项

  • 及时取消订阅:命令式用法务必在不需要时调用返回的unwatch();React 用法由 Hook 自动处理,但要注意enabled与依赖数组的配合。
  • 按需过滤:事件量大时优先使用argspolicyId/updater)过滤,减少无效回调与网络负载。
  • 轮询 vs 订阅:默认订阅模式实时性最好;RPC 不支持订阅或需要兼容性时启用poll: true并合理设置pollingInterval(未设置时沿用 Client 的pollingInterval配置)。
  • 错误处理:订阅期间区块拉取可能出错,通过onError捕获并记录,避免静默失败。
  • 历史回放:需要补偿缺失事件时使用fromBlock从指定区块开始监听,可结合最新区块号回溯补全。
  • 事件与交易联动watchCreate回调中的log对象可用于关联交易哈希、区块高度,与createSync返回的receipt相互印证。

延伸阅读

  • 本文核心参考:policy.watchCreate官方文档
  • Tempo Actions 总览(含全部 Policy/Token/DEX 等 Action):site/tempo/actions/index.md
  • 底层实现:packages/core/src/tempo/actions/policy.ts
  • 端到端测试:packages/core/src/tempo/actions/policy.test.ts
  • React Hook 实现:packages/react/src/tempo/hooks/policy.ts
  • Tempo 配置模板:site/snippets/react/config-tempo.ts

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

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

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

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

立即咨询