diff --git a/packages/web3-errors/CHANGELOG.md b/packages/web3-errors/CHANGELOG.md index 06946bb65df..2acbb60bc4f 100644 --- a/packages/web3-errors/CHANGELOG.md +++ b/packages/web3-errors/CHANGELOG.md @@ -166,4 +166,8 @@ Documentation: - Fixed grammar and spelling in `transactionTimeoutHint` (#6559) -## [Unreleased] \ No newline at end of file +## [Unreleased] + +### Added + +- Added `InvalidIntegerError` error for fromWei and toWei (#7052) \ No newline at end of file diff --git a/packages/web3-errors/src/error_codes.ts b/packages/web3-errors/src/error_codes.ts index 1db99b30ea7..16c95ad81cb 100644 --- a/packages/web3-errors/src/error_codes.ts +++ b/packages/web3-errors/src/error_codes.ts @@ -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_INTEGER = 1015; // Validation error codes export const ERR_VALIDATION = 1100; diff --git a/packages/web3-errors/src/errors/utils_errors.ts b/packages/web3-errors/src/errors/utils_errors.ts index b93ff964f38..ca213958b9a 100644 --- a/packages/web3-errors/src/errors/utils_errors.ts +++ b/packages/web3-errors/src/errors/utils_errors.ts @@ -31,6 +31,7 @@ import { ERR_INVALID_TYPE, ERR_INVALID_TYPE_ABI, ERR_INVALID_UNIT, + ERR_INVALID_INTEGER, ERR_INVALID_UNSIGNED_INTEGER, } from '../error_codes.js'; import { InvalidValueError } from '../web3_error_base.js'; @@ -75,6 +76,15 @@ export class InvalidUnitError extends InvalidValueError { } } +export class InvalidIntegerError extends InvalidValueError { + public code = ERR_INVALID_INTEGER; + + public constructor(value: unknown) { + super(value, 'not a valid unit. Must be a positive integer'); + + } +} + export class HexProcessingError extends InvalidValueError { public code = ERR_INVALID_HEX; diff --git a/packages/web3-utils/CHANGELOG.md b/packages/web3-utils/CHANGELOG.md index 2310e93c49e..763f7f1d462 100644 --- a/packages/web3-utils/CHANGELOG.md +++ b/packages/web3-utils/CHANGELOG.md @@ -221,8 +221,9 @@ Documentation: ### Added - `toWei` add warning when using large numbers or large decimals that may cause precision loss (#6908) +- `toWei` and `fromWei` now supports integers as a unit. (#7053) ### Fixed - `toWei` support numbers in scientific notation (#6908) -- `toWei` and `fromWei` trims according to ether unit successfuly (#7044) \ No newline at end of file +- `toWei` and `fromWei` trims according to ether unit successfuly (#7044) diff --git a/packages/web3-utils/src/converters.ts b/packages/web3-utils/src/converters.ts index 3c5b09ed27f..f525150187e 100644 --- a/packages/web3-utils/src/converters.ts +++ b/packages/web3-utils/src/converters.ts @@ -41,6 +41,7 @@ import { InvalidBytesError, InvalidNumberError, InvalidUnitError, + InvalidIntegerError, } from 'web3-errors'; import { isUint8Array } from './uint8array.js'; @@ -492,13 +493,22 @@ export const toBigInt = (value: unknown): bigint => { * > 0.000000001 * ``` */ -export const fromWei = (number: Numbers, unit: EtherUnits): string => { - const denomination = ethUnitMap[unit]; +export const fromWei = (number: Numbers, unit: EtherUnits | number): string => { + let denomination; + if (typeof unit === 'string') { + denomination = ethUnitMap[unit]; - if (!denomination) { - throw new InvalidUnitError(unit); + if (!denomination) { + throw new InvalidUnitError(unit); + } + } else { + if (unit < 0 || !Number.isInteger(unit)) { + throw new InvalidIntegerError(unit); + } + denomination = BigInt(10)**BigInt(unit); } + // value in wei would always be integer // 13456789, 1234 const value = String(toNumber(number)); @@ -551,14 +561,23 @@ export const fromWei = (number: Numbers, unit: EtherUnits): string => { * ``` */ // todo in 1.x unit defaults to 'ether' -export const toWei = (number: Numbers, unit: EtherUnits): string => { +export const toWei = (number: Numbers, unit: EtherUnits | number): string => { validator.validate(['number'], [number]); - const denomination = ethUnitMap[unit]; - - if (!denomination) { - throw new InvalidUnitError(unit); + let denomination; + if (typeof unit === 'string') { + denomination = ethUnitMap[unit]; + if (!denomination) { + throw new InvalidUnitError(unit); + } + } else { + if (unit < 0 || !Number.isInteger(unit)) { + throw new InvalidIntegerError(unit); + } + + denomination = BigInt(10)**BigInt(unit); } + let parsedNumber = number; if (typeof parsedNumber === 'number') { if (parsedNumber < 1e-15) { diff --git a/packages/web3-utils/test/fixtures/converters.ts b/packages/web3-utils/test/fixtures/converters.ts index 14dc271015e..9f0324b68ad 100644 --- a/packages/web3-utils/test/fixtures/converters.ts +++ b/packages/web3-utils/test/fixtures/converters.ts @@ -256,7 +256,7 @@ export const toHexInvalidData: [any, string][] = [ [undefined, 'Invalid value given "undefined". Error: can not be converted to hex.'], ]; -const conversionBaseData: [[Numbers, EtherUnits], string][] = [ +const conversionBaseData: [[Numbers, EtherUnits | number], string][] = [ [[0, 'wei'], '0'], [[123, 'wei'], '123'], [['123', 'wei'], '123'], @@ -290,9 +290,35 @@ const conversionBaseData: [[Numbers, EtherUnits], string][] = [ [['178373938391829348', 'ether'], '0.178373938391829348'], [['879123456788877661', 'gwei'], '879123456.788877661'], [['879123456788877661', 'tether'], '0.000000000000879123456788877661'], + [['1', 0], '1'], + [['1', 1], '0.1'], + [['1', 2], '0.01'], + [['1', 3], '0.001'], + [['1', 4], '0.0001'], + [['1', 5], '0.00001'], + [['1', 6], '0.000001'], + [['1', 7], '0.0000001'], + [['1', 8], '0.00000001'], + [['1', 9], '0.000000001'], + [['1', 10], '0.0000000001'], + [[1, 18], '0.000000000000000001'], + [[100, 2], '1'], + [['100', 2], '1'], + [['1000', 3], '1'], + [['10000', 4], '1'], + [['100000', 5], '1'], + [['1000000', 6], '1'], + [['10000000', 7], '1'], + [['100000000', 8], '1'], + [['1000000000', 9], '1'], + [['10000000000', 10], '1'], + [['100000000000', 11], '1'], + [['1000000000000', 12], '1'], + [['10000000000000', 13], '1'], + [['1000000000000000000', 18], '1'], ]; -export const fromWeiValidData: [[Numbers, EtherUnits], Numbers][] = [ +export const fromWeiValidData: [[Numbers, EtherUnits | number], Numbers][] = [ ...conversionBaseData, [['0xff', 'wei'], '255'], [[1e+22, 'ether'], '10000'], @@ -305,7 +331,7 @@ export const fromWeiValidData: [[Numbers, EtherUnits], Numbers][] = [ [['3308685546611893', 'ether'], '0.003308685546611893'] ]; -export const toWeiValidData: [[Numbers, EtherUnits], Numbers][] = [ +export const toWeiValidData: [[Numbers, EtherUnits | number], Numbers][] = [ ...conversionBaseData, [['255', 'wei'], '0xFF'], [['100000000000', 'ether'], 0.0000001], @@ -336,6 +362,8 @@ export const fromWeiInvalidData: [[any, any], string][] = [ [[{}, 'kwei'], 'Invalid value given "{}". Error: can not parse as number data'], [['data', 'kwei'], 'Invalid value given "data". Error: can not parse as number data.'], [['1234', 'uwei'], 'Invalid value given "uwei". Error: invalid unit.'], + [['1234', -1], 'Invalid value given "-1". Error: not a valid unit. Must be a positive integer.'], + [['1234', 3.3], 'Invalid value given "3.3". Error: not a valid unit. Must be a positive integer.'] ]; export const toWeiInvalidData: [[any, any], string][] = [