How to Deal with Big Numbers in Javascript
Most of numeric values in Solidity smart contracts are expressed using uint256, unfortunately Javascript numbers.
What you will learn
- Where how to deal with big numbers in javascript fits into an Ethereum application.
- Which assumptions should be tested before a mainnet deployment.
- What to read next when this concept is working.
Most of numeric values in Solidity smart contracts are expressed using uint256, unfortunately Javascript numbers are always 64-bit floating point. Therefore when you call a function that returns an uint256 you’ll receive a string instead of a Javascript number. Moreover Solidity does not handle floating number so Eth and token amounts are expressed as unsigned integers with a defined number of decimals. For example 18 for Eth.
In order to be able to deal with such big numbers in Javascript we recommend you to use the bignumber.js library.
For a fixed-precision contrast with wei and ether, use the exact BTC and satoshi denomination calculator.
Installation
The library is the single JavaScript file bignumber.js (or minified, bignumber.min.js).
Inside a browser:
For display-value checks, compare the application output with the ETH-to-USD informational converter, then account separately for fees and slippage.
<script src='path/to/bignumber.js'></script> With Node:
npm install bignumber.js --save then import the library your code:
Issuance assumptions are easier to see on the Bitcoin supply, subsidy, and halving calculator.
const BigNumber = require('bignumber.js'); Usage
Instantiate
You can chose to instanciate a BigNumber from a numeric value, a string or even an hexadecimal value. Read more about the constructor documentation.
let x = new BigNumber(3.141592); //From a numeric value let y = new BigNumber("3.141592"); //From a string let z = new BigNumber('0xff'); //From an hexadecimal string Operations
All basic numeric operations are available as methods: plus, minus, multipliedBy, dividedBy.
x = new BigNumber(0.1) y = x.plus(0.2) // '0.3' BigNumber(0.7).plus(x).plus(y) // '1' x.plus('0.1', 8) // '0.225' If you’d like to round your number, you can use the decimalPlaces method with a numeric parameter with the desired number of decimals:
x = new BigNumber(1234.56) x.decimalPlaces(1) // '1234.6' x.decimalPlaces(0) // 1235 Cast to other types
Once you are working with a BigNumber instance, it’s useful to be able to transform it back to a numeric value or a string to pass to your smart contract or user interface.
Back to a JavaScript numeric value:
x = new BigNumber(456.789) x.toNumber() // 456.789 Back to a String:
x = new BigNumber(456.789) x.toString() // "456.789" When you are converting your big number to a string, it might be useful to use toFixed() to avoid getting a lot of decimal numbers for eg:
y = new BigNumber(3.456) x.toFixed() // '3' y.toFixed() // '3.456' y.toFixed(0) // '3' x.toFixed(2) // '3.46' y.toFixed(2) // '3.46' y.toFixed(2, 1) // '3.45' (ROUND_DOWN) x.toFixed(5) // '3.45600' y.toFixed(5) // '3.45600' Tips
When dealing with ERC20 token or ETH amounts you often have to transform a number to get the number of decimals. The shiftedBy function enable you to easily shift the position of the comma by a defined amount. For example you can transform a 18 decimal value returned by a smart contract call to a readable number:
let oneEther = new BigNumber('10000000000000000000') oneEther.shiftedBy(-18) // '1' And the opposite is achievable by passing a positive value to the shiftedBy function:
let oneEther = new BigNumber(1) oneEther.shiftedBy(18) // '10000000000000000000'Turn the example into production evidence
A working demo is the beginning of verification, not the end. Add tests for failure paths, inspect every permission, and record the chain, contract address, compiler, and dependency versions used for the deployment.
Check behavior
Test expected inputs, boundary values, reverts, events, and calls made to other contracts.
Check operations
Plan key storage, monitoring, pause or upgrade authority, and a response if an assumption stops being true.