BigNumber

Many operations in Ethereum operate on numbers which are outside the range of safe values to use in JavaScript.

A BigNumber is an object which safely allows mathematical operations on numbers of any magnitude.

Most operations which need to return a value will return a BigNumber and parameters which accept values will generally accept them.

Types

BigNumberish

Many functions and methods in this library take in values which can be non-ambiguously and safely converted to a BigNumber. These values can be specified as:

string

A HexString or a decimal string, either of which may be negative.

BytesLike

A BytesLike Object, such as an Array or Uint8Array.

BigNumber

An existing BigNumber instance.

number

A number that is within the safe range for JavaScript numbers.

BigInt

A JavaScript BigInt object, on environments that support BigInt.

Creating Instances

The constructor of BigNumber cannot be called directly. Instead, Use the static BigNumber.from.

ethers.BigNumber.from( aBigNumberish ) BigNumber

Returns an instance of a BigNumber for aBigNumberish.

Examples:

// From a decimal string... BigNumber.from("42") // { BigNumber: "42" } // From a HexString... BigNumber.from("0x2a") // { BigNumber: "42" } // From a negative HexString... BigNumber.from("-0x2a") // { BigNumber: "-42" } // From an Array (or Uint8Array)... BigNumber.from([ 42 ]) // { BigNumber: "42" } // From an existing BigNumber... let one1 = constants.One; let one2 = BigNumber.from(one1) one2 // { BigNumber: "1" } // ...which returns the same instance one1 === one2 // true // From a (safe) number... BigNumber.from(42) // { BigNumber: "42" } // From a ES2015 BigInt... (only on platforms with BigInt support) BigNumber.from(42n) // { BigNumber: "42" } // Numbers outside the safe range fail: BigNumber.from(Number.MAX_SAFE_INTEGER); // [Error: overflow [ See: https://links.ethers.org/v5-errors-NUMERIC_FAULT-overflow ]] { // code: 'NUMERIC_FAULT', // fault: 'overflow', // operation: 'BigNumber.from', // reason: 'overflow', // value: 9007199254740991 // }

Methods

The BigNumber class is immutable, so no operations can change the value it represents.

Math Operations

bigNumber.add( otherValue ) BigNumber

Returns a BigNumber with the value of BigNumber + otherValue.

bigNumber.sub( otherValue ) BigNumber

Returns a BigNumber with the value of BigNumber - otherValue.

bigNumber.mul( otherValue ) BigNumber

Returns a BigNumber with the value of BigNumber × otherValue.

bigNumber.div( divisor ) BigNumber

Returns a BigNumber with the value of BigNumber ÷ divisor.

bigNumber.mod( divisor ) BigNumber

Returns a BigNumber with the value of the remainder of BigNumber ÷ divisor.

bigNumber.pow( exponent ) BigNumber

Returns a BigNumber with the value of BigNumber to the power of exponent.

bigNumber.abs( ) BigNumber

Returns a BigNumber with the absolute value of BigNumber.

bigNumber.mask( bitcount ) BigNumber

Returns a BigNumber with the value of BigNumber with bits beyond the bitcount least significant bits set to zero.

Two's Complement

Two's Complement is an elegant method used to encode and decode fixed-width signed values while efficiently preserving mathematical operations. Most users will not need to interact with these.

bigNumber.fromTwos( bitwidth ) BigNumber

Returns a BigNumber with the value of BigNumber converted from twos-complement with bitwidth.

bigNumber.toTwos( bitwidth ) BigNumber

Returns a BigNumber with the value of BigNumber converted to twos-complement with bitwidth.

Comparison and Equivalence

bigNumber.eq( otherValue ) boolean

Returns true if and only if the value of BigNumber is equal to otherValue.

bigNumber.lt( otherValue ) boolean

Returns true if and only if the value of BigNumber < otherValue.

bigNumber.lte( otherValue ) boolean

Returns true if and only if the value of BigNumber otherValue.

bigNumber.gt( otherValue ) boolean

Returns true if and only if the value of BigNumber > otherValue.

bigNumber.gte( otherValue ) boolean

Returns true if and only if the value of BigNumber otherValue.

bigNumber.isZero( ) boolean

Returns true if and only if the value of BigNumber is zero.

Conversion

bigNumber.toBigInt( ) bigint

Returns the value of BigNumber as a JavaScript BigInt value, on platforms which support them.

bigNumber.toNumber( ) number

Returns the value of BigNumber as a JavaScript value.

This will throw an error if the value is greater than or equal to Number.MAX_SAFE_INTEGER or less than or equal to Number.MIN_SAFE_INTEGER.

bigNumber.toString( ) string

Returns the value of BigNumber as a base-10 string.

bigNumber.toHexString( ) string< DataHexString >

Returns the value of BigNumber as a base-16, 0x-prefixed DataHexString.

Inspection

ethers.BigNumber.isBigNumber( object ) boolean

Returns true if and only if the object is a BigNumber object.

Examples

let a = BigNumber.from(42); let b = BigNumber.from("91"); a.mul(b); // { BigNumber: "3822" }

Notes

This section is a for a couple of questions that come up frequently.

Why can't I just use numbers?

The first problem many encounter when dealing with Ethereum is the concept of numbers. Most common currencies are broken down with very little granularity. For example, there are only 100 cents in a single dollar. However, there are 1018 wei in a single ether.

JavaScript uses IEEE 754 double-precision binary floating point numbers to represent numeric values. As a result, there are holes in the integer set after 9,007,199,254,740,991; which is problematic for Ethereum because that is only around 0.009 ether (in wei), which means any value over that will begin to experience rounding errors.

To demonstrate how this may be an issue in your code, consider:

(Number.MAX_SAFE_INTEGER + 2 - 2) == (Number.MAX_SAFE_INTEGER) // false

To remedy this, all numbers (which can be large) are stored and manipulated as Big Numbers.

The functions parseEther( etherString ) and formatEther( wei ) can be used to convert between string representations, which are displayed to or entered by the user and Big Number representations which can have mathematical operations handled safely.

Why not BigNumber.js, BN.js, BigDecimal, etc?

Everyone has their own favourite Big Number library, and once someone has chosen one, it becomes part of their identity, like their editor, vi vs emacs. There are over 100 Big Number libraries on npm.

One of the biggest differences between the Ethers BigNumber object and other libraries is that it is immutable, which is very important when dealing with the asynchronous nature of the blockchain.

Capturing the value is not safe in async functions, so immutability protects us from easy to make mistakes, which is not possible on the low-level library's objects which supports myriad in-place operations.

Second, the Ethers BigNumber provides all the functionality required internally and should generally be sufficient for most developers while not exposing some of the more advanced and rare functionality. So it will be easier to swap out the underlying library without impacting consumers.

For example, if BN.js was exposed, someone may use the greatest-common-denominator functions, which would then be functionality the replacing library should also provide to ensure anyone depending on that functionality is not broken.

Why BN.js??

The reason why BN.js is used internally as the big number is because that is the library used by elliptic.

Therefore it must be included regardless, so we leverage that library rather than adding another Big Number library, which would mean two different libraries offering the same functionality.

This has saved about 85kb (80% of this library size) of library size over other libraries which include separate Big Number libraries for various purposes.

Allow us to set a global Big Number library?

Another comment that comes up frequently is the desire to specify a global user-defined Big Number library, which all functions would return.

This becomes problematic since your code may live along side other libraries or code that use Ethers. In fact, even Ethers uses a lot of the public functions internally.

If you, for example, used a library that used a.plus(b) instead of a.add(b), this would break Ethers when it tries to compute fees internally, and other libraries likely have similar logic.

But, the BigNumber prototype is exposed, so you can always add a toMyCustomBigNumber() method to all BigNumber's globally which is safe.