How Should We Handle Precision Issues in JavaScript?
JavaScript's native Number type is a 64-bit floating point number (IEEE 754). This limits its integer precision to 2^53 - 1, or about 9e15. Beyond that, numbers get rounded and lose accuracy.
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(9007199254740991 + 1); // 9007199254740992 âś…
console.log(9007199254740991 + 2); // 9007199254740992 ❌ precision loss
Ethereum (and other EVM chains) use
weias the smallest unit of ETH.1 ETH = 10^18 wei→ sending just 1 ETH involves manipulating a big integer, far beyond JS safe integer range.Smart contracts return values in
wei, making it unsafe to use regularNumberfor balances, gas, token supply, etc.
To safely handle large numbers in Web3 apps, you must use arbitrary-precision number types, like:
ethers.BigNumber(fromethers.js)BigNumber.js(arbitrary precision lib)Native
BigInt(ES2020)web3.utils.BN(if using web3.js)
Example (using ethers.js):
import { parseEther, formatEther } from 'ethers';
const amountInWei = parseEther('1.0'); // returns BigNumber of 10^18 console.log(amountInWei.toString()); // '1000000000000000000'
const readable = formatEther(amountInWei); // back to human-readable ETH console.log(readable); // '1.0'
Avoid this unless you're 100% sure the value is within the safe range:
const unsafe = BigNumber.from("1000000000000000000"); console.log(unsafe.toNumber()); // May throw or round incorrectly if too large
Instead, use:
console.log(unsafe.toString()); // Safe
If you don’t need compatibility with libraries like ethers.js, and you’re just doing arithmetic:
const a = BigInt("1000000000000000000");
const b = BigInt("3000000000000000000");
const c = a + b;
console.log(c.toString()); // "4000000000000000000"
But be careful: BigInt ≠Number, and you can’t mix them.
ReasonExplanation✅ PrecisionJS Number can't represent large wei values accurately💡 CompatibilityWeb3 libraries return balances and values as BigNumber🔒 SafetyPrevent silent rounding bugs in balances, gas, etc.🛠️ ToolsUse parseEther, formatUnits, BigNumber.from, etc.
