Wagmi Tempo 事件监听实战:使用reward.watchRewardRecipientSet跟踪奖励接收者变更
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
本文讲解 Wagmi 框架中 Tempo 链上reward.watchRewardRecipientSet动作(Action)的完整用法,涵盖参数详解、事件回调与过滤器、取消订阅生命周期,并结合 React HookuseWatchRewardRecipientSet与底层源码实现,帮助开发者在 Tempo 生态应用中实时监听代币持有者设置或更改奖励接收者的链上事件,并与其他 Reward 系列动作联动构建完整的奖励分发闭环。
动作概述:监听什么事件,为什么需要它
在 Tempo 链上,TIP-20 代币持有者可以通过reward.setRecipient为自己设置(或更改)奖励接收者地址。当这一状态发生变化时,链上会发出RewardRecipientSet事件。reward.watchRewardRecipientSet正是用于持续监听这类事件的动作:
- 当任意持有者设置奖励接收者时,回调立即触发;
- 回调携带事件参数
args(持有者地址与新的接收者地址)以及原始事件日志log; - 返回一个
unwatch函数,用于随时停止监听。
典型的应用场景包括:奖励分发面板中实时展示"谁更新了接收者"、审计/数据分析系统追踪接收者变更流水、以及在持有者退出奖励计划(设置为零地址)时做业务提醒。
该动作属于 Tempo Actions 总览 中 Reward Actions 分组的一员,与reward.setRecipient、reward.claim、reward.distribute、reward.watchRewardDistributed、reward.getUserRewardInfo共同构成完整的奖励机制。
前置准备:Tempo 配置文件
使用任何 Tempo 动作之前,都需要一个已连接 Tempo 链与钱包连接器的 Wagmi 配置。文档引用的是 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]声明目标链为 Tempo;connectors: [tempoWallet()]接入 Tempo 钱包连接器,事件监听依赖链上 RPC 而非钱包签名,因此监听动作本身无需用户连接钱包,但同一条 Reward 业务链路上的写操作(如setRecipient)需要账户;transports中为tempo.id指定http()传输层,事件轮询/订阅基于该 RPC 端点。
基本用法:开始监听与停止监听
文档中的标准示例(完整可运行):
import { Actions } from 'wagmi/tempo' import { config } from './config' const unwatch = Actions.reward.watchRewardRecipientSet(config, { onRewardRecipientSet(args, log) { console.log('args:', args) }, token: '0x20c0000000000000000000000000000000000000', }) // Later, stop watching unwatch()使用要点:
- 第一个参数是 Wagmi
config(即上面的createConfig结果); - 第二个参数是配置对象,
token必填,onRewardRecipientSet为事件回调; - 调用立即返回
unwatch函数,页面卸载、组件销毁或业务不再需要时务必调用以释放资源; - 回调中
log为 viem 的Log类型原始日志对象,包含blockNumber、transactionHash、address等链上元信息,便于追溯来源交易。
参数详解
onRewardRecipientSet(必填回调)
- 类型:
function
declare function onRewardRecipientSet(args: Args, log: Log): void type Args = { /** Token holder address who set their reward recipient */ holder: Address /** New reward recipient address (zero address indicates opt-out) */ recipient: Address }回调在每次事件发生时被调用:
args.holder:设置奖励接收者的代币持有者地址;args.recipient:新的奖励接收者地址。零地址表示该持有者已退出奖励计划(opt-out),此语义与reward.setRecipient中"使用零地址退出"的设计完全对应;log:完整的链上事件日志。
token(必填)
- 类型:
Address
要监听的 TIP-20 代币地址。监听粒度是"单个代币",如需同时跟踪多个代币,需要为每个代币分别调用一次watchRewardRecipientSet。
args(可选过滤器)
- 类型:
object
type Args = { /** Filter events by holder address */ holder?: Address /** Filter events by recipient address */ recipient?: Address }用于收窄监听范围:
- 只关心某个持有者的变更时传入
holder; - 只关心某个接收者被设置时传入
recipient; - 两者可组合使用。
当订阅方较多或代币活跃度高时,合理使用过滤器可以显著减少回调次数与 RPC 负载。从类型签名看,过滤器的取值沿用 viem Tempo 动作的参数定义(见下文源码解析中对Actions.reward.watchRewardRecipientSet.Parameters的透传)。
返回类型与生命周期管理
- 返回类型:
() => void
返回一个取消订阅函数。调用后监听立即停止,且幂等安全——重复调用不会产生副作用。在 SPA 应用中,推荐把该函数挂到组件的卸载阶段:
import { useEffect } from 'react' import { Actions } from 'wagmi/tempo' import { config } from './config' useEffect(() => { const unwatch = Actions.reward.watchRewardRecipientSet(config, { onRewardRecipientSet(args, log) { console.log('args:', args) }, token: '0x20c0000000000000000000000000000000000000', }) return unwatch }, [])这样监听的生命周期与组件生命周期严格对齐,避免内存泄漏与重复订阅。
源码实现:从 Wagmi 动作到 viem 底层
在 packages/core/src/tempo/actions/reward.ts 中,该动作的实现非常精简:
export function watchRewardRecipientSet<config extends Config>( config: config, parameters: watchRewardRecipientSet.Parameters<config>, ) { const { chainId, ...rest } = parameters const client = config.getClient({ chainId }) return Actions.reward.watchRewardRecipientSet(client, rest) } export declare namespace watchRewardRecipientSet { export type Parameters<config extends Config> = ChainIdParameter<config> & Actions.reward.watchRewardRecipientSet.Parameters }从源码可以确认两点实现事实:
- 参数透传:Wagmi 层将
chainId从参数中拆分出来,用于通过config.getClient({ chainId })获取对应链的 viem 客户端,其余参数(token、onRewardRecipientSet、过滤器等)原样透传给 viem 的Actions.reward.watchRewardRecipientSet,因此其类型签名直接继承自 viem Tempo 动作; - 客户端来源:监听动作复用 Wagmi
Config中按chainId管理的客户端,这保证了与同一 config 下其他读/写动作使用一致的 RPC 端点与连接器配置。
文件头部还展示了同模块的其他动作(claim、setRecipient、distribute、getUserRewardInfo等),它们与监听动作共享相同的config.getClient/getConnectorClient机制,便于组合使用。
React 场景:useWatchRewardRecipientSetHook
在 React 应用中,更推荐使用对应的 Hook 形式(见 packages/react/src/tempo/hooks/reward.ts):
import { Hooks } from 'wagmi/tempo' function App() { Hooks.reward.useWatchRewardRecipientSet({ token: '0x20c0000000000000000000000000000000000001', onRewardRecipientSet(args) { console.log('Reward recipient set:', args) }, }) return <div>Watching for reward recipient set events...</div> }Hook 的配置参数与 Wagmi Actionreward.watchRewardRecipientSetParameters 保持一致,并额外提供:
config:Config | undefined,可显式传入,缺省时从最近的WagmiProvider获取;enabled:boolean(默认true),为false时暂停监听;chainId:指定监听链;fromBlock、poll、pollingInterval、onError等底层监听参数(从源码中useEffect依赖数组可见,见 reward.ts)。
从源码实现看,Hook 内部通过useConfig与useChainId解析 config 与链 ID,并在useEffect中调用Actions.reward.watchRewardRecipientSet(config, ...);只有enabled、onRewardRecipientSet、token全部就绪时才建立监听,且依赖数组显式列出fromBlock、onError、poll、pollingInterval,这些参数变化时会自动重建订阅。useEffect的 cleanup 机制会调用返回的unwatch,因此组件卸载后无需手动清理。
与 Reward 系列动作组合:完整的业务闭环
watchRewardRecipientSet单独使用只能"看见"变更,要构成完整业务需与同组动作配合(参见 Tempo Actions 总览 中的 Reward Actions):
| 动作 | 职责 |
|---|---|
reward.setRecipient | 设置/更改奖励接收者(零地址 = 退出奖励) |
reward.watchRewardRecipientSet | 监听接收者变更事件(本文主题) |
reward.distribute | 向已加入(opted-in)的持有者分发奖励 |
reward.watchRewardDistributed | 监听奖励分发事件 |
reward.claim | 领取累积奖励 |
reward.getUserRewardInfo | 查询某账户的奖励余额、每代币奖励与当前接收者 |
组合示例——监听事件并联动查询最新状态:
import { Actions } from 'wagmi/tempo' import { config } from './config' const TOKEN = '0x20c0000000000000000000000000000000000000' const unwatch = Actions.reward.watchRewardRecipientSet(config, { token: TOKEN, onRewardRecipientSet: async ({ holder, recipient }, log) => { console.log(`Holder ${holder} set recipient to ${recipient}`) // 联动查询该持有者最新奖励信息 const { rewardBalance, rewardPerToken, rewardRecipient } = await Actions.reward.getUserRewardInfo(config, { account: holder, token: TOKEN, }) console.log({ rewardBalance, rewardPerToken, rewardRecipient }) }, })注意事项:
- 若
recipient为零地址,表示持有者退出奖励计划,处理逻辑应与正常设置区分开; - 若你同时在实现"设置接收者"功能,可参考
reward.setRecipient文档中的同步(setRecipientSync)与异步两种用法,以及"Rewards are automatically distributed to the current recipient before changing"的链上语义提示——接收者变更前,链会自动先把应得奖励结算给原接收者; - 性能优先时,监听回调内不要做阻塞式重操作,复杂的衍生计算建议放到队列或事件总线中异步处理。
总结
reward.watchRewardRecipientSet是 Tempo 奖励体系中面向"变更流"的监听动作:它通过 Wagmi 的config.getClient复用链客户端(源码见 packages/core/src/tempo/actions/reward.ts),将参数透传给 viem 的 Tempo 实现,并提供unwatch取消订阅函数以精确控制生命周期;React 侧对应的useWatchRewardRecipientSetHook(源码见 packages/react/src/tempo/hooks/reward.ts)则自动处理订阅与清理。掌握holder/recipient过滤器、零地址 opt-out 语义,并与setRecipient、getUserRewardInfo、distribute、claim组合使用,即可构建实时、完整的 Tempo 链上奖励分发应用。
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考