@zkp2p/cash 0.1.3 → 0.1.4

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.js CHANGED
@@ -1,6 +1,6 @@
1
- import { MARKET_SPREAD_BPS, ORACLE_MIN_CONVERSION_RATE_SENTINEL, CASH_RETAIN_ON_EMPTY, BASE_USDC_ADDRESS, USDC_DECIMALS, BASE_CHAIN_ID, errors, isCashError, CASH_ORDER_STATUSES, mapChainError } from './chunk-FKVPZVFH.js';
2
- export { BASE_CHAIN_ID, BASE_USDC_ADDRESS, CASH_ORDER_POLL_INTERVAL_MS, CASH_ORDER_STATUSES, CASH_RETAIN_ON_EMPTY, CashError, MARKET_SPREAD_BPS, ORACLE_MIN_CONVERSION_RATE_SENTINEL, USDC_DECIMALS, errors, isCashError } from './chunk-FKVPZVFH.js';
3
- import { parseAbi, parseEventLogs, http, createWalletClient, encodeFunctionData } from 'viem';
1
+ import { MARKET_SPREAD_BPS, ORACLE_MIN_CONVERSION_RATE_SENTINEL, CASH_RETAIN_ON_EMPTY, BASE_USDC_ADDRESS, USDC_DECIMALS, BASE_CHAIN_ID, errors, isCashError, CASH_ORDER_STATUSES, mapChainError, CashError } from './chunk-P3KYZ2FX.js';
2
+ export { BASE_CHAIN_ID, BASE_USDC_ADDRESS, CASH_ORDER_POLL_INTERVAL_MS, CASH_ORDER_STATUSES, CASH_RETAIN_ON_EMPTY, CashError, MARKET_SPREAD_BPS, ORACLE_MIN_CONVERSION_RATE_SENTINEL, USDC_DECIMALS, errors, isCashError } from './chunk-P3KYZ2FX.js';
3
+ import { parseAbi, parseEventLogs, isAddress, http, createWalletClient, encodeFunctionData } from 'viem';
4
4
  import { base } from 'viem/chains';
5
5
  import { getSpreadOracleConfig, currencyInfo, getPaymentMethodsCatalog, getGatingServiceAddress, resolvePaymentMethodHashFromCatalog, resolvePaymentMethodNameFromHash, getCurrencyCodeFromHash, createCompositeDepositId, appendAttributionToCalldata, Zkp2pClient, CHAINLINK_ORACLE_FEEDS } from '@zkp2p/sdk';
6
6
  import { createClient, MAINNET_RELAY_API } from '@relayprotocol/relay-sdk';
@@ -221,10 +221,12 @@ function deriveCashOrder(depositId, intents, options = {}) {
221
221
  const total = options.totalAmount ?? remaining + outstanding + taken + withdrawn;
222
222
  const status = options.status;
223
223
  const isTerminal = status === "CLOSED" || status === "WITHDRAWN";
224
- const hasLiveFunds = remaining > DUST_THRESHOLD || outstanding > 0n;
224
+ const hasLiveFunds = remaining >= DUST_THRESHOLD || outstanding > 0n;
225
225
  let state;
226
226
  if (outstanding > 0n) {
227
227
  state = taken > 0n ? "delivering" : "matched";
228
+ } else if (!hasLiveFunds && withdrawn > 0n) {
229
+ state = "returned";
228
230
  } else if (taken > 0n && !hasLiveFunds) {
229
231
  state = "delivered";
230
232
  } else if (taken > 0n && hasLiveFunds) {
@@ -266,7 +268,7 @@ function deriveCashOrder(depositId, intents, options = {}) {
266
268
  ...options.payouts !== void 0 ? { payouts: options.payouts } : {},
267
269
  ...options.successRateBps !== void 0 ? { successRateBps: options.successRateBps } : {},
268
270
  isInFlight,
269
- withdrawn: isTerminal
271
+ withdrawn: state === "returned" && withdrawn > 0n
270
272
  });
271
273
  }
272
274
  var ORACLE_KINDS = /* @__PURE__ */ new Set(["oracle_chainlink", "oracle_pyth"]);
@@ -376,12 +378,14 @@ function resolveCashDepositId(params) {
376
378
  }
377
379
  function parseCompositeDepositId(compositeId) {
378
380
  const idx = compositeId.lastIndexOf("_");
379
- if (idx === -1) {
380
- return { escrowAddress: "", onchainDepositId: BigInt(compositeId) };
381
- }
382
381
  const escrowAddress = compositeId.slice(0, idx);
383
- const onchainDepositId = BigInt(compositeId.slice(idx + 1) || "0");
384
- return { escrowAddress, onchainDepositId };
382
+ const rawDepositId = compositeId.slice(idx + 1);
383
+ if (idx <= 0 || compositeId.indexOf("_") !== idx || !isAddress(escrowAddress, { strict: false }) || !/^\d+$/.test(rawDepositId)) {
384
+ throw new Error(`Invalid deposit id: '${compositeId}'`);
385
+ }
386
+ const canonicalEscrowAddress = escrowAddress.toLowerCase();
387
+ const onchainDepositId = BigInt(rawDepositId);
388
+ return { escrowAddress: canonicalEscrowAddress, onchainDepositId };
385
389
  }
386
390
  var MIN_CASHOUT_AMOUNT = 10000n;
387
391
  var RECOMMENDED_MIN_CASHOUT_AMOUNT = 1000000n;
@@ -399,9 +403,6 @@ var PAYEE_HINTS = {
399
403
  n26: "MoneyBeam email or phone number"
400
404
  };
401
405
  var IDENTITY_ATTESTATION_PLATFORMS = /* @__PURE__ */ new Set(["wise", "paypal"]);
402
- function platformRequiresIdentityAttestation(platform) {
403
- return IDENTITY_ATTESTATION_PLATFORMS.has(platform);
404
- }
405
406
  function buildCapabilities(environment) {
406
407
  const catalog = getPaymentMethodsCatalog(BASE_CHAIN_ID, environment);
407
408
  const platforms = Object.entries(catalog).map(([platform, entry]) => {
@@ -591,20 +592,175 @@ function normalizeChain(chain) {
591
592
  function isSupportedEvmChain(chain) {
592
593
  return chain.vmType === void 0 || chain.vmType === "evm";
593
594
  }
595
+ function isExecutableSourceChain(chain) {
596
+ return isSupportedEvmChain(chain) && !chain.disabled && chain.depositEnabled && !chain.blockProductionLagging;
597
+ }
594
598
  function quoteRequestId(quote) {
595
599
  return quote.steps.map((step) => step.requestId).find((id) => id !== void 0);
596
600
  }
601
+ function collectRelayTransactions(steps, sourceChainId) {
602
+ const origin = [];
603
+ const destination = [];
604
+ const record = (tx) => {
605
+ (tx.chainId === sourceChainId ? origin : destination).push(tx);
606
+ };
607
+ for (const step of steps) {
608
+ for (const item of step.items) {
609
+ for (const tx of item.internalTxHashes ?? []) {
610
+ record({ hash: tx.txHash, chainId: tx.chainId });
611
+ }
612
+ for (const tx of item.txHashes ?? []) {
613
+ record({ hash: tx.txHash, chainId: tx.chainId });
614
+ }
615
+ }
616
+ }
617
+ const dedupe = (txs) => [
618
+ ...new Map(txs.map((tx) => [`${tx.chainId}:${tx.hash.toLowerCase()}`, tx])).values()
619
+ ];
620
+ return { origin: dedupe(origin), destination: dedupe(destination) };
621
+ }
622
+ function relayTransactionHashes(transactions) {
623
+ return [
624
+ ...new Set([...transactions.origin, ...transactions.destination].map(({ hash }) => hash))
625
+ ];
626
+ }
597
627
  function quoteSourceChainId(quote) {
598
628
  const details = asRecord(quote.details);
599
629
  const currencyIn = asRecord(details.currencyIn);
600
630
  const sourceCurrency = asRecord(currencyIn.currency);
601
631
  return asNumber(sourceCurrency.chainId);
602
632
  }
633
+ function assertCanonicalRelayDestination(quote) {
634
+ const details = asRecord(quote.details);
635
+ const currencyOut = asRecord(details.currencyOut);
636
+ const destination = asRecord(currencyOut.currency);
637
+ if (asNumber(destination.chainId) !== BASE_CHAIN_ID || asString(destination.address)?.toLowerCase() !== BASE_USDC_ADDRESS.toLowerCase()) {
638
+ throw new Error("Relay quote destination is not canonical Base USDC");
639
+ }
640
+ }
641
+ async function assertWalletChainId(wallet, expectedChainId, operation) {
642
+ let actualChainId;
643
+ try {
644
+ actualChainId = await wallet.getChainId();
645
+ } catch (err) {
646
+ throw errors.signerChainUnavailable(operation, expectedChainId, err);
647
+ }
648
+ if (actualChainId !== expectedChainId) {
649
+ throw errors.signerChainMismatch(operation, expectedChainId, actualChainId);
650
+ }
651
+ }
652
+ async function assertRelayExecutionIdentity(quote, wallet, expectedRecipient) {
653
+ const signer = wallet.account?.address;
654
+ if (!signer) throw new Error("Relay execution requires a wallet account");
655
+ const sourceChainId = quoteSourceChainId(quote);
656
+ if (sourceChainId !== void 0) {
657
+ await assertWalletChainId(wallet, sourceChainId, "Relay execution");
658
+ }
659
+ const details = asRecord(quote.details);
660
+ const sender = asString(details.sender);
661
+ const recipient = asString(details.recipient);
662
+ if (!sender || sender.toLowerCase() !== signer.toLowerCase()) {
663
+ throw new Error("Relay quote sender does not match the execution signer");
664
+ }
665
+ const destinationOwner = expectedRecipient ?? signer;
666
+ if (!recipient || recipient.toLowerCase() !== destinationOwner.toLowerCase()) {
667
+ throw new Error("Relay quote recipient does not match the expected Base recipient");
668
+ }
669
+ }
670
+ function isRelaySecretKey(key) {
671
+ const normalized = key.toLowerCase();
672
+ return normalized === "headers" || normalized === "apikey";
673
+ }
674
+ function redactRelayValue(value, seen = /* @__PURE__ */ new WeakMap()) {
675
+ if (value === null || typeof value !== "object") return value;
676
+ if (value instanceof Date || value instanceof Error) return value;
677
+ const existing = seen.get(value);
678
+ if (existing !== void 0) return existing;
679
+ if (Array.isArray(value)) {
680
+ const output2 = [];
681
+ seen.set(value, output2);
682
+ for (const entry of value) output2.push(redactRelayValue(entry, seen));
683
+ return output2;
684
+ }
685
+ const output = {};
686
+ seen.set(value, output);
687
+ for (const [key, entry] of Object.entries(value)) {
688
+ if (!isRelaySecretKey(key)) output[key] = redactRelayValue(entry, seen);
689
+ }
690
+ return output;
691
+ }
692
+ var RELAY_WIRE_TYPE = "__zkp2pCashType";
693
+ function sanitizeRelayValue(value, seen = /* @__PURE__ */ new WeakSet()) {
694
+ if (typeof value === "bigint") {
695
+ return { [RELAY_WIRE_TYPE]: "bigint", value: value.toString() };
696
+ }
697
+ if (value === null || typeof value === "string" || typeof value === "boolean") {
698
+ return value;
699
+ }
700
+ if (typeof value === "number") {
701
+ return Number.isFinite(value) ? value : { [RELAY_WIRE_TYPE]: "number", value: String(value) };
702
+ }
703
+ if (typeof value === "undefined") return { [RELAY_WIRE_TYPE]: "undefined" };
704
+ if (value instanceof Date) {
705
+ return { [RELAY_WIRE_TYPE]: "date", value: value.toISOString() };
706
+ }
707
+ if (value instanceof Error) {
708
+ return {
709
+ [RELAY_WIRE_TYPE]: "error",
710
+ name: value.name,
711
+ message: value.message
712
+ };
713
+ }
714
+ if (typeof value !== "object") return void 0;
715
+ if (seen.has(value)) throw new TypeError("Relay payload contains a circular reference");
716
+ seen.add(value);
717
+ if (Array.isArray(value)) {
718
+ const output2 = value.map((entry) => sanitizeRelayValue(entry, seen));
719
+ seen.delete(value);
720
+ return output2;
721
+ }
722
+ const output = {};
723
+ for (const [key, entry] of Object.entries(value)) {
724
+ if (isRelaySecretKey(key)) continue;
725
+ const sanitized = sanitizeRelayValue(entry, seen);
726
+ if (sanitized !== void 0) output[key] = sanitized;
727
+ }
728
+ seen.delete(value);
729
+ return output;
730
+ }
731
+ function restoreRelayValue(value) {
732
+ if (Array.isArray(value)) return value.map(restoreRelayValue);
733
+ if (value === null || typeof value !== "object") return value;
734
+ const row = value;
735
+ const wireType = row[RELAY_WIRE_TYPE];
736
+ const keyCount = Object.keys(row).length;
737
+ if (keyCount === 2 && wireType === "bigint" && typeof row.value === "string") {
738
+ return BigInt(row.value);
739
+ }
740
+ if (keyCount === 2 && wireType === "date" && typeof row.value === "string") {
741
+ return new Date(row.value);
742
+ }
743
+ if (keyCount === 2 && wireType === "number" && typeof row.value === "string") {
744
+ return Number(row.value);
745
+ }
746
+ if (keyCount === 1 && wireType === "undefined") return void 0;
747
+ if (keyCount === 3 && wireType === "error" && typeof row.message === "string") {
748
+ const error = new Error(row.message);
749
+ if (typeof row.name === "string") error.name = row.name;
750
+ return error;
751
+ }
752
+ return Object.fromEntries(
753
+ Object.entries(row).map(([key, entry]) => [key, restoreRelayValue(entry)])
754
+ );
755
+ }
756
+ function redactRelayQuoteRaw(quote) {
757
+ return redactRelayValue(quote);
758
+ }
603
759
  function sanitizeRelayQuoteRaw(quote) {
604
- if (!quote.request) return quote;
605
- const request = { ...quote.request };
606
- delete request.headers;
607
- return { ...quote, request };
760
+ return sanitizeRelayValue(quote);
761
+ }
762
+ function restoreRelayQuoteRaw(value) {
763
+ return restoreRelayValue(value);
608
764
  }
609
765
  async function resolveRelayChains(options, client, config = {}) {
610
766
  const preferInjectedClientChains = config.preferInjectedClientChains ?? true;
@@ -618,19 +774,38 @@ function relayQuoteFromExecute(input, quote) {
618
774
  const currencyOut = asRecord(details.currencyOut);
619
775
  const sourceCurrency = asRecord(currencyIn.currency);
620
776
  const destinationCurrency = asRecord(currencyOut.currency);
621
- const source = normalizeToken(input.source.chainId, sourceCurrency) ?? {
622
- chainId: input.source.chainId,
623
- address: input.source.currency,
624
- symbol: "TOKEN",
625
- decimals: 0
626
- };
627
- const destination = normalizeToken(BASE_CHAIN_ID, destinationCurrency) ?? BASE_USDC_ASSET;
777
+ const sourceChainId = asNumber(sourceCurrency.chainId);
778
+ const sourceAddress = asString(sourceCurrency.address);
779
+ const sender = asString(details.sender);
780
+ const recipient = asString(details.recipient);
781
+ const expectedRecipient = input.recipient ?? input.user;
782
+ const destinationChainId = asNumber(destinationCurrency.chainId);
783
+ const destinationAddress = asString(destinationCurrency.address);
784
+ if (sourceChainId !== input.source.chainId || sourceAddress?.toLowerCase() !== input.source.currency.toLowerCase()) {
785
+ throw new Error("Relay quote source does not match the requested asset");
786
+ }
787
+ if (!sender || sender.toLowerCase() !== input.user.toLowerCase()) {
788
+ throw new Error("Relay quote sender does not match the requested wallet");
789
+ }
790
+ if (!recipient || recipient.toLowerCase() !== expectedRecipient.toLowerCase()) {
791
+ throw new Error("Relay quote recipient does not match the requested Base recipient");
792
+ }
793
+ if (destinationChainId !== BASE_CHAIN_ID || destinationAddress?.toLowerCase() !== BASE_USDC_ADDRESS.toLowerCase()) {
794
+ throw new Error("Relay quote destination is not canonical Base USDC");
795
+ }
796
+ const source = normalizeToken(input.source.chainId, sourceCurrency);
797
+ if (!source) throw new Error("Relay quote source metadata is malformed");
798
+ const destination = normalizeToken(destinationChainId, destinationCurrency);
799
+ if (!destination) throw new Error("Relay quote destination metadata is malformed");
628
800
  const txs = quote.steps.flatMap(
629
801
  (step) => step.items.map((item) => normalizeTx(item.data, input.source.chainId)).filter((tx) => tx !== null)
630
802
  );
631
- const outputAmount = BigInt(
632
- String(currencyOut.minimumAmount ?? currencyOut.amount ?? input.amount.toString())
633
- );
803
+ const rawOutputAmount = currencyOut.minimumAmount ?? currencyOut.amount;
804
+ if (rawOutputAmount === void 0 || rawOutputAmount === null) {
805
+ throw new Error("Relay quote is missing an output amount");
806
+ }
807
+ const outputAmount = BigInt(String(rawOutputAmount));
808
+ if (outputAmount <= 0n) throw new Error("Relay quote output amount must be positive");
634
809
  const requestId = quoteRequestId(quote);
635
810
  const rate = asNumber(details.rate);
636
811
  const timeEstimateSeconds = asNumber(details.timeEstimate);
@@ -638,92 +813,135 @@ function relayQuoteFromExecute(input, quote) {
638
813
  ...requestId ? { requestId } : {},
639
814
  source,
640
815
  destination,
641
- inputAmount: BigInt(String(currencyIn.amount ?? input.amount.toString())),
816
+ inputAmount: BigInt(String(currencyIn.amount)),
642
817
  outputAmount,
643
818
  ...rate !== void 0 ? { rate } : {},
644
819
  ...timeEstimateSeconds !== void 0 ? { timeEstimateSeconds } : {},
645
820
  ...quote.fees !== void 0 ? { fees: quote.fees } : {},
646
821
  txs,
647
- raw: sanitizeRelayQuoteRaw(quote)
822
+ raw: redactRelayQuoteRaw(quote)
648
823
  };
649
824
  }
650
825
  async function readRelaySourceCapabilities(options = {}) {
651
- const client = relayClient(options);
652
- const chains = await resolveRelayChains(options, client);
653
- return {
654
- destination: BASE_USDC_ASSET,
655
- chains: chains.map(normalizeChain).filter((chain) => chain.tokens.length > 0 && isSupportedEvmChain(chain)).sort((a, b) => a.displayName.localeCompare(b.displayName)),
656
- source: "relay-sdk",
657
- asOf: Math.floor(Date.now() / 1e3)
658
- };
826
+ try {
827
+ const client = relayClient(options);
828
+ const chains = await resolveRelayChains(options, client);
829
+ return {
830
+ destination: BASE_USDC_ASSET,
831
+ chains: chains.map(normalizeChain).filter((chain) => chain.tokens.length > 0 && isExecutableSourceChain(chain)).sort((a, b) => a.displayName.localeCompare(b.displayName)),
832
+ source: "relay-sdk",
833
+ asOf: Math.floor(Date.now() / 1e3)
834
+ };
835
+ } catch (err) {
836
+ if (isCashError(err)) throw err;
837
+ throw errors.sourceCapabilitiesFailed(err);
838
+ }
659
839
  }
660
840
  async function quoteRelayToBaseUsdc(input, options = {}) {
661
- const client = relayClient(options);
662
- const quote = await client.actions.getQuote(
663
- {
664
- chainId: input.source.chainId,
665
- currency: input.source.currency,
666
- toChainId: BASE_CHAIN_ID,
667
- toCurrency: BASE_USDC_ADDRESS,
668
- user: input.user,
669
- recipient: input.recipient ?? input.user,
670
- amount: input.amount.toString(),
671
- tradeType: input.tradeType ?? "EXACT_INPUT"
672
- },
673
- false
674
- );
675
- return relayQuoteFromExecute(input, quote);
841
+ try {
842
+ if (input.amount <= 0n) throw new Error("Relay quote amount must be positive");
843
+ const client = relayClient(options);
844
+ const quote = await client.actions.getQuote(
845
+ {
846
+ chainId: input.source.chainId,
847
+ currency: input.source.currency,
848
+ toChainId: BASE_CHAIN_ID,
849
+ toCurrency: BASE_USDC_ADDRESS,
850
+ user: input.user,
851
+ recipient: input.recipient ?? input.user,
852
+ amount: input.amount.toString(),
853
+ tradeType: input.tradeType ?? "EXACT_INPUT"
854
+ },
855
+ false
856
+ );
857
+ return relayQuoteFromExecute(input, quote);
858
+ } catch (err) {
859
+ if (isCashError(err)) throw err;
860
+ throw errors.sourceQuoteFailed(err);
861
+ }
676
862
  }
677
863
  async function executeRelayQuote(quote, wallet, options = {}) {
678
- const client = relayClient(options.relay);
679
- const sourceChainId = quoteSourceChainId(quote);
680
- if (sourceChainId !== void 0 && !(client.chains ?? []).some((chain) => chain.id === sourceChainId)) {
681
- await resolveRelayChains(options.relay ?? {}, client, { preferInjectedClientChains: false });
682
- }
683
- const { data } = await client.actions.execute({
684
- quote,
685
- wallet,
686
- ...options.onProgress ? { onProgress: options.onProgress } : {},
687
- ...options.disableCapabilitiesCheck !== void 0 ? { disableCapabilitiesCheck: options.disableCapabilitiesCheck } : {}
688
- });
689
- const requestId = quoteRequestId(data);
690
- return {
691
- ...requestId ? { requestId } : {},
692
- txHashes: data.steps.flatMap(
693
- (step) => step.items.flatMap((item) => (item.txHashes ?? []).map((tx) => tx.txHash))
694
- ),
695
- quote: data
696
- };
864
+ let observedRequestId;
865
+ let observedTransactions = { origin: [], destination: [] };
866
+ try {
867
+ const rawQuote = "raw" in quote ? quote.raw : quote;
868
+ observedRequestId = quoteRequestId(rawQuote);
869
+ assertCanonicalRelayDestination(rawQuote);
870
+ await assertRelayExecutionIdentity(rawQuote, wallet, options.recipient);
871
+ const client = relayClient(options.relay);
872
+ const sourceChainId = quoteSourceChainId(rawQuote);
873
+ if (sourceChainId !== void 0 && !(client.chains ?? []).some((chain) => chain.id === sourceChainId)) {
874
+ await resolveRelayChains(options.relay ?? {}, client, { preferInjectedClientChains: false });
875
+ }
876
+ const onProgress = (data2) => {
877
+ const progressSteps = Array.isArray(data2.steps) ? data2.steps : [];
878
+ observedRequestId = progressSteps.map((step) => step.requestId).find((id) => id !== void 0) ?? observedRequestId;
879
+ observedTransactions = collectRelayTransactions(progressSteps, sourceChainId);
880
+ if (options.onProgress) {
881
+ try {
882
+ options.onProgress(data2);
883
+ } catch {
884
+ }
885
+ }
886
+ };
887
+ const { data } = await client.actions.execute({
888
+ quote: rawQuote,
889
+ wallet,
890
+ onProgress,
891
+ ...options.disableCapabilitiesCheck !== void 0 ? { disableCapabilitiesCheck: options.disableCapabilitiesCheck } : {}
892
+ });
893
+ const requestId = quoteRequestId(data) ?? observedRequestId;
894
+ const transactions = collectRelayTransactions(data.steps, sourceChainId);
895
+ return {
896
+ ...requestId ? { requestId } : {},
897
+ txHashes: relayTransactionHashes(transactions),
898
+ transactions,
899
+ quote: redactRelayQuoteRaw(data)
900
+ };
901
+ } catch (err) {
902
+ if (isCashError(err)) throw err;
903
+ const txHashes = relayTransactionHashes(observedTransactions);
904
+ throw errors.sourceExecutionFailed(err, {
905
+ ...observedRequestId ? { requestId: observedRequestId } : {},
906
+ txHashes,
907
+ ...txHashes.length > 0 ? { transactions: observedTransactions } : {}
908
+ });
909
+ }
697
910
  }
698
911
  async function readRelayStatus(requestId, options = {}) {
699
- const client = relayClient(options);
700
- const response = await client.utils.request({
701
- url: `${client.baseApiUrl}/intents/status/v3`,
702
- method: "get",
703
- params: { requestId }
704
- });
705
- const root = asRecord(response.data);
706
- const status = asString(root.status);
707
- if (status !== "refund" && status !== "waiting" && status !== "depositing" && status !== "failure" && status !== "pending" && status !== "submitted" && status !== "success") {
708
- throw new Error(`Relay returned unknown status: ${String(root.status)}`);
709
- }
710
- const details = asString(root.details);
711
- const updatedAt = asNumber(root.updatedAt);
712
- const originChainId = asNumber(root.originChainId);
713
- const destinationChainId = asNumber(root.destinationChainId);
714
- const quoteCreatedAt = asNumber(root.quoteCreatedAt);
715
- return {
716
- requestId,
717
- status,
718
- ...details ? { details } : {},
719
- inTxHashes: Array.isArray(root.inTxHashes) ? root.inTxHashes.map(String) : [],
720
- txHashes: Array.isArray(root.txHashes) ? root.txHashes.map(String) : [],
721
- ...updatedAt !== void 0 ? { updatedAt } : {},
722
- ...originChainId !== void 0 ? { originChainId } : {},
723
- ...destinationChainId !== void 0 ? { destinationChainId } : {},
724
- ...quoteCreatedAt !== void 0 ? { quoteCreatedAt } : {},
725
- raw: response.data
726
- };
912
+ try {
913
+ const client = relayClient(options);
914
+ const response = await client.utils.request({
915
+ url: `${client.baseApiUrl}/intents/status/v3`,
916
+ method: "get",
917
+ params: { requestId }
918
+ });
919
+ const root = asRecord(response.data);
920
+ const status = asString(root.status);
921
+ if (status !== "refund" && status !== "waiting" && status !== "depositing" && status !== "failure" && status !== "pending" && status !== "submitted" && status !== "success") {
922
+ throw new Error(`Relay returned unknown status: ${String(root.status)}`);
923
+ }
924
+ const details = asString(root.details);
925
+ const updatedAt = asNumber(root.updatedAt);
926
+ const originChainId = asNumber(root.originChainId);
927
+ const destinationChainId = asNumber(root.destinationChainId);
928
+ const quoteCreatedAt = asNumber(root.quoteCreatedAt);
929
+ return {
930
+ requestId,
931
+ status,
932
+ ...details ? { details } : {},
933
+ inTxHashes: Array.isArray(root.inTxHashes) ? root.inTxHashes.map(String) : [],
934
+ txHashes: Array.isArray(root.txHashes) ? root.txHashes.map(String) : [],
935
+ ...updatedAt !== void 0 ? { updatedAt } : {},
936
+ ...originChainId !== void 0 ? { originChainId } : {},
937
+ ...destinationChainId !== void 0 ? { destinationChainId } : {},
938
+ ...quoteCreatedAt !== void 0 ? { quoteCreatedAt } : {},
939
+ raw: response.data
940
+ };
941
+ } catch (err) {
942
+ if (isCashError(err)) throw err;
943
+ throw errors.sourceStatusFailed(requestId, err);
944
+ }
727
945
  }
728
946
 
729
947
  // src/client/estimate.ts
@@ -770,11 +988,16 @@ async function readEstimate(publicClient, input, context = {}) {
770
988
  if (!feedConfig || feedConfig.feed.toLowerCase() === ZERO_ADDRESS) {
771
989
  rate = 1;
772
990
  } else {
773
- const result = await publicClient.readContract({
774
- address: feedConfig.feed,
775
- abi: CHAINLINK_LATEST_ROUND_ABI,
776
- functionName: "latestRoundData"
777
- });
991
+ let result;
992
+ try {
993
+ result = await publicClient.readContract({
994
+ address: feedConfig.feed,
995
+ abi: CHAINLINK_LATEST_ROUND_ABI,
996
+ functionName: "latestRoundData"
997
+ });
998
+ } catch (err) {
999
+ throw errors.oracleReadFailed(currency, err);
1000
+ }
778
1001
  const answer = Number(result[1]);
779
1002
  const price = answer / 10 ** feedConfig.decimals;
780
1003
  if (!Number.isFinite(price) || price <= 0) {
@@ -820,6 +1043,7 @@ async function readEstimate(publicClient, input, context = {}) {
820
1043
  var DEFAULT_RPC_URL = "https://mainnet.base.org";
821
1044
  var CASH_ATTRIBUTION_CODE = "peer-cash";
822
1045
  var DEFAULT_CURATOR_URLS = {
1046
+ preproduction: "https://api-preprod.zkp2p.xyz",
823
1047
  staging: "https://api-staging.zkp2p.xyz"
824
1048
  };
825
1049
  var ERC20_APPROVE_ABI = parseAbi([
@@ -854,12 +1078,29 @@ async function submitAndConfirm(client, verb, send) {
854
1078
  try {
855
1079
  hash = await send();
856
1080
  } catch (err) {
857
- throw mapChainError(verb, err);
1081
+ const mapped = mapChainError(verb, err);
1082
+ if (isKnownPreBroadcastFailure(err, mapped)) throw mapped;
1083
+ throw errors.transactionSubmissionUnknown(verb, err, {
1084
+ kind: "inspect-base-operation-submission",
1085
+ operation: verb
1086
+ });
1087
+ }
1088
+ let receipt;
1089
+ try {
1090
+ receipt = await client.publicClient.waitForTransactionReceipt({ hash });
1091
+ } catch (err) {
1092
+ throw errors.transactionStatusUnknown(hash, err, verb);
858
1093
  }
859
- const receipt = await client.publicClient.waitForTransactionReceipt({ hash });
860
1094
  if (receipt.status === "reverted") throw errors.transactionFailed(hash);
861
1095
  return hash;
862
1096
  }
1097
+ function isKnownPreBroadcastFailure(err, mapped) {
1098
+ if (mapped.code === "INSUFFICIENT_TOKEN_BALANCE" || mapped.code === "ALLOWANCE_NOT_VISIBLE" || mapped.code === "ESCROW_PAUSED") {
1099
+ return true;
1100
+ }
1101
+ const message = err instanceof Error ? err.message : String(err);
1102
+ return /user rejected|user denied|rejected request|action_rejected/i.test(message);
1103
+ }
863
1104
  function depositOrderOptions(deposit) {
864
1105
  const remaining = toBigIntOrUndefined(deposit.remainingDeposits);
865
1106
  const outstanding = toBigIntOrUndefined(deposit.outstandingIntentAmount);
@@ -899,9 +1140,10 @@ function createCashClient(options) {
899
1140
  }
900
1141
  const readClient = buildSdkClient(createWalletClient({ chain: base, transport }));
901
1142
  const signingClients = /* @__PURE__ */ new WeakMap();
902
- function signingClient(verb, opts) {
1143
+ async function signingClient(verb, opts) {
903
1144
  const signer = opts?.signer;
904
1145
  if (!signer?.account) throw errors.signerRequired(verb);
1146
+ await assertWalletChainId(signer, BASE_CHAIN_ID, verb);
905
1147
  let client = signingClients.get(signer);
906
1148
  if (!client) {
907
1149
  client = buildSdkClient(signer);
@@ -911,13 +1153,15 @@ function createCashClient(options) {
911
1153
  }
912
1154
  function validatePayout(input) {
913
1155
  const { receive } = input;
914
- const catalog = getPaymentMethodsCatalog(BASE_CHAIN_ID, environment);
915
- if (!catalog[receive.platform]) throw errors.unsupportedPlatform(receive.platform);
1156
+ const platform = buildCapabilities(environment).platforms.find(
1157
+ (capability) => capability.platform === receive.platform
1158
+ );
1159
+ if (!platform) throw errors.unsupportedPlatform(receive.platform);
916
1160
  if (!isMarketRateSupported(receive.currency)) {
917
1161
  throw errors.oracleUnsupportedCurrency(receive.currency);
918
1162
  }
919
- if (platformRequiresIdentityAttestation(receive.platform) && !receive.payee.identityAttestation) {
920
- throw errors.payeeVerificationRequired(receive.platform);
1163
+ if (!platform.currencies.includes(receive.currency)) {
1164
+ throw errors.unsupportedPlatformCurrency(receive.platform, receive.currency);
921
1165
  }
922
1166
  return {
923
1167
  payouts: [
@@ -926,15 +1170,22 @@ function createCashClient(options) {
926
1170
  currency: receive.currency,
927
1171
  payeeData: receive.payee
928
1172
  }
929
- ],
930
- ...input.intentAmountRange ? { intentAmountRange: input.intentAmountRange } : {}
1173
+ ]
931
1174
  };
932
1175
  }
933
- function validateInput(input) {
934
- if (input.amount < MIN_CASHOUT_AMOUNT) {
935
- throw errors.amountBelowMinimum(input.amount, MIN_CASHOUT_AMOUNT);
1176
+ function validateDepositInput(amount, input, payoutInput = validatePayout(input)) {
1177
+ if (amount < MIN_CASHOUT_AMOUNT) {
1178
+ throw errors.amountBelowMinimum(amount, MIN_CASHOUT_AMOUNT);
936
1179
  }
937
- return { amount: input.amount, ...validatePayout(input) };
1180
+ const range = input.intentAmountRange;
1181
+ if (range && (range.min <= 0n || range.max < range.min || range.max > amount)) {
1182
+ throw errors.invalidIntentAmountRange(amount, range.min, range.max);
1183
+ }
1184
+ return {
1185
+ amount,
1186
+ ...payoutInput,
1187
+ ...range ? { intentAmountRange: range } : {}
1188
+ };
938
1189
  }
939
1190
  async function buildDepositParams(client, depositInput) {
940
1191
  try {
@@ -949,32 +1200,54 @@ function createCashClient(options) {
949
1200
  throw errors.payeeRegistrationFailed(err);
950
1201
  }
951
1202
  }
1203
+ function parseDepositId(depositId) {
1204
+ try {
1205
+ const parsed = parseCompositeDepositId(depositId);
1206
+ return {
1207
+ ...parsed,
1208
+ compositeId: createCompositeDepositId(parsed.escrowAddress, parsed.onchainDepositId)
1209
+ };
1210
+ } catch (err) {
1211
+ throw errors.invalidDepositId(depositId, err);
1212
+ }
1213
+ }
952
1214
  async function fetchOrder(depositId) {
953
- const deposits = await readClient.indexer.getDepositsByIdsWithRelations([depositId], {
954
- includeIntents: true,
955
- intentStatuses: CASH_ORDER_STATUSES
956
- });
1215
+ const { compositeId } = parseDepositId(depositId);
1216
+ let deposits;
1217
+ try {
1218
+ deposits = await readClient.indexer.getDepositsByIdsWithRelations([compositeId], {
1219
+ includeIntents: true,
1220
+ intentStatuses: CASH_ORDER_STATUSES
1221
+ });
1222
+ } catch (err) {
1223
+ throw errors.indexerUnavailable("order", err);
1224
+ }
957
1225
  const deposit = deposits[0];
958
1226
  if (!deposit) {
959
- const intents = await readClient.indexer.getIntentsForDeposits(
960
- [depositId],
961
- CASH_ORDER_STATUSES
962
- );
963
- if (intents.length === 0) throw errors.orderNotFound(depositId);
964
- return deriveCashOrder(depositId, intents);
1227
+ let intents;
1228
+ try {
1229
+ intents = await readClient.indexer.getIntentsForDeposits(
1230
+ [compositeId],
1231
+ CASH_ORDER_STATUSES
1232
+ );
1233
+ } catch (err) {
1234
+ throw errors.indexerUnavailable("order intents", err);
1235
+ }
1236
+ if (intents.length === 0) throw errors.orderNotFound(compositeId);
1237
+ return deriveCashOrder(compositeId, intents);
965
1238
  }
966
1239
  const payouts = derivePayouts(
967
1240
  deposit.paymentMethods ?? [],
968
1241
  deposit.currencies ?? [],
969
1242
  getPaymentMethodsCatalog(BASE_CHAIN_ID, environment)
970
1243
  );
971
- return deriveCashOrder(depositId, deposit.intents ?? [], {
1244
+ return deriveCashOrder(compositeId, deposit.intents ?? [], {
972
1245
  ...depositOrderOptions(deposit),
973
1246
  ...payouts.length > 0 ? { payouts } : {}
974
1247
  });
975
1248
  }
976
1249
  function escrowContext(depositId) {
977
- const { escrowAddress, onchainDepositId } = parseCompositeDepositId(depositId);
1250
+ const { escrowAddress, onchainDepositId } = parseDepositId(depositId);
978
1251
  return {
979
1252
  onchainDepositId,
980
1253
  escrowArg: escrowAddress ? { escrowAddress } : {}
@@ -989,7 +1262,7 @@ function createCashClient(options) {
989
1262
  const signaled = order.fills.filter((f) => f.status === "SIGNALED");
990
1263
  const liveIntent = signaled.some((f) => isFillLive(f, nowSeconds));
991
1264
  const expiredIntent = signaled.length > 0 && !liveIntent;
992
- if (order.pendingAmount > 0n && liveIntent) {
1265
+ if (liveIntent || order.pendingAmount > 0n && signaled.length === 0) {
993
1266
  throw errors.activeIntentBlocksWithdrawal(depositId);
994
1267
  }
995
1268
  if (availableAmount(order) <= 0n && order.pendingAmount === 0n) {
@@ -1030,22 +1303,32 @@ function createCashClient(options) {
1030
1303
  txOverrides: attribution
1031
1304
  });
1032
1305
  } catch (err) {
1033
- throw mapChainError("approve", err);
1306
+ throw mapChainError("approve", err, { requiredAmount: amount });
1034
1307
  }
1035
1308
  if (allowance.hadAllowance || !allowance.hash) return;
1036
- const receipt = await client.publicClient.waitForTransactionReceipt({ hash: allowance.hash });
1309
+ let receipt;
1310
+ try {
1311
+ receipt = await client.publicClient.waitForTransactionReceipt({ hash: allowance.hash });
1312
+ } catch (err) {
1313
+ throw errors.transactionStatusUnknown(allowance.hash, err, "approve");
1314
+ }
1037
1315
  if (receipt.status === "reverted") throw errors.transactionFailed(allowance.hash);
1316
+ let lastReadError;
1038
1317
  for (let attempt = 0; attempt < 15; attempt++) {
1039
- const visible = await client.publicClient.readContract({
1040
- address: token,
1041
- abi: ERC20_ALLOWANCE_ABI,
1042
- functionName: "allowance",
1043
- args: [owner, escrow]
1044
- });
1045
- if (visible >= amount) return;
1318
+ try {
1319
+ const visible = await client.publicClient.readContract({
1320
+ address: token,
1321
+ abi: ERC20_ALLOWANCE_ABI,
1322
+ functionName: "allowance",
1323
+ args: [owner, escrow]
1324
+ });
1325
+ if (visible >= amount) return;
1326
+ } catch (err) {
1327
+ lastReadError = err;
1328
+ }
1046
1329
  await sleep(1e3);
1047
1330
  }
1048
- throw errors.allowanceNotVisible(amount);
1331
+ throw errors.allowanceNotVisible(amount, lastReadError);
1049
1332
  }
1050
1333
  return {
1051
1334
  capabilities,
@@ -1056,8 +1339,10 @@ function createCashClient(options) {
1056
1339
  return quoteRelayToBaseUsdc(input, options.relay);
1057
1340
  },
1058
1341
  async executeSourceQuote(quote, opts) {
1342
+ if (!opts.signer.account) throw errors.signerRequired("executeSourceQuote");
1059
1343
  return executeRelayQuote(quote, opts.signer, {
1060
1344
  ...options.relay ? { relay: options.relay } : {},
1345
+ ...opts.recipient ? { recipient: opts.recipient } : {},
1061
1346
  ...opts.onProgress ? { onProgress: opts.onProgress } : {},
1062
1347
  ...opts.disableCapabilitiesCheck !== void 0 ? { disableCapabilitiesCheck: opts.disableCapabilitiesCheck } : {}
1063
1348
  });
@@ -1073,7 +1358,7 @@ function createCashClient(options) {
1073
1358
  });
1074
1359
  },
1075
1360
  async cashout(input, opts) {
1076
- const client = signingClient("cashout", opts);
1361
+ const client = await signingClient("cashout", opts);
1077
1362
  const owner = opts.signer.account.address;
1078
1363
  const payoutInput = validatePayout(input);
1079
1364
  let sourceResult;
@@ -1081,6 +1366,7 @@ function createCashClient(options) {
1081
1366
  if (input.source) {
1082
1367
  const sourceSigner = opts.sourceSigner ?? (input.source.chainId === BASE_CHAIN_ID ? opts.signer : void 0);
1083
1368
  if (!sourceSigner?.account) throw errors.signerRequired("source cashout");
1369
+ await assertWalletChainId(sourceSigner, input.source.chainId, "source cashout");
1084
1370
  if (input.source.recipient !== void 0 && input.source.recipient.toLowerCase() !== owner.toLowerCase()) {
1085
1371
  throw errors.sourceRecipientMismatch(input.source.recipient, owner);
1086
1372
  }
@@ -1098,20 +1384,23 @@ function createCashClient(options) {
1098
1384
  throw errors.amountBelowMinimum(relayQuote.outputAmount, MIN_CASHOUT_AMOUNT);
1099
1385
  }
1100
1386
  cashoutAmount = relayQuote.outputAmount;
1101
- const depositInput2 = { amount: cashoutAmount, ...payoutInput };
1387
+ const depositInput2 = validateDepositInput(cashoutAmount, input, payoutInput);
1102
1388
  const params2 = await buildDepositParams(client, depositInput2);
1103
1389
  const escrow2 = client.escrowV2Address ?? client.escrowAddress;
1104
1390
  await settleAllowance(client, params2.token, owner, escrow2, depositInput2.amount);
1105
1391
  const executed = await executeRelayQuote(relayQuote.raw, sourceSigner, {
1106
1392
  ...options.relay ? { relay: options.relay } : {},
1393
+ recipient: owner,
1107
1394
  ...opts.onSourceProgress ? { onProgress: opts.onSourceProgress } : {},
1108
1395
  ...opts.disableSourceCapabilitiesCheck !== void 0 ? { disableCapabilitiesCheck: opts.disableSourceCapabilitiesCheck } : {}
1109
1396
  });
1110
- sourceResult = {
1397
+ const routedSource = {
1111
1398
  amount: cashoutAmount,
1112
1399
  ...executed.requestId ? { requestId: executed.requestId } : {},
1113
- txHashes: executed.txHashes
1400
+ txHashes: executed.txHashes,
1401
+ ...executed.transactions ? { transactions: executed.transactions } : {}
1114
1402
  };
1403
+ sourceResult = routedSource;
1115
1404
  const attributedParams2 = { ...params2, txOverrides: attribution };
1116
1405
  const send2 = async () => {
1117
1406
  try {
@@ -1128,10 +1417,26 @@ function createCashClient(options) {
1128
1417
  try {
1129
1418
  hash2 = await send2();
1130
1419
  } catch (err) {
1131
- throw mapChainError("createDeposit", err);
1420
+ const mapped = mapChainError("createDeposit", err, {
1421
+ requiredAmount: depositInput2.amount
1422
+ });
1423
+ if (isKnownPreBroadcastFailure(err, mapped)) {
1424
+ throw errors.sourceRouteCompletedCashoutFailed(routedSource, mapped);
1425
+ }
1426
+ throw errors.sourceCashoutSubmissionUnknown(routedSource, owner, mapped);
1427
+ }
1428
+ let receipt2;
1429
+ try {
1430
+ receipt2 = await client.publicClient.waitForTransactionReceipt({ hash: hash2 });
1431
+ } catch (err) {
1432
+ throw errors.sourceCashoutStatusUnknown(routedSource, hash2, err);
1433
+ }
1434
+ if (receipt2.status === "reverted") {
1435
+ throw errors.sourceRouteCompletedCashoutFailed(
1436
+ routedSource,
1437
+ errors.transactionFailed(hash2)
1438
+ );
1132
1439
  }
1133
- const receipt2 = await client.publicClient.waitForTransactionReceipt({ hash: hash2 });
1134
- if (receipt2.status === "reverted") throw errors.transactionFailed(hash2);
1135
1440
  const abi2 = client.escrowV2Abi ?? client.escrowAbi;
1136
1441
  const resolved2 = resolveCashDepositId({ logs: receipt2.logs, abi: abi2 });
1137
1442
  if (!resolved2) throw errors.depositResolutionFailed(hash2);
@@ -1145,10 +1450,10 @@ function createCashClient(options) {
1145
1450
  escrowAddress: resolved2.escrowAddress,
1146
1451
  onchainDepositId: resolved2.onchainDepositId,
1147
1452
  order: order2,
1148
- source: sourceResult
1453
+ source: routedSource
1149
1454
  };
1150
1455
  }
1151
- const depositInput = validateInput(input);
1456
+ const depositInput = validateDepositInput(input.amount, input, payoutInput);
1152
1457
  const params = await buildDepositParams(client, depositInput);
1153
1458
  const escrow = client.escrowV2Address ?? client.escrowAddress;
1154
1459
  await settleAllowance(client, params.token, owner, escrow, depositInput.amount);
@@ -1168,9 +1473,23 @@ function createCashClient(options) {
1168
1473
  try {
1169
1474
  hash = await send();
1170
1475
  } catch (err) {
1171
- throw mapChainError("createDeposit", err);
1476
+ const mapped = mapChainError("createDeposit", err, {
1477
+ requiredAmount: depositInput.amount
1478
+ });
1479
+ if (isKnownPreBroadcastFailure(err, mapped)) throw mapped;
1480
+ throw errors.transactionSubmissionUnknown("cashout", err, {
1481
+ kind: "inspect-base-cashout-submission",
1482
+ amount: depositInput.amount.toString(),
1483
+ depositor: owner,
1484
+ txHashes: []
1485
+ });
1486
+ }
1487
+ let receipt;
1488
+ try {
1489
+ receipt = await client.publicClient.waitForTransactionReceipt({ hash });
1490
+ } catch (err) {
1491
+ throw errors.transactionStatusUnknown(hash, err, "cashout");
1172
1492
  }
1173
- const receipt = await client.publicClient.waitForTransactionReceipt({ hash });
1174
1493
  if (receipt.status === "reverted") throw errors.transactionFailed(hash);
1175
1494
  const abi = client.escrowV2Abi ?? client.escrowAbi;
1176
1495
  const resolved = resolveCashDepositId({ logs: receipt.logs, abi });
@@ -1190,7 +1509,7 @@ function createCashClient(options) {
1190
1509
  },
1191
1510
  async prepare(input) {
1192
1511
  if (input.source) throw errors.sourceRouteUnsupportedInPrepare();
1193
- const depositInput = validateInput(input);
1512
+ const depositInput = validateDepositInput(input.amount, input);
1194
1513
  const params = await buildDepositParams(readClient, depositInput);
1195
1514
  const { prepared } = await readClient.prepareCreateDeposit({
1196
1515
  ...params,
@@ -1229,13 +1548,46 @@ function createCashClient(options) {
1229
1548
  return fetchOrder(depositId);
1230
1549
  },
1231
1550
  async buyer(address) {
1232
- const intents = await readClient.indexer.getOwnerIntents(address, CASH_ORDER_STATUSES);
1551
+ let intents;
1552
+ try {
1553
+ intents = await readClient.indexer.getOwnerIntents(address, CASH_ORDER_STATUSES);
1554
+ } catch (err) {
1555
+ throw errors.indexerUnavailable("buyer profile", err);
1556
+ }
1233
1557
  return deriveBuyerProfile(address, intents);
1234
1558
  },
1235
1559
  async orders(owner, opts = {}) {
1236
1560
  const { inFlight = false, limit = 100 } = opts;
1237
- const deposits = await readClient.indexer.getDeposits({ depositor: owner }, { limit });
1238
- const derived = deposits.map((d) => deriveCashOrder(d.id, [], { ...depositOrderOptions(d), fillsIncluded: false })).filter((o) => o.totalAmount > 10000n).sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
1561
+ let deposits;
1562
+ try {
1563
+ deposits = await readClient.indexer.getDepositsWithRelations(
1564
+ { depositor: owner },
1565
+ { limit }
1566
+ );
1567
+ } catch (err) {
1568
+ throw errors.indexerUnavailable("orders", err);
1569
+ }
1570
+ const catalog = getPaymentMethodsCatalog(BASE_CHAIN_ID, environment);
1571
+ const derived = deposits.flatMap((deposit) => {
1572
+ if (deposit.token.toLowerCase() !== BASE_USDC_ADDRESS.toLowerCase()) return [];
1573
+ const payouts = derivePayouts(
1574
+ deposit.paymentMethods ?? [],
1575
+ deposit.currencies ?? [],
1576
+ catalog
1577
+ );
1578
+ if (payouts.length !== 1 || !payouts.every((payout) => payout.pricing.marketRate && payout.pricing.spreadBps === 0)) {
1579
+ return [];
1580
+ }
1581
+ return [
1582
+ deriveCashOrder(deposit.id, [], {
1583
+ ...depositOrderOptions(deposit),
1584
+ payouts,
1585
+ // List rows carry no intent detail - a positive outstanding
1586
+ // amount is treated conservatively as a live lock.
1587
+ fillsIncluded: false
1588
+ })
1589
+ ];
1590
+ }).filter((o) => o.totalAmount >= MIN_CASHOUT_AMOUNT).sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
1239
1591
  return inFlight ? derived.filter((o) => o.isInFlight) : derived;
1240
1592
  },
1241
1593
  async *watch(depositId, opts = {}) {
@@ -1265,7 +1617,7 @@ function createCashClient(options) {
1265
1617
  }
1266
1618
  },
1267
1619
  async withdraw(depositId, opts) {
1268
- const client = signingClient("withdraw", opts);
1620
+ const client = await signingClient("withdraw", opts);
1269
1621
  if (opts.amount !== void 0) {
1270
1622
  const { onchainDepositId: onchainDepositId2, escrowArg: escrowArg2 } = await partialWithdrawContext(
1271
1623
  depositId,
@@ -1363,7 +1715,7 @@ function createCashClient(options) {
1363
1715
  return { txs, steps };
1364
1716
  },
1365
1717
  async topUp(depositId, amount, opts) {
1366
- const client = signingClient("topUp", opts);
1718
+ const client = await signingClient("topUp", opts);
1367
1719
  const { onchainDepositId, escrowArg } = await topUpContext(depositId, amount);
1368
1720
  const owner = opts.signer.account.address;
1369
1721
  const escrow = escrowArg.escrowAddress ?? client.escrowV2Address ?? client.escrowAddress;
@@ -1418,6 +1770,39 @@ function createCashClient(options) {
1418
1770
  };
1419
1771
  }
1420
1772
  var bigintString = z.string().regex(/^-?\d+$/, "expected a decimal bigint string");
1773
+ var nonNegativeBigintString = z.string().regex(/^\d+$/, "expected a non-negative decimal bigint string");
1774
+ var relayTransactionJsonSchema = z.object({
1775
+ hash: z.string(),
1776
+ chainId: z.number()
1777
+ });
1778
+ var relayTransactionsJsonSchema = z.object({
1779
+ origin: z.array(relayTransactionJsonSchema),
1780
+ destination: z.array(relayTransactionJsonSchema)
1781
+ }).strict();
1782
+ var cashAssetJsonSchema = z.object({
1783
+ chainId: z.number(),
1784
+ address: z.string(),
1785
+ symbol: z.string(),
1786
+ decimals: z.number(),
1787
+ name: z.string().optional(),
1788
+ isNative: z.boolean().optional()
1789
+ });
1790
+ var cashChainJsonSchema = z.object({
1791
+ id: z.number(),
1792
+ name: z.string(),
1793
+ displayName: z.string(),
1794
+ disabled: z.boolean(),
1795
+ depositEnabled: z.boolean(),
1796
+ blockProductionLagging: z.boolean(),
1797
+ vmType: z.string().optional(),
1798
+ tokens: z.array(cashAssetJsonSchema)
1799
+ });
1800
+ var cashSourceCapabilitiesJsonSchema = z.object({
1801
+ destination: cashAssetJsonSchema,
1802
+ chains: z.array(cashChainJsonSchema),
1803
+ source: z.literal("relay-sdk"),
1804
+ asOf: z.number()
1805
+ });
1421
1806
  var cashOrderStateSchema = z.enum([
1422
1807
  "awaiting-buyer",
1423
1808
  "matched",
@@ -1430,18 +1815,18 @@ var intentStatusSchema = z.enum(["SIGNALED", "FULFILLED", "PRUNED", "MANUALLY_RE
1430
1815
  var cashFillJsonSchema = z.object({
1431
1816
  intentHash: z.string(),
1432
1817
  status: intentStatusSchema,
1433
- amount: bigintString,
1818
+ amount: nonNegativeBigintString,
1434
1819
  buyer: z.string(),
1435
1820
  currency: z.string().optional(),
1436
1821
  currencyHash: z.string().optional(),
1437
1822
  rate: z.number().optional(),
1438
- conversionRate: bigintString.optional(),
1823
+ conversionRate: nonNegativeBigintString.optional(),
1439
1824
  fiatOwed: z.number().optional(),
1440
1825
  fiatPaid: z.number().optional(),
1441
1826
  paidCurrency: z.string().optional(),
1442
1827
  paymentId: z.string().optional(),
1443
1828
  paidAt: z.number().optional(),
1444
- releasedAmount: bigintString.optional(),
1829
+ releasedAmount: nonNegativeBigintString.optional(),
1445
1830
  fillLatencySeconds: z.number().optional(),
1446
1831
  isExpired: z.boolean().optional(),
1447
1832
  signaledAt: z.number().optional(),
@@ -1480,10 +1865,10 @@ var cashOrderJsonSchema = z.object({
1480
1865
  depositId: z.string(),
1481
1866
  state: cashOrderStateSchema,
1482
1867
  fills: z.array(cashFillJsonSchema),
1483
- totalAmount: bigintString,
1484
- filledAmount: bigintString,
1485
- pendingAmount: bigintString,
1486
- returnedAmount: bigintString,
1868
+ totalAmount: nonNegativeBigintString,
1869
+ filledAmount: nonNegativeBigintString,
1870
+ pendingAmount: nonNegativeBigintString,
1871
+ returnedAmount: nonNegativeBigintString,
1487
1872
  nextActions: z.array(cashNextActionSchema),
1488
1873
  primaryIntentHash: z.string().optional(),
1489
1874
  matchedAt: z.number().optional(),
@@ -1498,7 +1883,7 @@ var cashOrderJsonSchema = z.object({
1498
1883
  var cashEstimateJsonSchema = z.object({
1499
1884
  kind: z.literal("oracle-estimate"),
1500
1885
  currency: z.string(),
1501
- amount: bigintString,
1886
+ amount: nonNegativeBigintString,
1502
1887
  rate: z.number(),
1503
1888
  receiveAmount: z.number(),
1504
1889
  asOf: z.number(),
@@ -1514,7 +1899,7 @@ var cashEstimateJsonSchema = z.object({
1514
1899
  name: z.string().optional(),
1515
1900
  isNative: z.boolean().optional()
1516
1901
  }),
1517
- inputAmount: bigintString,
1902
+ inputAmount: nonNegativeBigintString,
1518
1903
  relayQuote: z.object({
1519
1904
  requestId: z.string().optional(),
1520
1905
  source: z.object({
@@ -1533,8 +1918,8 @@ var cashEstimateJsonSchema = z.object({
1533
1918
  name: z.string().optional(),
1534
1919
  isNative: z.boolean().optional()
1535
1920
  }),
1536
- inputAmount: bigintString,
1537
- outputAmount: bigintString,
1921
+ inputAmount: nonNegativeBigintString,
1922
+ outputAmount: nonNegativeBigintString,
1538
1923
  rate: z.number().optional(),
1539
1924
  timeEstimateSeconds: z.number().optional(),
1540
1925
  fees: z.unknown().optional(),
@@ -1542,7 +1927,7 @@ var cashEstimateJsonSchema = z.object({
1542
1927
  z.object({
1543
1928
  to: z.string(),
1544
1929
  data: z.string(),
1545
- value: bigintString,
1930
+ value: nonNegativeBigintString,
1546
1931
  chainId: z.number()
1547
1932
  })
1548
1933
  ),
@@ -1557,9 +1942,39 @@ var cashEstimateJsonSchema = z.object({
1557
1942
  var preparedTransactionJsonSchema = z.object({
1558
1943
  to: z.string(),
1559
1944
  data: z.string(),
1560
- value: bigintString,
1945
+ value: nonNegativeBigintString,
1561
1946
  chainId: z.number()
1562
1947
  });
1948
+ var relayQuoteJsonSchema = z.object({
1949
+ requestId: z.string().optional(),
1950
+ source: cashAssetJsonSchema,
1951
+ destination: cashAssetJsonSchema,
1952
+ inputAmount: nonNegativeBigintString,
1953
+ outputAmount: nonNegativeBigintString,
1954
+ rate: z.number().optional(),
1955
+ timeEstimateSeconds: z.number().optional(),
1956
+ fees: z.unknown().optional(),
1957
+ txs: z.array(preparedTransactionJsonSchema),
1958
+ raw: z.unknown()
1959
+ });
1960
+ var relayStatusJsonSchema = z.object({
1961
+ requestId: z.string(),
1962
+ status: z.enum(["refund", "waiting", "depositing", "failure", "pending", "submitted", "success"]),
1963
+ details: z.string().optional(),
1964
+ inTxHashes: z.array(z.string()),
1965
+ txHashes: z.array(z.string()),
1966
+ updatedAt: z.number().optional(),
1967
+ originChainId: z.number().optional(),
1968
+ destinationChainId: z.number().optional(),
1969
+ quoteCreatedAt: z.number().optional(),
1970
+ raw: z.unknown()
1971
+ });
1972
+ var relayExecutionResultJsonSchema = z.object({
1973
+ requestId: z.string().optional(),
1974
+ txHashes: z.array(z.string()),
1975
+ transactions: relayTransactionsJsonSchema.optional(),
1976
+ quote: z.unknown()
1977
+ });
1563
1978
  var cashPreparedStepJsonSchema = z.object({
1564
1979
  kind: z.enum([
1565
1980
  "approve",
@@ -1575,12 +1990,13 @@ var cashoutResultJsonSchema = z.object({
1575
1990
  depositId: z.string(),
1576
1991
  txHash: z.string(),
1577
1992
  escrowAddress: z.string(),
1578
- onchainDepositId: bigintString,
1993
+ onchainDepositId: nonNegativeBigintString,
1579
1994
  order: cashOrderJsonSchema,
1580
1995
  source: z.object({
1581
- amount: bigintString,
1996
+ amount: nonNegativeBigintString,
1582
1997
  requestId: z.string().optional(),
1583
- txHashes: z.array(z.string())
1998
+ txHashes: z.array(z.string()),
1999
+ transactions: relayTransactionsJsonSchema.optional()
1584
2000
  }).optional()
1585
2001
  });
1586
2002
  var prepareResultJsonSchema = z.object({
@@ -1610,39 +2026,7 @@ var cashCapabilitiesJsonSchema = z.object({
1610
2026
  chainId: z.number(),
1611
2027
  token: z.object({ address: z.string(), symbol: z.literal("USDC"), decimals: z.number() })
1612
2028
  }),
1613
- relay: z.object({
1614
- destination: z.object({
1615
- chainId: z.number(),
1616
- address: z.string(),
1617
- symbol: z.string(),
1618
- decimals: z.number(),
1619
- name: z.string().optional(),
1620
- isNative: z.boolean().optional()
1621
- }),
1622
- chains: z.array(
1623
- z.object({
1624
- id: z.number(),
1625
- name: z.string(),
1626
- displayName: z.string(),
1627
- disabled: z.boolean(),
1628
- depositEnabled: z.boolean(),
1629
- blockProductionLagging: z.boolean(),
1630
- vmType: z.string().optional(),
1631
- tokens: z.array(
1632
- z.object({
1633
- chainId: z.number(),
1634
- address: z.string(),
1635
- symbol: z.string(),
1636
- decimals: z.number(),
1637
- name: z.string().optional(),
1638
- isNative: z.boolean().optional()
1639
- })
1640
- )
1641
- })
1642
- ),
1643
- source: z.literal("relay-sdk"),
1644
- asOf: z.number()
1645
- }).optional()
2029
+ relay: cashSourceCapabilitiesJsonSchema.optional()
1646
2030
  }),
1647
2031
  platforms: z.array(
1648
2032
  z.object({
@@ -1653,15 +2037,98 @@ var cashCapabilitiesJsonSchema = z.object({
1653
2037
  })
1654
2038
  ),
1655
2039
  currencies: z.array(z.string()),
1656
- amount: z.object({ min: bigintString, recommendedMin: bigintString, max: z.null() }),
2040
+ amount: z.object({
2041
+ min: nonNegativeBigintString,
2042
+ recommendedMin: nonNegativeBigintString,
2043
+ max: z.null()
2044
+ }),
1657
2045
  pricing: z.object({ kind: z.literal("oracle-market-rate"), spreadBps: z.literal(0) })
1658
2046
  });
2047
+ function defineCashErrorCodes(codes) {
2048
+ return codes;
2049
+ }
2050
+ var CASH_ERROR_CODES = defineCashErrorCodes([
2051
+ "ORACLE_UNSUPPORTED_CURRENCY",
2052
+ "ORACLE_READ_FAILED",
2053
+ "UNSUPPORTED_PLATFORM",
2054
+ "UNSUPPORTED_PLATFORM_CURRENCY",
2055
+ "AMOUNT_BELOW_MINIMUM",
2056
+ "INVALID_INTENT_AMOUNT_RANGE",
2057
+ "ACTIVE_INTENT_BLOCKS_WITHDRAWAL",
2058
+ "NOTHING_TO_WITHDRAW",
2059
+ "INSUFFICIENT_AVAILABLE_FUNDS",
2060
+ "INSUFFICIENT_TOKEN_BALANCE",
2061
+ "ORDER_NOT_ACTIVE",
2062
+ "INVALID_DEPOSIT_ID",
2063
+ "ESCROW_PAUSED",
2064
+ "INDEXER_LAG",
2065
+ "INDEXER_UNAVAILABLE",
2066
+ "ORDER_NOT_FOUND",
2067
+ "PAYEE_REGISTRATION_FAILED",
2068
+ "PAYEE_VERIFICATION_REQUIRED",
2069
+ "SOURCE_ROUTE_UNSUPPORTED_IN_PREPARE",
2070
+ "SOURCE_RECIPIENT_MISMATCH",
2071
+ "SOURCE_CAPABILITIES_FAILED",
2072
+ "SOURCE_QUOTE_FAILED",
2073
+ "SOURCE_EXECUTION_FAILED",
2074
+ "SOURCE_STATUS_FAILED",
2075
+ "SOURCE_ROUTE_COMPLETED_CASHOUT_FAILED",
2076
+ "SOURCE_CASHOUT_SUBMISSION_UNKNOWN",
2077
+ "SOURCE_CASHOUT_STATUS_UNKNOWN",
2078
+ "DEPOSIT_RESOLUTION_FAILED",
2079
+ "ALLOWANCE_NOT_VISIBLE",
2080
+ "SIGNER_REQUIRED",
2081
+ "SIGNER_CHAIN_MISMATCH",
2082
+ "SIGNER_CHAIN_UNAVAILABLE",
2083
+ "WATCH_TIMEOUT",
2084
+ "TRANSACTION_FAILED",
2085
+ "TRANSACTION_SUBMISSION_UNKNOWN",
2086
+ "TRANSACTION_STATUS_UNKNOWN"
2087
+ ]);
2088
+ var cashSourceRecoveryJsonShape = {
2089
+ amount: nonNegativeBigintString,
2090
+ requestId: z.string().optional(),
2091
+ txHashes: z.array(z.string()),
2092
+ transactions: relayTransactionsJsonSchema.optional()
2093
+ };
2094
+ var cashErrorRecoveryJsonSchema = z.discriminatedUnion("kind", [
2095
+ z.object({
2096
+ ...cashSourceRecoveryJsonShape,
2097
+ kind: z.literal("retry-base-usdc-cashout")
2098
+ }).strict(),
2099
+ z.object({
2100
+ ...cashSourceRecoveryJsonShape,
2101
+ kind: z.literal("inspect-base-cashout-transaction"),
2102
+ depositTxHash: z.string()
2103
+ }).strict(),
2104
+ z.object({
2105
+ ...cashSourceRecoveryJsonShape,
2106
+ kind: z.literal("inspect-base-cashout-submission"),
2107
+ depositor: z.string()
2108
+ }).strict(),
2109
+ z.object({
2110
+ kind: z.literal("inspect-relay-route"),
2111
+ requestId: z.string().optional(),
2112
+ txHashes: z.array(z.string()),
2113
+ transactions: relayTransactionsJsonSchema.optional()
2114
+ }).strict(),
2115
+ z.object({
2116
+ kind: z.literal("inspect-base-operation-submission"),
2117
+ operation: z.string()
2118
+ }).strict(),
2119
+ z.object({
2120
+ kind: z.literal("inspect-base-transaction"),
2121
+ transactionHash: z.string(),
2122
+ operation: z.string()
2123
+ }).strict()
2124
+ ]);
1659
2125
  var cashErrorJsonSchema = z.object({
1660
- code: z.string(),
2126
+ code: z.enum(CASH_ERROR_CODES),
1661
2127
  message: z.string(),
1662
2128
  retryable: z.boolean(),
1663
- remediation: z.string()
1664
- });
2129
+ remediation: z.string(),
2130
+ recovery: cashErrorRecoveryJsonSchema.optional()
2131
+ }).strict();
1665
2132
 
1666
2133
  // src/codecs/json.ts
1667
2134
  function omitUndefined(obj) {
@@ -1692,35 +2159,38 @@ function fillToJson(fill) {
1692
2159
  });
1693
2160
  }
1694
2161
  function fillFromJson(json) {
2162
+ const parsed = cashFillJsonSchema.parse(json);
1695
2163
  return omitUndefined({
1696
- ...json,
1697
- amount: BigInt(json.amount),
1698
- conversionRate: json.conversionRate !== void 0 ? BigInt(json.conversionRate) : void 0,
1699
- releasedAmount: json.releasedAmount !== void 0 ? BigInt(json.releasedAmount) : void 0
2164
+ ...parsed,
2165
+ amount: BigInt(parsed.amount),
2166
+ conversionRate: parsed.conversionRate !== void 0 ? BigInt(parsed.conversionRate) : void 0,
2167
+ releasedAmount: parsed.releasedAmount !== void 0 ? BigInt(parsed.releasedAmount) : void 0
1700
2168
  });
1701
2169
  }
1702
2170
  function orderToJson(order) {
1703
- return omitUndefined({
1704
- depositId: order.depositId,
1705
- state: order.state,
1706
- fills: order.fills.map(fillToJson),
1707
- totalAmount: order.totalAmount.toString(),
1708
- filledAmount: order.filledAmount.toString(),
1709
- pendingAmount: order.pendingAmount.toString(),
1710
- returnedAmount: order.returnedAmount.toString(),
1711
- nextActions: order.nextActions,
1712
- primaryIntentHash: order.primaryIntentHash,
1713
- matchedAt: order.matchedAt,
1714
- deliveredAt: order.deliveredAt,
1715
- updatedAt: order.updatedAt,
1716
- intentCount: order.intentCount,
1717
- payouts: order.payouts?.map(
1718
- (p) => omitUndefined({ ...p, pricing: omitUndefined({ ...p.pricing }) })
1719
- ),
1720
- successRateBps: order.successRateBps,
1721
- isInFlight: order.isInFlight,
1722
- withdrawn: order.withdrawn
1723
- });
2171
+ return cashOrderJsonSchema.parse(
2172
+ omitUndefined({
2173
+ depositId: order.depositId,
2174
+ state: order.state,
2175
+ fills: order.fills.map(fillToJson),
2176
+ totalAmount: order.totalAmount.toString(),
2177
+ filledAmount: order.filledAmount.toString(),
2178
+ pendingAmount: order.pendingAmount.toString(),
2179
+ returnedAmount: order.returnedAmount.toString(),
2180
+ nextActions: order.nextActions,
2181
+ primaryIntentHash: order.primaryIntentHash,
2182
+ matchedAt: order.matchedAt,
2183
+ deliveredAt: order.deliveredAt,
2184
+ updatedAt: order.updatedAt,
2185
+ intentCount: order.intentCount,
2186
+ payouts: order.payouts?.map(
2187
+ (p) => omitUndefined({ ...p, pricing: omitUndefined({ ...p.pricing }) })
2188
+ ),
2189
+ successRateBps: order.successRateBps,
2190
+ isInFlight: order.isInFlight,
2191
+ withdrawn: order.withdrawn
2192
+ })
2193
+ );
1724
2194
  }
1725
2195
  function orderFromJson(json) {
1726
2196
  const parsed = cashOrderJsonSchema.parse(json);
@@ -1746,6 +2216,7 @@ function estimateToJson(estimate) {
1746
2216
  inputAmount: estimate.source.relayQuote.inputAmount.toString(),
1747
2217
  outputAmount: estimate.source.relayQuote.outputAmount.toString(),
1748
2218
  txs: estimate.source.relayQuote.txs.map(preparedTxToJson),
2219
+ ...estimate.source.relayQuote.fees !== void 0 ? { fees: sanitizeRelayValue(estimate.source.relayQuote.fees) } : {},
1749
2220
  raw: sanitizeRelayQuoteRaw(estimate.source.relayQuote.raw)
1750
2221
  }
1751
2222
  } : void 0
@@ -1764,11 +2235,108 @@ function estimateFromJson(json) {
1764
2235
  ...parsed.source.relayQuote,
1765
2236
  inputAmount: BigInt(parsed.source.relayQuote.inputAmount),
1766
2237
  outputAmount: BigInt(parsed.source.relayQuote.outputAmount),
1767
- txs: parsed.source.relayQuote.txs.map(preparedTxFromJson)
2238
+ txs: parsed.source.relayQuote.txs.map(preparedTxFromJson),
2239
+ ...parsed.source.relayQuote.fees !== void 0 ? { fees: restoreRelayValue(parsed.source.relayQuote.fees) } : {},
2240
+ raw: restoreRelayQuoteRaw(parsed.source.relayQuote.raw)
1768
2241
  }
1769
2242
  } : void 0
1770
2243
  });
1771
2244
  }
2245
+ function cashAssetFromJson(asset) {
2246
+ return {
2247
+ chainId: asset.chainId,
2248
+ address: asset.address,
2249
+ symbol: asset.symbol,
2250
+ decimals: asset.decimals,
2251
+ ...asset.name !== void 0 ? { name: asset.name } : {},
2252
+ ...asset.isNative !== void 0 ? { isNative: asset.isNative } : {}
2253
+ };
2254
+ }
2255
+ function relayQuoteToJson(quote) {
2256
+ return relayQuoteJsonSchema.parse({
2257
+ ...quote.requestId !== void 0 ? { requestId: quote.requestId } : {},
2258
+ source: quote.source,
2259
+ destination: quote.destination,
2260
+ inputAmount: quote.inputAmount.toString(),
2261
+ outputAmount: quote.outputAmount.toString(),
2262
+ ...quote.rate !== void 0 ? { rate: quote.rate } : {},
2263
+ ...quote.timeEstimateSeconds !== void 0 ? { timeEstimateSeconds: quote.timeEstimateSeconds } : {},
2264
+ ...quote.fees !== void 0 ? { fees: sanitizeRelayValue(quote.fees) } : {},
2265
+ txs: quote.txs.map(preparedTxToJson),
2266
+ raw: sanitizeRelayQuoteRaw(quote.raw)
2267
+ });
2268
+ }
2269
+ function relayQuoteFromJson(json) {
2270
+ const parsed = relayQuoteJsonSchema.parse(json);
2271
+ return {
2272
+ ...parsed.requestId !== void 0 ? { requestId: parsed.requestId } : {},
2273
+ source: cashAssetFromJson(parsed.source),
2274
+ destination: cashAssetFromJson(parsed.destination),
2275
+ inputAmount: BigInt(parsed.inputAmount),
2276
+ outputAmount: BigInt(parsed.outputAmount),
2277
+ ...parsed.rate !== void 0 ? { rate: parsed.rate } : {},
2278
+ ...parsed.timeEstimateSeconds !== void 0 ? { timeEstimateSeconds: parsed.timeEstimateSeconds } : {},
2279
+ ...parsed.fees !== void 0 ? { fees: restoreRelayValue(parsed.fees) } : {},
2280
+ txs: parsed.txs.map(preparedTxFromJson),
2281
+ raw: restoreRelayQuoteRaw(parsed.raw)
2282
+ };
2283
+ }
2284
+ function sourceCapabilitiesToJson(capabilities) {
2285
+ return cashSourceCapabilitiesJsonSchema.parse(capabilities);
2286
+ }
2287
+ function sourceCapabilitiesFromJson(json) {
2288
+ const parsed = cashSourceCapabilitiesJsonSchema.parse(json);
2289
+ return {
2290
+ destination: cashAssetFromJson(parsed.destination),
2291
+ chains: parsed.chains.map((chain) => ({
2292
+ id: chain.id,
2293
+ name: chain.name,
2294
+ displayName: chain.displayName,
2295
+ disabled: chain.disabled,
2296
+ depositEnabled: chain.depositEnabled,
2297
+ blockProductionLagging: chain.blockProductionLagging,
2298
+ ...chain.vmType !== void 0 ? { vmType: chain.vmType } : {},
2299
+ tokens: chain.tokens.map(cashAssetFromJson)
2300
+ })),
2301
+ source: parsed.source,
2302
+ asOf: parsed.asOf
2303
+ };
2304
+ }
2305
+ function relayStatusToJson(status) {
2306
+ return relayStatusJsonSchema.parse({ ...status, raw: sanitizeRelayValue(status.raw) });
2307
+ }
2308
+ function relayStatusFromJson(json) {
2309
+ const parsed = relayStatusJsonSchema.parse(json);
2310
+ return {
2311
+ requestId: parsed.requestId,
2312
+ status: parsed.status,
2313
+ ...parsed.details !== void 0 ? { details: parsed.details } : {},
2314
+ inTxHashes: parsed.inTxHashes,
2315
+ txHashes: parsed.txHashes,
2316
+ ...parsed.updatedAt !== void 0 ? { updatedAt: parsed.updatedAt } : {},
2317
+ ...parsed.originChainId !== void 0 ? { originChainId: parsed.originChainId } : {},
2318
+ ...parsed.destinationChainId !== void 0 ? { destinationChainId: parsed.destinationChainId } : {},
2319
+ ...parsed.quoteCreatedAt !== void 0 ? { quoteCreatedAt: parsed.quoteCreatedAt } : {},
2320
+ raw: restoreRelayValue(parsed.raw)
2321
+ };
2322
+ }
2323
+ function relayExecutionResultToJson(result) {
2324
+ return relayExecutionResultJsonSchema.parse({
2325
+ ...result.requestId !== void 0 ? { requestId: result.requestId } : {},
2326
+ txHashes: result.txHashes,
2327
+ ...result.transactions !== void 0 ? { transactions: result.transactions } : {},
2328
+ quote: sanitizeRelayQuoteRaw(result.quote)
2329
+ });
2330
+ }
2331
+ function relayExecutionResultFromJson(json) {
2332
+ const parsed = relayExecutionResultJsonSchema.parse(json);
2333
+ return {
2334
+ ...parsed.requestId !== void 0 ? { requestId: parsed.requestId } : {},
2335
+ txHashes: parsed.txHashes,
2336
+ ...parsed.transactions !== void 0 ? { transactions: parsed.transactions } : {},
2337
+ quote: restoreRelayQuoteRaw(parsed.quote)
2338
+ };
2339
+ }
1772
2340
  function preparedTxToJson(tx) {
1773
2341
  return { to: tx.to, data: tx.data, value: tx.value.toString(), chainId: tx.chainId };
1774
2342
  }
@@ -1887,7 +2455,68 @@ function capabilitiesFromJson(json) {
1887
2455
  }
1888
2456
  };
1889
2457
  }
2458
+ function cashErrorToJson(error) {
2459
+ return cashErrorJsonSchema.parse({
2460
+ code: error.code,
2461
+ message: error.message,
2462
+ retryable: error.retryable,
2463
+ remediation: error.remediation,
2464
+ ...error.recovery ? { recovery: error.recovery } : {}
2465
+ });
2466
+ }
2467
+ function cashErrorFromJson(json) {
2468
+ const parsed = cashErrorJsonSchema.parse(json);
2469
+ let recovery;
2470
+ if (parsed.recovery) {
2471
+ if (parsed.recovery.kind === "inspect-base-transaction") {
2472
+ recovery = {
2473
+ kind: parsed.recovery.kind,
2474
+ transactionHash: parsed.recovery.transactionHash,
2475
+ operation: parsed.recovery.operation
2476
+ };
2477
+ } else if (parsed.recovery.kind === "inspect-base-operation-submission") {
2478
+ recovery = {
2479
+ kind: parsed.recovery.kind,
2480
+ operation: parsed.recovery.operation
2481
+ };
2482
+ } else if (parsed.recovery.kind === "inspect-relay-route") {
2483
+ recovery = {
2484
+ kind: parsed.recovery.kind,
2485
+ txHashes: parsed.recovery.txHashes,
2486
+ ...parsed.recovery.requestId !== void 0 ? { requestId: parsed.recovery.requestId } : {},
2487
+ ...parsed.recovery.transactions !== void 0 ? { transactions: parsed.recovery.transactions } : {}
2488
+ };
2489
+ } else {
2490
+ const common = {
2491
+ amount: parsed.recovery.amount,
2492
+ txHashes: parsed.recovery.txHashes,
2493
+ ...parsed.recovery.requestId !== void 0 ? { requestId: parsed.recovery.requestId } : {},
2494
+ ...parsed.recovery.transactions !== void 0 ? { transactions: parsed.recovery.transactions } : {}
2495
+ };
2496
+ if (parsed.recovery.kind === "retry-base-usdc-cashout") {
2497
+ recovery = { ...common, kind: parsed.recovery.kind };
2498
+ } else if (parsed.recovery.kind === "inspect-base-cashout-submission") {
2499
+ recovery = {
2500
+ ...common,
2501
+ kind: parsed.recovery.kind,
2502
+ depositor: parsed.recovery.depositor
2503
+ };
2504
+ } else {
2505
+ recovery = {
2506
+ ...common,
2507
+ kind: parsed.recovery.kind,
2508
+ depositTxHash: parsed.recovery.depositTxHash
2509
+ };
2510
+ }
2511
+ }
2512
+ }
2513
+ return new CashError({
2514
+ code: parsed.code,
2515
+ message: parsed.message,
2516
+ retryable: parsed.retryable,
2517
+ remediation: parsed.remediation,
2518
+ ...recovery ? { recovery } : {}
2519
+ });
2520
+ }
1890
2521
 
1891
- export { CASH_ATTRIBUTION_CODE, MIN_CASHOUT_AMOUNT, RATE_PRECISION, RECOMMENDED_MIN_CASHOUT_AMOUNT, bigintString, buildCapabilities, buildIntentAmountRange, buildMarketRateCurrencyOverride, buyerProfileFromJson, buyerProfileToJson, capabilitiesFromJson, capabilitiesToJson, cashBuyerProfileJsonSchema, cashCapabilitiesJsonSchema, cashErrorJsonSchema, cashEstimateJsonSchema, cashFillJsonSchema, cashNextActionSchema, cashOrderJsonSchema, cashOrderStateSchema, cashPayoutInfoJsonSchema, cashPayoutPricingJsonSchema, cashPreparedStepJsonSchema, cashoutResultFromJson, cashoutResultJsonSchema, cashoutResultToJson, centsToNumber, createCashClient, deriveBuyerProfile, deriveCashOrder, derivePayouts, estimateFromJson, estimateToJson, explainOrder, fiatFromUsdc, fiatToNumber, fillFromJson, fillToJson, formatUsdc, intentStatusSchema, isFillLive, isMarketRateSupported, orderFromJson, orderToJson, parseCompositeDepositId, prepareCashDepositParams, prepareResultFromJson, prepareResultJsonSchema, prepareResultToJson, preparedStepFromJson, preparedStepToJson, preparedTransactionJsonSchema, preparedTxFromJson, preparedTxToJson, rateToNumber, resolveCashDepositId, topUpResultFromJson, topUpResultJsonSchema, topUpResultToJson, usdc, withExplain, withdrawResultFromJson, withdrawResultJsonSchema, withdrawResultToJson };
1892
- //# sourceMappingURL=index.js.map
1893
- //# sourceMappingURL=index.js.map
2522
+ export { CASH_ATTRIBUTION_CODE, MIN_CASHOUT_AMOUNT, RATE_PRECISION, RECOMMENDED_MIN_CASHOUT_AMOUNT, bigintString, buildCapabilities, buildIntentAmountRange, buildMarketRateCurrencyOverride, buyerProfileFromJson, buyerProfileToJson, capabilitiesFromJson, capabilitiesToJson, cashAssetJsonSchema, cashBuyerProfileJsonSchema, cashCapabilitiesJsonSchema, cashChainJsonSchema, cashErrorFromJson, cashErrorJsonSchema, cashErrorRecoveryJsonSchema, cashErrorToJson, cashEstimateJsonSchema, cashFillJsonSchema, cashNextActionSchema, cashOrderJsonSchema, cashOrderStateSchema, cashPayoutInfoJsonSchema, cashPayoutPricingJsonSchema, cashPreparedStepJsonSchema, cashSourceCapabilitiesJsonSchema, cashoutResultFromJson, cashoutResultJsonSchema, cashoutResultToJson, centsToNumber, createCashClient, deriveBuyerProfile, deriveCashOrder, derivePayouts, estimateFromJson, estimateToJson, explainOrder, fiatFromUsdc, fiatToNumber, fillFromJson, fillToJson, formatUsdc, intentStatusSchema, isFillLive, isMarketRateSupported, nonNegativeBigintString, orderFromJson, orderToJson, parseCompositeDepositId, prepareCashDepositParams, prepareResultFromJson, prepareResultJsonSchema, prepareResultToJson, preparedStepFromJson, preparedStepToJson, preparedTransactionJsonSchema, preparedTxFromJson, preparedTxToJson, rateToNumber, relayExecutionResultFromJson, relayExecutionResultJsonSchema, relayExecutionResultToJson, relayQuoteFromJson, relayQuoteJsonSchema, relayQuoteToJson, relayStatusFromJson, relayStatusJsonSchema, relayStatusToJson, relayTransactionJsonSchema, relayTransactionsJsonSchema, resolveCashDepositId, sourceCapabilitiesFromJson, sourceCapabilitiesToJson, topUpResultFromJson, topUpResultJsonSchema, topUpResultToJson, usdc, withExplain, withdrawResultFromJson, withdrawResultJsonSchema, withdrawResultToJson };