ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

fuels-ts 数值运算模块 `@fuel-ts/math` 完全指南:基于 bn.js 的安全大数运算、单位换算与格式化工具

2026/9/10 11:26:08 拓冰建站 浏览量
fuels-ts 数值运算模块 `@fuel-ts/math` 完全指南:基于 bn.js 的安全大数运算、单位换算与格式化工具 fuels-ts 数值运算模块fuel-ts/math完全指南基于 bn.js 的安全大数运算、单位换算与格式化工具【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-tsfuel-ts/math是 Fuel TypeScript SDKfuels-tsmonorepo 中的一个基础子模块为上层所有涉及数值运算的代码提供统一入口。它围绕decimal十进制小数、hex十六进制字符串与Uint8Array字节数组三类数据形态封装了一整套基于 bn.js 的数学工具让任意大小的整数计算都足够安全、精确。读完本文你将掌握该模块的安装方式、核心BN类型与函数式 API 的完整用法理解formatUnits/parseUnits的单位换算机制、默认精度配置的来源以及该模块在 SDK 内部如账户余额、交易金额处理的真实应用场景。模块定位为什么 fuels-ts 需要一个独立的数学包在区块链场景下绝大多数数值都远超 JavaScriptNumber的安全整数范围Number.MAX_SAFE_INTEGER即2^53 - 1。无论是 Fuel 网络的资产余额、交易金额还是燃料价格都以最小单位wei 级别的整数在网络中传输。如果直接使用原生number进行计算很容易因精度丢失而引入严重 bug。为此fuels-ts 单独抽取了 packages/math 作为 SDK 共用的数值底座其设计要点是基于 bn.js实现任意精度整数运算无论数值多大都能安全完成加减乘除、幂、取模等计算面向 Fuel 的实际开发场景额外提供decimal、hex、Uint8Array三种形态之间的互转以及带小数位的单位格式化能力被 SDK 内其他包大量复用。例如在 account.ts 中余额、手续费、CoinQuantity等几乎全部用bn(...)构造、用.toNumber()/.toHex()转换说明该模块是 SDK 数值处理的公共基础设施。安装方式单独使用该模块时按官方 README 推荐使用pnpmpnpm add fuel-ts/math # 或 npm add fuel-ts/math根据 package.json其运行时依赖仅有两个bn.js5.2.1及其类型声明types/bn.js5.1.6外加 monorepo 内的fuel-ts/errors用于抛出标准化的FuelError。安装体积与依赖面都很小可在任意 Node.js 环境^20 || ^22 || ^24中使用同时打包产物支持require/import/类型三种入口。如果你正在开发完整的 Fuel 应用而非底层库官方推荐直接安装聚合包fuelsSDK 的 umbrella package它将fuel-ts/math与地址、账户、合约、脚本、钱包等能力一并带入pnpm add fuels # 或 npm add fuels导出结构总览模块的统一出口是 index.ts仅用五条 re-export 就组织好了全部能力export * from ./bn; export * from ./decimal; export * from ./functional; export * from ./math; export * from ./types;各文件的职责划分非常清晰源文件职责bn.ts核心BN类继承 bn.js 的BN与函数式工厂bn()、bn.parseUnits()decimal.ts面向展示场景的toFixed小数格式化函数functional.tstoNumber/toHex/toBytes/formatUnits/format五个函数式快捷调用math.tsmax、multiply等聚合数学函数types.tsBigNumberish、FormatConfig、ToFixedConfig等共享类型核心BN类与bn()工厂函数统一入参类型BNInputBN的构造与所有算术方法都接受一个宽松的入参联合类型BNInput定义于 bn.tstype BNInput number | string | number[] | Uint8Array | Buffer | BnJs;也就是说无论你手头是普通数字、1000000000000000000这样的十进制字符串、0x1ff十六进制字符串、字节数组还是另一个bn.js实例都可以直接传入参与运算无需手动统一。构造与输入归一化规则BN构造函数bn.ts做了几件关键的输入处理传入BN实例时先转成字节数组再重新构造保证返回的是本模块的BN类型十六进制字符串会自动剔除0x前缀bn.js 本身不接受该前缀并把进制默认设为hex空值保护null/undefined/缺省参数都会被当作0安全整数校验当入参是number且超过Number.MAX_SAFE_INTEGER时直接抛出携带ErrorCode.NUMBER_TOO_BIG的FuelError提示“数值过大请改用字符串”。测试 bn.test.ts 明确验证了Number.MAX_SAFE_INTEGER 1这种不安全的 number 会被拒绝。函数式工厂bn(value?, base?, endian?)只是new BN(...)的语法糖bn.ts在 SDK 内部的使用频率远高于new BN(...)例如 account.ts 中的amount: bn(fee)。核心方法速查表方法签名行为要点toString(base?, length?)重写后base 16或hex时强制带0x前缀toHex(bytesPadding?: number)输出0x...负数与超出 padding 长度都会抛CONVERTING_FAILEDtoBytes(bytesPadding?: number)输出Uint8Array负数抛错支持前置补零toJSON()输出十六进制字符串valueOf()输出十进制字符串与无参toString()一致add/sub/mul/div/pow/mod/divRound(v: BNInput)运算后返回本模块的BN永不丢失类型引用lt/lte/gt/gte/eq(v: BNInput)返回布尔值的比较cmp(v: BNInput)返回-1 \| 0 \| 1sqr/neg/abs/toTwos/fromTwos(width?)返回BN覆盖 bn.js 原方法clone()深拷贝为新的BNmaxU64()若当前值超过0xFFFFFFFFFFFFFFFF钳制到该上限max(v: BNInput)返回两者中的较小值语义为上限保护normalizeZeroToOne()若为0则返回1否则不变format/formatUnits见下文单位换算与展示格式化为什么重写这么多方法避免丢失BN引用阅读 bn.ts 可以发现一个精心设计add、pow、sub等所有算术与比较方法都经由内部caller(v, methodName)转发bn.ts其结果若仍是 bn.js 的BN会立即new BN(output.toArray())重新包装成本模块的BN。sqr、neg、abs、toTwos、fromTwos、mulTo、egcd、divmod也如法炮制。这意味着你可以像下面这样无限链式调用且每一步返回值都是本模块的BN链式表达式的类型与行为保持一致bn(2).add(2).sub(2).pow(0x3).mul(2).div(2).sqr().abs().mod(2).divRound(2);对应测试见 bn.test.ts它逐个断言了链式中每步调用结果仍能以toString(16)得到0x前缀的十六进制串。hex 与 Uint8Array 互转及字节对齐Fuel 链上与交易、签名相关的很多字段都是定长字节因此toHex(bytesPadding)/toBytes(bytesPadding)的补零对齐能力至关重要。bytesPadding以字节为单位调用toHex(8)会把值补足为 8 字节16 个十六进制字符宽度的0x0000000000000000形式toBytes(8)同理返回 8 个字节的Uint8Array。若值本身超出声明的字节宽度则抛出转换失败错误。完整边界用例可参考 bn.test.ts。import { bn } from fuel-ts/math; bn(1).toHex(); // 0x1 bn(1).toHex(2); // 0x0001 bn(0x1ff).toBytes(); // Uint8Array [1, 255] bn(255).toBytes(4); // Uint8Array [0, 0, 0, 255]单位换算与展示格式化format/formatUnits/parseUnits区块链应用最常见的两类需求是把链上的最小单位整数还原成带小数的资产展示值以及把用户输入的带小数金额转换回最小单位整数提交上链。fuel-ts/math为此提供了镜像的两个 API。formatUnits(units?)整数 → 带小数位字符串formatUnits按指定小数位在整数值上打小数点bn.ts默认units 9Fuel 网络默认 9 位小数bn(1000000000).formatUnits(); // 1.000000000 bn(2).formatUnits(); // 0.000000002 bn(100000020000).formatUnits(); // 100.000020000 bn(1000000000).formatUnits(7); // 100.0000000format(options?)带千分位、去尾零的展示格式化format在formatUnits基础上叠加precision最大小数位数与minPrecision最小保留位数并自动添加千分位分隔符与去除尾部多余的零是面向UI 展示的高阶封装bn.tsbn(1000000000).format(); // 1.000 默认去零后保留 3 位最小精度 bn(2).format(); // 0.000000002 bn(100000020000).format(); // 100.00002 bn(100100000020000).format(); // 100,100.00002 bn(1000000000).format({ minPrecision: 2, units: 8 }); // 10.00其中配置项来自 types.ts 定义的FormatConfigtype FormatConfig { units?: number } ToFixedConfig; type ToFixedConfig { minPrecision?: number; precision?: number };bn.parseUnits(value, units?)展示值 → 最小单位整数parseUnits是formatUnits的逆操作bn.ts它把形如100.00002、甚至带千分位100,100.00002或.的字符串解析回最小单位整数位数不足则自动补零小数位超过units时抛出CONVERTING_FAILEDbn.parseUnits(1); // BN: 1000000000 bn.parseUnits(100.00002); // BN: 100000020000 bn.parseUnits(100,100.00002, 5); // BN: 10010000002 bn.parseUnits(.); // BN: 0 bn.parseUnits(0.000000002); // BN: 2默认配置的出处以上默认值全部定义在 configs.ts并由测试 configs.test.ts 锁定不可随意变更常量值含义DEFAULT_DECIMAL_UNITS9默认小数位formatUnits/parseUnits的默认unitsDEFAULT_PRECISION9默认最大展示精度DEFAULT_MIN_PRECISION3默认最小展示精度防止整块金额被显示成1而丢失小数视觉信息DECIMAL_FUEL9Fuel 网络的原生小数位数DECIMAL_WEI/DECIMAL_KWEI/DECIMAL_MWEI/DECIMAL_GWEI18 / 15 / 12 / 9Ethereum 生态常见单位换算常数供需要换算 ERC-20 金额的场景参考展示辅助函数toFixeddecimal.ts 提供的toFixed(value, options?)面向纯粹的展示场景接受字符串或数字输入返回带千分位分隔且小数位数被precision/minPrecision约束的字符串。它同样默认使用DEFAULT_PRECISION 9与DEFAULT_MIN_PRECISION 3并在minPrecision precision时先去除尾部零再按最小精度补齐toFixed(100000020000); // 100,000,020,000无小数输入时的整数分组 toFixed(1234567.89123); // 千分位分组 精度约束 toFixed(1234.5, { precision: 4, minPrecision: 2 }); // 1,234.5若你只处理纯整数且不需要单位换算用toFixed即可完成分组展示无需构造BN实例。函数式快捷 API 与聚合函数为了让不持有BN实例的代码也能方便使用functional.ts 暴露了五个一等函数它们内部都是bn(value)的薄封装toNumber(0x1ff); // 511 toHex(1, 2); // 0x0001 toBytes(0x1ff); // Uint8Array [1, 255] formatUnits(1000000000); // 1.000000000 format(100000020000); // 100.00002math.ts 则提供两个聚合运算max(...numbers)返回一组BigNumberish中的最大值以bn(0)为起点归约multiply(...numbers)对一组值连续相乘后向上取整。这里的BigNumberish string | number | BN同样来自 types.ts是 SDK 其他模块引用本包时最常用的类型别名。在 SDK 中的真实应用从源码检索可以看到fuel-ts/math并不是孤立的工具包而是被大量 SDK 内部代码直接依赖。以 account.ts 为例余额与CoinQuantity的组装使用bn(0)、bn(fee)、bn(transferParam.amount)在计算手续费、合并输入时大量使用acc.add(input.amount)、bn(0)这类链式与归约运算十六进制编码输出时使用0x.concat(bn(amount).toHex()...)或直接依赖toHex()自带的0x前缀。换言之你在使用fuels聚合包开发 DApp 时凡是经手余额、金额、gas 等数值的场景底层都在使用本文介绍的BN、parseUnits、format等能力。理解了fuel-ts/math就等于理解了 fuels-ts 全部数值处理行为的地基。生态与配套信息版本与依赖包版本号见 packages/math/package.json构建脚本为tsup产物输出到dist变更记录完整的版本变更历史见 packages/math/CHANGELOG.md许可证该子模块采用Apache 2.0详见 packages/math/LICENSE参与贡献本包是 fuels-ts 单一 monorepo 的一部分贡献指引请参见仓库根目录的 CONTRIBUTING.md其余包对fuel-ts/math的调用方式也可直接查阅上文提到的 account.ts 等源码作为最佳实践参考。【免费下载链接】fuels-tsFuel Network Typescript SDK项目地址: https://gitcode.com/GitHub_Trending/fu/fuels-ts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考