bigNumber not parsing ether properly

14.4k views Asked by At

I have the following:

import { BigNumber } from "@ethersproject/bignumber";
import { parseUnits } from "@ethersproject/units";

const decimals = 18;

export const add = (a: string, b: string): string => {
  const _a = parseUnits(a, decimals);
  console.log(_a.toString(), a);
  const _b = BigNumber.from(b);
  const res = _a.add(_b).toString();
  return res;
};

// a = 123456789123456789.123456789123456789
// b = 1
// _a.toString() = 123456789123456789123456789123456789
// res = 123456789123456789123456789123456790

Am I missing something obvious as to why res wouldn't be calculated as "123456789123456790.123456789123456789"?

Even if I don't pass in decimals, it's still the same result. (Ideally I wouldn't want to specify an actual decimals value)

1

There are 1 answers

1
Soham Zemse On

The BigNumber is actually a BigInteger (you can't have decimal values in it). This is because on the Ethereum blockchain, numbers are represented as 256 bit integers. You can also see my answer to the same topic.

Now working with decimals could be confusing let me put it this way:

// creating BigNumber instances
const a = ethers.BigNumber.from('1') // creates BigNumber of 1
const b = ethers.utils.parseUnits('1', 18) // Creates BigNumber of 1000000000000000000
const c = ethers.utils.parseEther('1') // same as above, by default 18 decimals

a.toString() // '1'
b.toString() // '1000000000000000000'
ethers.utils.formatEther(a) // '0.000000000000000001'
ethers.utils.formatEther(b) // '1.0'

If you're mostly dealing with currency numerics having decimals, then you can simply stick with parseEther and formatEther utils.

If you're not working with currency and it's still a BigNumber then you'll can use BigNumber.from() and value.toString()