Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web3.utils.fromWei silently performs unsafe conversion for big numbers because of scientific notation #6880

Closed
sgerodes opened this issue Mar 11, 2024 · 7 comments · Fixed by #6882
Labels
4.x 4.0 related

Comments

@sgerodes
Copy link
Contributor

sgerodes commented Mar 11, 2024

Expected behavior

Web3.utils.fromWei is parsing big numbers (>=10^21) without adding an unnecessary dot

Actual behavior

Web3.utils.fromWei(19999990000000099000000, 'ether')  === "1..99999900000001e+22"
Web3.utils.fromWei(19999990000000000000000, 'ether') ===  "0.0000001.999999e+22"
Web3.utils.fromWei(19000000000000000000000, 'ether') === "0.000000000001.9e+22"

Web3.utils.fromWei insert an additional dot in the scientific notation when dealing with Big numbers
In the example below the bumber 19999999999999990000000 is parsed to ether. this correcponds to 19999.99999999999 ETH.

When parsed we can see that there is an additional dot in the output: 1.9.99999999999999e+22.
If we parse this string to a float then a 1.9 will be produced.

This behaviour silently without errors converted a number representing ca 19999 ETH to 1.9 ETH.

Steps to reproduce the behavior

import Web3 from "web3";

const wei = 19999999999999990000000; // A value bigger than 10^21
console.log(wei) // 1.999999999999999e+22
console.log(BigInt(wei)) // 19999999999999991611392n

let ethConverted = Web3.utils.fromWei(wei, 'ether');
console.log(ethConverted) // 1.9.99999999999999e+22. //  Here a string is returned with a second dot

let ethParsed = parseFloat(ethConverted);
console.log(ethParsed) // 1.9 // but should be > 19999

Logs

1.999999999999999e+22
19999999999999991611392n
1.9.99999999999999e+22
1.9

Environment

node version 20
web3.js version 4.6.0

Reason of the error

The internal logic of fromWei is behaving wrongly because the number is parsed into a scientific notation string like "1.999999999999999e+22". This inroduceses errors into the output

@SantiagoDevRel
Copy link
Member

Thanks for posting this @sgerodes , our devs will take a look at it and reply asap!💪

@SantiagoDevRel SantiagoDevRel added the 4.x 4.0 related label Mar 11, 2024
@sgerodes
Copy link
Contributor Author

sgerodes commented Mar 11, 2024

The Issue comes from very large numbers (>= 10^21) are incorrectly converted into a format with an additional dot due to JavaScript's automatic scientific notation for large numbers.

Example:
String(10000000000000000000000) === '1e+22' and this messes up the fromWei function.

@sgerodes
Copy link
Contributor Author

@SantiagoDevRel I have created a PR that fixes this Bug #6882

@sgerodes sgerodes changed the title Web3.utils.fromWei silently performs unsafe conversion for big numbers Web3.utils.fromWei silently performs unsafe conversion for big numbers because of scientific notation Mar 11, 2024
@SantiagoDevRel
Copy link
Member

Amazing @sgerodes , the devs will review it tomorrow!

@jdevcs
Copy link
Contributor

jdevcs commented Mar 12, 2024

@sgerodes if you want to use fromWei with large number that exceeds number range use bigint as this function accepts bigint as well:

let ethConverted = Web3.utils.fromWei(BigInt(wei), 'ether');
console.log("ethConverted ",ethConverted)

> ethConverted  19999.999999999991611392

@sgerodes
Copy link
Contributor Author

sgerodes commented Mar 12, 2024

@jdevcs Thank you. That will fix my code.

But there is still a bug to be fixed. The following is clearly an errornous behaviour:

Web3.utils.fromWei(19999990000000099000000, 'ether')  === "1..99999900000001e+22"
Web3.utils.fromWei(19999990000000000000000, 'ether') ===  "0.0000001.999999e+22"
Web3.utils.fromWei(19000000000000000000000, 'ether') === "0.000000000001.9e+22"

The problem is this function accepts js non-bigint numbers greater than 10^21 and parses them incorrectly without errors or warnings.

This can create errornous behaviour. And it will occur silently.

parseFloat(Web3.utils.fromWei(19999999999999990000000, 'ether')) === 1.9 // but should equal 19999.99999999999

19999 ETH was parsed as 1.9 ETH with little code, that felt very intutive. Just using parseFloat. Which probably many of the devs use after they receive a string from "fromWei".

@sgerodes
Copy link
Contributor Author

sgerodes commented Mar 12, 2024

@jdevcs My implementation fixes all of those Issues. I have implemented a very straightforward and simple fix for that. #6882

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
4.x 4.0 related
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants