@haven_ai/sdk 0.1.23-alpha.0 → 0.1.23-alpha.2

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.cjs CHANGED
@@ -703,73 +703,6 @@ function stableStringify(value) {
703
703
  const object = value;
704
704
  return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(object[key])}`).join(",")}}`;
705
705
  }
706
- function normalizeChallenge(value) {
707
- const candidate = value;
708
- if (!candidate || typeof candidate !== "object" || candidate.rail !== "mpp_demo" || typeof candidate.version !== "string" || typeof candidate.challengeId !== "string" || typeof candidate.resource !== "string" || typeof candidate.description !== "string" || // TODO: relax these checks when non-demo machine payment rails are added.
709
- candidate.network?.chainId !== 8453 || candidate.network?.name !== "base" || candidate.asset?.symbol !== "USDC" || typeof candidate.asset?.address !== "string" || candidate.asset.decimals !== 6 || typeof candidate.amount?.display !== "string" || typeof candidate.amount?.atomic !== "string" || typeof candidate.recipient !== "string" || typeof candidate.expiresAt !== "string") {
710
- return null;
711
- }
712
- return {
713
- rail: candidate.rail,
714
- version: candidate.version,
715
- challengeId: candidate.challengeId,
716
- resource: candidate.resource,
717
- description: candidate.description,
718
- network: candidate.network,
719
- asset: candidate.asset,
720
- amount: candidate.amount,
721
- recipient: candidate.recipient,
722
- expiresAt: candidate.expiresAt,
723
- metadata: candidate.metadata
724
- };
725
- }
726
- function parseMachinePaymentChallenge(response) {
727
- const header = response.headers.get("MACHINE-PAYMENT-CHALLENGE");
728
- if (!header) {
729
- throw new Error("No MACHINE-PAYMENT-CHALLENGE header found in 402 response.");
730
- }
731
- const parsed = normalizeChallenge(
732
- decodeBase64Json(header, "MACHINE-PAYMENT-CHALLENGE header")
733
- );
734
- if (!parsed) throw new Error("Invalid machine payment challenge");
735
- return parsed;
736
- }
737
- async function parseMachinePaymentChallengeResponse(response) {
738
- try {
739
- return parseMachinePaymentChallenge(response);
740
- } catch (headerErr) {
741
- try {
742
- const body = await response.clone().json();
743
- const parsed = normalizeChallenge(body.challenge);
744
- if (parsed) return parsed;
745
- } catch {
746
- }
747
- throw headerErr;
748
- }
749
- }
750
- function buildMachinePaymentIdempotencyKey(challenge) {
751
- const material = [
752
- challenge.rail,
753
- challenge.challengeId,
754
- challenge.resource,
755
- challenge.recipient.toLowerCase(),
756
- challenge.asset.address.toLowerCase(),
757
- challenge.amount.atomic,
758
- challenge.network.chainId
759
- ].join("|");
760
- return `${challenge.rail}:${crypto.createHash("sha256").update(material).digest("hex").slice(0, 16)}`;
761
- }
762
- function encodeMachinePaymentProof(receipt) {
763
- return encodeBase64Json({
764
- rail: receipt.rail,
765
- challengeId: receipt.challengeId,
766
- paymentId: receipt.paymentId,
767
- txHash: receipt.txHash,
768
- settledVia: "haven",
769
- payer: receipt.payer,
770
- chainId: receipt.chainId
771
- });
772
- }
773
706
  function createJsonRpcProvider(url) {
774
707
  return new ethers.ethers.JsonRpcProvider(url);
775
708
  }
@@ -890,9 +823,6 @@ function messageForState(label, status, paymentId, nextAction) {
890
823
  function sameAddress(a, b) {
891
824
  return Boolean(a && b && a.toLowerCase() === b.toLowerCase());
892
825
  }
893
- function isMppRail(rail) {
894
- return rail === "mpp" || Boolean(rail?.startsWith("mpp_"));
895
- }
896
826
  function decimalFromUsdcAtomic(value) {
897
827
  const amount = BigInt(value);
898
828
  const whole = amount / 1000000n;
@@ -994,7 +924,6 @@ var HavenClient = class {
994
924
  chainRpcs;
995
925
  inFlightX402 = /* @__PURE__ */ new Map();
996
926
  x402ReceiptCache = /* @__PURE__ */ new Map();
997
- inFlightMachinePayments = /* @__PURE__ */ new Map();
998
927
  /**
999
928
  * Setup-time headers configured via `HavenClientConfig.defaultHeaders`.
1000
929
  * Read-only after construction — use `withRequestContext` for per-call
@@ -1608,10 +1537,11 @@ var HavenClient = class {
1608
1537
  return { receipt, verification: verifyPaymentReceipt(receipt) };
1609
1538
  }
1610
1539
  /**
1611
- * Rehydrate the x402/MPP resume-state bundle for a payment id.
1540
+ * Rehydrate the x402 resume-state bundle for a payment id (#1328: the MPP
1541
+ * resume-state variant retired along with the rest of the mpp_demo surface).
1612
1542
  *
1613
1543
  * The server returns stored protocol context only. The client still signs the
1614
- * merchant proof locally when resumeX402Payment() or resumeMppPayment() runs.
1544
+ * merchant proof locally when resumeX402Payment() runs.
1615
1545
  */
1616
1546
  async getResumeState(paymentId) {
1617
1547
  return this.get(`/payments/${paymentId}/resume_state`);
@@ -1882,22 +1812,11 @@ var HavenClient = class {
1882
1812
  if (response.status !== 402) {
1883
1813
  return mcpSessionId ? this.surfaceMcpResult(response) : response;
1884
1814
  }
1885
- const machineChallengeHeader = response.headers.get("MACHINE-PAYMENT-CHALLENGE");
1886
- if (machineChallengeHeader) {
1887
- const challenge = await parseMachinePaymentChallengeResponse(response);
1888
- return this.fetchWithMachinePayment(url, requestInit, challenge);
1889
- }
1890
1815
  let paymentRequired;
1891
1816
  try {
1892
1817
  paymentRequired = await parsePaymentRequiredResponse(response);
1893
1818
  } catch {
1894
- let challenge;
1895
- try {
1896
- challenge = await parseMachinePaymentChallengeResponse(response);
1897
- } catch {
1898
- return response;
1899
- }
1900
- return this.fetchWithMachinePayment(url, requestInit, challenge);
1819
+ return response;
1901
1820
  }
1902
1821
  if (!mcpSessionId && await responseHasBazaarExtension(response)) {
1903
1822
  mcpSessionId = await this.mcpInitialize(url, init);
@@ -2040,49 +1959,6 @@ var HavenClient = class {
2040
1959
  headers
2041
1960
  });
2042
1961
  }
2043
- /**
2044
- * Probe a paid MPP endpoint or inspect an existing challenge without creating
2045
- * a Haven payment or approval request.
2046
- */
2047
- async quoteMpp(challengeOrUrl, init, options = {}) {
2048
- if (typeof challengeOrUrl !== "string") {
2049
- const request2 = this.snapshotX402Request(challengeOrUrl.resource, init);
2050
- return this.buildMppQuote(challengeOrUrl, request2, options.idempotencyKey);
2051
- }
2052
- const request = this.snapshotX402Request(challengeOrUrl, init);
2053
- const response = await this.merchantFetch(challengeOrUrl, init);
2054
- if (response.status !== 402) {
2055
- throw new HavenApiError(
2056
- `Expected an MPP quote response with HTTP 402, got HTTP ${response.status}.`,
2057
- response.status || 400
2058
- );
2059
- }
2060
- const challenge = await parseMachinePaymentChallengeResponse(response);
2061
- return this.buildMppQuote(challenge, request, options.idempotencyKey);
2062
- }
2063
- /**
2064
- * Pay a previously inspected MPP quote and retry the exact captured request.
2065
- */
2066
- async payMppChallenge(quote, options = {}) {
2067
- const idempotencyKey = options.idempotencyKey ?? quote.idempotencyKey;
2068
- try {
2069
- const receipt = await this.authorizeMachinePayment(quote.challenge, { idempotencyKey });
2070
- return this.retryMppRequest(
2071
- quote.request.url,
2072
- this.requestInitFromSnapshot(quote.request),
2073
- quote.challenge,
2074
- receipt
2075
- );
2076
- } catch (err) {
2077
- this.attachResumeState(err, {
2078
- rail: "mpp",
2079
- challenge: quote.challenge,
2080
- idempotencyKey,
2081
- request: quote.request
2082
- });
2083
- throw err;
2084
- }
2085
- }
2086
1962
  async retryX402Request(url, initialInit, paymentRequired, receipt) {
2087
1963
  if (!receipt.accepted) {
2088
1964
  throw new HavenApiError("No accepted x402 option was recorded for payment retry", 500);
@@ -2347,151 +2223,13 @@ var HavenClient = class {
2347
2223
  return void 0;
2348
2224
  }
2349
2225
  }
2350
- async authorizeMachinePayment(challenge, options = {}) {
2351
- if (!this.delegateKey) {
2352
- throw new HavenSigningError(
2353
- "delegateKey is required for machine payments. Pass it in the HavenClient config."
2354
- );
2355
- }
2356
- if (challenge.rail !== "mpp_demo") {
2357
- throw new HavenApiError(`Unsupported machine payment rail: ${challenge.rail}`, 400);
2358
- }
2359
- const idempotencyKey = options.idempotencyKey ?? buildMachinePaymentIdempotencyKey(challenge);
2360
- const inFlight = this.inFlightMachinePayments.get(idempotencyKey);
2361
- if (inFlight) return inFlight;
2362
- const promise = this.authorizeMppDemoPayment(challenge, idempotencyKey);
2363
- this.inFlightMachinePayments.set(idempotencyKey, promise);
2364
- try {
2365
- return await promise;
2366
- } catch (err) {
2367
- this.attachResumeState(err, {
2368
- rail: "mpp",
2369
- challenge,
2370
- idempotencyKey
2371
- });
2372
- throw err;
2373
- } finally {
2374
- this.inFlightMachinePayments.delete(idempotencyKey);
2375
- }
2376
- }
2377
- async authorizeMppDemoPayment(challenge, idempotencyKey) {
2378
- const raw = await this.post(
2379
- "/machine-payments/authorize",
2380
- { challenge, idempotencyKey }
2381
- );
2382
- if (raw.success && raw.tx_hash) {
2383
- return this.mapMachinePaymentReceipt(challenge, raw, raw.tx_hash);
2384
- }
2385
- this.throwIfNonSignableAuthorizationState("Machine payment", raw);
2386
- if (!raw.sign_data?.hash) {
2387
- throw new HavenApiError("No sign_hash returned from machine payment authorization", 500, raw);
2388
- }
2389
- const sig = await this.signForData(raw.sign_data);
2390
- const execResult = await this.post(
2391
- `/payments/${raw.payment_id}/sign`,
2392
- { signature: sig }
2393
- );
2394
- if (execResult.status !== "confirmed" || !execResult.tx_hash) {
2395
- this.throwPaymentStateError("Machine payment", execResult);
2396
- }
2397
- return this.mapMachinePaymentReceipt(challenge, raw, execResult.tx_hash, execResult);
2398
- }
2399
- async resumeAuthorizedMpp(input) {
2400
- if (!this.delegateKey) {
2401
- throw new HavenSigningError(
2402
- "delegateKey is required for machine payments. Pass it in the HavenClient config."
2403
- );
2404
- }
2405
- const status = await this.getPaymentStatus(input.paymentId);
2406
- this.assertCanResumeMpp(status, input.challenge);
2407
- return this.mapMachinePaymentReceiptFromStatus(input.challenge, status);
2408
- }
2409
- async resumeMppPayment(input) {
2410
- const inputInit = "init" in input ? input.init : void 0;
2411
- const initialInit = inputInit ?? (input.request ? this.requestInitFromSnapshot(input.request) : void 0);
2412
- let challenge = input.challenge;
2413
- const url = input.url ?? input.request?.url;
2414
- if (!challenge) {
2415
- if (!url) {
2416
- throw new HavenApiError("MPP resume requires the original URL or a captured request snapshot.", 400);
2417
- }
2418
- const response = await this.merchantFetch(url, initialInit);
2419
- if (response.status !== 402) {
2420
- throw new HavenApiError("Expected the original MPP request to return HTTP 402 before resuming.", 400);
2421
- }
2422
- challenge = await parseMachinePaymentChallengeResponse(response);
2423
- }
2424
- const receipt = await this.resumeAuthorizedMpp({
2425
- paymentId: input.paymentId,
2426
- challenge,
2427
- idempotencyKey: input.idempotencyKey
2428
- });
2429
- return this.retryMppRequest(url ?? challenge.resource, initialInit, challenge, receipt);
2430
- }
2431
- async fetchWithMachinePayment(url, initialInit, challenge) {
2432
- const request = this.snapshotX402Request(url, initialInit);
2433
- const idempotencyKey = buildMachinePaymentIdempotencyKey(challenge);
2434
- let receipt;
2435
- try {
2436
- receipt = await this.authorizeMachinePayment(challenge, { idempotencyKey });
2437
- } catch (err) {
2438
- this.attachResumeState(err, {
2439
- rail: "mpp",
2440
- challenge,
2441
- idempotencyKey,
2442
- request
2443
- });
2444
- throw err;
2445
- }
2446
- return this.retryMppRequest(url, initialInit, challenge, receipt);
2447
- }
2448
- async retryMppRequest(url, initialInit, challenge, receipt) {
2449
- const retryHeaders = new Headers(initialInit?.headers);
2450
- retryHeaders.set("MACHINE-PAYMENT-PROOF", receipt.proofHeader);
2451
- const retryResponse = await this.merchantFetch(url, {
2452
- ...initialInit,
2453
- headers: retryHeaders
2454
- });
2455
- if (!retryResponse.ok) {
2456
- const merchant = await captureMerchantResponse(retryResponse);
2457
- await this.recordMerchantRetryRejected({
2458
- rail: receipt.rail,
2459
- paymentId: receipt.paymentId,
2460
- txHash: receipt.txHash,
2461
- resourceUrl: receipt.resourceUrl,
2462
- merchant,
2463
- details: {
2464
- challenge_id: receipt.challengeId
2465
- }
2466
- });
2467
- throw new HavenApiError(
2468
- "Machine payment retry failed after Haven sent the payment.",
2469
- merchant.merchant_status,
2470
- {
2471
- marker: "machine_payment_retry_rejected_after_payment",
2472
- payment_id: receipt.paymentId,
2473
- tx_hash: receipt.txHash,
2474
- resource_url: receipt.resourceUrl,
2475
- rail: receipt.rail,
2476
- ...merchant
2477
- }
2478
- );
2479
- }
2480
- await this.reportMachinePaymentEvidence({
2481
- paymentId: receipt.paymentId,
2482
- rail: receipt.rail,
2483
- txHash: receipt.txHash,
2484
- resourceUrl: receipt.resourceUrl,
2485
- merchantStatus: retryResponse.status,
2486
- challengePayload: challenge,
2487
- paymentProofHeaderName: "MACHINE-PAYMENT-PROOF",
2488
- paymentProofHeader: receipt.proofHeader,
2489
- protocolReceiptHeaderName: retryResponse.headers.has("Payment-Receipt") ? "Payment-Receipt" : retryResponse.headers.has("MACHINE-PAYMENT-RESPONSE") ? "MACHINE-PAYMENT-RESPONSE" : void 0,
2490
- protocolReceiptHeader: retryResponse.headers.get("Payment-Receipt") ?? retryResponse.headers.get("MACHINE-PAYMENT-RESPONSE") ?? void 0
2491
- });
2492
- await this.reportMerchantReceipt(receipt.paymentId, retryResponse);
2493
- return retryResponse;
2494
- }
2226
+ // #1328: authorizeMachinePayment / authorizeMppDemoPayment / resumeAuthorizedMpp
2227
+ // / resumeMppPayment / fetchWithMachinePayment / retryMppRequest (the
2228
+ // MACHINE-PAYMENT-CHALLENGE / mpp_demo client surface) are retired — the
2229
+ // backend's POST /machine-payments/authorize refuses unconditionally now,
2230
+ // and MACHINE-PAYMENT-CHALLENGE was never produced by any other Haven
2231
+ // surface. Use the x402 flow (authorizeX402 / fetch / quoteX402 / payX402Quote)
2232
+ // for agent-to-merchant payments.
2495
2233
  assertCanResumeX402(status, paymentRequired, option) {
2496
2234
  if (status.rail !== "x402") {
2497
2235
  throw new HavenPaymentStateError(
@@ -2555,68 +2293,6 @@ var HavenClient = class {
2555
2293
  );
2556
2294
  }
2557
2295
  }
2558
- assertCanResumeMpp(status, challenge) {
2559
- if (!isMppRail(status.rail)) {
2560
- throw new HavenPaymentStateError(
2561
- `Payment ${status.paymentId} is ${status.rail}, not MPP.`,
2562
- 409,
2563
- status
2564
- );
2565
- }
2566
- if (status.nextAction !== AgentPaymentNextAction.RetryOriginalX402Request) {
2567
- throw new HavenPaymentStateError(status.message, PAYMENT_STATE_STATUS_CODES[status.status] ?? 409, status);
2568
- }
2569
- if (!status.txHash) {
2570
- throw new HavenApiError(
2571
- `MPP payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
2572
- 502,
2573
- status,
2574
- status.paymentId
2575
- );
2576
- }
2577
- if (status.resourceUrl && status.resourceUrl !== challenge.resource) {
2578
- throw new HavenApiError(
2579
- "MPP resume request does not match the approved resource URL.",
2580
- 409,
2581
- { status, challenge },
2582
- status.paymentId
2583
- );
2584
- }
2585
- if (status.merchantAddress && !sameAddress(status.merchantAddress, challenge.recipient)) {
2586
- throw new HavenApiError(
2587
- "MPP resume request does not match the approved merchant.",
2588
- 409,
2589
- { status, challenge },
2590
- status.paymentId
2591
- );
2592
- }
2593
- if (status.chainId && status.chainId !== challenge.network.chainId) {
2594
- throw new HavenApiError(
2595
- "MPP resume request does not match the approved network.",
2596
- 409,
2597
- { status, challenge },
2598
- status.paymentId
2599
- );
2600
- }
2601
- if (status.token && status.token !== challenge.asset.symbol) {
2602
- throw new HavenApiError(
2603
- "MPP resume request does not match the approved token.",
2604
- 409,
2605
- { status, challenge },
2606
- status.paymentId
2607
- );
2608
- }
2609
- const approvedAmount = status.amount ? normalizeDecimal(status.amount) : "";
2610
- const requestedAmount = normalizeDecimal(challenge.amount.display);
2611
- if (approvedAmount && approvedAmount !== requestedAmount) {
2612
- throw new HavenApiError(
2613
- "MPP resume request does not match the approved amount.",
2614
- 409,
2615
- { status, challenge },
2616
- status.paymentId
2617
- );
2618
- }
2619
- }
2620
2296
  mapX402ReceiptFromAuthorization(paymentRequired, option, paymentHeader, raw, execResult) {
2621
2297
  const txHash = execResult?.tx_hash ?? raw.tx_hash ?? "";
2622
2298
  const chainId = execResult?.chain_id ?? raw.chain_id ?? chainIdFromNetwork(option.network);
@@ -2723,53 +2399,6 @@ var HavenClient = class {
2723
2399
  this.x402ReceiptCache.set(idempotencyKey, { expiresAt, receipt });
2724
2400
  }
2725
2401
  }
2726
- mapMachinePaymentReceipt(challenge, raw, txHash, execResult) {
2727
- const receiptWithoutHeader = {
2728
- success: true,
2729
- rail: challenge.rail,
2730
- paymentId: raw.payment_id,
2731
- challengeId: challenge.challengeId,
2732
- txHash,
2733
- token: execResult?.token ?? raw.token ?? challenge.asset.symbol,
2734
- amount: execResult?.amount ?? raw.amount ?? challenge.amount.display,
2735
- to: execResult?.to ?? raw.to ?? challenge.recipient,
2736
- resourceUrl: raw.resource_url ?? challenge.resource,
2737
- explorerUrl: execResult?.explorer_url ?? raw.explorer_url ?? buildExplorerUrl(execResult?.chain_id ?? raw.chain_id ?? challenge.network.chainId, txHash),
2738
- payer: raw.payer ?? raw.safe_address,
2739
- chainId: execResult?.chain_id ?? raw.chain_id ?? challenge.network.chainId
2740
- };
2741
- return {
2742
- ...receiptWithoutHeader,
2743
- proofHeader: encodeMachinePaymentProof(receiptWithoutHeader)
2744
- };
2745
- }
2746
- mapMachinePaymentReceiptFromStatus(challenge, status) {
2747
- if (!status.txHash) {
2748
- throw new HavenApiError(
2749
- `MPP payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
2750
- 502,
2751
- status,
2752
- status.paymentId
2753
- );
2754
- }
2755
- const receiptWithoutHeader = {
2756
- success: true,
2757
- rail: challenge.rail,
2758
- paymentId: status.paymentId,
2759
- challengeId: challenge.challengeId,
2760
- txHash: status.txHash,
2761
- token: status.token || challenge.asset.symbol,
2762
- amount: status.amount || challenge.amount.display,
2763
- to: status.merchantAddress ?? challenge.recipient,
2764
- resourceUrl: status.resourceUrl ?? challenge.resource,
2765
- explorerUrl: explorerUrlOrEmpty(status.chainId || challenge.network.chainId, status.txHash),
2766
- chainId: status.chainId || challenge.network.chainId
2767
- };
2768
- return {
2769
- ...receiptWithoutHeader,
2770
- proofHeader: encodeMachinePaymentProof(receiptWithoutHeader)
2771
- };
2772
- }
2773
2402
  async recordMerchantRetryRejected(input) {
2774
2403
  try {
2775
2404
  await this.post("/machine-payments/reconciliation-events", {
@@ -3012,63 +2641,18 @@ var HavenClient = class {
3012
2641
  merchantAddress: input.accepted.payTo
3013
2642
  };
3014
2643
  }
3015
- buildMppQuote(challenge, request, idempotencyKey) {
3016
- return {
3017
- rail: "mpp",
3018
- paymentRail: challenge.rail,
3019
- idempotencyKey: idempotencyKey ?? buildMachinePaymentIdempotencyKey(challenge),
3020
- challenge,
3021
- request,
3022
- resourceUrl: challenge.resource,
3023
- description: challenge.description ?? null,
3024
- amountAtomic: challenge.amount.atomic,
3025
- amount: challenge.amount.display,
3026
- token: challenge.asset.symbol,
3027
- asset: challenge.asset.address,
3028
- network: challenge.network.name,
3029
- chainId: challenge.network.chainId,
3030
- merchantAddress: challenge.recipient,
3031
- expiresAt: challenge.expiresAt
3032
- };
3033
- }
3034
- buildMppResumeState(input) {
3035
- const quote = this.buildMppQuote(
3036
- input.challenge,
3037
- input.request ?? this.snapshotX402Request(input.challenge.resource),
3038
- input.idempotencyKey
3039
- );
3040
- return {
3041
- rail: "mpp",
3042
- paymentRail: quote.paymentRail,
3043
- paymentId: input.paymentId,
3044
- idempotencyKey: quote.idempotencyKey,
3045
- challenge: input.challenge,
3046
- url: input.request?.url ?? input.challenge.resource,
3047
- request: input.request,
3048
- resourceUrl: quote.resourceUrl,
3049
- description: quote.description,
3050
- amountAtomic: quote.amountAtomic,
3051
- amount: quote.amount,
3052
- token: quote.token,
3053
- asset: quote.asset,
3054
- network: quote.network,
3055
- chainId: quote.chainId,
3056
- merchantAddress: quote.merchantAddress,
3057
- expiresAt: quote.expiresAt
3058
- };
3059
- }
2644
+ // #1328: attachResumeState's 'mpp' branch (buildMppQuote / buildMppResumeState
2645
+ // / attachMppResumeState) is retired along with the rest of the MPP-demo
2646
+ // client surface — every remaining caller passes rail: 'x402' only, so this
2647
+ // is now a direct alias for attachX402ResumeState rather than a dispatcher.
3060
2648
  attachResumeState(err, input) {
3061
- if (input.rail === "x402") {
3062
- this.attachX402ResumeState(
3063
- err,
3064
- input.paymentRequired,
3065
- input.accepted,
3066
- input.idempotencyKey,
3067
- input.request
3068
- );
3069
- return;
3070
- }
3071
- this.attachMppResumeState(err, input.challenge, input.idempotencyKey, input.request);
2649
+ this.attachX402ResumeState(
2650
+ err,
2651
+ input.paymentRequired,
2652
+ input.accepted,
2653
+ input.idempotencyKey,
2654
+ input.request
2655
+ );
3072
2656
  }
3073
2657
  attachX402ResumeState(err, paymentRequired, accepted, idempotencyKey, request) {
3074
2658
  if (!(err instanceof HavenPaymentStateError)) return;
@@ -3081,16 +2665,6 @@ var HavenClient = class {
3081
2665
  request
3082
2666
  });
3083
2667
  }
3084
- attachMppResumeState(err, challenge, idempotencyKey, request) {
3085
- if (!(err instanceof HavenPaymentStateError)) return;
3086
- if (!isMppRail(err.state.rail)) return;
3087
- err.resumeState = this.buildMppResumeState({
3088
- paymentId: err.state.paymentId,
3089
- challenge,
3090
- idempotencyKey,
3091
- request
3092
- });
3093
- }
3094
2668
  // ── Tool Execution (for agent frameworks) ────────────────────────
3095
2669
  /**
3096
2670
  * Execute a tool call by name and input.
@@ -3149,29 +2723,6 @@ var HavenClient = class {
3149
2723
  return this.toolError(err);
3150
2724
  }
3151
2725
  }
3152
- if (toolName === "authorize_machine_payment") {
3153
- const { challenge, idempotencyKey } = input;
3154
- try {
3155
- const receipt = await this.authorizeMachinePayment(challenge, { idempotencyKey });
3156
- return {
3157
- success: true,
3158
- payment_id: receipt.paymentId,
3159
- tx_hash: receipt.txHash,
3160
- token: receipt.token,
3161
- amount: receipt.amount,
3162
- to: receipt.to,
3163
- resource_url: receipt.resourceUrl,
3164
- explorer_url: receipt.explorerUrl,
3165
- proof_header: receipt.proofHeader,
3166
- rail: receipt.rail,
3167
- challenge_id: receipt.challengeId,
3168
- payer: receipt.payer,
3169
- chain_id: receipt.chainId
3170
- };
3171
- } catch (err) {
3172
- return this.toolError(err);
3173
- }
3174
- }
3175
2726
  if (toolName === "get_payment_status") {
3176
2727
  const { payment_id } = input;
3177
2728
  const result = await this.getPaymentStatus(payment_id);
@@ -3519,7 +3070,7 @@ var toolDescriptions = {
3519
3070
  payX402OneShot: {
3520
3071
  summary: "Fetch an x402 paid HTTP resource in a single call. Handles the full probe -> pay -> retry round trip and returns the merchant response.",
3521
3072
  selectionGuidance: "Prefer this over the quote+pay split when the agent just wants the paid resource and does not need to inspect the price first. If you already have a quote from haven_quote_x402, use haven_pay_x402_quote instead. Do not use for read-only allowance, budget, spend-limit, remaining-amount, reset-period, or what-can-I-spend questions; use the allowance lookup tool instead.",
3522
- behavior: "Calls the URL, parses any HTTP 402 x402 challenge, signs the EIP-3009 payment from the delegate wallet, asks Haven for a Safe AllowanceModule top-up if needed, then retries the original request with the X-PAYMENT header and returns the merchant response. If the resource returns an MPP machine-payment challenge instead of standard x402, the MPP payment path is used automatically. If the resource returns a non-402 status, returns it unchanged without contacting Haven.",
3073
+ behavior: "Calls the URL, parses any HTTP 402 x402 challenge, signs the EIP-3009 payment from the delegate wallet, asks Haven for a Safe AllowanceModule top-up if needed, then retries the original request with the X-PAYMENT header and returns the merchant response. If the resource returns a non-402 status, returns it unchanged without contacting Haven.",
3523
3074
  nextActionGuidance: "If approval is needed, preserve the returned resume_state or paymentId and call the resume tool once nextAction=retry_original_x402_request. If the response carries phase=insufficient_funds and nextAction=fund_safe_or_raise_allowance, the payment cannot be retried until the originating Safe is funded or the agent allowance raised \u2014 stop and tell the user the shortfall reported on the response."
3524
3075
  },
3525
3076
  resumeX402: {
@@ -3527,29 +3078,17 @@ var toolDescriptions = {
3527
3078
  behavior: "Accepts either resume_state or payment_id, validates the original x402 details against the approved Haven funding, and retries the merchant request with the X-PAYMENT header. No new Haven approval is created.",
3528
3079
  nextActionGuidance: "Only use when get_payment_status returns nextAction=retry_original_x402_request; do not start a new merchant session."
3529
3080
  },
3530
- quoteMpp: {
3531
- summary: "Inspect a Haven MPP challenge or paid MPP URL without creating a Haven payment, signature, approval, or on-chain transaction.",
3532
- behavior: "Parses an MPP challenge envelope and returns a typed quote with rail tag, amount, asset, and merchant context. Pure read-only \u2014 Haven is not contacted.",
3533
- nextActionGuidance: "On success the returned quote is the input to haven_pay_mpp_challenge. Do not call the merchant again \u2014 Haven re-uses the captured request when paying."
3534
- },
3535
- payMpp: {
3536
- summary: "Pay an inspected MPP challenge. The delegate key signs locally; Haven only validates and relays signed, on-chain-constrained payment transactions.",
3537
- selectionGuidance: "Do not use this for read-only allowance, budget, spend-limit, remaining-amount, reset-period, or what-can-I-spend questions; use the allowance lookup tool instead.",
3538
- behavior: "Authorizes the payment through Haven within the on-chain allowance, signs the challenge proof, and returns the proof header for retrying the original paid resource.",
3539
- nextActionGuidance: "If approval is needed, preserve resume_state or payment_id and wait for nextAction=retry_original_x402_request before resuming."
3540
- },
3541
- resumeMpp: {
3542
- summary: "Resume an MPP payment after the Haven wallet owner approved the funding step.",
3543
- behavior: "Accepts either resume_state or payment_id and retries the original paid resource with the MPP proof header. No new Haven approval is created.",
3544
- nextActionGuidance: ""
3545
- },
3081
+ // #1328: quoteMpp / payMpp / resumeMpp (the mpp_demo challenge/quote/resume
3082
+ // fragments) are retired along with the client surface they described
3083
+ // MACHINE-PAYMENT-CHALLENGE was never produced by anything besides the now
3084
+ // deleted `/demo/mpp/*` route. Use the x402 fragments above instead.
3546
3085
  getPaymentStatus: {
3547
3086
  summary: "Fetch structured Haven payment status, including phase and nextAction taxonomy for agent recovery.",
3548
3087
  behavior: "Accepts a payment intent or approval request id and returns the full state taxonomy (phase, nextAction, rail, amount, merchant, resource url, idempotency key, message).",
3549
3088
  nextActionGuidance: ""
3550
3089
  },
3551
3090
  getResumeState: {
3552
- summary: "Rehydrate stored x402 or MPP resume_state by payment_id.",
3091
+ summary: "Rehydrate stored x402 resume_state by payment_id.",
3553
3092
  behavior: "Returns the context that the agent originally received in a pending-approval response, reconstructed from Haven's database. This is context only; signing still happens locally when a resume tool is called.",
3554
3093
  nextActionGuidance: ""
3555
3094
  },
@@ -3591,13 +3130,13 @@ var toolDescriptions = {
3591
3130
  },
3592
3131
  sweep_delegate: {
3593
3132
  summary: "Sweep stranded USDC and/or ETH from the delegate wallet back to the originating Safe.",
3594
- selectionGuidance: "Use this when the user instructs you to recover stranded funds on the delegate wallet, or when a payment status returns nextAction=sweep_stranded_funds. Do NOT use for normal payments \u2014 use haven_pay_x402 or haven_pay_mpp_challenge. Do NOT use to read balances only \u2014 use haven_get_allowances.",
3133
+ selectionGuidance: "Use this when the user instructs you to recover stranded funds on the delegate wallet, or when a payment status returns nextAction=sweep_stranded_funds. Do NOT use for normal payments \u2014 use haven_pay_x402. Do NOT use to read balances only \u2014 use haven_get_allowances.",
3595
3134
  behavior: "Reads the delegate EOA's on-chain USDC and ETH balances. For each non-zero balance, signs and submits a transfer from the delegate EOA to the originating Safe (hardcoded destination). The delegate key signs locally \u2014 Haven never sees it and the backend never constructs signed transactions (CASP/MiCA Red Line #2). Returns tx hashes and recovered amounts. Returns an empty transfers list when nothing is stranded.",
3596
3135
  nextActionGuidance: "If transfers is non-empty, confirm the amounts with the user. No further action required \u2014 funds are on their way back to the Safe."
3597
3136
  },
3598
3137
  send: {
3599
3138
  summary: "Send ETH or USDC directly from the agent's Haven wallet to a recipient address.",
3600
- selectionGuidance: "Use this for plain transfers \u2014 refunding a user, paying a freelancer, topping up a co-agent's wallet, or moving funds between addresses. Do NOT use for x402 paid endpoints (use haven_pay_x402 instead) or MPP merchant payments (use haven_pay_mpp_challenge). Do NOT use for read-only allowance, budget, or what-can-I-spend questions \u2014 use haven_get_allowances.",
3139
+ selectionGuidance: "Use this for plain transfers \u2014 refunding a user, paying a freelancer, topping up a co-agent's wallet, or moving funds between addresses. Do NOT use for x402 paid endpoints \u2014 use haven_pay_x402 instead. Do NOT use for read-only allowance, budget, or what-can-I-spend questions \u2014 use haven_get_allowances.",
3601
3140
  behavior: "Sends the requested amount through the Safe AllowanceModule. Amounts within the remaining on-chain allowance for the asset execute automatically; amounts that exceed the allowance are queued as pending_approval for the wallet owner to approve in Haven. The agent's signing key signs the AllowanceModule transfer hash; Haven never receives the key.",
3602
3141
  nextActionGuidance: "If pending_approval is returned, preserve the payment_id and wait for the wallet owner to approve in Haven. Poll haven_get_payment_status until nextAction=none."
3603
3142
  }
@@ -3713,22 +3252,11 @@ var resumeX402Schema = {
3713
3252
  },
3714
3253
  required: ["payment_id", "url", "payTo", "amount", "asset", "network"]
3715
3254
  };
3716
- var authorizeMachinePaymentSchema = {
3717
- type: "object",
3718
- properties: {
3719
- challenge: {
3720
- type: "object",
3721
- description: "Machine payment challenge returned by a Haven demo endpoint"
3722
- }
3723
- },
3724
- required: ["challenge"]
3725
- };
3726
3255
  var MAKE_PAYMENT_DESCRIPTION = "Request and sign a payment from the user-controlled Safe within approved on-chain limits. For read-only allowance, budget, spend-limit, remaining-amount, or reset-period questions, use get_allowances instead of making a payment. Haven authenticates the agent, validates the signed intent, and relays the Safe AllowanceModule transaction; it does not hold keys or control funds. Gnosis Chain tokens: EURe, USDC.e, xDAI. Base tokens: USDC, ETH.";
3727
3256
  var GET_STATUS_DESCRIPTION = toolDescriptions.getPaymentStatus.summary + " Accepts payment intent IDs and approval request IDs. Returns the current status, phase, next_action, transaction hash if available, and payment details.";
3728
3257
  var GET_ALLOWANCES_DESCRIPTION = composeDescription(toolDescriptions.getAllowances);
3729
3258
  var AUTHORIZE_X402_DESCRIPTION = composeDescription(toolDescriptions.payX402) + " In this SDK tool set, the allowance lookup tool is get_allowances. When a paid API returns x402 payment requirements, use this tool to sign with the agent-owned delegate key and request a policy-limited Safe AllowanceModule top-up when needed. Haven relays signed transactions only; the agent key authorizes payment and on-chain limits enforce spend. If this returns pending_approval, tell the user it is waiting in Haven, preserve the original merchant/MCP session and x402 details, call get_payment_status later, and use resume_x402_payment only when next_action is retry_original_x402_request. Do not start a new merchant session or loop retries while approval is pending. Use the returned payment_header as the X-PAYMENT header on the retry request when doing a manual HTTP retry.";
3730
3259
  var RESUME_X402_DESCRIPTION = toolDescriptions.resumeX402.summary + " Use this only after get_payment_status returns next_action=retry_original_x402_request. It checks the approved payment, validates the original x402 details, and returns a merchant X-PAYMENT header without creating a new approval request or merchant session.";
3731
- var AUTHORIZE_MACHINE_PAYMENT_DESCRIPTION = composeDescription(toolDescriptions.payMpp) + " In this SDK tool set, the allowance lookup tool is get_allowances. Currently scoped to the internal MPP demo rail. The agent signs the payment, Haven relays it within the on-chain allowance, and the tool returns a proof header for the retry request.";
3732
3260
  var SWEEP_DELEGATE_DESCRIPTION = composeDescription(toolDescriptions.sweep_delegate);
3733
3261
  var sweepDelegateSchema = {
3734
3262
  type: "object",
@@ -3762,11 +3290,6 @@ function claudeTools() {
3762
3290
  description: RESUME_X402_DESCRIPTION,
3763
3291
  input_schema: resumeX402Schema
3764
3292
  },
3765
- {
3766
- name: "authorize_machine_payment",
3767
- description: AUTHORIZE_MACHINE_PAYMENT_DESCRIPTION,
3768
- input_schema: authorizeMachinePaymentSchema
3769
- },
3770
3293
  {
3771
3294
  name: "haven_sweep_delegate",
3772
3295
  description: SWEEP_DELEGATE_DESCRIPTION,
@@ -3816,14 +3339,6 @@ function openaiTools() {
3816
3339
  parameters: resumeX402Schema
3817
3340
  }
3818
3341
  },
3819
- {
3820
- type: "function",
3821
- function: {
3822
- name: "authorize_machine_payment",
3823
- description: AUTHORIZE_MACHINE_PAYMENT_DESCRIPTION,
3824
- parameters: authorizeMachinePaymentSchema
3825
- }
3826
- },
3827
3342
  {
3828
3343
  type: "function",
3829
3344
  function: {
@@ -4258,7 +3773,6 @@ exports.X402UnexpectedStatusError = X402UnexpectedStatusError;
4258
3773
  exports.X402_MAX_AUTHORIZATION_WINDOW_SECONDS = X402_MAX_AUTHORIZATION_WINDOW_SECONDS;
4259
3774
  exports.X402_SETTLEMENT_FORWARD_MARGIN_SECONDS = X402_SETTLEMENT_FORWARD_MARGIN_SECONDS;
4260
3775
  exports.addressFromKey = addressFromKey;
4261
- exports.buildMachinePaymentIdempotencyKey = buildMachinePaymentIdempotencyKey;
4262
3776
  exports.buildSweepAuthorizationMessage = buildSweepAuthorizationMessage;
4263
3777
  exports.buildSweepTypedData = buildSweepTypedData;
4264
3778
  exports.buildX402ExpectedMessage = buildX402ExpectedMessage;
@@ -4269,13 +3783,10 @@ exports.decodeBase64Utf8 = decodeBase64Utf8;
4269
3783
  exports.discoverMerchantMcpUrl = discoverMerchantMcpUrl;
4270
3784
  exports.encodeBase64Json = encodeBase64Json;
4271
3785
  exports.encodeBase64Utf8 = encodeBase64Utf8;
4272
- exports.encodeMachinePaymentProof = encodeMachinePaymentProof;
4273
3786
  exports.encodePaymentProof = encodePaymentProof;
4274
3787
  exports.havenTools = havenTools;
4275
3788
  exports.isSupportedNodeVersion = isSupportedNodeVersion;
4276
3789
  exports.isSweepableChain = isSweepableChain;
4277
- exports.parseMachinePaymentChallenge = parseMachinePaymentChallenge;
4278
- exports.parseMachinePaymentChallengeResponse = parseMachinePaymentChallengeResponse;
4279
3790
  exports.parsePaymentRequired = parsePaymentRequired;
4280
3791
  exports.parsePaymentRequiredResponse = parsePaymentRequiredResponse;
4281
3792
  exports.resolveTokenFromAddress = resolveTokenFromAddress;