Wagmi Tempoamm.useLiquidityBalanceHook 详解:查询 AMM 流动性池的 LP 余额
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
本篇技术指南围绕 Wagmi Tempo 体系中的Hooks.amm.useLiquidityBalanceReact Hook 展开,它用于查询某个地址在指定流动性池(Liquidity Pool)中持有的 LP 代币余额。读者将掌握该 Hook 的完整用法、全部可选/必填参数与返回类型、底层amm.getLiquidityBalanceAction 的调用链,以及基于 TanStack Query 的缓存键(queryKey)与自动启停机制,从而在基于 Tempo 链的 DEX、Fee AMM 场景中直接落地使用。
背景:Tempo 的 Fee AMM 与 LP 余额
Tempo 是一条为支付场景专门设计的 Layer 1 区块链,将 token 管理(TIP-20)、Fee AMM 与稳定币 DEX(Stablecoin Exchange)直接内置于协议层。在 Tempo 的 AMM 中,用户可以通过向交易对注入 user token 与 validator token 来提供流动性,并因此获得对应数量的 LP 代币(Liquidity Provider token)。amm.useLiquidityBalance正是用来读取这笔 LP 持仓的 Hook:传入地址与池子定位信息,即可拿到该地址在该池中的流动性份额(以bigint返回)。
在 Wagmi 中,Tempo 的 React Hook 统一从wagmi/tempo入口导出,与普通 Wagmi Hook(如useSendTransactionSync)风格一致,且天然支持 TanStack Query 的缓存、重取与加载状态管理。完整环境搭建可参考 Tempo Getting Started。
基本用法
useLiquidityBalance是一个查询型(query)Hook,它通过池子定位参数定位到具体的 AMM 池,再查询给定地址在该池中的流动性余额:
import { Hooks } from 'wagmi/tempo' const { data: balance } = Hooks.amm.useLiquidityBalance({ address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb', userToken: '0x20c0000000000000000000000000000000000000', validatorToken: '0x20c0000000000000000000000000000000000001', }) console.log('Liquidity balance:', balance) // @log: Liquidity balance: 10500000000000000000n其中:
address是必填参数,表示要查询 LP 余额的账户地址;userToken与validatorToken共同定位池子(两者组合唯一确定一个交易对);- 返回值
balance是bigint,@log中展示的10500000000000000000n即余额的原始最小单位数值。
配套 Config
useLiquidityBalance依赖 Wagmi 的Config上下文。下面是一份最小可用的 Tempo 配置(见仓库中的 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(), }, })在组件树根部通过WagmiProvider config={config}挂载该配置后,任意组件内即可直接调用Hooks.amm.useLiquidityBalance,无需手动传入config(也可通过参数中的config字段显式覆盖,适用于测试或非 Provider 场景)。
参数(Parameters)
useLiquidityBalance的参数类型定义在 packages/react/src/tempo/hooks/amm.ts 中,是ConfigParameter、QueryParameter与 Action 参数的组合。以下参数与底层 amm.getLiquidityBalance Action 一一对应:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
address | Address | 是 | 要查询流动性余额的账户地址 |
poolId | Hex | 否 | 池 ID。若已知池 ID 可直接传入 |
userToken | Address \| bigint | 否 | 池中的 user token(地址或 token ID) |
validatorToken | Address \| bigint | 否 | 池中的 validator token(地址或 token ID) |
chainId | number | 否 | 目标链 ID,缺省时使用当前useChainId解析出的链 |
config | Config | 否 | 显式指定 Wagmi 配置,缺省时取上下文中的 config |
query | object | 否 | TanStack Query 查询选项(见下文) |
定位池子的两种方式
从getLiquidityBalance的参数设计看,池子定位存在两种等价的输入路径:
- 直接传
poolId:如果已经拿到池 ID(例如通过Hooks.amm.usePoolId({ userToken, validatorToken })查询得到),则只需address + poolId即可完成查询; - 传
userToken+validatorToken:通过交易对的两个 token 定位池子,此时无需知道池 ID。
在 Hook 源码的 JSDoc 示例中,官方演示了两种方式的组合使用(见 amm.ts):
const { data: poolId } = Hooks.amm.usePoolId({ userToken: '0x...', validatorToken: '0x...', }) const { data, isLoading } = Hooks.amm.useLiquidityBalance({ poolId, address: '0x20c...0055', }) if (isLoading) return <div>Loading...</div> return <div>LP Balance: {data?.toString()}</div>query 选项
query字段完整透传给 TanStack Query 的useQuery,可用于控制缓存、重取、选择器等行为,例如:
Hooks.amm.useLiquidityBalance({ address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbb', userToken: '0x20c0000000000000000000000000000000000000', validatorToken: '0x20c0000000000000000000000000000000000001', query: { select(data) { // 将 bigint 转为可读字符串,方便渲染 return data.toString() }, refetchInterval: 30_000, // 每 30 秒轮询一次余额 }, })返回类型(Return Type)
data的类型与底层 Action 的返回类型一致,即bigint(LP 流动性余额,以最小单位表示)。而 Hook 整体返回的是 TanStack Query 的查询结果对象(UseQueryReturnType),因此除了data之外,还包含以下常用状态字段:
isLoading/isFetching:是否处于首次加载 / 后台重取中;isError与error:查询失败状态与错误对象;isSuccess:查询是否成功;refetch:手动触发重新查询的函数;status:'pending' | 'error' | 'success'状态机。
由于data是bigint,直接渲染到 UI 前建议先toString()或进行精度格式化(例如除以 10 的 token 小数位次方),这一点在官方示例中也有体现。
源码级原理:从 Hook 到链上读请求
useLiquidityBalance的实现非常轻量,核心逻辑全部委托给 Core 层 Action,形成了清晰的调用链:
useLiquidityBalance (react) └─ Actions.amm.getLiquidityBalance.queryOptions(config, parameters) [core] └─ useQuery(options) [TanStack Query] └─ Actions.amm.getLiquidityBalance(client, parameters) [viem/tempo]React Hook 层
在 packages/react/src/tempo/hooks/amm.ts 中,useLiquidityBalance先通过useConfig获取配置、useChainId获取当前链 ID,然后用Actions.amm.getLiquidityBalance.queryOptions构建查询选项,最后交给useQuery执行:
export function useLiquidityBalance< config extends Config = ResolvedRegister['config'], selectData = Actions.amm.getLiquidityBalance.ReturnValue, >(parameters: useLiquidityBalance.Parameters<config, selectData> = {}) { const config = useConfig(parameters) const chainId = useChainId({ config }) const options = Actions.amm.getLiquidityBalance.queryOptions(config, { ...parameters, chainId: parameters.chainId ?? chainId, } as never) return useQuery(options) as never }注意chainId: parameters.chainId ?? chainId这行:当用户未显式传入chainId时,Hook 会自动跟随当前激活的链,多链场景下无需手动切换。
Core Action 层
在 packages/core/src/tempo/actions/amm.ts 中,getLiquidityBalance的queryOptions定义了两个关键行为:
- 自动启停(enabled):查询只有在必要参数齐备时才会真正发起请求:
enabled: Boolean( rest.address && (rest.poolId || (rest.userToken !== undefined && rest.validatorToken !== undefined)) && (query?.enabled ?? true), )也就是说:address必须存在,且poolId与userToken + validatorToken两组定位方式至少满足其一,查询才会执行。这解释了为什么在未拿到poolId前,可以先用usePoolId查询池 ID——一旦依赖的数据就绪,useLiquidityBalance会自动开始请求。
- 查询键(queryKey):
queryKey由['getLiquidityBalance', filterQueryOptions(parameters)]组成(见 amm.ts),参数不同(如不同 address 或不同 token 对)会生成不同的缓存条目,TanStack Query 借此实现按参数粒度的缓存与去重。
Action 层本身只做一件事:从config取出对应chainId的 client,然后把请求转发给viem/tempo的Actions.amm.getLiquidityBalance(client, rest),由 viem 完成最终的 RPC 调用。
测试佐证:余额查询的实际行为
仓库中的集成测试 packages/core/src/tempo/actions/amm.test.ts 验证了该功能的行为:
describe('getLiquidityBalance', () => { test('default', async () => { const balance = await ammActions.getLiquidityBalance(config, { userToken: addresses.alphaUsd, validatorToken: '0x20c0000000000000000000000000000000000001', address: account.address, }) expect(balance).toMatchInlineSnapshot('0n') }) describe('queryOptions', () => { test('default', async () => { const options = ammActions.getLiquidityBalance.queryOptions(config, { userToken: addresses.alphaUsd, validatorToken: '0x20c0000000000000000000000000000000000001', address: account.address, }) const balance = await queryClient.fetchQuery(options) expect(balance).toMatchInlineSnapshot('0n') }) }) })可以看到:直接调用 Action 与通过queryOptions+fetchQuery走 TanStack Query 两条路径的返回一致(未提供流动性时余额为0n)。而在 burnSync 测试 中,getLiquidityBalance还被用于在燃烧 LP 前读取余额,作为后续burn的输入——这展示了它在"查询余额 → 操作流动性"完整流程中的典型定位。
React 侧的类型测试 packages/react/src/tempo/hooks/amm.test-d.ts 则保证了query.select回调中的data类型与Actions.amm.getLiquidityBalance.ReturnValue(即bigint)严格一致,且选中后的result.data类型会随之收窄。
实战建议
- 配合
usePoolId使用:当只持有 token 对信息时,先查poolId再查询余额,利用query.enabled的自动联动避免无效请求; - 展示前格式化 bigint:
data为原始最小单位,UI 渲染前应结合 token 精度换算成可读金额,避免出现一长串数字; - 利用 TanStack Query 缓存:多次渲染或组件重挂载不会重复发请求,可通过
query.refetchInterval实现余额轮询、通过select做派生数据; - 查询失败兜底:余额查询属于只读请求,建议结合
isLoading/isError做加载态与错误态展示。
相关资源
- 底层 Action 文档:amm.getLiquidityBalance
- Tempo Hook 索引:Tempo Hooks
- Tempo 环境搭建:Tempo Getting Started
- Hook 实现:packages/react/src/tempo/hooks/amm.ts
- Core Action 实现:packages/core/src/tempo/actions/amm.ts
【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考