@armory-sh/client-web3 0.2.5 → 0.2.9

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.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Web3BaseWalletAccount, Web3BaseWallet } from 'web3-types';
2
- import { PaymentPayloadV1, PaymentPayloadV2, CustomToken, NetworkConfig, PaymentRequirementsV1, PaymentRequirementsV2, SettlementResponseV1, SettlementResponseV2 } from '@armory-sh/base';
3
- export { EIP712_TYPES as CORE_EIP712_TYPES, USDC_DOMAIN as CORE_USDC_DOMAIN, NETWORKS, NetworkConfig, PaymentPayload, PaymentPayloadV1, PaymentPayloadV2, PaymentRequirements, PaymentRequirementsV1, PaymentRequirementsV2, SettlementResponse, SettlementResponseV1, SettlementResponseV2, V1_HEADERS, V2_HEADERS, createEIP712Domain as createCoreEIP712Domain, createTransferWithAuthorization as createCoreTransferWithAuthorization, decodePaymentV1, decodePaymentV2, decodeSettlementV1, decodeSettlementV2, encodePaymentV1, encodePaymentV2, encodeSettlementV1, encodeSettlementV2, getMainnets, getNetworkByChainId, getNetworkConfig, getPaymentHeaderName, getPaymentRequiredHeaderName, getPaymentResponseHeaderName, getPaymentVersion, getRequirementsVersion, getSettlementVersion, getTestnets, getTxHash, isAddress, isCAIP2ChainId, isCAIPAssetId, isSettlementSuccessful, isV1, isV2, validateTransferWithAuthorization as validateCoreTransferWithAuthorization } from '@armory-sh/base';
2
+ import { PaymentPayloadV1, PaymentPayloadV2, CustomToken, NetworkConfig, PaymentRequirementsV1, PaymentRequirementsV2, SettlementResponseV1, SettlementResponseV2, X402PaymentRequiredV1, PaymentRequiredV2, X402PaymentPayloadV1 } from '@armory-sh/base';
3
+ export { EIP712_TYPES as CORE_EIP712_TYPES, USDC_DOMAIN as CORE_USDC_DOMAIN, NETWORKS, NetworkConfig, PaymentPayload, PaymentPayloadV1, PaymentPayloadV2, PaymentRequirements, PaymentRequirementsV1, PaymentRequirementsV2, SettlementResponse, SettlementResponseV1, SettlementResponseV2, V1_HEADERS, V2_HEADERS, combineSignatureV2, createEIP712Domain as createCoreEIP712Domain, createTransferWithAuthorization as createCoreTransferWithAuthorization, createNonce, decodePaymentV1, decodePaymentV2, decodeSettlementV1, decodeSettlementV2, encodePaymentV1, encodePaymentV2, encodeSettlementV1, encodeSettlementV2, getMainnets, getNetworkByChainId, getNetworkConfig, getPaymentHeaderName, getPaymentRequiredHeaderName, getPaymentResponseHeaderName, getPaymentVersion, getRequirementsVersion, getSettlementVersion, getTestnets, getTxHash, isSettlementSuccessful, isV1, isV2, isX402V1Payload, isX402V1Requirements, isX402V1Settlement, isX402V2Payload, isX402V2Requirements, isX402V2Settlement, parseSignatureV2, validateTransferWithAuthorization as validateCoreTransferWithAuthorization } from '@armory-sh/base';
4
4
 
5
5
  type Web3Account = Web3BaseWalletAccount | Web3BaseWallet<Web3BaseWalletAccount>;
6
6
  /** Token configuration - can use pre-configured tokens from @armory-sh/tokens */
@@ -82,9 +82,103 @@ declare const isV2Settlement: (response: SettlementResponseV1 | SettlementRespon
82
82
 
83
83
  declare const createX402Client: (config: Web3ClientConfig) => Web3X402Client;
84
84
 
85
+ /**
86
+ * Create an x402 transport layer for handling payment-required responses
87
+ */
85
88
  declare const createX402Transport: (options: X402TransportOptions) => X402Transport;
89
+ /**
90
+ * Create a fetch function bound to an x402 transport
91
+ */
86
92
  declare const createFetchWithX402: (transport: X402Transport) => (url: string | Request, init?: RequestInit) => Promise<Response>;
87
93
 
94
+ /**
95
+ * X402 Protocol Detection and Parsing Functions
96
+ *
97
+ * Handles both x402 V1 and V2 protocol detection and parsing from HTTP responses.
98
+ */
99
+
100
+ type X402Version = 1 | 2;
101
+ interface ParsedPaymentRequired {
102
+ version: X402Version;
103
+ requirements: PaymentRequirementsV1[] | PaymentRequirementsV2[];
104
+ raw: X402PaymentRequiredV1 | PaymentRequiredV2;
105
+ }
106
+ /**
107
+ * Detect x402 protocol version from response headers
108
+ * Returns V2 if PAYMENT-REQUIRED header exists, V1 for X-PAYMENT-REQUIRED
109
+ * Falls back to body detection if no headers present
110
+ */
111
+ declare const detectX402Version: (response: Response, fallbackVersion?: X402Version) => X402Version;
112
+ /**
113
+ * Detect version from a parsed payment required object
114
+ */
115
+ declare const detectVersionFromObject: (obj: unknown) => X402Version | null;
116
+ /**
117
+ * Parse PAYMENT-REQUIRED header or response body
118
+ * Handles both V1 (base64 encoded) and V2 (JSON) formats
119
+ */
120
+ declare const parsePaymentRequired: (response: Response, version?: X402Version) => Promise<ParsedPaymentRequired>;
121
+ /**
122
+ * Parse payment required from header value
123
+ */
124
+ declare const parsePaymentRequiredFromHeader: (header: string, version: X402Version) => ParsedPaymentRequired;
125
+ /**
126
+ * Parse payment required from response body
127
+ */
128
+ declare const parsePaymentRequiredFromBody: (body: string, version: X402Version) => ParsedPaymentRequired;
129
+ /**
130
+ * Create x402 V1 payment payload
131
+ */
132
+ declare const createX402V1Payment: (params: {
133
+ from: string;
134
+ to: string;
135
+ value: string;
136
+ nonce: `0x${string}`;
137
+ validAfter: string;
138
+ validBefore: string;
139
+ signature: `0x${string}`;
140
+ network: string;
141
+ }) => X402PaymentPayloadV1;
142
+ /**
143
+ * Create x402 V2 payment payload
144
+ */
145
+ declare const createX402V2Payment: (params: {
146
+ from: string;
147
+ to: string;
148
+ value: string;
149
+ nonce: `0x${string}`;
150
+ validAfter: string;
151
+ validBefore: string;
152
+ signature: `0x${string}`;
153
+ accepted: PaymentRequirementsV2;
154
+ resource?: {
155
+ url: string;
156
+ description?: string;
157
+ mimeType?: string;
158
+ };
159
+ }) => PaymentPayloadV2;
160
+ /**
161
+ * Create payment header for request
162
+ */
163
+ declare const createPaymentHeader: (payload: X402PaymentPayloadV1 | PaymentPayloadV2, version: X402Version) => string;
164
+ /**
165
+ * Get the payment header name for a version
166
+ */
167
+ declare const getPaymentHeader: (version: X402Version) => string;
168
+ /**
169
+ * Get the payment required header name for a version
170
+ */
171
+ declare const getPaymentRequiredHeader: (version: X402Version) => string;
172
+ /**
173
+ * Check if response indicates payment is required
174
+ */
175
+ declare const isPaymentRequiredResponse: (response: Response) => boolean;
176
+ /**
177
+ * Extract requirements for a specific scheme from accepts array
178
+ * Uses type assertion to handle union types
179
+ */
180
+ declare const selectSchemeRequirements: (requirements: PaymentRequirementsV1[] | PaymentRequirementsV2[], scheme?: string) => PaymentRequirementsV1 | PaymentRequirementsV2 | undefined;
181
+
88
182
  declare const EIP712_TYPES: {
89
183
  readonly EIP712Domain: readonly [{
90
184
  readonly name: "name";
@@ -144,4 +238,4 @@ declare const signWithPrivateKey: (_privateKey: string, _domain: Web3EIP712Domai
144
238
  s: string;
145
239
  }>;
146
240
 
147
- export { EIP712_TYPES, type PaymentSignOptions, type PaymentSignatureResult, type Token, USDC_DOMAIN, type Web3Account, type Web3ClientConfig, type Web3EIP712Domain, type Web3TransferWithAuthorization, type Web3X402Client, type X402RequestContext, type X402Transport, type X402TransportOptions, adjustVForChainId, concatenateSignature, createEIP712Domain, createFetchWithX402, createTransferWithAuthorization, createX402Client, createX402Transport, isV1Requirements, isV1Settlement, isV2Requirements, isV2Settlement, parseSignature, signTypedData, signWithPrivateKey, validateTransferWithAuthorization };
241
+ export { EIP712_TYPES, type ParsedPaymentRequired, type PaymentSignOptions, type PaymentSignatureResult, type Token, USDC_DOMAIN, type Web3Account, type Web3ClientConfig, type Web3EIP712Domain, type Web3TransferWithAuthorization, type Web3X402Client, type X402RequestContext, type X402Transport, type X402TransportOptions, type X402Version, adjustVForChainId, concatenateSignature, createEIP712Domain, createFetchWithX402, createPaymentHeader, createTransferWithAuthorization, createX402Client, createX402Transport, createX402V1Payment, createX402V2Payment, detectVersionFromObject, detectX402Version, getPaymentHeader, getPaymentRequiredHeader, isPaymentRequiredResponse, isV1Requirements, isV1Settlement, isV2Requirements, isV2Settlement, parsePaymentRequired, parsePaymentRequiredFromBody, parsePaymentRequiredFromHeader, parseSignature, selectSchemeRequirements, signTypedData, signWithPrivateKey, validateTransferWithAuthorization };
package/dist/index.js CHANGED
@@ -3,7 +3,10 @@ import { Web3 } from "web3";
3
3
  import {
4
4
  getNetworkConfig,
5
5
  encodePaymentV1,
6
- encodePaymentV2
6
+ encodePaymentV2,
7
+ isX402V1Requirements,
8
+ isX402V2Requirements,
9
+ combineSignatureV2
7
10
  } from "@armory-sh/base";
8
11
 
9
12
  // src/eip3009.ts
@@ -118,6 +121,150 @@ var signWithPrivateKey = async (_privateKey, _domain, _message) => {
118
121
  );
119
122
  };
120
123
 
124
+ // src/protocol.ts
125
+ import {
126
+ V1_HEADERS,
127
+ V2_HEADERS,
128
+ decodeX402PaymentRequiredV1,
129
+ isX402V1PaymentRequired,
130
+ isX402V2PaymentRequired,
131
+ getPaymentRequiredHeaderName,
132
+ getPaymentHeaderName
133
+ } from "@armory-sh/base";
134
+ var detectX402Version = (response, fallbackVersion = 2) => {
135
+ if (response.headers.has(V2_HEADERS.PAYMENT_REQUIRED)) {
136
+ return 2;
137
+ }
138
+ if (response.headers.has(V1_HEADERS.PAYMENT_REQUIRED)) {
139
+ return 1;
140
+ }
141
+ if (response.headers.has("Payment-Required")) {
142
+ return 2;
143
+ }
144
+ return fallbackVersion;
145
+ };
146
+ var detectVersionFromObject = (obj) => {
147
+ if (isX402V2PaymentRequired(obj)) return 2;
148
+ if (isX402V1PaymentRequired(obj)) return 1;
149
+ return null;
150
+ };
151
+ var parsePaymentRequired = async (response, version) => {
152
+ const detectedVersion = version ?? detectX402Version(response);
153
+ const headerName = getPaymentRequiredHeaderName(detectedVersion);
154
+ const header = response.headers.get(headerName);
155
+ if (header) {
156
+ return parsePaymentRequiredFromHeader(header, detectedVersion);
157
+ }
158
+ const body = await response.clone().text();
159
+ return parsePaymentRequiredFromBody(body, detectedVersion);
160
+ };
161
+ var parsePaymentRequiredFromHeader = (header, version) => {
162
+ if (version === 1) {
163
+ const decoded = decodeX402PaymentRequiredV1(header);
164
+ return {
165
+ version: 1,
166
+ requirements: decoded.accepts,
167
+ raw: decoded
168
+ };
169
+ }
170
+ let parsed;
171
+ try {
172
+ parsed = JSON.parse(header);
173
+ } catch {
174
+ const decoded = Buffer.from(header, "base64").toString("utf-8");
175
+ parsed = JSON.parse(decoded);
176
+ }
177
+ return {
178
+ version: 2,
179
+ requirements: parsed.accepts,
180
+ raw: parsed
181
+ };
182
+ };
183
+ var parsePaymentRequiredFromBody = (body, version) => {
184
+ let parsed;
185
+ try {
186
+ parsed = JSON.parse(body);
187
+ } catch {
188
+ const decoded = Buffer.from(body, "base64").toString("utf-8");
189
+ parsed = JSON.parse(decoded);
190
+ }
191
+ const detectedVersion = detectVersionFromObject(parsed) ?? version;
192
+ if (detectedVersion === 1 && isX402V1PaymentRequired(parsed)) {
193
+ return {
194
+ version: 1,
195
+ requirements: parsed.accepts,
196
+ raw: parsed
197
+ };
198
+ }
199
+ if (detectedVersion === 2 && isX402V2PaymentRequired(parsed)) {
200
+ const v2Parsed = parsed;
201
+ return {
202
+ version: 2,
203
+ requirements: v2Parsed.accepts,
204
+ raw: v2Parsed
205
+ };
206
+ }
207
+ throw new Error("Unable to parse payment required response");
208
+ };
209
+ var createX402V1Payment = (params) => {
210
+ const authorization = {
211
+ from: params.from,
212
+ to: params.to,
213
+ value: params.value,
214
+ validAfter: params.validAfter,
215
+ validBefore: params.validBefore,
216
+ nonce: params.nonce
217
+ };
218
+ return {
219
+ x402Version: 1,
220
+ scheme: "exact",
221
+ network: params.network,
222
+ payload: {
223
+ signature: params.signature,
224
+ authorization
225
+ }
226
+ };
227
+ };
228
+ var createX402V2Payment = (params) => {
229
+ const authorization = {
230
+ from: params.from,
231
+ to: params.to,
232
+ value: params.value,
233
+ validAfter: params.validAfter,
234
+ validBefore: params.validBefore,
235
+ nonce: params.nonce
236
+ };
237
+ return {
238
+ x402Version: 2,
239
+ resource: params.resource,
240
+ accepted: params.accepted,
241
+ payload: {
242
+ signature: params.signature,
243
+ authorization
244
+ }
245
+ };
246
+ };
247
+ var createPaymentHeader = (payload, version) => {
248
+ const headerName = getPaymentHeaderName(version);
249
+ const encoded = Buffer.from(JSON.stringify(payload)).toString("base64");
250
+ return encoded;
251
+ };
252
+ var getPaymentHeader = (version) => {
253
+ return getPaymentHeaderName(version);
254
+ };
255
+ var getPaymentRequiredHeader = (version) => {
256
+ return getPaymentRequiredHeaderName(version);
257
+ };
258
+ var isPaymentRequiredResponse = (response) => {
259
+ if (response.status === 402) return true;
260
+ return response.headers.has(V1_HEADERS.PAYMENT_REQUIRED) || response.headers.has(V2_HEADERS.PAYMENT_REQUIRED) || response.headers.has("Payment-Required");
261
+ };
262
+ var selectSchemeRequirements = (requirements, scheme = "exact") => {
263
+ return requirements.find(
264
+ (r) => "scheme" in r && r.scheme === scheme
265
+ );
266
+ };
267
+
121
268
  // src/client.ts
122
269
  var DEFAULT_EXPIRY_SECONDS = 3600;
123
270
  var DEFAULT_VALID_AFTER = 0;
@@ -167,7 +314,7 @@ var signTypedDataWrapper = async (account, domain, message) => {
167
314
  const sig = await acc.signTypedData(domain, message);
168
315
  return parseSignature2(sig);
169
316
  }
170
- const getAddress2 = () => {
317
+ const getAddressLocal = () => {
171
318
  if ("address" in account) return account.address;
172
319
  if (Array.isArray(account) && account[0]) return account[0].address;
173
320
  throw new Error("Unable to get address from account");
@@ -175,7 +322,7 @@ var signTypedDataWrapper = async (account, domain, message) => {
175
322
  if (typeof acc.request === "function") {
176
323
  const sig = await acc.request({
177
324
  method: "eth_signTypedData_v4",
178
- params: [getAddress2(), JSON.stringify({ domain, message })]
325
+ params: [getAddressLocal(), JSON.stringify({ domain, message })]
179
326
  });
180
327
  return parseSignature2(sig);
181
328
  }
@@ -197,7 +344,7 @@ var signPaymentV1 = async (state, params) => {
197
344
  nonce: `0x${nonce}`
198
345
  });
199
346
  const signature = await signTypedDataWrapper(state.account, domain, message);
200
- const payload = {
347
+ const legacyPayload = {
201
348
  from,
202
349
  to,
203
350
  amount,
@@ -210,10 +357,10 @@ var signPaymentV1 = async (state, params) => {
210
357
  contractAddress: network.usdcAddress,
211
358
  network: network.name.toLowerCase().replace(" ", "-")
212
359
  };
213
- return { v: signature.v, r: signature.r, s: signature.s, payload };
360
+ return { v: signature.v, r: signature.r, s: signature.s, payload: legacyPayload };
214
361
  };
215
362
  var signPaymentV2 = async (state, params) => {
216
- const { from, to, amount, nonce, expiry } = params;
363
+ const { from, to, amount, nonce, expiry, accepted } = params;
217
364
  const { network, domainName, domainVersion } = state;
218
365
  const domain = createEIP712Domain(network.chainId, network.usdcAddress, domainName, domainVersion);
219
366
  const message = createTransferWithAuthorization({
@@ -225,21 +372,33 @@ var signPaymentV2 = async (state, params) => {
225
372
  nonce: `0x${nonce}`
226
373
  });
227
374
  const signature = await signTypedDataWrapper(state.account, domain, message);
228
- const payload = {
375
+ const combinedSig = combineSignatureV2(signature.v, signature.r, signature.s);
376
+ const defaultAccepted = accepted ?? {
377
+ scheme: "exact",
378
+ network: network.caip2Id,
379
+ amount,
380
+ asset: network.usdcAddress,
381
+ payTo: to,
382
+ maxTimeoutSeconds: expiry - Math.floor(Date.now() / 1e3)
383
+ };
384
+ const x402Payload = createX402V2Payment({
229
385
  from,
230
386
  to,
231
- amount,
232
- nonce,
233
- expiry,
387
+ value: amount,
388
+ nonce: `0x${nonce.padStart(64, "0")}`,
389
+ validAfter: "0x0",
390
+ validBefore: `0x${expiry.toString(16)}`,
391
+ signature: combinedSig,
392
+ accepted: defaultAccepted
393
+ });
394
+ return {
234
395
  signature: {
235
396
  v: signature.v,
236
397
  r: signature.r,
237
398
  s: signature.s
238
399
  },
239
- chainId: network.caip2Id,
240
- assetId: network.caipAssetId
400
+ payload: x402Payload
241
401
  };
242
- return { signature: payload.signature, payload };
243
402
  };
244
403
  var createX402Client = (config) => {
245
404
  const state = createClientState(config);
@@ -276,28 +435,55 @@ var createX402Client = (config) => {
276
435
  return headers;
277
436
  },
278
437
  handlePaymentRequired: async (requirements) => {
279
- if ("contractAddress" in requirements) {
438
+ const version = detectVersionFromRequirements(requirements);
439
+ if (version === 1) {
280
440
  const req2 = requirements;
441
+ if (isX402V1Requirements(req2)) {
442
+ const x402Req = req2;
443
+ return signPayment({
444
+ amount: x402Req.maxAmountRequired,
445
+ to: x402Req.payTo
446
+ }, state);
447
+ }
448
+ const legacyReq = req2;
281
449
  return signPayment({
282
- amount: req2.amount,
283
- to: req2.payTo,
284
- expiry: req2.expiry
450
+ amount: legacyReq.amount,
451
+ to: legacyReq.payTo,
452
+ expiry: legacyReq.expiry
285
453
  }, state);
286
454
  }
287
455
  const req = requirements;
288
- const to = typeof req.to === "string" ? req.to : "0x0000000000000000000000000000000000000000";
289
- return signPayment({
290
- amount: req.amount,
456
+ const to = typeof req.payTo === "string" ? req.payTo : "0x0000000000000000000000000000000000000000";
457
+ const from = getAddress(state.account);
458
+ return signPaymentV2(state, {
459
+ from,
291
460
  to,
292
- nonce: req.nonce,
293
- expiry: req.expiry
294
- }, state);
461
+ amount: req.amount,
462
+ nonce: crypto.randomUUID(),
463
+ expiry: Math.floor(Date.now() / 1e3) + DEFAULT_EXPIRY_SECONDS,
464
+ accepted: req
465
+ });
295
466
  },
296
467
  verifySettlement: (response) => {
297
- return "success" in response ? response.success : response.status === "success";
468
+ if ("success" in response) {
469
+ return response.success;
470
+ }
471
+ return false;
298
472
  }
299
473
  };
300
474
  };
475
+ var detectVersionFromRequirements = (requirements) => {
476
+ if (isX402V2Requirements(requirements)) {
477
+ return 2;
478
+ }
479
+ if (isX402V1Requirements(requirements)) {
480
+ return 1;
481
+ }
482
+ if ("contractAddress" in requirements) {
483
+ return 1;
484
+ }
485
+ return 2;
486
+ };
301
487
  var signPayment = async (options, state) => {
302
488
  const from = getAddress(state.account);
303
489
  if (state.version === 1) {
@@ -320,50 +506,47 @@ var signPayment = async (options, state) => {
320
506
  };
321
507
 
322
508
  // src/transport.ts
323
- import { V1_HEADERS, V2_HEADERS, encodePaymentV1 as encodePaymentV12, encodePaymentV2 as encodePaymentV22 } from "@armory-sh/base";
509
+ import {
510
+ V1_HEADERS as V1_HEADERS2,
511
+ V2_HEADERS as V2_HEADERS2,
512
+ encodePaymentV1 as encodePaymentV12,
513
+ encodePaymentV2 as encodePaymentV22,
514
+ isX402V1Requirements as isX402V1Requirements2,
515
+ isX402V2Requirements as isX402V2Requirements2
516
+ } from "@armory-sh/base";
324
517
  var DEFAULT_MAX_RETRIES = 3;
325
- var detectProtocolVersion = (response, client) => {
326
- if (response.headers.has(V2_HEADERS.PAYMENT_REQUIRED) || response.headers.has("PAYMENT-REQUIRED")) {
327
- return 2;
328
- }
329
- if (response.headers.has("X-PAYMENT-REQUIRED")) {
330
- return 1;
331
- }
332
- return client.getVersion();
333
- };
334
- var parsePaymentRequirements = async (response, version) => {
335
- if (version === 2) {
336
- const header = response.headers.get(V2_HEADERS.PAYMENT_REQUIRED);
337
- if (header) return JSON.parse(header);
338
- } else {
339
- const header = response.headers.get("X-PAYMENT-REQUIRED");
340
- if (header) {
341
- const json = Buffer.from(header, "base64").toString("utf-8");
342
- return JSON.parse(json);
343
- }
344
- }
345
- return JSON.parse(await response.clone().text());
346
- };
347
518
  var createPaymentHeaders = (payload, version) => {
348
519
  const headers = new Headers();
349
520
  if (version === 1) {
350
- headers.set(V1_HEADERS.PAYMENT, encodePaymentV12(payload));
521
+ headers.set(V1_HEADERS2.PAYMENT, encodePaymentV12(payload));
351
522
  } else {
352
- headers.set(V2_HEADERS.PAYMENT_SIGNATURE, encodePaymentV22(payload));
523
+ headers.set(V2_HEADERS2.PAYMENT_SIGNATURE, encodePaymentV22(payload));
353
524
  }
354
525
  return headers;
355
526
  };
356
- var isPaymentRelatedError = (error) => error.message.includes("402") || error.message.includes("payment") || error.message.includes("signature");
527
+ var isPaymentRelatedError = (error) => error.message.includes("402") || error.message.includes("payment") || error.message.includes("signature") || error.message.includes("Payment");
357
528
  var backoff = (attempt) => {
358
- const delay = Math.min(1e3 * Math.pow(2, attempt - 1), 1e4);
359
- return new Promise((resolve) => setTimeout(resolve, delay));
529
+ const baseDelay = Math.min(1e3 * Math.pow(2, attempt - 1), 1e4);
530
+ const jitter = Math.random() * 100;
531
+ return new Promise((resolve) => setTimeout(resolve, baseDelay + jitter));
360
532
  };
361
533
  var handlePaymentRequired = async (response, client) => {
362
- const version = detectProtocolVersion(response, client);
363
- const requirements = await parsePaymentRequirements(response, version);
364
- const result = await client.handlePaymentRequired(
365
- requirements
366
- );
534
+ const version = detectX402Version(response, client.getVersion());
535
+ const parsed = await parsePaymentRequired(response, version);
536
+ const selectedRequirements = selectSchemeRequirements(parsed.requirements, "exact");
537
+ if (!selectedRequirements) {
538
+ throw new Error("No supported payment scheme found in requirements");
539
+ }
540
+ let result;
541
+ if (version === 1 && isX402V1Requirements2(selectedRequirements)) {
542
+ const req = selectedRequirements;
543
+ result = await client.handlePaymentRequired(req);
544
+ } else if (version === 2 && isX402V2Requirements2(selectedRequirements)) {
545
+ const req = selectedRequirements;
546
+ result = await client.handlePaymentRequired(req);
547
+ } else {
548
+ result = await client.handlePaymentRequired(selectedRequirements);
549
+ }
367
550
  return createPaymentHeaders(result.payload, version);
368
551
  };
369
552
  var mergePaymentHeaders = (init = {}, paymentHeaders) => {
@@ -386,7 +569,7 @@ var createX402Transport = (options) => {
386
569
  attempt++;
387
570
  try {
388
571
  const response = await fetch(url, init);
389
- if (response.status === 402 && autoSign) {
572
+ if (isPaymentRequiredResponse(response) && autoSign) {
390
573
  const paymentHeaders = await handlePaymentRequired(response, client);
391
574
  const newInit = mergePaymentHeaders(init, paymentHeaders);
392
575
  return await fetch(url, newInit);
@@ -416,15 +599,12 @@ var isV2Settlement = (response) => "status" in response;
416
599
 
417
600
  // src/index.ts
418
601
  import {
419
- V1_HEADERS as V1_HEADERS2,
602
+ V1_HEADERS as V1_HEADERS3,
603
+ V2_HEADERS as V2_HEADERS3,
420
604
  encodePaymentV1 as encodePaymentV13,
421
605
  decodePaymentV1,
422
606
  encodeSettlementV1,
423
607
  decodeSettlementV1,
424
- V2_HEADERS as V2_HEADERS2,
425
- isCAIP2ChainId,
426
- isCAIPAssetId,
427
- isAddress,
428
608
  encodePaymentV2 as encodePaymentV23,
429
609
  decodePaymentV2,
430
610
  encodeSettlementV2,
@@ -434,9 +614,9 @@ import {
434
614
  getPaymentVersion,
435
615
  getRequirementsVersion,
436
616
  getSettlementVersion,
437
- getPaymentHeaderName,
617
+ getPaymentHeaderName as getPaymentHeaderName2,
438
618
  getPaymentResponseHeaderName,
439
- getPaymentRequiredHeaderName,
619
+ getPaymentRequiredHeaderName as getPaymentRequiredHeaderName2,
440
620
  isSettlementSuccessful,
441
621
  getTxHash,
442
622
  NETWORKS,
@@ -444,6 +624,15 @@ import {
444
624
  getNetworkByChainId,
445
625
  getMainnets,
446
626
  getTestnets,
627
+ isX402V1Payload,
628
+ isX402V2Payload,
629
+ isX402V1Requirements as isX402V1Requirements3,
630
+ isX402V2Requirements as isX402V2Requirements3,
631
+ isX402V1Settlement,
632
+ isX402V2Settlement,
633
+ combineSignatureV2 as combineSignatureV22,
634
+ parseSignatureV2,
635
+ createNonce as createNonce2,
447
636
  EIP712_TYPES as EIP712_TYPES2,
448
637
  USDC_DOMAIN as USDC_DOMAIN2,
449
638
  createEIP712Domain as createEIP712Domain2,
@@ -456,21 +645,28 @@ export {
456
645
  EIP712_TYPES,
457
646
  NETWORKS,
458
647
  USDC_DOMAIN,
459
- V1_HEADERS2 as V1_HEADERS,
460
- V2_HEADERS2 as V2_HEADERS,
648
+ V1_HEADERS3 as V1_HEADERS,
649
+ V2_HEADERS3 as V2_HEADERS,
461
650
  adjustVForChainId,
651
+ combineSignatureV22 as combineSignatureV2,
462
652
  concatenateSignature,
463
653
  createEIP712Domain2 as createCoreEIP712Domain,
464
654
  createTransferWithAuthorization2 as createCoreTransferWithAuthorization,
465
655
  createEIP712Domain,
466
656
  createFetchWithX402,
657
+ createNonce2 as createNonce,
658
+ createPaymentHeader,
467
659
  createTransferWithAuthorization,
468
660
  createX402Client,
469
661
  createX402Transport,
662
+ createX402V1Payment,
663
+ createX402V2Payment,
470
664
  decodePaymentV1,
471
665
  decodePaymentV2,
472
666
  decodeSettlementV1,
473
667
  decodeSettlementV2,
668
+ detectVersionFromObject,
669
+ detectX402Version,
474
670
  encodePaymentV13 as encodePaymentV1,
475
671
  encodePaymentV23 as encodePaymentV2,
476
672
  encodeSettlementV1,
@@ -478,17 +674,17 @@ export {
478
674
  getMainnets,
479
675
  getNetworkByChainId,
480
676
  getNetworkConfig2 as getNetworkConfig,
481
- getPaymentHeaderName,
482
- getPaymentRequiredHeaderName,
677
+ getPaymentHeader,
678
+ getPaymentHeaderName2 as getPaymentHeaderName,
679
+ getPaymentRequiredHeader,
680
+ getPaymentRequiredHeaderName2 as getPaymentRequiredHeaderName,
483
681
  getPaymentResponseHeaderName,
484
682
  getPaymentVersion,
485
683
  getRequirementsVersion,
486
684
  getSettlementVersion,
487
685
  getTestnets,
488
686
  getTxHash,
489
- isAddress,
490
- isCAIP2ChainId,
491
- isCAIPAssetId,
687
+ isPaymentRequiredResponse,
492
688
  isSettlementSuccessful,
493
689
  isV1,
494
690
  isV1Requirements,
@@ -496,7 +692,18 @@ export {
496
692
  isV2,
497
693
  isV2Requirements,
498
694
  isV2Settlement,
695
+ isX402V1Payload,
696
+ isX402V1Requirements3 as isX402V1Requirements,
697
+ isX402V1Settlement,
698
+ isX402V2Payload,
699
+ isX402V2Requirements3 as isX402V2Requirements,
700
+ isX402V2Settlement,
701
+ parsePaymentRequired,
702
+ parsePaymentRequiredFromBody,
703
+ parsePaymentRequiredFromHeader,
499
704
  parseSignature,
705
+ parseSignatureV2,
706
+ selectSchemeRequirements,
500
707
  signTypedData,
501
708
  signWithPrivateKey,
502
709
  validateTransferWithAuthorization2 as validateCoreTransferWithAuthorization,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@armory-sh/client-web3",
3
- "version": "0.2.5",
3
+ "version": "0.2.9",
4
4
  "license": "MIT",
5
5
  "author": "Sawyer Cutler <sawyer@dirtroad.dev>",
6
6
  "type": "module",
@@ -27,7 +27,7 @@
27
27
  "directory": "packages/client-web3"
28
28
  },
29
29
  "dependencies": {
30
- "@armory-sh/base": "^0.2.9",
30
+ "@armory-sh/base": "^0.2.12",
31
31
  "web3": "4.16.0",
32
32
  "web3-types": "1.10.0"
33
33
  },