@zeroxyz/sdk 0.2.0 → 0.4.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.
@@ -77,6 +77,16 @@ var ZeroPaymentError = class extends ZeroError {
77
77
  this.name = "ZeroPaymentError";
78
78
  }
79
79
  };
80
+ var ZeroInsufficientFundsError = class extends ZeroError {
81
+ have;
82
+ need;
83
+ constructor(message, init) {
84
+ super("insufficient_funds", message, { cause: init.cause });
85
+ this.name = "ZeroInsufficientFundsError";
86
+ this.have = init.have;
87
+ this.need = init.need;
88
+ }
89
+ };
80
90
  var ZeroSessionCloseFailedError = class extends ZeroError {
81
91
  session;
82
92
  response;
@@ -423,7 +433,12 @@ var FETCH_SKIP_REASONS = Object.freeze({
423
433
  bodyReadFailed: "body_read_failed",
424
434
  mppSessionCloseFailedNotRecorded: "mpp_session_close_failed_not_recorded",
425
435
  paidButStill402NotRecorded: FETCH_WARNINGS.paidButStill402NotRecorded,
426
- paymentSettlementUnconfirmed: FETCH_WARNINGS.paymentSettlementUnconfirmed
436
+ paymentSettlementUnconfirmed: FETCH_WARNINGS.paymentSettlementUnconfirmed,
437
+ // Pre-sign abort: deliberately NOT recorded as a run — the wallet was
438
+ // empty before we reached the capability, so charging it as a 402 would
439
+ // corrupt cap reliability. The wallet funnel is tracked via the
440
+ // fetch_executed.outcome analytics event instead.
441
+ insufficientFunds: "insufficient_funds_not_recorded"
427
442
  });
428
443
  var MAX_RECEIPT_HEADER_BYTES = 8 * 1024;
429
444
  var decodeSessionReceiptHeader = (header) => {
@@ -565,6 +580,7 @@ var Payments = class {
565
580
  );
566
581
  let capturedAmount = null;
567
582
  let capturedNetwork;
583
+ let preflightError = null;
568
584
  const x402 = registerExactEvmScheme(new x402Client(), { signer: account });
569
585
  x402.onBeforePaymentCreation(async (context) => {
570
586
  const selected = context.selectedRequirements;
@@ -598,6 +614,29 @@ var Payments = class {
598
614
  reason: `Payment of ${capturedAmount} USDC exceeds maxPay ${input.maxPay}`
599
615
  };
600
616
  }
617
+ const detected = networkToChain(capturedNetwork);
618
+ const balanceChain = detected === "base-sepolia" ? "base-sepolia" : "base";
619
+ let balance = null;
620
+ try {
621
+ balance = await this.readUsdcBalance(account.address, balanceChain);
622
+ } catch (readErr) {
623
+ this.client.logger?.({
624
+ level: "warn",
625
+ message: "Pre-flight balance read failed; proceeding to attempt payment",
626
+ meta: {
627
+ chain: balanceChain,
628
+ error: readErr instanceof Error ? readErr.message : String(readErr)
629
+ }
630
+ });
631
+ }
632
+ if (balance !== null && balance < rawAmountUnits) {
633
+ const have = formatUnits(balance, 6);
634
+ preflightError = new ZeroInsufficientFundsError(
635
+ `wallet has ${have} USDC on Base, needs ${capturedAmount}.`,
636
+ { have, need: capturedAmount }
637
+ );
638
+ return { abort: true, reason: preflightError.message };
639
+ }
601
640
  });
602
641
  const configuredFetch = buildConfiguredFetch(this.client, {
603
642
  timeoutMs: input.timeoutMs
@@ -618,6 +657,7 @@ var Payments = class {
618
657
  signal: input.signal
619
658
  });
620
659
  } catch (err) {
660
+ if (preflightError) throw preflightError;
621
661
  if (err instanceof ZeroError) throw err;
622
662
  throw new ZeroPaymentError(
623
663
  `x402 payment failed: ${err instanceof Error ? err.message : String(err)}`,
@@ -862,23 +902,29 @@ var Payments = class {
862
902
  );
863
903
  if (tempoBalance < requiredRaw) {
864
904
  if (coerced.chain === "tempo-testnet") {
865
- throw new ZeroPaymentError(
866
- `Insufficient pathUSD on Tempo testnet: have ${formatUnits(tempoBalance, 6)}, need ${capturedAmount}. Fund via the Tempo testnet faucet: https://docs.tempo.xyz/quickstart/faucet`
905
+ const have = formatUnits(tempoBalance, 6);
906
+ throw new ZeroInsufficientFundsError(
907
+ `Insufficient pathUSD on Tempo testnet: have ${have}, need ${capturedAmount}. Fund via the Tempo testnet faucet: https://docs.tempo.xyz/quickstart/faucet`,
908
+ { have, need: capturedAmount }
867
909
  );
868
910
  }
869
- await this.bridgeBaseToTempo(account, requiredRaw - tempoBalance);
911
+ await this.bridgeBaseToTempo(account, requiredRaw - tempoBalance, {
912
+ isSessionDeposit: challenge.intent === "session",
913
+ depositTotal: capturedAmount
914
+ });
870
915
  }
871
916
  return capturedAmount;
872
917
  };
873
- bridgeBaseToTempo = async (account, requiredAmount) => {
918
+ bridgeBaseToTempo = async (account, requiredAmount, depositContext) => {
874
919
  this.ensureRelayClient();
875
920
  const baseBalance = await this.readUsdcBalance(account.address, "base");
876
921
  const buffer = calculateBuffer(baseBalance);
877
922
  const bridgeAmount = requiredAmount + buffer;
878
923
  if (baseBalance < bridgeAmount) {
879
- throw new ZeroPaymentError(
880
- `Insufficient Base USDC to bridge: have ${formatUnits(baseBalance, 6)}, need ${formatUnits(bridgeAmount, 6)} (${formatUnits(requiredAmount, 6)} + ${formatUnits(buffer, 6)} buffer). This capability uses an MPP payment channel, which is pre-funded up front. Either fund your wallet on Base, or pass \`maxPay\` to size a smaller channel (e.g. \`maxPay: '0.05'\` for a ~5-cent channel sized for a single cheap call).`
881
- );
924
+ const have = formatUnits(baseBalance, 6);
925
+ const need = formatUnits(bridgeAmount, 6);
926
+ const message = depositContext?.isSessionDeposit ? `wallet has ${have} USDC on Base, but this capability pre-funds a ${depositContext.depositTotal} USDC MPP payment channel up front (the channel is deposited before the call, so it asks for more than a single charge). Needs ${need} on Base to open it \u2014 fund the wallet, or pass a smaller \`maxPay\` (e.g. '0.05') to size the channel down to one cheap call.` : `wallet has ${have} USDC on Base, needs ${need} to fund this capability's MPP payment channel (${formatUnits(requiredAmount, 6)} + ${formatUnits(buffer, 6)} buffer). Tip: pass a smaller \`maxPay\` (e.g. '0.05') to size a cheaper channel.`;
927
+ throw new ZeroInsufficientFundsError(message, { have, need });
882
928
  }
883
929
  this.client.logger?.({
884
930
  level: "info",
@@ -1098,7 +1144,7 @@ var Payments = class {
1098
1144
 
1099
1145
  // package.json
1100
1146
  var package_default = {
1101
- version: "0.2.0"};
1147
+ version: "0.4.0"};
1102
1148
 
1103
1149
  // src/version.ts
1104
1150
  var SDK_VERSION = package_default.version;
@@ -2480,6 +2526,15 @@ var clientFetch = async (client, url, opts = {}) => {
2480
2526
  session: err.session
2481
2527
  };
2482
2528
  warnings.push(FETCH_WARNINGS.mppSessionCloseFailed);
2529
+ } else if (err instanceof ZeroInsufficientFundsError) {
2530
+ return errorFetchResult(
2531
+ startedAt,
2532
+ err.message,
2533
+ FETCH_SKIP_REASONS.insufficientFunds,
2534
+ capabilityIdRequested,
2535
+ "insufficient_funds",
2536
+ null
2537
+ );
2483
2538
  } else if (err instanceof ZeroPaymentError || err instanceof ZeroAuthError) {
2484
2539
  const result2 = errorFetchResult(
2485
2540
  startedAt,
@@ -2677,8 +2732,15 @@ var searchResultSchema = z.object({
2677
2732
  slug: z.string(),
2678
2733
  name: z.string(),
2679
2734
  canonicalName: z.string().nullable().optional(),
2735
+ brandName: z.string().nullable().optional(),
2680
2736
  description: z.string(),
2681
2737
  whatItDoes: z.string().nullable().optional(),
2738
+ // HTTP verb the capability expects. Surfaced on the search row so a caller
2739
+ // can tell GET from POST without a `capabilities.get()` round-trip — enough
2740
+ // to `fetch()` a no-body GET directly. POST bodies still need `get()` for
2741
+ // the `bodySchema`. Optional (not required) so a response that omits it —
2742
+ // an older API deploy — still parses rather than failing the whole search.
2743
+ method: z.string().optional(),
2682
2744
  url: z.string(),
2683
2745
  urlTemplate: z.string().nullable().optional(),
2684
2746
  cost: z.object({ amount: z.string(), asset: z.string() }),
@@ -3076,5 +3138,5 @@ var ZeroClient = class _ZeroClient {
3076
3138
  };
3077
3139
 
3078
3140
  export { Auth, AuthDevice, BUG_REPORT_CATEGORIES, BugReports, Capabilities, DEFAULT_BASE_URL, DEFAULT_MAX_RETRIES, DEFAULT_TIMEOUT_MS, FETCH_SKIP_REASONS, FETCH_WARNINGS, Payments, Runs, SDK_VERSION, TEMPO_CHAIN_ID, TEMPO_TESTNET_CHAIN_ID, Wallet, ZeroApiError, ZeroAuthError, ZeroClient, ZeroConfigurationError, ZeroError, ZeroPaymentError, ZeroSessionCloseFailedError, ZeroTimeoutError, ZeroValidationError, ZeroWalletError, coerceTempoChainId, createManagedAccount, paymentHasAnchor, tempoChainLabelFromId };
3079
- //# sourceMappingURL=chunk-SLXRHGE4.js.map
3080
- //# sourceMappingURL=chunk-SLXRHGE4.js.map
3141
+ //# sourceMappingURL=chunk-RPL7VC32.js.map
3142
+ //# sourceMappingURL=chunk-RPL7VC32.js.map