@opendatalabs/vana-sdk 3.23.0-pr.211.fa01520 → 4.0.0

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":"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","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,7 +36,7 @@ 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";
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
40
  export { ENCLAVE_IDENTITY_EVIDENCE_VERSION, USER_PS_ID_DOMAIN, ENCLAVE_WALLET_PURPOSE, MASTER_SIGNATURE_DELIVERY_VERSION, MASTER_SIGNATURE_DELIVERY_MAX_AGE_SECONDS, 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 { JOB_PROTOCOL_VERSION, JOB_OPERATIONS, JOB_STATES, DEFAULT_LEASE_SECONDS, MAX_LEASE_SECONDS, MAX_ATTEMPTS, MAX_WAIT_SECONDS, CLAIM_POLL_FLOOR_MS, DEFAULT_JOB_DEADLINE_SECONDS, MAX_JOB_DEADLINE_SECONDS, type JobOperation, type JobState, type PaymentState, type JobRequest, type JobRequestEnvelope, type JobSubmission, type ResultHandle, type JobStatus, type ClaimRequest, type ClaimResponse, type HeartbeatRequest, type CompleteRequest, type FailRequest, type FencedResponse, type JobResult, type TeeNodeState, type TeeNodeRegistration, type TeeNodeHeartbeat, type TeeNode, } from "./protocol/jobs.js";
42
42
  export { JobEnvelopeError, JOB_RESULT_FORMAT_VERSION, JOB_RESULT_CHUNK_BYTES, canonicalJobRequestBytes, sealJobRequest, openJobRequest, sealJobResultStream, openJobResultStream, sealJobResult, openJobResult, type JobResultMetadata, type JobResultExpectation, type SealedJobResultStream, type OpenedJobResultStream, } from "./crypto/envelope/job.js";
@@ -59,5 +59,5 @@ export { DERIVATIVE_STATUS_PATH, DEFAULT_DERIVATIVE_STATUS_TIMEOUT_MS, DEFAULT_D
59
59
  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";
60
60
  export { DataFileEnvelopeSchema, createDataFileEnvelope, IngestResponseSchema, type DataFileEnvelope, type IngestResponse, } from "./protocol/data-file.js";
61
61
  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";
62
- 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";
62
+ 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";
63
63
  export { PSError, parsePSError, type PSErrorCode } from "./types/ps-errors.js";
@@ -31391,6 +31391,9 @@ function escrowPaymentDomain(config) {
31391
31391
  config.contracts.dataPortabilityEscrow
31392
31392
  );
31393
31393
  }
31394
+ function withdrawAuthorizationDomain(config) {
31395
+ return escrowPaymentDomain(config);
31396
+ }
31394
31397
  var GRANT_REGISTRATION_TYPES = {
31395
31398
  GrantRegistration: [
31396
31399
  { name: "grantorAddress", type: "address" },
@@ -31423,6 +31426,15 @@ var BUILDER_REGISTRATION_TYPES = {
31423
31426
  { name: "appUrl", type: "string" }
31424
31427
  ]
31425
31428
  };
31429
+ var WITHDRAW_AUTHORIZATION_TYPES = {
31430
+ WithdrawAuthorization: [
31431
+ { name: "account", type: "address" },
31432
+ { name: "asset", type: "address" },
31433
+ { name: "amount", type: "uint256" },
31434
+ { name: "withdrawNonce", type: "uint256" },
31435
+ { name: "deadline", type: "uint256" }
31436
+ ]
31437
+ };
31426
31438
  var ADD_DATA_TYPES = {
31427
31439
  AddData: [
31428
31440
  { name: "ownerAddress", type: "address" },
@@ -31441,6 +31453,14 @@ var RECORD_DATA_ACCESS_TYPES = {
31441
31453
  { name: "recordId", type: "bytes32" }
31442
31454
  ]
31443
31455
  };
31456
+ function buildWithdrawAuthorizationTypedData(config, message) {
31457
+ return {
31458
+ domain: withdrawAuthorizationDomain(config),
31459
+ types: WITHDRAW_AUTHORIZATION_TYPES,
31460
+ primaryType: "WithdrawAuthorization",
31461
+ message
31462
+ };
31463
+ }
31444
31464
 
31445
31465
  // src/protocol/identity.ts
31446
31466
  init_interface();
@@ -31479,8 +31499,13 @@ function emptyAnchor() {
31479
31499
  var ENCLAVE_TRUST_ANCHORS = Object.freeze({
31480
31500
  // filled at fleet provisioning; verify fails closed while empty
31481
31501
  [VANA_MAINNET_CHAIN_ID]: emptyAnchor(),
31482
- // filled at fleet provisioning; verify fails closed while empty
31483
- [MOKSHA_CHAIN_ID]: emptyAnchor()
31502
+ // Moksha workers share this dstack app and KMS root; the controller does not derive owner keys.
31503
+ [MOKSHA_CHAIN_ID]: Object.freeze({
31504
+ kmsRootPubkey: "0x0434c76e0c3f52ec64cbf9bbf5c910c272330166fd656c0a86bb330963e46910e1a0e6fa51bec74be2f9129342707636060d85856d102cee8290185409ecf7422f",
31505
+ appIds: Object.freeze([
31506
+ "0xec9a39de98c760e1ded9f1e97016dc5f0e357cf2"
31507
+ ])
31508
+ })
31484
31509
  });
31485
31510
  function userPsId(chainId, ownerAddress) {
31486
31511
  const packed = encodePacked(
@@ -35517,6 +35542,7 @@ function createGatewayClient(baseUrl) {
35517
35542
  }
35518
35543
 
35519
35544
  // src/protocol/escrow.ts
35545
+ import { isHex as isHex2 } from "viem";
35520
35546
  var GENERIC_PAYMENT_TYPES = {
35521
35547
  GenericPayment: [
35522
35548
  { name: "payerAddress", type: "address" },
@@ -35556,6 +35582,26 @@ var ESCROW_DEPOSIT_ABI2 = [
35556
35582
  }
35557
35583
  ];
35558
35584
  var NATIVE_ASSET_ADDRESS = "0x0000000000000000000000000000000000000000";
35585
+ var EscrowWithdrawalLifecycleError = class extends Error {
35586
+ constructor(httpStatus, result) {
35587
+ super(result.error);
35588
+ this.httpStatus = httpStatus;
35589
+ this.result = result;
35590
+ }
35591
+ httpStatus;
35592
+ result;
35593
+ name = "EscrowWithdrawalLifecycleError";
35594
+ };
35595
+ var EscrowWithdrawalRejectionError = class extends Error {
35596
+ constructor(httpStatus, result) {
35597
+ super(result.error);
35598
+ this.httpStatus = httpStatus;
35599
+ this.result = result;
35600
+ }
35601
+ httpStatus;
35602
+ result;
35603
+ name = "EscrowWithdrawalRejectionError";
35604
+ };
35559
35605
  function createEscrowGatewayClient(baseUrl) {
35560
35606
  const base = baseUrl.replace(/\/+$/, "");
35561
35607
  async function throwOnError(res, context) {
@@ -35571,6 +35617,27 @@ function createEscrowGatewayClient(baseUrl) {
35571
35617
  );
35572
35618
  }
35573
35619
  }
35620
+ async function throwOnWithdrawError(res) {
35621
+ if (res.ok) return;
35622
+ let body;
35623
+ try {
35624
+ body = await res.json();
35625
+ } catch {
35626
+ throw new Error(
35627
+ `Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}`
35628
+ );
35629
+ }
35630
+ if (isEscrowWithdrawalFailureResult(body)) {
35631
+ throw new EscrowWithdrawalLifecycleError(res.status, body);
35632
+ }
35633
+ if (isEscrowWithdrawalRejectedResult(body)) {
35634
+ throw new EscrowWithdrawalRejectionError(res.status, body);
35635
+ }
35636
+ const error = getGatewayErrorMessage(body);
35637
+ throw new Error(
35638
+ `Escrow gateway error (POST /v1/escrow/withdraw): ${res.status} ${res.statusText}${error ? `: ${error}` : ""}`
35639
+ );
35640
+ }
35574
35641
  return {
35575
35642
  async submitDeposit({ txHash }) {
35576
35643
  const res = await fetch(`${base}/v1/escrow/deposit`, {
@@ -35626,9 +35693,108 @@ function createEscrowGatewayClient(baseUrl) {
35626
35693
  });
35627
35694
  await throwOnError(res, "POST /v1/escrow/pay");
35628
35695
  return res.json();
35696
+ },
35697
+ async withdraw({
35698
+ account,
35699
+ asset,
35700
+ amount,
35701
+ withdrawNonce,
35702
+ deadline,
35703
+ signature
35704
+ }) {
35705
+ const res = await fetch(`${base}/v1/escrow/withdraw`, {
35706
+ method: "POST",
35707
+ headers: {
35708
+ "Content-Type": "application/json",
35709
+ Authorization: `Web3Signed ${signature}`
35710
+ },
35711
+ body: JSON.stringify({
35712
+ account,
35713
+ asset,
35714
+ amount,
35715
+ withdrawNonce,
35716
+ deadline
35717
+ })
35718
+ });
35719
+ await throwOnWithdrawError(res);
35720
+ return res.json();
35721
+ },
35722
+ async getWithdrawNonce(account) {
35723
+ const res = await fetch(
35724
+ `${base}/v1/escrow/withdraw/nonce?account=${encodeURIComponent(account)}`,
35725
+ { cache: "no-store" }
35726
+ );
35727
+ await throwOnError(res, "GET /v1/escrow/withdraw/nonce");
35728
+ const body = await res.json();
35729
+ if (!isWithdrawNonceResponse(body, account)) {
35730
+ throw new Error(
35731
+ "GET /v1/escrow/withdraw/nonce: invalid response structure"
35732
+ );
35733
+ }
35734
+ return body;
35629
35735
  }
35630
35736
  };
35631
35737
  }
35738
+ function getGatewayErrorMessage(body) {
35739
+ if (typeof body === "object" && body !== null && "error" in body && typeof body.error === "string") {
35740
+ return body.error;
35741
+ }
35742
+ return void 0;
35743
+ }
35744
+ function isEscrowWithdrawalFailureResult(body) {
35745
+ if (typeof body !== "object" || body === null) return false;
35746
+ const value = body;
35747
+ 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));
35748
+ }
35749
+ function isEscrowWithdrawalRejectedResult(body) {
35750
+ if (typeof body !== "object" || body === null) return false;
35751
+ const value = body;
35752
+ 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);
35753
+ }
35754
+ function isWithdrawalRejectionCode(value) {
35755
+ return value === "below_minimum" || value === "deadline_too_far" || value === "expired" || value === "insufficient_available" || value === "stale_nonce";
35756
+ }
35757
+ function optionalUint256Decimal(value) {
35758
+ return value === void 0 || isUint256Decimal(value);
35759
+ }
35760
+ function isAddressHex(value) {
35761
+ return typeof value === "string" && isHex2(value, { strict: true }) && value.length === 42;
35762
+ }
35763
+ function isHash(value) {
35764
+ return typeof value === "string" && isHex2(value, { strict: true }) && value.length === 66;
35765
+ }
35766
+ function isUint256Decimal(value) {
35767
+ if (typeof value !== "string" || value.length === 0 || value.length > 78) {
35768
+ return false;
35769
+ }
35770
+ if (!/^(0|[1-9]\d*)$/.test(value)) return false;
35771
+ return BigInt(value) <= 2n ** 256n - 1n;
35772
+ }
35773
+ function isBlockNumber(value) {
35774
+ return value === null || isUint256Decimal(value);
35775
+ }
35776
+ function isWithdrawNonceResponse(body, requestedAccount) {
35777
+ if (typeof body !== "object" || body === null) return false;
35778
+ const value = body;
35779
+ if (value.success !== true) return false;
35780
+ if (!isAddressHex(value.account)) return false;
35781
+ if (value.account.toLowerCase() !== requestedAccount.toLowerCase())
35782
+ return false;
35783
+ if (typeof value.chainId !== "string") return false;
35784
+ if (!/^(0|[1-9]\d*)$/.test(value.chainId)) return false;
35785
+ const isLastNull = value.lastWithdrawNonce === null;
35786
+ const lastNonceValid = isLastNull || isUint256Decimal(value.lastWithdrawNonce);
35787
+ if (!lastNonceValid) return false;
35788
+ if (!isUint256Decimal(value.nextWithdrawNonce)) return false;
35789
+ if (isLastNull) {
35790
+ return value.nextWithdrawNonce === "1";
35791
+ }
35792
+ const lastNonce = BigInt(value.lastWithdrawNonce);
35793
+ const nextNonce = BigInt(value.nextWithdrawNonce);
35794
+ const expectedNextNonce = lastNonce + 1n;
35795
+ if (expectedNextNonce > 2n ** 256n - 1n) return false;
35796
+ return nextNonce === expectedNextNonce;
35797
+ }
35632
35798
 
35633
35799
  // src/types/ps-errors.ts
35634
35800
  var PSError = class extends Error {
@@ -35725,6 +35891,8 @@ export {
35725
35891
  ENCLAVE_TRUST_ANCHORS,
35726
35892
  ENCLAVE_WALLET_PURPOSE,
35727
35893
  ESCROW_DEPOSIT_ABI2 as ESCROW_DEPOSIT_ABI,
35894
+ EscrowWithdrawalLifecycleError,
35895
+ EscrowWithdrawalRejectionError,
35728
35896
  ExpiredTokenError2 as ExpiredTokenError,
35729
35897
  FEE_REGISTRY_ABI,
35730
35898
  GENERIC_PAYMENT_TYPES,
@@ -35793,6 +35961,7 @@ export {
35793
35961
  TOMBSTONE_METADATA_HASH_PREIMAGE,
35794
35962
  USER_PS_ID_DOMAIN,
35795
35963
  VanaStorage,
35964
+ WITHDRAW_AUTHORIZATION_TYPES,
35796
35965
  WRITER_ATTRIBUTION_KEY,
35797
35966
  WRITE_CONTENT_DISPOSITION_HEADER,
35798
35967
  WRITE_FILENAME_HEADER,
@@ -35817,6 +35986,7 @@ export {
35817
35986
  buildPersonalServerRegistrationTypedData,
35818
35987
  buildSetDataPointStatusRequest,
35819
35988
  buildWeb3SignedHeader,
35989
+ buildWithdrawAuthorizationTypedData,
35820
35990
  builderRegistrationDomain,
35821
35991
  canonicalJobRequestBytes,
35822
35992
  chains,
@@ -35934,6 +36104,7 @@ export {
35934
36104
  verifyWeb3Signed,
35935
36105
  waitForDerivativeStatus,
35936
36106
  waitForQuestion,
36107
+ withdrawAuthorizationDomain,
35937
36108
  writeData,
35938
36109
  writePersonalServerData
35939
36110
  };