{"version":3,"sources":["../../src/protocol/escrow.ts"],"sourcesContent":["/**\n * DPv2 escrow payment helpers.\n *\n * Covers the three-phase flow used by builders to pay for data access:\n *\n *  1. **Deposit** — call `depositNative` or `depositToken` on the\n *     DataPortabilityEscrow contract, then notify the gateway.\n *  2. **Balance** — read or force-sync the gateway's off-chain credit view.\n *  3. **Pay** — sign a `GenericPayment` EIP-712 message and POST it to the\n *     gateway's `/v1/escrow/pay` endpoint.\n *\n * The gateway is the authority on balances; the on-chain contract is the\n * authority on what has been settled. Nothing in this module touches the\n * chain directly — signing is done by the caller's wallet.\n *\n * @category Protocol\n * @module escrow\n */\n\nexport {\n  buildWithdrawAuthorizationTypedData,\n  withdrawAuthorizationDomain,\n  WITHDRAW_AUTHORIZATION_TYPES,\n  type WithdrawAuthorizationMessage,\n} from \"./eip712\";\nimport type { TypedDataDomain } from \"viem\";\nimport { isHex } from \"viem\";\n\n// ---------------------------------------------------------------------------\n// EIP-712 — GenericPayment\n// ---------------------------------------------------------------------------\n\n/**\n * EIP-712 typed-data types for a generic op payment.\n *\n * The gateway verifies that the recovered signer == `payerAddress` and that\n * the (payer, paymentNonce) pair has not been seen before. Use a\n * monotonically-increasing nonce; the first payment for any payer should\n * start at 1.\n */\nexport const GENERIC_PAYMENT_TYPES = {\n  GenericPayment: [\n    { name: \"payerAddress\", type: \"address\" },\n    { name: \"opType\", type: \"string\" },\n    { name: \"opId\", type: \"bytes32\" },\n    { name: \"asset\", type: \"address\" },\n    { name: \"amount\", type: \"uint256\" },\n    { name: \"paymentNonce\", type: \"uint256\" },\n  ],\n} as const;\n\n/**\n * EIP-712 message payload for a generic op payment.\n *\n * - `opType` is `\"grant\"` for legacy grant lifecycle payments or\n *   `\"data_access\"` for a standalone receipt-bound read.\n * - `opId` is the bytes32 id of the operation being paid for: the grant id for\n *   `\"grant\"`, or `accessRecord.recordId` for `\"data_access\"`.\n * - `asset` is the ERC-20 token address, or the zero address for native VANA.\n * - `amount` is the total amount in base units (wei for VANA). Must match the\n *   sum the gateway expects for the current lifecycle of the op.\n * - `paymentNonce` must be a positive integer unique per `payerAddress`. Use 1\n *   for the first payment; increment by at least 1 for each subsequent call.\n */\nexport interface GenericPaymentMessage {\n  payerAddress: `0x${string}`;\n  opType: string;\n  opId: `0x${string}`;\n  asset: `0x${string}`;\n  amount: bigint;\n  paymentNonce: bigint;\n}\n\n/**\n * Returns the EIP-712 domain for signing a `GenericPayment` message.\n *\n * The verifying contract is the `DataPortabilityEscrow` contract; all gateway\n * deployments share the same domain name and version.\n *\n * @param chainId - Chain ID of the Vana network (e.g. 1480 mainnet, 14800 testnet).\n * @param escrowContract - Deployed address of DataPortabilityEscrow.\n */\nexport function genericPaymentDomain(\n  chainId: number,\n  escrowContract: `0x${string}`,\n): TypedDataDomain {\n  return {\n    name: \"Vana Data Portability\",\n    version: \"1\",\n    chainId,\n    verifyingContract: escrowContract,\n  };\n}\n\n// ---------------------------------------------------------------------------\n// On-chain deposit ABI fragments\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal ABI for the two deposit entry points on `DataPortabilityEscrow`.\n *\n * - `depositNative(address account)` payable — credits native VANA.\n * - `depositToken(address account, address token, uint256 amount)` — credits\n *   an ERC-20 token (caller must have pre-approved the escrow contract).\n *\n * Pass this to viem's `writeContract` or encode it manually.\n */\nexport const ESCROW_DEPOSIT_ABI = [\n  {\n    type: \"function\",\n    name: \"depositNative\",\n    stateMutability: \"payable\",\n    inputs: [{ name: \"account\", type: \"address\" }],\n    outputs: [],\n  },\n  {\n    type: \"function\",\n    name: \"depositToken\",\n    stateMutability: \"nonpayable\",\n    inputs: [\n      { name: \"account\", type: \"address\" },\n      { name: \"token\", type: \"address\" },\n      { name: \"amount\", type: \"uint256\" },\n    ],\n    outputs: [],\n  },\n] as const;\n\n/**\n * The zero address used by the DataPortabilityEscrow contract to represent\n * native VANA in `asset` fields of events and balance responses.\n */\nexport const NATIVE_ASSET_ADDRESS =\n  \"0x0000000000000000000000000000000000000000\" as const;\n\n// ---------------------------------------------------------------------------\n// Gateway API client\n// ---------------------------------------------------------------------------\n\n/**\n * Per-asset balance entry returned by the gateway's escrow balance endpoints.\n *\n * - `balance` — gross finalized credit (deposits credited so far).\n * - `pendingAmount` — sum of submitted deposits not yet confirmed.\n * - `authorizedAmount` — sum of all in-flight payments authorized by\n *   `/v1/escrow/pay` (soft-lock). May include payments not yet settled\n *   on-chain.\n * - `withdrawingAmount` — sum of in-flight withdrawal reservations.\n * - `availableAmount` — `max(balance − authorizedAmount − withdrawingAmount, 0)`.\n *   This is what the account can still authorize or withdraw.\n */\nexport interface EscrowBalanceEntry {\n  asset: string;\n  balance: string;\n  pendingAmount: string;\n  authorizedAmount: string;\n  withdrawingAmount: string;\n  availableAmount: string;\n  /** Minimum withdrawal amount currently accepted for this asset, if configured. */\n  withdrawalMinimumAmount: string | null;\n  updatedAt: string | null;\n}\n\nexport interface SubmittedDepositEntry {\n  txHash: string;\n  submittedAt: string;\n  claimedAsset: string;\n  claimedAmount: string;\n}\n\nexport interface FinalizedDepositEntry {\n  txHash: string;\n  finalizedAt: string | null;\n  blockNumber: string | null;\n  claimedAsset: string;\n  claimedAmount: string;\n}\n\nexport interface FailedDepositEntry {\n  txHash: string;\n  submittedAt: string;\n  claimedAsset: string;\n  claimedAmount: string;\n  lastError: string | null;\n}\n\n/** Full balance read response from `GET /v1/escrow/balance`. */\nexport interface EscrowBalanceResult {\n  account: string;\n  balances: EscrowBalanceEntry[];\n  deposits: {\n    submitted: SubmittedDepositEntry[];\n    finalized: FinalizedDepositEntry[];\n    failed: FailedDepositEntry[];\n  };\n}\n\n/**\n * Response from `POST /v1/escrow/balance/sync`.\n *\n * Extends {@link EscrowBalanceResult} with a `sync` summary of what the\n * lazy-confirmation pass did.\n */\nexport interface EscrowBalanceSyncResult extends EscrowBalanceResult {\n  sync:\n    | {\n        scanned: number;\n        finalized: number;\n        stillPending: number;\n        failed: number;\n      }\n    | { skipped: true };\n}\n\n/** Response from `POST /v1/escrow/deposit`. */\nexport interface DepositSubmissionResult {\n  success: true;\n  txHash: string;\n  account: string;\n  status: \"submitted\" | \"finalized\" | \"failed\";\n  blockNumber?: string | null;\n  submittedAt: string;\n  finalizedAt?: string | null;\n  lastError?: string | null;\n}\n\n/** Breakdown returned by a successful `POST /v1/escrow/pay`. */\nexport interface PaymentBreakdown {\n  registrationFee: string;\n  dataAccessFee: string;\n  /** True when this call settled the registration fee for the op. */\n  registrationPaid: boolean;\n}\n\n/** Response from `POST /v1/escrow/pay`. */\nexport interface EscrowPayResult {\n  success: true;\n  opType: string;\n  opId: string;\n  payerAddress: string;\n  asset: string;\n  amount: string;\n  breakdown: PaymentBreakdown;\n  paymentNonce: string;\n  paidAt: string;\n}\n\ninterface EscrowWithdrawalResponseBase {\n  account: `0x${string}`;\n  asset: `0x${string}`;\n  amount: string;\n  withdrawNonce: string;\n  deadline: string;\n}\n\n/** A persisted authorization whose transaction has not been broadcast yet. */\nexport interface EscrowWithdrawalSubmittedWithoutTransaction extends EscrowWithdrawalResponseBase {\n  success: true;\n  status: \"submitted\";\n  txHash: null;\n  message: string;\n}\n\n/** A withdrawal with a persisted transaction that is awaiting reconciliation. */\nexport interface EscrowWithdrawalSubmittedWithTransaction {\n  success: true;\n  status: \"submitted\";\n  txHash: `0x${string}`;\n  message: string;\n  // A provisional-revert response contains only txHash, blockNumber, and\n  // message. Ordinary submissions include the signed-intent fields.\n  account?: `0x${string}`;\n  asset?: `0x${string}`;\n  amount?: string;\n  withdrawNonce?: string;\n  deadline?: string;\n  blockNumber?: string;\n}\n\n/** A withdrawal that the gateway has accepted but not yet confirmed. */\nexport type EscrowWithdrawalSubmittedResult =\n  | EscrowWithdrawalSubmittedWithoutTransaction\n  | EscrowWithdrawalSubmittedWithTransaction;\n\n/** A withdrawal whose on-chain debit has reached the named lifecycle state. */\nexport interface EscrowWithdrawalSettledResult extends EscrowWithdrawalResponseBase {\n  success: true;\n  status: \"confirmed\" | \"finalized\";\n  txHash: `0x${string}`;\n  blockNumber: string | null;\n}\n\n/** Successful lifecycle responses from `POST /v1/escrow/withdraw`. */\nexport type EscrowWithdrawalResult =\n  | EscrowWithdrawalSubmittedResult\n  | EscrowWithdrawalSettledResult;\n\n/** Terminal or retryable withdrawal lifecycle state returned with a non-2xx status. */\nexport interface EscrowWithdrawalFailureResult extends EscrowWithdrawalResponseBase {\n  success: false;\n  status: \"retryable\" | \"reorged\" | \"failed\";\n  error: string;\n  txHash: `0x${string}` | null;\n  blockNumber?: string | null;\n}\n\nexport type EscrowWithdrawalRejectionCode =\n  | \"below_minimum\"\n  | \"deadline_too_far\"\n  | \"expired\"\n  | \"insufficient_available\"\n  | \"stale_nonce\";\n\n/** Definite pre-acceptance rejection. No durable withdrawal intent was created. */\nexport interface EscrowWithdrawalRejectedResult extends EscrowWithdrawalResponseBase {\n  success: false;\n  status: \"rejected\";\n  code: EscrowWithdrawalRejectionCode;\n  error: string;\n  balance?: string;\n  authorizedAmount?: string;\n  withdrawingAmount?: string;\n  availableAmount?: string;\n  requestedAmount?: string;\n  minimumAmount?: string;\n}\n\n/**\n * A typed non-2xx gateway lifecycle response.\n *\n * `retryable` means resend the exact signed intent. `reorged` and `failed`\n * require a newly signed authorization with a new nonce.\n */\nexport class EscrowWithdrawalLifecycleError extends Error {\n  override readonly name = \"EscrowWithdrawalLifecycleError\";\n\n  constructor(\n    readonly httpStatus: number,\n    readonly result: EscrowWithdrawalFailureResult,\n  ) {\n    super(result.error);\n  }\n}\n\n/** A typed non-2xx gateway rejection before a withdrawal intent is accepted. */\nexport class EscrowWithdrawalRejectionError extends Error {\n  override readonly name = \"EscrowWithdrawalRejectionError\";\n\n  constructor(\n    readonly httpStatus: number,\n    readonly result: EscrowWithdrawalRejectedResult,\n  ) {\n    super(result.error);\n  }\n}\n\n/**\n * Parameters for submitting a deposit tx hash to the gateway.\n *\n * The gateway will decode the `account` from the tx's calldata and\n * credit the identified account once the tx reaches the configured\n * confirmation depth.\n */\nexport interface SubmitDepositParams {\n  /** 0x-prefixed 32-byte transaction hash. */\n  txHash: `0x${string}`;\n}\n\n/**\n * Parameters for the generic op payment endpoint (`POST /v1/escrow/pay`).\n *\n * The `signature` is an EIP-712 signature over a `GenericPayment` message\n * (see {@link GENERIC_PAYMENT_TYPES} and {@link genericPaymentDomain}).\n * Build and sign the typed data with your wallet before calling\n * {@link EscrowGatewayClient.payForOp}.\n */\nexport interface PayForOpParams {\n  payerAddress: `0x${string}`;\n  opType: string;\n  opId: `0x${string}`;\n  asset: `0x${string}`;\n  /** Decimal string representation of the uint256 amount. */\n  amount: string;\n  /** Decimal string representation of the uint256 nonce. */\n  paymentNonce: string;\n  /** 0x-prefixed 65-byte EIP-712 signature hex string. */\n  signature: `0x${string}`;\n  /**\n   * Optional data-access receipt carried by x402 challenges.\n   *\n   * The gateway verifies its server signature; this type only describes the\n   * wire shape.\n   */\n  accessRecord?: EscrowAccessRecord;\n}\n\n/**\n * Parameters for `POST /v1/escrow/withdraw`.\n *\n * `withdrawNonce` and `deadline` are caller-supplied decimal uint256 strings.\n * The SDK intentionally does not generate a nonce: retrying safely requires a\n * durable caller-owned nonce source and the exact same signed payload.\n */\nexport interface WithdrawFromEscrowParams {\n  account: `0x${string}`;\n  asset: `0x${string}`;\n  amount: string;\n  withdrawNonce: string;\n  deadline: string;\n  signature: `0x${string}`;\n}\n\n/**\n * Response from `GET /v1/escrow/withdraw/nonce`.\n *\n * The gateway provides a read-only snapshot of the account's withdrawal nonce\n * state. This is **not** a reservation; multiple concurrent callers will see\n * the same `nextWithdrawNonce`. To reduce staleness risk, query immediately before\n * signing/submitting the withdrawal authorization. However, `stale_nonce` errors can\n * still occur under concurrent withdrawal attempts; if rejected, re-query and re-sign.\n *\n * Use `nextWithdrawNonce` in the signed withdrawal authorization; `lastWithdrawNonce`\n * is provided for reference and diagnostics.\n */\nexport interface WithdrawNonceResponse {\n  success: true;\n  account: `0x${string}`;\n  chainId: string;\n  lastWithdrawNonce: string | null;\n  nextWithdrawNonce: string;\n}\n\n/** Wire shape of a receipt whose server signature the gateway verifies. */\nexport interface EscrowAccessRecord {\n  dataPointId: `0x${string}`;\n  version: string;\n  accessor: `0x${string}`;\n  recordId: `0x${string}`;\n  signature: `0x${string}`;\n}\n\n/**\n * Minimal client for the gateway's escrow endpoints.\n *\n * Construct with {@link createEscrowGatewayClient}.\n */\nexport interface EscrowGatewayClient {\n  /**\n   * Notify the gateway of a submitted deposit transaction.\n   *\n   * The gateway decodes the credited account from the on-chain tx calldata\n   * and starts tracking the deposit. Call this immediately after your\n   * `depositNative` or `depositToken` tx is broadcast (it accepts pending\n   * mempool txs). Returns `202` while the tx awaits confirmation.\n   */\n  submitDeposit(params: SubmitDepositParams): Promise<DepositSubmissionResult>;\n\n  /**\n   * Read the current escrow balance for an account.\n   *\n   * Pure read — no chain calls. To force a reconciliation pass first,\n   * use {@link syncEscrowBalance}.\n   */\n  getEscrowBalance(account: `0x${string}`): Promise<EscrowBalanceResult>;\n\n  /**\n   * Force a reconciliation pass then return the updated balance.\n   *\n   * Triggers the gateway's lazy-confirmation worker for the account — any\n   * submitted deposits that have reached the configured confirmation level\n   * are credited before the balance is returned. Prefer this over\n   * {@link getEscrowBalance} when you need a fresh view after a deposit.\n   */\n  syncEscrowBalance(account: `0x${string}`): Promise<EscrowBalanceSyncResult>;\n\n  /**\n   * Authorize a payment against the payer's escrow balance.\n   *\n   * The caller must:\n   *  1. Assemble a {@link GenericPaymentMessage}.\n   *  2. Sign it with `signTypedData` using {@link GENERIC_PAYMENT_TYPES} and\n   *     the domain from {@link genericPaymentDomain}.\n   *  3. Pass the message fields + signature here.\n   *\n   * The gateway verifies the signature, checks the soft-lock balance, and\n   * records the payment. Returns 402 if the payer has insufficient balance.\n   */\n  payForOp(params: PayForOpParams): Promise<EscrowPayResult>;\n\n  /**\n   * Submit or reconcile a signed withdrawal authorization.\n   *\n   * The gateway decides which signers may authorize an account. For example,\n   * it may accept the account itself or the confirmed owner of a registered\n   * app account.\n   *\n   * Retry a `submitted` result with the exact same parameters. Do not replace\n   * `withdrawNonce`, `deadline`, or signature unless starting a new intent.\n   */\n  withdraw(params: WithdrawFromEscrowParams): Promise<EscrowWithdrawalResult>;\n\n  /**\n   * Read the authoritative next withdrawal nonce for an account.\n   *\n   * The gateway is the authority on what nonce to use; use the value from\n   * `nextWithdrawNonce` when signing a withdrawal authorization.\n   *\n   * Do NOT generate or cache nonces client-side; concurrent callers cannot be\n   * safely coordinated without durable shared state. Query this endpoint immediately\n   * before signing/submitting to reduce staleness risk. However, `stale_nonce` errors\n   * can still occur; if rejected, re-query and re-sign.\n   */\n  getWithdrawNonce(account: `0x${string}`): Promise<WithdrawNonceResponse>;\n}\n\n/** The only gateway capability required by direct data-access payment flows. */\nexport type EscrowPaymentClient = Pick<EscrowGatewayClient, \"payForOp\">;\n\n/**\n * Creates a client for the gateway escrow endpoints.\n *\n * @param baseUrl - Base URL of the DP RPC gateway\n *   (e.g. `\"https://dp.vana.org\"`). Trailing slashes are trimmed.\n *\n * @example\n * ```typescript\n * import {\n *   createEscrowGatewayClient,\n *   genericPaymentDomain,\n *   GENERIC_PAYMENT_TYPES,\n * } from \"@opendatalabs/vana-sdk/node\";\n *\n * const escrow = createEscrowGatewayClient(\"https://dp.vana.org\");\n *\n * // 1. Submit your deposit tx hash after broadcasting depositNative on-chain\n * const deposit = await escrow.submitDeposit({ txHash: \"0xabc…\" });\n *\n * // 2. Force-sync and read the updated balance\n * const { balances } = await escrow.syncEscrowBalance(\"0xpayerAddress\");\n *\n * // 3. Sign and authorize a grant payment\n * const sig = await walletClient.signTypedData({\n *   domain: genericPaymentDomain(1480, \"0xEscrowContract\"),\n *   types: GENERIC_PAYMENT_TYPES,\n *   primaryType: \"GenericPayment\",\n *   message: {\n *     payerAddress: \"0xpayerAddress\",\n *     opType: \"grant\",\n *     opId: \"0xgrantId\",\n *     asset: \"0x0000000000000000000000000000000000000000\",\n *     amount: 1000000000000000000n,\n *     paymentNonce: 1n,\n *   },\n * });\n * const result = await escrow.payForOp({\n *   payerAddress: \"0xpayerAddress\",\n *   opType: \"grant\",\n *   opId: \"0xgrantId\",\n *   asset: \"0x0000000000000000000000000000000000000000\",\n *   amount: \"1000000000000000000\",\n *   paymentNonce: \"1\",\n *   signature: sig,\n * });\n * ```\n */\nexport function createEscrowGatewayClient(\n  baseUrl: string,\n): EscrowGatewayClient {\n  const base = baseUrl.replace(/\\/+$/, \"\");\n\n  async function throwOnError(res: Response, context: string): Promise<void> {\n    if (!res.ok) {\n      let detail = \"\";\n      try {\n        const body = (await res.json()) as { error?: string };\n        if (body.error) detail = `: ${body.error}`;\n      } catch {\n        // Ignore JSON parse errors; use status text only.\n      }\n      throw new Error(\n        `Escrow gateway error (${context}): ${res.status} ${res.statusText}${detail}`,\n      );\n    }\n  }\n\n  async function throwOnWithdrawError(res: Response): Promise<void> {\n    if (res.ok) return;\n\n    let body: unknown;\n    try {\n      body = await res.json();\n    } catch {\n      throw new Error(\n        `Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}`,\n      );\n    }\n\n    if (isEscrowWithdrawalFailureResult(body)) {\n      throw new EscrowWithdrawalLifecycleError(res.status, body);\n    }\n    if (isEscrowWithdrawalRejectedResult(body)) {\n      throw new EscrowWithdrawalRejectionError(res.status, body);\n    }\n\n    const error = getGatewayErrorMessage(body);\n    throw new Error(\n      `Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}${error ? `: ${error}` : \"\"}`,\n    );\n  }\n\n  return {\n    async submitDeposit({ txHash }) {\n      const res = await fetch(`${base}/v1/escrow/deposit`, {\n        method: \"POST\",\n        headers: { \"Content-Type\": \"application/json\" },\n        body: JSON.stringify({ txHash }),\n      });\n      // 202 Accepted and 200 OK are both success states for deposit submission.\n      if (res.status !== 200 && res.status !== 202) {\n        await throwOnError(res, \"POST /v1/escrow/deposit\");\n      }\n      return res.json() as Promise<DepositSubmissionResult>;\n    },\n\n    async getEscrowBalance(account) {\n      const res = await fetch(\n        `${base}/v1/escrow/balance?account=${encodeURIComponent(account)}`,\n      );\n      await throwOnError(res, \"GET /v1/escrow/balance\");\n      return res.json() as Promise<EscrowBalanceResult>;\n    },\n\n    async syncEscrowBalance(account) {\n      const res = await fetch(\n        `${base}/v1/escrow/balance/sync?account=${encodeURIComponent(account)}`,\n        { method: \"POST\" },\n      );\n      await throwOnError(res, \"POST /v1/escrow/balance/sync\");\n      return res.json() as Promise<EscrowBalanceSyncResult>;\n    },\n\n    async payForOp({\n      payerAddress,\n      opType,\n      opId,\n      asset,\n      amount,\n      paymentNonce,\n      signature,\n      accessRecord,\n    }) {\n      const res = await fetch(`${base}/v1/escrow/pay`, {\n        method: \"POST\",\n        headers: {\n          \"Content-Type\": \"application/json\",\n          Authorization: `Web3Signed ${signature}`,\n        },\n        body: JSON.stringify({\n          payerAddress,\n          opType,\n          opId,\n          asset,\n          amount,\n          paymentNonce,\n          ...(accessRecord ? { accessRecord } : {}),\n        }),\n      });\n      await throwOnError(res, \"POST /v1/escrow/pay\");\n      return res.json() as Promise<EscrowPayResult>;\n    },\n\n    async withdraw({\n      account,\n      asset,\n      amount,\n      withdrawNonce,\n      deadline,\n      signature,\n    }) {\n      const res = await fetch(`${base}/v1/escrow/withdraw`, {\n        method: \"POST\",\n        headers: {\n          \"Content-Type\": \"application/json\",\n          Authorization: `Web3Signed ${signature}`,\n        },\n        body: JSON.stringify({\n          account,\n          asset,\n          amount,\n          withdrawNonce,\n          deadline,\n        }),\n      });\n      await throwOnWithdrawError(res);\n      return res.json() as Promise<EscrowWithdrawalResult>;\n    },\n\n    async getWithdrawNonce(account) {\n      const res = await fetch(\n        `${base}/v1/escrow/withdraw/nonce?account=${encodeURIComponent(account)}`,\n        { cache: \"no-store\" },\n      );\n      await throwOnError(res, \"GET /v1/escrow/withdraw/nonce\");\n      const body = (await res.json()) as unknown;\n      if (!isWithdrawNonceResponse(body, account)) {\n        throw new Error(\n          \"GET /v1/escrow/withdraw/nonce: invalid response structure\",\n        );\n      }\n      return body;\n    },\n  };\n}\n\nfunction getGatewayErrorMessage(body: unknown): string | undefined {\n  if (\n    typeof body === \"object\" &&\n    body !== null &&\n    \"error\" in body &&\n    typeof body.error === \"string\"\n  ) {\n    return body.error;\n  }\n  return undefined;\n}\n\nfunction isEscrowWithdrawalFailureResult(\n  body: unknown,\n): body is EscrowWithdrawalFailureResult {\n  if (typeof body !== \"object\" || body === null) return false;\n  const value = body as Record<string, unknown>;\n  return (\n    value.success === false &&\n    (value.status === \"retryable\" ||\n      value.status === \"reorged\" ||\n      value.status === \"failed\") &&\n    typeof value.error === \"string\" &&\n    isAddressHex(value.account) &&\n    isAddressHex(value.asset) &&\n    isUint256Decimal(value.amount) &&\n    isUint256Decimal(value.withdrawNonce) &&\n    isUint256Decimal(value.deadline) &&\n    (isHash(value.txHash) || value.txHash === null) &&\n    (!(\"blockNumber\" in value) || isBlockNumber(value.blockNumber))\n  );\n}\n\nfunction isEscrowWithdrawalRejectedResult(\n  body: unknown,\n): body is EscrowWithdrawalRejectedResult {\n  if (typeof body !== \"object\" || body === null) return false;\n  const value = body as Record<string, unknown>;\n  return (\n    value.success === false &&\n    value.status === \"rejected\" &&\n    isWithdrawalRejectionCode(value.code) &&\n    typeof value.error === \"string\" &&\n    isAddressHex(value.account) &&\n    isAddressHex(value.asset) &&\n    isUint256Decimal(value.amount) &&\n    isUint256Decimal(value.withdrawNonce) &&\n    isUint256Decimal(value.deadline) &&\n    optionalUint256Decimal(value.balance) &&\n    optionalUint256Decimal(value.authorizedAmount) &&\n    optionalUint256Decimal(value.withdrawingAmount) &&\n    optionalUint256Decimal(value.availableAmount) &&\n    optionalUint256Decimal(value.requestedAmount) &&\n    optionalUint256Decimal(value.minimumAmount)\n  );\n}\n\nfunction isWithdrawalRejectionCode(\n  value: unknown,\n): value is EscrowWithdrawalRejectionCode {\n  return (\n    value === \"below_minimum\" ||\n    value === \"deadline_too_far\" ||\n    value === \"expired\" ||\n    value === \"insufficient_available\" ||\n    value === \"stale_nonce\"\n  );\n}\n\nfunction optionalUint256Decimal(value: unknown): boolean {\n  return value === undefined || isUint256Decimal(value);\n}\n\nfunction isAddressHex(value: unknown): value is `0x${string}` {\n  return (\n    typeof value === \"string\" &&\n    isHex(value, { strict: true }) &&\n    value.length === 42\n  );\n}\n\nfunction isHash(value: unknown): value is `0x${string}` {\n  return (\n    typeof value === \"string\" &&\n    isHex(value, { strict: true }) &&\n    value.length === 66\n  );\n}\n\nfunction isUint256Decimal(value: unknown): value is string {\n  if (typeof value !== \"string\" || value.length === 0 || value.length > 78) {\n    return false;\n  }\n  if (!/^(0|[1-9]\\d*)$/.test(value)) return false;\n  return BigInt(value) <= 2n ** 256n - 1n;\n}\n\nfunction isBlockNumber(value: unknown): value is string | null {\n  return value === null || isUint256Decimal(value);\n}\n\nfunction isWithdrawNonceResponse(\n  body: unknown,\n  requestedAccount: `0x${string}`,\n): body is WithdrawNonceResponse {\n  if (typeof body !== \"object\" || body === null) return false;\n  const value = body as Record<string, unknown>;\n\n  if (value.success !== true) return false;\n\n  if (!isAddressHex(value.account)) return false;\n  if (value.account.toLowerCase() !== requestedAccount.toLowerCase())\n    return false;\n  if (typeof value.chainId !== \"string\") return false;\n  if (!/^(0|[1-9]\\d*)$/.test(value.chainId)) return false;\n\n  const isLastNull = value.lastWithdrawNonce === null;\n  const lastNonceValid =\n    isLastNull || isUint256Decimal(value.lastWithdrawNonce);\n  if (!lastNonceValid) return false;\n\n  if (!isUint256Decimal(value.nextWithdrawNonce)) return false;\n\n  // Validate nonce pair consistency: nextWithdrawNonce must be exactly lastWithdrawNonce + 1\n  // or exactly 1 if lastWithdrawNonce is null\n  if (isLastNull) {\n    return value.nextWithdrawNonce === \"1\";\n  }\n\n  const lastNonce = BigInt(value.lastWithdrawNonce as string);\n  const nextNonce = BigInt(value.nextWithdrawNonce as string);\n  const expectedNextNonce = lastNonce + 1n;\n\n  // Ensure no overflow (nextNonce must still be within uint256)\n  if (expectedNextNonce > 2n ** 256n - 1n) return false;\n\n  return nextNonce === expectedNextNonce;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA,oBAKO;AAEP,kBAAsB;AAcf,MAAM,wBAAwB;AAAA,EACnC,gBAAgB;AAAA,IACd,EAAE,MAAM,gBAAgB,MAAM,UAAU;AAAA,IACxC,EAAE,MAAM,UAAU,MAAM,SAAS;AAAA,IACjC,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,IAChC,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,IACjC,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IAClC,EAAE,MAAM,gBAAgB,MAAM,UAAU;AAAA,EAC1C;AACF;AAiCO,SAAS,qBACd,SACA,gBACiB;AACjB,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT;AAAA,IACA,mBAAmB;AAAA,EACrB;AACF;AAeO,MAAM,qBAAqB;AAAA,EAChC;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ,CAAC,EAAE,MAAM,WAAW,MAAM,UAAU,CAAC;AAAA,IAC7C,SAAS,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,iBAAiB;AAAA,IACjB,QAAQ;AAAA,MACN,EAAE,MAAM,WAAW,MAAM,UAAU;AAAA,MACnC,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,MACjC,EAAE,MAAM,UAAU,MAAM,UAAU;AAAA,IACpC;AAAA,IACA,SAAS,CAAC;AAAA,EACZ;AACF;AAMO,MAAM,uBACX;AAwMK,MAAM,uCAAuC,MAAM;AAAA,EAGxD,YACW,YACA,QACT;AACA,UAAM,OAAO,KAAK;AAHT;AACA;AAAA,EAGX;AAAA,EAJW;AAAA,EACA;AAAA,EAJO,OAAO;AAQ3B;AAGO,MAAM,uCAAuC,MAAM;AAAA,EAGxD,YACW,YACA,QACT;AACA,UAAM,OAAO,KAAK;AAHT;AACA;AAAA,EAGX;AAAA,EAJW;AAAA,EACA;AAAA,EAJO,OAAO;AAQ3B;AAmNO,SAAS,0BACd,SACqB;AACrB,QAAM,OAAO,QAAQ,QAAQ,QAAQ,EAAE;AAEvC,iBAAe,aAAa,KAAe,SAAgC;AACzE,QAAI,CAAC,IAAI,IAAI;AACX,UAAI,SAAS;AACb,UAAI;AACF,cAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,YAAI,KAAK,MAAO,UAAS,KAAK,KAAK,KAAK;AAAA,MAC1C,QAAQ;AAAA,MAER;AACA,YAAM,IAAI;AAAA,QACR,yBAAyB,OAAO,MAAM,IAAI,MAAM,IAAI,IAAI,UAAU,GAAG,MAAM;AAAA,MAC7E;AAAA,IACF;AAAA,EACF;AAEA,iBAAe,qBAAqB,KAA8B;AAChE,QAAI,IAAI,GAAI;AAEZ,QAAI;AACJ,QAAI;AACF,aAAO,MAAM,IAAI,KAAK;AAAA,IACxB,QAAQ;AACN,YAAM,IAAI;AAAA,QACR,oDAAoD,IAAI,MAAM,IAAI,IAAI,UAAU;AAAA,MAClF;AAAA,IACF;AAEA,QAAI,gCAAgC,IAAI,GAAG;AACzC,YAAM,IAAI,+BAA+B,IAAI,QAAQ,IAAI;AAAA,IAC3D;AACA,QAAI,iCAAiC,IAAI,GAAG;AAC1C,YAAM,IAAI,+BAA+B,IAAI,QAAQ,IAAI;AAAA,IAC3D;AAEA,UAAM,QAAQ,uBAAuB,IAAI;AACzC,UAAM,IAAI;AAAA,MACR,oDAAoD,IAAI,MAAM,IAAI,IAAI,UAAU,GAAG,QAAQ,KAAK,KAAK,KAAK,EAAE;AAAA,IAC9G;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,cAAc,EAAE,OAAO,GAAG;AAC9B,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,sBAAsB;AAAA,QACnD,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,OAAO,CAAC;AAAA,MACjC,CAAC;AAED,UAAI,IAAI,WAAW,OAAO,IAAI,WAAW,KAAK;AAC5C,cAAM,aAAa,KAAK,yBAAyB;AAAA,MACnD;AACA,aAAO,IAAI,KAAK;AAAA,IAClB;AAAA,IAEA,MAAM,iBAAiB,SAAS;AAC9B,YAAM,MAAM,MAAM;AAAA,QAChB,GAAG,IAAI,8BAA8B,mBAAmB,OAAO,CAAC;AAAA,MAClE;AACA,YAAM,aAAa,KAAK,wBAAwB;AAChD,aAAO,IAAI,KAAK;AAAA,IAClB;AAAA,IAEA,MAAM,kBAAkB,SAAS;AAC/B,YAAM,MAAM,MAAM;AAAA,QAChB,GAAG,IAAI,mCAAmC,mBAAmB,OAAO,CAAC;AAAA,QACrE,EAAE,QAAQ,OAAO;AAAA,MACnB;AACA,YAAM,aAAa,KAAK,8BAA8B;AACtD,aAAO,IAAI,KAAK;AAAA,IAClB;AAAA,IAEA,MAAM,SAAS;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,GAAG;AACD,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,kBAAkB;AAAA,QAC/C,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,cAAc,SAAS;AAAA,QACxC;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;AAAA,QACzC,CAAC;AAAA,MACH,CAAC;AACD,YAAM,aAAa,KAAK,qBAAqB;AAC7C,aAAO,IAAI,KAAK;AAAA,IAClB;AAAA,IAEA,MAAM,SAAS;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,GAAG;AACD,YAAM,MAAM,MAAM,MAAM,GAAG,IAAI,uBAAuB;AAAA,QACpD,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,eAAe,cAAc,SAAS;AAAA,QACxC;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AACD,YAAM,qBAAqB,GAAG;AAC9B,aAAO,IAAI,KAAK;AAAA,IAClB;AAAA,IAEA,MAAM,iBAAiB,SAAS;AAC9B,YAAM,MAAM,MAAM;AAAA,QAChB,GAAG,IAAI,qCAAqC,mBAAmB,OAAO,CAAC;AAAA,QACvE,EAAE,OAAO,WAAW;AAAA,MACtB;AACA,YAAM,aAAa,KAAK,+BAA+B;AACvD,YAAM,OAAQ,MAAM,IAAI,KAAK;AAC7B,UAAI,CAAC,wBAAwB,MAAM,OAAO,GAAG;AAC3C,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,SAAS,uBAAuB,MAAmC;AACjE,MACE,OAAO,SAAS,YAChB,SAAS,QACT,WAAW,QACX,OAAO,KAAK,UAAU,UACtB;AACA,WAAO,KAAK;AAAA,EACd;AACA,SAAO;AACT;AAEA,SAAS,gCACP,MACuC;AACvC,MAAI,OAAO,SAAS,YAAY,SAAS,KAAM,QAAO;AACtD,QAAM,QAAQ;AACd,SACE,MAAM,YAAY,UACjB,MAAM,WAAW,eAChB,MAAM,WAAW,aACjB,MAAM,WAAW,aACnB,OAAO,MAAM,UAAU,YACvB,aAAa,MAAM,OAAO,KAC1B,aAAa,MAAM,KAAK,KACxB,iBAAiB,MAAM,MAAM,KAC7B,iBAAiB,MAAM,aAAa,KACpC,iBAAiB,MAAM,QAAQ,MAC9B,OAAO,MAAM,MAAM,KAAK,MAAM,WAAW,UACzC,EAAE,iBAAiB,UAAU,cAAc,MAAM,WAAW;AAEjE;AAEA,SAAS,iCACP,MACwC;AACxC,MAAI,OAAO,SAAS,YAAY,SAAS,KAAM,QAAO;AACtD,QAAM,QAAQ;AACd,SACE,MAAM,YAAY,SAClB,MAAM,WAAW,cACjB,0BAA0B,MAAM,IAAI,KACpC,OAAO,MAAM,UAAU,YACvB,aAAa,MAAM,OAAO,KAC1B,aAAa,MAAM,KAAK,KACxB,iBAAiB,MAAM,MAAM,KAC7B,iBAAiB,MAAM,aAAa,KACpC,iBAAiB,MAAM,QAAQ,KAC/B,uBAAuB,MAAM,OAAO,KACpC,uBAAuB,MAAM,gBAAgB,KAC7C,uBAAuB,MAAM,iBAAiB,KAC9C,uBAAuB,MAAM,eAAe,KAC5C,uBAAuB,MAAM,eAAe,KAC5C,uBAAuB,MAAM,aAAa;AAE9C;AAEA,SAAS,0BACP,OACwC;AACxC,SACE,UAAU,mBACV,UAAU,sBACV,UAAU,aACV,UAAU,4BACV,UAAU;AAEd;AAEA,SAAS,uBAAuB,OAAyB;AACvD,SAAO,UAAU,UAAa,iBAAiB,KAAK;AACtD;AAEA,SAAS,aAAa,OAAwC;AAC5D,SACE,OAAO,UAAU,gBACjB,mBAAM,OAAO,EAAE,QAAQ,KAAK,CAAC,KAC7B,MAAM,WAAW;AAErB;AAEA,SAAS,OAAO,OAAwC;AACtD,SACE,OAAO,UAAU,gBACjB,mBAAM,OAAO,EAAE,QAAQ,KAAK,CAAC,KAC7B,MAAM,WAAW;AAErB;AAEA,SAAS,iBAAiB,OAAiC;AACzD,MAAI,OAAO,UAAU,YAAY,MAAM,WAAW,KAAK,MAAM,SAAS,IAAI;AACxE,WAAO;AAAA,EACT;AACA,MAAI,CAAC,iBAAiB,KAAK,KAAK,EAAG,QAAO;AAC1C,SAAO,OAAO,KAAK,KAAK,MAAM,OAAO;AACvC;AAEA,SAAS,cAAc,OAAwC;AAC7D,SAAO,UAAU,QAAQ,iBAAiB,KAAK;AACjD;AAEA,SAAS,wBACP,MACA,kBAC+B;AAC/B,MAAI,OAAO,SAAS,YAAY,SAAS,KAAM,QAAO;AACtD,QAAM,QAAQ;AAEd,MAAI,MAAM,YAAY,KAAM,QAAO;AAEnC,MAAI,CAAC,aAAa,MAAM,OAAO,EAAG,QAAO;AACzC,MAAI,MAAM,QAAQ,YAAY,MAAM,iBAAiB,YAAY;AAC/D,WAAO;AACT,MAAI,OAAO,MAAM,YAAY,SAAU,QAAO;AAC9C,MAAI,CAAC,iBAAiB,KAAK,MAAM,OAAO,EAAG,QAAO;AAElD,QAAM,aAAa,MAAM,sBAAsB;AAC/C,QAAM,iBACJ,cAAc,iBAAiB,MAAM,iBAAiB;AACxD,MAAI,CAAC,eAAgB,QAAO;AAE5B,MAAI,CAAC,iBAAiB,MAAM,iBAAiB,EAAG,QAAO;AAIvD,MAAI,YAAY;AACd,WAAO,MAAM,sBAAsB;AAAA,EACrC;AAEA,QAAM,YAAY,OAAO,MAAM,iBAA2B;AAC1D,QAAM,YAAY,OAAO,MAAM,iBAA2B;AAC1D,QAAM,oBAAoB,YAAY;AAGtC,MAAI,oBAAoB,MAAM,OAAO,GAAI,QAAO;AAEhD,SAAO,cAAc;AACvB;","names":[]}