@armory-sh/base 0.2.28 → 0.2.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +304 -28
  2. package/dist/client-hooks-runtime.d.ts +9 -0
  3. package/dist/encoding/x402.d.ts +1 -1
  4. package/dist/errors.d.ts +10 -0
  5. package/dist/facilitator-capabilities.d.ts +9 -0
  6. package/dist/index.d.ts +30 -22
  7. package/dist/index.js +1198 -650
  8. package/dist/payment-client.d.ts +1 -1
  9. package/dist/payment-requirements.d.ts +35 -0
  10. package/dist/protocol.d.ts +33 -0
  11. package/dist/types/api.d.ts +1 -1
  12. package/dist/types/hooks.d.ts +17 -1
  13. package/dist/types/protocol.d.ts +1 -1
  14. package/dist/types/wallet.d.ts +24 -0
  15. package/dist/utils/base64.d.ts +4 -0
  16. package/dist/utils/x402.d.ts +1 -1
  17. package/dist/validation.d.ts +1 -1
  18. package/package.json +15 -2
  19. package/src/abi/erc20.ts +84 -0
  20. package/src/client-hooks-runtime.ts +153 -0
  21. package/src/data/tokens.ts +199 -0
  22. package/src/eip712.ts +108 -0
  23. package/src/encoding/x402.ts +205 -0
  24. package/src/encoding.ts +98 -0
  25. package/src/errors.ts +23 -0
  26. package/src/facilitator-capabilities.ts +125 -0
  27. package/src/index.ts +330 -0
  28. package/src/payment-client.ts +201 -0
  29. package/src/payment-requirements.ts +354 -0
  30. package/src/protocol.ts +57 -0
  31. package/src/types/api.ts +304 -0
  32. package/src/types/hooks.ts +85 -0
  33. package/src/types/networks.ts +175 -0
  34. package/src/types/protocol.ts +182 -0
  35. package/src/types/v2.ts +282 -0
  36. package/src/types/wallet.ts +30 -0
  37. package/src/types/x402.ts +151 -0
  38. package/src/utils/base64.ts +48 -0
  39. package/src/utils/routes.ts +240 -0
  40. package/src/utils/utils/index.ts +7 -0
  41. package/src/utils/utils/mock-facilitator.ts +184 -0
  42. package/src/utils/x402.ts +147 -0
  43. package/src/validation.ts +654 -0
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Armory V2 Types - x402 Protocol V2 Compatible
3
+ *
4
+ * These types match the Coinbase x402 V2 specification for full interoperability.
5
+ * No conversion needed - this is the native format.
6
+ *
7
+ * Specification: https://github.com/coinbase/x402
8
+ */
9
+
10
+ // ============================================================================
11
+ // Base Types
12
+ // ============================================================================
13
+
14
+ export type CAIP2Network = `eip155:${string}`;
15
+
16
+ export type CAIPAssetId = `eip155:${string}/erc20:${string}`;
17
+
18
+ export type Address = `0x${string}`;
19
+
20
+ export interface Signature {
21
+ v: number;
22
+ r: string;
23
+ s: string;
24
+ }
25
+
26
+ export type PayToV2 =
27
+ | Address
28
+ | {
29
+ role?: string;
30
+ callback?: string;
31
+ };
32
+
33
+ export type PayToAddress = Address | PayToV2;
34
+
35
+ export interface Extensions {
36
+ [key: string]: unknown;
37
+ }
38
+
39
+ // ============================================================================
40
+ // Resource Info
41
+ // ============================================================================
42
+
43
+ /**
44
+ * Resource information describing the protected resource
45
+ */
46
+ export interface ResourceInfo {
47
+ /** URL of the protected resource */
48
+ url: string;
49
+ /** Human-readable description of the resource */
50
+ description?: string;
51
+ /** MIME type of the expected response */
52
+ mimeType?: string;
53
+ }
54
+
55
+ // ============================================================================
56
+ // Payment Requirements (Server → Client in accepts[] array)
57
+ // ============================================================================
58
+
59
+ /**
60
+ * Payment requirements for a specific payment method
61
+ * Matches x402 V2 PaymentRequirements spec
62
+ */
63
+ export interface PaymentRequirementsV2 {
64
+ /** Payment scheme identifier (e.g., "exact") */
65
+ scheme: "exact";
66
+ /** Blockchain network identifier in CAIP-2 format */
67
+ network: CAIP2Network;
68
+ /** Required payment amount in atomic token units */
69
+ amount: string;
70
+ /** Token contract address (extracted from CAIP asset ID) */
71
+ asset: Address;
72
+ /** Recipient wallet address or role constant */
73
+ payTo: Address;
74
+ /** Maximum time allowed for payment completion */
75
+ maxTimeoutSeconds: number;
76
+ /** EIP-712 domain parameter: token name */
77
+ name?: string;
78
+ /** EIP-712 domain parameter: token version */
79
+ version?: string;
80
+ /** Scheme-specific additional information */
81
+ extra?: Extensions;
82
+ }
83
+
84
+ // ============================================================================
85
+ // Payment Required Response (Server → Client, 402 status)
86
+ // ============================================================================
87
+
88
+ /**
89
+ * Payment required response (PAYMENT-REQUIRED header)
90
+ * Matches x402 V2 PaymentRequired spec
91
+ */
92
+ export interface PaymentRequiredV2 {
93
+ /** Protocol version identifier (must be 2) */
94
+ x402Version: 2;
95
+ /** Human-readable error message */
96
+ error?: string;
97
+ /** Resource being accessed */
98
+ resource: ResourceInfo;
99
+ /** Array of acceptable payment methods */
100
+ accepts: PaymentRequirementsV2[];
101
+ /** Protocol extensions data */
102
+ extensions?: Extensions;
103
+ }
104
+
105
+ // ============================================================================
106
+ // EIP-3009 Authorization (for exact scheme on EVM)
107
+ // ============================================================================
108
+
109
+ /**
110
+ * EIP-3009 TransferWithAuthorization authorization data
111
+ * Matches x402 V2 spec for exact scheme
112
+ */
113
+ export interface EIP3009Authorization {
114
+ /** Payer's wallet address */
115
+ from: Address;
116
+ /** Recipient's wallet address */
117
+ to: Address;
118
+ /** Payment amount in atomic units */
119
+ value: string;
120
+ /** Unix timestamp when authorization becomes valid */
121
+ validAfter: string;
122
+ /** Unix timestamp when authorization expires */
123
+ validBefore: string;
124
+ /** 32-byte random nonce (bytes32 hex string) */
125
+ nonce: `0x${string}`;
126
+ }
127
+
128
+ /**
129
+ * Scheme-specific payment payload data
130
+ */
131
+ export interface SchemePayloadV2 {
132
+ /** Signature for the authorization (0x-prefixed 65-byte hex) */
133
+ signature: `0x${string}`;
134
+ /** EIP-3009 authorization */
135
+ authorization: EIP3009Authorization;
136
+ }
137
+
138
+ // ============================================================================
139
+ // Payment Payload (Client → Server, PAYMENT-SIGNATURE header)
140
+ // ============================================================================
141
+
142
+ /**
143
+ * Payment payload sent by client
144
+ * Matches x402 V2 PaymentPayload spec (Coinbase format)
145
+ *
146
+ * The 'accepted' field echoes the server's requirements being accepted.
147
+ */
148
+ export interface PaymentPayloadV2 {
149
+ /** Protocol version identifier */
150
+ x402Version: 2;
151
+ /** The payment requirements being accepted (echoed from server) */
152
+ accepted: PaymentRequirementsV2;
153
+ /** Scheme-specific payment data */
154
+ payload: SchemePayloadV2;
155
+ /** Resource being accessed (optional) */
156
+ resource?: ResourceInfo;
157
+ /** Protocol extensions data */
158
+ extensions?: Extensions;
159
+ }
160
+
161
+ // ============================================================================
162
+ // Settlement Response (Server → Client, PAYMENT-RESPONSE header)
163
+ // ============================================================================
164
+
165
+ /**
166
+ * Settlement response after payment settlement
167
+ * Matches x402 V2 SettlementResponse spec
168
+ */
169
+ export interface SettlementResponseV2 {
170
+ /** Whether settlement was successful */
171
+ success: boolean;
172
+ /** Error reason if settlement failed */
173
+ errorReason?: string;
174
+ /** Address of the payer's wallet */
175
+ payer?: Address;
176
+ /** Blockchain transaction hash (empty if failed) */
177
+ transaction: string;
178
+ /** Blockchain network identifier in CAIP-2 format */
179
+ network: CAIP2Network;
180
+ /** Protocol extensions data */
181
+ extensions?: Extensions;
182
+ }
183
+
184
+ // ============================================================================
185
+ // Headers
186
+ // ============================================================================
187
+
188
+ export const V2_HEADERS = {
189
+ PAYMENT_SIGNATURE: "PAYMENT-SIGNATURE",
190
+ PAYMENT_REQUIRED: "PAYMENT-REQUIRED",
191
+ PAYMENT_RESPONSE: "PAYMENT-RESPONSE",
192
+ } as const;
193
+
194
+ // ============================================================================
195
+ // Type Guards
196
+ // ============================================================================
197
+
198
+ export function isCAIP2ChainId(value: string): value is CAIP2Network {
199
+ return /^eip155:\d+$/.test(value);
200
+ }
201
+
202
+ export function isCAIPAssetId(value: string): value is CAIPAssetId {
203
+ return /^eip155:\d+\/erc20:0x[a-fA-F0-9]+$/.test(value);
204
+ }
205
+
206
+ export function isAddress(value: string): value is Address {
207
+ return /^0x[a-fA-F0-9]{40}$/.test(value);
208
+ }
209
+
210
+ export function isPaymentRequiredV2(obj: unknown): obj is PaymentRequiredV2 {
211
+ return (
212
+ typeof obj === "object" &&
213
+ obj !== null &&
214
+ "x402Version" in obj &&
215
+ (obj as PaymentRequiredV2).x402Version === 2 &&
216
+ "resource" in obj &&
217
+ "accepts" in obj &&
218
+ Array.isArray((obj as PaymentRequiredV2).accepts)
219
+ );
220
+ }
221
+
222
+ export function isPaymentPayloadV2(obj: unknown): obj is PaymentPayloadV2 {
223
+ return (
224
+ typeof obj === "object" &&
225
+ obj !== null &&
226
+ "x402Version" in obj &&
227
+ (obj as PaymentPayloadV2).x402Version === 2 &&
228
+ "accepted" in obj &&
229
+ "payload" in obj
230
+ );
231
+ }
232
+
233
+ // ============================================================================
234
+ // Utility Functions
235
+ // ============================================================================
236
+
237
+ /**
238
+ * Extract token address from CAIP asset ID
239
+ */
240
+ export function assetIdToAddress(assetId: CAIPAssetId): Address {
241
+ const match = assetId.match(/\/erc20:(0x[a-fA-F0-9]{40})$/);
242
+ if (!match) throw new Error(`Invalid CAIP asset ID: ${assetId}`);
243
+ return match[1] as Address;
244
+ }
245
+
246
+ /**
247
+ * Create CAIP asset ID from token address and chain ID
248
+ */
249
+ export function addressToAssetId(
250
+ address: Address,
251
+ chainId: string | number,
252
+ ): CAIPAssetId {
253
+ const chain = typeof chainId === "number" ? `eip155:${chainId}` : chainId;
254
+ if (!isCAIP2ChainId(chain)) throw new Error(`Invalid chain ID: ${chain}`);
255
+ return `${chain}/erc20:${address}` as CAIPAssetId;
256
+ }
257
+
258
+ /**
259
+ * Parse combined signature (0x + r + s + v) into components
260
+ */
261
+ export function parseSignature(signature: `0x${string}`): Signature {
262
+ const sig = signature.slice(2);
263
+ return {
264
+ r: `0x${sig.slice(0, 64)}`,
265
+ s: `0x${sig.slice(64, 128)}`,
266
+ v: parseInt(sig.slice(128, 130), 16),
267
+ };
268
+ }
269
+
270
+ /**
271
+ * Combine signature components into 65-byte hex string
272
+ */
273
+ export function combineSignature(
274
+ v: number,
275
+ r: string,
276
+ s: string,
277
+ ): `0x${string}` {
278
+ const rClean = r.startsWith("0x") ? r.slice(2) : r;
279
+ const sClean = s.startsWith("0x") ? s.slice(2) : s;
280
+ const vHex = v.toString(16).padStart(2, "0");
281
+ return `0x${rClean}${sClean}${vHex}` as `0x${string}`;
282
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Generic Wallet Adapter Interface
3
+ *
4
+ * This interface defines the minimum wallet operations required
5
+ * for x402 payment signing. Each client package implements this
6
+ * interface for their specific wallet library (viem, ethers, etc.).
7
+ */
8
+
9
+ export interface PaymentWallet {
10
+ /**
11
+ * Get the wallet address
12
+ * Can be synchronous or asynchronous depending on the wallet library
13
+ */
14
+ getAddress(): string | Promise<string>;
15
+
16
+ /**
17
+ * Sign EIP-712 typed data
18
+ * Used for EIP-3009 TransferWithAuthorization signatures
19
+ *
20
+ * @param domain - EIP-712 domain separator
21
+ * @param types - EIP-712 type definitions
22
+ * @param value - Message to sign
23
+ * @returns Signature as hex string (0x-prefixed)
24
+ */
25
+ signTypedData(
26
+ domain: Record<string, unknown>,
27
+ types: Record<string, unknown>,
28
+ value: Record<string, unknown>,
29
+ ): Promise<string>;
30
+ }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * X402 Protocol Types - Coinbase Compatible Format
3
+ *
4
+ * This module provides types that match the official Coinbase x402 SDK format
5
+ * for full interoperability with their facilitator and extensions.
6
+ */
7
+
8
+ export type Address = `0x${string}`;
9
+ export type Hex = `0x${string}`;
10
+
11
+ // X402 Protocol Version
12
+ export const X402_VERSION = 2 as const;
13
+ export type X402Version = typeof X402_VERSION;
14
+
15
+ // Supported schemes
16
+ export const SCHEMES = ["exact"] as const;
17
+ export type Scheme = (typeof SCHEMES)[number];
18
+
19
+ // Supported networks (CAIP-2 format)
20
+ export type Network =
21
+ | "base"
22
+ | "base-sepolia"
23
+ | "ethereum"
24
+ | "ethereum-sepolia"
25
+ | "polygon"
26
+ | "polygon-amoy"
27
+ | "arbitrum"
28
+ | "arbitrum-sepolia"
29
+ | "optimism"
30
+ | "optimism-sepolia"
31
+ | string; // For custom networks
32
+
33
+ /**
34
+ * EIP-3009 TransferWithAuthorization authorization data
35
+ */
36
+ export interface ExactEvmAuthorization {
37
+ from: Address;
38
+ to: Address;
39
+ value: string; // Atomic units (e.g., "1500000" for 1.5 USDC)
40
+ validAfter: string; // Unix timestamp as string
41
+ validBefore: string; // Unix timestamp as string (expiry)
42
+ nonce: Hex; // 32-byte hex string (bytes32)
43
+ }
44
+
45
+ /**
46
+ * Exact EVM payment payload structure
47
+ */
48
+ export interface ExactEvmPayload {
49
+ signature: Hex; // Full hex signature (0x + r + s + v)
50
+ authorization: ExactEvmAuthorization;
51
+ }
52
+
53
+ /**
54
+ * Resource information for payment payload
55
+ */
56
+ export interface ResourceInfo {
57
+ url: string;
58
+ description?: string;
59
+ mimeType?: string;
60
+ }
61
+
62
+ /**
63
+ * Payment payload - Coinbase compatible format (x402 v2)
64
+ * Uses 'accepted' field to echo server's requirements
65
+ */
66
+ export interface PaymentPayload {
67
+ x402Version: X402Version;
68
+ accepted: PaymentRequirements;
69
+ payload: ExactEvmPayload;
70
+ resource?: ResourceInfo;
71
+ extensions?: Record<string, unknown>;
72
+ }
73
+
74
+ /**
75
+ * Unsigned payment payload (before signing)
76
+ */
77
+ export interface UnsignedPaymentPayload {
78
+ x402Version: X402Version;
79
+ accepted: PaymentRequirements;
80
+ payload: Omit<ExactEvmPayload, "signature"> & { signature: undefined };
81
+ resource?: ResourceInfo;
82
+ extensions?: Record<string, unknown>;
83
+ }
84
+
85
+ /**
86
+ * Payment requirements for 402 response
87
+ * Matches x402 SDK format
88
+ */
89
+ export interface PaymentRequirements {
90
+ scheme: Scheme;
91
+ network: Network;
92
+ amount: string; // Atomic units (x402 V2 spec)
93
+ payTo: Address;
94
+ maxTimeoutSeconds: number;
95
+ asset: Address; // Token contract address
96
+ name?: string; // EIP-712 domain parameter
97
+ version?: string; // EIP-712 domain parameter
98
+ extra?: Record<string, unknown>; // Additional extensions
99
+ }
100
+
101
+ /**
102
+ * Settlement response
103
+ */
104
+ export interface SettlementResponse {
105
+ success: boolean;
106
+ errorReason?: string;
107
+ payer?: Address;
108
+ transaction: string; // Transaction hash
109
+ network: Network;
110
+ }
111
+
112
+ /**
113
+ * Verify response
114
+ */
115
+ export interface VerifyResponse {
116
+ isValid: boolean;
117
+ invalidReason?: string;
118
+ payer?: Address;
119
+ }
120
+
121
+ /**
122
+ * X402 response structure for 402 errors
123
+ */
124
+ export interface X402Response {
125
+ x402Version: X402Version;
126
+ error?: string;
127
+ accepts?: PaymentRequirements[];
128
+ payer?: Address;
129
+ }
130
+
131
+ /**
132
+ * Type guards
133
+ */
134
+ export function isPaymentPayload(obj: unknown): obj is PaymentPayload {
135
+ return (
136
+ typeof obj === "object" &&
137
+ obj !== null &&
138
+ "x402Version" in obj &&
139
+ "accepted" in obj &&
140
+ "payload" in obj
141
+ );
142
+ }
143
+
144
+ export function isExactEvmPayload(obj: unknown): obj is ExactEvmPayload {
145
+ return (
146
+ typeof obj === "object" &&
147
+ obj !== null &&
148
+ "signature" in obj &&
149
+ "authorization" in obj
150
+ );
151
+ }
@@ -0,0 +1,48 @@
1
+ const textEncoder = new TextEncoder();
2
+ const textDecoder = new TextDecoder();
3
+
4
+ function toBase64(bytes: Uint8Array): string {
5
+ if (typeof btoa === "function") {
6
+ let binary = "";
7
+ for (let index = 0; index < bytes.length; index += 1) {
8
+ binary += String.fromCharCode(bytes[index]);
9
+ }
10
+ return btoa(binary);
11
+ }
12
+
13
+ throw new Error("No base64 encoder available in this runtime");
14
+ }
15
+
16
+ function fromBase64(base64: string): Uint8Array {
17
+ if (typeof atob === "function") {
18
+ const binary = atob(base64);
19
+ const bytes = new Uint8Array(binary.length);
20
+ for (let index = 0; index < binary.length; index += 1) {
21
+ bytes[index] = binary.charCodeAt(index);
22
+ }
23
+ return bytes;
24
+ }
25
+
26
+ throw new Error("No base64 decoder available in this runtime");
27
+ }
28
+
29
+ export function encodeUtf8ToBase64(value: string): string {
30
+ const bytes = textEncoder.encode(value);
31
+ return toBase64(bytes);
32
+ }
33
+
34
+ export function decodeBase64ToUtf8(value: string): string {
35
+ const bytes = fromBase64(value);
36
+ return textDecoder.decode(bytes);
37
+ }
38
+
39
+ export function toBase64Url(base64: string): string {
40
+ return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
41
+ }
42
+
43
+ export function normalizeBase64Url(value: string): string {
44
+ return value
45
+ .replace(/-/g, "+")
46
+ .replace(/_/g, "/")
47
+ .padEnd(Math.ceil(value.length / 4) * 4, "=");
48
+ }