3

我想从代币智能合约中获取余额(代币数量)。

我正在使用 web3.js 与合同进行交互,并且能够获得返回值。但是,有了这个值,如果我这样做.toString(),我会看到它具有正确的值。但是,如果我这样做.toNumber(),它会给我一个错误: Error: Number can only safely store up to 53 bits

为什么会这样?以及如何从智能合约中获取特定账户的余额,作为数字(而不是字符串)?

4

2 回答 2

4

智能合约可以支持非常大的数字(高达uint256Solidity)。然而,Javascript 的内置Number类型不能表示那么大的数字,因此在 中web3.js,任何数值都包含在BN(Big Number) 中。你可以在 中找到这个类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()如果 BN 足够小,您可以使用。
  • 如果 BN 太大,.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将与通常显示在用户界面中的代币数量相匹配……而不是存储在智能合约本身中的值。

于 2021-06-08T15:59:36.050 回答
2

或使用 BN - 它扩展字节长度,实际上更好(xmr / vet 也需要更多数字) - http://silentmatt.com/biginteger/

于 2021-06-09T15:00:42.593 回答