{"version":3,"sources":["../../src/hooks.ts","../../src/server/BatchFacilitatorClient.ts","../../src/server/GatewayEvmScheme.ts","../../src/client/GatewayClient.ts","../../src/client/BatchEvmScheme.ts","../../src/constants.ts","../../src/detection.ts","../../src/server/middleware.ts"],"sourcesContent":["/**\n * Lifecycle hook types for the Circle Gateway batching SDK.\n *\n * These mirror the lifecycle hooks defined in the standard `@x402/core` SDK.\n * See https://docs.x402.org/advanced-concepts/lifecycle-hooks for the full\n * reference. The semantics implemented here match that documentation: hooks\n * receive a read-only context, drive control flow via `abort` / `skip` /\n * `recovered` return values, and a thrown hook is logged but does not break\n * the surrounding payment flow (the next hook still runs).\n */\n\n/**\n * Minimal `PaymentPayload` shape (subset used by hook contexts).\n */\nexport interface HookPaymentPayload {\n  x402Version: number;\n  payload: Record<string, unknown>;\n  resource?: { url: string; description: string; mimeType: string };\n  accepted?: Record<string, unknown>;\n  extensions?: Record<string, unknown>;\n}\n\n/**\n * Minimal `PaymentRequirements` shape (subset used by hook contexts).\n */\nexport interface HookPaymentRequirements {\n  scheme: string;\n  network: string;\n  asset: string;\n  amount: string;\n  payTo: string;\n  maxTimeoutSeconds: number;\n  extra?: Record<string, unknown>;\n}\n\n/**\n * Minimal `VerifyResponse` shape (subset used by hook contexts).\n */\nexport interface HookVerifyResponse {\n  isValid: boolean;\n  invalidReason?: string;\n  payer?: string;\n}\n\n/**\n * Minimal `SettleResponse` shape (subset used by hook contexts).\n */\nexport interface HookSettleResponse {\n  success: boolean;\n  errorReason?: string;\n  payer?: string;\n  transaction: string;\n  network: string;\n}\n\n// ============================================================================\n// Verify / Settle hook contexts (resource server + facilitator)\n// ============================================================================\n\nexport interface VerifyContext {\n  paymentPayload: HookPaymentPayload;\n  requirements: HookPaymentRequirements;\n}\n\nexport interface VerifyResultContext extends VerifyContext {\n  result: HookVerifyResponse;\n}\n\nexport interface VerifyFailureContext extends VerifyContext {\n  error: Error;\n}\n\nexport interface SettleContext {\n  paymentPayload: HookPaymentPayload;\n  requirements: HookPaymentRequirements;\n}\n\nexport interface SettleResultContext extends SettleContext {\n  result: HookSettleResponse;\n}\n\nexport interface SettleFailureContext extends SettleContext {\n  error: Error;\n}\n\n/**\n * Reason a verified payment never reached settlement. `handler_threw` matches\n * the standard SDK's reason for \"the protected handler errored\".\n */\nexport type VerifiedPaymentCancellationReason = 'handler_threw' | 'handler_failed';\n\nexport interface VerifiedPaymentCanceledContext extends SettleContext {\n  reason: VerifiedPaymentCancellationReason;\n  error?: unknown;\n  responseStatus?: number;\n}\n\n// ============================================================================\n// Verify / Settle hook signatures (resource server flavor)\n// ============================================================================\n\nexport type BeforeVerifyHook = (\n  context: VerifyContext,\n) => Promise<\n  | void\n  | { abort: true; reason: string; message?: string }\n  | { skip: true; result: HookVerifyResponse }\n>;\n\nexport type AfterVerifyHook = (context: VerifyResultContext) => Promise<void | {\n  skipHandler: true;\n  response?: { contentType?: string; body?: unknown };\n}>;\n\nexport type OnVerifyFailureHook = (\n  context: VerifyFailureContext,\n) => Promise<void | { recovered: true; result: HookVerifyResponse }>;\n\nexport type BeforeSettleHook = (\n  context: SettleContext,\n) => Promise<\n  | void\n  | { abort: true; reason: string; message?: string }\n  | { skip: true; result: HookSettleResponse }\n>;\n\nexport type AfterSettleHook = (context: SettleResultContext) => Promise<void>;\n\nexport type OnSettleFailureHook = (\n  context: SettleFailureContext,\n) => Promise<void | { recovered: true; result: HookSettleResponse }>;\n\nexport type OnVerifiedPaymentCanceledHook = (\n  context: VerifiedPaymentCanceledContext,\n) => Promise<void>;\n\n// ============================================================================\n// Facilitator hook signatures\n// (mirror x402Facilitator: no skip/skipHandler/cancellation, no `message`)\n// ============================================================================\n\nexport type FacilitatorBeforeVerifyHook = (\n  context: VerifyContext,\n) => Promise<void | { abort: true; reason: string }>;\n\nexport type FacilitatorAfterVerifyHook = (context: VerifyResultContext) => Promise<void>;\n\nexport type FacilitatorOnVerifyFailureHook = (\n  context: VerifyFailureContext,\n) => Promise<void | { recovered: true; result: HookVerifyResponse }>;\n\nexport type FacilitatorBeforeSettleHook = (\n  context: SettleContext,\n) => Promise<void | { abort: true; reason: string }>;\n\nexport type FacilitatorAfterSettleHook = (context: SettleResultContext) => Promise<void>;\n\nexport type FacilitatorOnSettleFailureHook = (\n  context: SettleFailureContext,\n) => Promise<void | { recovered: true; result: HookSettleResponse }>;\n\n// ============================================================================\n// HTTP resource-server hook (`onProtectedRequest`)\n// ============================================================================\n\n/**\n * Minimal HTTP request descriptor passed to `onProtectedRequest`. Mirrors the\n * shape standard x402 uses, but reduced to the bits the gateway middleware\n * actually has access to.\n */\nexport interface ProtectedRequestContext {\n  /** The HTTP method (uppercase, e.g. \"GET\"). */\n  method: string;\n  /** The request path (no query string). */\n  path: string;\n  /** Full URL as advertised in the 402 response (may equal `path`). */\n  url: string;\n  /**\n   * Case-insensitive header lookup. Returns `undefined` for unknown headers.\n   */\n  getHeader(name: string): string | undefined;\n}\n\nexport interface ProtectedRouteConfig {\n  /** Price string passed to `gateway.require(...)`. */\n  price: string;\n}\n\nexport type ProtectedRequestHook = (\n  context: ProtectedRequestContext,\n  routeConfig: ProtectedRouteConfig,\n) => Promise<void | { grantAccess: true } | { abort: true; reason: string }>;\n\n// ============================================================================\n// Client (payment payload creation) hook contexts and signatures\n// ============================================================================\n\n/**\n * Minimal `PaymentRequired` shape passed to client hook contexts.\n */\nexport interface HookPaymentRequired {\n  x402Version: number;\n  resource?: { url: string; description: string; mimeType: string };\n  accepts: HookPaymentRequirements[];\n  extensions?: Record<string, unknown>;\n  error?: string;\n}\n\nexport interface PaymentCreationContext {\n  paymentRequired: HookPaymentRequired;\n  selectedRequirements: HookPaymentRequirements;\n}\n\nexport interface PaymentCreatedContext extends PaymentCreationContext {\n  paymentPayload: HookPaymentPayload;\n}\n\nexport interface PaymentCreationFailureContext extends PaymentCreationContext {\n  error: Error;\n}\n\nexport interface PaymentResponseContext {\n  paymentPayload: HookPaymentPayload;\n  requirements: HookPaymentRequirements;\n  settleResponse?: HookSettleResponse;\n  paymentRequired?: HookPaymentRequired;\n  error?: Error;\n}\n\nexport type BeforePaymentCreationHook = (\n  context: PaymentCreationContext,\n) => Promise<void | { abort: true; reason: string }>;\n\nexport type AfterPaymentCreationHook = (context: PaymentCreatedContext) => Promise<void>;\n\nexport type OnPaymentCreationFailureHook = (\n  context: PaymentCreationFailureContext,\n) => Promise<void | { recovered: true; payload: HookPaymentPayload }>;\n\nexport type OnPaymentResponseHook = (\n  context: PaymentResponseContext,\n) => Promise<void | { recovered: true }>;\n\n// ============================================================================\n// Internal helpers (shared between facilitator / middleware / scheme)\n// ============================================================================\n\n/**\n * Logs a warning when a hook throws. Mirrors the standard SDK's\n * `warnResourceServerHookFailure` log line so log-grepping continues to work.\n */\nexport function warnHookFailure(\n  component: string,\n  phase: string,\n  label: string,\n  error: unknown,\n): void {\n  const detail = error instanceof Error ? error.message : String(error);\n  console.warn(`[x402] ${component} ${phase} hook threw (${label}): ${detail}`);\n}\n","import type { BatchFacilitatorConfig } from '../types';\nimport {\n  warnHookFailure,\n  type FacilitatorBeforeVerifyHook,\n  type FacilitatorAfterVerifyHook,\n  type FacilitatorOnVerifyFailureHook,\n  type FacilitatorBeforeSettleHook,\n  type FacilitatorAfterSettleHook,\n  type FacilitatorOnSettleFailureHook,\n  type VerifyContext,\n  type VerifyResultContext,\n  type VerifyFailureContext,\n  type SettleContext,\n  type SettleResultContext,\n  type SettleFailureContext,\n} from '../hooks';\n\n/**\n * PaymentPayload interface (minimal subset needed).\n */\ninterface PaymentPayload {\n  x402Version: number;\n  resource?: {\n    url: string;\n    description: string;\n    mimeType: string;\n  };\n  accepted?: Record<string, unknown>;\n  payload: Record<string, unknown>;\n  extensions?: Record<string, unknown>;\n}\n\n/**\n * PaymentRequirements interface (minimal subset needed).\n */\ninterface PaymentRequirements {\n  scheme: string;\n  network: string;\n  asset: string;\n  amount: string;\n  payTo: string;\n  maxTimeoutSeconds: number;\n  extra?: Record<string, unknown>;\n}\n\n/**\n * VerifyResponse from facilitator.\n */\ninterface VerifyResponse {\n  isValid: boolean;\n  invalidReason?: string;\n  payer?: string;\n}\n\n/**\n * SettleResponse from facilitator.\n */\ninterface SettleResponse {\n  success: boolean;\n  errorReason?: string;\n  payer?: string;\n  transaction: string;\n  network: string;\n}\n\n/**\n * SupportedKind from facilitator.\n */\ninterface SupportedKind {\n  x402Version: number;\n  scheme: string;\n  network: string;\n  extra?: Record<string, unknown>;\n}\n\n/**\n * SupportedResponse from facilitator.\n */\ninterface SupportedResponse {\n  kinds: SupportedKind[];\n  extensions: string[];\n  signers: Record<string, string[]>;\n}\n\n/**\n * FacilitatorClient interface from @x402/core.\n */\ninterface FacilitatorClient {\n  verify(\n    paymentPayload: PaymentPayload,\n    paymentRequirements: PaymentRequirements,\n  ): Promise<VerifyResponse>;\n\n  settle(\n    paymentPayload: PaymentPayload,\n    paymentRequirements: PaymentRequirements,\n  ): Promise<SettleResponse>;\n\n  getSupported(): Promise<SupportedResponse>;\n}\n\n/**\n * Circle Gateway Facilitator Client.\n *\n * A FacilitatorClient implementation that communicates with Circle Gateway's\n * x402 endpoints for verification and settlement of batched payments.\n *\n * The client calls:\n * - `POST /v1/x402/verify` for payment verification\n * - `POST /v1/x402/settle` for payment settlement\n * - `GET /v1/x402/supported` for supported payment kinds\n *\n * Lifecycle hooks (`onBeforeVerify`, `onAfterVerify`, `onVerifyFailure`,\n * `onBeforeSettle`, `onAfterSettle`, `onSettleFailure`) are supported with\n * the same semantics as the standard SDK's `x402Facilitator` — see\n * https://docs.x402.org/advanced-concepts/lifecycle-hooks for details.\n *\n * @example\n * ```typescript\n * import { x402ResourceServer } from \"@x402/core/server\";\n * import { BatchFacilitatorClient } from \"@circle-fin/x402-batching/server\";\n *\n * const circleClient = new BatchFacilitatorClient({\n *   url: \"https://gateway.circle.com\",\n * });\n *\n * const server = new x402ResourceServer([circleClient]);\n * await server.initialize();\n * ```\n */\nexport class BatchFacilitatorClient implements FacilitatorClient {\n  readonly url: string;\n  private readonly _createAuthHeaders?: BatchFacilitatorConfig['createAuthHeaders'];\n  private readonly _headers: Record<string, string>;\n\n  private beforeVerifyHooks: FacilitatorBeforeVerifyHook[] = [];\n  private afterVerifyHooks: FacilitatorAfterVerifyHook[] = [];\n  private onVerifyFailureHooks: FacilitatorOnVerifyFailureHook[] = [];\n  private beforeSettleHooks: FacilitatorBeforeSettleHook[] = [];\n  private afterSettleHooks: FacilitatorAfterSettleHook[] = [];\n  private onSettleFailureHooks: FacilitatorOnSettleFailureHook[] = [];\n\n  /**\n   * Creates a new BatchFacilitatorClient.\n   *\n   * @param config - Configuration including Gateway URL and optional auth headers\n   */\n  constructor(config: BatchFacilitatorConfig = {}) {\n    // Ensure URL doesn't have trailing slash\n    this.url = (config.url ?? 'https://gateway-api.circle.com').replace(/\\/$/, '');\n    this._createAuthHeaders = config.createAuthHeaders;\n    this._headers = config.headers ?? {};\n  }\n\n  private gatewayApiHeaders(base: Record<string, string> = {}): Record<string, string> {\n    return { ...base, ...this._headers };\n  }\n\n  /**\n   * Register a hook that runs before facilitator verification.\n   * Return `{ abort: true, reason }` to short-circuit and treat the payment\n   * as invalid (returns `{ isValid: false, invalidReason: reason }`).\n   */\n  onBeforeVerify(hook: FacilitatorBeforeVerifyHook): this {\n    this.beforeVerifyHooks.push(hook);\n    return this;\n  }\n\n  /**\n   * Register a hook that runs after a successful verification (`isValid: true`).\n   * Not invoked when verification fails — use {@link onVerifyFailure} for that.\n   */\n  onAfterVerify(hook: FacilitatorAfterVerifyHook): this {\n    this.afterVerifyHooks.push(hook);\n    return this;\n  }\n\n  /**\n   * Register a hook that runs when verification fails — either when the\n   * facilitator returns `isValid: false` or when an exception is thrown.\n   * Return `{ recovered: true, result }` to override the failure with a\n   * successful verification result.\n   */\n  onVerifyFailure(hook: FacilitatorOnVerifyFailureHook): this {\n    this.onVerifyFailureHooks.push(hook);\n    return this;\n  }\n\n  /**\n   * Register a hook that runs before facilitator settlement. Return\n   * `{ abort: true, reason }` to throw `Error(\"Settlement aborted: <reason>\")`.\n   */\n  onBeforeSettle(hook: FacilitatorBeforeSettleHook): this {\n    this.beforeSettleHooks.push(hook);\n    return this;\n  }\n\n  /**\n   * Register a hook that runs after a successful settlement.\n   */\n  onAfterSettle(hook: FacilitatorAfterSettleHook): this {\n    this.afterSettleHooks.push(hook);\n    return this;\n  }\n\n  /**\n   * Register a hook that runs when settlement throws. Return\n   * `{ recovered: true, result }` to swallow the error and return `result`\n   * to the caller as if settlement had succeeded.\n   */\n  onSettleFailure(hook: FacilitatorOnSettleFailureHook): this {\n    this.onSettleFailureHooks.push(hook);\n    return this;\n  }\n\n  /**\n   * Verify a payment with Circle Gateway.\n   *\n   * @param paymentPayload - The payment payload to verify\n   * @param paymentRequirements - The payment requirements\n   * @returns Verification response\n   */\n  async verify(\n    paymentPayload: PaymentPayload,\n    paymentRequirements: PaymentRequirements,\n  ): Promise<VerifyResponse> {\n    const context: VerifyContext = {\n      paymentPayload,\n      requirements: paymentRequirements,\n    };\n\n    for (const hook of this.beforeVerifyHooks) {\n      const result = await hook(context);\n      if (result && 'abort' in result && result.abort) {\n        return {\n          isValid: false,\n          invalidReason: result.reason,\n        };\n      }\n    }\n\n    try {\n      const verifyResult = await this.callVerify(paymentPayload, paymentRequirements);\n\n      if (!verifyResult.isValid) {\n        const failureContext: VerifyFailureContext = {\n          ...context,\n          error: new Error(verifyResult.invalidReason || 'Verification failed'),\n        };\n\n        for (const hook of this.onVerifyFailureHooks) {\n          const result = await hook(failureContext);\n          if (result && 'recovered' in result && result.recovered) {\n            const recoveredContext: VerifyResultContext = {\n              ...context,\n              result: result.result,\n            };\n            for (const [index, afterHook] of this.afterVerifyHooks.entries()) {\n              try {\n                await afterHook(recoveredContext);\n              } catch (err) {\n                warnHookFailure(\n                  'BatchFacilitatorClient',\n                  'afterVerify',\n                  `manual hook #${index}`,\n                  err,\n                );\n              }\n            }\n            return result.result;\n          }\n        }\n\n        return verifyResult;\n      }\n\n      const resultContext: VerifyResultContext = { ...context, result: verifyResult };\n      for (const [index, hook] of this.afterVerifyHooks.entries()) {\n        try {\n          await hook(resultContext);\n        } catch (err) {\n          warnHookFailure(\n            'BatchFacilitatorClient',\n            'afterVerify',\n            `manual hook #${index}`,\n            err,\n          );\n        }\n      }\n\n      return verifyResult;\n    } catch (error) {\n      const failureContext: VerifyFailureContext = {\n        ...context,\n        error: error as Error,\n      };\n\n      for (const hook of this.onVerifyFailureHooks) {\n        const result = await hook(failureContext);\n        if (result && 'recovered' in result && result.recovered) {\n          return result.result;\n        }\n      }\n\n      throw error;\n    }\n  }\n\n  /**\n   * Settle a payment with Circle Gateway.\n   *\n   * @param paymentPayload - The payment payload to settle\n   * @param paymentRequirements - The payment requirements\n   * @returns Settlement response\n   */\n  async settle(\n    paymentPayload: PaymentPayload,\n    paymentRequirements: PaymentRequirements,\n  ): Promise<SettleResponse> {\n    const context: SettleContext = {\n      paymentPayload,\n      requirements: paymentRequirements,\n    };\n\n    for (const hook of this.beforeSettleHooks) {\n      const result = await hook(context);\n      if (result && 'abort' in result && result.abort) {\n        throw new Error(`Settlement aborted: ${result.reason}`);\n      }\n    }\n\n    try {\n      const settleResult = await this.callSettle(paymentPayload, paymentRequirements);\n\n      const resultContext: SettleResultContext = {\n        ...context,\n        result: settleResult,\n      };\n      for (const [index, hook] of this.afterSettleHooks.entries()) {\n        try {\n          await hook(resultContext);\n        } catch (err) {\n          warnHookFailure(\n            'BatchFacilitatorClient',\n            'afterSettle',\n            `manual hook #${index}`,\n            err,\n          );\n        }\n      }\n\n      return settleResult;\n    } catch (error) {\n      const failureContext: SettleFailureContext = {\n        ...context,\n        error: error as Error,\n      };\n\n      for (const hook of this.onSettleFailureHooks) {\n        const result = await hook(failureContext);\n        if (result && 'recovered' in result && result.recovered) {\n          return result.result;\n        }\n      }\n\n      throw error;\n    }\n  }\n\n  /**\n   * HTTP call into Circle Gateway's /verify endpoint. Split out so the hook\n   * machinery in `verify()` reads cleanly.\n   */\n  private async callVerify(\n    paymentPayload: PaymentPayload,\n    paymentRequirements: PaymentRequirements,\n  ): Promise<VerifyResponse> {\n    let headers = this.gatewayApiHeaders({\n      'Content-Type': 'application/json',\n    });\n\n    if (this._createAuthHeaders) {\n      const authHeaders = await this._createAuthHeaders();\n      headers = { ...headers, ...authHeaders.verify };\n    }\n\n    const response = await fetch(`${this.url}/v1/x402/verify`, {\n      method: 'POST',\n      headers,\n      body: JSON.stringify({\n        paymentPayload: this.toJsonSafe(paymentPayload),\n        paymentRequirements: this.toJsonSafe(paymentRequirements),\n      }),\n    });\n\n    const data = await response.json();\n\n    if (typeof data === 'object' && data !== null && 'isValid' in data) {\n      return data as VerifyResponse;\n    }\n\n    throw new Error(\n      `Circle Gateway verify failed (${response.status}): ${JSON.stringify(data)}`,\n    );\n  }\n\n  /**\n   * HTTP call into Circle Gateway's /settle endpoint. Split out so the hook\n   * machinery in `settle()` reads cleanly.\n   */\n  private async callSettle(\n    paymentPayload: PaymentPayload,\n    paymentRequirements: PaymentRequirements,\n  ): Promise<SettleResponse> {\n    let headers = this.gatewayApiHeaders({\n      'Content-Type': 'application/json',\n    });\n\n    if (this._createAuthHeaders) {\n      const authHeaders = await this._createAuthHeaders();\n      headers = { ...headers, ...authHeaders.settle };\n    }\n\n    const response = await fetch(`${this.url}/v1/x402/settle`, {\n      method: 'POST',\n      headers,\n      body: JSON.stringify({\n        paymentPayload: this.toJsonSafe(paymentPayload),\n        paymentRequirements: this.toJsonSafe(paymentRequirements),\n      }),\n    });\n\n    const text = await response.text();\n    if (!text) {\n      throw new Error(\n        `Circle Gateway settle returned empty response (${response.status})`,\n      );\n    }\n\n    const data = JSON.parse(text);\n\n    if (typeof data === 'object' && data !== null && 'success' in data) {\n      return data as SettleResponse;\n    }\n\n    throw new Error(`Circle Gateway settle failed (${response.status}): ${text}`);\n  }\n\n  /**\n   * Get supported payment kinds from Circle Gateway.\n   *\n   * This fetches the supported networks and their GatewayWallet contract addresses.\n   * The response includes `extra.verifyingContract` for each supported network.\n   *\n   * @returns Supported payment kinds and extensions\n   */\n  async getSupported(): Promise<SupportedResponse> {\n    let headers = this.gatewayApiHeaders({\n      'Content-Type': 'application/json',\n    });\n\n    if (this._createAuthHeaders) {\n      const authHeaders = await this._createAuthHeaders();\n      headers = { ...headers, ...authHeaders.supported };\n    }\n\n    const response = await fetch(`${this.url}/v1/x402/supported`, {\n      method: 'GET',\n      headers,\n    });\n\n    if (!response.ok) {\n      const errorText = await response.text().catch(() => response.statusText);\n      throw new Error(\n        `Circle Gateway getSupported failed (${response.status}): ${errorText}`,\n      );\n    }\n\n    return (await response.json()) as SupportedResponse;\n  }\n\n  /**\n   * Helper to convert objects to JSON-safe format.\n   * Handles BigInt and other non-JSON types.\n   */\n  private toJsonSafe(obj: unknown): unknown {\n    return JSON.parse(\n      JSON.stringify(obj, (_, value) =>\n        typeof value === 'bigint' ? value.toString() : value,\n      ),\n    );\n  }\n}\n","import { ExactEvmScheme } from '@x402/evm/exact/server';\nimport type { Network, PaymentRequirements } from '@x402/core/types';\nimport { CHAIN_CONFIGS } from '../client/GatewayClient';\nimport { GATEWAY_AUTH_VALIDITY_WINDOW_SECONDS } from '../constants';\n\n/**\n * Gateway EVM Scheme for x402 resource servers.\n *\n * Extends `ExactEvmScheme` with two Gateway-specific behaviors:\n *\n * 1. **enhancePaymentRequirements** — merges `supportedKind.extra` (e.g.\n *    `verifyingContract`) into `paymentRequirements.extra`. The base\n *    `ExactEvmScheme` discards this, but Gateway clients need it to\n *    construct the correct EIP-712 signing domain.\n *\n * 2. **Money parsers** — registers USDC address mappings for all\n *    Gateway-supported networks so `parsePrice(\"$0.01\")` works\n *    without manual `registerMoneyParser()` calls.\n *\n * @example\n * ```typescript\n * import { GatewayEvmScheme } from \"@circle-fin/x402-batching/server\";\n * import { x402ResourceServer } from \"@x402/express\";\n *\n * const resourceServer = new x402ResourceServer(facilitators)\n *   .register(\"eip155:5042002\", new GatewayEvmScheme());\n * ```\n */\nexport class GatewayEvmScheme extends ExactEvmScheme {\n  constructor() {\n    super();\n    this.registerGatewayMoneyParsers();\n  }\n\n  /**\n   * Enhances payment requirements by merging the facilitator's extra data.\n   *\n   * The base `ExactEvmScheme.enhancePaymentRequirements` returns requirements\n   * unchanged, dropping `supportedKind.extra`. Gateway payments require\n   * `extra.verifyingContract` (and other fields like `name`, `version`) to\n   * be present for clients to construct the correct signing domain.\n   */\n  async enhancePaymentRequirements(\n    paymentRequirements: PaymentRequirements,\n    supportedKind: {\n      x402Version: number;\n      scheme: string;\n      network: Network;\n      extra?: Record<string, unknown>;\n    },\n    extensionKeys: string[],\n  ): Promise<PaymentRequirements> {\n    void extensionKeys;\n    return {\n      ...paymentRequirements,\n      maxTimeoutSeconds: Math.max(\n        paymentRequirements.maxTimeoutSeconds,\n        GATEWAY_AUTH_VALIDITY_WINDOW_SECONDS,\n      ),\n      extra: {\n        ...paymentRequirements.extra,\n        ...supportedKind.extra,\n      },\n    };\n  }\n\n  /**\n   * Registers money parsers for all Gateway-supported networks.\n   *\n   * Builds a `network → USDC address` lookup from `CHAIN_CONFIGS` and\n   * registers a single parser that converts dollar amounts to USDC atomic\n   * units (6 decimals) for any Gateway-supported chain.\n   *\n   * Returns `null` for unknown networks so `ExactEvmScheme`'s built-in\n   * parser handles them.\n   */\n  private registerGatewayMoneyParsers(): void {\n    // Build network → USDC address map from CHAIN_CONFIGS\n    const networkUsdcMap = new Map<string, string>();\n    for (const config of Object.values(CHAIN_CONFIGS)) {\n      const network = `eip155:${config.chain.id}`;\n      networkUsdcMap.set(network, config.usdc);\n    }\n\n    this.registerMoneyParser(async (amount: number, network: Network) => {\n      const usdcAddress = networkUsdcMap.get(network);\n      if (!usdcAddress) {\n        return null; // Not a Gateway network — let default parser handle it\n      }\n      return {\n        amount: Math.round(amount * 1e6).toString(),\n        asset: usdcAddress,\n      };\n    });\n  }\n}\n","import {\n  createPublicClient,\n  createWalletClient,\n  http,\n  parseUnits,\n  formatUnits,\n  pad,\n  zeroAddress,\n  maxUint256,\n  type Address,\n  type Hex,\n  type Chain,\n  type PublicClient,\n  type WalletClient,\n  type Transport,\n  type Account,\n  defineChain,\n  erc20Abi,\n} from 'viem';\nimport { privateKeyToAccount } from 'viem/accounts';\nimport * as chains from 'viem/chains';\nimport { randomBytes } from 'crypto';\nimport { BatchEvmScheme } from './BatchEvmScheme';\nimport type { BatchEvmSigner } from '../types';\nimport type {\n  BeforePaymentCreationHook,\n  AfterPaymentCreationHook,\n  OnPaymentCreationFailureHook,\n  OnPaymentResponseHook,\n  PaymentResponseContext,\n} from '../hooks';\n\n// Arc chains: prefer viem's chain export (added in viem ~2.52), fall back to a\n// local definition for consumers pinned to older viem versions. viem's `arc`\n// export still ships an empty RPC list, so CHAIN_CONFIGS.arc.rpcUrl (and this\n// fallback) supply Circle's public mainnet RPC.\nconst ARC_MAINNET_RPC_URL = 'https://rpc.mainnet.arc.io';\n\nconst arcMainnet =\n  (chains as Record<string, Chain>).arc ??\n  defineChain({\n    id: 5042,\n    name: 'Arc',\n    nativeCurrency: { decimals: 18, name: 'USDC', symbol: 'USDC' },\n    rpcUrls: {\n      default: { http: [ARC_MAINNET_RPC_URL] },\n    },\n  });\n\nconst arcTestnetChain =\n  chains.arcTestnet ??\n  defineChain({\n    id: 5042002,\n    name: 'Arc Testnet',\n    nativeCurrency: { decimals: 18, name: 'USDC', symbol: 'USDC' },\n    rpcUrls: {\n      default: { http: ['https://rpc.testnet.arc.network'] },\n    },\n    testnet: true,\n  });\n\n// viem's sonicTestnet uses the old testnet.  This uses the new one.\nconst sonicTestnet = defineChain({\n  id: 14601,\n  name: 'Sonic Testnet',\n  nativeCurrency: { decimals: 18, name: 'Sonic', symbol: 'S' },\n  rpcUrls: {\n    default: { http: ['https://rpc.testnet.soniclabs.com'] },\n  },\n  blockExplorers: {\n    default: { name: 'Sonic Testnet Explorer', url: 'https://testnet.soniclabs.com/' },\n  },\n  testnet: true,\n});\n\n// ============================================================================\n// CONTRACT ABIS\n// ============================================================================\n\n// Gateway API URL\nconst GATEWAY_API_TESTNET = 'https://gateway-api-testnet.circle.com/v1';\nconst GATEWAY_API_MAINNET = 'https://gateway-api.circle.com/v1';\n\nconst GATEWAY_MINTER_ABI = [\n  {\n    name: 'gatewayMint',\n    type: 'function',\n    stateMutability: 'nonpayable',\n    inputs: [\n      { name: 'attestationPayload', type: 'bytes' },\n      { name: 'signature', type: 'bytes' },\n    ],\n    outputs: [],\n  },\n] as const;\n\nconst GATEWAY_WALLET_ABI = [\n  {\n    name: 'deposit',\n    type: 'function',\n    stateMutability: 'nonpayable',\n    inputs: [\n      { name: 'token', type: 'address' },\n      { name: 'value', type: 'uint256' },\n    ],\n    outputs: [],\n  },\n  {\n    name: 'depositFor',\n    type: 'function',\n    stateMutability: 'nonpayable',\n    inputs: [\n      { name: 'token', type: 'address' },\n      { name: 'depositor', type: 'address' },\n      { name: 'value', type: 'uint256' },\n    ],\n    outputs: [],\n  },\n  {\n    name: 'totalBalance',\n    type: 'function',\n    stateMutability: 'view',\n    inputs: [\n      { name: 'token', type: 'address' },\n      { name: 'depositor', type: 'address' },\n    ],\n    outputs: [{ name: '', type: 'uint256' }],\n  },\n  {\n    name: 'availableBalance',\n    type: 'function',\n    stateMutability: 'view',\n    inputs: [\n      { name: 'token', type: 'address' },\n      { name: 'depositor', type: 'address' },\n    ],\n    outputs: [{ name: '', type: 'uint256' }],\n  },\n  {\n    name: 'withdrawingBalance',\n    type: 'function',\n    stateMutability: 'view',\n    inputs: [\n      { name: 'token', type: 'address' },\n      { name: 'depositor', type: 'address' },\n    ],\n    outputs: [{ name: '', type: 'uint256' }],\n  },\n  {\n    name: 'withdrawableBalance',\n    type: 'function',\n    stateMutability: 'view',\n    inputs: [\n      { name: 'token', type: 'address' },\n      { name: 'depositor', type: 'address' },\n    ],\n    outputs: [{ name: '', type: 'uint256' }],\n  },\n  {\n    name: 'withdrawalDelay',\n    type: 'function',\n    stateMutability: 'view',\n    inputs: [],\n    outputs: [{ name: '', type: 'uint256' }],\n  },\n  {\n    name: 'withdrawalBlock',\n    type: 'function',\n    stateMutability: 'view',\n    inputs: [\n      { name: 'token', type: 'address' },\n      { name: 'depositor', type: 'address' },\n    ],\n    outputs: [{ name: '', type: 'uint256' }],\n  },\n  {\n    name: 'initiateWithdrawal',\n    type: 'function',\n    stateMutability: 'nonpayable',\n    inputs: [\n      { name: 'token', type: 'address' },\n      { name: 'value', type: 'uint256' },\n    ],\n    outputs: [],\n  },\n  {\n    name: 'withdraw',\n    type: 'function',\n    stateMutability: 'nonpayable',\n    inputs: [{ name: 'token', type: 'address' }],\n    outputs: [],\n  },\n] as const;\n\n// ============================================================================\n// CHAIN CONFIGURATIONS\n// ============================================================================\n\n/**\n * Gateway domain identifiers for supported chains.\n * See: https://developers.circle.com/gateway/gateway-supported-blockchains\n */\nexport const GATEWAY_DOMAINS = {\n  // Testnet\n  arbitrumSepolia: 3,\n  arcTestnet: 26,\n  avalancheFuji: 1,\n  baseSepolia: 6,\n  sepolia: 0,\n  hyperEvmTestnet: 19,\n  optimismSepolia: 2,\n  polygonAmoy: 7,\n  seiAtlantic: 16,\n  sonicTestnet: 13,\n  unichainSepolia: 10,\n  worldChainSepolia: 14,\n  // Mainnet\n  arbitrum: 3,\n  avalanche: 1,\n  base: 6,\n  ethereum: 0,\n  hyperEvm: 19,\n  optimism: 2,\n  polygon: 7,\n  sei: 16,\n  sonic: 13,\n  unichain: 10,\n  worldChain: 14,\n  arc: 26,\n} as const;\n\n/**\n * Supported chain names type.\n */\nexport type SupportedChainName = keyof typeof GATEWAY_DOMAINS;\n\n/**\n * Chain configuration with contract addresses.\n */\nexport interface ChainConfig {\n  chain: Chain;\n  domain: number;\n  usdc: Address;\n  gatewayWallet: Address;\n  gatewayMinter: Address;\n  rpcUrl?: string;\n}\n\n// Testnet GatewayWallet and GatewayMinter addresses (same across all testnet chains)\nconst TESTNET_GATEWAY_WALLET = '0x0077777d7EBA4688BDeF3E311b846F25870A19B9' as Address;\nconst TESTNET_GATEWAY_MINTER = '0x0022222ABE238Cc2C7Bb1f21003F0a260052475B' as Address;\n\n// Mainnet GatewayWallet and GatewayMinter addresses (same across all mainnet chains)\nconst MAINNET_GATEWAY_WALLET = '0x77777777Dcc4d5A8B6E418Fd04D8997ef11000eE' as Address;\nconst MAINNET_GATEWAY_MINTER = '0x2222222d7164433c4C09B0b0D809a9b52C04C205' as Address;\n\n/**\n * Chain configurations for supported chains.\n */\nexport const CHAIN_CONFIGS: Record<SupportedChainName, ChainConfig> = {\n  // Testnet chains\n  arbitrumSepolia: {\n    chain: chains.arbitrumSepolia,\n    domain: GATEWAY_DOMAINS.arbitrumSepolia,\n    usdc: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d' as Address,\n    gatewayWallet: TESTNET_GATEWAY_WALLET,\n    gatewayMinter: TESTNET_GATEWAY_MINTER,\n  },\n  arcTestnet: {\n    chain: arcTestnetChain,\n    domain: GATEWAY_DOMAINS.arcTestnet,\n    usdc: '0x3600000000000000000000000000000000000000' as Address,\n    gatewayWallet: TESTNET_GATEWAY_WALLET,\n    gatewayMinter: TESTNET_GATEWAY_MINTER,\n    rpcUrl: 'https://rpc.testnet.arc.network',\n  },\n  avalancheFuji: {\n    chain: chains.avalancheFuji,\n    domain: GATEWAY_DOMAINS.avalancheFuji,\n    usdc: '0x5425890298aed601595a70AB815c96711a31Bc65' as Address,\n    gatewayWallet: TESTNET_GATEWAY_WALLET,\n    gatewayMinter: TESTNET_GATEWAY_MINTER,\n  },\n  baseSepolia: {\n    chain: chains.baseSepolia,\n    domain: GATEWAY_DOMAINS.baseSepolia,\n    usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e' as Address,\n    gatewayWallet: TESTNET_GATEWAY_WALLET,\n    gatewayMinter: TESTNET_GATEWAY_MINTER,\n    rpcUrl: 'https://sepolia-preconf.base.org',\n  },\n  sepolia: {\n    chain: chains.sepolia,\n    domain: GATEWAY_DOMAINS.sepolia,\n    usdc: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' as Address,\n    gatewayWallet: TESTNET_GATEWAY_WALLET,\n    gatewayMinter: TESTNET_GATEWAY_MINTER,\n  },\n  hyperEvmTestnet: {\n    chain: chains.hyperliquidEvmTestnet,\n    domain: GATEWAY_DOMAINS.hyperEvmTestnet,\n    usdc: '0x2B3370eE501B4a559b57D449569354196457D8Ab' as Address,\n    gatewayWallet: TESTNET_GATEWAY_WALLET,\n    gatewayMinter: TESTNET_GATEWAY_MINTER,\n  },\n  optimismSepolia: {\n    chain: chains.optimismSepolia,\n    domain: GATEWAY_DOMAINS.optimismSepolia,\n    usdc: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7' as Address,\n    gatewayWallet: TESTNET_GATEWAY_WALLET,\n    gatewayMinter: TESTNET_GATEWAY_MINTER,\n  },\n  polygonAmoy: {\n    chain: chains.polygonAmoy,\n    domain: GATEWAY_DOMAINS.polygonAmoy,\n    usdc: '0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582' as Address,\n    gatewayWallet: TESTNET_GATEWAY_WALLET,\n    gatewayMinter: TESTNET_GATEWAY_MINTER,\n  },\n  seiAtlantic: {\n    chain: chains.seiTestnet,\n    domain: GATEWAY_DOMAINS.seiAtlantic,\n    usdc: '0x4fCF1784B31630811181f670Aea7A7bEF803eaED' as Address,\n    gatewayWallet: TESTNET_GATEWAY_WALLET,\n    gatewayMinter: TESTNET_GATEWAY_MINTER,\n  },\n  sonicTestnet: {\n    chain: sonicTestnet,\n    domain: GATEWAY_DOMAINS.sonicTestnet,\n    usdc: '0x0BA304580ee7c9a980CF72e55f5Ed2E9fd30Bc51' as Address,\n    gatewayWallet: TESTNET_GATEWAY_WALLET,\n    gatewayMinter: TESTNET_GATEWAY_MINTER,\n  },\n  unichainSepolia: {\n    chain: chains.unichainSepolia,\n    domain: GATEWAY_DOMAINS.unichainSepolia,\n    usdc: '0x31d0220469e10c4E71834a79b1f276d740d3768F' as Address,\n    gatewayWallet: TESTNET_GATEWAY_WALLET,\n    gatewayMinter: TESTNET_GATEWAY_MINTER,\n  },\n  worldChainSepolia: {\n    chain: chains.worldchainSepolia,\n    domain: GATEWAY_DOMAINS.worldChainSepolia,\n    usdc: '0x66145f38cBAC35Ca6F1Dfb4914dF98F1614aeA88' as Address,\n    gatewayWallet: TESTNET_GATEWAY_WALLET,\n    gatewayMinter: TESTNET_GATEWAY_MINTER,\n  },\n  // Mainnet chains\n  arbitrum: {\n    chain: chains.arbitrum,\n    domain: GATEWAY_DOMAINS.arbitrum,\n    usdc: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831' as Address,\n    gatewayWallet: MAINNET_GATEWAY_WALLET,\n    gatewayMinter: MAINNET_GATEWAY_MINTER,\n  },\n  avalanche: {\n    chain: chains.avalanche,\n    domain: GATEWAY_DOMAINS.avalanche,\n    usdc: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E' as Address,\n    gatewayWallet: MAINNET_GATEWAY_WALLET,\n    gatewayMinter: MAINNET_GATEWAY_MINTER,\n  },\n  base: {\n    chain: chains.base,\n    domain: GATEWAY_DOMAINS.base,\n    usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' as Address,\n    gatewayWallet: MAINNET_GATEWAY_WALLET,\n    gatewayMinter: MAINNET_GATEWAY_MINTER,\n  },\n  ethereum: {\n    chain: chains.mainnet,\n    domain: GATEWAY_DOMAINS.ethereum,\n    usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as Address,\n    gatewayWallet: MAINNET_GATEWAY_WALLET,\n    gatewayMinter: MAINNET_GATEWAY_MINTER,\n    rpcUrl: 'https://ethereum-rpc.publicnode.com',\n  },\n  hyperEvm: {\n    chain: chains.hyperEvm,\n    domain: GATEWAY_DOMAINS.hyperEvm,\n    usdc: '0xb88339CB7199b77E23DB6E890353E22632Ba630f' as Address,\n    gatewayWallet: MAINNET_GATEWAY_WALLET,\n    gatewayMinter: MAINNET_GATEWAY_MINTER,\n  },\n  optimism: {\n    chain: chains.optimism,\n    domain: GATEWAY_DOMAINS.optimism,\n    usdc: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85' as Address,\n    gatewayWallet: MAINNET_GATEWAY_WALLET,\n    gatewayMinter: MAINNET_GATEWAY_MINTER,\n  },\n  polygon: {\n    chain: chains.polygon,\n    domain: GATEWAY_DOMAINS.polygon,\n    usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359' as Address,\n    gatewayWallet: MAINNET_GATEWAY_WALLET,\n    gatewayMinter: MAINNET_GATEWAY_MINTER,\n    rpcUrl: 'https://poly.api.pocket.network',\n  },\n  sei: {\n    chain: chains.sei,\n    domain: GATEWAY_DOMAINS.sei,\n    usdc: '0xe15fC38F6D8c56aF07bbCBe3BAf5708A2Bf42392' as Address,\n    gatewayWallet: MAINNET_GATEWAY_WALLET,\n    gatewayMinter: MAINNET_GATEWAY_MINTER,\n    rpcUrl: 'https://sei.api.pocket.network',\n  },\n  sonic: {\n    chain: chains.sonic,\n    domain: GATEWAY_DOMAINS.sonic,\n    usdc: '0x29219dd400f2Bf60E5a23d13Be72B486D4038894' as Address,\n    gatewayWallet: MAINNET_GATEWAY_WALLET,\n    gatewayMinter: MAINNET_GATEWAY_MINTER,\n  },\n  unichain: {\n    chain: chains.unichain,\n    domain: GATEWAY_DOMAINS.unichain,\n    usdc: '0x078D782b760474a361dDA0AF3839290b0EF57AD6' as Address,\n    gatewayWallet: MAINNET_GATEWAY_WALLET,\n    gatewayMinter: MAINNET_GATEWAY_MINTER,\n  },\n  worldChain: {\n    chain: chains.worldchain,\n    domain: GATEWAY_DOMAINS.worldChain,\n    usdc: '0x79A02482A880bCE3F13e09Da970dC34db4CD24d1' as Address,\n    gatewayWallet: MAINNET_GATEWAY_WALLET,\n    gatewayMinter: MAINNET_GATEWAY_MINTER,\n  },\n  arc: {\n    chain: arcMainnet,\n    domain: GATEWAY_DOMAINS.arc,\n    usdc: '0x3600000000000000000000000000000000000000' as Address,\n    gatewayWallet: MAINNET_GATEWAY_WALLET,\n    gatewayMinter: MAINNET_GATEWAY_MINTER,\n    rpcUrl: ARC_MAINNET_RPC_URL,\n  },\n};\n\n// ============================================================================\n// GATEWAY CLIENT TYPES\n// ============================================================================\n\n/**\n * Configuration for creating a GatewayClient.\n */\nexport interface GatewayClientConfig {\n  /** The chain to connect to */\n  chain: SupportedChainName;\n  /** Private key for signing transactions */\n  privateKey: Hex;\n  /**\n   * Custom RPC URL. Optional for all chains (a public default is used).\n   */\n  rpcUrl?: string;\n  /** Additional headers merged into every outbound Gateway API request. */\n  headers?: Record<string, string>;\n}\n\n/**\n * Result of a deposit operation.\n */\nexport interface DepositResult {\n  /** Transaction hash of the approval (if needed) */\n  approvalTxHash?: Hex;\n  /** Transaction hash of the deposit */\n  depositTxHash: Hex;\n  /** Amount deposited in USDC atomic units */\n  amount: bigint;\n  /** Formatted amount deposited */\n  formattedAmount: string;\n  /** Depositor address */\n  depositor: Address;\n}\n\n/**\n * Result of a withdraw operation (instant transfer).\n */\nexport interface WithdrawResult {\n  /** Transaction hash of the mint on destination chain */\n  mintTxHash: Hex;\n  /** Amount withdrawn in USDC atomic units */\n  amount: bigint;\n  /** Formatted amount withdrawn */\n  formattedAmount: string;\n  /** Source chain name */\n  sourceChain: string;\n  /** Destination chain name */\n  destinationChain: string;\n  /** Recipient address */\n  recipient: Address;\n}\n\n/**\n * Result of a pay operation.\n */\nexport interface PayResult<T = unknown> {\n  /** The response data from the resource */\n  data: T;\n  /** Amount paid in USDC atomic units */\n  amount: bigint;\n  /** Formatted amount paid */\n  formattedAmount: string;\n  /** Transaction hash from settlement */\n  transaction: string;\n  /** HTTP status code */\n  status: number;\n}\n\n/**\n * All balances in one object.\n */\nexport interface Balances {\n  /** Regular wallet USDC balance */\n  wallet: {\n    balance: bigint;\n    formatted: string;\n  };\n  /** Gateway balances */\n  gateway: {\n    total: bigint;\n    available: bigint;\n    withdrawing: bigint;\n    withdrawable: bigint;\n    formattedTotal: string;\n    formattedAvailable: string;\n    formattedWithdrawing: string;\n    formattedWithdrawable: string;\n  };\n}\n\n/**\n * Result of checking if a URL supports batching.\n */\nexport interface SupportsResult {\n  /** Whether the URL supports Gateway batching */\n  supported: boolean;\n  /** Payment requirements if supported */\n  requirements?: Record<string, unknown>;\n  /** Error message if not supported */\n  error?: string;\n}\n\n/**\n * Result of a trustless withdrawal initiation.\n *\n * NOTE: Trustless withdrawals are for emergency use only when Circle's API is unavailable.\n * For normal withdrawals, use `transfer()` with the same source and destination chain.\n */\nexport interface TrustlessWithdrawalInitResult {\n  /** Transaction hash */\n  txHash: Hex;\n  /** Amount being withdrawn in USDC atomic units */\n  amount: bigint;\n  /** Formatted amount being withdrawn */\n  formattedAmount: string;\n  /** Block number at which withdrawal becomes available (~7 days) */\n  withdrawalBlock: bigint;\n}\n\n/**\n * Result of a trustless withdrawal completion.\n *\n * NOTE: Trustless withdrawals are for emergency use only when Circle's API is unavailable.\n */\nexport interface TrustlessWithdrawalResult {\n  /** Transaction hash */\n  txHash: Hex;\n  /** Amount withdrawn in USDC atomic units */\n  amount: bigint;\n  /** Formatted amount withdrawn */\n  formattedAmount: string;\n}\n\n/**\n * Gateway balance information.\n */\nexport interface GatewayBalance {\n  /** Total balance in Gateway */\n  total: bigint;\n  /** Available balance (can be used) */\n  available: bigint;\n  /** Balance in withdrawal process */\n  withdrawing: bigint;\n  /** Balance ready to be withdrawn */\n  withdrawable: bigint;\n  /** Formatted total balance */\n  formattedTotal: string;\n  /** Formatted available balance */\n  formattedAvailable: string;\n  /** Formatted withdrawing balance */\n  formattedWithdrawing: string;\n  /** Formatted withdrawable balance */\n  formattedWithdrawable: string;\n}\n\n// ============================================================================\n// TRANSFER TYPES\n// ============================================================================\n\nexport type TransferStatus =\n  | 'received'\n  | 'batched'\n  | 'confirmed'\n  | 'completed'\n  | 'failed';\n\n/**\n * Shape may evolve; preserve all fields as returned by the API.\n */\nexport interface TransferResponse {\n  id: string;\n  status: TransferStatus;\n  token: 'USDC';\n  sendingNetwork: string;\n  recipientNetwork: string;\n  fromAddress: string;\n  toAddress: string;\n  amount: string;\n  createdAt: string;\n  updatedAt: string;\n  [key: string]: unknown;\n}\n\nexport interface SearchTransfersParams {\n  from?: Hex;\n  to?: Hex;\n  nonce?: Hex;\n  network?: string;\n  status?: TransferStatus;\n  token?: 'USDC';\n  startDate?: string;\n  endDate?: string;\n  pageSize?: number;\n  pageAfter?: string;\n  pageBefore?: string;\n}\n\nexport interface CursorPagination {\n  self?: string;\n  first?: string;\n  prev?: string;\n  next?: string;\n  pageAfter?: string;\n  pageBefore?: string;\n}\n\nexport interface SearchTransfersResponse {\n  transfers: TransferResponse[];\n  pagination?: CursorPagination;\n}\n\n// ============================================================================\n// GATEWAY CLIENT\n// ============================================================================\n\n/**\n * Gateway Client for gasless payments and cross-chain USDC via Circle Gateway.\n *\n * This client provides a simple interface for buyers to:\n * - **Deposit**: Move USDC into Gateway for gasless payments\n * - **Pay**: Pay for x402-protected resources (handles 402 automatically)\n * - **Withdraw**: Get USDC back (same-chain or cross-chain, instant)\n * - **GetBalances**: Check all balances in one call\n *\n * ## Typical Flow\n * ```typescript\n * const gateway = new GatewayClient({ chain: 'arcTestnet', privateKey });\n *\n * // 1. Deposit (one-time setup)\n * await gateway.deposit('100');\n *\n * // 2. Pay for resources (many times, gasless!)\n * const { data } = await gateway.pay('https://api.example.com/resource');\n *\n * // 3. Check balances\n * const balances = await gateway.getBalances();\n *\n * // 4. Withdraw when done\n * await gateway.withdraw('50');\n * // Or withdraw to a different chain (requires gas on destination)\n * await gateway.withdraw('25', { chain: 'baseSepolia' });\n * ```\n *\n * ## Emergency Flow (when Circle's API is down)\n * Use `initiateTrustlessWithdrawal()` and `completeTrustlessWithdrawal()` (7-day delay).\n */\nexport class GatewayClient {\n  readonly chainConfig: ChainConfig;\n  readonly account: ReturnType<typeof privateKeyToAccount>;\n  readonly publicClient: PublicClient<Transport, Chain>;\n  readonly walletClient: WalletClient<Transport, Chain, Account>;\n  private readonly _headers: Record<string, string>;\n\n  /**\n   * The scheme that builds and signs the batched payment payload. `pay()`\n   * delegates to this so the buyer flow runs the same lifecycle hooks as the\n   * standalone `BatchEvmScheme` / `x402Client` paths.\n   */\n  private readonly batchScheme: BatchEvmScheme;\n\n  /**\n   * Creates a new GatewayClient.\n   *\n   * @param config - Configuration including chain and private key\n   */\n  constructor(config: GatewayClientConfig) {\n    const chainConfig = CHAIN_CONFIGS[config.chain];\n    if (!chainConfig) {\n      throw new Error(`Unsupported chain: ${config.chain}`);\n    }\n\n    this.chainConfig = chainConfig;\n    this._headers = config.headers ?? {};\n    this.account = privateKeyToAccount(config.privateKey);\n\n    const rpcUrl = config.rpcUrl ?? chainConfig.rpcUrl;\n    const transport = rpcUrl ? http(rpcUrl) : http();\n\n    this.publicClient = createPublicClient({\n      chain: chainConfig.chain,\n      transport,\n    }) as PublicClient<Transport, Chain>;\n\n    this.walletClient = createWalletClient({\n      account: this.account,\n      chain: chainConfig.chain,\n      transport,\n    }) as WalletClient<Transport, Chain, Account>;\n\n    // The viem account satisfies BatchEvmSigner (address + signTypedData).\n    const signer: BatchEvmSigner = {\n      address: this.account.address,\n      signTypedData: (params) => this.account.signTypedData(params),\n    };\n    this.batchScheme = new BatchEvmScheme(signer);\n  }\n\n  // ============================================================================\n  // PAYMENT LIFECYCLE HOOKS\n  // ============================================================================\n  //\n  // These delegate to the underlying BatchEvmScheme so that the `pay()` buyer\n  // flow runs the same lifecycle hooks as the standalone scheme / x402Client\n  // paths — see https://docs.x402.org/advanced-concepts/lifecycle-hooks.\n\n  /**\n   * Register a hook that runs before the payment payload is created. Returning\n   * `{ abort: true, reason }` causes `pay()` to throw before signing.\n   */\n  onBeforePaymentCreation(hook: BeforePaymentCreationHook): this {\n    this.batchScheme.onBeforePaymentCreation(hook);\n    return this;\n  }\n\n  /**\n   * Register a hook that runs after the payment payload is successfully created.\n   */\n  onAfterPaymentCreation(hook: AfterPaymentCreationHook): this {\n    this.batchScheme.onAfterPaymentCreation(hook);\n    return this;\n  }\n\n  /**\n   * Register a hook that runs when payload creation throws. Return\n   * `{ recovered: true, payload }` to recover with the provided payload.\n   */\n  onPaymentCreationFailure(hook: OnPaymentCreationFailureHook): this {\n    this.batchScheme.onPaymentCreationFailure(hook);\n    return this;\n  }\n\n  /**\n   * Register a hook that runs after the buyer's paid HTTP request completes.\n   * Return `{ recovered: true }` to have `pay()` retry once with a fresh payload.\n   */\n  onPaymentResponse(hook: OnPaymentResponseHook): this {\n    this.batchScheme.onPaymentResponse(hook);\n    return this;\n  }\n\n  /**\n   * Get the account address.\n   */\n  get address(): Address {\n    return this.account.address;\n  }\n\n  /**\n   * Get the chain name.\n   */\n  get chainName(): string {\n    return this.chainConfig.chain.name;\n  }\n\n  /**\n   * Get the Gateway domain for this chain.\n   */\n  get domain(): number {\n    return this.chainConfig.domain;\n  }\n\n  /**\n   * Get the chain name key for this client.\n   */\n  getChainName(): SupportedChainName {\n    // Find the key in CHAIN_CONFIGS that matches our domain\n    for (const [name, config] of Object.entries(CHAIN_CONFIGS)) {\n      if (\n        config.domain === this.chainConfig.domain &&\n        config.chain.id === this.chainConfig.chain.id\n      ) {\n        return name as SupportedChainName;\n      }\n    }\n    throw new Error('Unknown chain configuration');\n  }\n\n  /**\n   * Get the USDC balance of the account (not in Gateway).\n   *\n   * @param address - Optional address to check (defaults to account address)\n   * @returns USDC balance in atomic units and formatted\n   */\n  async getUsdcBalance(\n    address?: Address,\n  ): Promise<{ balance: bigint; formatted: string }> {\n    const target = address ?? this.account.address;\n    const balance = await this.publicClient.readContract({\n      address: this.chainConfig.usdc,\n      abi: erc20Abi,\n      functionName: 'balanceOf',\n      args: [target],\n    });\n\n    return {\n      balance,\n      formatted: formatUnits(balance, 6),\n    };\n  }\n\n  /**\n   * Get all balances (wallet + gateway) in one call.\n   *\n   * @param address - Optional address to check (defaults to account address)\n   * @returns All balances\n   */\n  async getBalances(address?: Address): Promise<Balances> {\n    const target = address ?? this.account.address;\n\n    const [wallet, gateway] = await Promise.all([\n      this.getUsdcBalance(target),\n      this.getGatewayBalance(target),\n    ]);\n\n    return {\n      wallet,\n      gateway,\n    };\n  }\n\n  /**\n   * Get the Gateway balance for an address.\n   *\n   * @param address - Optional address to check (defaults to account address)\n   * @returns Gateway balance information\n   * @deprecated Use `getBalances()` instead for a unified view\n   */\n  async getBalance(address?: Address): Promise<GatewayBalance> {\n    return this.getGatewayBalance(address);\n  }\n\n  /**\n   * Get the Gateway balance for an address via Gateway API.\n   */\n  private async getGatewayBalance(address?: Address): Promise<GatewayBalance> {\n    const target = address ?? this.account.address;\n    const apiBaseUrl = this.isTestnet() ? GATEWAY_API_TESTNET : GATEWAY_API_MAINNET;\n\n    const response = await fetch(`${apiBaseUrl}/balances`, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        ...this.gatewayApiHeaders(),\n      },\n      body: JSON.stringify({\n        token: 'USDC',\n        sources: [{ depositor: target, domain: this.chainConfig.domain }],\n      }),\n    });\n\n    const data = (await response.json()) as {\n      balances?: Array<{\n        balance: string;\n        withdrawing?: string;\n        withdrawable?: string;\n      }>;\n      message?: string;\n    };\n\n    if (!response.ok) {\n      throw new Error(\n        `Gateway API balance fetch failed: ${data.message ?? response.statusText}`,\n      );\n    }\n\n    if (!data.balances || data.balances.length === 0) {\n      throw new Error('Gateway API returned no balances for the depositor.');\n    }\n\n    const balanceData = data.balances[0];\n    // Gateway API returns formatted decimal strings (e.g. \"0.300000\") for USDC.\n    // Convert to atomic units (6 decimals) for bigint fields.\n    const available = parseUnits(balanceData.balance, 6);\n    const withdrawing = parseUnits(balanceData.withdrawing ?? '0', 6);\n    const withdrawable = parseUnits(balanceData.withdrawable ?? '0', 6);\n    const total = available + withdrawing;\n\n    return {\n      total,\n      available,\n      withdrawing,\n      withdrawable,\n      formattedTotal: formatUnits(total, 6),\n      formattedAvailable: formatUnits(available, 6),\n      formattedWithdrawing: formatUnits(withdrawing, 6),\n      formattedWithdrawable: formatUnits(withdrawable, 6),\n    };\n  }\n\n  /**\n   * Deposit USDC into the Gateway Wallet.\n   *\n   * This method first approves the Gateway Wallet contract to spend USDC,\n   * then deposits the specified amount.\n   *\n   * @param amount - Amount of USDC to deposit (as a decimal string, e.g., \"10.5\")\n   * @param options - Optional deposit options\n   * @returns Deposit result with transaction hashes\n   */\n  async deposit(\n    amount: string,\n    options?: {\n      /** Amount to approve (defaults to amount) */\n      approveAmount?: string;\n      /** Skip approval if already approved */\n      skipApprovalCheck?: boolean;\n    },\n  ): Promise<DepositResult> {\n    const depositAmount = parseUnits(amount, 6);\n    const approveAmount = parseUnits(options?.approveAmount ?? amount, 6);\n\n    // Check balance\n    const { balance } = await this.getUsdcBalance();\n    if (balance < depositAmount) {\n      throw new Error(\n        `Insufficient USDC balance. Have: ${formatUnits(balance, 6)}, Need: ${amount}`,\n      );\n    }\n\n    let approvalTxHash: Hex | undefined;\n\n    // Check current allowance unless skipped\n    if (!options?.skipApprovalCheck) {\n      const allowance = await this.publicClient.readContract({\n        address: this.chainConfig.usdc,\n        abi: erc20Abi,\n        functionName: 'allowance',\n        args: [this.account.address, this.chainConfig.gatewayWallet],\n      });\n\n      if (allowance < depositAmount) {\n        // Approve the Gateway Wallet\n        approvalTxHash = await this.walletClient.writeContract({\n          address: this.chainConfig.usdc,\n          abi: erc20Abi,\n          functionName: 'approve',\n          args: [this.chainConfig.gatewayWallet, approveAmount],\n        });\n\n        try {\n          await this.publicClient.waitForTransactionReceipt({ hash: approvalTxHash });\n        } catch (err) {\n          throw new Error(`Approval transaction failed: ${approvalTxHash}`, {\n            cause: err,\n          });\n        }\n      }\n    }\n\n    // Deposit into Gateway Wallet\n    const depositTxHash = await this.walletClient.writeContract({\n      address: this.chainConfig.gatewayWallet,\n      abi: GATEWAY_WALLET_ABI,\n      functionName: 'deposit',\n      args: [this.chainConfig.usdc, depositAmount],\n      gas: 120000n,\n    });\n\n    try {\n      await this.publicClient.waitForTransactionReceipt({ hash: depositTxHash });\n    } catch (err) {\n      throw new Error(`Deposit transaction failed: ${depositTxHash}`, {\n        cause: err,\n      });\n    }\n\n    return {\n      approvalTxHash,\n      depositTxHash,\n      amount: depositAmount,\n      formattedAmount: amount,\n      depositor: this.account.address,\n    };\n  }\n\n  /**\n   * Deposit USDC into the Gateway Wallet on behalf of another address.\n   *\n   * The resulting balance belongs to the specified depositor address,\n   * not the caller.\n   *\n   * @param amount - Amount of USDC to deposit (as a decimal string)\n   * @param depositor - Address that will own the resulting balance\n   * @param options - Optional deposit options\n   * @returns Deposit result with transaction hashes\n   */\n  async depositFor(\n    amount: string,\n    depositor: Address,\n    options?: {\n      /** Amount to approve (defaults to amount) */\n      approveAmount?: string;\n      /** Skip approval if already approved */\n      skipApprovalCheck?: boolean;\n    },\n  ): Promise<DepositResult> {\n    const depositAmount = parseUnits(amount, 6);\n    const approveAmount = parseUnits(options?.approveAmount ?? amount, 6);\n\n    // Check balance\n    const { balance } = await this.getUsdcBalance();\n    if (balance < depositAmount) {\n      throw new Error(\n        `Insufficient USDC balance. Have: ${formatUnits(balance, 6)}, Need: ${amount}`,\n      );\n    }\n\n    let approvalTxHash: Hex | undefined;\n\n    // Check current allowance unless skipped\n    if (!options?.skipApprovalCheck) {\n      const allowance = await this.publicClient.readContract({\n        address: this.chainConfig.usdc,\n        abi: erc20Abi,\n        functionName: 'allowance',\n        args: [this.account.address, this.chainConfig.gatewayWallet],\n      });\n\n      if (allowance < depositAmount) {\n        // Approve the Gateway Wallet\n        approvalTxHash = await this.walletClient.writeContract({\n          address: this.chainConfig.usdc,\n          abi: erc20Abi,\n          functionName: 'approve',\n          args: [this.chainConfig.gatewayWallet, approveAmount],\n        });\n\n        try {\n          await this.publicClient.waitForTransactionReceipt({ hash: approvalTxHash });\n        } catch (err) {\n          throw new Error(`Approval transaction failed: ${approvalTxHash}`, {\n            cause: err,\n          });\n        }\n      }\n    }\n\n    // Deposit into Gateway Wallet for another address\n    const depositTxHash = await this.walletClient.writeContract({\n      address: this.chainConfig.gatewayWallet,\n      abi: GATEWAY_WALLET_ABI,\n      functionName: 'depositFor',\n      args: [this.chainConfig.usdc, depositor, depositAmount],\n      gas: 120000n,\n    });\n\n    try {\n      await this.publicClient.waitForTransactionReceipt({ hash: depositTxHash });\n    } catch (err) {\n      throw new Error(`Deposit transaction failed: ${depositTxHash}`, {\n        cause: err,\n      });\n    }\n\n    return {\n      approvalTxHash,\n      depositTxHash,\n      amount: depositAmount,\n      formattedAmount: amount,\n      depositor,\n    };\n  }\n\n  // ============================================================================\n  // PAYMENT (Pay for x402 resources)\n  // ============================================================================\n\n  /**\n   * Check if a URL supports Gateway batching before paying.\n   *\n   * @param url - The URL to check\n   * @returns Whether batching is supported and payment requirements\n   */\n  async supports(url: string): Promise<SupportsResult> {\n    try {\n      const response = await fetch(url);\n\n      if (response.status !== 402) {\n        return { supported: false, error: 'Resource does not require payment (not 402)' };\n      }\n\n      // x402 v2: Read from PAYMENT-REQUIRED header (base64-encoded)\n      const paymentRequiredHeader = response.headers.get('PAYMENT-REQUIRED');\n      if (!paymentRequiredHeader) {\n        return {\n          supported: false,\n          error: 'Missing PAYMENT-REQUIRED header in 402 response',\n        };\n      }\n      const data: { accepts?: Array<Record<string, unknown>> } = JSON.parse(\n        Buffer.from(paymentRequiredHeader, 'base64').toString('utf-8'),\n      );\n      const accepts = data.accepts;\n\n      if (!accepts || accepts.length === 0) {\n        return { supported: false, error: 'No payment options in 402 response' };\n      }\n\n      // Find a batching option matching this client's chain\n      const expectedNetwork = `eip155:${this.chainConfig.chain.id}`;\n      const batchingOption = accepts.find((opt) => {\n        const extra = opt.extra as Record<string, unknown> | undefined;\n        return (\n          opt.network === expectedNetwork &&\n          extra?.name === 'GatewayWalletBatched' &&\n          extra?.version === '1' &&\n          typeof extra?.verifyingContract === 'string'\n        );\n      });\n\n      if (!batchingOption) {\n        return {\n          supported: false,\n          error: `No Gateway batching option available for network ${expectedNetwork} (${this.chainConfig.chain.name})`,\n        };\n      }\n\n      return { supported: true, requirements: batchingOption };\n    } catch (error) {\n      return { supported: false, error: (error as Error).message };\n    }\n  }\n\n  /**\n   * Pay for an x402-protected resource.\n   *\n   * This method handles the full 402 payment flow automatically:\n   * 1. Makes initial request\n   * 2. If 402, finds Gateway batching option\n   * 3. Signs payment authorization\n   * 4. Retries with Payment-Signature header\n   *\n   * @param url - The URL to pay for\n   * @param options - Optional request options\n   * @returns The response data and payment info\n   *\n   * @example\n   * ```typescript\n   * const { data, amount } = await gateway.pay('https://api.example.com/resource');\n   * console.log('Paid', amount, 'USDC for:', data);\n   * ```\n   */\n  async pay<T = unknown>(\n    url: string,\n    options?: {\n      /** HTTP method (default: GET) */\n      method?: 'GET' | 'POST' | 'PUT' | 'DELETE';\n      /** Request body for POST/PUT */\n      body?: unknown;\n      /** Additional headers */\n      headers?: Record<string, string>;\n    },\n  ): Promise<PayResult<T>> {\n    const method = options?.method ?? 'GET';\n    const headers: Record<string, string> = {\n      'Content-Type': 'application/json',\n      ...options?.headers,\n    };\n    const serializedBody =\n      options?.body !== undefined\n        ? typeof options.body === 'string'\n          ? options.body\n          : JSON.stringify(options.body)\n        : undefined;\n\n    // Step 1: Make initial request\n    const initialResponse = await fetch(url, {\n      method,\n      headers,\n      body: serializedBody,\n    });\n\n    // If not 402, check if it's an error or success\n    if (initialResponse.status !== 402) {\n      if (initialResponse.ok) {\n        const data = (await initialResponse.json()) as T;\n        return {\n          data,\n          amount: 0n,\n          formattedAmount: '0',\n          transaction: '',\n          status: initialResponse.status,\n        };\n      }\n      throw new Error(`Request failed with status ${initialResponse.status}`);\n    }\n\n    // Step 2: Parse 402 response\n    // x402 v2: Read from PAYMENT-REQUIRED header (base64-encoded)\n    const paymentRequiredHeader = initialResponse.headers.get('PAYMENT-REQUIRED');\n    if (!paymentRequiredHeader) {\n      throw new Error('Missing PAYMENT-REQUIRED header in 402 response');\n    }\n    const paymentRequired = JSON.parse(\n      Buffer.from(paymentRequiredHeader, 'base64').toString('utf-8'),\n    ) as {\n      x402Version?: number;\n      accepts?: Array<Record<string, unknown>>;\n      resource?: Record<string, unknown>;\n    };\n    const accepts = paymentRequired.accepts;\n\n    if (!accepts || accepts.length === 0) {\n      throw new Error('No payment options in 402 response');\n    }\n\n    // Step 3: Find Gateway batching option matching this client's chain\n    const expectedNetwork = `eip155:${this.chainConfig.chain.id}`;\n    const batchingOption = accepts.find((opt) => {\n      const extra = opt.extra as Record<string, unknown> | undefined;\n      return (\n        opt.network === expectedNetwork &&\n        extra?.name === 'GatewayWalletBatched' &&\n        extra?.version === '1' &&\n        typeof extra?.verifyingContract === 'string'\n      );\n    });\n\n    if (!batchingOption) {\n      throw new Error(\n        `No Gateway batching option available for network ${expectedNetwork} (${this.chainConfig.chain.name}). The seller may not support this chain. Use supports() to check first.`,\n      );\n    }\n\n    // Step 4: Create, sign, and send the payment. `createPaymentPayload`\n    // (delegated to BatchEvmScheme) runs the onBefore/onAfter/onFailure payment\n    // hooks; `dispatchPaymentResponse` runs the onPaymentResponse hooks and may\n    // request a single retry with a fresh payload.\n    const x402Version = paymentRequired.x402Version ?? 2;\n    const amount = BigInt(batchingOption.amount as string);\n\n    for (let attempt = 0; ; attempt++) {\n      const paymentPayload = await this.batchScheme.createPaymentPayload(\n        x402Version,\n        batchingOption as unknown as Parameters<\n          BatchEvmScheme['createPaymentPayload']\n        >[1],\n      );\n\n      const paymentHeader = Buffer.from(\n        JSON.stringify({\n          ...paymentPayload,\n          resource: paymentRequired.resource,\n          accepted: batchingOption,\n        }),\n      ).toString('base64');\n\n      const paidResponse = await fetch(url, {\n        method,\n        headers: {\n          ...headers,\n          'Payment-Signature': paymentHeader,\n        },\n        body: serializedBody,\n      });\n\n      // x402 v2: settlement info lives in the PAYMENT-RESPONSE header\n      // (base64-encoded). Parse it once for both the response hook and result.\n      let settleResponse: { transaction?: string } | undefined;\n      const paymentResponseHeader = paidResponse.headers.get('PAYMENT-RESPONSE');\n      if (paymentResponseHeader) {\n        settleResponse = JSON.parse(\n          Buffer.from(paymentResponseHeader, 'base64').toString('utf-8'),\n        ) as { transaction?: string };\n      }\n\n      const responseContext: PaymentResponseContext = {\n        paymentPayload: {\n          x402Version: paymentPayload.x402Version,\n          payload: paymentPayload.payload as unknown as Record<string, unknown>,\n        },\n        requirements: batchingOption as unknown as PaymentResponseContext['requirements'],\n        paymentRequired:\n          paymentRequired as unknown as PaymentResponseContext['paymentRequired'],\n        settleResponse:\n          settleResponse as unknown as PaymentResponseContext['settleResponse'],\n        error: paidResponse.ok\n          ? undefined\n          : new Error(`Payment failed with status ${paidResponse.status}`),\n      };\n\n      const recovery = await this.batchScheme.dispatchPaymentResponse(responseContext);\n      // Honor a single retry request from an onPaymentResponse hook.\n      if (recovery?.recovered && attempt === 0) {\n        continue;\n      }\n\n      if (!paidResponse.ok) {\n        const error = await paidResponse.json().catch(() => ({}));\n        throw new Error(\n          `Payment failed: ${(error as { error?: string }).error || paidResponse.statusText}`,\n        );\n      }\n\n      const data = (await paidResponse.json()) as T;\n\n      return {\n        data,\n        amount,\n        formattedAmount: formatUnits(amount, 6),\n        transaction: settleResponse?.transaction ?? '',\n        status: paidResponse.status,\n      };\n    }\n  }\n\n  // ============================================================================\n  // WITHDRAW (Instant way to get USDC out)\n  // ============================================================================\n\n  /**\n   * Withdraw USDC from Gateway to your wallet.\n   *\n   * By default, withdraws to the same chain (instant, no 7-day delay).\n   * Optionally, withdraw to a different chain (requires gas on destination).\n   *\n   * @param amount - Amount of USDC to withdraw (as a decimal string)\n   * @param options - Optional withdrawal options\n   * @returns Withdrawal result with transaction hash\n   *\n   * @example\n   * ```typescript\n   * // Withdraw to same chain (instant!)\n   * await gateway.withdraw('50');\n   *\n   * // Withdraw to Base Sepolia (requires ETH on Base for gas)\n   * await gateway.withdraw('25', { chain: 'baseSepolia' });\n   * ```\n   */\n  async withdraw(\n    amount: string,\n    options?: {\n      /** Destination chain (defaults to same chain) */\n      chain?: SupportedChainName;\n      /** Recipient address (defaults to your address) */\n      recipient?: Address;\n      /** Max fee willing to pay in USDC (defaults to 2.01) */\n      maxFee?: string;\n    },\n  ): Promise<WithdrawResult> {\n    // Find destination chain config\n    const destinationChainName = options?.chain ?? this.getChainName();\n    const destConfig = CHAIN_CONFIGS[destinationChainName];\n    if (!destConfig) {\n      throw new Error(`Unsupported destination chain: ${destinationChainName}`);\n    }\n\n    const withdrawAmount = parseUnits(amount, 6);\n    const recipient = options?.recipient ?? this.account.address;\n    const maxFee = parseUnits(options?.maxFee ?? '2.01', 6);\n\n    // Check available balance\n    const balances = await this.getBalances();\n    if (balances.gateway.available < withdrawAmount) {\n      throw new Error(\n        `Insufficient available balance. Have: ${balances.gateway.formattedAvailable}, Need: ${amount}`,\n      );\n    }\n\n    // Create burn intent\n    const burnIntent = this.createBurnIntent(\n      this.chainConfig,\n      destConfig,\n      withdrawAmount,\n      recipient,\n      maxFee,\n    );\n\n    // Sign the burn intent\n    const signature = await this.account.signTypedData({\n      domain: { name: 'GatewayWallet', version: '1' },\n      types: {\n        EIP712Domain: [\n          { name: 'name', type: 'string' },\n          { name: 'version', type: 'string' },\n        ],\n        TransferSpec: [\n          { name: 'version', type: 'uint32' },\n          { name: 'sourceDomain', type: 'uint32' },\n          { name: 'destinationDomain', type: 'uint32' },\n          { name: 'sourceContract', type: 'bytes32' },\n          { name: 'destinationContract', type: 'bytes32' },\n          { name: 'sourceToken', type: 'bytes32' },\n          { name: 'destinationToken', type: 'bytes32' },\n          { name: 'sourceDepositor', type: 'bytes32' },\n          { name: 'destinationRecipient', type: 'bytes32' },\n          { name: 'sourceSigner', type: 'bytes32' },\n          { name: 'destinationCaller', type: 'bytes32' },\n          { name: 'value', type: 'uint256' },\n          { name: 'salt', type: 'bytes32' },\n          { name: 'hookData', type: 'bytes' },\n        ],\n        BurnIntent: [\n          { name: 'maxBlockHeight', type: 'uint256' },\n          { name: 'maxFee', type: 'uint256' },\n          { name: 'spec', type: 'TransferSpec' },\n        ],\n      },\n      primaryType: 'BurnIntent',\n      message: burnIntent,\n    });\n\n    // Get attestation from Gateway API\n    const apiUrl = this.isTestnet() ? GATEWAY_API_TESTNET : GATEWAY_API_MAINNET;\n    const response = await fetch(`${apiUrl}/transfer`, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        ...this.gatewayApiHeaders(),\n      },\n      body: JSON.stringify([{ burnIntent, signature }], (_, v) =>\n        typeof v === 'bigint' ? v.toString() : v,\n      ),\n    });\n\n    const result = (await response.json()) as {\n      success?: boolean;\n      error?: string;\n      message?: string;\n      attestation?: string;\n      signature?: string;\n    };\n\n    if (\n      result.success === false ||\n      result.error ||\n      !result.attestation ||\n      !result.signature\n    ) {\n      throw new Error(\n        `Gateway API error: ${result.message || result.error || JSON.stringify(result)}`,\n      );\n    }\n\n    // Create destination chain client for minting\n    const destTransport = destConfig.rpcUrl ? http(destConfig.rpcUrl) : http();\n    const destWalletClient = createWalletClient({\n      account: this.account,\n      chain: destConfig.chain,\n      transport: destTransport,\n    });\n    const destPublicClient = createPublicClient({\n      chain: destConfig.chain,\n      transport: destTransport,\n    });\n\n    // Mint on destination chain\n    const mintTxHash = await destWalletClient.writeContract({\n      address: destConfig.gatewayMinter,\n      abi: GATEWAY_MINTER_ABI,\n      functionName: 'gatewayMint',\n      args: [result.attestation as Hex, result.signature as Hex],\n    });\n\n    try {\n      await destPublicClient.waitForTransactionReceipt({ hash: mintTxHash });\n    } catch (err) {\n      throw new Error(`Mint transaction failed: ${mintTxHash}`, { cause: err });\n    }\n\n    return {\n      mintTxHash,\n      amount: withdrawAmount,\n      formattedAmount: amount,\n      sourceChain: this.chainConfig.chain.name,\n      destinationChain: destConfig.chain.name,\n      recipient,\n    };\n  }\n\n  /**\n   * Transfer USDC to any supported chain (alias for withdraw with destination chain).\n   * @deprecated Use `withdraw({ chain })` instead\n   */\n  async transfer(\n    amount: string,\n    destinationChain: SupportedChainName,\n    recipient?: Address,\n  ): Promise<WithdrawResult> {\n    return this.withdraw(amount, { chain: destinationChain, recipient });\n  }\n\n  /**\n   * Create a burn intent for a transfer.\n   */\n  private createBurnIntent(\n    from: ChainConfig,\n    to: ChainConfig,\n    value: bigint,\n    recipient: Address,\n    maxFee: bigint,\n  ) {\n    const addressToBytes32 = (addr: string): Hex =>\n      pad(addr.toLowerCase() as Address, { size: 32 });\n\n    return {\n      maxBlockHeight: maxUint256,\n      maxFee,\n      spec: {\n        version: 1,\n        sourceDomain: from.domain,\n        destinationDomain: to.domain,\n        sourceContract: addressToBytes32(from.gatewayWallet),\n        destinationContract: addressToBytes32(to.gatewayMinter),\n        sourceToken: addressToBytes32(from.usdc),\n        destinationToken: addressToBytes32(to.usdc),\n        sourceDepositor: addressToBytes32(this.account.address),\n        destinationRecipient: addressToBytes32(recipient),\n        sourceSigner: addressToBytes32(this.account.address),\n        destinationCaller: addressToBytes32(zeroAddress),\n        value,\n        salt: `0x${randomBytes(32).toString('hex')}` as Hex,\n        hookData: '0x' as Hex,\n      },\n    };\n  }\n\n  // ============================================================================\n  // TRANSFER QUERIES\n  // ============================================================================\n\n  /**\n   * Get a single x402 transfer by ID.\n   *\n   * @param id - The transfer UUID\n   * @returns Transfer object\n   */\n  async getTransferById(id: string): Promise<TransferResponse> {\n    const apiBaseUrl = this.isTestnet() ? GATEWAY_API_TESTNET : GATEWAY_API_MAINNET;\n    const response = await fetch(\n      `${apiBaseUrl}/x402/transfers/${encodeURIComponent(id)}`,\n      { method: 'GET', headers: this.gatewayApiHeaders() },\n    );\n\n    if (!response.ok) {\n      const errorText = await response.text().catch(() => response.statusText);\n      throw new Error(\n        `Gateway getTransferById failed (${response.status}): ${errorText}`,\n      );\n    }\n\n    return (await response.json()) as TransferResponse;\n  }\n\n  /**\n   * Search x402 transfers with optional filters.\n   *\n   * Supports cursor-based pagination via `pageAfter` / `pageBefore`.\n   * When `network` is omitted, defaults to the client's chain (e.g., `eip155:84532`).\n   * When `status` is provided, also provide `from`, `to`, or `nonce`.\n   *\n   * @param params - Optional transfer search filters\n   * @returns Paginated transfer search response\n   */\n  async searchTransfers(\n    params: SearchTransfersParams = {},\n  ): Promise<SearchTransfersResponse> {\n    const apiBaseUrl = this.isTestnet() ? GATEWAY_API_TESTNET : GATEWAY_API_MAINNET;\n\n    const query = new URLSearchParams();\n    if (params.from) query.set('from', params.from);\n    if (params.to) query.set('to', params.to);\n    if (params.nonce) query.set('nonce', params.nonce);\n    const network = params.network ?? `eip155:${this.chainConfig.chain.id}`;\n    query.set('network', network);\n    if (params.status) query.set('status', params.status);\n    if (params.token) query.set('token', params.token);\n    if (params.startDate) query.set('startDate', params.startDate);\n    if (params.endDate) query.set('endDate', params.endDate);\n    if (typeof params.pageSize === 'number')\n      query.set('pageSize', String(params.pageSize));\n    if (params.pageAfter) query.set('pageAfter', params.pageAfter);\n    if (params.pageBefore) query.set('pageBefore', params.pageBefore);\n\n    const path = `${apiBaseUrl}/x402/transfers`;\n    const queryString = query.toString().replaceAll('%3A', ':');\n    const url = queryString ? `${path}?${queryString}` : path;\n\n    const response = await fetch(url, {\n      method: 'GET',\n      headers: this.gatewayApiHeaders(),\n    });\n\n    if (!response.ok) {\n      const errorText = await response.text().catch(() => response.statusText);\n      throw new Error(\n        `Gateway searchTransfers failed (${response.status}): ${errorText}`,\n      );\n    }\n\n    const data = (await response.json()) as SearchTransfersResponse;\n    const linkHeader = response.headers?.get?.('Link') ?? null;\n    const pagination = this.parseLinkHeader(linkHeader);\n\n    if (!pagination) {\n      return data;\n    }\n\n    return { ...data, pagination };\n  }\n\n  // ============================================================================\n  // PRIVATE HELPERS\n  // ============================================================================\n\n  private gatewayApiHeaders(): Record<string, string> {\n    return this._headers;\n  }\n\n  /**\n   * Check if this client is connected to a testnet.\n   */\n  private isTestnet(): boolean {\n    const testnetChainIds = new Set<number>(\n      (\n        [\n          'arbitrumSepolia',\n          'arcTestnet',\n          'avalancheFuji',\n          'baseSepolia',\n          'sepolia',\n          'hyperEvmTestnet',\n          'optimismSepolia',\n          'polygonAmoy',\n          'seiAtlantic',\n          'sonicTestnet',\n          'unichainSepolia',\n          'worldChainSepolia',\n        ] as SupportedChainName[]\n      ).map((name) => CHAIN_CONFIGS[name].chain.id),\n    );\n    return testnetChainIds.has(this.chainConfig.chain.id);\n  }\n\n  /**\n   * Parse pagination from an RFC 5988 Link header.\n   * Could be replaced with 'http-link-header' library\n   *\n   * Example:\n   * <https://.../transfers?pageAfter=...>; rel=\"next\", <...>; rel=\"self\"\n   */\n  private parseLinkHeader(linkHeader: string | null): CursorPagination | undefined {\n    if (!linkHeader) {\n      return undefined;\n    }\n\n    const pagination: CursorPagination = {};\n    const linkRegex = /<([^>]+)>\\s*;\\s*rel=\"([^\"]+)\"/g;\n    let match: RegExpExecArray | null = linkRegex.exec(linkHeader);\n\n    while (match) {\n      const [, url, rel] = match;\n      if (rel === 'self' || rel === 'first' || rel === 'prev' || rel === 'next') {\n        pagination[rel] = url;\n      }\n      match = linkRegex.exec(linkHeader);\n    }\n\n    if (pagination.next) {\n      const cursor = this.getQueryParam(pagination.next, 'pageAfter');\n      if (cursor) pagination.pageAfter = cursor;\n    }\n    if (pagination.prev) {\n      const cursor = this.getQueryParam(pagination.prev, 'pageBefore');\n      if (cursor) pagination.pageBefore = cursor;\n    }\n\n    return Object.keys(pagination).length > 0 ? pagination : undefined;\n  }\n\n  private getQueryParam(url: string, key: string): string | undefined {\n    try {\n      return new URL(url).searchParams.get(key) ?? undefined;\n    } catch {\n      return undefined;\n    }\n  }\n\n  // ============================================================================\n  // TRUSTLESS WITHDRAWAL (Emergency use only)\n  // ============================================================================\n\n  /**\n   * Get the trustless withdrawal delay in blocks (~7 days).\n   *\n   * NOTE: This is for the emergency trustless withdrawal flow only.\n   * For normal withdrawals, use `transfer()` to the same chain.\n   *\n   * @returns Number of blocks to wait after initiating trustless withdrawal\n   */\n  async getTrustlessWithdrawalDelay(): Promise<bigint> {\n    return this.publicClient.readContract({\n      address: this.chainConfig.gatewayWallet,\n      abi: GATEWAY_WALLET_ABI,\n      functionName: 'withdrawalDelay',\n    });\n  }\n\n  /**\n   * Get the block at which a pending trustless withdrawal becomes available.\n   *\n   * @param address - Optional address to check (defaults to account address)\n   * @returns Block number, or 0n if no pending withdrawal\n   */\n  async getTrustlessWithdrawalBlock(address?: Address): Promise<bigint> {\n    const target = address ?? this.account.address;\n    return this.publicClient.readContract({\n      address: this.chainConfig.gatewayWallet,\n      abi: GATEWAY_WALLET_ABI,\n      functionName: 'withdrawalBlock',\n      args: [this.chainConfig.usdc, target],\n    });\n  }\n\n  /**\n   * Initiate a trustless withdrawal from the Gateway Wallet.\n   *\n   * ⚠️ **WARNING: This is for emergency use only!**\n   *\n   * Use this only when Circle's Gateway API is unavailable. For normal\n   * withdrawals, use `transfer()` to the same chain - it's instant.\n   *\n   * After calling this, you must wait ~7 days (`withdrawalDelay` blocks)\n   * before calling `completeTrustlessWithdrawal()`.\n   *\n   * @param amount - Amount of USDC to withdraw (as a decimal string)\n   * @returns Withdrawal initiation result\n   */\n  async initiateTrustlessWithdrawal(\n    amount: string,\n  ): Promise<TrustlessWithdrawalInitResult> {\n    const withdrawAmount = parseUnits(amount, 6);\n\n    // Check available balance\n    const balance = await this.getBalance();\n    if (balance.available < withdrawAmount) {\n      throw new Error(\n        `Insufficient available balance. Have: ${balance.formattedAvailable}, Need: ${amount}`,\n      );\n    }\n\n    // Initiate withdrawal\n    const txHash = await this.walletClient.writeContract({\n      address: this.chainConfig.gatewayWallet,\n      abi: GATEWAY_WALLET_ABI,\n      functionName: 'initiateWithdrawal',\n      args: [this.chainConfig.usdc, withdrawAmount],\n      gas: 100000n,\n    });\n\n    try {\n      await this.publicClient.waitForTransactionReceipt({ hash: txHash });\n    } catch (err) {\n      throw new Error(`Trustless withdrawal initiation failed: ${txHash}`, {\n        cause: err,\n      });\n    }\n\n    // Get the withdrawal block\n    const withdrawalBlock = await this.getTrustlessWithdrawalBlock();\n\n    return {\n      txHash,\n      amount: withdrawAmount,\n      formattedAmount: amount,\n      withdrawalBlock,\n    };\n  }\n\n  /**\n   * Complete a trustless withdrawal after the ~7-day delay period.\n   *\n   * ⚠️ **WARNING: This is for emergency use only!**\n   *\n   * Use this only when Circle's Gateway API is unavailable. For normal\n   * withdrawals, use `transfer()` to the same chain - it's instant.\n   *\n   * @returns Withdrawal result\n   */\n  async completeTrustlessWithdrawal(): Promise<TrustlessWithdrawalResult> {\n    // Check withdrawable balance\n    const balance = await this.getBalance();\n    if (balance.withdrawable === 0n) {\n      const withdrawalBlock = await this.getTrustlessWithdrawalBlock();\n      const currentBlock = await this.publicClient.getBlockNumber();\n\n      if (withdrawalBlock > 0n && currentBlock < withdrawalBlock) {\n        throw new Error(\n          `Trustless withdrawal not yet available. Current block: ${currentBlock}, Available at: ${withdrawalBlock}`,\n        );\n      }\n\n      throw new Error(\n        'No withdrawable balance. Call initiateTrustlessWithdrawal() first.',\n      );\n    }\n\n    const withdrawAmount = balance.withdrawable;\n\n    // Complete withdrawal\n    const txHash = await this.walletClient.writeContract({\n      address: this.chainConfig.gatewayWallet,\n      abi: GATEWAY_WALLET_ABI,\n      functionName: 'withdraw',\n      args: [this.chainConfig.usdc],\n      gas: 100000n,\n    });\n\n    try {\n      await this.publicClient.waitForTransactionReceipt({ hash: txHash });\n    } catch (err) {\n      throw new Error(`Trustless withdrawal completion failed: ${txHash}`, {\n        cause: err,\n      });\n    }\n\n    return {\n      txHash,\n      amount: withdrawAmount,\n      formattedAmount: formatUnits(withdrawAmount, 6),\n    };\n  }\n}\n","import type { Address, Hex } from 'viem';\nimport { getAddress } from 'viem';\nimport {\n  CIRCLE_BATCHING_NAME,\n  CIRCLE_BATCHING_VERSION,\n  CIRCLE_BATCHING_SCHEME,\n  GATEWAY_AUTH_VALIDITY_WINDOW_SECONDS,\n} from '../constants';\nimport { supportsBatching, getVerifyingContract } from '../detection';\nimport type { BatchEvmSigner, BatchPayload } from '../types';\nimport {\n  warnHookFailure,\n  type BeforePaymentCreationHook,\n  type AfterPaymentCreationHook,\n  type OnPaymentCreationFailureHook,\n  type OnPaymentResponseHook,\n  type PaymentCreationContext,\n  type PaymentCreatedContext,\n  type PaymentCreationFailureContext,\n  type PaymentResponseContext,\n  type HookPaymentRequired,\n  type HookPaymentRequirements,\n  type HookPaymentPayload,\n} from '../hooks';\n\n/**\n * EIP-712 types for TransferWithAuthorization.\n */\nconst authorizationTypes: Record<string, Array<{ name: string; type: string }>> = {\n  TransferWithAuthorization: [\n    { name: 'from', type: 'address' },\n    { name: 'to', type: 'address' },\n    { name: 'value', type: 'uint256' },\n    { name: 'validAfter', type: 'uint256' },\n    { name: 'validBefore', type: 'uint256' },\n    { name: 'nonce', type: 'bytes32' },\n  ],\n};\n\n/**\n * Generate a random 32-byte nonce for EIP-3009.\n */\nfunction createNonce(): Hex {\n  const bytes = new Uint8Array(32);\n  crypto.getRandomValues(bytes);\n  return `0x${Array.from(bytes)\n    .map((b) => b.toString(16).padStart(2, '0'))\n    .join('')}` as Hex;\n}\n\n/**\n * PaymentRequirements interface (minimal subset needed).\n */\ninterface PaymentRequirements {\n  scheme: string;\n  network: string;\n  asset: string;\n  amount: string;\n  payTo: string;\n  maxTimeoutSeconds: number;\n  extra?: Record<string, unknown>;\n}\n\n/**\n * PaymentPayload interface (minimal subset needed).\n */\ninterface PaymentPayload {\n  x402Version: number;\n  payload: BatchPayload;\n}\n\n/**\n * SchemeNetworkClient interface from @x402/core.\n */\ninterface SchemeNetworkClient {\n  readonly scheme: string;\n  createPaymentPayload(\n    x402Version: number,\n    paymentRequirements: PaymentRequirements,\n  ): Promise<Pick<PaymentPayload, 'x402Version' | 'payload'>>;\n}\n\n/**\n * Circle Batching EVM Scheme Client.\n *\n * A SchemeNetworkClient implementation for Circle Gateway batched payments.\n * Signs EIP-3009 TransferWithAuthorization against the GatewayWallet contract\n * (from `extra.verifyingContract`) instead of the USDC token contract.\n *\n * Lifecycle hooks (`onBeforePaymentCreation`, `onAfterPaymentCreation`,\n * `onPaymentCreationFailure`, `onPaymentResponse`) mirror the standard SDK's\n * `x402Client` semantics — see https://docs.x402.org/advanced-concepts/lifecycle-hooks.\n *\n * Hooks fire inside `createPaymentPayload` so that this scheme can be used\n * standalone (without `x402Client`). When wrapped by an `x402Client`, register\n * hooks at that level instead — running them in both places would double-fire.\n *\n * @example\n * ```typescript\n * import { BatchEvmScheme } from \"@circle-fin/x402-batching/client\";\n *\n * const scheme = new BatchEvmScheme(evmSigner)\n *   .onBeforePaymentCreation(async (ctx) => {\n *     if (BigInt(ctx.selectedRequirements.amount) > 10_000_000n) {\n *       return { abort: true, reason: \"Payment exceeds spending limit\" };\n *     }\n *   })\n *   .onAfterPaymentCreation(async (ctx) => {\n *     console.log(\"Signed payment\", ctx.paymentPayload);\n *   });\n * ```\n */\nexport class BatchEvmScheme implements SchemeNetworkClient {\n  readonly scheme = CIRCLE_BATCHING_SCHEME;\n\n  private beforePaymentCreationHooks: BeforePaymentCreationHook[] = [];\n  private afterPaymentCreationHooks: AfterPaymentCreationHook[] = [];\n  private onPaymentCreationFailureHooks: OnPaymentCreationFailureHook[] = [];\n  private paymentResponseHooks: OnPaymentResponseHook[] = [];\n\n  /**\n   * Creates a new BatchEvmScheme.\n   *\n   * @param signer - The EVM signer for signing payment authorizations\n   */\n  constructor(private readonly signer: BatchEvmSigner) {}\n\n  /**\n   * Register a hook that runs before payment payload creation. Returning\n   * `{ abort: true, reason }` causes `createPaymentPayload` to throw\n   * `Error(\"Payment creation aborted: <reason>\")`.\n   */\n  onBeforePaymentCreation(hook: BeforePaymentCreationHook): this {\n    this.beforePaymentCreationHooks.push(hook);\n    return this;\n  }\n\n  /**\n   * Register a hook that runs after a successful payment payload creation.\n   */\n  onAfterPaymentCreation(hook: AfterPaymentCreationHook): this {\n    this.afterPaymentCreationHooks.push(hook);\n    return this;\n  }\n\n  /**\n   * Register a hook that runs when payload creation throws. Return\n   * `{ recovered: true, payload }` to swallow the error and use the\n   * provided payload as the result instead.\n   */\n  onPaymentCreationFailure(hook: OnPaymentCreationFailureHook): this {\n    this.onPaymentCreationFailureHooks.push(hook);\n    return this;\n  }\n\n  /**\n   * Register a hook that runs after the buyer's paid HTTP request completes.\n   * Hooks fire when {@link dispatchPaymentResponse} is called by the\n   * transport. Return `{ recovered: true }` to instruct the transport to\n   * retry with a fresh payload.\n   */\n  onPaymentResponse(hook: OnPaymentResponseHook): this {\n    this.paymentResponseHooks.push(hook);\n    return this;\n  }\n\n  /**\n   * Fire all registered `onPaymentResponse` hooks in order. Returns\n   * `{ recovered: true }` if any hook signals recovery (first wins).\n   *\n   * Transport wrappers should call this after the paid HTTP request settles\n   * — see `x402HTTPClient.processPaymentResult` in the standard SDK.\n   */\n  async dispatchPaymentResponse(\n    context: PaymentResponseContext,\n  ): Promise<{ recovered: true } | undefined> {\n    for (const [index, hook] of this.paymentResponseHooks.entries()) {\n      try {\n        const result = await hook(context);\n        if (result && 'recovered' in result && result.recovered) {\n          return { recovered: true };\n        }\n      } catch (err) {\n        warnHookFailure(\n          'BatchEvmScheme',\n          'onPaymentResponse',\n          `manual hook #${index}`,\n          err,\n        );\n      }\n    }\n    return undefined;\n  }\n\n  /**\n   * Creates a payment payload for Circle batching.\n   *\n   * @param x402Version - The x402 protocol version\n   * @param paymentRequirements - The payment requirements (must be a Circle batching option)\n   * @returns Promise resolving to the payment payload\n   * @throws Error if requirements are not a Circle batching option\n   */\n  async createPaymentPayload(\n    x402Version: number,\n    paymentRequirements: PaymentRequirements,\n  ): Promise<Pick<PaymentPayload, 'x402Version' | 'payload'>> {\n    // Build the hook context once.\n    const context: PaymentCreationContext = {\n      paymentRequired: this.synthesizePaymentRequired(x402Version, paymentRequirements),\n      selectedRequirements: paymentRequirements as HookPaymentRequirements,\n    };\n\n    // beforePaymentCreation: any hook may abort.\n    for (const hook of this.beforePaymentCreationHooks) {\n      const result = await hook(context);\n      if (result && 'abort' in result && result.abort) {\n        throw new Error(`Payment creation aborted: ${result.reason}`);\n      }\n    }\n\n    try {\n      // Validate this is a Circle batching option\n      if (!supportsBatching(paymentRequirements)) {\n        throw new Error(\n          `BatchEvmScheme can only handle Circle batching options. ` +\n            `Expected extra.name=\"${CIRCLE_BATCHING_NAME}\" and extra.version=\"${CIRCLE_BATCHING_VERSION}\"`,\n        );\n      }\n\n      const verifyingContract = getVerifyingContract(paymentRequirements);\n      if (!verifyingContract) {\n        throw new Error(\n          'Circle batching option missing extra.verifyingContract (GatewayWallet address)',\n        );\n      }\n\n      const nonce = createNonce();\n      const now = Math.floor(Date.now() / 1000);\n      const validityWindowSeconds = Math.max(\n        paymentRequirements.maxTimeoutSeconds,\n        GATEWAY_AUTH_VALIDITY_WINDOW_SECONDS,\n      );\n\n      const authorization: BatchPayload['authorization'] = {\n        from: this.signer.address,\n        to: getAddress(paymentRequirements.payTo) as Address,\n        value: paymentRequirements.amount,\n        validAfter: (now - 600).toString(), // 10 minutes before\n        // Clamp seller-published timeouts so the signed authorization is always\n        // valid long enough for Gateway batching.\n        validBefore: (now + validityWindowSeconds).toString(),\n        nonce,\n      };\n\n      // Sign against GatewayWallet contract (not USDC)\n      const signature = await this.signAuthorization(\n        authorization,\n        paymentRequirements,\n        verifyingContract,\n      );\n\n      const payload: BatchPayload = {\n        authorization,\n        signature,\n      };\n\n      const partial = {\n        x402Version,\n        payload,\n      };\n\n      // afterPaymentCreation: synthesize a \"wrapped\" PaymentPayload to match\n      // the shape the standard SDK passes to its hooks.\n      const created: HookPaymentPayload = {\n        x402Version,\n        payload: payload as unknown as Record<string, unknown>,\n      };\n      const createdContext: PaymentCreatedContext = {\n        ...context,\n        paymentPayload: created,\n      };\n      for (const [index, hook] of this.afterPaymentCreationHooks.entries()) {\n        try {\n          await hook(createdContext);\n        } catch (err) {\n          warnHookFailure(\n            'BatchEvmScheme',\n            'afterPaymentCreation',\n            `manual hook #${index}`,\n            err,\n          );\n        }\n      }\n\n      return partial;\n    } catch (error) {\n      const failureContext: PaymentCreationFailureContext = {\n        ...context,\n        error: error as Error,\n      };\n      for (const hook of this.onPaymentCreationFailureHooks) {\n        const result = await hook(failureContext);\n        if (result && 'recovered' in result && result.recovered) {\n          return {\n            x402Version: result.payload.x402Version,\n            payload: result.payload.payload as unknown as BatchPayload,\n          };\n        }\n      }\n      throw error;\n    }\n  }\n\n  /**\n   * Sign the EIP-3009 authorization using EIP-712.\n   * Uses the GatewayWallet contract as verifyingContract instead of USDC.\n   */\n  private async signAuthorization(\n    authorization: BatchPayload['authorization'],\n    requirements: PaymentRequirements,\n    verifyingContract: string,\n  ): Promise<Hex> {\n    if (!requirements.network.startsWith('eip155:')) {\n      throw new Error(\n        `BatchEvmScheme: unsupported network format \"${requirements.network}\". Expected \"eip155:<chainId>\"`,\n      );\n    }\n    const chainId = parseInt(requirements.network.split(':')[1]);\n\n    const domain = {\n      name: CIRCLE_BATCHING_NAME,\n      version: CIRCLE_BATCHING_VERSION,\n      chainId,\n      verifyingContract: getAddress(verifyingContract) as Address,\n    };\n\n    const message = {\n      from: getAddress(authorization.from),\n      to: getAddress(authorization.to),\n      value: BigInt(authorization.value),\n      validAfter: BigInt(authorization.validAfter),\n      validBefore: BigInt(authorization.validBefore),\n      nonce: authorization.nonce,\n    };\n\n    return await this.signer.signTypedData({\n      domain,\n      types: authorizationTypes,\n      primaryType: 'TransferWithAuthorization',\n      message,\n    });\n  }\n\n  /**\n   * When `createPaymentPayload` is called directly (not through an x402Client),\n   * we don't have a real PaymentRequired response. Synthesize a minimal one\n   * so the hook context still carries the standard SDK's shape.\n   */\n  private synthesizePaymentRequired(\n    x402Version: number,\n    requirements: PaymentRequirements,\n  ): HookPaymentRequired {\n    return {\n      x402Version,\n      accepts: [requirements as HookPaymentRequirements],\n    };\n  }\n}\n","/**\n * EIP-712 domain name for Circle Gateway batched payments.\n * Used in the `extra.name` field of PaymentRequirements to identify Circle batching options.\n */\nexport const CIRCLE_BATCHING_NAME = 'GatewayWalletBatched';\n\n/**\n * EIP-712 domain version for Circle Gateway batched payments.\n * Used in the `extra.version` field of PaymentRequirements.\n */\nexport const CIRCLE_BATCHING_VERSION = '1';\n\n/**\n * The payment scheme used for Circle batching (same as standard x402 exact scheme).\n */\nexport const CIRCLE_BATCHING_SCHEME = 'exact';\n\n/**\n * Minimum authorization validity window required by Gateway batching.\n */\nexport const GATEWAY_MIN_AUTH_VALIDITY_SECONDS = 7 * 24 * 60 * 60;\n\n/**\n * Extra validity window so authorizations still satisfy Gateway's minimum\n * after client/server clock differences and request latency.\n */\nexport const GATEWAY_AUTH_VALIDITY_BUFFER_SECONDS = 100;\n\n/**\n * Authorization validity window the SDK should publish and sign with.\n */\nexport const GATEWAY_AUTH_VALIDITY_WINDOW_SECONDS =\n  GATEWAY_MIN_AUTH_VALIDITY_SECONDS + GATEWAY_AUTH_VALIDITY_BUFFER_SECONDS;\n","import { CIRCLE_BATCHING_NAME, CIRCLE_BATCHING_VERSION } from './constants';\n\n/**\n * PaymentRequirements-like structure for detection.\n * We only need the `extra` field to detect batching options.\n */\ninterface PaymentRequirementsLike {\n  extra?: Record<string, unknown>;\n}\n\n/**\n * Check if a PaymentRequirements object supports batched settlement.\n *\n * Batching options are identified by:\n * - `extra.name === \"GatewayWalletBatched\"`\n * - `extra.version === \"1\"`\n *\n * @param requirements - The payment requirements to check\n * @returns true if this supports batched settlement\n *\n * @example\n * ```typescript\n * import { supportsBatching } from \"@circle-fin/x402-batching\";\n *\n * if (supportsBatching(paymentRequirements)) {\n *   // This option uses batched settlement (gas-free for users!)\n * }\n * ```\n */\nexport function supportsBatching(requirements: PaymentRequirementsLike): boolean {\n  const extra = requirements.extra;\n  if (!extra) {\n    return false;\n  }\n\n  return extra.name === CIRCLE_BATCHING_NAME && extra.version === CIRCLE_BATCHING_VERSION;\n}\n\n/**\n * Check if a PaymentRequirements object is a batched payment.\n *\n * This is an alias for `supportsBatching`, intended for server-side/facilitator use.\n * Use this to route payments to the appropriate handler.\n *\n * @param requirements - The payment requirements to check\n * @returns true if this is a batched payment\n *\n * @example\n * ```typescript\n * import { isBatchPayment, BatchFacilitatorClient } from \"@circle-fin/x402-batching/server\";\n *\n * const gateway = new BatchFacilitatorClient();\n *\n * // In your facilitator's verify/settle handler:\n * if (isBatchPayment(requirements)) {\n *   return gateway.verify(payload, requirements);\n * }\n * // else: handle with existing on-chain logic\n * ```\n */\nexport const isBatchPayment = supportsBatching;\n\n/**\n * Get the verifyingContract address from batching requirements.\n *\n * @param requirements - The payment requirements\n * @returns The batch wallet contract address, or undefined if not a batching option\n */\nexport function getVerifyingContract(\n  requirements: PaymentRequirementsLike,\n): string | undefined {\n  if (!supportsBatching(requirements)) {\n    return undefined;\n  }\n\n  const verifyingContract = requirements.extra?.verifyingContract;\n  if (typeof verifyingContract === 'string') {\n    return verifyingContract;\n  }\n\n  return undefined;\n}\n","import type { IncomingMessage, ServerResponse } from 'http';\nimport { BatchFacilitatorClient } from './BatchFacilitatorClient';\nimport {\n  CIRCLE_BATCHING_SCHEME,\n  CIRCLE_BATCHING_NAME,\n  CIRCLE_BATCHING_VERSION,\n  GATEWAY_AUTH_VALIDITY_WINDOW_SECONDS,\n} from '../constants';\nimport {\n  warnHookFailure,\n  type BeforeVerifyHook,\n  type AfterVerifyHook,\n  type OnVerifyFailureHook,\n  type BeforeSettleHook,\n  type AfterSettleHook,\n  type OnSettleFailureHook,\n  type OnVerifiedPaymentCanceledHook,\n  type ProtectedRequestHook,\n  type ProtectedRequestContext,\n  type ProtectedRouteConfig,\n  type VerifyContext,\n  type VerifyResultContext,\n  type VerifyFailureContext,\n  type SettleContext,\n  type SettleResultContext,\n  type SettleFailureContext,\n  type VerifiedPaymentCancellationReason,\n  type VerifiedPaymentCanceledContext,\n  type HookVerifyResponse,\n  type HookSettleResponse,\n} from '../hooks';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\n/**\n * Supported network kind from facilitator.\n */\ninterface SupportedKind {\n  network: string;\n  extra?: {\n    verifyingContract?: string;\n    assets?: Array<{ address: string; symbol: string; decimals: number }>;\n    [key: string]: unknown;\n  };\n}\n\n/**\n * Extract the USDC token address from a SupportedKind's assets list.\n * Returns null if no USDC asset is found.\n */\nfunction getUsdcAddress(kind: SupportedKind): string | null {\n  const assets = kind.extra?.assets;\n  if (!assets || assets.length === 0) return null;\n  const usdc = assets.find((a) => a.symbol === 'USDC');\n  return usdc?.address ?? null;\n}\n\n/**\n * Configuration for Gateway middleware.\n */\nexport interface GatewayMiddlewareConfig {\n  /** Seller's wallet address to receive payments */\n  sellerAddress: string;\n  /**\n   * Networks to accept payments on.\n   * - If omitted, accepts payments on ALL Gateway-supported networks (recommended)\n   * - Can be a single network string or array of networks\n   * - Format: CAIP-2 (e.g., 'eip155:8453' for Base, 'eip155:5042002' for Arc Testnet)\n   */\n  networks?: string | string[];\n  /**\n   * Optional Gateway facilitator URL.\n   * Defaults to mainnet: \"https://gateway-api.circle.com\".\n   * For testnet, pass \"https://gateway-api-testnet.circle.com\".\n   */\n  facilitatorUrl?: string;\n  /** Additional headers merged into every outbound facilitator request. */\n  headers?: Record<string, string>;\n  /** Optional resource description */\n  description?: string;\n}\n\n/**\n * Payment requirements for 402 responses.\n */\nexport interface PaymentRequirements {\n  scheme: string;\n  network: string;\n  asset: string;\n  amount: string;\n  payTo: string;\n  maxTimeoutSeconds: number;\n  extra: {\n    name: string;\n    version: string;\n    verifyingContract: string;\n  };\n}\n\n/**\n * Express-compatible request with payment info.\n */\nexport interface PaymentRequest extends IncomingMessage {\n  payment?: {\n    /** Whether the payment was verified */\n    verified: boolean;\n    /** Payer's address */\n    payer: string;\n    /** Amount paid in smallest units */\n    amount: string;\n    /** Network the payment was made on */\n    network: string;\n    /** Transaction hash after settlement */\n    transaction?: string;\n  };\n  body?: unknown;\n}\n\n/**\n * Express-compatible response.\n */\nexport interface PaymentResponse extends ServerResponse {\n  json?: (data: unknown) => void;\n  status?: (code: number) => PaymentResponse;\n}\n\n/**\n * Express-compatible next function.\n */\nexport type NextFunction = (err?: unknown) => void;\n\n/**\n * Express-compatible middleware function.\n */\nexport type MiddlewareFunction = (\n  req: PaymentRequest,\n  res: PaymentResponse,\n  next: NextFunction,\n) => void | Promise<void>;\n\n// ============================================================================\n// MIDDLEWARE FACTORY\n// ============================================================================\n\n/**\n * Gateway middleware instance.\n *\n * The middleware exposes lifecycle hooks that mirror the standard SDK's\n * `x402ResourceServer` and `x402HTTPResourceServer`:\n *\n * - `onProtectedRequest` — runs first, before any payment processing. Can grant\n *   access without payment (e.g. API key auth) or deny outright (returns 403).\n * - `onBeforeVerify` / `onAfterVerify` / `onVerifyFailure` — wrap the verify call.\n * - `onBeforeSettle` / `onAfterSettle` / `onSettleFailure` — wrap the settle call.\n * - `onVerifiedPaymentCanceled` — fires when a payment was verified but the\n *   protected handler erred and we never settled. (Note: with this transport\n *   middleware, settlement happens inline before `next()` runs, so the\n *   cancellation hook only fires when the same request encounters a settle\n *   failure that aborts further processing.)\n *\n * See https://docs.x402.org/advanced-concepts/lifecycle-hooks for the\n * canonical reference. All hooks return promises and can be chained.\n */\nexport interface GatewayMiddleware {\n  /**\n   * Require payment for a resource.\n   *\n   * @param price - Price in dollars (e.g., '$0.01' or '0.01')\n   * @returns Express-compatible middleware\n   *\n   * @example\n   * ```typescript\n   * app.get('/resource', gateway.require('$0.01'), (req, res) => {\n   *   res.json({ content: '...' });\n   * });\n   *\n   * app.post('/generate', gateway.require('$0.05'), (req, res) => {\n   *   res.json({ result: '...' });\n   * });\n   * ```\n   */\n  require: (price: string) => MiddlewareFunction;\n\n  /**\n   * Verify a payment without settling.\n   */\n  verify: (\n    payment: unknown,\n  ) => Promise<{ valid: boolean; payer?: string; error?: string }>;\n\n  /**\n   * Settle a verified payment.\n   */\n  settle: (\n    payment: unknown,\n  ) => Promise<{ success: boolean; transaction?: string; error?: string }>;\n\n  /** See {@link GatewayMiddleware} for hook semantics. */\n  onProtectedRequest: (hook: ProtectedRequestHook) => GatewayMiddleware;\n  /** See {@link GatewayMiddleware} for hook semantics. */\n  onBeforeVerify: (hook: BeforeVerifyHook) => GatewayMiddleware;\n  /** See {@link GatewayMiddleware} for hook semantics. */\n  onAfterVerify: (hook: AfterVerifyHook) => GatewayMiddleware;\n  /** See {@link GatewayMiddleware} for hook semantics. */\n  onVerifyFailure: (hook: OnVerifyFailureHook) => GatewayMiddleware;\n  /** See {@link GatewayMiddleware} for hook semantics. */\n  onBeforeSettle: (hook: BeforeSettleHook) => GatewayMiddleware;\n  /** See {@link GatewayMiddleware} for hook semantics. */\n  onAfterSettle: (hook: AfterSettleHook) => GatewayMiddleware;\n  /** See {@link GatewayMiddleware} for hook semantics. */\n  onSettleFailure: (hook: OnSettleFailureHook) => GatewayMiddleware;\n  /** See {@link GatewayMiddleware} for hook semantics. */\n  onVerifiedPaymentCanceled: (hook: OnVerifiedPaymentCanceledHook) => GatewayMiddleware;\n}\n\n/**\n * Parse a price string (e.g., '$0.01' or '0.01') to atomic units.\n */\nfunction parsePrice(price: string): string {\n  const numericPrice = price.replace(/[$]/g, '');\n  const amount = parseFloat(numericPrice);\n  if (isNaN(amount) || amount <= 0) {\n    throw new Error(`Invalid price: ${price}`);\n  }\n  // Convert to USDC atomic units (6 decimals)\n  return Math.round(amount * 1_000_000).toString();\n}\n\n/**\n * Build a `ProtectedRequestContext` from the raw IncomingMessage.\n */\nfunction buildProtectedRequestContext(req: PaymentRequest): ProtectedRequestContext {\n  const url = req.url ?? '/';\n  const path = url.split(/[?#]/)[0];\n  return {\n    method: (req.method ?? 'GET').toUpperCase(),\n    path,\n    url,\n    getHeader: (name: string) => {\n      const v = req.headers[name.toLowerCase()];\n      if (Array.isArray(v)) return v[0];\n      return v as string | undefined;\n    },\n  };\n}\n\n/**\n * Create a Gateway middleware instance.\n *\n * By default, accepts payments on ALL Gateway-supported networks. Buyers can\n * pay from any chain where they have Gateway balance.\n *\n * @param config - Middleware configuration\n * @returns Gateway middleware\n *\n * @example\n * ```typescript\n * import express from 'express';\n * import { createGatewayMiddleware } from '@circle-fin/x402-batching/server';\n *\n * const app = express();\n *\n * // Accept payments on all Gateway-supported networks (recommended)\n * const gateway = createGatewayMiddleware({\n *   sellerAddress: '0x...',\n * });\n *\n * // Or restrict to specific networks\n * const gateway = createGatewayMiddleware({\n *   sellerAddress: '0x...',\n *   networks: ['eip155:5042002', 'eip155:84532'], // Arc Testnet + Base Sepolia\n * });\n *\n * app.get('/resource', gateway.require('$0.01'), (req, res) => {\n *   res.json({ content: 'Paid content!' });\n * });\n *\n * // Bypass payment for callers carrying an API key\n * gateway.onProtectedRequest(async (ctx) => {\n *   if (await isValidApiKey(ctx.getHeader('x-api-key'))) {\n *     return { grantAccess: true };\n *   }\n * });\n * ```\n */\nexport function createGatewayMiddleware(\n  config: GatewayMiddlewareConfig,\n): GatewayMiddleware {\n  const facilitator = new BatchFacilitatorClient({\n    url: config.facilitatorUrl,\n    headers: config.headers,\n  });\n\n  // Normalize networks config\n  const configuredNetworks = config.networks\n    ? Array.isArray(config.networks)\n      ? config.networks\n      : [config.networks]\n    : null; // null means \"all networks\"\n\n  // Cache supported kinds from facilitator\n  let cachedSupportedKinds: SupportedKind[] | null = null;\n\n  async function getSupportedKinds(): Promise<SupportedKind[]> {\n    if (cachedSupportedKinds) {\n      return cachedSupportedKinds;\n    }\n\n    const supported = await facilitator.getSupported();\n    cachedSupportedKinds = supported.kinds as SupportedKind[];\n    return cachedSupportedKinds;\n  }\n\n  /**\n   * Get networks to advertise in 402 response.\n   */\n  async function getAcceptedNetworks(): Promise<SupportedKind[]> {\n    const allKinds = await getSupportedKinds();\n\n    // Filter to configured networks if specified, otherwise use all\n    if (configuredNetworks) {\n      return allKinds.filter(\n        (k) => configuredNetworks.includes(k.network) && k.extra?.verifyingContract,\n      );\n    }\n\n    // Return all networks with verifying contracts\n    return allKinds.filter((k) => k.extra?.verifyingContract);\n  }\n\n  /**\n   * Create payment requirements for all accepted networks.\n   */\n  async function createAllPaymentRequirements(\n    price: string,\n  ): Promise<PaymentRequirements[]> {\n    const networks = await getAcceptedNetworks();\n    const amount = parsePrice(price);\n\n    return networks\n      .filter((kind) => getUsdcAddress(kind)) // Only include networks we have USDC addresses for\n      .map((kind) => ({\n        scheme: CIRCLE_BATCHING_SCHEME, // Must be 'exact' for Gateway API\n        network: kind.network,\n        asset: getUsdcAddress(kind)!, // Use actual USDC address\n        amount,\n        payTo: config.sellerAddress,\n        maxTimeoutSeconds: GATEWAY_AUTH_VALIDITY_WINDOW_SECONDS, // 7 days plus verification latency buffer\n        extra: {\n          name: CIRCLE_BATCHING_NAME,\n          version: CIRCLE_BATCHING_VERSION,\n          verifyingContract: kind.extra!.verifyingContract as string,\n        },\n      }));\n  }\n\n  /**\n   * Create payment requirements for a specific network.\n   */\n  async function createPaymentRequirements(\n    price: string,\n    network: string,\n  ): Promise<PaymentRequirements | null> {\n    const networks = await getAcceptedNetworks();\n    const kind = networks.find((k) => k.network === network);\n\n    if (!kind || !kind.extra?.verifyingContract) {\n      return null;\n    }\n\n    const usdcAddress = getUsdcAddress(kind);\n    if (!usdcAddress) {\n      return null;\n    }\n\n    return {\n      scheme: CIRCLE_BATCHING_SCHEME, // Must be 'exact' for Gateway API\n      network: kind.network,\n      asset: usdcAddress, // Use actual USDC address\n      amount: parsePrice(price),\n      payTo: config.sellerAddress,\n      maxTimeoutSeconds: GATEWAY_AUTH_VALIDITY_WINDOW_SECONDS, // 7 days plus verification latency buffer\n      extra: {\n        name: CIRCLE_BATCHING_NAME,\n        version: CIRCLE_BATCHING_VERSION,\n        verifyingContract: kind.extra.verifyingContract as string,\n      },\n    };\n  }\n\n  // ==========================================================================\n  // Hook registries\n  // ==========================================================================\n\n  const protectedRequestHooks: ProtectedRequestHook[] = [];\n  const beforeVerifyHooks: BeforeVerifyHook[] = [];\n  const afterVerifyHooks: AfterVerifyHook[] = [];\n  const onVerifyFailureHooks: OnVerifyFailureHook[] = [];\n  const beforeSettleHooks: BeforeSettleHook[] = [];\n  const afterSettleHooks: AfterSettleHook[] = [];\n  const onSettleFailureHooks: OnSettleFailureHook[] = [];\n  const onVerifiedPaymentCanceledHooks: OnVerifiedPaymentCanceledHook[] = [];\n\n  // Run after-verify hooks. Returns a `skipHandler` directive if any hook\n  // requested the resource handler be bypassed.\n  async function runAfterVerifyHooks(\n    context: VerifyContext,\n    verifyResult: HookVerifyResponse,\n  ): Promise<{ contentType?: string; body?: unknown } | undefined> {\n    const resultContext: VerifyResultContext = { ...context, result: verifyResult };\n    let skipHandler: { contentType?: string; body?: unknown } | undefined;\n    for (const [index, hook] of afterVerifyHooks.entries()) {\n      try {\n        const directive = await hook(resultContext);\n        if (directive && 'skipHandler' in directive && directive.skipHandler) {\n          skipHandler = directive.response ?? {};\n        }\n      } catch (err) {\n        warnHookFailure('GatewayMiddleware', 'afterVerify', `manual hook #${index}`, err);\n      }\n    }\n    return skipHandler;\n  }\n\n  // Run a verify lifecycle (beforeVerify → facilitator.verify → afterVerify\n  // | onVerifyFailure). Returns either a verify response (with optional\n  // `skipHandler` directive) or an `aborted` marker.\n  async function runVerifyLifecycle(\n    paymentPayload: { x402Version: number; payload: Record<string, unknown> },\n    requirements: PaymentRequirements,\n  ): Promise<\n    | {\n        kind: 'verified';\n        result: HookVerifyResponse;\n        skipHandler?: { contentType?: string; body?: unknown };\n      }\n    | { kind: 'aborted'; reason: string; message?: string }\n    | { kind: 'failed'; result: HookVerifyResponse }\n    | { kind: 'thrown'; error: Error }\n  > {\n    const context: VerifyContext = {\n      paymentPayload,\n      requirements,\n    };\n\n    for (const [index, hook] of beforeVerifyHooks.entries()) {\n      try {\n        const result = await hook(context);\n        if (result && 'abort' in result && result.abort) {\n          return { kind: 'aborted', reason: result.reason, message: result.message };\n        }\n        if (result && 'skip' in result && result.skip) {\n          const skipHandler = await runAfterVerifyHooks(context, result.result);\n          return { kind: 'verified', result: result.result, skipHandler };\n        }\n      } catch (err) {\n        warnHookFailure(\n          'GatewayMiddleware',\n          'beforeVerify',\n          `manual hook #${index}`,\n          err,\n        );\n      }\n    }\n\n    try {\n      const verifyResult = await facilitator.verify(paymentPayload, requirements);\n\n      if (!verifyResult.isValid) {\n        // failed verify — run onVerifyFailure\n        const failureContext: VerifyFailureContext = {\n          ...context,\n          error: new Error(verifyResult.invalidReason || 'Verification failed'),\n        };\n        for (const hook of onVerifyFailureHooks) {\n          try {\n            const recovery = await hook(failureContext);\n            if (recovery && 'recovered' in recovery && recovery.recovered) {\n              const skipHandler = await runAfterVerifyHooks(context, recovery.result);\n              return { kind: 'verified', result: recovery.result, skipHandler };\n            }\n          } catch (err) {\n            warnHookFailure('GatewayMiddleware', 'onVerifyFailure', 'manual hook', err);\n          }\n        }\n        return { kind: 'failed', result: verifyResult };\n      }\n\n      const skipHandler = await runAfterVerifyHooks(context, verifyResult);\n      return { kind: 'verified', result: verifyResult, skipHandler };\n    } catch (error) {\n      const failureContext: VerifyFailureContext = {\n        ...context,\n        error: error as Error,\n      };\n      for (const hook of onVerifyFailureHooks) {\n        try {\n          const recovery = await hook(failureContext);\n          if (recovery && 'recovered' in recovery && recovery.recovered) {\n            const skipHandler = await runAfterVerifyHooks(context, recovery.result);\n            return { kind: 'verified', result: recovery.result, skipHandler };\n          }\n        } catch (err) {\n          warnHookFailure('GatewayMiddleware', 'onVerifyFailure', 'manual hook', err);\n        }\n      }\n      return { kind: 'thrown', error: error as Error };\n    }\n  }\n\n  // Run a settle lifecycle (beforeSettle → facilitator.settle → afterSettle\n  // | onSettleFailure). Returns either a settle response or a control-flow\n  // directive equivalent to the standard SDK's behavior.\n  async function runSettleLifecycle(\n    paymentPayload: { x402Version: number; payload: Record<string, unknown> },\n    requirements: PaymentRequirements,\n  ): Promise<\n    | { kind: 'settled'; result: HookSettleResponse }\n    | { kind: 'aborted'; reason: string; message?: string }\n    | { kind: 'thrown'; error: Error }\n  > {\n    const context: SettleContext = {\n      paymentPayload,\n      requirements,\n    };\n\n    for (const [index, hook] of beforeSettleHooks.entries()) {\n      try {\n        const result = await hook(context);\n        if (result && 'abort' in result && result.abort) {\n          return { kind: 'aborted', reason: result.reason, message: result.message };\n        }\n        if (result && 'skip' in result && result.skip) {\n          const skipResultContext: SettleResultContext = {\n            ...context,\n            result: result.result,\n          };\n          for (const [idx, after] of afterSettleHooks.entries()) {\n            try {\n              await after(skipResultContext);\n            } catch (err) {\n              warnHookFailure(\n                'GatewayMiddleware',\n                'afterSettle',\n                `manual hook #${idx}`,\n                err,\n              );\n            }\n          }\n          return { kind: 'settled', result: result.result };\n        }\n      } catch (err) {\n        warnHookFailure(\n          'GatewayMiddleware',\n          'beforeSettle',\n          `manual hook #${index}`,\n          err,\n        );\n      }\n    }\n\n    try {\n      const settleResult = await facilitator.settle(paymentPayload, requirements);\n      const resultContext: SettleResultContext = { ...context, result: settleResult };\n\n      for (const [index, hook] of afterSettleHooks.entries()) {\n        try {\n          await hook(resultContext);\n        } catch (err) {\n          warnHookFailure(\n            'GatewayMiddleware',\n            'afterSettle',\n            `manual hook #${index}`,\n            err,\n          );\n        }\n      }\n\n      return { kind: 'settled', result: settleResult };\n    } catch (error) {\n      const failureContext: SettleFailureContext = {\n        ...context,\n        error: error as Error,\n      };\n      for (const hook of onSettleFailureHooks) {\n        try {\n          const recovery = await hook(failureContext);\n          if (recovery && 'recovered' in recovery && recovery.recovered) {\n            return { kind: 'settled', result: recovery.result };\n          }\n        } catch (err) {\n          warnHookFailure('GatewayMiddleware', 'onSettleFailure', 'manual hook', err);\n        }\n      }\n      return { kind: 'thrown', error: error as Error };\n    }\n  }\n\n  // Notify `onVerifiedPaymentCanceled` hooks that a verified payment never\n  // reached settlement (e.g. because the protected handler threw, or\n  // settlement itself failed in a non-recoverable way).\n  async function dispatchVerifiedPaymentCanceled(\n    paymentPayload: { x402Version: number; payload: Record<string, unknown> },\n    requirements: PaymentRequirements,\n    options: {\n      reason: VerifiedPaymentCancellationReason;\n      error?: unknown;\n      responseStatus?: number;\n    },\n  ): Promise<void> {\n    const context: VerifiedPaymentCanceledContext = {\n      paymentPayload,\n      requirements,\n      reason: options.reason,\n      error: options.error,\n      responseStatus: options.responseStatus,\n    };\n    for (const [index, hook] of onVerifiedPaymentCanceledHooks.entries()) {\n      try {\n        await hook(context);\n      } catch (err) {\n        warnHookFailure(\n          'GatewayMiddleware',\n          'onVerifiedPaymentCanceled',\n          `manual hook #${index}`,\n          err,\n        );\n      }\n    }\n  }\n\n  // ==========================================================================\n  // Middleware\n  // ==========================================================================\n\n  const api: GatewayMiddleware = {\n    require: (price: string): MiddlewareFunction => {\n      const routeConfig: ProtectedRouteConfig = { price };\n      return async (req, res, next) => {\n        try {\n          // ----- onProtectedRequest --------------------------------------\n          const requestContext = buildProtectedRequestContext(req);\n          for (const [index, hook] of protectedRequestHooks.entries()) {\n            try {\n              const result = await hook(requestContext, routeConfig);\n              if (result && 'grantAccess' in result && result.grantAccess) {\n                next();\n                return;\n              }\n              if (result && 'abort' in result && result.abort) {\n                res.statusCode = 403;\n                res.setHeader('Content-Type', 'application/json');\n                res.end(JSON.stringify({ error: result.reason }));\n                return;\n              }\n            } catch (err) {\n              warnHookFailure(\n                'GatewayMiddleware',\n                'onProtectedRequest',\n                `manual hook #${index}`,\n                err,\n              );\n            }\n          }\n\n          // Check for payment header\n          const paymentHeader = req.headers['payment-signature'] as string | undefined;\n\n          if (!paymentHeader) {\n            // Return 402 Payment Required with all accepted networks\n            const allRequirements = await createAllPaymentRequirements(price);\n            const url = req.url ?? '/';\n            const description = config.description ?? 'Paid resource';\n\n            if (allRequirements.length === 0) {\n              res.statusCode = 503;\n              res.setHeader('Content-Type', 'application/json');\n              res.end(JSON.stringify({ error: 'No payment networks available' }));\n              return;\n            }\n\n            const paymentRequired = {\n              x402Version: 2, // Version 2 required by Gateway API\n              resource: {\n                url,\n                description,\n                mimeType: 'application/json',\n              },\n              accepts: allRequirements,\n            };\n\n            // x402 v2: Payment required info goes in PAYMENT-REQUIRED header (base64-encoded)\n            const paymentRequiredHeader = Buffer.from(\n              JSON.stringify(paymentRequired),\n            ).toString('base64');\n\n            res.statusCode = 402;\n            res.setHeader('PAYMENT-REQUIRED', paymentRequiredHeader);\n            res.setHeader('Content-Type', 'application/json');\n            res.end(JSON.stringify({}));\n            return;\n          }\n\n          // Decode payment\n          const paymentPayload = JSON.parse(\n            Buffer.from(paymentHeader, 'base64').toString('utf-8'),\n          );\n          const acceptedRequirements = paymentPayload.accepted as\n            | PaymentRequirements\n            | undefined;\n\n          if (!acceptedRequirements?.network) {\n            res.statusCode = 400;\n            res.setHeader('Content-Type', 'application/json');\n            res.end(\n              JSON.stringify({ error: 'Missing accepted requirements in payment' }),\n            );\n            return;\n          }\n\n          // Create requirements for the network the buyer chose\n          const requirements = await createPaymentRequirements(\n            price,\n            acceptedRequirements.network,\n          );\n\n          if (!requirements) {\n            res.statusCode = 400;\n            res.setHeader('Content-Type', 'application/json');\n            res.end(\n              JSON.stringify({\n                error: `Network ${acceptedRequirements.network} not accepted`,\n              }),\n            );\n            return;\n          }\n\n          // ----- verify lifecycle ----------------------------------------\n          const verify = await runVerifyLifecycle(paymentPayload, requirements);\n\n          if (verify.kind === 'aborted') {\n            res.statusCode = 402;\n            res.setHeader('Content-Type', 'application/json');\n            res.end(\n              JSON.stringify({\n                error: 'Payment verification aborted',\n                reason: verify.reason,\n                ...(verify.message ? { message: verify.message } : {}),\n              }),\n            );\n            return;\n          }\n\n          if (verify.kind === 'failed') {\n            res.statusCode = 402;\n            res.setHeader('Content-Type', 'application/json');\n            res.end(\n              JSON.stringify({\n                error: 'Payment verification failed',\n                reason: verify.result.invalidReason,\n              }),\n            );\n            return;\n          }\n\n          if (verify.kind === 'thrown') {\n            throw verify.error;\n          }\n\n          const verifyResult = verify.result;\n          const skipHandlerDirective = verify.skipHandler;\n\n          // ----- settle lifecycle ----------------------------------------\n          const settle = await runSettleLifecycle(paymentPayload, requirements);\n\n          if (settle.kind === 'aborted') {\n            await dispatchVerifiedPaymentCanceled(paymentPayload, requirements, {\n              reason: 'handler_failed',\n              responseStatus: 402,\n            });\n            res.statusCode = 402;\n            res.setHeader('Content-Type', 'application/json');\n            res.end(\n              JSON.stringify({\n                error: 'Payment settlement aborted',\n                reason: settle.reason,\n                ...(settle.message ? { message: settle.message } : {}),\n              }),\n            );\n            return;\n          }\n\n          if (settle.kind === 'thrown') {\n            await dispatchVerifiedPaymentCanceled(paymentPayload, requirements, {\n              reason: 'handler_failed',\n              error: settle.error,\n              responseStatus: 402,\n            });\n            throw settle.error;\n          }\n\n          const settleResult = settle.result;\n\n          if (!settleResult.success) {\n            await dispatchVerifiedPaymentCanceled(paymentPayload, requirements, {\n              reason: 'handler_failed',\n              responseStatus: 402,\n            });\n            res.statusCode = 402;\n            res.setHeader('Content-Type', 'application/json');\n            res.end(\n              JSON.stringify({\n                error: 'Payment settlement failed',\n                reason: settleResult.errorReason,\n              }),\n            );\n            return;\n          }\n\n          // Attach payment info to request\n          req.payment = {\n            verified: true,\n            payer: settleResult.payer ?? verifyResult.payer ?? '',\n            amount: parsePrice(price),\n            network: requirements.network,\n            transaction: settleResult.transaction,\n          };\n\n          // x402 v2: Settlement response goes in PAYMENT-RESPONSE header (base64-encoded)\n          const settleResponseHeader = Buffer.from(\n            JSON.stringify({\n              success: true,\n              transaction: settleResult.transaction,\n              network: requirements.network,\n              payer: settleResult.payer ?? verifyResult.payer ?? '',\n            }),\n          ).toString('base64');\n          res.setHeader('PAYMENT-RESPONSE', settleResponseHeader);\n\n          // If a verify hook requested the protected handler be skipped, write\n          // a 200 response now and bypass `next()`. Mirrors x402HTTPResourceServer's\n          // processSkipHandlerSettlement.\n          if (skipHandlerDirective) {\n            const contentType = skipHandlerDirective.contentType ?? 'application/json';\n            const body = skipHandlerDirective.body ?? {};\n            res.statusCode = 200;\n            res.setHeader('Content-Type', contentType);\n            res.end(typeof body === 'string' ? body : JSON.stringify(body));\n            return;\n          }\n\n          // Hand off to protected handler. If it throws synchronously, treat\n          // it as a verified-payment-canceled scenario.\n          try {\n            await Promise.resolve(next());\n          } catch (handlerError) {\n            await dispatchVerifiedPaymentCanceled(paymentPayload, requirements, {\n              reason: 'handler_threw',\n              error: handlerError,\n            });\n            throw handlerError;\n          }\n        } catch (error) {\n          res.statusCode = 500;\n          res.setHeader('Content-Type', 'application/json');\n          res.end(\n            JSON.stringify({\n              error: 'Payment processing error',\n              message: (error as Error).message,\n            }),\n          );\n        }\n      };\n    },\n\n    verify: async (payment) => {\n      try {\n        const paymentPayload = payment as {\n          paymentPayload: unknown;\n          paymentRequirements: PaymentRequirements;\n        };\n        const result = await facilitator.verify(\n          paymentPayload.paymentPayload as Parameters<typeof facilitator.verify>[0],\n          paymentPayload.paymentRequirements,\n        );\n        return {\n          valid: result.isValid,\n          payer: result.payer,\n          error: result.invalidReason,\n        };\n      } catch (error) {\n        return {\n          valid: false,\n          error: (error as Error).message,\n        };\n      }\n    },\n\n    settle: async (payment) => {\n      try {\n        const paymentPayload = payment as {\n          paymentPayload: unknown;\n          paymentRequirements: PaymentRequirements;\n        };\n        const result = await facilitator.settle(\n          paymentPayload.paymentPayload as Parameters<typeof facilitator.settle>[0],\n          paymentPayload.paymentRequirements,\n        );\n        return {\n          success: result.success,\n          transaction: result.transaction,\n          error: result.errorReason,\n        };\n      } catch (error) {\n        return {\n          success: false,\n          error: (error as Error).message,\n        };\n      }\n    },\n\n    onProtectedRequest: (hook) => {\n      protectedRequestHooks.push(hook);\n      return api;\n    },\n    onBeforeVerify: (hook) => {\n      beforeVerifyHooks.push(hook);\n      return api;\n    },\n    onAfterVerify: (hook) => {\n      afterVerifyHooks.push(hook);\n      return api;\n    },\n    onVerifyFailure: (hook) => {\n      onVerifyFailureHooks.push(hook);\n      return api;\n    },\n    onBeforeSettle: (hook) => {\n      beforeSettleHooks.push(hook);\n      return api;\n    },\n    onAfterSettle: (hook) => {\n      afterSettleHooks.push(hook);\n      return api;\n    },\n    onSettleFailure: (hook) => {\n      onSettleFailureHooks.push(hook);\n      return api;\n    },\n    onVerifiedPaymentCanceled: (hook) => {\n      onVerifiedPaymentCanceledHooks.push(hook);\n      return api;\n    },\n  };\n\n  return api;\n}\n"],"mappings":"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","names":["base","skipHandler"]}