fuels-ts 钱包余额查询全指南:getBalance 与 getBalances 的用法与原理解析
【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-ts
本指南以 Fuel Network TypeScript SDK(fuels-ts)官方文档 checking-balances.md 为主体,讲解在 fuels-ts 中如何查询单个资产余额与账户全部资产余额。文章将结合 Account 与 Provider 的真实源码,说明getBalance/getBalances的底层调用链、返回类型与分页行为,帮助你既会写查询代码,也理解其工作原理。
一、概述:两类余额查询场景
在 fuels-ts 中,钱包/账户对象(Account)封装了对链上资产状态的查询能力。查看余额通常分两种诉求:
| 场景 | 方法 | 返回值 |
|---|---|---|
| 查询某个特定资产的余额 | getBalance | BN(BigNumber 大数对象) |
| 查询账户下所有资产的余额 | getBalances | { balances: CoinQuantity[], pageInfo? } |
两个方法都定义在 Account 上,因此钱包(Wallet)、只读账户等一切继承 Account 的实体都能直接调用。官方文档对二者的定位分别是:
getBalance:聚合钱包中给定资产所有未花费 Coin(UTXO)的金额总和;getBalances:返回一组CoinQuantity,用于完整掌握账户的全部持仓。
二、查询单个资产余额:getBalance
2.1 官方示例
官方文档示例(checking-balances.ts)展示了最小可用写法:
import type { BN } from 'fuels'; import { Provider, Wallet } from 'fuels'; import { LOCAL_NETWORK_URL, WALLET_PVT_KEY } from '../../../env'; const provider = new Provider(LOCAL_NETWORK_URL); const myWallet = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider); // The returned amount is a BigNumber const balance: BN = await myWallet.getBalance(await provider.getBaseAssetId());代码要点:
- 创建 Provider:
new Provider(LOCAL_NETWORK_URL)建立与 Fuel 节点的连接。LOCAL_NETWORK_URL指向本地测试网络节点(通常是http://127.0.0.1:4000之类的地址,在文档示例工程 apps/docs/src/env.ts 中以环境注入变量形式提供)。 - 从私钥实例化钱包:
Wallet.fromPrivateKey(WALLET_PVT_KEY, provider),其中WALLET_PVT_KEY对应一个预先注资的测试账户私钥。 - 传入基准资产 ID:
provider.getBaseAssetId()返回当前网络的基准资产(Fuel 主资产)ID。在标准 Fuel 网络中它通常是0x0000...0000(零地址),但为了与自定义网络的配置解耦,官方示例统一通过 Provider 查询获取。 - 返回值是 BN:
getBalance返回BN大数类型,而非普通number。余额以最小原子单位(base asset 的最小精度单位)计,直接做数值运算或展示前应先转换(如balance.toString()),避免 JSnumber精度丢失。
2.2 参数省略的默认行为
从源码看,Account.getBalance 的assetId参数是可选的:
async getBalance(assetId?: BytesLike): Promise<BN> { const assetIdToFetch = assetId ?? (await this.provider.getBaseAssetId()); const amount = await this.provider.getBalance(this.address, assetIdToFetch); return amount; }也就是说,当你不传任何参数直接调用wallet.getBalance()时,它会自动取provider.getBaseAssetId()作为默认资产。显式传入与省略参数效果等价,但建议显式传入以增强代码可读性。
三、查询全部资产余额:getBalances
官方文档示例(checking-balances-two.ts):
import { Provider, Wallet } from 'fuels'; import { WALLET_PVT_KEY_2, LOCAL_NETWORK_URL } from '../../../env'; const provider = new Provider(LOCAL_NETWORK_URL); const myOtherWallet = Wallet.fromPrivateKey(WALLET_PVT_KEY_2, provider); const { balances } = await myOtherWallet.getBalances(); console.log('balances:', balances);返回的balances是CoinQuantity数组,其类型定义位于 coin-quantity.ts:
export type CoinQuantity = { amount: BN; assetId: string; max?: BN };每个元素包含:
| 字段 | 类型 | 含义 |
|---|---|---|
assetId | string | 资产 ID(燃料链上的资产唯一标识) |
amount | BN | 该资产的可花费余额(大数,单位为原子单位) |
max | BN(可选) | 可用的最大数量(预留估算费用等场景下与 amount 可能不同) |
getBalances是观察一个地址持仓全貌的最直接途径:遍历该地址下所有资产,逐个给出资产 ID 与对应金额,适合做资产看板、余额列表展示等场景。
四、底层原理:方法调用链
文档只展示了 Account 层的用法,理解底层能帮你把握分页、节点兼容等行为。
4.1 getBalance 的调用链
Account.getBalance只是薄封装,真正干活的是 Provider.getBalance:
async getBalance( owner: AddressInput, assetId: BytesLike ): Promise<BN> { const { balance } = await this.operations.getBalanceV2({ owner: new Address(owner).toB256(), assetId: hexlify(assetId), }); return bn(balance.amountU128, 10); }调用链为:Wallet.getBalance(assetId)→Account.getBalance(补齐默认 baseAssetId)→Provider.getBalance(address, assetId)→ GraphQL 操作getBalanceV2→ 返回BN。关键实现事实:
- 地址会被规范化为 b256 格式(
Address(owner).toB256()),资产 ID 会被hexlify统一处理,确保链上查询参数格式正确; - 余额金额来自节点响应中的
amountU128字段,属于u128 大整数,因此 SDK 用BN承载; - 文档描述"聚合所有未花费 Coin 的金额总和"正对应 Fuel 账户模型的 UTXO 特性——
getBalanceV2在节点侧对同一资产的全部 UTXO 求和返回。
4.2 getBalances 的调用链与分页
Provider.getBalances 的实现揭示了文档未明说的节点兼容与分页逻辑:
async getBalances( owner: string | Address, paginationArgs?: CursorPaginationArgs ): Promise<GetBalancesResponse> { // The largest possible size allowed by the node. let args: CursorPaginationArgs = { first: NON_PAGINATED_BALANCES_SIZE }; const { balancesPagination: supportsPagination } = await this.getNodeFeatures(); if (supportsPagination) { // If the node supports pagination, we use the provided pagination arguments. args = validatePaginationArgs({ inputArgs: paginationArgs, paginationLimit: BALANCES_PAGE_SIZE_LIMIT, }); } const { balances: { edges, pageInfo }, } = await this.operations.getBalancesV2({ ...args, filter: { owner: new Address(owner).toB256() }, supportsPagination, }); const balances = edges.map(({ node }) => ({ assetId: node.assetId, amount: bn(node.amountU128), })); return { balances, ...(supportsPagination ? { pageInfo } : {}), }; }值得注意的实现事实:
- 自动探测节点分页能力:SDK 通过
getNodeFeatures()读取节点的balancesPagination特性开关; - 不支持分页的旧节点:一次请求尽量取满
NON_PAGINATED_BALANCES_SIZE = 10000条(常量定义见 provider.ts 顶部); - 支持分页的新节点:使用
validatePaginationArgs校验用户传入的分页参数,上限受BALANCES_PAGE_SIZE_LIMIT = 100约束(分页单页大小限制为 100); - 返回结构差异:当节点支持分页时,返回值额外附带
pageInfo(含游标信息),便于后续翻页; - 字段映射:每条余额同样取自
amountU128并转为BN,组装成{ assetId, amount }形状的CoinQuantity。
因此在处理大量资产余额时,若账户持仓种类很多,你可能需要通过paginationArgs(after游标 +first数量)遍历所有页;而对常规账户,默认一次调用即可取回全部持仓。
五、实操要点小结
- 始终以原子单位处理余额:
BN表示的金额未做精度缩放,UI 展示时应按资产精度换算,切勿当作十进制小数额直接拼接字符串。 - 不要丢失 UTXO 语境:
getBalance汇总的是未花费 Coin,余额为"可花费金额",与账户"锁定金额"(如进行中的交易占用)不同。 - 复用 Provider:
Provider是重量级连接对象,官方示例刻意将同一个provider注入多个钱包,实际项目中也应复用而非每次新建。 - 资产 ID 的统一来源:多资产场景下,用
provider.getBaseAssetId()获取主资产 ID,而非硬编码零地址,以兼容不同网络配置。 - 相关阅读:余额查询是钱包基础操作之一,可与本目录下的 私钥钱包、助记词钱包、资产转账 文档组合成完整的钱包开发工作流。
六、结语
fuels-ts 的余额查询 API 设计得非常克制:getBalance解决"某一资产有多少",getBalances解决"我持有哪些资产",两者都收敛到Provider层的 GraphQL 查询。理解getBalance默认回退基准资产、getBalances随节点能力自动切换分页策略这两处实现细节,能让你在编写余额展示、资产清单、自动化校验逻辑时少踩坑。配套的官方示例代码位于 wallets/snippets 目录,可直接作为脚手架参考。
【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-ts
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考