Reputation: 171
I want to get the balance (number of tokens) from the token smart contract.
I'm using web3.js to interact with the contract, and am able to get a return value.
However, with this value, if I do .toString()
, I see that it has the correct value.
However, if I do .toNumber()
, it gives me an error:
Error: Number can only safely store up to 53 bits
Why does this happen? And how can I get the balance of a particular account from a smart contract, as a number (not a string)?
Upvotes: 4
Views: 1622
Reputation: 21
or use BN from - it extends bytes length and actually is better (xmr / vet also needs more digits) - http://silentmatt.com/biginteger/
Upvotes: 2
Reputation: 28587
Smart contracts can support extremely large numbers (up to uint256
in Solidity). However the built in Number
type of Javascript cannot represent numbers that large, and thus in web3.js
, any numeric values are wrapped in BN
(Big Number). You can find this class in web3.utils.BN
.
This is why when you get the error that you are getting for your balance query,
because balances are uint256
, and typically used to represent 18
decimal places. We can reproduce this using only web3.js, without
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();
This throws the following error:
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)
Therefore, your options are:
.toNumber()
if the BN is small enough..div()
to size it down before calling .toNumber()
.Applying the above to your specific question, about getting token balances, we can do the following:
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()
, since we are expecting this to be small enoughBN
by 10 raised to the power of the decimals BN
, and then call .toNumber
on itNOTE: The resulting value of
balance
will match the number of tokens that is typically show in user interfaces... not the value stored in the smart contract itself.
Upvotes: 3