I want to display a human readable balance with less decimal places like metamask does it. The function formatEther(wei) returns a string, so for proper rounding I need to parse it etc. And I wanted to ask if there is an easier method or best practice how it's done.
4 Answers
As you said
const {utils, BigNumber} = require('ethers');
const balance = BigNumber.from('824213281784279560');
console.log(utils.formatEther(balance));
gives 0.82421328178427956 as string.
You can
Use BigNumber -> string (with truncation)
const remainder = balance.mod(1e14);
console.log(utils.formatEther(balance.sub(remainder)));
gives 0.8242 as string.
Use BigNumber -> string -> number -> string (with truncation)
let res = utils.formatEther(balance);
res = (+res).toFixed(4);
console.log(res);
gives 0.8242 as string.
Use BigNumber -> string -> number (with rounding)
let res = utils.formatEther(balance);
res = Math.round(res * 1e4) / 1e4;
console.log(res);
gives 0.8242 as number.
- 926
- 8
- 12
I am posting this for other people who might encounter a similar issue:
In this instance, I find it useful to use the formatUnits() method instead. It accepts two arguments which specifies the value - the second argument specifies the decimals. You find some ERC20 tokens which do not default to 18 decimals: some tokens might even use 9 or any other allowable arbitrary decimal-length.
So the above examples could be refactored as follows (with provider and address identifiers already declared):
const balance = await provider.getBalance(address);
console.log('balance of ${balance} --> ${ethers.utils.formatUnits(balance, 18)}`);
Try it out and see if it works.
- 21
- 1
Here are two different ways to do it, given str as the string returned by function formatEther:
Option #1:
function truncate(str, maxDecimalDigits) {
if (str.includes('.')) {
const parts = str.split('.');
return parts[0] + '.' + parts[1].slice(0, maxDecimalDigits);
}
return str;
}
Option #2:
const Decimal = require('decimal.js');
function truncate(str, maxDecimalDigits) {
const num = new Decimal(str);
return num.toFixed(maxDecimalDigits, Decimal.ROUND_DOWN);
}
Though probably not critical for your application, see here for a list of rounding modes.
- 26,003
- 5
- 46
- 86
-
Thanks but first solution does not round and second solution uses a library. I'd prefer not to use a library for this. This might be a personal preference – CodingYourLife Jun 05 '20 at 14:50
-
@CodingYourLife: You can use
Number(str), then do some arithmetic on this. But knowing the typical magnitude of numeric values in this eco-system, I'm afraid thatNumberwill be potentially less accurate than simply truncating the string, as I have shown in the first option above. – goodvibration Jun 05 '20 at 15:03
You can use Number.prototype.toLocaleString() function with minimumFractionDigits option. The result is rounded too.
const balance = "0.82425328178427956"
const result = parseFloat(balance).toLocaleString("en", { minimumFractionDigits: 4 })
console.log(result) // 0.8243
- 101
- 1

toFixedmay round the number up – 0101 Nov 29 '23 at 13:48