@haven_ai/sdk 0.1.23-alpha.2 → 0.1.25-alpha.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.cjs CHANGED
@@ -344,7 +344,7 @@ function signHash(privateKey, hash) {
344
344
  );
345
345
  }
346
346
  }
347
- async function signUserOpTypedDataForDelegation(privateKey, typedData) {
347
+ async function signTypedDataVerbatim(privateKey, typedData, label) {
348
348
  try {
349
349
  const wallet = new ethers.ethers.Wallet(privateKey);
350
350
  const types = { ...typedData.types };
@@ -356,10 +356,16 @@ async function signUserOpTypedDataForDelegation(privateKey, typedData) {
356
356
  );
357
357
  } catch (err) {
358
358
  throw new HavenSigningError(
359
- `Failed to sign delegation UserOperation: ${err instanceof Error ? err.message : String(err)}`
359
+ `Failed to sign ${label}: ${err instanceof Error ? err.message : String(err)}`
360
360
  );
361
361
  }
362
362
  }
363
+ async function signUserOpTypedDataForDelegation(privateKey, typedData) {
364
+ return signTypedDataVerbatim(privateKey, typedData, "delegation UserOperation");
365
+ }
366
+ async function signSettlementDelegationTypedData(privateKey, typedData) {
367
+ return signTypedDataVerbatim(privateKey, typedData, "x402 settlement delegation");
368
+ }
363
369
  function addressFromKey(privateKey) {
364
370
  try {
365
371
  return new ethers.ethers.Wallet(privateKey).address;
@@ -437,12 +443,128 @@ function decodeBase64Json(value, label) {
437
443
  }
438
444
  }
439
445
 
446
+ // src/sweep.ts
447
+ var SWEEP_BASE_CHAIN_ID = 8453;
448
+ var SWEEP_BASE_SEPOLIA_CHAIN_ID = 84532;
449
+ var SWEEP_BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
450
+ var SWEEP_BASE_SEPOLIA_USDC_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
451
+ var USDC_EIP712_DOMAIN_BY_CHAIN = {
452
+ [SWEEP_BASE_CHAIN_ID]: {
453
+ name: "USD Coin",
454
+ version: "2",
455
+ chainId: SWEEP_BASE_CHAIN_ID,
456
+ verifyingContract: SWEEP_BASE_USDC_ADDRESS
457
+ },
458
+ [SWEEP_BASE_SEPOLIA_CHAIN_ID]: {
459
+ name: "USDC",
460
+ version: "2",
461
+ chainId: SWEEP_BASE_SEPOLIA_CHAIN_ID,
462
+ verifyingContract: SWEEP_BASE_SEPOLIA_USDC_ADDRESS
463
+ }
464
+ };
465
+ var USDC_ADDRESS_BY_CHAIN = {
466
+ [SWEEP_BASE_CHAIN_ID]: SWEEP_BASE_USDC_ADDRESS,
467
+ [SWEEP_BASE_SEPOLIA_CHAIN_ID]: SWEEP_BASE_SEPOLIA_USDC_ADDRESS
468
+ };
469
+ var SWEEPABLE_CHAIN_IDS = Object.keys(USDC_ADDRESS_BY_CHAIN).map(Number);
470
+ function isSweepableChain(chainId) {
471
+ return chainId in USDC_ADDRESS_BY_CHAIN;
472
+ }
473
+ var TRANSFER_WITH_AUTHORIZATION_TYPES = {
474
+ TransferWithAuthorization: [
475
+ { name: "from", type: "address" },
476
+ { name: "to", type: "address" },
477
+ { name: "value", type: "uint256" },
478
+ { name: "validAfter", type: "uint256" },
479
+ { name: "validBefore", type: "uint256" },
480
+ { name: "nonce", type: "bytes32" }
481
+ ]
482
+ };
483
+ function sweepUsdcAddress(chainId) {
484
+ const address = USDC_ADDRESS_BY_CHAIN[chainId];
485
+ if (!address) {
486
+ throw new HavenSigningError(
487
+ `Sweep is not supported on chain ${chainId}. Supported: ${SWEEPABLE_CHAIN_IDS.join(", ")}.`
488
+ );
489
+ }
490
+ return address;
491
+ }
492
+ function sweepUsdcDomain(chainId) {
493
+ const domain = USDC_EIP712_DOMAIN_BY_CHAIN[chainId];
494
+ if (!domain) {
495
+ throw new HavenSigningError(
496
+ `Sweep is not supported on chain ${chainId}. Supported: ${SWEEPABLE_CHAIN_IDS.join(", ")}.`
497
+ );
498
+ }
499
+ return domain;
500
+ }
501
+ function sameAddress(a, b) {
502
+ return a.toLowerCase() === b.toLowerCase();
503
+ }
504
+ function buildSweepTypedData(auth) {
505
+ const domain = sweepUsdcDomain(auth.chainId);
506
+ const expectedToken = sweepUsdcAddress(auth.chainId);
507
+ if (!sameAddress(auth.token, expectedToken)) {
508
+ throw new HavenSigningError(
509
+ `Sweep token ${auth.token} is not the canonical USDC contract for chain ${auth.chainId}.`
510
+ );
511
+ }
512
+ if (!/^0x[0-9a-fA-F]{64}$/.test(auth.nonce)) {
513
+ throw new HavenSigningError("Sweep nonce must be a 0x-prefixed 32-byte hex string.");
514
+ }
515
+ return {
516
+ domain,
517
+ types: TRANSFER_WITH_AUTHORIZATION_TYPES,
518
+ primaryType: "TransferWithAuthorization",
519
+ message: {
520
+ from: auth.from,
521
+ to: auth.to,
522
+ value: BigInt(auth.value),
523
+ validAfter: BigInt(auth.validAfter),
524
+ validBefore: BigInt(auth.validBefore),
525
+ nonce: auth.nonce
526
+ }
527
+ };
528
+ }
529
+ function buildSweepAuthorizationMessage(auth) {
530
+ return `Haven sweep authorization v1
531
+ ${stableStringify({
532
+ version: 1,
533
+ kind: "haven.sweep.authorization",
534
+ from: auth.from.toLowerCase(),
535
+ to: auth.to.toLowerCase(),
536
+ value: auth.value,
537
+ validAfter: auth.validAfter,
538
+ validBefore: auth.validBefore,
539
+ nonce: auth.nonce.toLowerCase(),
540
+ token: auth.token.toLowerCase(),
541
+ chainId: auth.chainId
542
+ })}`;
543
+ }
544
+ function stableStringify(value) {
545
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
546
+ if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(",")}]`;
547
+ const object = value;
548
+ return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(object[key])}`).join(",")}}`;
549
+ }
550
+
440
551
  // src/x402.ts
441
552
  var BASE_USDC_ADDRESS = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
442
553
  var BASE_SEPOLIA_USDC_ADDRESS = "0x036cbd53842c5426634e7929541ec2318f3dcf7e";
443
554
  var STANDARD_X402_USDC_ADDRESSES = /* @__PURE__ */ new Set([BASE_USDC_ADDRESS, BASE_SEPOLIA_USDC_ADDRESS]);
444
555
  var X402_IDEMPOTENCY_BUCKET_MS = 3e5;
445
556
  var DECIMAL_ATOMIC_AMOUNT_RE = /^[0-9]+$/;
557
+ var X402_PAYMENT_HEADER_MAX_LENGTH = 65536;
558
+ var BASE64_RE = /^[A-Za-z0-9+/]*={0,2}$/;
559
+ var ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
560
+ var SIGNATURE_RE = /^0x[0-9a-fA-F]{130}$/;
561
+ var NONCE_RE = /^0x[0-9a-fA-F]{64}$/;
562
+ var X402PaymentHeaderValidationError = class extends Error {
563
+ constructor() {
564
+ super("Invalid X-PAYMENT header.");
565
+ this.name = "X402PaymentHeaderValidationError";
566
+ }
567
+ };
446
568
  function isPositiveDecimalAtomicAmount(value) {
447
569
  return DECIMAL_ATOMIC_AMOUNT_RE.test(value) && BigInt(value) > 0n;
448
570
  }
@@ -485,7 +607,7 @@ function normalizePaymentRequired(value) {
485
607
  if (!candidate || typeof candidate !== "object" || typeof candidate.x402Version !== "number" || !Array.isArray(candidate.accepts)) {
486
608
  return null;
487
609
  }
488
- const accepts = candidate.accepts.map((option) => normalizePaymentOption(option)).filter((option) => !!option);
610
+ const accepts = candidate.accepts.map((option) => normalizePaymentOption(option)).filter((option) => !!option && typeof option === "object");
489
611
  if (accepts.length === 0) return null;
490
612
  const first = accepts[0];
491
613
  const resourceUrl = candidate.resource?.url ?? first.resource;
@@ -590,13 +712,52 @@ function selectPaymentOption(accepts) {
590
712
  }
591
713
  return null;
592
714
  }
715
+ var ERC7710_ASSET_TRANSFER_METHOD = "erc7710";
716
+ function x402AssetTransferMethod(option) {
717
+ const raw = option.extra?.assetTransferMethod;
718
+ return typeof raw === "string" ? raw : null;
719
+ }
720
+ function isErc7710Option(option) {
721
+ return x402AssetTransferMethod(option) === ERC7710_ASSET_TRANSFER_METHOD;
722
+ }
723
+ function x402FacilitatorAddresses(option) {
724
+ const raw = option.extra?.facilitatorAddresses;
725
+ if (!Array.isArray(raw)) return null;
726
+ const addresses = raw.filter((a) => typeof a === "string" && ADDRESS_RE.test(a));
727
+ return addresses.length > 0 ? addresses : null;
728
+ }
729
+ function isPayableStandardOption(opt) {
730
+ return opt.scheme === "exact" && opt.network in STANDARD_X402_NETWORKS && STANDARD_X402_USDC_ADDRESSES.has(opt.asset.toLowerCase()) && isPositiveDecimalAtomicAmount(optionAuthorizationAmount(opt));
731
+ }
593
732
  function selectStandardPaymentOption(accepts) {
594
733
  if (!accepts || accepts.length === 0) return null;
595
734
  for (const opt of accepts) {
596
- if (opt.scheme === "exact" && opt.network in STANDARD_X402_NETWORKS && STANDARD_X402_USDC_ADDRESSES.has(opt.asset.toLowerCase()) && isPositiveDecimalAtomicAmount(optionAuthorizationAmount(opt))) {
597
- return opt;
735
+ if (opt === null || typeof opt !== "object") continue;
736
+ if (!isErc7710Option(opt) && isPayableStandardOption(opt)) return opt;
737
+ }
738
+ return null;
739
+ }
740
+ function selectErc7710PaymentOption(accepts) {
741
+ if (!accepts || accepts.length === 0) return null;
742
+ for (const opt of accepts) {
743
+ if (opt === null || typeof opt !== "object") continue;
744
+ if (isErc7710Option(opt) && isPayableStandardOption(opt)) return opt;
745
+ }
746
+ return null;
747
+ }
748
+ function selectX402SettlementScheme(accepts, opts) {
749
+ if (opts.delegationRail) {
750
+ const preferred = selectErc7710PaymentOption(accepts);
751
+ if (preferred) {
752
+ return {
753
+ scheme: "erc7710",
754
+ option: preferred,
755
+ facilitatorAddresses: x402FacilitatorAddresses(preferred)
756
+ };
598
757
  }
599
758
  }
759
+ const fallback = selectStandardPaymentOption(accepts);
760
+ if (fallback) return { scheme: "eip3009", option: fallback, facilitatorAddresses: null };
600
761
  return null;
601
762
  }
602
763
  function x402AuthorizationAmount(option) {
@@ -626,7 +787,7 @@ function buildX402ExpectedMessage(context) {
626
787
  payload.typedDataHash = context.typedDataHash.toLowerCase();
627
788
  }
628
789
  return `Haven x402 expected context v${version}
629
- ${stableStringify(payload)}`;
790
+ ${stableStringify2(payload)}`;
630
791
  }
631
792
  function toStandardPaymentRequirements(paymentRequired, option) {
632
793
  const network = STANDARD_X402_NETWORKS[option.network];
@@ -657,6 +818,89 @@ function toStandardPaymentRequirements(paymentRequired, option) {
657
818
  extra: option.extra
658
819
  };
659
820
  }
821
+ async function validateStandardX402PaymentHeader(paymentHeader, context) {
822
+ try {
823
+ if (typeof paymentHeader !== "string" || paymentHeader.length === 0 || paymentHeader.length > X402_PAYMENT_HEADER_MAX_LENGTH || paymentHeader.length % 4 !== 0 || !BASE64_RE.test(paymentHeader)) {
824
+ throw new Error("wire");
825
+ }
826
+ const decoded = decodeBase64Json(paymentHeader);
827
+ if (!decoded || typeof decoded !== "object" || Array.isArray(decoded)) throw new Error("shape");
828
+ const version = decoded.x402Version;
829
+ const payload = decoded.payload;
830
+ if (version !== 1 && version !== 2 || !payload || typeof payload !== "object" || Array.isArray(payload)) {
831
+ throw new Error("shape");
832
+ }
833
+ if (version === 1) {
834
+ if (!hasOnlyKeys(decoded, ["x402Version", "scheme", "network", "payload"])) throw new Error("shape");
835
+ if (decoded.scheme !== "exact" || decoded.network !== standardX402WireNetwork(context.network)) {
836
+ throw new Error("context");
837
+ }
838
+ } else {
839
+ if (!hasOnlyKeys(decoded, ["x402Version", "accepted", "payload"])) throw new Error("shape");
840
+ const accepted = selectStandardPaymentOption([decoded.accepted]);
841
+ if (!accepted || !matchesHeaderContext(accepted, context)) throw new Error("context");
842
+ }
843
+ const record = payload;
844
+ if (!hasOnlyKeys(record, ["signature", "authorization"])) throw new Error("shape");
845
+ if (typeof record.signature !== "string" || !SIGNATURE_RE.test(record.signature)) throw new Error("shape");
846
+ const authorization = record.authorization;
847
+ if (!authorization || typeof authorization !== "object" || Array.isArray(authorization)) throw new Error("shape");
848
+ const auth = authorization;
849
+ if (!hasOnlyKeys(auth, ["from", "to", "value", "validAfter", "validBefore", "nonce"])) throw new Error("shape");
850
+ if (typeof auth.from !== "string" || !ADDRESS_RE.test(auth.from) || typeof auth.to !== "string" || !ADDRESS_RE.test(auth.to) || typeof auth.value !== "string" || !isPositiveDecimalAtomicAmount(auth.value) || typeof auth.validAfter !== "string" || !DECIMAL_ATOMIC_AMOUNT_RE.test(auth.validAfter) || typeof auth.validBefore !== "string" || !DECIMAL_ATOMIC_AMOUNT_RE.test(auth.validBefore) || typeof auth.nonce !== "string" || !NONCE_RE.test(auth.nonce)) {
851
+ throw new Error("shape");
852
+ }
853
+ if (!sameAddress2(auth.from, context.payer) || !sameAddress2(auth.to, context.merchantTo) || auth.value !== context.amountAtomic) {
854
+ throw new Error("context");
855
+ }
856
+ const validAfter = BigInt(auth.validAfter);
857
+ const validBefore = BigInt(auth.validBefore);
858
+ const now = BigInt(Math.floor(Date.now() / 1e3));
859
+ if (validBefore <= now || validAfter > validBefore) throw new Error("expired");
860
+ const typedData = buildSweepTypedData({
861
+ from: auth.from,
862
+ to: auth.to,
863
+ value: auth.value,
864
+ validAfter: auth.validAfter,
865
+ validBefore: auth.validBefore,
866
+ nonce: auth.nonce,
867
+ token: context.asset,
868
+ chainId: context.chainId
869
+ });
870
+ const recovered = await viem.recoverTypedDataAddress({
871
+ ...typedData,
872
+ // `buildSweepTypedData` keeps the public domain framework-neutral;
873
+ // viem brands contract addresses at this crypto call boundary only.
874
+ domain: {
875
+ ...typedData.domain,
876
+ verifyingContract: typedData.domain.verifyingContract
877
+ },
878
+ message: {
879
+ ...typedData.message,
880
+ from: typedData.message.from,
881
+ to: typedData.message.to,
882
+ nonce: typedData.message.nonce
883
+ },
884
+ signature: record.signature
885
+ });
886
+ if (!sameAddress2(recovered, context.payer)) throw new Error("recovery");
887
+ } catch {
888
+ throw new X402PaymentHeaderValidationError();
889
+ }
890
+ }
891
+ function hasOnlyKeys(value, allowed) {
892
+ return Object.keys(value).every((key) => allowed.includes(key)) && allowed.every((key) => key in value);
893
+ }
894
+ function sameAddress2(left, right) {
895
+ return left.toLowerCase() === right.toLowerCase();
896
+ }
897
+ function standardX402WireNetwork(network) {
898
+ return STANDARD_X402_NETWORKS[network] ?? null;
899
+ }
900
+ function matchesHeaderContext(option, context) {
901
+ if (option.scheme !== "exact" || !sameAddress2(option.payTo, context.merchantTo) || !sameAddress2(option.asset, context.asset) || option.network !== context.network || x402AuthorizationAmount(option) !== context.amountAtomic) return false;
902
+ return option.resource === void 0 || option.resource === context.resourceUrl;
903
+ }
660
904
  function buildX402IdempotencyKey(paymentRequired, option, now = Date.now()) {
661
905
  const bucket = Math.floor(now / X402_IDEMPOTENCY_BUCKET_MS);
662
906
  const material = [
@@ -693,15 +937,15 @@ function resolveTokenFromAddress(address, network) {
693
937
  }
694
938
  return ALL_TOKENS[lower] ?? null;
695
939
  }
696
- function stableStringify(value) {
940
+ function stableStringify2(value) {
697
941
  if (value === null || typeof value !== "object") {
698
942
  const primitive = JSON.stringify(value);
699
943
  return primitive === void 0 ? "undefined" : primitive;
700
944
  }
701
945
  if (value instanceof Date) return JSON.stringify(value.toISOString());
702
- if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(",")}]`;
946
+ if (Array.isArray(value)) return `[${value.map((item) => stableStringify2(item)).join(",")}]`;
703
947
  const object = value;
704
- return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(object[key])}`).join(",")}}`;
948
+ return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableStringify2(object[key])}`).join(",")}}`;
705
949
  }
706
950
  function createJsonRpcProvider(url) {
707
951
  return new ethers.ethers.JsonRpcProvider(url);
@@ -772,6 +1016,7 @@ var PAYMENT_STATE_STATUS_CODES = {
772
1016
  };
773
1017
  function chainIdFromNetwork(network) {
774
1018
  if (network === "base") return 8453;
1019
+ if (network === "base-sepolia") return 84532;
775
1020
  if (!network?.startsWith("eip155:")) return void 0;
776
1021
  const chainId = Number(network.slice("eip155:".length));
777
1022
  return Number.isFinite(chainId) ? chainId : void 0;
@@ -820,7 +1065,7 @@ function messageForState(label, status, paymentId, nextAction) {
820
1065
  }
821
1066
  return `${label} is ${status}; next_action=${nextAction} (payment_id: ${paymentId}).`;
822
1067
  }
823
- function sameAddress(a, b) {
1068
+ function sameAddress3(a, b) {
824
1069
  return Boolean(a && b && a.toLowerCase() === b.toLowerCase());
825
1070
  }
826
1071
  function decimalFromUsdcAtomic(value) {
@@ -1157,6 +1402,14 @@ var HavenClient = class {
1157
1402
  }
1158
1403
  return signUserOpTypedDataForDelegation(this.delegateKey, signData.typed_data);
1159
1404
  }
1405
+ if (scheme === "eip712_delegation") {
1406
+ if (!signData.typed_data) {
1407
+ throw new HavenSigningError(
1408
+ "sign_data.signature_scheme is eip712_delegation but typed_data is missing \u2014 refusing to sign the bare hash (the settlement would be rejected on redemption)."
1409
+ );
1410
+ }
1411
+ return signSettlementDelegationTypedData(this.delegateKey, signData.typed_data);
1412
+ }
1160
1413
  if (scheme === void 0) {
1161
1414
  return signHash(this.delegateKey, signData.hash);
1162
1415
  }
@@ -1727,6 +1980,140 @@ var HavenClient = class {
1727
1980
  this.cacheX402Receipt(idempotencyKey, paymentHeader, receipt);
1728
1981
  return receipt;
1729
1982
  }
1983
+ /**
1984
+ * Pay a merchant through **erc7710 direct settlement** (#1454, epic #1450).
1985
+ *
1986
+ * The whole point of this path is what it does NOT do. There is no funding
1987
+ * leg: the merchant redeems a delegation chain and pulls from the treasury
1988
+ * directly, so the delegate EOA never holds the money, no sweep can strand
1989
+ * it, and the #713 reconciliation class does not apply. It is also why this
1990
+ * method is SMALLER than the 3009 path — the backend assembles the merchant
1991
+ * `X-PAYMENT` header in `assembleSettlementPayload`, so the SDK builds no
1992
+ * header locally.
1993
+ *
1994
+ * authorize (payTo = the MERCHANT) → sign the child → settle → header
1995
+ *
1996
+ * The caller then retries the merchant with that header. **Nothing has
1997
+ * settled when this returns** — that is why it does not return an
1998
+ * `X402Receipt`.
1999
+ *
2000
+ * Requires a delegation-rail account. The backend enforces that
2001
+ * (`validateGenericSchemeRail`), and so does this method, before building a
2002
+ * request the backend would only reject: an error a client can explain is
2003
+ * worth more than a 400 it has to decode.
2004
+ *
2005
+ * **MCP callers must pass `options.resourceUrl`.** An in-band MCP 402
2006
+ * challenge frequently carries no `resource` object at all, so
2007
+ * `paymentRequired.resource?.url` is undefined and the backend answers
2008
+ * "Valid url is required". The QA scenario this path was ported from falls
2009
+ * back to the request URL for exactly that reason — the SDK cannot, because
2010
+ * it never saw the request. Pass it.
2011
+ */
2012
+ async settleX402Erc7710(paymentRequired, options = {}) {
2013
+ if (!this.delegateKey) {
2014
+ throw new HavenSigningError(
2015
+ "delegateKey is required for x402 payments. Pass it in the HavenClient config."
2016
+ );
2017
+ }
2018
+ const prepared = await this.prepareX402Erc7710(paymentRequired, options);
2019
+ const signature = await this.signForData(prepared.signData);
2020
+ const paymentHeader = await this.submitX402Erc7710(prepared.paymentId, signature);
2021
+ return { ...prepared.settlement, paymentHeader };
2022
+ }
2023
+ /**
2024
+ * The AUTHORIZE half of erc7710 settlement (#1456): select the scheme, build
2025
+ * the request, and return the child to be signed — without signing it.
2026
+ *
2027
+ * Split out because the hosted topology cannot use `settleX402Erc7710()`:
2028
+ * that method signs in-process with `delegateKey`, and hosted Haven does not
2029
+ * have one and must not. The hosted MCP server drives these two halves with
2030
+ * the LOCAL signer in between, so the key stays where it belongs and the
2031
+ * request shaping stays in one place rather than being reimplemented.
2032
+ */
2033
+ async prepareX402Erc7710(paymentRequired, options = {}) {
2034
+ const delegationRail = options.delegationRail ?? (await this.getAgent()).executionRail === "delegation";
2035
+ if (!delegationRail) {
2036
+ throw new HavenApiError(
2037
+ "erc7710 settlement requires a delegation-rail account; this one is not on it. Use authorizeX402() for the standard EIP-3009 path.",
2038
+ 400
2039
+ );
2040
+ }
2041
+ const selection = selectX402SettlementScheme(paymentRequired.accepts, { delegationRail });
2042
+ if (!selection || selection.scheme !== "erc7710") {
2043
+ throw new HavenApiError(
2044
+ "This merchant does not advertise an erc7710 settlement option (no accepts[] entry carries extra.assetTransferMethod: 'erc7710'). Use authorizeX402() for the standard EIP-3009 path.",
2045
+ 400
2046
+ );
2047
+ }
2048
+ const option = selection.option;
2049
+ const merchantPayTo = option.payTo;
2050
+ const amountAtomic = x402AuthorizationAmount(option);
2051
+ const raw = await this.post("/x402", {
2052
+ url: options.resourceUrl ?? paymentRequired.resource?.url,
2053
+ // payTo = the MERCHANT is what selects direct settlement server-side.
2054
+ // The explicit settlementScheme must AGREE with that shape (#1360) —
2055
+ // disagreement is a 400 by design, so that a stale delegate address
2056
+ // becomes a loud mismatch instead of a silent reroute to the 3009 leg.
2057
+ payTo: merchantPayTo,
2058
+ settlementScheme: "erc7710",
2059
+ amount: amountAtomic,
2060
+ asset: option.asset,
2061
+ network: option.network,
2062
+ // The v2 header echoes the accepted entry field-for-field, so the quoted
2063
+ // timeout must round-trip or the merchant rejects the echo (#1064).
2064
+ maxTimeoutSeconds: option.maxTimeoutSeconds,
2065
+ // #1058: forward the advertised facilitators verbatim — the child becomes
2066
+ // redeemable ONLY by them. `null` here means the merchant advertised none
2067
+ // (or an empty array, which the backend 400s on), so the field is OMITTED
2068
+ // rather than sent empty. See x402FacilitatorAddresses.
2069
+ ...selection.facilitatorAddresses ? { facilitatorAddresses: selection.facilitatorAddresses } : {}
2070
+ });
2071
+ if (!raw.payment_id) {
2072
+ throw new HavenApiError("No payment_id returned from x402/authorize", 500, raw);
2073
+ }
2074
+ const signData = raw.sign_data;
2075
+ if (signData?.signature_scheme !== "eip712_delegation" || !signData.typed_data) {
2076
+ throw new HavenApiError(
2077
+ `x402/authorize did not return an erc7710 settlement child (signature_scheme was ${JSON.stringify(signData?.signature_scheme)}). Refusing to sign a payload this path did not ask for.`,
2078
+ 500,
2079
+ raw
2080
+ );
2081
+ }
2082
+ return {
2083
+ paymentId: raw.payment_id,
2084
+ signData,
2085
+ settlement: {
2086
+ paymentId: raw.payment_id,
2087
+ merchantPayTo,
2088
+ amountAtomic,
2089
+ asset: option.asset,
2090
+ network: option.network,
2091
+ facilitatorAddresses: selection.facilitatorAddresses
2092
+ }
2093
+ };
2094
+ }
2095
+ /**
2096
+ * The SETTLE half (#1456): exchange the signed child for the merchant header.
2097
+ *
2098
+ * The SDK builds no header on this path — the backend assembles the MetaMask
2099
+ * erc7710 payload in `assembleSettlementPayload`. Whoever produced the
2100
+ * signature (an in-process delegate key, or the local edge signer over the
2101
+ * hosted boundary) is irrelevant here.
2102
+ */
2103
+ async submitX402Erc7710(paymentId, signature) {
2104
+ const settled = await this.post(
2105
+ `/x402/${paymentId}/settle`,
2106
+ { signature }
2107
+ );
2108
+ if (!settled.payment_header) {
2109
+ throw new HavenApiError(
2110
+ "x402 settle returned no payment_header \u2014 the merchant cannot be retried.",
2111
+ 500,
2112
+ settled
2113
+ );
2114
+ }
2115
+ return settled.payment_header;
2116
+ }
1730
2117
  async resumeAuthorizedX402(input) {
1731
2118
  if (!this.delegateKey) {
1732
2119
  throw new HavenSigningError(
@@ -2078,8 +2465,18 @@ var HavenClient = class {
2078
2465
  * balance — otherwise it rejects with "Payment verification failed". The
2079
2466
  * SDK's local path already does this (see authorizeStandardX402); the hosted
2080
2467
  * split flow regressed when the 5→3 collapse removed the incidental
2081
- * inter-call latency that used to mask it. No-op when the funding tx hash or
2082
- * a chain RPC (chainRpcs[chainId]) is unavailable.
2468
+ * inter-call latency that used to mask it.
2469
+ *
2470
+ * **NOT a no-op when the funding tx hash is absent** (#1508). The WAIT is
2471
+ * skipped without a hash or a chain RPC, but the `GET /payments/:id` read
2472
+ * below runs UNCONDITIONALLY — it is how the fallback hash and the chainId
2473
+ * are obtained. That distinction is load-bearing: this method must never be
2474
+ * called on a scheme with no funding leg, because the read itself fails once
2475
+ * the intent reaches a status the backend maps to a non-2xx (`submitted` is a
2476
+ * 409), turning a settled payment into a reported error. The previous wording
2477
+ * here said "No-op when the funding tx hash ... is unavailable", and the
2478
+ * hosted erc7710 path was written against that promise — see
2479
+ * `deliverMerchantPayment`'s `noFundingLeg` option.
2083
2480
  */
2084
2481
  async ensureFundingConfirmed(paymentId, fundingTxHash) {
2085
2482
  const status = await this.getPaymentStatus(paymentId);
@@ -2088,8 +2485,10 @@ var HavenClient = class {
2088
2485
  async completeX402MerchantCall(input) {
2089
2486
  const evidenceContext = await this.resolveX402MerchantCompletionContext({
2090
2487
  paymentId: input.paymentId,
2091
- url: input.url
2488
+ url: input.url,
2489
+ noFundingLeg: input.noFundingLeg === true
2092
2490
  });
2491
+ const fundingTxHash = evidenceContext.txHash;
2093
2492
  const shouldHandshakeMcp = isMcpUrl(input.url) || input.mcpTransport?.handshakeRequired === true;
2094
2493
  const x402Wallet = shouldHandshakeMcp ? await this.resolveX402WalletForMerchantCall() : this.x402PayerAddress();
2095
2494
  let mcpSessionId;
@@ -2113,33 +2512,37 @@ var HavenClient = class {
2113
2512
  body = text;
2114
2513
  }
2115
2514
  if (!surfaced.ok) {
2116
- await this.recordMerchantRetryRejected({
2117
- rail: "x402",
2118
- paymentId: evidenceContext.paymentId,
2119
- txHash: evidenceContext.txHash,
2120
- resourceUrl: evidenceContext.resourceUrl,
2121
- merchant: {
2122
- merchant_status: surfaced.status,
2123
- merchant_status_text: surfaced.statusText,
2124
- merchant_headers: Object.fromEntries(surfaced.headers.entries()),
2125
- merchant_body: text
2126
- },
2127
- details: {
2128
- merchant_to: evidenceContext.merchantAddress
2129
- }
2130
- });
2515
+ if (!input.noFundingLeg && fundingTxHash) {
2516
+ await this.recordMerchantRetryRejected({
2517
+ rail: "x402",
2518
+ paymentId: evidenceContext.paymentId,
2519
+ txHash: fundingTxHash,
2520
+ resourceUrl: evidenceContext.resourceUrl,
2521
+ merchant: {
2522
+ merchant_status: surfaced.status,
2523
+ merchant_status_text: surfaced.statusText,
2524
+ merchant_headers: Object.fromEntries(surfaced.headers.entries()),
2525
+ merchant_body: text
2526
+ },
2527
+ details: {
2528
+ merchant_to: evidenceContext.merchantAddress
2529
+ }
2530
+ });
2531
+ }
2131
2532
  } else {
2132
- await this.reportMachinePaymentEvidence({
2133
- paymentId: evidenceContext.paymentId,
2134
- rail: "x402",
2135
- txHash: evidenceContext.txHash,
2136
- resourceUrl: evidenceContext.resourceUrl,
2137
- merchantStatus: surfaced.status,
2138
- paymentProofHeaderName: "X-PAYMENT",
2139
- paymentProofHeader: input.paymentHeader,
2140
- protocolReceiptHeaderName: protocolReceiptHeader ? "PAYMENT-RESPONSE" : void 0,
2141
- protocolReceiptHeader
2142
- });
2533
+ if (!input.noFundingLeg && fundingTxHash) {
2534
+ await this.reportMachinePaymentEvidence({
2535
+ paymentId: evidenceContext.paymentId,
2536
+ rail: "x402",
2537
+ txHash: fundingTxHash,
2538
+ resourceUrl: evidenceContext.resourceUrl,
2539
+ merchantStatus: surfaced.status,
2540
+ paymentProofHeaderName: "X-PAYMENT",
2541
+ paymentProofHeader: input.paymentHeader,
2542
+ protocolReceiptHeaderName: protocolReceiptHeader ? "PAYMENT-RESPONSE" : void 0,
2543
+ protocolReceiptHeader
2544
+ });
2545
+ }
2143
2546
  await this.reportMerchantReceipt(evidenceContext.paymentId, surfaced);
2144
2547
  }
2145
2548
  return {
@@ -2185,11 +2588,11 @@ var HavenClient = class {
2185
2588
  status
2186
2589
  );
2187
2590
  }
2188
- const readyForMerchantCompletion = status.nextAction === AgentPaymentNextAction.RetryOriginalX402Request || status.kind === "payment_intent" && status.status === "confirmed" && status.phase === AgentPaymentPhase.PaymentConfirmed && status.nextAction === AgentPaymentNextAction.None;
2591
+ const readyForMerchantCompletion = input.noFundingLeg ? status.kind === "payment_intent" && status.status === "submitted" : status.nextAction === AgentPaymentNextAction.RetryOriginalX402Request || status.kind === "payment_intent" && status.status === "confirmed" && status.phase === AgentPaymentPhase.PaymentConfirmed && status.nextAction === AgentPaymentNextAction.None;
2189
2592
  if (!readyForMerchantCompletion) {
2190
2593
  throw new HavenPaymentStateError(status.message, PAYMENT_STATE_STATUS_CODES[status.status] ?? 409, status);
2191
2594
  }
2192
- if (!status.txHash) {
2595
+ if (!input.noFundingLeg && !status.txHash) {
2193
2596
  throw new HavenApiError(
2194
2597
  `x402 payment ${status.paymentId} is ready for merchant completion but has no Haven transaction hash.`,
2195
2598
  502,
@@ -2257,7 +2660,7 @@ var HavenClient = class {
2257
2660
  status.paymentId
2258
2661
  );
2259
2662
  }
2260
- if (status.merchantAddress && !sameAddress(status.merchantAddress, option.payTo)) {
2663
+ if (status.merchantAddress && !sameAddress3(status.merchantAddress, option.payTo)) {
2261
2664
  throw new HavenApiError(
2262
2665
  "x402 resume request does not match the approved merchant.",
2263
2666
  409,
@@ -2952,6 +3355,7 @@ var HavenClient = class {
2952
3355
  token: raw.token,
2953
3356
  resourceUrl: raw.resource_url,
2954
3357
  merchantAddress: raw.merchant_address,
3358
+ payerAddress: raw.payer_address ?? null,
2955
3359
  txHash: raw.tx_hash,
2956
3360
  expiresAt: raw.expires_at,
2957
3361
  chainId: raw.chain_id,
@@ -3414,14 +3818,18 @@ normal, not an error.
3414
3818
 
3415
3819
  1. \`mcp__haven__haven_discover_tools\` to find a payable service and its
3416
3820
  \`catalog_id\`.
3417
- 2. \`mcp__haven__haven_prepare_catalog_purchase\` with \`catalog_id\` and a
3821
+ 2. If the user needs the live price before authorizing a cap, call
3822
+ \`mcp__haven__haven_quote_catalog_purchase\` with \`catalog_id\`. It is
3823
+ read-only and informational only: it never reserves a price or creates a
3824
+ payment. Tell the user its \`amount\` / \`amount_atomic\`, then choose a cap.
3825
+ 3. \`mcp__haven__haven_prepare_catalog_purchase\` with \`catalog_id\` and a
3418
3826
  spending cap. A cap is REQUIRED on this tool and is best practice on every
3419
3827
  paid call below too \u2014 it caps what the LIVE merchant quote may charge,
3420
3828
  checked before any funding intent is created. Write it the way the user
3421
3829
  said it: \`max_amount_human\` is whole tokens, so "no more than 1 USDC" is
3422
3830
  \`max_amount_human: "1"\`. (\`max_amount\` is the atomic-unit form, where
3423
3831
  "1" means 0.000001 USDC \u2014 do not convert by hand, and never send both.)
3424
- 3. Then FOLLOW THE RESPONSE'S GUIDANCE FIELDS: \`next_action\`, \`next_tool\`,
3832
+ 4. Then FOLLOW THE RESPONSE'S GUIDANCE FIELDS: \`next_action\`, \`next_tool\`,
3425
3833
  and \`next_arguments\` name the exact next call \u2014 act on those first; the
3426
3834
  prose in this section is fallback and debugging detail. If the catalog
3427
3835
  entry is missing or degraded, the response instead names
@@ -3449,7 +3857,12 @@ do not re-pay.
3449
3857
 
3450
3858
  Step-by-step alternative (also key-safe; for an older signer or backend, or
3451
3859
  when you already have a merchant URL and tool name instead of a
3452
- \`catalog_id\`): \`mcp__haven__haven_pay_mcp_tool\` then
3860
+ \`catalog_id\`): if the user needs the live price before choosing a cap, first
3861
+ call \`mcp__haven__haven_quote_mcp_tool\` with that merchant URL, tool name,
3862
+ and arguments. It is informational only; then call
3863
+ \`mcp__haven__haven_pay_mcp_tool\` with the same inputs and the explicit cap.
3864
+ The paid call always obtains a fresh quote before it creates any intent. Then
3865
+ continue \`mcp__haven__haven_pay_mcp_tool\` \u2192
3453
3866
  \`mcp__haven-signer__haven_sign\` \u2192 \`mcp__haven__haven_submit\` \u2192
3454
3867
  \`mcp__haven-signer__haven_x402_sign_header\` \u2192
3455
3868
  \`mcp__haven__haven_complete_mcp_tool\`. Pass \`payment_required\`,
@@ -3471,11 +3884,13 @@ when the result says \`retry_original_x402_request\`.
3471
3884
  \`arguments\` field (for example
3472
3885
  \`tool_arguments: { "tier": "50gb" }\` -> \`arguments: { "tier": "50gb" }\`).
3473
3886
 
3474
- **Prices:** show the user the live price from the pay-tool result, never a
3475
- catalog price. \`haven_discover_tools\` prices are indicative
3476
- (\`price_is_indicative\`) and can be stale. The pay-tool result's \`amount\` /
3477
- \`amount_atomic\` is the amount Haven authorizes for the call \u2014 a ceiling the
3478
- merchant settles at or below \u2014 so present it as the most the user will pay.
3887
+ **Prices:** show the user the live price from a read-only quote or the pay-tool
3888
+ result, never a catalog price. \`haven_discover_tools\` prices are indicative
3889
+ (\`price_is_indicative\`) and can be stale. A read-only quote is informational
3890
+ only and does not reserve a price; the later paid call re-quotes and enforces
3891
+ the cap. The pay-tool result's \`amount\` / \`amount_atomic\` is the amount
3892
+ Haven authorizes for that call \u2014 a ceiling the merchant settles at or below \u2014
3893
+ so present it as the most the user will pay.
3479
3894
 
3480
3895
  **Status:** \`mcp__haven__haven_get_payment_status\` with a \`payment_id\` to
3481
3896
  check on queued or in-flight payments. Do not poll in a tight loop.
@@ -3542,6 +3957,7 @@ the agent in the Haven dashboard under Agents. New requests stop immediately
3542
3957
  for that credential.
3543
3958
  `;
3544
3959
  var SKILL_FOLDER_NAME = "haven-pay";
3960
+ var HAVEN_SKILL_BODY_MD = HAVEN_SKILL_MD.replace(/^---\n[\s\S]*?\n---\n+/, "");
3545
3961
 
3546
3962
  // src/node-version.ts
3547
3963
  var HAVEN_MINIMUM_NODE_VERSION = "22.0.0";
@@ -3582,111 +3998,6 @@ function major(version) {
3582
3998
  return String(parseNodeVersion(version)[0]);
3583
3999
  }
3584
4000
 
3585
- // src/sweep.ts
3586
- var SWEEP_BASE_CHAIN_ID = 8453;
3587
- var SWEEP_BASE_SEPOLIA_CHAIN_ID = 84532;
3588
- var SWEEP_BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
3589
- var SWEEP_BASE_SEPOLIA_USDC_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
3590
- var USDC_EIP712_DOMAIN_BY_CHAIN = {
3591
- [SWEEP_BASE_CHAIN_ID]: {
3592
- name: "USD Coin",
3593
- version: "2",
3594
- chainId: SWEEP_BASE_CHAIN_ID,
3595
- verifyingContract: SWEEP_BASE_USDC_ADDRESS
3596
- },
3597
- [SWEEP_BASE_SEPOLIA_CHAIN_ID]: {
3598
- name: "USDC",
3599
- version: "2",
3600
- chainId: SWEEP_BASE_SEPOLIA_CHAIN_ID,
3601
- verifyingContract: SWEEP_BASE_SEPOLIA_USDC_ADDRESS
3602
- }
3603
- };
3604
- var USDC_ADDRESS_BY_CHAIN = {
3605
- [SWEEP_BASE_CHAIN_ID]: SWEEP_BASE_USDC_ADDRESS,
3606
- [SWEEP_BASE_SEPOLIA_CHAIN_ID]: SWEEP_BASE_SEPOLIA_USDC_ADDRESS
3607
- };
3608
- var SWEEPABLE_CHAIN_IDS = Object.keys(USDC_ADDRESS_BY_CHAIN).map(Number);
3609
- function isSweepableChain(chainId) {
3610
- return chainId in USDC_ADDRESS_BY_CHAIN;
3611
- }
3612
- var TRANSFER_WITH_AUTHORIZATION_TYPES = {
3613
- TransferWithAuthorization: [
3614
- { name: "from", type: "address" },
3615
- { name: "to", type: "address" },
3616
- { name: "value", type: "uint256" },
3617
- { name: "validAfter", type: "uint256" },
3618
- { name: "validBefore", type: "uint256" },
3619
- { name: "nonce", type: "bytes32" }
3620
- ]
3621
- };
3622
- function sweepUsdcAddress(chainId) {
3623
- const address = USDC_ADDRESS_BY_CHAIN[chainId];
3624
- if (!address) {
3625
- throw new HavenSigningError(
3626
- `Sweep is not supported on chain ${chainId}. Supported: ${SWEEPABLE_CHAIN_IDS.join(", ")}.`
3627
- );
3628
- }
3629
- return address;
3630
- }
3631
- function sweepUsdcDomain(chainId) {
3632
- const domain = USDC_EIP712_DOMAIN_BY_CHAIN[chainId];
3633
- if (!domain) {
3634
- throw new HavenSigningError(
3635
- `Sweep is not supported on chain ${chainId}. Supported: ${SWEEPABLE_CHAIN_IDS.join(", ")}.`
3636
- );
3637
- }
3638
- return domain;
3639
- }
3640
- function sameAddress2(a, b) {
3641
- return a.toLowerCase() === b.toLowerCase();
3642
- }
3643
- function buildSweepTypedData(auth) {
3644
- const domain = sweepUsdcDomain(auth.chainId);
3645
- const expectedToken = sweepUsdcAddress(auth.chainId);
3646
- if (!sameAddress2(auth.token, expectedToken)) {
3647
- throw new HavenSigningError(
3648
- `Sweep token ${auth.token} is not the canonical USDC contract for chain ${auth.chainId}.`
3649
- );
3650
- }
3651
- if (!/^0x[0-9a-fA-F]{64}$/.test(auth.nonce)) {
3652
- throw new HavenSigningError("Sweep nonce must be a 0x-prefixed 32-byte hex string.");
3653
- }
3654
- return {
3655
- domain,
3656
- types: TRANSFER_WITH_AUTHORIZATION_TYPES,
3657
- primaryType: "TransferWithAuthorization",
3658
- message: {
3659
- from: auth.from,
3660
- to: auth.to,
3661
- value: BigInt(auth.value),
3662
- validAfter: BigInt(auth.validAfter),
3663
- validBefore: BigInt(auth.validBefore),
3664
- nonce: auth.nonce
3665
- }
3666
- };
3667
- }
3668
- function buildSweepAuthorizationMessage(auth) {
3669
- return `Haven sweep authorization v1
3670
- ${stableStringify2({
3671
- version: 1,
3672
- kind: "haven.sweep.authorization",
3673
- from: auth.from.toLowerCase(),
3674
- to: auth.to.toLowerCase(),
3675
- value: auth.value,
3676
- validAfter: auth.validAfter,
3677
- validBefore: auth.validBefore,
3678
- nonce: auth.nonce.toLowerCase(),
3679
- token: auth.token.toLowerCase(),
3680
- chainId: auth.chainId
3681
- })}`;
3682
- }
3683
- function stableStringify2(value) {
3684
- if (value === null || typeof value !== "object") return JSON.stringify(value);
3685
- if (Array.isArray(value)) return `[${value.map((item) => stableStringify2(item)).join(",")}]`;
3686
- const object = value;
3687
- return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableStringify2(object[key])}`).join(",")}}`;
3688
- }
3689
-
3690
4001
  // src/merchant-discovery.ts
3691
4002
  var MERCHANT_DISCOVERY_PATHS = ["/.well-known/haven-demo-merchant", "/"];
3692
4003
  var DISCOVERY_MAX_BYTES = 64 * 1024;
@@ -3749,7 +4060,9 @@ exports.AgentPaymentRailDescriptions = AgentPaymentRailDescriptions;
3749
4060
  exports.AgentPaymentRailSchema = AgentPaymentRailSchema;
3750
4061
  exports.AgentPaymentWarningCode = AgentPaymentWarningCode;
3751
4062
  exports.DISCOVERY_MAX_BYTES = DISCOVERY_MAX_BYTES;
4063
+ exports.ERC7710_ASSET_TRANSFER_METHOD = ERC7710_ASSET_TRANSFER_METHOD;
3752
4064
  exports.HAVEN_MINIMUM_NODE_VERSION = HAVEN_MINIMUM_NODE_VERSION;
4065
+ exports.HAVEN_SKILL_BODY_MD = HAVEN_SKILL_BODY_MD;
3753
4066
  exports.HAVEN_SKILL_MD = HAVEN_SKILL_MD;
3754
4067
  exports.HavenApiError = HavenApiError;
3755
4068
  exports.HavenClient = HavenClient;
@@ -3769,6 +4082,7 @@ exports.SWEEP_BASE_SEPOLIA_USDC_ADDRESS = SWEEP_BASE_SEPOLIA_USDC_ADDRESS;
3769
4082
  exports.SWEEP_BASE_USDC_ADDRESS = SWEEP_BASE_USDC_ADDRESS;
3770
4083
  exports.SignerRefusalCode = SignerRefusalCode;
3771
4084
  exports.TRANSFER_WITH_AUTHORIZATION_TYPES = TRANSFER_WITH_AUTHORIZATION_TYPES;
4085
+ exports.X402PaymentHeaderValidationError = X402PaymentHeaderValidationError;
3772
4086
  exports.X402UnexpectedStatusError = X402UnexpectedStatusError;
3773
4087
  exports.X402_MAX_AUTHORIZATION_WINDOW_SECONDS = X402_MAX_AUTHORIZATION_WINDOW_SECONDS;
3774
4088
  exports.X402_SETTLEMENT_FORWARD_MARGIN_SECONDS = X402_SETTLEMENT_FORWARD_MARGIN_SECONDS;
@@ -3785,14 +4099,18 @@ exports.encodeBase64Json = encodeBase64Json;
3785
4099
  exports.encodeBase64Utf8 = encodeBase64Utf8;
3786
4100
  exports.encodePaymentProof = encodePaymentProof;
3787
4101
  exports.havenTools = havenTools;
4102
+ exports.isErc7710Option = isErc7710Option;
3788
4103
  exports.isSupportedNodeVersion = isSupportedNodeVersion;
3789
4104
  exports.isSweepableChain = isSweepableChain;
4105
+ exports.normalizePaymentRequired = normalizePaymentRequired;
3790
4106
  exports.parsePaymentRequired = parsePaymentRequired;
3791
4107
  exports.parsePaymentRequiredResponse = parsePaymentRequiredResponse;
3792
4108
  exports.resolveTokenFromAddress = resolveTokenFromAddress;
3793
4109
  exports.sameUrl = sameUrl;
4110
+ exports.selectErc7710PaymentOption = selectErc7710PaymentOption;
3794
4111
  exports.selectPaymentOption = selectPaymentOption;
3795
4112
  exports.selectStandardPaymentOption = selectStandardPaymentOption;
4113
+ exports.selectX402SettlementScheme = selectX402SettlementScheme;
3796
4114
  exports.signHash = signHash;
3797
4115
  exports.signUserOpTypedDataForDelegation = signUserOpTypedDataForDelegation;
3798
4116
  exports.sweepUsdcAddress = sweepUsdcAddress;
@@ -3800,8 +4118,11 @@ exports.sweepUsdcDomain = sweepUsdcDomain;
3800
4118
  exports.toStandardPaymentRequirements = toStandardPaymentRequirements;
3801
4119
  exports.toolDescriptions = toolDescriptions;
3802
4120
  exports.unsupportedNodeVersionMessage = unsupportedNodeVersionMessage;
4121
+ exports.validateStandardX402PaymentHeader = validateStandardX402PaymentHeader;
3803
4122
  exports.verifyPaymentReceipt = verifyPaymentReceipt;
3804
4123
  exports.verifySignature = verifySignature;
4124
+ exports.x402AssetTransferMethod = x402AssetTransferMethod;
3805
4125
  exports.x402AuthorizationAmount = x402AuthorizationAmount;
4126
+ exports.x402FacilitatorAddresses = x402FacilitatorAddresses;
3806
4127
  //# sourceMappingURL=index.cjs.map
3807
4128
  //# sourceMappingURL=index.cjs.map