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.

Installation

The library is the single JavaScript file bignumber.js (or minified, bignumber.min.js).

Inside a browser:

<script src='path/to/bignumber.js'></script>

With Node:

npm install bignumber.js --save

then import the library your code:

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.

Continue from How to Deal with Big Numbers in Javascript