@x402r/evm 0.0.2 → 0.0.3

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 (89) hide show
  1. package/README.md +20 -16
  2. package/dist/cjs/escrow/client/index.cjs +227 -0
  3. package/dist/cjs/escrow/client/index.cjs.map +1 -0
  4. package/dist/cjs/escrow/client/index.d.cts +23 -0
  5. package/dist/cjs/escrow/client/index.d.ts +23 -0
  6. package/dist/cjs/escrow/client/index.js +223 -0
  7. package/dist/cjs/escrow/client/index.js.map +1 -0
  8. package/dist/cjs/escrow/facilitator/index.cjs +359 -0
  9. package/dist/cjs/escrow/facilitator/index.cjs.map +1 -0
  10. package/dist/cjs/escrow/facilitator/index.d.cts +53 -0
  11. package/dist/{escrow → cjs/escrow}/facilitator/index.d.ts +17 -13
  12. package/dist/cjs/escrow/facilitator/index.js +358 -0
  13. package/dist/cjs/escrow/facilitator/index.js.map +1 -0
  14. package/dist/cjs/escrow/server/index.cjs +222 -0
  15. package/dist/cjs/escrow/server/index.cjs.map +1 -0
  16. package/dist/cjs/escrow/server/index.d.cts +78 -0
  17. package/dist/{escrow → cjs/escrow}/server/index.d.ts +15 -9
  18. package/dist/cjs/escrow/server/index.js +217 -0
  19. package/dist/cjs/escrow/server/index.js.map +1 -0
  20. package/dist/{shared/types.d.ts → cjs/escrow/types/index.d.ts} +7 -6
  21. package/dist/cjs/escrow/types/index.js +40 -0
  22. package/dist/cjs/escrow/types/index.js.map +1 -0
  23. package/dist/cjs/index.cjs +215 -0
  24. package/dist/cjs/index.cjs.map +1 -0
  25. package/dist/cjs/index.d.cts +22 -0
  26. package/dist/cjs/index.d.ts +54 -0
  27. package/dist/cjs/index.js +223 -0
  28. package/dist/cjs/index.js.map +1 -0
  29. package/dist/cjs/scheme-CNrmuyp3.d.ts +22 -0
  30. package/dist/esm/chunk-DLIBGHEY.mjs +85 -0
  31. package/dist/esm/chunk-DLIBGHEY.mjs.map +1 -0
  32. package/dist/esm/chunk-IYUU7AJZ.mjs +187 -0
  33. package/dist/esm/chunk-IYUU7AJZ.mjs.map +1 -0
  34. package/dist/esm/chunk-JBHVAJN3.mjs +13 -0
  35. package/dist/esm/chunk-JBHVAJN3.mjs.map +1 -0
  36. package/dist/esm/chunk-NSSMTXJJ.mjs +8 -0
  37. package/dist/esm/chunk-NSSMTXJJ.mjs.map +1 -0
  38. package/dist/esm/escrow/client/index.d.mts +23 -0
  39. package/dist/esm/escrow/client/index.mjs +20 -0
  40. package/dist/esm/escrow/client/index.mjs.map +1 -0
  41. package/dist/esm/escrow/facilitator/index.d.mts +53 -0
  42. package/dist/esm/escrow/facilitator/index.mjs +230 -0
  43. package/dist/esm/escrow/facilitator/index.mjs.map +1 -0
  44. package/dist/esm/escrow/server/index.d.mts +78 -0
  45. package/dist/esm/escrow/server/index.mjs +191 -0
  46. package/dist/esm/escrow/server/index.mjs.map +1 -0
  47. package/dist/esm/index.d.mts +54 -0
  48. package/dist/esm/index.mjs +15 -0
  49. package/dist/esm/index.mjs.map +1 -0
  50. package/dist/esm/scheme-CNrmuyp3.d.mts +22 -0
  51. package/package.json +42 -16
  52. package/src/escrow/client/index.ts +3 -161
  53. package/src/escrow/client/register.ts +33 -0
  54. package/src/escrow/client/scheme.ts +107 -0
  55. package/src/escrow/facilitator/index.ts +3 -388
  56. package/src/escrow/facilitator/register.ts +33 -0
  57. package/src/escrow/facilitator/scheme.ts +289 -0
  58. package/src/escrow/index.ts +3 -0
  59. package/src/escrow/server/index.ts +3 -261
  60. package/src/escrow/server/register.ts +34 -0
  61. package/src/escrow/server/scheme.ts +226 -0
  62. package/src/escrow/shared/constants.ts +65 -0
  63. package/src/escrow/shared/nonce.ts +175 -0
  64. package/src/escrow/shared/types.ts +69 -0
  65. package/src/escrow/shared/utils.ts +16 -0
  66. package/dist/escrow/client/index.d.ts +0 -40
  67. package/dist/escrow/client/index.d.ts.map +0 -1
  68. package/dist/escrow/client/index.js +0 -104
  69. package/dist/escrow/client/index.js.map +0 -1
  70. package/dist/escrow/facilitator/index.d.ts.map +0 -1
  71. package/dist/escrow/facilitator/index.js +0 -300
  72. package/dist/escrow/facilitator/index.js.map +0 -1
  73. package/dist/escrow/server/index.d.ts.map +0 -1
  74. package/dist/escrow/server/index.js +0 -214
  75. package/dist/escrow/server/index.js.map +0 -1
  76. package/dist/shared/constants.d.ts +0 -112
  77. package/dist/shared/constants.d.ts.map +0 -1
  78. package/dist/shared/constants.js +0 -51
  79. package/dist/shared/constants.js.map +0 -1
  80. package/dist/shared/nonce.d.ts +0 -41
  81. package/dist/shared/nonce.d.ts.map +0 -1
  82. package/dist/shared/nonce.js +0 -154
  83. package/dist/shared/nonce.js.map +0 -1
  84. package/dist/shared/types.d.ts.map +0 -1
  85. package/dist/shared/types.js +0 -21
  86. package/dist/shared/types.js.map +0 -1
  87. package/src/shared/constants.ts +0 -58
  88. package/src/shared/nonce.ts +0 -203
  89. package/src/shared/types.ts +0 -69
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Escrow Scheme - Client
3
+ * Creates payment payloads for escrow payments.
4
+ *
5
+ * Implements x402's SchemeNetworkClient interface so it can be registered
6
+ * on an x402Client via client.register('eip155:84532', new EscrowEvmScheme(signer)).
7
+ */
8
+
9
+ import type {
10
+ PaymentPayloadContext,
11
+ PaymentPayloadResult,
12
+ PaymentRequirements,
13
+ SchemeNetworkClient,
14
+ } from '@x402/core/types'
15
+ import type { ClientEvmSigner } from '@x402/evm'
16
+ import { computeEscrowNonce, signERC3009, generateSalt } from '../shared/nonce'
17
+ import { MAX_UINT48 } from '../shared/constants'
18
+ import type { EscrowExtra } from '../shared/types'
19
+ import { parseChainId } from '../shared/utils'
20
+
21
+ /**
22
+ * Escrow Client Scheme - implements x402's SchemeNetworkClient
23
+ */
24
+ export class EscrowEvmScheme implements SchemeNetworkClient {
25
+ readonly scheme = 'escrow'
26
+
27
+ constructor(private readonly signer: ClientEvmSigner) {}
28
+
29
+ async createPaymentPayload(
30
+ x402Version: number,
31
+ requirements: PaymentRequirements,
32
+ _context?: PaymentPayloadContext,
33
+ ): Promise<PaymentPayloadResult> {
34
+ if (x402Version !== 2) {
35
+ throw new Error(`Unsupported x402Version: ${x402Version}. Only version 2 is supported.`)
36
+ }
37
+
38
+ const extra = requirements.extra as unknown as EscrowExtra
39
+
40
+ // Validate required EIP-712 domain parameters (M3, M10)
41
+ if (!extra.name) {
42
+ throw new Error(
43
+ `EIP-712 domain parameter 'name' is required in payment requirements for asset ${requirements.asset}`,
44
+ )
45
+ }
46
+ if (!extra.version) {
47
+ throw new Error(
48
+ `EIP-712 domain parameter 'version' is required in payment requirements for asset ${requirements.asset}`,
49
+ )
50
+ }
51
+
52
+ const {
53
+ escrowAddress,
54
+ operatorAddress,
55
+ tokenCollector,
56
+ minFeeBps = 0,
57
+ maxFeeBps = 0,
58
+ feeReceiver,
59
+ preApprovalExpirySeconds,
60
+ refundExpirySeconds,
61
+ authorizationExpirySeconds,
62
+ } = extra
63
+
64
+ const chainId = parseChainId(requirements.network)
65
+ const maxAmount = requirements.amount
66
+
67
+ const paymentInfo = {
68
+ operator: operatorAddress,
69
+ receiver: requirements.payTo as `0x${string}`,
70
+ token: requirements.asset as `0x${string}`,
71
+ maxAmount,
72
+ preApprovalExpiry: preApprovalExpirySeconds ?? MAX_UINT48,
73
+ authorizationExpiry: authorizationExpirySeconds ?? MAX_UINT48,
74
+ refundExpiry: refundExpirySeconds ?? MAX_UINT48,
75
+ minFeeBps,
76
+ maxFeeBps,
77
+ feeReceiver: feeReceiver ?? operatorAddress,
78
+ salt: generateSalt(),
79
+ }
80
+
81
+ const nonce = computeEscrowNonce(chainId, escrowAddress, paymentInfo)
82
+
83
+ // ERC-3009 authorization - validBefore MUST match what contract passes to receiveWithAuthorization
84
+ // The contract uses paymentInfo.preApprovalExpiry as validBefore
85
+ const authorization = {
86
+ from: this.signer.address,
87
+ to: tokenCollector,
88
+ value: maxAmount,
89
+ validAfter: '0',
90
+ validBefore: String(paymentInfo.preApprovalExpiry),
91
+ nonce,
92
+ }
93
+
94
+ const signature = await signERC3009(
95
+ this.signer,
96
+ authorization,
97
+ extra,
98
+ requirements.asset as `0x${string}`,
99
+ chainId,
100
+ )
101
+
102
+ return {
103
+ x402Version,
104
+ payload: { authorization, signature, paymentInfo },
105
+ }
106
+ }
107
+ }
@@ -1,388 +1,3 @@
1
- /**
2
- * Escrow Scheme - Facilitator
3
- * Handles verification and settlement of escrow payments.
4
- *
5
- * Implements x402's SchemeNetworkFacilitator interface so the escrow scheme
6
- * is a drop-in for the x402 facilitator, just like ExactEvmScheme.
7
- */
8
-
9
- import type {
10
- Network,
11
- PaymentPayload,
12
- PaymentRequirements,
13
- SchemeNetworkFacilitator,
14
- SettleResponse,
15
- VerifyResponse,
16
- } from "@x402/core/types";
17
- import type { FacilitatorEvmSigner } from "@x402/evm";
18
- import { x402Facilitator } from "@x402/core/facilitator";
19
- import {
20
- OPERATOR_ABI,
21
- ERC20_BALANCE_OF_ABI,
22
- ERC6492_MAGIC_VALUE,
23
- } from "../../shared/constants.js";
24
- import { verifyERC3009Signature } from "../../shared/nonce.js";
25
- import {
26
- isEscrowPayload,
27
- isEscrowExtra,
28
- } from "../../shared/types.js";
29
- import type { EscrowExtra, EscrowPayload } from "../../shared/types.js";
30
-
31
- /**
32
- * Parse chainId from CAIP-2 network identifier
33
- * @param network - CAIP-2 network identifier (e.g., 'eip155:84532')
34
- * @returns The chain ID as a number
35
- */
36
- function parseChainId(network: string): number {
37
- const parts = network.split(":");
38
- if (parts.length !== 2 || parts[0] !== "eip155") {
39
- throw new Error(
40
- `Invalid network format: ${network}. Expected 'eip155:<chainId>'`,
41
- );
42
- }
43
- const chainId = parseInt(parts[1], 10);
44
- if (isNaN(chainId)) {
45
- throw new Error(`Invalid chainId in network: ${network}`);
46
- }
47
- return chainId;
48
- }
49
-
50
- /**
51
- * Extract inner signature from an EIP-6492 wrapped signature.
52
- * If the signature is not EIP-6492 wrapped, returns it unchanged.
53
- *
54
- * EIP-6492 format: abi.encode(address, bytes, bytes) ++ MAGIC_VALUE
55
- * The inner signature is the third ABI-encoded bytes field.
56
- */
57
- function unwrapERC6492Signature(signature: `0x${string}`): `0x${string}` {
58
- // EIP-6492 magic is 32 bytes (64 hex chars) at the end
59
- if (signature.length <= 66) return signature; // Too short to be wrapped
60
-
61
- const magicSuffix = `0x${signature.slice(-64)}`;
62
- if (magicSuffix !== ERC6492_MAGIC_VALUE) return signature; // Not wrapped
63
-
64
- // Strip the magic suffix and ABI-decode: (address prepareTarget, bytes prepareData, bytes innerSignature)
65
- // The wrapped data (without magic) is: 0x + ABI-encoded (address, bytes, bytes)
66
- const wrappedHex = signature.slice(2, -64); // hex without 0x prefix and magic
67
-
68
- // ABI layout for (address, bytes, bytes):
69
- // word 0 (0-64): address (padded to 32 bytes)
70
- // word 1 (64-128): offset to prepareData bytes
71
- // word 2 (128-192): offset to innerSignature bytes
72
- // Then the dynamic data follows
73
-
74
- if (wrappedHex.length < 192) return signature; // Malformed
75
-
76
- const innerSigOffset = parseInt(wrappedHex.slice(128, 192), 16) * 2; // byte offset → hex offset
77
- if (innerSigOffset + 64 > wrappedHex.length) return signature; // Malformed
78
-
79
- const innerSigLength = parseInt(
80
- wrappedHex.slice(innerSigOffset, innerSigOffset + 64),
81
- 16,
82
- ) * 2; // bytes → hex chars
83
- const innerSigStart = innerSigOffset + 64;
84
-
85
- if (innerSigStart + innerSigLength > wrappedHex.length) return signature; // Malformed
86
-
87
- return `0x${wrappedHex.slice(innerSigStart, innerSigStart + innerSigLength)}` as `0x${string}`;
88
- }
89
-
90
- /**
91
- * Escrow Facilitator Scheme - implements x402's SchemeNetworkFacilitator
92
- *
93
- * The facilitator is operator-agnostic: it does not store operator/escrow/tokenCollector
94
- * config. Those values are set by the merchant via `refundable()` and arrive in
95
- * `requirements.extra` at verify/settle time.
96
- */
97
- export class EscrowFacilitatorScheme implements SchemeNetworkFacilitator {
98
- readonly scheme = "escrow";
99
- readonly caipFamily = "eip155:*";
100
-
101
- constructor(private signer: FacilitatorEvmSigner) {}
102
-
103
- getSigners(_network: string): string[] {
104
- return [...this.signer.getAddresses()];
105
- }
106
-
107
- // C4: name/version now come from server's parsePrice() via AssetAmount.extra.
108
- // The facilitator should not hardcode token-specific metadata.
109
- getExtra(_network: string): Record<string, unknown> | undefined {
110
- return undefined;
111
- }
112
-
113
- async verify(
114
- payload: PaymentPayload,
115
- requirements: PaymentRequirements,
116
- ): Promise<VerifyResponse> {
117
- // M5: Type guard instead of double cast
118
- if (!isEscrowPayload(payload.payload)) {
119
- return {
120
- isValid: false,
121
- invalidReason: "invalid_payload_format",
122
- };
123
- }
124
- const escrowPayload = payload.payload as EscrowPayload;
125
- const payer = escrowPayload.authorization.from;
126
-
127
- // Validate scheme
128
- if (requirements.scheme !== "escrow") {
129
- return {
130
- isValid: false,
131
- invalidReason: "unsupported_scheme",
132
- payer,
133
- };
134
- }
135
-
136
- // Validate network format
137
- const networkParts = requirements.network.split(":");
138
- if (networkParts.length !== 2 || networkParts[0] !== "eip155") {
139
- return {
140
- isValid: false,
141
- invalidReason: "invalid_network",
142
- payer,
143
- };
144
- }
145
-
146
- // M5: Type guard for extra
147
- if (!isEscrowExtra(requirements.extra)) {
148
- return {
149
- isValid: false,
150
- invalidReason: "invalid_escrow_extra",
151
- payer,
152
- };
153
- }
154
- const extra = requirements.extra as EscrowExtra;
155
- const chainId = parseChainId(requirements.network);
156
-
157
- // Time window validation
158
- const now = Math.floor(Date.now() / 1000);
159
- const validBefore = Number(escrowPayload.authorization.validBefore);
160
- const validAfter = Number(escrowPayload.authorization.validAfter);
161
-
162
- if (validBefore <= now + 6) {
163
- return {
164
- isValid: false,
165
- invalidReason: "authorization_expired",
166
- payer,
167
- };
168
- }
169
-
170
- if (validAfter > now) {
171
- return {
172
- isValid: false,
173
- invalidReason: "authorization_not_yet_valid",
174
- payer,
175
- };
176
- }
177
-
178
- // M4: Extract inner signature for verification if EIP-6492 wrapped.
179
- // The contract's ERC6492SignatureHandler handles deployment; the facilitator
180
- // only needs the inner ECDSA signature for ecrecover verification.
181
- const signatureForVerify = unwrapERC6492Signature(escrowPayload.signature);
182
-
183
- // Verify ERC-3009 signature
184
- const isValidSignature = await verifyERC3009Signature(
185
- this.signer,
186
- escrowPayload.authorization,
187
- signatureForVerify,
188
- { ...extra, chainId },
189
- requirements.asset as `0x${string}`,
190
- );
191
-
192
- if (!isValidSignature) {
193
- return {
194
- isValid: false,
195
- invalidReason: "invalid_escrow_signature",
196
- payer,
197
- };
198
- }
199
-
200
- // Verify amount meets requirements
201
- if (
202
- BigInt(escrowPayload.authorization.value) <
203
- BigInt(requirements.amount)
204
- ) {
205
- return {
206
- isValid: false,
207
- invalidReason: "insufficient_amount",
208
- payer,
209
- };
210
- }
211
-
212
- // Verify token matches
213
- if (
214
- escrowPayload.paymentInfo.token.toLowerCase() !==
215
- requirements.asset.toLowerCase()
216
- ) {
217
- return {
218
- isValid: false,
219
- invalidReason: "token_mismatch",
220
- payer,
221
- };
222
- }
223
-
224
- // Verify receiver matches
225
- if (
226
- escrowPayload.paymentInfo.receiver.toLowerCase() !==
227
- requirements.payTo.toLowerCase()
228
- ) {
229
- return {
230
- isValid: false,
231
- invalidReason: "receiver_mismatch",
232
- payer,
233
- };
234
- }
235
-
236
- // H4: Balance check — verify payer has sufficient token balance
237
- try {
238
- const balance = await this.signer.readContract({
239
- address: requirements.asset as `0x${string}`,
240
- abi: ERC20_BALANCE_OF_ABI,
241
- functionName: "balanceOf",
242
- args: [payer],
243
- });
244
-
245
- if (BigInt(balance as string) < BigInt(requirements.amount)) {
246
- return {
247
- isValid: false,
248
- invalidReason: "insufficient_balance",
249
- payer,
250
- };
251
- }
252
- } catch {
253
- // If balance check fails (e.g., non-standard token), skip it.
254
- // The on-chain transaction will fail anyway if balance is insufficient.
255
- }
256
-
257
- return {
258
- isValid: true,
259
- payer,
260
- };
261
- }
262
-
263
- async settle(
264
- payload: PaymentPayload,
265
- requirements: PaymentRequirements,
266
- ): Promise<SettleResponse> {
267
- // H2: Re-verify before settling to catch expired/invalid payloads
268
- const verification = await this.verify(payload, requirements);
269
- if (!verification.isValid) {
270
- return {
271
- success: false,
272
- errorReason: verification.invalidReason ?? "verification_failed",
273
- transaction: "",
274
- network: requirements.network,
275
- payer: verification.payer,
276
- };
277
- }
278
-
279
- const escrowPayload = payload.payload as unknown as EscrowPayload;
280
- const extra = requirements.extra as unknown as EscrowExtra;
281
- const { authorizeAddress, operatorAddress, tokenCollector } = extra;
282
-
283
- const paymentInfo = {
284
- operator: escrowPayload.paymentInfo.operator,
285
- payer: escrowPayload.authorization.from,
286
- receiver: escrowPayload.paymentInfo.receiver,
287
- token: escrowPayload.paymentInfo.token,
288
- maxAmount: BigInt(escrowPayload.paymentInfo.maxAmount),
289
- preApprovalExpiry: escrowPayload.paymentInfo.preApprovalExpiry,
290
- authorizationExpiry: escrowPayload.paymentInfo.authorizationExpiry,
291
- refundExpiry: escrowPayload.paymentInfo.refundExpiry,
292
- minFeeBps: escrowPayload.paymentInfo.minFeeBps,
293
- maxFeeBps: escrowPayload.paymentInfo.maxFeeBps,
294
- feeReceiver: escrowPayload.paymentInfo.feeReceiver,
295
- salt: BigInt(escrowPayload.paymentInfo.salt),
296
- };
297
-
298
- // Pass raw signature — ERC3009PaymentCollector/ERC6492SignatureHandler
299
- // handles EIP-6492 unwrapping and wallet deployment on-chain
300
- const collectorData = escrowPayload.signature;
301
-
302
- const target = authorizeAddress ?? operatorAddress;
303
-
304
- try {
305
- const txHash = await this.signer.writeContract({
306
- address: target,
307
- abi: OPERATOR_ABI,
308
- functionName: "authorize",
309
- args: [
310
- paymentInfo,
311
- BigInt(escrowPayload.authorization.value),
312
- tokenCollector,
313
- collectorData,
314
- ],
315
- });
316
-
317
- // Wait for transaction confirmation with 60s timeout to avoid hanging on stuck txs
318
- const receiptPromise = this.signer.waitForTransactionReceipt({
319
- hash: txHash,
320
- });
321
- const timeoutPromise = new Promise<never>((_, reject) =>
322
- setTimeout(
323
- () => reject(new Error("Transaction receipt timeout after 60s")),
324
- 60_000,
325
- ),
326
- );
327
- const receipt = await Promise.race([receiptPromise, timeoutPromise]);
328
-
329
- if (receipt.status !== "success") {
330
- return {
331
- success: false,
332
- errorReason: "transaction_reverted",
333
- transaction: txHash,
334
- network: requirements.network,
335
- payer: escrowPayload.authorization.from,
336
- };
337
- }
338
-
339
- return {
340
- success: true,
341
- transaction: txHash,
342
- network: requirements.network,
343
- payer: escrowPayload.authorization.from,
344
- };
345
- } catch (error) {
346
- return {
347
- success: false,
348
- errorReason:
349
- error instanceof Error ? error.message : "Settlement failed",
350
- transaction: "",
351
- network: requirements.network,
352
- payer: escrowPayload.authorization.from,
353
- };
354
- }
355
- }
356
- }
357
-
358
- /**
359
- * Register escrow scheme with x402Facilitator
360
- *
361
- * The facilitator is operator-agnostic — it supports any operator. Operator,
362
- * escrow, and tokenCollector addresses are provided per-request by the merchant
363
- * via `refundable()` and arrive in `requirements.extra`.
364
- *
365
- * @example
366
- * ```typescript
367
- * const facilitator = new x402Facilitator();
368
- * registerEscrowScheme(facilitator, {
369
- * signer: evmSigner,
370
- * networks: "eip155:84532",
371
- * });
372
- * ```
373
- */
374
- export function registerEscrowScheme(
375
- facilitator: x402Facilitator,
376
- config: {
377
- signer: FacilitatorEvmSigner;
378
- networks: Network | Network[];
379
- },
380
- ): x402Facilitator {
381
- facilitator.register(
382
- config.networks,
383
- new EscrowFacilitatorScheme(config.signer),
384
- );
385
- return facilitator;
386
- }
387
-
388
- export type { EscrowExtra, EscrowPayload } from "../../shared/types.js";
1
+ export { EscrowFacilitatorScheme } from './scheme'
2
+ export { registerEscrowEvmScheme } from './register'
3
+ export type { EvmFacilitatorConfig } from './register'
@@ -0,0 +1,33 @@
1
+ import type { Network } from '@x402/core/types'
2
+ import type { FacilitatorEvmSigner } from '@x402/evm'
3
+ import { x402Facilitator } from '@x402/core/facilitator'
4
+ import { EscrowFacilitatorScheme } from './scheme'
5
+
6
+ export interface EvmFacilitatorConfig {
7
+ signer: FacilitatorEvmSigner
8
+ networks: Network | Network[]
9
+ }
10
+
11
+ /**
12
+ * Register escrow scheme with x402Facilitator
13
+ *
14
+ * The facilitator is operator-agnostic — it supports any operator. Operator,
15
+ * escrow, and tokenCollector addresses are provided per-request by the merchant
16
+ * via `refundable()` and arrive in `requirements.extra`.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * const facilitator = new x402Facilitator();
21
+ * registerEscrowEvmScheme(facilitator, {
22
+ * signer: evmSigner,
23
+ * networks: "eip155:84532",
24
+ * });
25
+ * ```
26
+ */
27
+ export function registerEscrowEvmScheme(
28
+ facilitator: x402Facilitator,
29
+ config: EvmFacilitatorConfig,
30
+ ): x402Facilitator {
31
+ facilitator.register(config.networks, new EscrowFacilitatorScheme(config.signer))
32
+ return facilitator
33
+ }