我想从代币智能合约中获取余额(代币数量)。
我正在使用 web3.js 与合约进行交互,并且能够获得返回值。
但是,使用此值,如果我执行 .toString()
,我会看到它具有正确的值。
但是,如果我执行 .toNumber()
,它会给我一个错误:
Error: Number can only safely store up to 53 bits
为什么会这样?我如何从智能合约中获取特定帐户的余额,作为数字(不是字符串)?
答案 0 :(得分:3)
智能合约可以支持极大的数字(在 Solidity 中最多 uint256
)。然而,内置的 Number
类型的 Javascript 无法表示那么大的数字,因此在 web3.js
中,任何数值都包含在 BN
(大数字)中。您可以在 web3.utils.BN
中找到该课程。
这就是为什么当您收到余额查询错误时,
因为余额是 uint256
,通常用于表示 18
小数位。我们可以仅使用 web3.js 来重现这一点,而无需
const web3 = require('web3');
// the balance is a `1` with 21 `0`-s after it
// typical token would return this value for an account with 1000 tokens
const balanceBN = new web3.utils.BN('1000000000000000000000');
const balance = balanceBN.toNumber();
这会引发以下错误:
Uncaught Error: Number can only safely store up to 53 bits
at assert (/some/path/node_modules/bn.js/lib/bn.js:6:21)
at BN.toNumber (/some/path/node_modules/bn.js/lib/bn.js:519:7)
因此,您的选择是:
.toNumber()
。.div()
之前使用 .toNumber()
将其缩小。将上述内容应用于您的具体问题,关于获取代币余额, 我们可以执行以下操作:
const balanceBN = contract.methods.balanceOf(myAddress).call();
const decimalsBN = contract.methods.decimals().call();
// when we know that the BN is small engouh to be represented in JS number
const decimals = decimalsBN.toNumber();
// when we know that the BN is too alrge to be represented in JS number
const balance = balanceBN.div(new web3.utils.BN(10).pow(decimalsBN)).toNumber();
BN
.toNumber()
直接将小数转换为数字,因为我们希望它足够小BN
除以 10 的小数次幂 BN
,然后对其调用 .toNumber
注意:balance
的结果值将与通常显示在用户界面中的代币数量相匹配……而不是存储在智能合约本身中的值。
答案 1 :(得分:2)
或使用 BN from - 它扩展了字节长度,实际上更好(xmr / vet 也需要更多数字) - http://silentmatt.com/biginteger/