@opendatalabs/vana-sdk 3.22.0-pr.207.e47cd30 → 3.22.0-pr.208.fee4237

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/direct/escrow-payment.ts"],"sourcesContent":["/**\n * Escrow-backed payment authorization for the Direct Data Controller.\n *\n * @remarks\n * Builds on the DPv2 escrow surface added in `protocol/escrow`. When a Personal\n * Server read returns `402 Payment Required`, the controller settles the\n * challenged operation through the escrow gateway:\n *\n * 1. Sign the challenge's `GenericPayment` EIP-712 message with the app key.\n * 2. POST it to the gateway's `/v1/escrow/pay` via {@link EscrowGatewayClient}.\n * 3. Map the gateway's {@link EscrowPayResult} into a typed\n * {@link DirectPaymentReceipt} for the caller to inspect.\n *\n * This module supports legacy `\"grant\"` operations and receipt-bound\n * `\"data_access\"` operations. It adapts the escrow `payForOp` flow to the\n * direct-read use case; it does not define its own payment scheme.\n *\n * @category Direct\n * @module direct/escrow-payment\n */\n\nimport {\n GENERIC_PAYMENT_TYPES,\n NATIVE_ASSET_ADDRESS,\n genericPaymentDomain,\n type EscrowAccessRecord,\n type EscrowGatewayClient,\n type EscrowPayResult,\n type PaymentBreakdown,\n} from \"../protocol/escrow\";\nimport type {\n DirectFeeBreakdown,\n DirectPaymentReceipt,\n DirectPaymentResponseMetadata,\n PersonalServerPaymentOperation,\n PersonalServerPaymentRequired,\n} from \"./types\";\n\n/** The escrow `GenericPayment.opType` used for grant-lifecycle payments. */\nexport const GRANT_OP_TYPE = \"grant\" as const;\n/** The escrow `GenericPayment.opType` used for receipt-bound data access. */\nexport const DATA_ACCESS_OP_TYPE = \"data_access\" as const;\n\n/**\n * EIP-712 typed-data signer (e.g. viem `account.signTypedData`).\n *\n * @remarks\n * Kept structurally minimal so any viem account/wallet client satisfies it\n * without the SDK depending on viem's exact `signTypedData` overload set.\n */\nexport type SignTypedDataFn = (args: {\n domain: ReturnType<typeof genericPaymentDomain>;\n types: typeof GENERIC_PAYMENT_TYPES;\n primaryType: \"GenericPayment\";\n message: {\n payerAddress: `0x${string}`;\n opType: string;\n opId: `0x${string}`;\n asset: `0x${string}`;\n amount: bigint;\n paymentNonce: bigint;\n };\n}) => Promise<`0x${string}`>;\n\n/** Supplies a monotonically-increasing payment nonce per payer. */\nexport type PaymentNonceSource = (\n payerAddress: string,\n) => Promise<bigint> | bigint;\n\ninterface EscrowPaymentMessage {\n payerAddress: `0x${string}`;\n opType: typeof GRANT_OP_TYPE | typeof DATA_ACCESS_OP_TYPE;\n opId: `0x${string}`;\n asset: `0x${string}`;\n amount: string;\n paymentNonce: string;\n}\n\ninterface SignedEscrowPayment {\n message: EscrowPaymentMessage;\n signature: `0x${string}`;\n accessRecord?: EscrowAccessRecord;\n}\n\ninterface X402PaymentHeader {\n x402Version: 1;\n scheme: \"vana-escrow-grant\";\n network: string;\n payload: SignedEscrowPayment;\n}\n\n/** Configuration required to sign an escrow X-PAYMENT header. */\nexport interface EscrowPaymentHeaderConfig {\n /** Deployed `DataPortabilityEscrow` contract address. */\n escrowContract: `0x${string}`;\n /** Chain id for the EIP-712 domain (1480 mainnet, 14800 moksha). */\n chainId: number;\n /** App EIP-712 signer. */\n signTypedData: SignTypedDataFn;\n /**\n * Supplies the next payment nonce for a payer. Defaults to a process-local\n * monotonic counter seeded at 1. Provide a durable source in production so\n * nonces survive restarts (the gateway rejects reused (payer, nonce) pairs).\n */\n nonceSource?: PaymentNonceSource;\n}\n\n/**\n * Escrow settlement configuration for gateway authorization.\n *\n * @remarks\n * Extends the header-signing boundary with the gateway client used by\n * {@link authorizeEscrowPayment}. Existing controller and legacy wrapper\n * callers can continue to provide this full configuration.\n */\nexport interface EscrowPaymentConfig extends EscrowPaymentHeaderConfig {\n /** Client for the gateway escrow endpoints (`/v1/escrow/*`). */\n client: EscrowGatewayClient;\n}\n\n/** Map the gateway {@link PaymentBreakdown} into the public {@link DirectFeeBreakdown}. */\nexport function toDirectFeeBreakdown(\n breakdown: PaymentBreakdown,\n): DirectFeeBreakdown {\n return {\n registrationFee: breakdown.registrationFee,\n dataAccessFee: breakdown.dataAccessFee,\n registrationPaid: breakdown.registrationPaid,\n };\n}\n\n/** Map a gateway {@link EscrowPayResult} into the public {@link DirectPaymentReceipt}. */\nexport function toDirectPaymentReceipt(\n result: EscrowPayResult,\n): DirectPaymentReceipt {\n return {\n opType: result.opType,\n opId: result.opId,\n asset: result.asset,\n amount: result.amount,\n paymentNonce: result.paymentNonce,\n breakdown: toDirectFeeBreakdown(result.breakdown),\n paidAt: result.paidAt,\n };\n}\n\n/** Default in-process monotonic nonce counter (seeded at 1 per payer). */\nexport function createDefaultNonceSource(): PaymentNonceSource {\n const counters = new Map<string, bigint>();\n return (payerAddress: string): bigint => {\n const key = payerAddress.toLowerCase();\n const next = (counters.get(key) ?? 0n) + 1n;\n counters.set(key, next);\n return next;\n };\n}\n\nconst processLocalNonceSource = createDefaultNonceSource();\nconst UINT256_MAX = (1n << 256n) - 1n;\nconst ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;\nconst BYTES32_RE = /^0x[0-9a-fA-F]{64}$/;\nconst SIGNATURE_RE = /^0x[0-9a-fA-F]{130}$/;\n\nfunction isUint256Decimal(value: string, allowZero: boolean): boolean {\n const pattern = allowZero ? /^(0|[1-9]\\d*)$/ : /^[1-9]\\d*$/;\n return (\n value.length <= UINT256_MAX.toString().length &&\n pattern.test(value) &&\n BigInt(value) <= UINT256_MAX\n );\n}\n\nfunction isValidAccessRecord(record: EscrowAccessRecord): boolean {\n return (\n BYTES32_RE.test(record.dataPointId) &&\n isUint256Decimal(record.version, false) &&\n ADDRESS_RE.test(record.accessor) &&\n BYTES32_RE.test(record.recordId) &&\n SIGNATURE_RE.test(record.signature)\n );\n}\n\nfunction validateSigningOperation(\n payerAddress: `0x${string}`,\n required: PersonalServerPaymentOperation,\n): void {\n if (!ADDRESS_RE.test(payerAddress)) {\n throw new Error(\"Payment payer must be a 20-byte EVM address\");\n }\n if (!BYTES32_RE.test(required.opId)) {\n throw new Error(\"Payment operation id must be a 32-byte hex value\");\n }\n if (!ADDRESS_RE.test(required.asset || NATIVE_ASSET_ADDRESS)) {\n throw new Error(\"Payment asset must be a 20-byte EVM address\");\n }\n if (!isUint256Decimal(required.amount, true)) {\n throw new Error(\"Payment amount must be a canonical uint256 decimal\");\n }\n if (\n required.paymentNonce !== undefined &&\n !isUint256Decimal(required.paymentNonce, false)\n ) {\n throw new Error(\"Payment nonce must be a positive uint256 decimal\");\n }\n\n const accessRecord = required.accessRecord;\n if (required.opType === DATA_ACCESS_OP_TYPE) {\n if (!accessRecord || !isValidAccessRecord(accessRecord)) {\n throw new Error(\"Data-access payment requires a valid access record\");\n }\n if (required.opId.toLowerCase() !== accessRecord.recordId.toLowerCase()) {\n throw new Error(\n \"Data-access payment operation id must equal the access record id\",\n );\n }\n if (accessRecord.accessor.toLowerCase() !== payerAddress.toLowerCase()) {\n throw new Error(\n \"Data-access payment accessor must equal the payment payer address\",\n );\n }\n return;\n }\n\n if (required.amount === \"0\") {\n if (\n !accessRecord ||\n !isValidAccessRecord(accessRecord) ||\n accessRecord.accessor.toLowerCase() !== payerAddress.toLowerCase()\n ) {\n throw new Error(\n \"Zero-amount grant payments require a valid access record for the payer\",\n );\n }\n }\n}\n\nfunction base64EncodeJson(value: unknown): string {\n const bytes = new TextEncoder().encode(JSON.stringify(value));\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary);\n}\n\nfunction base64DecodeJson(value: string): unknown {\n const binary = atob(value);\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n return JSON.parse(new TextDecoder().decode(bytes));\n}\n\nasync function signEscrowPayment(params: {\n payerAddress: `0x${string}`;\n required: PersonalServerPaymentOperation;\n config: EscrowPaymentHeaderConfig;\n}): Promise<SignedEscrowPayment> {\n const { payerAddress, required, config } = params;\n validateSigningOperation(payerAddress, required);\n const nonceSource = config.nonceSource ?? processLocalNonceSource;\n const paymentNonce = BigInt(\n required.paymentNonce ?? (await nonceSource(payerAddress)),\n );\n const asset = (required.asset || NATIVE_ASSET_ADDRESS) as `0x${string}`;\n const opId = required.opId as `0x${string}`;\n const amount = BigInt(required.amount);\n if (amount < 0n || amount > UINT256_MAX) {\n throw new Error(\"Payment amount must be a uint256\");\n }\n if (paymentNonce <= 0n || paymentNonce > UINT256_MAX) {\n throw new Error(\"Payment nonce must be a positive uint256\");\n }\n\n const message = {\n payerAddress,\n opType: required.opType,\n opId,\n asset,\n amount,\n paymentNonce,\n };\n\n const signature = await config.signTypedData({\n domain: genericPaymentDomain(config.chainId, config.escrowContract),\n types: GENERIC_PAYMENT_TYPES,\n primaryType: \"GenericPayment\",\n message,\n });\n\n return {\n message: {\n ...message,\n amount: amount.toString(),\n paymentNonce: paymentNonce.toString(),\n },\n signature,\n ...(required.accessRecord ? { accessRecord: required.accessRecord } : {}),\n };\n}\n\n/**\n * Build the canonical X-PAYMENT header for a validated escrow operation.\n *\n * @remarks\n * Supports both legacy grant payments and receipt-bound data-access payments.\n * Signing is injected through {@link EscrowPaymentHeaderConfig.signTypedData}.\n */\nexport async function buildEscrowPaymentHeader(params: {\n /** Address whose escrow balance pays for the operation. */\n payerAddress: `0x${string}`;\n /** Validated operation parsed from the Personal Server challenge. */\n required: PersonalServerPaymentOperation;\n /** Escrow contract, chain, signer, and nonce configuration. */\n config: EscrowPaymentHeaderConfig;\n}): Promise<string> {\n const network = params.required.network ?? `vana:${params.config.chainId}`;\n if (network !== `vana:${params.config.chainId}`) {\n throw new Error(\"Payment network must match the configured chain\");\n }\n\n const signed = await signEscrowPayment(params);\n const payment: X402PaymentHeader = {\n x402Version: 1,\n scheme: \"vana-escrow-grant\",\n network,\n payload: signed,\n };\n return base64EncodeJson(payment);\n}\n\n/** Build a legacy grant X-PAYMENT header. */\nexport async function buildGrantPaymentHeader(params: {\n payerAddress: `0x${string}`;\n required: PersonalServerPaymentRequired;\n config: EscrowPaymentConfig;\n}): Promise<string> {\n return buildEscrowPaymentHeader({\n ...params,\n required: {\n ...params.required,\n opType: GRANT_OP_TYPE,\n opId: params.required.grantId,\n },\n });\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction stringField(\n value: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n const field = value?.[key];\n return typeof field === \"string\" ? field : undefined;\n}\n\nfunction isCanonicalIsoTimestamp(value: string): boolean {\n try {\n return new Date(value).toISOString() === value;\n } catch {\n return false;\n }\n}\n\n/**\n * Parse shape-validated payment response metadata echoed by a Personal Server.\n *\n * @remarks\n * This metadata is not authenticated by the gateway. It is suitable for\n * display and debugging, not as proof that a payment occurred.\n */\nexport function paymentResponseMetadataFromHeader(\n header: string | null | undefined,\n): DirectPaymentResponseMetadata | undefined {\n if (!header) return undefined;\n try {\n const result = asRecord(base64DecodeJson(header));\n const breakdown = asRecord(result?.breakdown);\n const opType = stringField(result, \"opType\");\n const opId = stringField(result, \"opId\");\n const payerAddress = stringField(result, \"payerAddress\");\n const asset = stringField(result, \"asset\");\n const amount = stringField(result, \"amount\");\n const paymentNonce = stringField(result, \"paymentNonce\");\n const registrationFee = stringField(breakdown, \"registrationFee\");\n const dataAccessFee = stringField(breakdown, \"dataAccessFee\");\n const paidAt = stringField(result, \"paidAt\");\n if (\n result?.success !== true ||\n !opType ||\n !opId ||\n !BYTES32_RE.test(opId) ||\n !payerAddress ||\n !ADDRESS_RE.test(payerAddress) ||\n !asset ||\n !ADDRESS_RE.test(asset) ||\n !amount ||\n !isUint256Decimal(amount, true) ||\n !paymentNonce ||\n !isUint256Decimal(paymentNonce, false) ||\n !registrationFee ||\n !isUint256Decimal(registrationFee, true) ||\n !dataAccessFee ||\n !isUint256Decimal(dataAccessFee, true) ||\n typeof breakdown?.registrationPaid !== \"boolean\" ||\n !paidAt ||\n !isCanonicalIsoTimestamp(paidAt)\n ) {\n return undefined;\n }\n return {\n opType,\n opId,\n asset,\n amount,\n paymentNonce,\n breakdown: {\n registrationFee,\n dataAccessFee,\n registrationPaid: breakdown.registrationPaid,\n },\n paidAt,\n };\n } catch {\n return undefined;\n }\n}\n\n/**\n * @deprecated Use {@link paymentResponseMetadataFromHeader}. A Personal\n * Server response header is untrusted metadata, not a gateway-authenticated\n * receipt.\n */\nexport function paymentReceiptFromHeader(\n header: string | null | undefined,\n): DirectPaymentResponseMetadata | undefined {\n return paymentResponseMetadataFromHeader(header);\n}\n\n/**\n * Authorize an escrow payment for a grant data-access fee.\n *\n * @param params - The payment requirement, the payer address, and escrow config.\n * @returns The gateway's {@link EscrowPayResult} as a typed\n * {@link DirectPaymentReceipt}.\n */\nexport async function authorizeGrantPayment(params: {\n payerAddress: `0x${string}`;\n required: PersonalServerPaymentRequired;\n config: EscrowPaymentConfig;\n}): Promise<DirectPaymentReceipt> {\n return authorizeEscrowPayment({\n ...params,\n required: {\n ...params.required,\n opType: GRANT_OP_TYPE,\n opId: params.required.grantId,\n },\n });\n}\n\n/**\n * Authorize a validated grant or data-access operation through the escrow\n * gateway.\n */\nexport async function authorizeEscrowPayment(params: {\n /** Address whose escrow balance pays for the operation. */\n payerAddress: `0x${string}`;\n /** Validated operation to authorize. */\n required: PersonalServerPaymentOperation;\n /** Escrow gateway and signing configuration. */\n config: EscrowPaymentConfig;\n}): Promise<DirectPaymentReceipt> {\n const { payerAddress, config } = params;\n const signed = await signEscrowPayment(params);\n\n const result = await config.client.payForOp({\n payerAddress,\n opType: signed.message.opType,\n opId: signed.message.opId,\n asset: signed.message.asset,\n amount: signed.message.amount,\n paymentNonce: signed.message.paymentNonce,\n signature: signed.signature,\n accessRecord: signed.accessRecord,\n });\n\n return toDirectPaymentReceipt(result);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/direct/escrow-payment.ts"],"sourcesContent":["/**\n * Escrow-backed payment authorization for the Direct Data Controller.\n *\n * @remarks\n * Builds on the DPv2 escrow surface added in `protocol/escrow`. When a Personal\n * Server read returns `402 Payment Required`, the controller settles the\n * challenged operation through the escrow gateway:\n *\n * 1. Sign the challenge's `GenericPayment` EIP-712 message with the app key.\n * 2. POST it to the gateway's `/v1/escrow/pay` via {@link EscrowGatewayClient}.\n * 3. Map the gateway's {@link EscrowPayResult} into a typed\n * {@link DirectPaymentReceipt} for the caller to inspect.\n *\n * This module supports legacy `\"grant\"` operations and receipt-bound\n * `\"data_access\"` operations. It adapts the escrow `payForOp` flow to the\n * direct-read use case; it does not define its own payment scheme.\n *\n * @category Direct\n * @module direct/escrow-payment\n */\n\nimport {\n GENERIC_PAYMENT_TYPES,\n NATIVE_ASSET_ADDRESS,\n genericPaymentDomain,\n type EscrowAccessRecord,\n type EscrowPaymentClient,\n type EscrowPayResult,\n type PaymentBreakdown,\n} from \"../protocol/escrow\";\nimport type {\n DirectFeeBreakdown,\n DirectPaymentReceipt,\n DirectPaymentResponseMetadata,\n PersonalServerPaymentOperation,\n PersonalServerPaymentRequired,\n} from \"./types\";\n\n/** The escrow `GenericPayment.opType` used for grant-lifecycle payments. */\nexport const GRANT_OP_TYPE = \"grant\" as const;\n/** The escrow `GenericPayment.opType` used for receipt-bound data access. */\nexport const DATA_ACCESS_OP_TYPE = \"data_access\" as const;\n\n/**\n * EIP-712 typed-data signer (e.g. viem `account.signTypedData`).\n *\n * @remarks\n * Kept structurally minimal so any viem account/wallet client satisfies it\n * without the SDK depending on viem's exact `signTypedData` overload set.\n */\nexport type SignTypedDataFn = (args: {\n domain: ReturnType<typeof genericPaymentDomain>;\n types: typeof GENERIC_PAYMENT_TYPES;\n primaryType: \"GenericPayment\";\n message: {\n payerAddress: `0x${string}`;\n opType: string;\n opId: `0x${string}`;\n asset: `0x${string}`;\n amount: bigint;\n paymentNonce: bigint;\n };\n}) => Promise<`0x${string}`>;\n\n/** Supplies a monotonically-increasing payment nonce per payer. */\nexport type PaymentNonceSource = (\n payerAddress: string,\n) => Promise<bigint> | bigint;\n\ninterface EscrowPaymentMessage {\n payerAddress: `0x${string}`;\n opType: typeof GRANT_OP_TYPE | typeof DATA_ACCESS_OP_TYPE;\n opId: `0x${string}`;\n asset: `0x${string}`;\n amount: string;\n paymentNonce: string;\n}\n\ninterface SignedEscrowPayment {\n message: EscrowPaymentMessage;\n signature: `0x${string}`;\n accessRecord?: EscrowAccessRecord;\n}\n\ninterface X402PaymentHeader {\n x402Version: 1;\n scheme: \"vana-escrow-grant\";\n network: string;\n payload: SignedEscrowPayment;\n}\n\n/** Configuration required to sign an escrow X-PAYMENT header. */\nexport interface EscrowPaymentHeaderConfig {\n /** Deployed `DataPortabilityEscrow` contract address. */\n escrowContract: `0x${string}`;\n /** Chain id for the EIP-712 domain (1480 mainnet, 14800 moksha). */\n chainId: number;\n /** App EIP-712 signer. */\n signTypedData: SignTypedDataFn;\n /**\n * Supplies the next payment nonce for a payer. Defaults to a process-local\n * monotonic counter seeded at 1. Provide a durable source in production so\n * nonces survive restarts (the gateway rejects reused (payer, nonce) pairs).\n */\n nonceSource?: PaymentNonceSource;\n}\n\n/**\n * Escrow settlement configuration for gateway authorization.\n *\n * @remarks\n * Extends the header-signing boundary with the gateway client used by\n * {@link authorizeEscrowPayment}. Existing controller and legacy wrapper\n * callers can continue to provide this full configuration.\n */\nexport interface EscrowPaymentConfig extends EscrowPaymentHeaderConfig {\n /** Client for the gateway escrow endpoints (`/v1/escrow/*`). */\n client: EscrowPaymentClient;\n}\n\n/** Map the gateway {@link PaymentBreakdown} into the public {@link DirectFeeBreakdown}. */\nexport function toDirectFeeBreakdown(\n breakdown: PaymentBreakdown,\n): DirectFeeBreakdown {\n return {\n registrationFee: breakdown.registrationFee,\n dataAccessFee: breakdown.dataAccessFee,\n registrationPaid: breakdown.registrationPaid,\n };\n}\n\n/** Map a gateway {@link EscrowPayResult} into the public {@link DirectPaymentReceipt}. */\nexport function toDirectPaymentReceipt(\n result: EscrowPayResult,\n): DirectPaymentReceipt {\n return {\n opType: result.opType,\n opId: result.opId,\n asset: result.asset,\n amount: result.amount,\n paymentNonce: result.paymentNonce,\n breakdown: toDirectFeeBreakdown(result.breakdown),\n paidAt: result.paidAt,\n };\n}\n\n/** Default in-process monotonic nonce counter (seeded at 1 per payer). */\nexport function createDefaultNonceSource(): PaymentNonceSource {\n const counters = new Map<string, bigint>();\n return (payerAddress: string): bigint => {\n const key = payerAddress.toLowerCase();\n const next = (counters.get(key) ?? 0n) + 1n;\n counters.set(key, next);\n return next;\n };\n}\n\nconst processLocalNonceSource = createDefaultNonceSource();\nconst UINT256_MAX = (1n << 256n) - 1n;\nconst ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;\nconst BYTES32_RE = /^0x[0-9a-fA-F]{64}$/;\nconst SIGNATURE_RE = /^0x[0-9a-fA-F]{130}$/;\n\nfunction isUint256Decimal(value: string, allowZero: boolean): boolean {\n const pattern = allowZero ? /^(0|[1-9]\\d*)$/ : /^[1-9]\\d*$/;\n return (\n value.length <= UINT256_MAX.toString().length &&\n pattern.test(value) &&\n BigInt(value) <= UINT256_MAX\n );\n}\n\nfunction isValidAccessRecord(record: EscrowAccessRecord): boolean {\n return (\n BYTES32_RE.test(record.dataPointId) &&\n isUint256Decimal(record.version, false) &&\n ADDRESS_RE.test(record.accessor) &&\n BYTES32_RE.test(record.recordId) &&\n SIGNATURE_RE.test(record.signature)\n );\n}\n\nfunction validateSigningOperation(\n payerAddress: `0x${string}`,\n required: PersonalServerPaymentOperation,\n): void {\n if (!ADDRESS_RE.test(payerAddress)) {\n throw new Error(\"Payment payer must be a 20-byte EVM address\");\n }\n if (!BYTES32_RE.test(required.opId)) {\n throw new Error(\"Payment operation id must be a 32-byte hex value\");\n }\n if (!ADDRESS_RE.test(required.asset || NATIVE_ASSET_ADDRESS)) {\n throw new Error(\"Payment asset must be a 20-byte EVM address\");\n }\n if (!isUint256Decimal(required.amount, true)) {\n throw new Error(\"Payment amount must be a canonical uint256 decimal\");\n }\n if (\n required.paymentNonce !== undefined &&\n !isUint256Decimal(required.paymentNonce, false)\n ) {\n throw new Error(\"Payment nonce must be a positive uint256 decimal\");\n }\n\n const accessRecord = required.accessRecord;\n if (required.opType === DATA_ACCESS_OP_TYPE) {\n if (!accessRecord || !isValidAccessRecord(accessRecord)) {\n throw new Error(\"Data-access payment requires a valid access record\");\n }\n if (required.opId.toLowerCase() !== accessRecord.recordId.toLowerCase()) {\n throw new Error(\n \"Data-access payment operation id must equal the access record id\",\n );\n }\n if (accessRecord.accessor.toLowerCase() !== payerAddress.toLowerCase()) {\n throw new Error(\n \"Data-access payment accessor must equal the payment payer address\",\n );\n }\n return;\n }\n\n if (required.amount === \"0\") {\n if (\n !accessRecord ||\n !isValidAccessRecord(accessRecord) ||\n accessRecord.accessor.toLowerCase() !== payerAddress.toLowerCase()\n ) {\n throw new Error(\n \"Zero-amount grant payments require a valid access record for the payer\",\n );\n }\n }\n}\n\nfunction base64EncodeJson(value: unknown): string {\n const bytes = new TextEncoder().encode(JSON.stringify(value));\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary);\n}\n\nfunction base64DecodeJson(value: string): unknown {\n const binary = atob(value);\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n return JSON.parse(new TextDecoder().decode(bytes));\n}\n\nasync function signEscrowPayment(params: {\n payerAddress: `0x${string}`;\n required: PersonalServerPaymentOperation;\n config: EscrowPaymentHeaderConfig;\n}): Promise<SignedEscrowPayment> {\n const { payerAddress, required, config } = params;\n validateSigningOperation(payerAddress, required);\n const nonceSource = config.nonceSource ?? processLocalNonceSource;\n const paymentNonce = BigInt(\n required.paymentNonce ?? (await nonceSource(payerAddress)),\n );\n const asset = (required.asset || NATIVE_ASSET_ADDRESS) as `0x${string}`;\n const opId = required.opId as `0x${string}`;\n const amount = BigInt(required.amount);\n if (amount < 0n || amount > UINT256_MAX) {\n throw new Error(\"Payment amount must be a uint256\");\n }\n if (paymentNonce <= 0n || paymentNonce > UINT256_MAX) {\n throw new Error(\"Payment nonce must be a positive uint256\");\n }\n\n const message = {\n payerAddress,\n opType: required.opType,\n opId,\n asset,\n amount,\n paymentNonce,\n };\n\n const signature = await config.signTypedData({\n domain: genericPaymentDomain(config.chainId, config.escrowContract),\n types: GENERIC_PAYMENT_TYPES,\n primaryType: \"GenericPayment\",\n message,\n });\n\n return {\n message: {\n ...message,\n amount: amount.toString(),\n paymentNonce: paymentNonce.toString(),\n },\n signature,\n ...(required.accessRecord ? { accessRecord: required.accessRecord } : {}),\n };\n}\n\n/**\n * Build the canonical X-PAYMENT header for a validated escrow operation.\n *\n * @remarks\n * Supports both legacy grant payments and receipt-bound data-access payments.\n * Signing is injected through {@link EscrowPaymentHeaderConfig.signTypedData}.\n */\nexport async function buildEscrowPaymentHeader(params: {\n /** Address whose escrow balance pays for the operation. */\n payerAddress: `0x${string}`;\n /** Validated operation parsed from the Personal Server challenge. */\n required: PersonalServerPaymentOperation;\n /** Escrow contract, chain, signer, and nonce configuration. */\n config: EscrowPaymentHeaderConfig;\n}): Promise<string> {\n const network = params.required.network ?? `vana:${params.config.chainId}`;\n if (network !== `vana:${params.config.chainId}`) {\n throw new Error(\"Payment network must match the configured chain\");\n }\n\n const signed = await signEscrowPayment(params);\n const payment: X402PaymentHeader = {\n x402Version: 1,\n scheme: \"vana-escrow-grant\",\n network,\n payload: signed,\n };\n return base64EncodeJson(payment);\n}\n\n/** Build a legacy grant X-PAYMENT header. */\nexport async function buildGrantPaymentHeader(params: {\n payerAddress: `0x${string}`;\n required: PersonalServerPaymentRequired;\n config: EscrowPaymentConfig;\n}): Promise<string> {\n return buildEscrowPaymentHeader({\n ...params,\n required: {\n ...params.required,\n opType: GRANT_OP_TYPE,\n opId: params.required.grantId,\n },\n });\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction stringField(\n value: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n const field = value?.[key];\n return typeof field === \"string\" ? field : undefined;\n}\n\nfunction isCanonicalIsoTimestamp(value: string): boolean {\n try {\n return new Date(value).toISOString() === value;\n } catch {\n return false;\n }\n}\n\n/**\n * Parse shape-validated payment response metadata echoed by a Personal Server.\n *\n * @remarks\n * This metadata is not authenticated by the gateway. It is suitable for\n * display and debugging, not as proof that a payment occurred.\n */\nexport function paymentResponseMetadataFromHeader(\n header: string | null | undefined,\n): DirectPaymentResponseMetadata | undefined {\n if (!header) return undefined;\n try {\n const result = asRecord(base64DecodeJson(header));\n const breakdown = asRecord(result?.breakdown);\n const opType = stringField(result, \"opType\");\n const opId = stringField(result, \"opId\");\n const payerAddress = stringField(result, \"payerAddress\");\n const asset = stringField(result, \"asset\");\n const amount = stringField(result, \"amount\");\n const paymentNonce = stringField(result, \"paymentNonce\");\n const registrationFee = stringField(breakdown, \"registrationFee\");\n const dataAccessFee = stringField(breakdown, \"dataAccessFee\");\n const paidAt = stringField(result, \"paidAt\");\n if (\n result?.success !== true ||\n !opType ||\n !opId ||\n !BYTES32_RE.test(opId) ||\n !payerAddress ||\n !ADDRESS_RE.test(payerAddress) ||\n !asset ||\n !ADDRESS_RE.test(asset) ||\n !amount ||\n !isUint256Decimal(amount, true) ||\n !paymentNonce ||\n !isUint256Decimal(paymentNonce, false) ||\n !registrationFee ||\n !isUint256Decimal(registrationFee, true) ||\n !dataAccessFee ||\n !isUint256Decimal(dataAccessFee, true) ||\n typeof breakdown?.registrationPaid !== \"boolean\" ||\n !paidAt ||\n !isCanonicalIsoTimestamp(paidAt)\n ) {\n return undefined;\n }\n return {\n opType,\n opId,\n asset,\n amount,\n paymentNonce,\n breakdown: {\n registrationFee,\n dataAccessFee,\n registrationPaid: breakdown.registrationPaid,\n },\n paidAt,\n };\n } catch {\n return undefined;\n }\n}\n\n/**\n * @deprecated Use {@link paymentResponseMetadataFromHeader}. A Personal\n * Server response header is untrusted metadata, not a gateway-authenticated\n * receipt.\n */\nexport function paymentReceiptFromHeader(\n header: string | null | undefined,\n): DirectPaymentResponseMetadata | undefined {\n return paymentResponseMetadataFromHeader(header);\n}\n\n/**\n * Authorize an escrow payment for a grant data-access fee.\n *\n * @param params - The payment requirement, the payer address, and escrow config.\n * @returns The gateway's {@link EscrowPayResult} as a typed\n * {@link DirectPaymentReceipt}.\n */\nexport async function authorizeGrantPayment(params: {\n payerAddress: `0x${string}`;\n required: PersonalServerPaymentRequired;\n config: EscrowPaymentConfig;\n}): Promise<DirectPaymentReceipt> {\n return authorizeEscrowPayment({\n ...params,\n required: {\n ...params.required,\n opType: GRANT_OP_TYPE,\n opId: params.required.grantId,\n },\n });\n}\n\n/**\n * Authorize a validated grant or data-access operation through the escrow\n * gateway.\n */\nexport async function authorizeEscrowPayment(params: {\n /** Address whose escrow balance pays for the operation. */\n payerAddress: `0x${string}`;\n /** Validated operation to authorize. */\n required: PersonalServerPaymentOperation;\n /** Escrow gateway and signing configuration. */\n config: EscrowPaymentConfig;\n}): Promise<DirectPaymentReceipt> {\n const { payerAddress, config } = params;\n const signed = await signEscrowPayment(params);\n\n const result = await config.client.payForOp({\n payerAddress,\n opType: signed.message.opType,\n opId: signed.message.opId,\n asset: signed.message.asset,\n amount: signed.message.amount,\n paymentNonce: signed.message.paymentNonce,\n signature: signed.signature,\n accessRecord: signed.accessRecord,\n });\n\n return toDirectPaymentReceipt(result);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBA,oBAQO;AAUA,MAAM,gBAAgB;AAEtB,MAAM,sBAAsB;AAgF5B,SAAS,qBACd,WACoB;AACpB,SAAO;AAAA,IACL,iBAAiB,UAAU;AAAA,IAC3B,eAAe,UAAU;AAAA,IACzB,kBAAkB,UAAU;AAAA,EAC9B;AACF;AAGO,SAAS,uBACd,QACsB;AACtB,SAAO;AAAA,IACL,QAAQ,OAAO;AAAA,IACf,MAAM,OAAO;AAAA,IACb,OAAO,OAAO;AAAA,IACd,QAAQ,OAAO;AAAA,IACf,cAAc,OAAO;AAAA,IACrB,WAAW,qBAAqB,OAAO,SAAS;AAAA,IAChD,QAAQ,OAAO;AAAA,EACjB;AACF;AAGO,SAAS,2BAA+C;AAC7D,QAAM,WAAW,oBAAI,IAAoB;AACzC,SAAO,CAAC,iBAAiC;AACvC,UAAM,MAAM,aAAa,YAAY;AACrC,UAAM,QAAQ,SAAS,IAAI,GAAG,KAAK,MAAM;AACzC,aAAS,IAAI,KAAK,IAAI;AACtB,WAAO;AAAA,EACT;AACF;AAEA,MAAM,0BAA0B,yBAAyB;AACzD,MAAM,eAAe,MAAM,QAAQ;AACnC,MAAM,aAAa;AACnB,MAAM,aAAa;AACnB,MAAM,eAAe;AAErB,SAAS,iBAAiB,OAAe,WAA6B;AACpE,QAAM,UAAU,YAAY,mBAAmB;AAC/C,SACE,MAAM,UAAU,YAAY,SAAS,EAAE,UACvC,QAAQ,KAAK,KAAK,KAClB,OAAO,KAAK,KAAK;AAErB;AAEA,SAAS,oBAAoB,QAAqC;AAChE,SACE,WAAW,KAAK,OAAO,WAAW,KAClC,iBAAiB,OAAO,SAAS,KAAK,KACtC,WAAW,KAAK,OAAO,QAAQ,KAC/B,WAAW,KAAK,OAAO,QAAQ,KAC/B,aAAa,KAAK,OAAO,SAAS;AAEtC;AAEA,SAAS,yBACP,cACA,UACM;AACN,MAAI,CAAC,WAAW,KAAK,YAAY,GAAG;AAClC,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACA,MAAI,CAAC,WAAW,KAAK,SAAS,IAAI,GAAG;AACnC,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AACA,MAAI,CAAC,WAAW,KAAK,SAAS,SAAS,kCAAoB,GAAG;AAC5D,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACA,MAAI,CAAC,iBAAiB,SAAS,QAAQ,IAAI,GAAG;AAC5C,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACtE;AACA,MACE,SAAS,iBAAiB,UAC1B,CAAC,iBAAiB,SAAS,cAAc,KAAK,GAC9C;AACA,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACpE;AAEA,QAAM,eAAe,SAAS;AAC9B,MAAI,SAAS,WAAW,qBAAqB;AAC3C,QAAI,CAAC,gBAAgB,CAAC,oBAAoB,YAAY,GAAG;AACvD,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,QAAI,SAAS,KAAK,YAAY,MAAM,aAAa,SAAS,YAAY,GAAG;AACvE,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,aAAa,SAAS,YAAY,MAAM,aAAa,YAAY,GAAG;AACtE,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AAEA,MAAI,SAAS,WAAW,KAAK;AAC3B,QACE,CAAC,gBACD,CAAC,oBAAoB,YAAY,KACjC,aAAa,SAAS,YAAY,MAAM,aAAa,YAAY,GACjE;AACA,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,iBAAiB,OAAwB;AAChD,QAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,KAAK,UAAU,KAAK,CAAC;AAC5D,MAAI,SAAS;AACb,aAAW,QAAQ,MAAO,WAAU,OAAO,aAAa,IAAI;AAC5D,SAAO,KAAK,MAAM;AACpB;AAEA,SAAS,iBAAiB,OAAwB;AAChD,QAAM,SAAS,KAAK,KAAK;AACzB,QAAM,QAAQ,WAAW,KAAK,QAAQ,CAAC,SAAS,KAAK,WAAW,CAAC,CAAC;AAClE,SAAO,KAAK,MAAM,IAAI,YAAY,EAAE,OAAO,KAAK,CAAC;AACnD;AAEA,eAAe,kBAAkB,QAIA;AAC/B,QAAM,EAAE,cAAc,UAAU,OAAO,IAAI;AAC3C,2BAAyB,cAAc,QAAQ;AAC/C,QAAM,cAAc,OAAO,eAAe;AAC1C,QAAM,eAAe;AAAA,IACnB,SAAS,gBAAiB,MAAM,YAAY,YAAY;AAAA,EAC1D;AACA,QAAM,QAAS,SAAS,SAAS;AACjC,QAAM,OAAO,SAAS;AACtB,QAAM,SAAS,OAAO,SAAS,MAAM;AACrC,MAAI,SAAS,MAAM,SAAS,aAAa;AACvC,UAAM,IAAI,MAAM,kCAAkC;AAAA,EACpD;AACA,MAAI,gBAAgB,MAAM,eAAe,aAAa;AACpD,UAAM,IAAI,MAAM,0CAA0C;AAAA,EAC5D;AAEA,QAAM,UAAU;AAAA,IACd;AAAA,IACA,QAAQ,SAAS;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,YAAY,MAAM,OAAO,cAAc;AAAA,IAC3C,YAAQ,oCAAqB,OAAO,SAAS,OAAO,cAAc;AAAA,IAClE,OAAO;AAAA,IACP,aAAa;AAAA,IACb;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,SAAS;AAAA,MACP,GAAG;AAAA,MACH,QAAQ,OAAO,SAAS;AAAA,MACxB,cAAc,aAAa,SAAS;AAAA,IACtC;AAAA,IACA;AAAA,IACA,GAAI,SAAS,eAAe,EAAE,cAAc,SAAS,aAAa,IAAI,CAAC;AAAA,EACzE;AACF;AASA,eAAsB,yBAAyB,QAO3B;AAClB,QAAM,UAAU,OAAO,SAAS,WAAW,QAAQ,OAAO,OAAO,OAAO;AACxE,MAAI,YAAY,QAAQ,OAAO,OAAO,OAAO,IAAI;AAC/C,UAAM,IAAI,MAAM,iDAAiD;AAAA,EACnE;AAEA,QAAM,SAAS,MAAM,kBAAkB,MAAM;AAC7C,QAAM,UAA6B;AAAA,IACjC,aAAa;AAAA,IACb,QAAQ;AAAA,IACR;AAAA,IACA,SAAS;AAAA,EACX;AACA,SAAO,iBAAiB,OAAO;AACjC;AAGA,eAAsB,wBAAwB,QAI1B;AAClB,SAAO,yBAAyB;AAAA,IAC9B,GAAG;AAAA,IACH,UAAU;AAAA,MACR,GAAG,OAAO;AAAA,MACV,QAAQ;AAAA,MACR,MAAM,OAAO,SAAS;AAAA,IACxB;AAAA,EACF,CAAC;AACH;AAEA,SAAS,SAAS,OAAqD;AACrE,SAAO,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IAC5D,QACD;AACN;AAEA,SAAS,YACP,OACA,KACoB;AACpB,QAAM,QAAQ,QAAQ,GAAG;AACzB,SAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C;AAEA,SAAS,wBAAwB,OAAwB;AACvD,MAAI;AACF,WAAO,IAAI,KAAK,KAAK,EAAE,YAAY,MAAM;AAAA,EAC3C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASO,SAAS,kCACd,QAC2C;AAC3C,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI;AACF,UAAM,SAAS,SAAS,iBAAiB,MAAM,CAAC;AAChD,UAAM,YAAY,SAAS,QAAQ,SAAS;AAC5C,UAAM,SAAS,YAAY,QAAQ,QAAQ;AAC3C,UAAM,OAAO,YAAY,QAAQ,MAAM;AACvC,UAAM,eAAe,YAAY,QAAQ,cAAc;AACvD,UAAM,QAAQ,YAAY,QAAQ,OAAO;AACzC,UAAM,SAAS,YAAY,QAAQ,QAAQ;AAC3C,UAAM,eAAe,YAAY,QAAQ,cAAc;AACvD,UAAM,kBAAkB,YAAY,WAAW,iBAAiB;AAChE,UAAM,gBAAgB,YAAY,WAAW,eAAe;AAC5D,UAAM,SAAS,YAAY,QAAQ,QAAQ;AAC3C,QACE,QAAQ,YAAY,QACpB,CAAC,UACD,CAAC,QACD,CAAC,WAAW,KAAK,IAAI,KACrB,CAAC,gBACD,CAAC,WAAW,KAAK,YAAY,KAC7B,CAAC,SACD,CAAC,WAAW,KAAK,KAAK,KACtB,CAAC,UACD,CAAC,iBAAiB,QAAQ,IAAI,KAC9B,CAAC,gBACD,CAAC,iBAAiB,cAAc,KAAK,KACrC,CAAC,mBACD,CAAC,iBAAiB,iBAAiB,IAAI,KACvC,CAAC,iBACD,CAAC,iBAAiB,eAAe,IAAI,KACrC,OAAO,WAAW,qBAAqB,aACvC,CAAC,UACD,CAAC,wBAAwB,MAAM,GAC/B;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA,kBAAkB,UAAU;AAAA,MAC9B;AAAA,MACA;AAAA,IACF;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOO,SAAS,yBACd,QAC2C;AAC3C,SAAO,kCAAkC,MAAM;AACjD;AASA,eAAsB,sBAAsB,QAIV;AAChC,SAAO,uBAAuB;AAAA,IAC5B,GAAG;AAAA,IACH,UAAU;AAAA,MACR,GAAG,OAAO;AAAA,MACV,QAAQ;AAAA,MACR,MAAM,OAAO,SAAS;AAAA,IACxB;AAAA,EACF,CAAC;AACH;AAMA,eAAsB,uBAAuB,QAOX;AAChC,QAAM,EAAE,cAAc,OAAO,IAAI;AACjC,QAAM,SAAS,MAAM,kBAAkB,MAAM;AAE7C,QAAM,SAAS,MAAM,OAAO,OAAO,SAAS;AAAA,IAC1C;AAAA,IACA,QAAQ,OAAO,QAAQ;AAAA,IACvB,MAAM,OAAO,QAAQ;AAAA,IACrB,OAAO,OAAO,QAAQ;AAAA,IACtB,QAAQ,OAAO,QAAQ;AAAA,IACvB,cAAc,OAAO,QAAQ;AAAA,IAC7B,WAAW,OAAO;AAAA,IAClB,cAAc,OAAO;AAAA,EACvB,CAAC;AAED,SAAO,uBAAuB,MAAM;AACtC;","names":[]}
@@ -18,7 +18,7 @@
18
18
  * @category Direct
19
19
  * @module direct/escrow-payment
20
20
  */
21
- import { GENERIC_PAYMENT_TYPES, genericPaymentDomain, type EscrowGatewayClient, type EscrowPayResult, type PaymentBreakdown } from "../protocol/escrow.js";
21
+ import { GENERIC_PAYMENT_TYPES, genericPaymentDomain, type EscrowPaymentClient, type EscrowPayResult, type PaymentBreakdown } from "../protocol/escrow.js";
22
22
  import type { DirectFeeBreakdown, DirectPaymentReceipt, DirectPaymentResponseMetadata, PersonalServerPaymentOperation, PersonalServerPaymentRequired } from "./types.js";
23
23
  /** The escrow `GenericPayment.opType` used for grant-lifecycle payments. */
24
24
  export declare const GRANT_OP_TYPE: "grant";
@@ -71,7 +71,7 @@ export interface EscrowPaymentHeaderConfig {
71
71
  */
72
72
  export interface EscrowPaymentConfig extends EscrowPaymentHeaderConfig {
73
73
  /** Client for the gateway escrow endpoints (`/v1/escrow/*`). */
74
- client: EscrowGatewayClient;
74
+ client: EscrowPaymentClient;
75
75
  }
76
76
  /** Map the gateway {@link PaymentBreakdown} into the public {@link DirectFeeBreakdown}. */
77
77
  export declare function toDirectFeeBreakdown(breakdown: PaymentBreakdown): DirectFeeBreakdown;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/direct/escrow-payment.ts"],"sourcesContent":["/**\n * Escrow-backed payment authorization for the Direct Data Controller.\n *\n * @remarks\n * Builds on the DPv2 escrow surface added in `protocol/escrow`. When a Personal\n * Server read returns `402 Payment Required`, the controller settles the\n * challenged operation through the escrow gateway:\n *\n * 1. Sign the challenge's `GenericPayment` EIP-712 message with the app key.\n * 2. POST it to the gateway's `/v1/escrow/pay` via {@link EscrowGatewayClient}.\n * 3. Map the gateway's {@link EscrowPayResult} into a typed\n * {@link DirectPaymentReceipt} for the caller to inspect.\n *\n * This module supports legacy `\"grant\"` operations and receipt-bound\n * `\"data_access\"` operations. It adapts the escrow `payForOp` flow to the\n * direct-read use case; it does not define its own payment scheme.\n *\n * @category Direct\n * @module direct/escrow-payment\n */\n\nimport {\n GENERIC_PAYMENT_TYPES,\n NATIVE_ASSET_ADDRESS,\n genericPaymentDomain,\n type EscrowAccessRecord,\n type EscrowGatewayClient,\n type EscrowPayResult,\n type PaymentBreakdown,\n} from \"../protocol/escrow\";\nimport type {\n DirectFeeBreakdown,\n DirectPaymentReceipt,\n DirectPaymentResponseMetadata,\n PersonalServerPaymentOperation,\n PersonalServerPaymentRequired,\n} from \"./types\";\n\n/** The escrow `GenericPayment.opType` used for grant-lifecycle payments. */\nexport const GRANT_OP_TYPE = \"grant\" as const;\n/** The escrow `GenericPayment.opType` used for receipt-bound data access. */\nexport const DATA_ACCESS_OP_TYPE = \"data_access\" as const;\n\n/**\n * EIP-712 typed-data signer (e.g. viem `account.signTypedData`).\n *\n * @remarks\n * Kept structurally minimal so any viem account/wallet client satisfies it\n * without the SDK depending on viem's exact `signTypedData` overload set.\n */\nexport type SignTypedDataFn = (args: {\n domain: ReturnType<typeof genericPaymentDomain>;\n types: typeof GENERIC_PAYMENT_TYPES;\n primaryType: \"GenericPayment\";\n message: {\n payerAddress: `0x${string}`;\n opType: string;\n opId: `0x${string}`;\n asset: `0x${string}`;\n amount: bigint;\n paymentNonce: bigint;\n };\n}) => Promise<`0x${string}`>;\n\n/** Supplies a monotonically-increasing payment nonce per payer. */\nexport type PaymentNonceSource = (\n payerAddress: string,\n) => Promise<bigint> | bigint;\n\ninterface EscrowPaymentMessage {\n payerAddress: `0x${string}`;\n opType: typeof GRANT_OP_TYPE | typeof DATA_ACCESS_OP_TYPE;\n opId: `0x${string}`;\n asset: `0x${string}`;\n amount: string;\n paymentNonce: string;\n}\n\ninterface SignedEscrowPayment {\n message: EscrowPaymentMessage;\n signature: `0x${string}`;\n accessRecord?: EscrowAccessRecord;\n}\n\ninterface X402PaymentHeader {\n x402Version: 1;\n scheme: \"vana-escrow-grant\";\n network: string;\n payload: SignedEscrowPayment;\n}\n\n/** Configuration required to sign an escrow X-PAYMENT header. */\nexport interface EscrowPaymentHeaderConfig {\n /** Deployed `DataPortabilityEscrow` contract address. */\n escrowContract: `0x${string}`;\n /** Chain id for the EIP-712 domain (1480 mainnet, 14800 moksha). */\n chainId: number;\n /** App EIP-712 signer. */\n signTypedData: SignTypedDataFn;\n /**\n * Supplies the next payment nonce for a payer. Defaults to a process-local\n * monotonic counter seeded at 1. Provide a durable source in production so\n * nonces survive restarts (the gateway rejects reused (payer, nonce) pairs).\n */\n nonceSource?: PaymentNonceSource;\n}\n\n/**\n * Escrow settlement configuration for gateway authorization.\n *\n * @remarks\n * Extends the header-signing boundary with the gateway client used by\n * {@link authorizeEscrowPayment}. Existing controller and legacy wrapper\n * callers can continue to provide this full configuration.\n */\nexport interface EscrowPaymentConfig extends EscrowPaymentHeaderConfig {\n /** Client for the gateway escrow endpoints (`/v1/escrow/*`). */\n client: EscrowGatewayClient;\n}\n\n/** Map the gateway {@link PaymentBreakdown} into the public {@link DirectFeeBreakdown}. */\nexport function toDirectFeeBreakdown(\n breakdown: PaymentBreakdown,\n): DirectFeeBreakdown {\n return {\n registrationFee: breakdown.registrationFee,\n dataAccessFee: breakdown.dataAccessFee,\n registrationPaid: breakdown.registrationPaid,\n };\n}\n\n/** Map a gateway {@link EscrowPayResult} into the public {@link DirectPaymentReceipt}. */\nexport function toDirectPaymentReceipt(\n result: EscrowPayResult,\n): DirectPaymentReceipt {\n return {\n opType: result.opType,\n opId: result.opId,\n asset: result.asset,\n amount: result.amount,\n paymentNonce: result.paymentNonce,\n breakdown: toDirectFeeBreakdown(result.breakdown),\n paidAt: result.paidAt,\n };\n}\n\n/** Default in-process monotonic nonce counter (seeded at 1 per payer). */\nexport function createDefaultNonceSource(): PaymentNonceSource {\n const counters = new Map<string, bigint>();\n return (payerAddress: string): bigint => {\n const key = payerAddress.toLowerCase();\n const next = (counters.get(key) ?? 0n) + 1n;\n counters.set(key, next);\n return next;\n };\n}\n\nconst processLocalNonceSource = createDefaultNonceSource();\nconst UINT256_MAX = (1n << 256n) - 1n;\nconst ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;\nconst BYTES32_RE = /^0x[0-9a-fA-F]{64}$/;\nconst SIGNATURE_RE = /^0x[0-9a-fA-F]{130}$/;\n\nfunction isUint256Decimal(value: string, allowZero: boolean): boolean {\n const pattern = allowZero ? /^(0|[1-9]\\d*)$/ : /^[1-9]\\d*$/;\n return (\n value.length <= UINT256_MAX.toString().length &&\n pattern.test(value) &&\n BigInt(value) <= UINT256_MAX\n );\n}\n\nfunction isValidAccessRecord(record: EscrowAccessRecord): boolean {\n return (\n BYTES32_RE.test(record.dataPointId) &&\n isUint256Decimal(record.version, false) &&\n ADDRESS_RE.test(record.accessor) &&\n BYTES32_RE.test(record.recordId) &&\n SIGNATURE_RE.test(record.signature)\n );\n}\n\nfunction validateSigningOperation(\n payerAddress: `0x${string}`,\n required: PersonalServerPaymentOperation,\n): void {\n if (!ADDRESS_RE.test(payerAddress)) {\n throw new Error(\"Payment payer must be a 20-byte EVM address\");\n }\n if (!BYTES32_RE.test(required.opId)) {\n throw new Error(\"Payment operation id must be a 32-byte hex value\");\n }\n if (!ADDRESS_RE.test(required.asset || NATIVE_ASSET_ADDRESS)) {\n throw new Error(\"Payment asset must be a 20-byte EVM address\");\n }\n if (!isUint256Decimal(required.amount, true)) {\n throw new Error(\"Payment amount must be a canonical uint256 decimal\");\n }\n if (\n required.paymentNonce !== undefined &&\n !isUint256Decimal(required.paymentNonce, false)\n ) {\n throw new Error(\"Payment nonce must be a positive uint256 decimal\");\n }\n\n const accessRecord = required.accessRecord;\n if (required.opType === DATA_ACCESS_OP_TYPE) {\n if (!accessRecord || !isValidAccessRecord(accessRecord)) {\n throw new Error(\"Data-access payment requires a valid access record\");\n }\n if (required.opId.toLowerCase() !== accessRecord.recordId.toLowerCase()) {\n throw new Error(\n \"Data-access payment operation id must equal the access record id\",\n );\n }\n if (accessRecord.accessor.toLowerCase() !== payerAddress.toLowerCase()) {\n throw new Error(\n \"Data-access payment accessor must equal the payment payer address\",\n );\n }\n return;\n }\n\n if (required.amount === \"0\") {\n if (\n !accessRecord ||\n !isValidAccessRecord(accessRecord) ||\n accessRecord.accessor.toLowerCase() !== payerAddress.toLowerCase()\n ) {\n throw new Error(\n \"Zero-amount grant payments require a valid access record for the payer\",\n );\n }\n }\n}\n\nfunction base64EncodeJson(value: unknown): string {\n const bytes = new TextEncoder().encode(JSON.stringify(value));\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary);\n}\n\nfunction base64DecodeJson(value: string): unknown {\n const binary = atob(value);\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n return JSON.parse(new TextDecoder().decode(bytes));\n}\n\nasync function signEscrowPayment(params: {\n payerAddress: `0x${string}`;\n required: PersonalServerPaymentOperation;\n config: EscrowPaymentHeaderConfig;\n}): Promise<SignedEscrowPayment> {\n const { payerAddress, required, config } = params;\n validateSigningOperation(payerAddress, required);\n const nonceSource = config.nonceSource ?? processLocalNonceSource;\n const paymentNonce = BigInt(\n required.paymentNonce ?? (await nonceSource(payerAddress)),\n );\n const asset = (required.asset || NATIVE_ASSET_ADDRESS) as `0x${string}`;\n const opId = required.opId as `0x${string}`;\n const amount = BigInt(required.amount);\n if (amount < 0n || amount > UINT256_MAX) {\n throw new Error(\"Payment amount must be a uint256\");\n }\n if (paymentNonce <= 0n || paymentNonce > UINT256_MAX) {\n throw new Error(\"Payment nonce must be a positive uint256\");\n }\n\n const message = {\n payerAddress,\n opType: required.opType,\n opId,\n asset,\n amount,\n paymentNonce,\n };\n\n const signature = await config.signTypedData({\n domain: genericPaymentDomain(config.chainId, config.escrowContract),\n types: GENERIC_PAYMENT_TYPES,\n primaryType: \"GenericPayment\",\n message,\n });\n\n return {\n message: {\n ...message,\n amount: amount.toString(),\n paymentNonce: paymentNonce.toString(),\n },\n signature,\n ...(required.accessRecord ? { accessRecord: required.accessRecord } : {}),\n };\n}\n\n/**\n * Build the canonical X-PAYMENT header for a validated escrow operation.\n *\n * @remarks\n * Supports both legacy grant payments and receipt-bound data-access payments.\n * Signing is injected through {@link EscrowPaymentHeaderConfig.signTypedData}.\n */\nexport async function buildEscrowPaymentHeader(params: {\n /** Address whose escrow balance pays for the operation. */\n payerAddress: `0x${string}`;\n /** Validated operation parsed from the Personal Server challenge. */\n required: PersonalServerPaymentOperation;\n /** Escrow contract, chain, signer, and nonce configuration. */\n config: EscrowPaymentHeaderConfig;\n}): Promise<string> {\n const network = params.required.network ?? `vana:${params.config.chainId}`;\n if (network !== `vana:${params.config.chainId}`) {\n throw new Error(\"Payment network must match the configured chain\");\n }\n\n const signed = await signEscrowPayment(params);\n const payment: X402PaymentHeader = {\n x402Version: 1,\n scheme: \"vana-escrow-grant\",\n network,\n payload: signed,\n };\n return base64EncodeJson(payment);\n}\n\n/** Build a legacy grant X-PAYMENT header. */\nexport async function buildGrantPaymentHeader(params: {\n payerAddress: `0x${string}`;\n required: PersonalServerPaymentRequired;\n config: EscrowPaymentConfig;\n}): Promise<string> {\n return buildEscrowPaymentHeader({\n ...params,\n required: {\n ...params.required,\n opType: GRANT_OP_TYPE,\n opId: params.required.grantId,\n },\n });\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction stringField(\n value: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n const field = value?.[key];\n return typeof field === \"string\" ? field : undefined;\n}\n\nfunction isCanonicalIsoTimestamp(value: string): boolean {\n try {\n return new Date(value).toISOString() === value;\n } catch {\n return false;\n }\n}\n\n/**\n * Parse shape-validated payment response metadata echoed by a Personal Server.\n *\n * @remarks\n * This metadata is not authenticated by the gateway. It is suitable for\n * display and debugging, not as proof that a payment occurred.\n */\nexport function paymentResponseMetadataFromHeader(\n header: string | null | undefined,\n): DirectPaymentResponseMetadata | undefined {\n if (!header) return undefined;\n try {\n const result = asRecord(base64DecodeJson(header));\n const breakdown = asRecord(result?.breakdown);\n const opType = stringField(result, \"opType\");\n const opId = stringField(result, \"opId\");\n const payerAddress = stringField(result, \"payerAddress\");\n const asset = stringField(result, \"asset\");\n const amount = stringField(result, \"amount\");\n const paymentNonce = stringField(result, \"paymentNonce\");\n const registrationFee = stringField(breakdown, \"registrationFee\");\n const dataAccessFee = stringField(breakdown, \"dataAccessFee\");\n const paidAt = stringField(result, \"paidAt\");\n if (\n result?.success !== true ||\n !opType ||\n !opId ||\n !BYTES32_RE.test(opId) ||\n !payerAddress ||\n !ADDRESS_RE.test(payerAddress) ||\n !asset ||\n !ADDRESS_RE.test(asset) ||\n !amount ||\n !isUint256Decimal(amount, true) ||\n !paymentNonce ||\n !isUint256Decimal(paymentNonce, false) ||\n !registrationFee ||\n !isUint256Decimal(registrationFee, true) ||\n !dataAccessFee ||\n !isUint256Decimal(dataAccessFee, true) ||\n typeof breakdown?.registrationPaid !== \"boolean\" ||\n !paidAt ||\n !isCanonicalIsoTimestamp(paidAt)\n ) {\n return undefined;\n }\n return {\n opType,\n opId,\n asset,\n amount,\n paymentNonce,\n breakdown: {\n registrationFee,\n dataAccessFee,\n registrationPaid: breakdown.registrationPaid,\n },\n paidAt,\n };\n } catch {\n return undefined;\n }\n}\n\n/**\n * @deprecated Use {@link paymentResponseMetadataFromHeader}. A Personal\n * Server response header is untrusted metadata, not a gateway-authenticated\n * receipt.\n */\nexport function paymentReceiptFromHeader(\n header: string | null | undefined,\n): DirectPaymentResponseMetadata | undefined {\n return paymentResponseMetadataFromHeader(header);\n}\n\n/**\n * Authorize an escrow payment for a grant data-access fee.\n *\n * @param params - The payment requirement, the payer address, and escrow config.\n * @returns The gateway's {@link EscrowPayResult} as a typed\n * {@link DirectPaymentReceipt}.\n */\nexport async function authorizeGrantPayment(params: {\n payerAddress: `0x${string}`;\n required: PersonalServerPaymentRequired;\n config: EscrowPaymentConfig;\n}): Promise<DirectPaymentReceipt> {\n return authorizeEscrowPayment({\n ...params,\n required: {\n ...params.required,\n opType: GRANT_OP_TYPE,\n opId: params.required.grantId,\n },\n });\n}\n\n/**\n * Authorize a validated grant or data-access operation through the escrow\n * gateway.\n */\nexport async function authorizeEscrowPayment(params: {\n /** Address whose escrow balance pays for the operation. */\n payerAddress: `0x${string}`;\n /** Validated operation to authorize. */\n required: PersonalServerPaymentOperation;\n /** Escrow gateway and signing configuration. */\n config: EscrowPaymentConfig;\n}): Promise<DirectPaymentReceipt> {\n const { payerAddress, config } = params;\n const signed = await signEscrowPayment(params);\n\n const result = await config.client.payForOp({\n payerAddress,\n opType: signed.message.opType,\n opId: signed.message.opId,\n asset: signed.message.asset,\n amount: signed.message.amount,\n paymentNonce: signed.message.paymentNonce,\n signature: signed.signature,\n accessRecord: signed.accessRecord,\n });\n\n return toDirectPaymentReceipt(result);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/direct/escrow-payment.ts"],"sourcesContent":["/**\n * Escrow-backed payment authorization for the Direct Data Controller.\n *\n * @remarks\n * Builds on the DPv2 escrow surface added in `protocol/escrow`. When a Personal\n * Server read returns `402 Payment Required`, the controller settles the\n * challenged operation through the escrow gateway:\n *\n * 1. Sign the challenge's `GenericPayment` EIP-712 message with the app key.\n * 2. POST it to the gateway's `/v1/escrow/pay` via {@link EscrowGatewayClient}.\n * 3. Map the gateway's {@link EscrowPayResult} into a typed\n * {@link DirectPaymentReceipt} for the caller to inspect.\n *\n * This module supports legacy `\"grant\"` operations and receipt-bound\n * `\"data_access\"` operations. It adapts the escrow `payForOp` flow to the\n * direct-read use case; it does not define its own payment scheme.\n *\n * @category Direct\n * @module direct/escrow-payment\n */\n\nimport {\n GENERIC_PAYMENT_TYPES,\n NATIVE_ASSET_ADDRESS,\n genericPaymentDomain,\n type EscrowAccessRecord,\n type EscrowPaymentClient,\n type EscrowPayResult,\n type PaymentBreakdown,\n} from \"../protocol/escrow\";\nimport type {\n DirectFeeBreakdown,\n DirectPaymentReceipt,\n DirectPaymentResponseMetadata,\n PersonalServerPaymentOperation,\n PersonalServerPaymentRequired,\n} from \"./types\";\n\n/** The escrow `GenericPayment.opType` used for grant-lifecycle payments. */\nexport const GRANT_OP_TYPE = \"grant\" as const;\n/** The escrow `GenericPayment.opType` used for receipt-bound data access. */\nexport const DATA_ACCESS_OP_TYPE = \"data_access\" as const;\n\n/**\n * EIP-712 typed-data signer (e.g. viem `account.signTypedData`).\n *\n * @remarks\n * Kept structurally minimal so any viem account/wallet client satisfies it\n * without the SDK depending on viem's exact `signTypedData` overload set.\n */\nexport type SignTypedDataFn = (args: {\n domain: ReturnType<typeof genericPaymentDomain>;\n types: typeof GENERIC_PAYMENT_TYPES;\n primaryType: \"GenericPayment\";\n message: {\n payerAddress: `0x${string}`;\n opType: string;\n opId: `0x${string}`;\n asset: `0x${string}`;\n amount: bigint;\n paymentNonce: bigint;\n };\n}) => Promise<`0x${string}`>;\n\n/** Supplies a monotonically-increasing payment nonce per payer. */\nexport type PaymentNonceSource = (\n payerAddress: string,\n) => Promise<bigint> | bigint;\n\ninterface EscrowPaymentMessage {\n payerAddress: `0x${string}`;\n opType: typeof GRANT_OP_TYPE | typeof DATA_ACCESS_OP_TYPE;\n opId: `0x${string}`;\n asset: `0x${string}`;\n amount: string;\n paymentNonce: string;\n}\n\ninterface SignedEscrowPayment {\n message: EscrowPaymentMessage;\n signature: `0x${string}`;\n accessRecord?: EscrowAccessRecord;\n}\n\ninterface X402PaymentHeader {\n x402Version: 1;\n scheme: \"vana-escrow-grant\";\n network: string;\n payload: SignedEscrowPayment;\n}\n\n/** Configuration required to sign an escrow X-PAYMENT header. */\nexport interface EscrowPaymentHeaderConfig {\n /** Deployed `DataPortabilityEscrow` contract address. */\n escrowContract: `0x${string}`;\n /** Chain id for the EIP-712 domain (1480 mainnet, 14800 moksha). */\n chainId: number;\n /** App EIP-712 signer. */\n signTypedData: SignTypedDataFn;\n /**\n * Supplies the next payment nonce for a payer. Defaults to a process-local\n * monotonic counter seeded at 1. Provide a durable source in production so\n * nonces survive restarts (the gateway rejects reused (payer, nonce) pairs).\n */\n nonceSource?: PaymentNonceSource;\n}\n\n/**\n * Escrow settlement configuration for gateway authorization.\n *\n * @remarks\n * Extends the header-signing boundary with the gateway client used by\n * {@link authorizeEscrowPayment}. Existing controller and legacy wrapper\n * callers can continue to provide this full configuration.\n */\nexport interface EscrowPaymentConfig extends EscrowPaymentHeaderConfig {\n /** Client for the gateway escrow endpoints (`/v1/escrow/*`). */\n client: EscrowPaymentClient;\n}\n\n/** Map the gateway {@link PaymentBreakdown} into the public {@link DirectFeeBreakdown}. */\nexport function toDirectFeeBreakdown(\n breakdown: PaymentBreakdown,\n): DirectFeeBreakdown {\n return {\n registrationFee: breakdown.registrationFee,\n dataAccessFee: breakdown.dataAccessFee,\n registrationPaid: breakdown.registrationPaid,\n };\n}\n\n/** Map a gateway {@link EscrowPayResult} into the public {@link DirectPaymentReceipt}. */\nexport function toDirectPaymentReceipt(\n result: EscrowPayResult,\n): DirectPaymentReceipt {\n return {\n opType: result.opType,\n opId: result.opId,\n asset: result.asset,\n amount: result.amount,\n paymentNonce: result.paymentNonce,\n breakdown: toDirectFeeBreakdown(result.breakdown),\n paidAt: result.paidAt,\n };\n}\n\n/** Default in-process monotonic nonce counter (seeded at 1 per payer). */\nexport function createDefaultNonceSource(): PaymentNonceSource {\n const counters = new Map<string, bigint>();\n return (payerAddress: string): bigint => {\n const key = payerAddress.toLowerCase();\n const next = (counters.get(key) ?? 0n) + 1n;\n counters.set(key, next);\n return next;\n };\n}\n\nconst processLocalNonceSource = createDefaultNonceSource();\nconst UINT256_MAX = (1n << 256n) - 1n;\nconst ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;\nconst BYTES32_RE = /^0x[0-9a-fA-F]{64}$/;\nconst SIGNATURE_RE = /^0x[0-9a-fA-F]{130}$/;\n\nfunction isUint256Decimal(value: string, allowZero: boolean): boolean {\n const pattern = allowZero ? /^(0|[1-9]\\d*)$/ : /^[1-9]\\d*$/;\n return (\n value.length <= UINT256_MAX.toString().length &&\n pattern.test(value) &&\n BigInt(value) <= UINT256_MAX\n );\n}\n\nfunction isValidAccessRecord(record: EscrowAccessRecord): boolean {\n return (\n BYTES32_RE.test(record.dataPointId) &&\n isUint256Decimal(record.version, false) &&\n ADDRESS_RE.test(record.accessor) &&\n BYTES32_RE.test(record.recordId) &&\n SIGNATURE_RE.test(record.signature)\n );\n}\n\nfunction validateSigningOperation(\n payerAddress: `0x${string}`,\n required: PersonalServerPaymentOperation,\n): void {\n if (!ADDRESS_RE.test(payerAddress)) {\n throw new Error(\"Payment payer must be a 20-byte EVM address\");\n }\n if (!BYTES32_RE.test(required.opId)) {\n throw new Error(\"Payment operation id must be a 32-byte hex value\");\n }\n if (!ADDRESS_RE.test(required.asset || NATIVE_ASSET_ADDRESS)) {\n throw new Error(\"Payment asset must be a 20-byte EVM address\");\n }\n if (!isUint256Decimal(required.amount, true)) {\n throw new Error(\"Payment amount must be a canonical uint256 decimal\");\n }\n if (\n required.paymentNonce !== undefined &&\n !isUint256Decimal(required.paymentNonce, false)\n ) {\n throw new Error(\"Payment nonce must be a positive uint256 decimal\");\n }\n\n const accessRecord = required.accessRecord;\n if (required.opType === DATA_ACCESS_OP_TYPE) {\n if (!accessRecord || !isValidAccessRecord(accessRecord)) {\n throw new Error(\"Data-access payment requires a valid access record\");\n }\n if (required.opId.toLowerCase() !== accessRecord.recordId.toLowerCase()) {\n throw new Error(\n \"Data-access payment operation id must equal the access record id\",\n );\n }\n if (accessRecord.accessor.toLowerCase() !== payerAddress.toLowerCase()) {\n throw new Error(\n \"Data-access payment accessor must equal the payment payer address\",\n );\n }\n return;\n }\n\n if (required.amount === \"0\") {\n if (\n !accessRecord ||\n !isValidAccessRecord(accessRecord) ||\n accessRecord.accessor.toLowerCase() !== payerAddress.toLowerCase()\n ) {\n throw new Error(\n \"Zero-amount grant payments require a valid access record for the payer\",\n );\n }\n }\n}\n\nfunction base64EncodeJson(value: unknown): string {\n const bytes = new TextEncoder().encode(JSON.stringify(value));\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary);\n}\n\nfunction base64DecodeJson(value: string): unknown {\n const binary = atob(value);\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n return JSON.parse(new TextDecoder().decode(bytes));\n}\n\nasync function signEscrowPayment(params: {\n payerAddress: `0x${string}`;\n required: PersonalServerPaymentOperation;\n config: EscrowPaymentHeaderConfig;\n}): Promise<SignedEscrowPayment> {\n const { payerAddress, required, config } = params;\n validateSigningOperation(payerAddress, required);\n const nonceSource = config.nonceSource ?? processLocalNonceSource;\n const paymentNonce = BigInt(\n required.paymentNonce ?? (await nonceSource(payerAddress)),\n );\n const asset = (required.asset || NATIVE_ASSET_ADDRESS) as `0x${string}`;\n const opId = required.opId as `0x${string}`;\n const amount = BigInt(required.amount);\n if (amount < 0n || amount > UINT256_MAX) {\n throw new Error(\"Payment amount must be a uint256\");\n }\n if (paymentNonce <= 0n || paymentNonce > UINT256_MAX) {\n throw new Error(\"Payment nonce must be a positive uint256\");\n }\n\n const message = {\n payerAddress,\n opType: required.opType,\n opId,\n asset,\n amount,\n paymentNonce,\n };\n\n const signature = await config.signTypedData({\n domain: genericPaymentDomain(config.chainId, config.escrowContract),\n types: GENERIC_PAYMENT_TYPES,\n primaryType: \"GenericPayment\",\n message,\n });\n\n return {\n message: {\n ...message,\n amount: amount.toString(),\n paymentNonce: paymentNonce.toString(),\n },\n signature,\n ...(required.accessRecord ? { accessRecord: required.accessRecord } : {}),\n };\n}\n\n/**\n * Build the canonical X-PAYMENT header for a validated escrow operation.\n *\n * @remarks\n * Supports both legacy grant payments and receipt-bound data-access payments.\n * Signing is injected through {@link EscrowPaymentHeaderConfig.signTypedData}.\n */\nexport async function buildEscrowPaymentHeader(params: {\n /** Address whose escrow balance pays for the operation. */\n payerAddress: `0x${string}`;\n /** Validated operation parsed from the Personal Server challenge. */\n required: PersonalServerPaymentOperation;\n /** Escrow contract, chain, signer, and nonce configuration. */\n config: EscrowPaymentHeaderConfig;\n}): Promise<string> {\n const network = params.required.network ?? `vana:${params.config.chainId}`;\n if (network !== `vana:${params.config.chainId}`) {\n throw new Error(\"Payment network must match the configured chain\");\n }\n\n const signed = await signEscrowPayment(params);\n const payment: X402PaymentHeader = {\n x402Version: 1,\n scheme: \"vana-escrow-grant\",\n network,\n payload: signed,\n };\n return base64EncodeJson(payment);\n}\n\n/** Build a legacy grant X-PAYMENT header. */\nexport async function buildGrantPaymentHeader(params: {\n payerAddress: `0x${string}`;\n required: PersonalServerPaymentRequired;\n config: EscrowPaymentConfig;\n}): Promise<string> {\n return buildEscrowPaymentHeader({\n ...params,\n required: {\n ...params.required,\n opType: GRANT_OP_TYPE,\n opId: params.required.grantId,\n },\n });\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n}\n\nfunction stringField(\n value: Record<string, unknown> | undefined,\n key: string,\n): string | undefined {\n const field = value?.[key];\n return typeof field === \"string\" ? field : undefined;\n}\n\nfunction isCanonicalIsoTimestamp(value: string): boolean {\n try {\n return new Date(value).toISOString() === value;\n } catch {\n return false;\n }\n}\n\n/**\n * Parse shape-validated payment response metadata echoed by a Personal Server.\n *\n * @remarks\n * This metadata is not authenticated by the gateway. It is suitable for\n * display and debugging, not as proof that a payment occurred.\n */\nexport function paymentResponseMetadataFromHeader(\n header: string | null | undefined,\n): DirectPaymentResponseMetadata | undefined {\n if (!header) return undefined;\n try {\n const result = asRecord(base64DecodeJson(header));\n const breakdown = asRecord(result?.breakdown);\n const opType = stringField(result, \"opType\");\n const opId = stringField(result, \"opId\");\n const payerAddress = stringField(result, \"payerAddress\");\n const asset = stringField(result, \"asset\");\n const amount = stringField(result, \"amount\");\n const paymentNonce = stringField(result, \"paymentNonce\");\n const registrationFee = stringField(breakdown, \"registrationFee\");\n const dataAccessFee = stringField(breakdown, \"dataAccessFee\");\n const paidAt = stringField(result, \"paidAt\");\n if (\n result?.success !== true ||\n !opType ||\n !opId ||\n !BYTES32_RE.test(opId) ||\n !payerAddress ||\n !ADDRESS_RE.test(payerAddress) ||\n !asset ||\n !ADDRESS_RE.test(asset) ||\n !amount ||\n !isUint256Decimal(amount, true) ||\n !paymentNonce ||\n !isUint256Decimal(paymentNonce, false) ||\n !registrationFee ||\n !isUint256Decimal(registrationFee, true) ||\n !dataAccessFee ||\n !isUint256Decimal(dataAccessFee, true) ||\n typeof breakdown?.registrationPaid !== \"boolean\" ||\n !paidAt ||\n !isCanonicalIsoTimestamp(paidAt)\n ) {\n return undefined;\n }\n return {\n opType,\n opId,\n asset,\n amount,\n paymentNonce,\n breakdown: {\n registrationFee,\n dataAccessFee,\n registrationPaid: breakdown.registrationPaid,\n },\n paidAt,\n };\n } catch {\n return undefined;\n }\n}\n\n/**\n * @deprecated Use {@link paymentResponseMetadataFromHeader}. A Personal\n * Server response header is untrusted metadata, not a gateway-authenticated\n * receipt.\n */\nexport function paymentReceiptFromHeader(\n header: string | null | undefined,\n): DirectPaymentResponseMetadata | undefined {\n return paymentResponseMetadataFromHeader(header);\n}\n\n/**\n * Authorize an escrow payment for a grant data-access fee.\n *\n * @param params - The payment requirement, the payer address, and escrow config.\n * @returns The gateway's {@link EscrowPayResult} as a typed\n * {@link DirectPaymentReceipt}.\n */\nexport async function authorizeGrantPayment(params: {\n payerAddress: `0x${string}`;\n required: PersonalServerPaymentRequired;\n config: EscrowPaymentConfig;\n}): Promise<DirectPaymentReceipt> {\n return authorizeEscrowPayment({\n ...params,\n required: {\n ...params.required,\n opType: GRANT_OP_TYPE,\n opId: params.required.grantId,\n },\n });\n}\n\n/**\n * Authorize a validated grant or data-access operation through the escrow\n * gateway.\n */\nexport async function authorizeEscrowPayment(params: {\n /** Address whose escrow balance pays for the operation. */\n payerAddress: `0x${string}`;\n /** Validated operation to authorize. */\n required: PersonalServerPaymentOperation;\n /** Escrow gateway and signing configuration. */\n config: EscrowPaymentConfig;\n}): Promise<DirectPaymentReceipt> {\n const { payerAddress, config } = params;\n const signed = await signEscrowPayment(params);\n\n const result = await config.client.payForOp({\n payerAddress,\n opType: signed.message.opType,\n opId: signed.message.opId,\n asset: signed.message.asset,\n amount: signed.message.amount,\n paymentNonce: signed.message.paymentNonce,\n signature: signed.signature,\n accessRecord: signed.accessRecord,\n });\n\n return toDirectPaymentReceipt(result);\n}\n"],"mappings":"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","names":[]}
@@ -36,8 +36,8 @@ export { encryptWithPassword, decryptWithPassword, } from "./crypto/envelope/ope
36
36
  export { parseWeb3SignedHeader, verifyWeb3Signed, type Web3SignedPayload, type VerifiedAuth, } from "./auth/web3-signed.js";
37
37
  export { buildWeb3SignedHeader, computeBodyHash, type Web3SignedSignFn, } from "./auth/web3-signed-builder.js";
38
38
  export { MissingAuthError, InvalidSignatureError, ExpiredTokenError, } from "./auth/errors.js";
39
- export { NATIVE_VANA_ASSET, dataRegistryDomain, grantRegistrationDomain, grantRevocationDomain, serverRegistrationDomain, builderRegistrationDomain, escrowPaymentDomain, GRANT_REGISTRATION_TYPES, GRANT_REVOCATION_TYPES, SERVER_REGISTRATION_TYPES, BUILDER_REGISTRATION_TYPES, ADD_DATA_TYPES, RECORD_DATA_ACCESS_TYPES, type DataPortabilityContracts, type DataPortabilityGatewayConfig, type GrantRegistrationMessage, type GrantRevocationMessage, type ServerRegistrationMessage, type BuilderRegistrationMessage, type AddDataMessage, type RecordDataAccessMessage, } from "./protocol/eip712.js";
40
- export { ENCLAVE_IDENTITY_EVIDENCE_VERSION, USER_PS_ID_DOMAIN, ENCLAVE_WALLET_PURPOSE, MASTER_SIGNATURE_DELIVERY_VERSION, SEALED_ENVELOPE_VERSION, ENCLAVE_TRUST_ANCHORS, userPsId, appRootPreimage, kmsIssuedPreimage, verifyEnclaveIdentityEvidence, buildMasterSignatureDelivery, encryptMasterSignatureDelivery, type UserPsId, type EnclaveIdentityEvidence, type IdentityRequest, type IdentityState, type IdentityResponse, type IdentityRegistrationRequest, type IdentityRegistrationResponse, type MasterSignatureDelivery, type SealedSecretSubmission, type SealedSecretResponse, type AesGcmBox, type SealedEnvelope, type EnclaveTrustAnchors, } from "./protocol/identity.js";
39
+ export { NATIVE_VANA_ASSET, dataRegistryDomain, grantRegistrationDomain, grantRevocationDomain, serverRegistrationDomain, builderRegistrationDomain, escrowPaymentDomain, withdrawAuthorizationDomain, buildWithdrawAuthorizationTypedData, GRANT_REGISTRATION_TYPES, GRANT_REVOCATION_TYPES, SERVER_REGISTRATION_TYPES, BUILDER_REGISTRATION_TYPES, ADD_DATA_TYPES, RECORD_DATA_ACCESS_TYPES, WITHDRAW_AUTHORIZATION_TYPES, type DataPortabilityContracts, type DataPortabilityGatewayConfig, type GrantRegistrationMessage, type GrantRevocationMessage, type ServerRegistrationMessage, type BuilderRegistrationMessage, type AddDataMessage, type RecordDataAccessMessage, type WithdrawAuthorizationMessage, } from "./protocol/eip712.js";
40
+ export { ENCLAVE_IDENTITY_EVIDENCE_VERSION, USER_PS_ID_DOMAIN, ENCLAVE_WALLET_PURPOSE, MASTER_SIGNATURE_DELIVERY_VERSION, SEALED_ENVELOPE_VERSION, ENCLAVE_TRUST_ANCHORS, userPsId, appRootPreimage, kmsIssuedPreimage, verifyEnclaveIdentityEvidence, buildMasterSignatureDelivery, encryptMasterSignatureDelivery, type UserPsId, type EnclaveIdentityEvidence, type ExpectedIdentity, type IdentityRequest, type IdentityState, type IdentityResponse, type IdentityRegistrationRequest, type IdentityRegistrationResponse, type MasterSignatureDelivery, type SealedSecretSubmission, type SealedSecretResponse, type AesGcmBox, type SealedEnvelope, type EnclaveTrustAnchors, } from "./protocol/identity.js";
41
41
  export { PERSONAL_SERVER_REGISTRATION_DEFAULT_CHAIN_ID, PERSONAL_SERVER_REGISTRATION_DEFAULT_VERIFYING_CONTRACT, personalServerRegistrationDomain, createViemPersonalServerRegistrationSigner, buildPersonalServerRegistrationTypedData, buildPersonalServerRegistrationSignature, registerPersonalServerSignature, type PersonalServerRegistrationTypedData, type PersonalServerRegistrationSigner, type PersonalServerRegistrationDomainInput, type ViemPersonalServerRegistrationWalletClient, type ViemPersonalServerRegistrationSignerSource, type BuildPersonalServerRegistrationTypedDataInput, type BuildPersonalServerRegistrationSignatureInput, type PersonalServerRegistrationSignature, } from "./protocol/personal-server-registration.js";
42
42
  export { PERSONAL_SERVER_LITE_OWNER_BINDING_VERSION, PERSONAL_SERVER_LITE_OWNER_BINDING_PURPOSE, PERSONAL_SERVER_LITE_OWNER_BINDING_PREFIX, buildPersonalServerLiteOwnerBindingMessage, createViemPersonalServerLiteOwnerBindingSigner, buildPersonalServerLiteOwnerBindingSignature, signPersonalServerLiteOwnerBinding, type PersonalServerLiteOwnerBindingPurpose, type PersonalServerLiteOwnerBindingMessage, type PersonalServerLiteOwnerBindingSigner, type ViemPersonalServerLiteOwnerBindingWalletClient, type ViemPersonalServerLiteOwnerBindingSignerSource, type BuildPersonalServerLiteOwnerBindingSignatureInput, type PersonalServerLiteOwnerBindingSignature, } from "./personal-server-lite/owner-binding.js";
43
43
  export { ACCOUNT_PERSONAL_SERVER_REGISTRATION_INTENT, AccountPersonalServerRegistrationError, signPersonalServerRegistrationWithAccount, type AccountPersonalServerRegistrationIntent, type AccountPersonalServerRegistrationSignature, type AccountPersonalServerRegistrationStatus, type AccountPersonalServerRegistrationRequest, type AccountPersonalServerRegistrationConfig, type AccountSignedPersonalServerRegistration, type AccountConfirmationRequiredPersonalServerRegistration, type AccountFallbackSignedPersonalServerRegistration, type AccountPersonalServerRegistrationResult, } from "./account/personal-server-registration.js";
@@ -57,5 +57,5 @@ export { DERIVATIVE_STATUS_PATH, DEFAULT_DERIVATIVE_STATUS_TIMEOUT_MS, DEFAULT_D
57
57
  export { deriveDataPointId, isDataPointId, scopeNamespace, derivedScopeViolatesNaming, assertDerivedScopeNaming, isRedactedLineageNode, personalServerLineagePath, gatewayLineagePath, getLineage, getPersonalServerLineage, getGatewayLineage, LineageNodeSchema, RedactedLineageNodeSchema, LineageEntrySchema, LineageGraphSchema, type LineageNode, type RedactedLineageNode, type LineageEntry, type LineageGraph, type LineageReadResult, type PersonalServerLineageParams, type GatewayLineageParams, type GetLineageParams, } from "./protocol/lineage.js";
58
58
  export { DataFileEnvelopeSchema, createDataFileEnvelope, IngestResponseSchema, type DataFileEnvelope, type IngestResponse, } from "./protocol/data-file.js";
59
59
  export { createGatewayClient, type GatewayEnvelope, type GatewayProof, type Builder, type Schema, type ServerInfo, type OwnerServerRecord, type OwnerServersResult, type GatewayGrantFee, type GatewayGrantStatus, type GatewayGrantResponse, type GrantListItem, type DataPointRecord, type DataPointListResult, type ListDataPointsOptions, type RegisterServerParams, type RegisterServerResult, type RegisterBuilderParams, type RegisterBuilderResult, type RegisterDataPointParams, type RegisterDataPointResult, type GetDataPointOptions, type DeleteDataPointParams, type DeleteDataPointResult, type CreateGrantParams, type RevokeGrantParams, type AccessRecord, type PayForOperationParams, type PayForOperationResult, type SettleOpType, type SettleItem, type SettlePromoteResult, type SettleReconcileItem, type SettleParams, type SettleResult, type GatewayClient, } from "./protocol/gateway.js";
60
- export { createEscrowGatewayClient, genericPaymentDomain, GENERIC_PAYMENT_TYPES, ESCROW_DEPOSIT_ABI, NATIVE_ASSET_ADDRESS, type GenericPaymentMessage, type EscrowBalanceEntry, type EscrowBalanceResult, type EscrowBalanceSyncResult, type DepositSubmissionResult, type PaymentBreakdown, type EscrowPayResult, type SubmitDepositParams, type PayForOpParams, type EscrowGatewayClient, type SubmittedDepositEntry, type FinalizedDepositEntry, type FailedDepositEntry, } from "./protocol/escrow.js";
60
+ export { createEscrowGatewayClient, genericPaymentDomain, GENERIC_PAYMENT_TYPES, ESCROW_DEPOSIT_ABI, NATIVE_ASSET_ADDRESS, type GenericPaymentMessage, type EscrowBalanceEntry, type EscrowBalanceResult, type EscrowBalanceSyncResult, type DepositSubmissionResult, type PaymentBreakdown, type EscrowPayResult, EscrowWithdrawalLifecycleError, EscrowWithdrawalRejectionError, type EscrowPaymentClient, type EscrowWithdrawalFailureResult, type EscrowWithdrawalRejectedResult, type EscrowWithdrawalRejectionCode, type EscrowWithdrawalSubmittedResult, type EscrowWithdrawalSubmittedWithoutTransaction, type EscrowWithdrawalSubmittedWithTransaction, type EscrowWithdrawalSettledResult, type EscrowWithdrawalResult, type SubmitDepositParams, type PayForOpParams, type WithdrawFromEscrowParams, type WithdrawNonceResponse, type EscrowGatewayClient, type SubmittedDepositEntry, type FinalizedDepositEntry, type FailedDepositEntry, } from "./protocol/escrow.js";
61
61
  export { PSError, parsePSError, type PSErrorCode } from "./types/ps-errors.js";
@@ -31685,6 +31685,9 @@ function escrowPaymentDomain(config) {
31685
31685
  config.contracts.dataPortabilityEscrow
31686
31686
  );
31687
31687
  }
31688
+ function withdrawAuthorizationDomain(config) {
31689
+ return escrowPaymentDomain(config);
31690
+ }
31688
31691
  var GRANT_REGISTRATION_TYPES = {
31689
31692
  GrantRegistration: [
31690
31693
  { name: "grantorAddress", type: "address" },
@@ -31717,6 +31720,15 @@ var BUILDER_REGISTRATION_TYPES = {
31717
31720
  { name: "appUrl", type: "string" }
31718
31721
  ]
31719
31722
  };
31723
+ var WITHDRAW_AUTHORIZATION_TYPES = {
31724
+ WithdrawAuthorization: [
31725
+ { name: "account", type: "address" },
31726
+ { name: "asset", type: "address" },
31727
+ { name: "amount", type: "uint256" },
31728
+ { name: "withdrawNonce", type: "uint256" },
31729
+ { name: "deadline", type: "uint256" }
31730
+ ]
31731
+ };
31720
31732
  var ADD_DATA_TYPES = {
31721
31733
  AddData: [
31722
31734
  { name: "ownerAddress", type: "address" },
@@ -31735,6 +31747,14 @@ var RECORD_DATA_ACCESS_TYPES = {
31735
31747
  { name: "recordId", type: "bytes32" }
31736
31748
  ]
31737
31749
  };
31750
+ function buildWithdrawAuthorizationTypedData(config, message) {
31751
+ return {
31752
+ domain: withdrawAuthorizationDomain(config),
31753
+ types: WITHDRAW_AUTHORIZATION_TYPES,
31754
+ primaryType: "WithdrawAuthorization",
31755
+ message
31756
+ };
31757
+ }
31738
31758
 
31739
31759
  // src/protocol/identity.ts
31740
31760
  init_interface();
@@ -31744,9 +31764,11 @@ import {
31744
31764
  encodePacked,
31745
31765
  fromHex as fromHex5,
31746
31766
  getAddress,
31767
+ isAddressEqual,
31747
31768
  keccak256,
31748
31769
  recoverPublicKey,
31749
- toBytes
31770
+ toBytes,
31771
+ toHex as toHex6
31750
31772
  } from "viem";
31751
31773
  import { publicKeyToAddress } from "viem/accounts";
31752
31774
  var ENCLAVE_IDENTITY_EVIDENCE_VERSION = 1;
@@ -31773,18 +31795,21 @@ function userPsId(chainId, ownerAddress) {
31773
31795
  );
31774
31796
  return keccak256(packed);
31775
31797
  }
31798
+ function compressPublicKey(publicKey) {
31799
+ return secp256k13.ProjectivePoint.fromHex(
31800
+ fromHex5(publicKey, "bytes")
31801
+ ).toRawBytes(true);
31802
+ }
31776
31803
  function appRootPreimage(purpose, publicKey) {
31777
- const keyHex = publicKey.slice(2).toLowerCase();
31804
+ const keyHex = toHex6(compressPublicKey(publicKey)).slice(2);
31778
31805
  return keccak256(toBytes(`${purpose}${PREIMAGE_SEPARATOR}${keyHex}`));
31779
31806
  }
31780
31807
  function kmsIssuedPreimage(appId, appRootPublicKey) {
31781
- const appIdHex = appId.slice(2).toLowerCase();
31782
- const prefix = toBytes(
31783
- `${KMS_ISSUED_PREFIX}${PREIMAGE_SEPARATOR}${appIdHex}`
31784
- );
31785
- const compressed = secp256k13.ProjectivePoint.fromHex(
31786
- fromHex5(appRootPublicKey, "bytes")
31787
- ).toRawBytes(true);
31808
+ const prefix = concat4([
31809
+ toBytes(`${KMS_ISSUED_PREFIX}${PREIMAGE_SEPARATOR}`),
31810
+ fromHex5(appId, "bytes")
31811
+ ]);
31812
+ const compressed = compressPublicKey(appRootPublicKey);
31788
31813
  return keccak256(concat4([prefix, compressed]));
31789
31814
  }
31790
31815
  async function recoverChainKey(hash, signature, link) {
@@ -31794,13 +31819,31 @@ async function recoverChainKey(hash, signature, link) {
31794
31819
  throw new Error(`Invalid enclave signature chain link ${link}`);
31795
31820
  }
31796
31821
  }
31797
- async function verifyEnclaveIdentityEvidence(evidence, anchors) {
31822
+ async function verifyEnclaveIdentityEvidence(evidence, anchors, expected) {
31798
31823
  if (evidence.v !== ENCLAVE_IDENTITY_EVIDENCE_VERSION) {
31799
31824
  throw new Error("Unsupported enclave identity evidence version");
31800
31825
  }
31801
31826
  if (!Number.isInteger(evidence.epoch) || evidence.epoch < 1) {
31802
31827
  throw new Error("Invalid enclave identity epoch");
31803
31828
  }
31829
+ if (evidence.chainId !== expected.chainId) {
31830
+ throw new Error(
31831
+ "Enclave identity chain ID does not match expected chain ID"
31832
+ );
31833
+ }
31834
+ if (!isAddressEqual(evidence.ownerAddress, expected.ownerAddress)) {
31835
+ throw new Error("Enclave identity owner does not match expected owner");
31836
+ }
31837
+ if (evidence.epoch !== expected.epoch) {
31838
+ throw new Error("Enclave identity epoch does not match expected epoch");
31839
+ }
31840
+ const expectedUserPsId = userPsId(expected.chainId, expected.ownerAddress);
31841
+ if (evidence.userPsId.toLowerCase() !== expectedUserPsId.toLowerCase()) {
31842
+ throw new Error("Enclave userPsId does not match expected identity");
31843
+ }
31844
+ if (evidence.purpose !== ENCLAVE_WALLET_PURPOSE) {
31845
+ throw new Error("Unexpected enclave wallet purpose");
31846
+ }
31804
31847
  const derivedAddress = publicKeyToAddress(evidence.publicKey);
31805
31848
  if (getAddress(derivedAddress) !== getAddress(evidence.address)) {
31806
31849
  throw new Error("Enclave public key does not match its address");
@@ -31829,8 +31872,12 @@ async function verifyEnclaveIdentityEvidence(evidence, anchors) {
31829
31872
  throw new Error("Enclave app ID is not trusted");
31830
31873
  }
31831
31874
  }
31832
- function buildMasterSignatureDelivery(evidence, masterSignature, now = Math.floor(Date.now() / 1e3)) {
31875
+ async function buildMasterSignatureDelivery(evidence, masterSignature, now = Math.floor(Date.now() / 1e3)) {
31833
31876
  deriveMasterKey(masterSignature);
31877
+ const signerAddress = await recoverServerOwner(masterSignature);
31878
+ if (!isAddressEqual(signerAddress, evidence.ownerAddress)) {
31879
+ throw new Error("Master signature signer does not match evidence owner");
31880
+ }
31834
31881
  return {
31835
31882
  v: MASTER_SIGNATURE_DELIVERY_VERSION,
31836
31883
  userPsId: evidence.userPsId,
@@ -34926,6 +34973,7 @@ function createGatewayClient(baseUrl) {
34926
34973
  }
34927
34974
 
34928
34975
  // src/protocol/escrow.ts
34976
+ import { isHex } from "viem";
34929
34977
  var GENERIC_PAYMENT_TYPES = {
34930
34978
  GenericPayment: [
34931
34979
  { name: "payerAddress", type: "address" },
@@ -34965,6 +35013,26 @@ var ESCROW_DEPOSIT_ABI2 = [
34965
35013
  }
34966
35014
  ];
34967
35015
  var NATIVE_ASSET_ADDRESS = "0x0000000000000000000000000000000000000000";
35016
+ var EscrowWithdrawalLifecycleError = class extends Error {
35017
+ constructor(httpStatus, result) {
35018
+ super(result.error);
35019
+ this.httpStatus = httpStatus;
35020
+ this.result = result;
35021
+ }
35022
+ httpStatus;
35023
+ result;
35024
+ name = "EscrowWithdrawalLifecycleError";
35025
+ };
35026
+ var EscrowWithdrawalRejectionError = class extends Error {
35027
+ constructor(httpStatus, result) {
35028
+ super(result.error);
35029
+ this.httpStatus = httpStatus;
35030
+ this.result = result;
35031
+ }
35032
+ httpStatus;
35033
+ result;
35034
+ name = "EscrowWithdrawalRejectionError";
35035
+ };
34968
35036
  function createEscrowGatewayClient(baseUrl) {
34969
35037
  const base = baseUrl.replace(/\/+$/, "");
34970
35038
  async function throwOnError(res, context) {
@@ -34980,6 +35048,27 @@ function createEscrowGatewayClient(baseUrl) {
34980
35048
  );
34981
35049
  }
34982
35050
  }
35051
+ async function throwOnWithdrawError(res) {
35052
+ if (res.ok) return;
35053
+ let body;
35054
+ try {
35055
+ body = await res.json();
35056
+ } catch {
35057
+ throw new Error(
35058
+ `Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}`
35059
+ );
35060
+ }
35061
+ if (isEscrowWithdrawalFailureResult(body)) {
35062
+ throw new EscrowWithdrawalLifecycleError(res.status, body);
35063
+ }
35064
+ if (isEscrowWithdrawalRejectedResult(body)) {
35065
+ throw new EscrowWithdrawalRejectionError(res.status, body);
35066
+ }
35067
+ const error = getGatewayErrorMessage(body);
35068
+ throw new Error(
35069
+ `Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}${error ? `: ${error}` : ""}`
35070
+ );
35071
+ }
34983
35072
  return {
34984
35073
  async submitDeposit({ txHash }) {
34985
35074
  const res = await fetch(`${base}/v1/escrow/deposit`, {
@@ -35035,9 +35124,108 @@ function createEscrowGatewayClient(baseUrl) {
35035
35124
  });
35036
35125
  await throwOnError(res, "POST /v1/escrow/pay");
35037
35126
  return res.json();
35127
+ },
35128
+ async withdraw({
35129
+ account,
35130
+ asset,
35131
+ amount,
35132
+ withdrawNonce,
35133
+ deadline,
35134
+ signature
35135
+ }) {
35136
+ const res = await fetch(`${base}/v1/escrow/withdraw`, {
35137
+ method: "POST",
35138
+ headers: {
35139
+ "Content-Type": "application/json",
35140
+ Authorization: `Web3Signed ${signature}`
35141
+ },
35142
+ body: JSON.stringify({
35143
+ account,
35144
+ asset,
35145
+ amount,
35146
+ withdrawNonce,
35147
+ deadline
35148
+ })
35149
+ });
35150
+ await throwOnWithdrawError(res);
35151
+ return res.json();
35152
+ },
35153
+ async getWithdrawNonce(account) {
35154
+ const res = await fetch(
35155
+ `${base}/v1/escrow/withdraw/nonce?account=${encodeURIComponent(account)}`,
35156
+ { cache: "no-store" }
35157
+ );
35158
+ await throwOnError(res, "GET /v1/escrow/withdraw/nonce");
35159
+ const body = await res.json();
35160
+ if (!isWithdrawNonceResponse(body, account)) {
35161
+ throw new Error(
35162
+ "GET /v1/escrow/withdraw/nonce: invalid response structure"
35163
+ );
35164
+ }
35165
+ return body;
35038
35166
  }
35039
35167
  };
35040
35168
  }
35169
+ function getGatewayErrorMessage(body) {
35170
+ if (typeof body === "object" && body !== null && "error" in body && typeof body.error === "string") {
35171
+ return body.error;
35172
+ }
35173
+ return void 0;
35174
+ }
35175
+ function isEscrowWithdrawalFailureResult(body) {
35176
+ if (typeof body !== "object" || body === null) return false;
35177
+ const value = body;
35178
+ return value.success === false && (value.status === "retryable" || value.status === "reorged" || value.status === "failed") && typeof value.error === "string" && isAddressHex(value.account) && isAddressHex(value.asset) && isUint256Decimal(value.amount) && isUint256Decimal(value.withdrawNonce) && isUint256Decimal(value.deadline) && (isHash(value.txHash) || value.txHash === null) && (!("blockNumber" in value) || isBlockNumber(value.blockNumber));
35179
+ }
35180
+ function isEscrowWithdrawalRejectedResult(body) {
35181
+ if (typeof body !== "object" || body === null) return false;
35182
+ const value = body;
35183
+ return value.success === false && value.status === "rejected" && isWithdrawalRejectionCode(value.code) && typeof value.error === "string" && isAddressHex(value.account) && isAddressHex(value.asset) && isUint256Decimal(value.amount) && isUint256Decimal(value.withdrawNonce) && isUint256Decimal(value.deadline) && optionalUint256Decimal(value.balance) && optionalUint256Decimal(value.authorizedAmount) && optionalUint256Decimal(value.withdrawingAmount) && optionalUint256Decimal(value.availableAmount) && optionalUint256Decimal(value.requestedAmount) && optionalUint256Decimal(value.minimumAmount);
35184
+ }
35185
+ function isWithdrawalRejectionCode(value) {
35186
+ return value === "below_minimum" || value === "deadline_too_far" || value === "expired" || value === "insufficient_available" || value === "stale_nonce";
35187
+ }
35188
+ function optionalUint256Decimal(value) {
35189
+ return value === void 0 || isUint256Decimal(value);
35190
+ }
35191
+ function isAddressHex(value) {
35192
+ return typeof value === "string" && isHex(value, { strict: true }) && value.length === 42;
35193
+ }
35194
+ function isHash(value) {
35195
+ return typeof value === "string" && isHex(value, { strict: true }) && value.length === 66;
35196
+ }
35197
+ function isUint256Decimal(value) {
35198
+ if (typeof value !== "string" || value.length === 0 || value.length > 78) {
35199
+ return false;
35200
+ }
35201
+ if (!/^(0|[1-9]\d*)$/.test(value)) return false;
35202
+ return BigInt(value) <= 2n ** 256n - 1n;
35203
+ }
35204
+ function isBlockNumber(value) {
35205
+ return value === null || isUint256Decimal(value);
35206
+ }
35207
+ function isWithdrawNonceResponse(body, requestedAccount) {
35208
+ if (typeof body !== "object" || body === null) return false;
35209
+ const value = body;
35210
+ if (value.success !== true) return false;
35211
+ if (!isAddressHex(value.account)) return false;
35212
+ if (value.account.toLowerCase() !== requestedAccount.toLowerCase())
35213
+ return false;
35214
+ if (typeof value.chainId !== "string") return false;
35215
+ if (!/^(0|[1-9]\d*)$/.test(value.chainId)) return false;
35216
+ const isLastNull = value.lastWithdrawNonce === null;
35217
+ const lastNonceValid = isLastNull || isUint256Decimal(value.lastWithdrawNonce);
35218
+ if (!lastNonceValid) return false;
35219
+ if (!isUint256Decimal(value.nextWithdrawNonce)) return false;
35220
+ if (isLastNull) {
35221
+ return value.nextWithdrawNonce === "1";
35222
+ }
35223
+ const lastNonce = BigInt(value.lastWithdrawNonce);
35224
+ const nextNonce = BigInt(value.nextWithdrawNonce);
35225
+ const expectedNextNonce = lastNonce + 1n;
35226
+ if (expectedNextNonce > 2n ** 256n - 1n) return false;
35227
+ return nextNonce === expectedNextNonce;
35228
+ }
35041
35229
 
35042
35230
  // src/types/ps-errors.ts
35043
35231
  var PSError = class extends Error {
@@ -35145,6 +35333,8 @@ export {
35145
35333
  ENCLAVE_TRUST_ANCHORS,
35146
35334
  ENCLAVE_WALLET_PURPOSE,
35147
35335
  ESCROW_DEPOSIT_ABI2 as ESCROW_DEPOSIT_ABI,
35336
+ EscrowWithdrawalLifecycleError,
35337
+ EscrowWithdrawalRejectionError,
35148
35338
  ExpiredTokenError,
35149
35339
  FEE_REGISTRY_ABI,
35150
35340
  GENERIC_PAYMENT_TYPES,
@@ -35217,6 +35407,7 @@ export {
35217
35407
  UserRejectedRequestError,
35218
35408
  VanaError,
35219
35409
  VanaStorage,
35410
+ WITHDRAW_AUTHORIZATION_TYPES,
35220
35411
  WRITER_ATTRIBUTION_KEY,
35221
35412
  WRITE_CONTENT_DISPOSITION_HEADER,
35222
35413
  WRITE_FILENAME_HEADER,
@@ -35250,6 +35441,7 @@ export {
35250
35441
  buildPersonalServerRegistrationTypedData,
35251
35442
  buildSetDataPointStatusRequest,
35252
35443
  buildWeb3SignedHeader,
35444
+ buildWithdrawAuthorizationTypedData,
35253
35445
  builderRegistrationDomain,
35254
35446
  chains,
35255
35447
  clearContractCache,
@@ -35360,6 +35552,7 @@ export {
35360
35552
  verifyWeb3Signed,
35361
35553
  waitForDerivativeStatus,
35362
35554
  waitForQuestion,
35555
+ withdrawAuthorizationDomain,
35363
35556
  writeData,
35364
35557
  writePersonalServerData
35365
35558
  };