uvd-x402-sdk 2.61.0 → 2.62.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.
package/dist/index.d.mts CHANGED
@@ -271,6 +271,18 @@ interface AnchorOptions {
271
271
  * payment wallet works fine here, because this key only ever decrypts.
272
272
  */
273
273
  sellerEncryptionKey?: Uint8Array;
274
+ /**
275
+ * The settlement proof, in the facilitator's `ProofOfPayment` shape
276
+ * (`transactionHash`, `blockNumber`, `network`, `payer`, `payee`, `amount`,
277
+ * `token`, `timestamp`, `paymentHash`).
278
+ *
279
+ * **The only thing that reaches `verified: true`.** Without it the
280
+ * facilitator has checked no chain, so it records the anchor as provisional
281
+ * and answers `notVerifiedReason: "dx402_proof_missing"`: the signature is
282
+ * accepted (`signed: true`) but authorship is not certified, and a claim that
283
+ * proves more may supersede it.
284
+ */
285
+ proofOfPayment?: Record<string, unknown>;
274
286
  /**
275
287
  * `(digest) => "0x..."`. A callable rather than a private key is what lets a
276
288
  * custodian sign: it receives the digest and returns the signature without the
@@ -284,6 +296,32 @@ interface AnchorOptions {
284
296
  facilitator?: string;
285
297
  fetch?: typeof fetch;
286
298
  }
299
+ /**
300
+ * The digest the facilitator will ACTUALLY verify, chosen by the payee's curve.
301
+ *
302
+ * The gate dispatches on the payee and checks **one** form -- never both. A
303
+ * secp256k1 payee is verified against the digest built with its REAL address and
304
+ * chain id; an ed25519 payee, whose address does not fit the `address` field, is
305
+ * verified against the zero address and chain id 0.
306
+ *
307
+ * Signing the wrong form throws nothing. It yields a signature that never
308
+ * verifies, the anchor silently stays **provisional**, and a provisional anchor
309
+ * can be superseded by anyone -- the very hijack a signed anchor exists to stop.
310
+ * Reproduced against production by KarmaKadabra, 2026-08-19: with everything else
311
+ * identical, the ed25519 form was refused (`409 dx402_already_anchored`) and the
312
+ * EVM form superseded the provisional.
313
+ *
314
+ * `pointer` stays empty on both branches: this call sends `sealed`, so the
315
+ * facilitator issues the pointer and you cannot sign what you have not seen.
316
+ */
317
+ declare function sellerDigestFor(paymentId: string, contentHash: string, payee: string, network: string): Uint8Array | undefined;
318
+ /**
319
+ * Largest `POST /dx402/anchor` request the facilitator accepts, mirroring its
320
+ * `MAX_REQUEST_BODY_BYTES` (default 64 KiB, an anti-OOM bound on every route).
321
+ * After base64 inflation and ~600 bytes of metadata this leaves ~47 KB of
322
+ * plaintext.
323
+ */
324
+ declare const ANCHOR_MAX_REQUEST_BYTES: number;
287
325
  declare function anchorEvidence(body: Uint8Array, opts: AnchorOptions): Promise<Record<string, unknown>>;
288
326
  /** Encode an anchor result for the `X-Durable-Evidence` response header. */
289
327
  declare function evidenceHeader(evidence: unknown): string;
@@ -935,4 +973,4 @@ interface EscrowPreAuthParams {
935
973
  */
936
974
  declare function buildEscrowPreAuth(wallet: EscrowPreAuthSigner, params: EscrowPreAuthParams): Promise<string>;
937
975
 
938
- export { type AnchorOptions, type AnchoredEvidence, ContentHashMismatch, type CreateSignedFetchConfig, DX402Error, type ERC8128RequestOptions, ESCROW_DEPOSIT_LIMIT_USD, ESCROW_TIER_WINDOWS, EVENT_KINDS, EVIDENCE_HEADER, type EscrowNetworkConfig, type EscrowPaymentInfo, type EscrowPreAuthParams, type EscrowPreAuthSigner, type EscrowTierWindows, type EvidenceMode, EvidenceSkipped, FACILITATOR_ADDRESSES, type FacilitatorAddresses, KEEPALIVE_INTERVAL_MS, OPERATOR_FEE_BPS, type RecipientRole, type SSEFrame, SSEParser, type SignRequestOptions, type SignRequestWithSignerOptions, type SignatureBaseParams, type SignatureHeaders, type SignatureParamsInput, SigningWalletAdapter, type StreamTrafficEventsOptions, type TrafficEvent, type TrafficEventKind, TrafficStreamError, ZERO_ADDRESS, anchorDigest, anchorEvidence, buildEscrowPreAuth, buildSignatureBase, buildSignatureParams, computeEscrowNonce, contentHash, createSignedFetch, dereferencePointer, paymentId as dx402PaymentId, ed25519ToX25519, evidenceFromHeaders, evidenceHeader, fetchNonce, getFacilitatorAddress, isEndToEnd, matchesFilters, parseEvidenceHeader, parseSealed, parseTrafficEvent, payerKeyFromEvmSignature, payerKeyFromSolanaAddress, recoverEvidence, sealEvidence, sealEvidenceTo, sealedRoles, signAnchorEd25519, signAnchorEvm, signRequest, signRequestWithSigner, signRequestWithWallet, streamTrafficEvents, unseal };
976
+ export { ANCHOR_MAX_REQUEST_BYTES, type AnchorOptions, type AnchoredEvidence, ContentHashMismatch, type CreateSignedFetchConfig, DX402Error, type ERC8128RequestOptions, ESCROW_DEPOSIT_LIMIT_USD, ESCROW_TIER_WINDOWS, EVENT_KINDS, EVIDENCE_HEADER, type EscrowNetworkConfig, type EscrowPaymentInfo, type EscrowPreAuthParams, type EscrowPreAuthSigner, type EscrowTierWindows, type EvidenceMode, EvidenceSkipped, FACILITATOR_ADDRESSES, type FacilitatorAddresses, KEEPALIVE_INTERVAL_MS, OPERATOR_FEE_BPS, type RecipientRole, type SSEFrame, SSEParser, type SignRequestOptions, type SignRequestWithSignerOptions, type SignatureBaseParams, type SignatureHeaders, type SignatureParamsInput, SigningWalletAdapter, type StreamTrafficEventsOptions, type TrafficEvent, type TrafficEventKind, TrafficStreamError, ZERO_ADDRESS, anchorDigest, anchorEvidence, buildEscrowPreAuth, buildSignatureBase, buildSignatureParams, computeEscrowNonce, contentHash, createSignedFetch, dereferencePointer, paymentId as dx402PaymentId, ed25519ToX25519, evidenceFromHeaders, evidenceHeader, fetchNonce, getFacilitatorAddress, isEndToEnd, matchesFilters, parseEvidenceHeader, parseSealed, parseTrafficEvent, payerKeyFromEvmSignature, payerKeyFromSolanaAddress, recoverEvidence, sealEvidence, sealEvidenceTo, sealedRoles, sellerDigestFor, signAnchorEd25519, signAnchorEvm, signRequest, signRequestWithSigner, signRequestWithWallet, streamTrafficEvents, unseal };
package/dist/index.d.ts CHANGED
@@ -271,6 +271,18 @@ interface AnchorOptions {
271
271
  * payment wallet works fine here, because this key only ever decrypts.
272
272
  */
273
273
  sellerEncryptionKey?: Uint8Array;
274
+ /**
275
+ * The settlement proof, in the facilitator's `ProofOfPayment` shape
276
+ * (`transactionHash`, `blockNumber`, `network`, `payer`, `payee`, `amount`,
277
+ * `token`, `timestamp`, `paymentHash`).
278
+ *
279
+ * **The only thing that reaches `verified: true`.** Without it the
280
+ * facilitator has checked no chain, so it records the anchor as provisional
281
+ * and answers `notVerifiedReason: "dx402_proof_missing"`: the signature is
282
+ * accepted (`signed: true`) but authorship is not certified, and a claim that
283
+ * proves more may supersede it.
284
+ */
285
+ proofOfPayment?: Record<string, unknown>;
274
286
  /**
275
287
  * `(digest) => "0x..."`. A callable rather than a private key is what lets a
276
288
  * custodian sign: it receives the digest and returns the signature without the
@@ -284,6 +296,32 @@ interface AnchorOptions {
284
296
  facilitator?: string;
285
297
  fetch?: typeof fetch;
286
298
  }
299
+ /**
300
+ * The digest the facilitator will ACTUALLY verify, chosen by the payee's curve.
301
+ *
302
+ * The gate dispatches on the payee and checks **one** form -- never both. A
303
+ * secp256k1 payee is verified against the digest built with its REAL address and
304
+ * chain id; an ed25519 payee, whose address does not fit the `address` field, is
305
+ * verified against the zero address and chain id 0.
306
+ *
307
+ * Signing the wrong form throws nothing. It yields a signature that never
308
+ * verifies, the anchor silently stays **provisional**, and a provisional anchor
309
+ * can be superseded by anyone -- the very hijack a signed anchor exists to stop.
310
+ * Reproduced against production by KarmaKadabra, 2026-08-19: with everything else
311
+ * identical, the ed25519 form was refused (`409 dx402_already_anchored`) and the
312
+ * EVM form superseded the provisional.
313
+ *
314
+ * `pointer` stays empty on both branches: this call sends `sealed`, so the
315
+ * facilitator issues the pointer and you cannot sign what you have not seen.
316
+ */
317
+ declare function sellerDigestFor(paymentId: string, contentHash: string, payee: string, network: string): Uint8Array | undefined;
318
+ /**
319
+ * Largest `POST /dx402/anchor` request the facilitator accepts, mirroring its
320
+ * `MAX_REQUEST_BODY_BYTES` (default 64 KiB, an anti-OOM bound on every route).
321
+ * After base64 inflation and ~600 bytes of metadata this leaves ~47 KB of
322
+ * plaintext.
323
+ */
324
+ declare const ANCHOR_MAX_REQUEST_BYTES: number;
287
325
  declare function anchorEvidence(body: Uint8Array, opts: AnchorOptions): Promise<Record<string, unknown>>;
288
326
  /** Encode an anchor result for the `X-Durable-Evidence` response header. */
289
327
  declare function evidenceHeader(evidence: unknown): string;
@@ -935,4 +973,4 @@ interface EscrowPreAuthParams {
935
973
  */
936
974
  declare function buildEscrowPreAuth(wallet: EscrowPreAuthSigner, params: EscrowPreAuthParams): Promise<string>;
937
975
 
938
- export { type AnchorOptions, type AnchoredEvidence, ContentHashMismatch, type CreateSignedFetchConfig, DX402Error, type ERC8128RequestOptions, ESCROW_DEPOSIT_LIMIT_USD, ESCROW_TIER_WINDOWS, EVENT_KINDS, EVIDENCE_HEADER, type EscrowNetworkConfig, type EscrowPaymentInfo, type EscrowPreAuthParams, type EscrowPreAuthSigner, type EscrowTierWindows, type EvidenceMode, EvidenceSkipped, FACILITATOR_ADDRESSES, type FacilitatorAddresses, KEEPALIVE_INTERVAL_MS, OPERATOR_FEE_BPS, type RecipientRole, type SSEFrame, SSEParser, type SignRequestOptions, type SignRequestWithSignerOptions, type SignatureBaseParams, type SignatureHeaders, type SignatureParamsInput, SigningWalletAdapter, type StreamTrafficEventsOptions, type TrafficEvent, type TrafficEventKind, TrafficStreamError, ZERO_ADDRESS, anchorDigest, anchorEvidence, buildEscrowPreAuth, buildSignatureBase, buildSignatureParams, computeEscrowNonce, contentHash, createSignedFetch, dereferencePointer, paymentId as dx402PaymentId, ed25519ToX25519, evidenceFromHeaders, evidenceHeader, fetchNonce, getFacilitatorAddress, isEndToEnd, matchesFilters, parseEvidenceHeader, parseSealed, parseTrafficEvent, payerKeyFromEvmSignature, payerKeyFromSolanaAddress, recoverEvidence, sealEvidence, sealEvidenceTo, sealedRoles, signAnchorEd25519, signAnchorEvm, signRequest, signRequestWithSigner, signRequestWithWallet, streamTrafficEvents, unseal };
976
+ export { ANCHOR_MAX_REQUEST_BYTES, type AnchorOptions, type AnchoredEvidence, ContentHashMismatch, type CreateSignedFetchConfig, DX402Error, type ERC8128RequestOptions, ESCROW_DEPOSIT_LIMIT_USD, ESCROW_TIER_WINDOWS, EVENT_KINDS, EVIDENCE_HEADER, type EscrowNetworkConfig, type EscrowPaymentInfo, type EscrowPreAuthParams, type EscrowPreAuthSigner, type EscrowTierWindows, type EvidenceMode, EvidenceSkipped, FACILITATOR_ADDRESSES, type FacilitatorAddresses, KEEPALIVE_INTERVAL_MS, OPERATOR_FEE_BPS, type RecipientRole, type SSEFrame, SSEParser, type SignRequestOptions, type SignRequestWithSignerOptions, type SignatureBaseParams, type SignatureHeaders, type SignatureParamsInput, SigningWalletAdapter, type StreamTrafficEventsOptions, type TrafficEvent, type TrafficEventKind, TrafficStreamError, ZERO_ADDRESS, anchorDigest, anchorEvidence, buildEscrowPreAuth, buildSignatureBase, buildSignatureParams, computeEscrowNonce, contentHash, createSignedFetch, dereferencePointer, paymentId as dx402PaymentId, ed25519ToX25519, evidenceFromHeaders, evidenceHeader, fetchNonce, getFacilitatorAddress, isEndToEnd, matchesFilters, parseEvidenceHeader, parseSealed, parseTrafficEvent, payerKeyFromEvmSignature, payerKeyFromSolanaAddress, recoverEvidence, sealEvidence, sealEvidenceTo, sealedRoles, sellerDigestFor, signAnchorEd25519, signAnchorEvm, signRequest, signRequestWithSigner, signRequestWithWallet, streamTrafficEvents, unseal };
package/dist/index.js CHANGED
@@ -1625,6 +1625,9 @@ async function anchorEvidence(body, opts) {
1625
1625
  retention: opts.retention ?? "90d"
1626
1626
  };
1627
1627
  let unsigned;
1628
+ if (opts.proofOfPayment) {
1629
+ payload.proofOfPayment = opts.proofOfPayment;
1630
+ }
1628
1631
  if (opts.sign) {
1629
1632
  const digest = sellerDigestFor(opts.paymentId, hash, opts.payee, opts.network);
1630
1633
  if (digest === void 0) {
@@ -1663,8 +1666,8 @@ async function anchorEvidence(body, opts) {
1663
1666
  }
1664
1667
  }
1665
1668
  function evidenceHeader(evidence) {
1666
- const json = JSON.stringify(evidence);
1667
- return btoa(json).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1669
+ const bytes = new TextEncoder().encode(JSON.stringify(evidence));
1670
+ return toBase64(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1668
1671
  }
1669
1672
 
1670
1673
  // src/types/index.ts
@@ -4297,6 +4300,7 @@ var ESCROW_TIMEOUT_MS = {
4297
4300
  // Monad: 90s
4298
4301
  };
4299
4302
 
4303
+ exports.ANCHOR_MAX_REQUEST_BYTES = ANCHOR_MAX_REQUEST_BYTES;
4300
4304
  exports.CAIP2_IDENTIFIERS = CAIP2_IDENTIFIERS;
4301
4305
  exports.CAIP2_TO_CHAIN = CAIP2_TO_CHAIN;
4302
4306
  exports.ContentHashMismatch = ContentHashMismatch;
@@ -4401,6 +4405,7 @@ exports.recoverEvidence = recoverEvidence;
4401
4405
  exports.sealEvidence = sealEvidence;
4402
4406
  exports.sealEvidenceTo = sealEvidenceTo;
4403
4407
  exports.sealedRoles = sealedRoles;
4408
+ exports.sellerDigestFor = sellerDigestFor;
4404
4409
  exports.signAnchorEd25519 = signAnchorEd25519;
4405
4410
  exports.signAnchorEvm = signAnchorEvm;
4406
4411
  exports.signRequest = signRequest;