UNPKG

@metamask/utils

Version:

Various JavaScript/TypeScript utilities of wide relevance to the MetaMask codebase

1 lines 10.4 kB
{"version":3,"file":"hex.cjs","sourceRoot":"","sources":["../src/hex.ts"],"names":[],"mappings":"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","sourcesContent":["import { pattern, type Struct, string } from '@metamask/superstruct';\nimport { keccak_256 as keccak256 } from '@noble/hashes/sha3';\nimport { memoize } from 'lodash';\n\nimport { assert } from './assert';\n\nexport type Hex = `0x${string}`;\n\n// Use native regexes instead of superstruct for maximum performance.\n// Pre-compiled regex for maximum performance - avoids recompilation on each call\nconst HEX_REGEX = /^(?:0x)?[0-9a-f]+$/iu;\nconst STRICT_HEX_REGEX = /^0x[0-9a-f]+$/iu;\nconst HEX_ADDRESS_REGEX = /^0x[0-9a-f]{40}$/u;\nconst HEX_CHECKSUM_ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/u;\n\nexport const HexStruct = pattern(string(), HEX_REGEX);\nexport const StrictHexStruct = pattern(string(), STRICT_HEX_REGEX) as Struct<\n Hex,\n null\n>;\nexport const HexAddressStruct = pattern(string(), HEX_ADDRESS_REGEX) as Struct<\n Hex,\n null\n>;\nexport const HexChecksumAddressStruct = pattern(\n string(),\n HEX_CHECKSUM_ADDRESS_REGEX,\n) as Struct<Hex, null>;\n\nconst isString = (value: unknown): value is string => typeof value === 'string';\n\n/**\n * Check if a string is a valid hex string.\n *\n * @param value - The value to check.\n * @returns Whether the value is a valid hex string.\n */\nexport function isHexString(value: unknown): value is string {\n return isString(value) && HEX_REGEX.test(value);\n}\n\n/**\n * Strictly check if a string is a valid hex string. A valid hex string must\n * start with the \"0x\"-prefix.\n *\n * @param value - The value to check.\n * @returns Whether the value is a valid hex string.\n */\nexport function isStrictHexString(value: unknown): value is Hex {\n return isString(value) && STRICT_HEX_REGEX.test(value);\n}\n\n/**\n * Check if a string is a valid hex address.\n *\n * @param value - The value to check.\n * @returns Whether the value is a valid hex address.\n */\nexport function isHexAddress(value: unknown): value is Hex {\n return isString(value) && HEX_ADDRESS_REGEX.test(value);\n}\n\n/**\n * Check if a string is a valid hex checksum address.\n *\n * @param value - The value to check.\n * @returns Whether the value is a valid hex checksum address.\n */\nexport function isHexChecksumAddress(value: unknown): value is Hex {\n return isString(value) && HEX_CHECKSUM_ADDRESS_REGEX.test(value);\n}\n\n/**\n * Assert that a value is a valid hex string.\n *\n * @param value - The value to check.\n * @throws If the value is not a valid hex string.\n */\nexport function assertIsHexString(value: unknown): asserts value is string {\n assert(isHexString(value), 'Value must be a hexadecimal string.');\n}\n\n/**\n * Assert that a value is a valid hex string. A valid hex string must start with\n * the \"0x\"-prefix.\n *\n * @param value - The value to check.\n * @throws If the value is not a valid hex string.\n */\nexport function assertIsStrictHexString(value: unknown): asserts value is Hex {\n assert(\n isStrictHexString(value),\n 'Value must be a hexadecimal string, starting with \"0x\".',\n );\n}\n\n/**\n * Encode a passed hex string as an ERC-55 mixed-case checksum address.\n * This is the unmemoized version, primarily used for testing.\n *\n * @param hexAddress - The hex address to encode.\n * @returns The address encoded according to ERC-55.\n * @see https://eips.ethereum.org/EIPS/eip-55\n */\nexport function getChecksumAddressUnmemoized(hexAddress: Hex): Hex {\n assert(isHexChecksumAddress(hexAddress), 'Invalid hex address.');\n const address = remove0x(hexAddress).toLowerCase();\n\n const hashBytes = keccak256(address);\n const { length } = address;\n const result = new Array(length); // Pre-allocate array\n\n for (let i = 0; i < length; i++) {\n /* eslint-disable no-bitwise */\n const byteIndex = i >> 1; // Faster than Math.floor(i / 2)\n const nibbleIndex = i & 1; // Faster than i % 2\n const byte = hashBytes[byteIndex] as number;\n const nibble = nibbleIndex === 0 ? byte >> 4 : byte & 0x0f;\n /* eslint-enable no-bitwise */\n\n result[i] = nibble >= 8 ? (address[i] as string).toUpperCase() : address[i];\n }\n\n return `0x${result.join('')}`;\n}\n\n/**\n * Encode a passed hex string as an ERC-55 mixed-case checksum address.\n * This function is memoized for performance.\n *\n * @param hexAddress - The hex address to encode.\n * @returns The address encoded according to ERC-55.\n * @see https://eips.ethereum.org/EIPS/eip-55\n */\nexport const getChecksumAddress = memoize(getChecksumAddressUnmemoized);\n\n/**\n * Validate that the passed hex string is a valid ERC-55 mixed-case\n * checksum address.\n *\n * @param possibleChecksum - The hex address to check.\n * @returns True if the address is a checksum address.\n */\nexport function isValidChecksumAddressUnmemoized(possibleChecksum: Hex) {\n if (!isHexChecksumAddress(possibleChecksum)) {\n return false;\n }\n\n return getChecksumAddress(possibleChecksum) === possibleChecksum;\n}\n\n/**\n * Validate that the passed hex string is a valid ERC-55 mixed-case\n * checksum address.\n *\n * @param possibleChecksum - The hex address to check.\n * @returns True if the address is a checksum address.\n */\nexport const isValidChecksumAddress = memoize(isValidChecksumAddressUnmemoized);\n\n/**\n * Validate that the passed prefixed hex string is an all-lowercase\n * hex address, or a valid mixed-case checksum address.\n *\n * @param possibleAddress - Input parameter to check against.\n * @returns Whether or not the input is a valid hex address.\n */\nexport function isValidHexAddressUnmemoized(possibleAddress: Hex) {\n return (\n isHexAddress(possibleAddress) || isValidChecksumAddress(possibleAddress)\n );\n}\n\n/**\n * Validate that the passed prefixed hex string is an all-lowercase\n * hex address, or a valid mixed-case checksum address.\n *\n * @param possibleAddress - Input parameter to check against.\n * @returns Whether or not the input is a valid hex address.\n */\nexport const isValidHexAddress = memoize(isValidHexAddressUnmemoized);\n\n/**\n * Add the `0x`-prefix to a hexadecimal string. If the string already has the\n * prefix, it is returned as-is.\n *\n * @param hexadecimal - The hexadecimal string to add the prefix to.\n * @returns The prefixed hexadecimal string.\n */\nexport function add0x(hexadecimal: string): Hex {\n if (hexadecimal.startsWith('0x')) {\n return hexadecimal as Hex;\n }\n\n if (hexadecimal.startsWith('0X')) {\n return `0x${hexadecimal.substring(2)}`;\n }\n\n return `0x${hexadecimal}`;\n}\n\n/**\n * Remove the `0x`-prefix from a hexadecimal string. If the string doesn't have\n * the prefix, it is returned as-is.\n *\n * @param hexadecimal - The hexadecimal string to remove the prefix from.\n * @returns The un-prefixed hexadecimal string.\n */\nexport function remove0x(hexadecimal: string): string {\n if (hexadecimal.startsWith('0x') || hexadecimal.startsWith('0X')) {\n return hexadecimal.substring(2);\n }\n\n return hexadecimal;\n}\n"]}