Web3.js中BN.js处理大幂指数数值时报错Assertion failed如何解决
问题原因
- 核心问题出在JSON解析阶段:你接口返回的余额是超过JS安全整数范围(2^53-1)的大数字,调用
await post_response_2.json()时,JS会自动把大数字转为Number类型,不仅会变成科学计数法格式,还会丢失精度。BN.js不支持接收已经失真的Number类型、或者科学计数法格式的字符串作为入参,所以触发了内部的assert断言报错。 - 代码冗余问题:
new BN()和web3.utils.fromWei()都不是异步方法,不需要加await关键字。
解决方案
方案1:优先调整服务端返回逻辑(最稳妥)
让服务端把代币余额以字符串类型返回,不要返回数字类型,从根源避免JS自动转Number丢失精度。调整后代码如下:
const post_response_2 = await fetch('/balanceOf-TKN-by-addr', { method: 'POST', body: stringify_post_input, headers: { "content-type": "application/json" } }); var TKN_balance_response = await post_response_2.json(); console.log(TKN_balance_response); // 直接传入字符串格式的余额即可 var TKN_BN = new BN(TKN_balance_response); var TKN_balance = web3.utils.fromWei(TKN_BN, 'ether'); console.log("TKN_balance :: "+String(TKN_balance));
方案2:服务端无法修改的场景,手动解析响应文本
如果服务端逻辑没法调整,就不要直接调用json()方法解析,先拿到原始响应文本,用支持大整数的规则解析出完整的余额字符串:
const post_response_2 = await fetch('/balanceOf-TKN-by-addr', { method: 'POST', body: stringify_post_input, headers: { "content-type": "application/json" } }); // 先获取原始响应文本 const rawResText = await post_response_2.text(); // 自定义解析逻辑,把大数字转成字符串保留完整精度 const parsedRes = JSON.parse(rawResText, (key, value) => { // 替换成你接口里余额对应的字段名 if (key === 'balance' && typeof value === 'number') { return value.toLocaleString('fullwide', { useGrouping: false }); } return value; }); var TKN_balance_response = parsedRes.balance; var TKN_BN = new BN(TKN_balance_response); var TKN_balance = web3.utils.fromWei(TKN_BN, 'ether'); console.log("TKN_balance :: "+String(TKN_balance));
额外注意事项
BN.js的合法入参仅包括安全整数范围内的数字、完整的数字字符串、Buffer等类型,不要传入超过安全整数范围的Number、或者科学计数法格式的字符串,否则都会触发断言报错。
内容的提问来源于stack exchange,提问作者JDS
相关产品推荐
相关产品推荐

