@metamask/utils
Version:
Various JavaScript/TypeScript utilities of wide relevance to the MetaMask codebase
1 lines • 13.2 kB
Source Map (JSON)
{"version":3,"file":"unitsConversion.mjs","sourceRoot":"","sources":["../src/unitsConversion.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable operator-assignment */\n/*\nPrimary Attribution\nRichard Moore <ricmoo@me.com>\nhttps://github.com/ethers-io\n\nNote, Richard is a god of ether gods. Follow and respect him, and use Ethers.io!\n*/\n\nconst zero = BigInt(0);\nconst negative1 = BigInt(-1);\n\n/**\n * Converts a string, number, or bigint to a bigint.\n *\n * @param arg - The value to convert to bigint.\n * @returns The bigint representation of the input.\n * @throws Error if the input type cannot be converted to bigint.\n */\nexport function numericToBigInt(arg: string | number | bigint): bigint {\n if (typeof arg === 'string') {\n return BigInt(arg);\n }\n if (typeof arg === 'number') {\n return BigInt(arg);\n }\n if (typeof arg === 'bigint') {\n return arg;\n }\n\n throw new Error(`Cannot convert ${typeof arg} to BigInt`);\n}\n\n// complete ethereum unit map\nexport const unitMap = {\n noether: '0',\n wei: '1',\n kwei: '1000',\n Kwei: '1000',\n babbage: '1000',\n femtoether: '1000',\n mwei: '1000000',\n Mwei: '1000000',\n lovelace: '1000000',\n picoether: '1000000',\n gwei: '1000000000',\n Gwei: '1000000000',\n shannon: '1000000000',\n nanoether: '1000000000',\n nano: '1000000000',\n szabo: '1000000000000',\n microether: '1000000000000',\n micro: '1000000000000',\n finney: '1000000000000000',\n milliether: '1000000000000000',\n milli: '1000000000000000',\n ether: '1000000000000000000',\n kether: '1000000000000000000000',\n grand: '1000000000000000000000',\n mether: '1000000000000000000000000',\n gether: '1000000000000000000000000000',\n tether: '1000000000000000000000000000000',\n} as const;\n\n// Pre-computed unit values as BigInt for performance\nconst unitMapBigInt = Object.fromEntries(\n Object.entries(unitMap).map(([key, value]) => [key, BigInt(value)]),\n) as Record<EthereumUnit, bigint>;\n\nconst unitLengths = Object.fromEntries(\n Object.entries(unitMap).map(([key, value]) => [key, value.length - 1 || 1]),\n) as Record<EthereumUnit, number>;\n\nconst NUMBER_REGEX = /^-?[0-9.]+$/u;\nconst FRACTION_REGEX = /^([0-9]*[1-9]|0)(0*)/u;\nconst COMMIFY_REGEX = /\\B(?=(\\d{3})+(?!\\d))/gu;\n\ntype EthereumUnit = keyof typeof unitMap;\n\n/**\n * Returns value of unit in Wei.\n *\n * @param unitInput - The unit to convert to, default ether.\n * @returns Value of the unit (in Wei).\n * @throws Error if the unit is not correct.\n */\nexport function getValueOfUnit(unitInput: EthereumUnit = 'ether'): bigint {\n const unit = unitInput.toLowerCase() as EthereumUnit;\n const unitValue = unitMapBigInt[unit];\n\n if (unitValue === undefined) {\n throw new Error(\n `The unit provided ${unitInput} doesn't exist, please use the one of the following units ${JSON.stringify(\n unitMap,\n null,\n 2,\n )}`,\n );\n }\n\n return unitValue;\n}\n\n/**\n * Converts a number to a string.\n *\n * @param arg - The number to convert to a string.\n * @returns The string representation of the number.\n * @throws Error if the number is invalid.\n */\nexport function numberToString(arg: string | number | bigint) {\n if (typeof arg === 'string') {\n if (!NUMBER_REGEX.test(arg)) {\n throw new Error(\n `while converting number to string, invalid number value '${arg}', should be a number matching (^-?[0-9.]+).`,\n );\n }\n return arg;\n }\n if (typeof arg === 'number') {\n return String(arg);\n }\n if (typeof arg === 'bigint') {\n return arg.toString();\n }\n throw new Error(\n `while converting number to string, invalid number value '${String(\n arg,\n )}' type ${typeof arg}.`,\n );\n}\n\n/**\n * Converts a number from Wei to a string.\n *\n * @param weiInput - The number to convert from Wei.\n * @param unit - The unit to convert to, default ether.\n * @param optionsInput - The options to use for the conversion.\n * @param optionsInput.pad - Whether to pad the fractional part with zeros.\n * @param optionsInput.commify - Whether to add commas to separate thousands.\n * @returns The string representation of the number.\n * @throws Error if the number is invalid.\n */\nexport function fromWei(\n weiInput: string | number | bigint,\n unit: EthereumUnit,\n optionsInput?: { pad?: boolean; commify?: boolean },\n) {\n let wei = numericToBigInt(weiInput);\n const negative = wei < zero;\n const unitLower = unit.toLowerCase() as EthereumUnit;\n const base = unitMapBigInt[unitLower];\n const baseLength = unitLengths[unitLower];\n const options = optionsInput ?? {};\n\n if (base === undefined) {\n throw new Error(\n `The unit provided ${unit} doesn't exist, please use the one of the following units ${JSON.stringify(\n unitMap,\n null,\n 2,\n )}`,\n );\n }\n\n // Handle special case of noether (base = 0)\n if (base === zero) {\n return negative ? '-0' : '0';\n }\n\n if (negative) {\n wei = wei * negative1;\n }\n\n let fraction = (wei % base).toString();\n\n fraction = fraction.padStart(baseLength, '0');\n\n if (!options.pad) {\n const fractionMatch = fraction.match(FRACTION_REGEX);\n // istanbul ignore next: defensive fallback that's never reachable but necessary to satisfy TS\n fraction = fractionMatch?.[1] ?? '0';\n }\n\n let whole = (wei / base).toString();\n\n if (options.commify) {\n whole = whole.replace(COMMIFY_REGEX, ',');\n }\n\n let value = `${whole}${fraction === '0' ? '' : `.${fraction}`}`;\n\n if (negative) {\n value = `-${value}`;\n }\n\n return value;\n}\n\n/**\n * Converts a number to Wei.\n *\n * @param etherInput - The number to convert to Wei.\n * @param unit - The unit to convert to, default ether.\n * @returns The number in Wei.\n * @throws Error if the number is invalid.\n */\nexport function toWei(\n etherInput: string | number | bigint,\n unit: EthereumUnit,\n): bigint {\n const unitLower = unit.toLowerCase() as EthereumUnit;\n const base = unitMapBigInt[unitLower];\n const baseLength = unitLengths[unitLower];\n\n if (base === undefined) {\n throw new Error(\n `The unit provided ${unit} doesn't exist, please use the one of the following units ${JSON.stringify(\n unitMap,\n null,\n 2,\n )}`,\n );\n }\n\n // Handle special case of noether (base = 0)\n if (base === zero) {\n return zero;\n }\n\n // Fast path for bigint inputs when unit is wei (no conversion needed)\n if (typeof etherInput === 'bigint' && unitLower === 'wei') {\n return etherInput;\n }\n\n // Fast path for bigint inputs with whole units (no fractional part)\n if (typeof etherInput === 'bigint') {\n return etherInput * base;\n }\n\n let ether = numberToString(etherInput);\n\n // Is it negative?\n const negative = ether.startsWith('-');\n if (negative) {\n ether = ether.substring(1);\n }\n\n if (ether === '.') {\n throw new Error(\n `While converting number ${etherInput} to wei, invalid value`,\n );\n }\n\n // Split it into a whole and fractional part\n const comps = ether.split('.');\n if (comps.length > 2) {\n throw new Error(\n `While converting number ${etherInput} to wei, too many decimal points`,\n );\n }\n\n let whole = comps[0];\n let fraction = comps[1];\n\n if (!whole) {\n whole = '0';\n }\n if (!fraction) {\n fraction = '0';\n }\n if (fraction.length > baseLength) {\n throw new Error(\n `While converting number ${etherInput} to wei, too many decimal places`,\n );\n }\n\n fraction = fraction.padEnd(baseLength, '0');\n\n const wholeBigInt = BigInt(whole);\n const fractionBigInt = BigInt(fraction);\n let wei = wholeBigInt * base + fractionBigInt;\n\n if (negative) {\n wei = wei * negative1;\n }\n\n return wei;\n}\n"]}