1- import type { Struct } from '@metamask/superstruct' ;
2- import { is , pattern , string } from '@metamask/superstruct' ;
1+ import { pattern , type Struct , string } from '@metamask/superstruct' ;
32import { keccak_256 as keccak256 } from '@noble/hashes/sha3' ;
43import memoize from 'lodash.memoize' ;
54
65import { assert } from './assert' ;
76
87export type Hex = `0x${string } `;
98
10- export const HexStruct = pattern ( string ( ) , / ^ (?: 0 x ) ? [ 0 - 9 a - f ] + $ / iu) ;
11- export const StrictHexStruct = pattern ( string ( ) , / ^ 0 x [ 0 - 9 a - f ] + $ / iu) as Struct <
9+ // Use native regexes instead of superstruct for maximum performance.
10+ // Pre-compiled regex for maximum performance - avoids recompilation on each call
11+ const HEX_REGEX = / ^ (?: 0 x ) ? [ 0 - 9 a - f ] + $ / iu;
12+ const STRICT_HEX_REGEX = / ^ 0 x [ 0 - 9 a - f ] + $ / iu;
13+ const HEX_ADDRESS_REGEX = / ^ 0 x [ 0 - 9 a - f ] { 40 } $ / u;
14+ const HEX_CHECKSUM_ADDRESS_REGEX = / ^ 0 x [ 0 - 9 a - f A - F ] { 40 } $ / u;
15+
16+ export const HexStruct = pattern ( string ( ) , HEX_REGEX ) ;
17+ export const StrictHexStruct = pattern ( string ( ) , STRICT_HEX_REGEX ) as Struct <
18+ Hex ,
19+ null
20+ > ;
21+ export const HexAddressStruct = pattern ( string ( ) , HEX_ADDRESS_REGEX ) as Struct <
1222 Hex ,
1323 null
1424> ;
15- export const HexAddressStruct = pattern (
16- string ( ) ,
17- / ^ 0 x [ 0 - 9 a - f ] { 40 } $ / u,
18- ) as Struct < Hex , null > ;
1925export const HexChecksumAddressStruct = pattern (
2026 string ( ) ,
21- / ^ 0 x [ 0 - 9 a - f A - F ] { 40 } $ / u ,
27+ HEX_CHECKSUM_ADDRESS_REGEX ,
2228) as Struct < Hex , null > ;
2329
30+ const isString = ( value : unknown ) : value is string => typeof value === 'string' ;
31+
2432/**
2533 * Check if a string is a valid hex string.
2634 *
2735 * @param value - The value to check.
2836 * @returns Whether the value is a valid hex string.
2937 */
3038export function isHexString ( value : unknown ) : value is string {
31- return is ( value , HexStruct ) ;
39+ return isString ( value ) && HEX_REGEX . test ( value ) ;
3240}
3341
3442/**
@@ -39,7 +47,27 @@ export function isHexString(value: unknown): value is string {
3947 * @returns Whether the value is a valid hex string.
4048 */
4149export function isStrictHexString ( value : unknown ) : value is Hex {
42- return is ( value , StrictHexStruct ) ;
50+ return isString ( value ) && STRICT_HEX_REGEX . test ( value ) ;
51+ }
52+
53+ /**
54+ * Check if a string is a valid hex address.
55+ *
56+ * @param value - The value to check.
57+ * @returns Whether the value is a valid hex address.
58+ */
59+ export function isHexAddress ( value : unknown ) : value is Hex {
60+ return isString ( value ) && HEX_ADDRESS_REGEX . test ( value ) ;
61+ }
62+
63+ /**
64+ * Check if a string is a valid hex checksum address.
65+ *
66+ * @param value - The value to check.
67+ * @returns Whether the value is a valid hex checksum address.
68+ */
69+ export function isHexChecksumAddress ( value : unknown ) : value is Hex {
70+ return isString ( value ) && HEX_CHECKSUM_ADDRESS_REGEX . test ( value ) ;
4371}
4472
4573/**
@@ -66,20 +94,6 @@ export function assertIsStrictHexString(value: unknown): asserts value is Hex {
6694 ) ;
6795}
6896
69- /**
70- * Validate that the passed prefixed hex string is an all-lowercase
71- * hex address, or a valid mixed-case checksum address.
72- *
73- * @param possibleAddress - Input parameter to check against.
74- * @returns Whether or not the input is a valid hex address.
75- */
76- export function isValidHexAddress ( possibleAddress : Hex ) {
77- return (
78- is ( possibleAddress , HexAddressStruct ) ||
79- isValidChecksumAddress ( possibleAddress )
80- ) ;
81- }
82-
8397/**
8498 * Encode a passed hex string as an ERC-55 mixed-case checksum address.
8599 * This is the unmemoized version, primarily used for testing.
@@ -89,7 +103,7 @@ export function isValidHexAddress(possibleAddress: Hex) {
89103 * @see https://eips.ethereum.org/EIPS/eip-55
90104 */
91105export function getChecksumAddressUnmemoized ( hexAddress : Hex ) : Hex {
92- assert ( is ( hexAddress , HexChecksumAddressStruct ) , 'Invalid hex address.' ) ;
106+ assert ( isHexChecksumAddress ( hexAddress ) , 'Invalid hex address.' ) ;
93107 const address = remove0x ( hexAddress ) . toLowerCase ( ) ;
94108
95109 const hashBytes = keccak256 ( address ) ;
@@ -127,14 +141,45 @@ export const getChecksumAddress = memoize(getChecksumAddressUnmemoized);
127141 * @param possibleChecksum - The hex address to check.
128142 * @returns True if the address is a checksum address.
129143 */
130- export function isValidChecksumAddress ( possibleChecksum : Hex ) {
131- if ( ! is ( possibleChecksum , HexChecksumAddressStruct ) ) {
144+ export function isValidChecksumAddressUnmemoized ( possibleChecksum : Hex ) {
145+ if ( ! isHexChecksumAddress ( possibleChecksum ) ) {
132146 return false ;
133147 }
134148
135149 return getChecksumAddress ( possibleChecksum ) === possibleChecksum ;
136150}
137151
152+ /**
153+ * Validate that the passed hex string is a valid ERC-55 mixed-case
154+ * checksum address.
155+ *
156+ * @param possibleChecksum - The hex address to check.
157+ * @returns True if the address is a checksum address.
158+ */
159+ export const isValidChecksumAddress = memoize ( isValidChecksumAddressUnmemoized ) ;
160+
161+ /**
162+ * Validate that the passed prefixed hex string is an all-lowercase
163+ * hex address, or a valid mixed-case checksum address.
164+ *
165+ * @param possibleAddress - Input parameter to check against.
166+ * @returns Whether or not the input is a valid hex address.
167+ */
168+ export function isValidHexAddressUnmemoized ( possibleAddress : Hex ) {
169+ return (
170+ isHexAddress ( possibleAddress ) || isValidChecksumAddress ( possibleAddress )
171+ ) ;
172+ }
173+
174+ /**
175+ * Validate that the passed prefixed hex string is an all-lowercase
176+ * hex address, or a valid mixed-case checksum address.
177+ *
178+ * @param possibleAddress - Input parameter to check against.
179+ * @returns Whether or not the input is a valid hex address.
180+ */
181+ export const isValidHexAddress = memoize ( isValidHexAddressUnmemoized ) ;
182+
138183/**
139184 * Add the `0x`-prefix to a hexadecimal string. If the string already has the
140185 * prefix, it is returned as-is.
0 commit comments