-
-
Notifications
You must be signed in to change notification settings - Fork 40
fix: drop viem from x402 address validation #246
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
Changes from 1 commit
2840e23
b06ec40
81206b0
6a892cc
571bd1b
3d23e9d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,67 @@ | ||||||
| import { keccak_256 as keccak256 } from '@noble/hashes/sha3'; | ||||||
| import { bytesToHex, utf8ToBytes } from '@noble/hashes/utils'; | ||||||
|
|
||||||
| export type Address = `0x${string}`; | ||||||
| export type Hex = `0x${string}`; | ||||||
|
|
||||||
| const ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/u; | ||||||
| const HEX_REGEX = /^0x[0-9a-fA-F]*$/u; | ||||||
|
|
||||||
| /** | ||||||
| * Check whether a value is a 0x-prefixed hexadecimal string. | ||||||
| * | ||||||
| * @param value - Value to inspect. | ||||||
| * @returns True when the value is hex data. | ||||||
| */ | ||||||
| export function isHex(value: unknown): value is Hex { | ||||||
| return typeof value === 'string' && HEX_REGEX.test(value); | ||||||
| } | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can remove the isHex util and HEX_REGEX from here, and use the It ensures non-zero length '0x' prefixed hex string. |
||||||
|
|
||||||
| /** | ||||||
| * Validate and normalize an Ethereum address to its EIP-55 checksum form. | ||||||
| * | ||||||
| * @param value - Address string to normalize. | ||||||
| * @returns The checksummed address. | ||||||
| */ | ||||||
| export function getAddress(value: string): Address { | ||||||
| if (!ADDRESS_REGEX.test(value)) { | ||||||
| throw new Error('Invalid Ethereum address'); | ||||||
| } | ||||||
|
|
||||||
| const address = value.slice(2); | ||||||
| const lowerAddress = address.toLowerCase(); | ||||||
| const upperAddress = address.toUpperCase(); | ||||||
| const checksummedAddress = checksumAddress(lowerAddress); | ||||||
|
|
||||||
| if ( | ||||||
| address !== lowerAddress && | ||||||
| address !== upperAddress && | ||||||
| `0x${address}` !== checksummedAddress | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of using string interpolation here, we can just compare
Suggested change
|
||||||
| ) { | ||||||
| throw new Error('Invalid Ethereum address checksum'); | ||||||
| } | ||||||
|
|
||||||
| return checksummedAddress; | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * Convert a lowercase Ethereum address body to EIP-55 checksum form. | ||||||
| * | ||||||
| * @param lowerAddress - 40-character lowercase hex address without 0x prefix. | ||||||
| * @returns The checksummed address with 0x prefix. | ||||||
| */ | ||||||
| function checksumAddress(lowerAddress: string): Address { | ||||||
| const addressHash = bytesToHex(keccak256(utf8ToBytes(lowerAddress))); | ||||||
| let checksummed = '0x'; | ||||||
|
|
||||||
| for (let index = 0; index < lowerAddress.length; index += 1) { | ||||||
| const character = lowerAddress[index] as string; | ||||||
| const hashNibble = addressHash[index] as string; | ||||||
| checksummed += | ||||||
| Number.parseInt(hashNibble, 16) >= 8 | ||||||
| ? character.toUpperCase() | ||||||
| : character; | ||||||
| } | ||||||
|
|
||||||
| return checksummed as Address; | ||||||
| } | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would make sense to add a dependency to @metamask/utils instead of @noble/hashes directly, and use the We could also drop the regex validation as this is implemented in The checksum validation in |
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can also remove the
HexandAddresstypes and use theHextype exported from @metamask/utils in all places where we reference these types (HexandAddressare functionally identical, so I don't think there's value in distinguishing unless there's an actual difference in the type).