致歉
首先和大家说句抱歉!最近项目太忙,有很多朋友私信我,要我帮忙解决下问题。很多问题我也需要去试一下才能知道问题出在哪里,但是确实忙的连这个时间也没有。再次抱歉!
前言
之前写的文章以太坊开发(二十九)[升级版]使用Web3.js+Node.js封装成接口以供钱包管理/查询/转账,提供了使用Web3.js转账的方法。之前没有测试转账带小数的代币,例如9999.9999
。现在项目测试时发现会报错,错误信息大致是web3.utils.toHex(amount)
参数不支持小数,也就是在转账的这一步出错:
let tokenTransferData = await contract.methods.transfer(receiverAddress,
web3.utils.toHex(amount)).encodeABI()
按理说前面已经获取了代币小数位,然后将传入的要转账的代币数量乘以了10的小数位的次方,本来应该不会再出现小数位:
let decimals = await contract.methods.decimals().call()
let amount = num * Math.pow(10, decimals)
假如此代币的小数位为4,转账数量为9999.9999
那么此处amount
应该是:
9999.9999 * Math.pow(10, 4)
=
9999.9999 * 10000
=
99999999
但通过观察输出,实际结果为99999999.0001
,存在小数位,所以在后面web3.utils.toHex(99999999.0001)
时报错。
解决
原因和解决方法可以查看下面这篇文章:Nodejs学习笔记(十七)--- 浮点运算decimal.js。
需要引入decimal.js
进行处理。安装过程不再赘述,直接看修改后的代码:
Token转账代码修改:
旧:
let decimals = await contract.methods.decimals().call()
let amount = num * Math.pow(10, decimals)
新:
let decimals = await contract.methods.decimals().call()
let amount = new decimal(num).mul(new decimal(Math.pow(10, decimals))).toNumber()
Token余额查询也需要修改:
旧:
try {
let balance = await contract.methods.balanceOf(address).call()
ctx.body = await Promise.resolve({
code: 0,
data: balance / Math.pow(10, decimals),
message: 'Success',
})
} catch (error) {
ctx.body = await Promise.resolve({
code: 1,
data: {},
message: error.stack,
})
}
新:
try {
let balance = await contract.methods.balanceOf(address).call()
ctx.body = await Promise.resolve({
code: 0,
data: new decimal(balance).div(new decimal(Math.pow(10, decimals))).toNumber(),
message: 'Success',
})
} catch (error) {
ctx.body = await Promise.resolve({
code: 1,
data: {},
message: error.stack,
})
}