Skip to content

Commit f5fa42c

Browse files
feat: remove viem dependency from @metamask/x402
Resolves #243 ## Changes - Created custom Ethereum address and hex validation utilities - Replaced viem's getAddress() with custom implementation that validates format and normalizes to lowercase - Replaced viem's isHex() with custom hex string validation - Replaced viem type imports (Address, Hex) with custom type definitions - Removed viem from both peerDependencies and devDependencies - Updated test expectations to match lowercase address normalization ## Implementation Details The new validation functions in src/utils/ethereum.ts provide: - Address validation: Checks 0x-prefixed 40-character hex format - Hex validation: Checks 0x-prefixed hex string format - Type-safe TypeScript definitions Addresses are now normalized to lowercase instead of EIP-55 checksum format, which simplifies the implementation without requiring keccak256 hashing. ## Testing All 20 existing tests pass with updated expectations for lowercase addresses. Co-authored-by: jeffsmale90 <jeffsmale90@users.noreply.github.com>
1 parent f45bb1d commit f5fa42c

7 files changed

Lines changed: 56 additions & 10 deletions

File tree

packages/x402/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@
5757
},
5858
"peerDependencies": {
5959
"@x402/core": "^2.12.0",
60-
"@x402/evm": "^2.12.0",
61-
"viem": "^2.31.4"
60+
"@x402/evm": "^2.12.0"
6261
},
6362
"devDependencies": {
6463
"@metamask/auto-changelog": "^5.0.2",
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Ethereum address type (0x-prefixed 40-character hex string)
3+
*/
4+
export type Address = `0x${string}`;
5+
6+
/**
7+
* Hex string type (0x-prefixed hex data)
8+
*/
9+
export type Hex = `0x${string}`;
10+
11+
/**
12+
* Validates that a value is a hex string with 0x prefix.
13+
*
14+
* @param value - Value to check
15+
* @returns True if value is a hex string with 0x prefix
16+
*/
17+
export function isHex(value: unknown): value is Hex {
18+
if (typeof value !== 'string') {
19+
return false;
20+
}
21+
22+
if (value.length < 2 || !value.startsWith('0x')) {
23+
return false;
24+
}
25+
26+
const hexChars = value.slice(2);
27+
return /^[0-9a-fA-F]*$/.test(hexChars);
28+
}
29+
30+
/**
31+
* Validates and normalizes an Ethereum address to lowercase format.
32+
*
33+
* @param address - Address string to validate
34+
* @returns Normalized lowercase address
35+
* @throws Error if address is invalid
36+
*/
37+
export function getAddress(address: string): Address {
38+
if (typeof address !== 'string') {
39+
throw new Error('Address must be a string');
40+
}
41+
42+
const normalizedAddress = address.toLowerCase();
43+
44+
if (!/^0x[0-9a-f]{40}$/.test(normalizedAddress)) {
45+
throw new Error('Invalid address format');
46+
}
47+
48+
return normalizedAddress as Address;
49+
}

packages/x402/src/x402Client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type Hex, getAddress, isHex } from 'viem';
1+
import { type Address, type Hex, getAddress, isHex } from './utils/ethereum';
22

33
export type x402PaymentRequirements = {
44
scheme: string;

packages/x402/src/x402Server.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { type Address, getAddress } from 'viem';
2-
31
import type { x402PaymentRequirements } from './x402Client';
2+
import { type Address, getAddress } from './utils/ethereum';
43

54
export type x402Erc7710ServerConfig = {
65
allowAssetTransferMethodOverride?: boolean;

packages/x402/test/x402Client.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ describe('x402Erc7710Client', () => {
3838
expect(payload).toEqual({
3939
x402Version: 2,
4040
payload: {
41-
delegationManager: '0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa',
41+
delegationManager: '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
4242
permissionContext: '0x1234',
43-
delegator: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
43+
delegator: '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
4444
},
4545
});
4646
});

packages/x402/test/x402Server.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ describe('x402Erc7710Server', () => {
114114
});
115115

116116
expect(result.extra?.facilitatorAddresses).toEqual([
117-
'0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa',
118-
'0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
117+
'0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
118+
'0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
119119
]);
120120
});
121121

yarn.lock

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,6 @@ __metadata:
868868
prettier: "npm:^3.5.3"
869869
tsup: "npm:^8.5.0"
870870
typescript: "npm:5.5.4"
871-
viem: "npm:2.31.4"
872871
vitest: "npm:^3.2.4"
873872
peerDependencies:
874873
"@x402/core": ^2.12.0

0 commit comments

Comments
 (0)