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

Fix towei scientific notation #6908

Merged
merged 28 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/web3-errors/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,8 @@ Documentation:

- Fixed grammar and spelling in `transactionTimeoutHint` (#6559)

## [Unreleased]
## [Unreleased]

### Added

- Add new `InvalidNumberDecimalPrecisionLossError` (#6908)
1 change: 1 addition & 0 deletions packages/web3-errors/src/error_codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ export const ERR_INVALID_LARGE_VALUE = 1011;
export const ERR_INVALID_BLOCK = 1012;
export const ERR_INVALID_TYPE_ABI = 1013;
export const ERR_INVALID_NIBBLE_WIDTH = 1014;
export const ERR_INVALID_NUMBER_DECIMAL_PRECISION_LOSS = 1015;

// Validation error codes
export const ERR_VALIDATION = 1100;
Expand Down
9 changes: 9 additions & 0 deletions packages/web3-errors/src/errors/utils_errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
ERR_INVALID_TYPE_ABI,
ERR_INVALID_UNIT,
ERR_INVALID_UNSIGNED_INTEGER,
ERR_INVALID_NUMBER_DECIMAL_PRECISION_LOSS
} from '../error_codes.js';
import { InvalidValueError } from '../web3_error_base.js';

Expand Down Expand Up @@ -146,3 +147,11 @@
super(value, 'components found but type is not tuple');
}
}

export class InvalidNumberDecimalPrecisionLossError extends InvalidValueError {
public code = ERR_INVALID_NUMBER_DECIMAL_PRECISION_LOSS;

Check warning on line 152 in packages/web3-errors/src/errors/utils_errors.ts

View check run for this annotation

Codecov / codecov/patch

packages/web3-errors/src/errors/utils_errors.ts#L152

Added line #L152 was not covered by tests

public constructor(value: number) {
super(value, 'value is too small to be represented accurately, use bigInt or string instead.');

Check warning on line 155 in packages/web3-errors/src/errors/utils_errors.ts

View check run for this annotation

Codecov / codecov/patch

packages/web3-errors/src/errors/utils_errors.ts#L154-L155

Added lines #L154 - L155 were not covered by tests
}
}
10 changes: 9 additions & 1 deletion packages/web3-utils/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,12 @@ Documentation:

- fixed erroneous parsing of big numbers in the `toNumber(...)` function (#6880)

## [Unreleased]
## [Unreleased]

### Fixed

- `toWei` support numbers in scientific notation #6908

### Added

- `toWei` add warning when using large decimals that may cause precision loss #6908
20 changes: 18 additions & 2 deletions packages/web3-utils/src/converters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
InvalidBytesError,
InvalidNumberError,
InvalidUnitError,
InvalidNumberDecimalPrecisionLossError
} from 'web3-errors';
import { isUint8Array } from './uint8array.js';

Expand Down Expand Up @@ -411,7 +412,8 @@
*/
export const toNumber = (value: Numbers): number | bigint => {
if (typeof value === 'number') {
if (value > 1e+20) {
if (value > 1e+20) {
console.warn('Warning: Using type `number` with values that are large or contain many decimals may cause loss of precision, it is recommended to use type `string` or `BigInt` when using conversion methods')
// JavaScript converts numbers >= 10^21 to scientific notation when coerced to strings,
// leading to potential parsing errors and incorrect representations.
// For instance, String(10000000000000000000000) yields '1e+22'.
Expand Down Expand Up @@ -551,17 +553,31 @@
if (!denomination) {
throw new InvalidUnitError(unit);
}
let parsedNumber = number;
if (typeof parsedNumber === 'number'){
if (parsedNumber < 1e-15){
console.warn('Warning: The type `numbers` that are large or contain many decimals may cause loss of precision, it is recommended to use type `string` or `BigInt` when using conversion methods')
throw new InvalidNumberDecimalPrecisionLossError(number as number);
luu-alex marked this conversation as resolved.
Show resolved Hide resolved
}
if (parsedNumber > 1e+20) {
console.warn('Warning: Using type `number` with values that are large or contain many decimals may cause loss of precision, it is recommended to use type `string` or `BigInt` when using conversion methods')

Check warning on line 563 in packages/web3-utils/src/converters.ts

View check run for this annotation

Codecov / codecov/patch

packages/web3-utils/src/converters.ts#L563

Added line #L563 was not covered by tests

parsedNumber = BigInt(parsedNumber);

Check warning on line 565 in packages/web3-utils/src/converters.ts

View check run for this annotation

Codecov / codecov/patch

packages/web3-utils/src/converters.ts#L565

Added line #L565 was not covered by tests
}
}

parsedNumber = typeof number === 'number' ? number.toLocaleString('fullwide', {useGrouping: false, maximumFractionDigits: 20}) : number;
luu-alex marked this conversation as resolved.
Show resolved Hide resolved
// if value is decimal e.g. 24.56 extract `integer` and `fraction` part
// to avoid `fraction` to be null use `concat` with empty string
const [integer, fraction] = String(
typeof number === 'string' && !isHexStrict(number) ? number : toNumber(number),
typeof parsedNumber === 'string' && !isHexStrict(parsedNumber) ? parsedNumber : toNumber(parsedNumber),
)
.split('.')
.concat('');

// join the value removing `.` from
// 24.56 -> 2456

const value = BigInt(`${integer}${fraction}`);

// multiply value with denomination
Expand Down
8 changes: 7 additions & 1 deletion packages/web3-utils/test/fixtures/converters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,14 @@ export const fromWeiValidData: [[Numbers, EtherUnits], string][] = [
[[1.9999999999999991611392e+22, 'ether'], '19999.999999999991611392'],
];

export const toWeiValidData: [[Numbers, EtherUnits], string][] = [
export const toWeiValidData: [[Numbers, EtherUnits], Numbers][] = [
...conversionBaseData,
[['255', 'wei'], '0xFF'],
[['255', 'wei'], '0xFF'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is doublicate. Was it meant to have differnt values? Or, should this be deleted?

[['100000000000', 'ether'], 0.0000001],
[['1000000000', 'ether'], 0.000000001],
[['1000000', 'ether'], 0.000000000001]

];

export const fromWeiInvalidData: [[any, any], string][] = [
Expand All @@ -310,6 +315,7 @@ export const toWeiInvalidData: [[any, any], string][] = [
[[{}, 'kwei'], 'value "{}" at "/0" must pass "number" validation'],
[['data', 'kwei'], 'value "data" at "/0" must pass "number" validation'],
[['1234', 'uwei'], 'Invalid value given "uwei". Error: invalid unit.'],
[[0.0000000000000000000001, 'ether'], 'value is too small to be represented accurately, use bigInt or string instead.'],
];
export const toCheckSumValidData: [string, string][] = [
['0x0089d53f703f7e0843953d48133f74ce247184c2', '0x0089d53F703f7E0843953D48133f74cE247184c2'],
Expand Down
Loading