从 1.x 到 4.x:web3.js 工具函数库(web3-utils)完整迁移指南
【免费下载链接】web3.jsCollection of comprehensive TypeScript libraries for Interaction with the Ethereum JSON RPC API and utility functions.项目地址: https://gitcode.com/gh_mirrors/we/web3.js
导读:web3.js 4.x 对工具函数库
web3-utils做了一系列破坏性变更:推荐按需命名导入、用原生BigInt取代BN、强制显式传入单位参数、调整toHex/isHex的边界行为、把校验函数迁移到web3-validator、把stripHexPrefix挪到web3-eth-accounts,并收紧了compareBlockNumbers的类型约束。本文以官方迁移指南为骨架,结合仓库源码与测试用例,逐项拆解这些差异,给出可直接复制的迁移示例,帮助你将基于 web3.js 1.x 的代码平滑升级到 4.x。
迁移总览:一次看清所有破坏性变更
| 变更项 | 1.x 行为 | 4.x 行为 | 影响等级 |
|---|---|---|---|
| 导入方式 | import web3Utils from 'web3-utils' | 推荐import * as web3Utils from 'web3-utils'或按需命名导入 | 编译期 |
BN大数类 | 内置Web3.utils.BN(基于 bn.js) | 移除,改用原生BigInt | 运行时 |
toWei单位参数 | 可省略,默认ether | 必须显式传入单位 | 编译期/运行时 |
toHex('1') | 数字字符串被当作数字,返回0x1 | 纯数字字符串按字符串处理,返回0x31 | 运行时(易踩坑) |
| 校验函数 | 位于web3-utils | 迁移至web3-validator,旧位置标记 deprecated | 编译期告警 |
stripHexPrefix | 位于web3-utils | 迁移至web3-eth-accounts | 编译期 |
compareBlockNumbers | 允许 block tag 与数字混比 | 只允许同类比较(或earliest特例),否则抛InvalidBlockError | 运行时 |
其中大部分为编译期即可发现的变化,真正需要逐行排查的是toHex的字符串语义变化与compareBlockNumbers的抛错行为——这两处属于"编译能过、运行结果不同/抛错"的隐蔽差异。
导入方式:按需命名导入
1.x 中web3-utils默认导出整个工具包;4.x 将每个工具函数改为具名导出(见 packages/web3-utils/src/index.ts 中从converters.js、validation.js、hash.js、random.js等模块的export *转发),并鼓励只导入应用实际用到的函数,以利于 tree-shaking 减小打包体积:
// 1.x —— 默认导出整个包 import web3Utils from 'web3-utils'; // 4.x —— 全量导入(兼容 1.x 习惯) import * as web3Utils from 'web3-utils'; // 4.x —— 推荐:按需具名导入 import { toWei, fromWei, toHex } from 'web3-utils';该改动不影响Web3.utils与web3.utils命名空间的访问方式,例如web3.utils.toWei('0.1', 'ether')依然可用。按需导入配合 4.x 的 tree-shaking 支持,能显著减小最终 bundle 体积(可参考 13_advanced/tree_shaking 一节)。
告别 BN:全面切换原生 BigInt
1.x 中web3-utils内置BN属性(封装 bn.js)用于处理超出Number安全范围的大整数。4.x 移除了该属性,全面采用 JavaScript 原生BigInt类型:
// 1.x new Web3.utils.BN(1); // 4.x BigInt(4);这一变更的底层证据在源码中随处可见:单位换算映射表ethUnitMap的全部值均为BigInt(见 packages/web3-utils/src/converters.ts 中wei: BigInt(1)、ether: BigInt('1000000000000000000')等);compareBlockNumbers在数字比较路径上直接使用BigInt(blockA) < BigInt(blockB)进行比较(见 packages/web3-utils/src/validation.ts)。
迁移时注意:BigInt与Number不能直接混用算术运算符,跨类型计算需显式转换;另外BigInt不能与Math.*函数、JSON 序列化直接配合,需要时可用Number(...)或toString()过渡。
单位换算:toWei/fromWei 必须显式传单位
1.x 中toWei的第二参(单位)可省略,默认ether。4.x 中该可选参数被移除,必须显式传入单位:
// 1.x —— 省略单位,默认 ether web3.utils.toWei('0.1'); // 4.x —— 必须显式传单位 web3.utils.toWei('0.1', 'ether');从 packages/web3-utils/src/converters.ts 的toWei实现可以看到,单位参数unit: EtherUnits | number已被声明为必选,且支持两类取值:
- 字符串单位:查表
ethUnitMap,如wei、gwei、shannon、ether等,传入不存在的单位会抛InvalidUnitError; - 数字(十进制幂):直接作为 10 的指数,例如传
18等价于ether(denomination = bigintPower(BigInt(10), BigInt(18)))。
fromWei同样要求显式单位(见 packages/web3-utils/src/converters.ts)。此外,当以number类型传入较大数值或高精度小数时,库会输出PrecisionLossWarning警告,提示改用string或BigInt以避免精度丢失——这是所有换算函数(toWei/fromWei/toNumber等)共用的保护机制。
十六进制转换:toHex 对纯数字字符串的处理变了
toHex在两个版本中的绝大多数行为一致,唯一差异是仅包含数字的字符串:
// 1.x new Web3().utils.toHex(0x1); // 0x1 new Web3().utils.toHex('0x1'); // 0x1 new Web3().utils.toHex(1); // 0x1 new Web3().utils.toHex('1'); // 0x1(数字字符串被当作数字) // 4.x new Web3().utils.toHex(0x1); // 0x1 new Web3().utils.toHex('0x1'); // 0x1 new Web3().utils.toHex(1); // 0x1 new Web3().utils.toHex('1'); // 0x31(按字符串处理,即字符 '1' 的 ASCII 十六进制)原因在 packages/web3-utils/src/converters.ts 的toHex分支逻辑中清晰可见:4.x 对字符串先检查是否0x/-0x前缀(走numberToHex),再检查isHexStrict(原样返回),随后才根据isHex/isInt/isUInt的组合判断;纯数字字符串'1'会被当作普通字符串做 UTF-8 编码,因此'1'的十六进制是0x31。注意,toHex对字符串输入遵循"除非以0x为前缀,否则一律按字符串处理"的规则。
迁移排查清单:凡是对"可能为数字的字符串"调用toHex的代码,要么预先用Number()/BigInt()转换,要么确保输入带0x前缀。
校验函数迁移:从 web3-utils 到 web3-validator
4.x 将全部校验函数(isAddress、isBloom、isInBloom、isTopic、checkAddressCheckSum、isHex、isHexStrict等)迁移到了新包web3-validator。为兼容 1.x 代码,web3-utils仍保留这些导出,但在源码中明确标注了 deprecated 并提示迁移(见 packages/web3-utils/src/validation.ts 中大量@deprecated Will be removed in next release. Please use 'web3-validator' package instead.注释,且每个函数实质上是web3-validator同名实现的再导出):
// 1.x / 4.x(可用但已弃用,会收到弃用告警) import { isAddress, isHex } from 'web3-utils'; // 4.x(推荐) import { isAddress, isHex, isHexStrict } from 'web3-validator';web3-validator的校验实现集中在 packages/web3-validator/src/validation 目录下,isHex/isHexStrict的具体正则见 packages/web3-validator/src/validation/string.ts。
isHex:负数返回 true
isHex('-123'); // 1.x 返回 false;4.x 返回 true // true新实现的正则^((-0x|0x|-)?[0-9a-f]+|(0x))$允许可选的-前缀,因此'-123'被视为合法十六进制表示(注意-0x单独不匹配)。
isHex:空字符串返回 false
isHex(''); // 1.x 返回 true;4.x 返回 false // false空串不满足上述正则中"至少一个十六进制字符"的要求。
isHex / isHexStrict:'-0x' 返回 false
isHex('-0x'); // 1.x 返回 true;4.x 返回 false // false isHexStrict('-0x'); // 1.x 返回 true;4.x 返回 false // falseisHexStrict的正则^((-)?0x[0-9a-f]+|(0x))$要求0x之后至少跟一个十六进制字符(packages/web3-validator/src/validation/string.ts),所以'-0x'、'0x'均不通过严格校验。
stripHexPrefix:改从 web3-eth-accounts 导入
stripHexPrefix在 4.x 中从web3-utils移至web3-eth-accounts(实现位于 packages/web3-eth-accounts/src/common/utils.ts,对非字符串输入会抛类型错误):
// 4.x import { stripHexPrefix } from 'web3-eth-accounts'; console.log(stripHexPrefix('0x123')); // "123"从源码看,该函数同时被web3-eth-accounts内部大量使用(如 nonce 补零、RLP 编码前的十六进制规范化等,见 packages/web3-eth-accounts/src/common/utils.ts 与 packages/web3-eth-accounts/src/common/utils.ts),这也是它被"下沉"到账户包的原因。若需在web3-utils中获取同等能力,可自行用str.replace(/^0x/i, '')替代。
compareBlockNumbers:只允许同类比较
compareBlockNumbers(blockA, blockB)用于比较两个区块位置(区块号或区块标签),返回-1(A < B)、0(相等)或1(A > B)。4.x 收紧了入参约束:要么两边都传区块标签,要么两边都传区块数字,唯一例外是earliest与数字0的等价比较。
compareBlockNumbers('earliest', 'safe'); // 合法,返回 -1 compareBlockNumbers(8692, 2); // 合法,返回 1 compareBlockNumbers('latest', 500); // 1.x 返回 1;4.x 抛 InvalidBlockError源码逻辑(packages/web3-utils/src/validation.ts)按以下顺序执行:
- 相等短路:
blockA === blockB或('earliest'|0)与('earliest'|0)的组合返回0; - earliest 特判:任一方为
earliest时直接返回-1/1(这是标签与数字混比的唯一豁免,且测试覆盖了['earliest', 2]、[2, 'earliest']等组合); - 双标签比较:按
earliest → finalized → safe → latest → pending的递增顺序(内部tagsOrder映射为 1~5)返回-1/1; - 标签与数字混比:直接抛
InvalidBlockError('Cannot compare blocktag with provided non-blocktag input.'); - 双数字比较:用
BigInt精确比较(支持 number、string、bigint 混用)。
测试用例完整验证了上述行为(packages/web3-utils/test/fixtures/validation.ts):合法数据包括['earliest', 0]、[0, 'earliest']、[['safe', 'pending'], -1]等;非法数据则覆盖['latest', 110]、[[22, 'finalized'], errorObj]、['pending', BigInt(1)]等所有标签与数字混比组合,均断言抛出InvalidBlockError。
迁移注意:1.x 代码中若存在"数字区块号与'latest'/'pending'标签比较"的逻辑(例如判断某区块是否已确认),需改写为先获取对应标签的区块号再比较,或改用BlockTags之间的比较,避免运行时抛错。
迁移实战检查清单
完成上述逐项改造后,建议按以下清单回归验证:
- 搜索
BN:仓库内所有Web3.utils.BN/new BN(...)用法替换为BigInt(...),并检查toString()、比较运算等跨类型操作; - 搜索
toWei/fromWei:确认所有调用都传入了单位参数(字符串或十进制指数); - 搜索
toHex('纯数字字符串'):确认输入带0x前缀或先转数字,防止'1' → 0x31这类静默语义变化; - 搜索
isHex/isHexStrict的边界输入:关注负数、空串、'-0x'三类返回值变化(web3-validator 校验实现); - 搜索
stripHexPrefix的导入来源:统一改为web3-eth-accounts; - 搜索
compareBlockNumbers的混比调用:标签与数字混比需改写,必要时捕获InvalidBlockError(web3-errors 错误码定义); - 检查弃用告警:对
web3-utils中 deprecated 的校验函数统一改导web3-validator。
需要说明的是,本文所有行为差异均以当前仓库(web3.js 4.x 系列)源码与测试为据,若你的项目锁定在特定 4.x 小版本,建议以该版本发布说明为准做最终核对。其他包的迁移可继续参考本升级指南目录下的 accounts_migration_guide、providers_migration_guide 等姊妹篇。
【免费下载链接】web3.jsCollection of comprehensive TypeScript libraries for Interaction with the Ethereum JSON RPC API and utility functions.项目地址: https://gitcode.com/gh_mirrors/we/web3.js
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考