{"version":3,"sources":["../../src/signer.ts","../../src/shared/erc7702.ts","../../src/auth-capture/types.ts"],"sourcesContent":["import type { Log } from \"viem\";\n\n/**\n * ClientEvmSigner - Used by x402 clients to sign payment authorizations.\n *\n * Typically a viem LocalAccount:\n * ```typescript\n * const account = privateKeyToAccount('0x...');\n * ```\n *\n * Or composed via `toClientEvmSigner(account, publicClient)`.\n */\nexport type ClientEvmSigner = {\n  readonly address: `0x${string}`;\n  signTypedData(message: {\n    domain: Record<string, unknown>;\n    types: Record<string, unknown>;\n    primaryType: string;\n    message: Record<string, unknown>;\n  }): Promise<`0x${string}`>;\n  /**\n   * Optional on-chain reads.\n   * Required only for extension enrichment (EIP-2612 / ERC-20 approval).\n   */\n  readContract?(args: {\n    address: `0x${string}`;\n    abi: readonly unknown[];\n    functionName: string;\n    args?: readonly unknown[];\n  }): Promise<unknown>;\n  /**\n   * Optional: Signs a raw EIP-1559 transaction without broadcasting.\n   * Required for ERC-20 approval gas sponsoring when the token lacks EIP-2612.\n   */\n  signTransaction?(args: {\n    to: `0x${string}`;\n    data: `0x${string}`;\n    nonce: number;\n    gas: bigint;\n    maxFeePerGas: bigint;\n    maxPriorityFeePerGas: bigint;\n    chainId: number;\n  }): Promise<`0x${string}`>;\n  /**\n   * Optional: Gets the current transaction count (nonce) for an address.\n   * Required for ERC-20 approval gas sponsoring.\n   */\n  getTransactionCount?(args: { address: `0x${string}` }): Promise<number>;\n  /**\n   * Optional: Estimates current gas fees per gas.\n   * Required for ERC-20 approval gas sponsoring.\n   */\n  estimateFeesPerGas?(): Promise<{ maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }>;\n};\n\n/**\n * FacilitatorEvmSigner - Used by x402 facilitators to verify and settle payments\n * This is typically a viem PublicClient + WalletClient combination that can\n * read contract state, verify signatures, write transactions, and wait for receipts\n *\n * Supports multiple addresses for load balancing, key rotation, and high availability\n */\nexport type FacilitatorEvmSigner = {\n  /**\n   * Get all addresses this facilitator can use for signing\n   * Enables dynamic address selection for load balancing and key rotation\n   */\n  getAddresses(): readonly `0x${string}`[];\n\n  readContract(args: {\n    address: `0x${string}`;\n    abi: readonly unknown[];\n    functionName: string;\n    args?: readonly unknown[];\n  }): Promise<unknown>;\n  verifyTypedData(args: {\n    address: `0x${string}`;\n    domain: Record<string, unknown>;\n    types: Record<string, unknown>;\n    primaryType: string;\n    message: Record<string, unknown>;\n    signature: `0x${string}`;\n  }): Promise<boolean>;\n  writeContract(args: {\n    address: `0x${string}`;\n    abi: readonly unknown[];\n    functionName: string;\n    args: readonly unknown[];\n    gas?: bigint;\n    dataSuffix?: `0x${string}`;\n  }): Promise<`0x${string}`>;\n  sendTransaction(args: { to: `0x${string}`; data: `0x${string}` }): Promise<`0x${string}`>;\n  waitForTransactionReceipt(args: { hash: `0x${string}` }): Promise<{\n    status: string;\n    logs?: readonly Log[];\n  }>;\n  getCode(args: { address: `0x${string}` }): Promise<`0x${string}` | undefined>;\n};\n\n/**\n * Composes a ClientEvmSigner from a local account and a public client.\n *\n * Use this when your signer (e.g., `privateKeyToAccount`) doesn't have\n * `readContract`. The `publicClient` provides the on-chain read capability.\n *\n * Alternatively, use a local account with an explicit public client:\n * ```typescript\n * const account = privateKeyToAccount('0x...');\n * const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });\n * const signer = toClientEvmSigner(account, publicClient);\n * ```\n *\n * @param signer - A signer with `address` and `signTypedData` (and optionally `readContract`)\n * @param publicClient - A client with optional read/nonce/fee helpers\n * @param publicClient.readContract - The readContract method from the public client\n * @param publicClient.getTransactionCount - Optional getTransactionCount for ERC-20 approval\n * @param publicClient.estimateFeesPerGas - Optional estimateFeesPerGas for ERC-20 approval\n * @returns A ClientEvmSigner with any available optional capabilities\n *\n * @example\n * ```typescript\n * const account = privateKeyToAccount(\"0x...\");\n * const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });\n * const signer = toClientEvmSigner(account, publicClient);\n * ```\n */\nexport function toClientEvmSigner(\n  signer: Omit<ClientEvmSigner, \"readContract\"> & {\n    readContract?: ClientEvmSigner[\"readContract\"];\n  },\n  publicClient?: {\n    readContract(args: {\n      address: `0x${string}`;\n      abi: readonly unknown[];\n      functionName: string;\n      args?: readonly unknown[];\n    }): Promise<unknown>;\n    getTransactionCount?(args: { address: `0x${string}` }): Promise<number>;\n    estimateFeesPerGas?(): Promise<{ maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }>;\n  },\n): ClientEvmSigner {\n  const readContract = signer.readContract ?? publicClient?.readContract.bind(publicClient);\n\n  const result: ClientEvmSigner = {\n    address: signer.address,\n    signTypedData: msg => signer.signTypedData(msg),\n  };\n\n  if (readContract) {\n    result.readContract = readContract;\n  }\n\n  // Forward optional capabilities from signer or publicClient\n  const signTransaction = signer.signTransaction;\n  if (signTransaction) {\n    result.signTransaction = args => signTransaction(args);\n  }\n\n  const getTransactionCount =\n    signer.getTransactionCount ?? publicClient?.getTransactionCount?.bind(publicClient);\n  if (getTransactionCount) {\n    result.getTransactionCount = args => getTransactionCount(args);\n  }\n\n  const estimateFeesPerGas =\n    signer.estimateFeesPerGas ?? publicClient?.estimateFeesPerGas?.bind(publicClient);\n  if (estimateFeesPerGas) {\n    result.estimateFeesPerGas = () => estimateFeesPerGas();\n  }\n\n  return result;\n}\n\n/**\n * Converts a viem client with single address to a FacilitatorEvmSigner\n * Wraps the single address in a getAddresses() function for compatibility\n *\n * @param client - The client to convert (must have 'address' property)\n * @returns FacilitatorEvmSigner with getAddresses() support\n */\nexport function toFacilitatorEvmSigner(\n  client: Omit<FacilitatorEvmSigner, \"getAddresses\"> & { address: `0x${string}` },\n): FacilitatorEvmSigner {\n  return {\n    ...client,\n    getAddresses: () => [client.address],\n  };\n}\n","/**\n * Detection utilities for the ERC-7702 delegation designation (`0xef0100 + 20-byte address`).\n *\n * NOTE: These helpers are diagnostic only. The signature-verification path does\n * not branch on 7702 detection — it routes by `code.length` (matching on-chain\n * SignatureChecker) and the delegate decides via `isValidSignature`. See\n * {@link ./verifySignature.ts} for the verification primitive.\n *\n * Use these helpers for telemetry, logging, or surfacing wallet types in UIs.\n */\n\nconst ERC7702_PREFIX = \"0xef0100\";\nconst ERC7702_BYTECODE_LENGTH = 48; // \"0x\" + 6 hex chars (prefix) + 40 hex chars (address)\n\n/**\n * Returns `true` if `bytecode` is a valid ERC-7702 delegation designation.\n *\n * The check is case-insensitive — `eth_getCode` casing is not normalized at the\n * JSON-RPC layer, so callers using ethers, custom signers, or post-processed\n * hex can pass uppercase variants.\n *\n * @param bytecode - Raw hex bytecode returned by `eth_getCode`.\n * @returns `true` if the bytecode is an ERC-7702 delegation designation.\n */\nexport function isERC7702Delegation(bytecode: `0x${string}` | undefined | null): boolean {\n  if (!bytecode || bytecode === \"0x\") return false;\n  if (bytecode.length !== ERC7702_BYTECODE_LENGTH) return false;\n  return bytecode.toLowerCase().startsWith(ERC7702_PREFIX);\n}\n\n/**\n * Extracts the 20-byte delegate address from a 7702 delegation designation.\n * Returns the address in **lowercase** hex with a `0x` prefix.\n * The Go equivalent ({@link GetERC7702DelegateAddress}) returns a checksummed EIP-55 address.\n * The Python equivalent returns lowercase hex. Normalise with `getAddress()` when comparing\n * cross-SDK outputs or storing in a case-sensitive index.\n * Returns `null` for non-7702 bytecode.\n *\n * @param bytecode - Raw hex bytecode returned by `eth_getCode`.\n * @returns The lowercase `0x`-prefixed delegate address, or `null` if `bytecode` is not a 7702 designation.\n */\nexport function getERC7702DelegateAddress(\n  bytecode: `0x${string}` | undefined | null,\n): `0x${string}` | null {\n  if (!isERC7702Delegation(bytecode)) return null;\n  return (\"0x\" + bytecode!.slice(8).toLowerCase()) as `0x${string}`;\n}\n","/**\n * auth-capture wire-format types.\n *\n * Spec-level field names (captureAuthorizer, captureDeadline, refundDeadline,\n * feeRecipient) live here at the extra/wire layer. The on-chain PaymentInfo\n * struct keeps the canonical Solidity field names (operator, authorizationExpiry,\n * refundExpiry, feeReceiver) so the EIP-712 typehash stays byte-identical with\n * the AuthCaptureEscrow contract.\n *\n * Salt is NOT in extra. It is generated client-side per signing call and rides\n * on the payload alongside the signature.\n */\n\nimport type { AssetTransferMethod } from \"../types\";\n\n// AuthCaptureExtra — fields in PaymentRequirements.extra.\n//\n// Fee-policy fields (minFeeBps, maxFeeBps, feeRecipient) are all required.\n// No implicit defaults: a merchant who wants no minimum fee writes\n// `minFeeBps: 0` explicitly. This forces fee policy to be a conscious choice\n// on the wire and avoids \"did they mean 0 or did they forget?\" ambiguity.\nexport interface AuthCaptureExtra {\n  // Required\n  // The only address allowed to call authorize/capture/void/refund/charge on\n  // AuthCaptureEscrow (each of those is gated by onlySender(paymentInfo.operator))\n  // — i.e., it must be msg.sender of the \"Authorize\" call. In x402's\n  // facilitator-submits flow that means either the facilitator's EOA, or any\n  // smart contract that ultimately calls escrow (arbiter with dispute logic,\n  // multisig, etc.). Independent of assetTransferMethod — applies to both\n  // EIP-3009 and Permit2.\n  captureAuthorizer: `0x${string}`; // formerly `operator` in commerce-payments\n  captureDeadline: number; // absolute Unix seconds; capture must occur before this\n  refundDeadline: number; // absolute Unix seconds; refunds allowed until this\n  feeRecipient: `0x${string}`; // address that receives the fee portion (renamed from feeReceiver)\n  minFeeBps: number; // floor on the captureAuthorizer's fee; 0 = no minimum\n  maxFeeBps: number; // cap on the captureAuthorizer's fee\n  name: string; // EIP-712 token-domain name (e.g., \"USDC\")\n  version: string; // EIP-712 token-domain version (e.g., \"2\")\n  // Optional\n  autoCapture?: boolean; // default: false. true → facilitator calls charge(), false → authorize()\n  assetTransferMethod?: AssetTransferMethod; // default: 'eip3009'\n}\n\n/**\n * Type guard for AuthCaptureExtra. Checks the structural shape an auth-capture\n * scheme requires inside `PaymentRequirements.extra`: every spec-mandated\n * required field present with the right primitive type.\n *\n * @param value - Candidate object from `requirements.extra`.\n * @returns True if `value` has every required AuthCaptureExtra field.\n */\nexport function isAuthCaptureExtra(value: unknown): value is AuthCaptureExtra {\n  if (typeof value !== \"object\" || value === null) return false;\n  const v = value as Record<string, unknown>;\n  return (\n    typeof v.captureAuthorizer === \"string\" &&\n    typeof v.captureDeadline === \"number\" &&\n    typeof v.refundDeadline === \"number\" &&\n    typeof v.feeRecipient === \"string\" &&\n    typeof v.minFeeBps === \"number\" &&\n    typeof v.maxFeeBps === \"number\" &&\n    typeof v.name === \"string\" &&\n    typeof v.version === \"string\"\n  );\n}\n\n// EIP-3009 payload — ReceiveWithAuthorization to the canonical EIP-3009 token collector.\nexport interface Eip3009Payload {\n  authorization: {\n    from: `0x${string}`;\n    to: `0x${string}`; // EIP3009_TOKEN_COLLECTOR_ADDRESS\n    value: string;\n    validAfter: string;\n    validBefore: string; // = preApprovalExpiry\n    nonce: `0x${string}`; // = payer-agnostic PaymentInfo hash\n  };\n  signature: `0x${string}`;\n  salt: `0x${string}`; // bytes32, fresh per request, used to reconstruct PaymentInfo\n}\n\n/**\n * Type guard for an EIP-3009-shaped auth-capture payload. Checks for an\n * `authorization` object plus the required `signature` and `salt` fields;\n * field-level validation happens later in `verify()`.\n *\n * @param value - Candidate payment payload from the wire.\n * @returns True if `value` has the EIP-3009 envelope shape.\n */\nexport function isEip3009Payload(value: unknown): value is Eip3009Payload {\n  if (typeof value !== \"object\" || value === null) return false;\n  const v = value as Record<string, unknown>;\n  return (\n    \"authorization\" in v &&\n    typeof v.authorization === \"object\" &&\n    v.authorization !== null &&\n    typeof v.signature === \"string\" &&\n    typeof v.salt === \"string\"\n  );\n}\n\n// Permit2 payload — PermitTransferFrom to the canonical Permit2 token collector.\nexport interface Permit2Payload {\n  permit2Authorization: {\n    from: `0x${string}`;\n    permitted: {\n      token: `0x${string}`;\n      amount: string;\n    };\n    spender: `0x${string}`; // PERMIT2_TOKEN_COLLECTOR_ADDRESS\n    nonce: string; // uint256 string, = uint256(payer-agnostic PaymentInfo hash)\n    deadline: string; // = preApprovalExpiry\n  };\n  signature: `0x${string}`;\n  salt: `0x${string}`; // bytes32, fresh per request, used to reconstruct PaymentInfo\n}\n\n/**\n * Type guard for a Permit2-shaped auth-capture payload. Checks for the\n * `permit2Authorization` envelope (with `from`, `spender`, `nonce`,\n * `deadline`, `permitted`) plus the required `signature` and `salt` fields.\n *\n * @param value - Candidate payment payload from the wire.\n * @returns True if `value` has the Permit2 envelope shape.\n */\nexport function isPermit2Payload(value: unknown): value is Permit2Payload {\n  if (typeof value !== \"object\" || value === null) return false;\n  const v = value as Record<string, unknown>;\n  if (typeof v.signature !== \"string\" || typeof v.salt !== \"string\") return false;\n  if (typeof v.permit2Authorization !== \"object\" || v.permit2Authorization === null) return false;\n  const a = v.permit2Authorization as Record<string, unknown>;\n  return (\n    typeof a.from === \"string\" &&\n    typeof a.spender === \"string\" &&\n    typeof a.nonce === \"string\" &&\n    typeof a.deadline === \"string\" &&\n    typeof a.permitted === \"object\" &&\n    a.permitted !== null\n  );\n}\n\n// Discriminated union of all auth-capture payload shapes.\nexport type AuthCapturePayload = Eip3009Payload | Permit2Payload;\n\n/**\n * Type guard for any auth-capture payload. Returns true if `value` matches\n * either the EIP-3009 envelope or the Permit2 envelope.\n *\n * @param value - Candidate payment payload from the wire.\n * @returns True if `value` is a valid auth-capture envelope of either shape.\n */\nexport function isAuthCapturePayload(value: unknown): value is AuthCapturePayload {\n  return isEip3009Payload(value) || isPermit2Payload(value);\n}\n\n/**\n * On-chain PaymentInfo struct (canonical Solidity names — DO NOT RENAME).\n * Reconstructed by the facilitator from extra + payload.salt + payer + receiver/asset/amount.\n */\nexport interface PaymentInfoStruct {\n  operator: `0x${string}`; // = extra.captureAuthorizer\n  payer: `0x${string}`;\n  receiver: `0x${string}`; // = requirements.payTo\n  token: `0x${string}`; // = requirements.asset\n  maxAmount: string; // = requirements.amount\n  preApprovalExpiry: number;\n  authorizationExpiry: number; // = extra.captureDeadline\n  refundExpiry: number; // = extra.refundDeadline\n  minFeeBps: number;\n  maxFeeBps: number;\n  feeReceiver: `0x${string}`; // = extra.feeRecipient\n  salt: `0x${string}`; // = payload.salt\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8HO,SAAS,kBACd,QAGA,cAUiB;AACjB,QAAM,eAAe,OAAO,gBAAgB,cAAc,aAAa,KAAK,YAAY;AAExF,QAAM,SAA0B;AAAA,IAC9B,SAAS,OAAO;AAAA,IAChB,eAAe,SAAO,OAAO,cAAc,GAAG;AAAA,EAChD;AAEA,MAAI,cAAc;AAChB,WAAO,eAAe;AAAA,EACxB;AAGA,QAAM,kBAAkB,OAAO;AAC/B,MAAI,iBAAiB;AACnB,WAAO,kBAAkB,UAAQ,gBAAgB,IAAI;AAAA,EACvD;AAEA,QAAM,sBACJ,OAAO,uBAAuB,cAAc,qBAAqB,KAAK,YAAY;AACpF,MAAI,qBAAqB;AACvB,WAAO,sBAAsB,UAAQ,oBAAoB,IAAI;AAAA,EAC/D;AAEA,QAAM,qBACJ,OAAO,sBAAsB,cAAc,oBAAoB,KAAK,YAAY;AAClF,MAAI,oBAAoB;AACtB,WAAO,qBAAqB,MAAM,mBAAmB;AAAA,EACvD;AAEA,SAAO;AACT;AASO,SAAS,uBACd,QACsB;AACtB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,cAAc,MAAM,CAAC,OAAO,OAAO;AAAA,EACrC;AACF;;;AChLA,IAAM,iBAAiB;AACvB,IAAM,0BAA0B;AAYzB,SAAS,oBAAoB,UAAqD;AACvF,MAAI,CAAC,YAAY,aAAa,KAAM,QAAO;AAC3C,MAAI,SAAS,WAAW,wBAAyB,QAAO;AACxD,SAAO,SAAS,YAAY,EAAE,WAAW,cAAc;AACzD;AAaO,SAAS,0BACd,UACsB;AACtB,MAAI,CAAC,oBAAoB,QAAQ,EAAG,QAAO;AAC3C,SAAQ,OAAO,SAAU,MAAM,CAAC,EAAE,YAAY;AAChD;;;ACKO,SAAS,mBAAmB,OAA2C;AAC5E,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,IAAI;AACV,SACE,OAAO,EAAE,sBAAsB,YAC/B,OAAO,EAAE,oBAAoB,YAC7B,OAAO,EAAE,mBAAmB,YAC5B,OAAO,EAAE,iBAAiB,YAC1B,OAAO,EAAE,cAAc,YACvB,OAAO,EAAE,cAAc,YACvB,OAAO,EAAE,SAAS,YAClB,OAAO,EAAE,YAAY;AAEzB;AAwBO,SAAS,iBAAiB,OAAyC;AACxE,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,IAAI;AACV,SACE,mBAAmB,KACnB,OAAO,EAAE,kBAAkB,YAC3B,EAAE,kBAAkB,QACpB,OAAO,EAAE,cAAc,YACvB,OAAO,EAAE,SAAS;AAEtB;AA0BO,SAASA,kBAAiB,OAAyC;AACxE,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,cAAc,YAAY,OAAO,EAAE,SAAS,SAAU,QAAO;AAC1E,MAAI,OAAO,EAAE,yBAAyB,YAAY,EAAE,yBAAyB,KAAM,QAAO;AAC1F,QAAM,IAAI,EAAE;AACZ,SACE,OAAO,EAAE,SAAS,YAClB,OAAO,EAAE,YAAY,YACrB,OAAO,EAAE,UAAU,YACnB,OAAO,EAAE,aAAa,YACtB,OAAO,EAAE,cAAc,YACvB,EAAE,cAAc;AAEpB;AAYO,SAAS,qBAAqB,OAA6C;AAChF,SAAO,iBAAiB,KAAK,KAAKA,kBAAiB,KAAK;AAC1D;","names":["isPermit2Payload"]}