0xtrails 0.9.3 → 0.9.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.
Files changed (73) hide show
  1. package/dist/{ccip-CDO_EkNr.js → ccip-lAtzqne5.js} +1 -1
  2. package/dist/config.d.ts +1 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/constants.d.ts +1 -0
  5. package/dist/constants.d.ts.map +1 -1
  6. package/dist/error.d.ts.map +1 -1
  7. package/dist/{index-CybzMCeP.js → index-D5AG6huo.js} +22141 -21641
  8. package/dist/index.js +3 -3
  9. package/dist/intents.d.ts +1 -1
  10. package/dist/intents.d.ts.map +1 -1
  11. package/dist/mutations.d.ts +5 -2
  12. package/dist/mutations.d.ts.map +1 -1
  13. package/dist/tokens.d.ts.map +1 -1
  14. package/dist/transactionIntent/constants.d.ts +1 -0
  15. package/dist/transactionIntent/constants.d.ts.map +1 -1
  16. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +3 -1
  17. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -1
  18. package/dist/transactionIntent/deposits/standardDeposit.d.ts +4 -1
  19. package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -1
  20. package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -1
  21. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -1
  22. package/dist/transactionIntent/utils/resilientDepositTracker.d.ts +25 -0
  23. package/dist/transactionIntent/utils/resilientDepositTracker.d.ts.map +1 -0
  24. package/dist/widget/components/AccountIntentTransactionHistory.d.ts.map +1 -1
  25. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  26. package/dist/widget/components/ConfigDisplay.d.ts.map +1 -1
  27. package/dist/widget/components/DynamicInputStyles.d.ts +2 -2
  28. package/dist/widget/components/Earn.d.ts.map +1 -1
  29. package/dist/widget/components/EarnPools.d.ts.map +1 -1
  30. package/dist/widget/components/Fund.d.ts.map +1 -1
  31. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  32. package/dist/widget/components/Receipt.d.ts.map +1 -1
  33. package/dist/widget/components/SlippageToleranceSettings.d.ts.map +1 -1
  34. package/dist/widget/components/TransactionDetails.d.ts.map +1 -1
  35. package/dist/widget/components/UserPreferences.d.ts.map +1 -1
  36. package/dist/widget/components/WalletConnect.d.ts.map +1 -1
  37. package/dist/widget/css/compiled.css +1 -1
  38. package/dist/widget/hooks/useQuote.d.ts.map +1 -1
  39. package/dist/widget/index.js +1 -1
  40. package/dist/widget/providers/TrailsProvider.d.ts +2 -0
  41. package/dist/widget/providers/TrailsProvider.d.ts.map +1 -1
  42. package/dist/widget/widget.d.ts +1 -0
  43. package/dist/widget/widget.d.ts.map +1 -1
  44. package/package.json +2 -2
  45. package/src/config.ts +1 -0
  46. package/src/constants.ts +1 -0
  47. package/src/error.ts +6 -1
  48. package/src/intents.ts +22 -1
  49. package/src/prices.ts +1 -1
  50. package/src/tokens.ts +4 -3
  51. package/src/transactionIntent/constants.ts +2 -0
  52. package/src/transactionIntent/deposits/depositOrchestrator.ts +7 -0
  53. package/src/transactionIntent/deposits/standardDeposit.ts +194 -37
  54. package/src/transactionIntent/handlers/crossChain.ts +152 -105
  55. package/src/transactionIntent/handlers/sameChainSameToken.ts +1 -0
  56. package/src/transactionIntent/utils/resilientDepositTracker.ts +281 -0
  57. package/src/widget/compiled.css +1 -1
  58. package/src/widget/components/AccountIntentTransactionHistory.tsx +170 -87
  59. package/src/widget/components/ClassicSwap.tsx +7 -1
  60. package/src/widget/components/ConfigDisplay.tsx +5 -0
  61. package/src/widget/components/Earn.tsx +14 -1
  62. package/src/widget/components/EarnPools.tsx +180 -59
  63. package/src/widget/components/Fund.tsx +3 -1
  64. package/src/widget/components/PoolWithdraw.tsx +1 -1
  65. package/src/widget/components/QuoteDetails.tsx +12 -35
  66. package/src/widget/components/Receipt.tsx +66 -40
  67. package/src/widget/components/SlippageToleranceSettings.tsx +86 -44
  68. package/src/widget/components/TransactionDetails.tsx +138 -218
  69. package/src/widget/components/UserPreferences.tsx +114 -41
  70. package/src/widget/components/WalletConnect.tsx +111 -48
  71. package/src/widget/hooks/useQuote.ts +387 -355
  72. package/src/widget/providers/TrailsProvider.tsx +5 -0
  73. package/src/widget/widget.tsx +2 -0
@@ -587,397 +587,429 @@ export function useQuote({
587
587
  return null
588
588
  }
589
589
 
590
- // Get token balance using async method
591
- let balances: any[] = []
590
+ // Create a 20-second timeout
591
+ const timeoutId = setTimeout(() => {
592
+ logger.console.warn(
593
+ "[trails-sdk] [useQuote] Quote request timed out after 20 seconds",
594
+ )
595
+ abortControllerRef.current.abort()
596
+ }, 20000) // 20 seconds
597
+
592
598
  try {
593
- const result = await getTokenBalancesWithPrices({
594
- account: walletClient.account!.address,
595
- indexerGatewayClient,
596
- trailsClient,
597
- })
598
- balances = result.balances
599
- } catch (balanceError) {
600
- const balanceErrorMessage = getFullErrorMessage(balanceError)
601
- const isCorsError =
602
- balanceErrorMessage.includes("Cross-Origin") ||
603
- balanceErrorMessage.includes("CORS") ||
604
- balanceErrorMessage.includes("Same Origin Policy")
605
- const isNetworkError =
606
- balanceErrorMessage.includes("fetch failed") ||
607
- balanceErrorMessage.includes("network")
599
+ // Get token balance using async method
600
+ let balances: any[] = []
601
+ try {
602
+ const result = await getTokenBalancesWithPrices({
603
+ account: walletClient.account!.address,
604
+ indexerGatewayClient,
605
+ trailsClient,
606
+ })
607
+ balances = result.balances
608
+ } catch (balanceError) {
609
+ const balanceErrorMessage = getFullErrorMessage(balanceError)
610
+ const isCorsError =
611
+ balanceErrorMessage.includes("Cross-Origin") ||
612
+ balanceErrorMessage.includes("CORS") ||
613
+ balanceErrorMessage.includes("Same Origin Policy")
614
+ const isNetworkError =
615
+ balanceErrorMessage.includes("fetch failed") ||
616
+ balanceErrorMessage.includes("network")
608
617
 
609
- if (isCorsError || isNetworkError) {
610
- logger.console.warn(
611
- "[trails-sdk] [useQuote] Network or CORS error fetching balances, proceeding with quote using zero balance:",
612
- {
613
- error: balanceErrorMessage,
614
- account: walletClient.account!.address,
615
- },
616
- )
617
- // Continue with empty balances instead of crashing
618
- balances = []
619
- } else {
620
- throw balanceError
618
+ if (isCorsError || isNetworkError) {
619
+ logger.console.warn(
620
+ "[trails-sdk] [useQuote] Network or CORS error fetching balances, proceeding with quote using zero balance:",
621
+ {
622
+ error: balanceErrorMessage,
623
+ account: walletClient.account!.address,
624
+ },
625
+ )
626
+ // Continue with empty balances instead of crashing
627
+ balances = []
628
+ } else {
629
+ throw balanceError
630
+ }
621
631
  }
622
- }
623
632
 
624
- const originTokenBalance = balances.find(
625
- (b) =>
626
- b.chainId === fromChainId &&
627
- (b.contractAddress?.toLowerCase() ===
628
- fromTokenAddress.toLowerCase() ||
629
- (!b.contractAddress && fromTokenAddress === zeroAddress)),
630
- )
631
-
632
- const originTokenBalanceAmount = originTokenBalance?.balance ?? "0"
633
+ const originTokenBalance = balances.find(
634
+ (b) =>
635
+ b.chainId === fromChainId &&
636
+ (b.contractAddress?.toLowerCase() ===
637
+ fromTokenAddress.toLowerCase() ||
638
+ (!b.contractAddress && fromTokenAddress === zeroAddress)),
639
+ )
633
640
 
634
- // Note: Disable this check for now to allow fetching a quote even when the origin balance is zero
635
- // if (originTokenBalanceAmount === "0") {
636
- // return null
637
- // }
641
+ const originTokenBalanceAmount = originTokenBalance?.balance ?? "0"
638
642
 
639
- // logger.console.log("supportedTokens", supportedTokens)
643
+ // Note: Disable this check for now to allow fetching a quote even when the origin balance is zero
644
+ // if (originTokenBalanceAmount === "0") {
645
+ // return null
646
+ // }
640
647
 
641
- // Get native token price for origin chain (for gas cost calculation)
642
- let originNativeTokenPriceUsd = 0
643
- try {
644
- const originChain = getChainInfo(fromChainId)
645
- const nativeTokenSymbol = originChain?.nativeCurrency?.symbol ?? ""
646
- if (nativeTokenSymbol) {
647
- const nativePrice = await getTokenPrice(trailsClient, {
648
- tokenSymbol: nativeTokenSymbol,
649
- tokenAddress: zeroAddress,
650
- chainId: fromChainId,
651
- })
652
- originNativeTokenPriceUsd = nativePrice?.priceUsd ?? 0
653
- logger.console.log(
654
- "[trails-sdk] [useQuote] Origin native token price:",
655
- {
656
- chainId: fromChainId,
657
- symbol: nativeTokenSymbol,
658
- priceUsd: originNativeTokenPriceUsd,
659
- },
660
- )
661
- }
662
- } catch (error) {
663
- logger.console.error(
664
- "[trails-sdk] [useQuote] Error getting origin native token price:",
665
- error,
666
- )
667
- }
648
+ // logger.console.log("supportedTokens", supportedTokens)
668
649
 
669
- // Helper function to fetch decimals on-chain if not found in token list
670
- const fetchDecimalsOnChain = async (
671
- tokenAddress: string,
672
- chainId: number,
673
- ): Promise<number | null> => {
650
+ // Get native token price for origin chain (for gas cost calculation)
651
+ let originNativeTokenPriceUsd = 0
674
652
  try {
675
- // Use the hook-based RPC clients that are already available
676
- const publicClient =
677
- chainId === fromChainId
678
- ? originPublicClient
679
- : chainId === toChainId
680
- ? destinationPublicClient
681
- : null
682
-
683
- if (!publicClient) {
684
- logger.console.warn(
685
- `[trails-sdk] No RPC client available for chain ${chainId}`,
653
+ const originChain = getChainInfo(fromChainId)
654
+ const nativeTokenSymbol = originChain?.nativeCurrency?.symbol ?? ""
655
+ if (nativeTokenSymbol) {
656
+ const nativePrice = await getTokenPrice(trailsClient, {
657
+ tokenSymbol: nativeTokenSymbol,
658
+ tokenAddress: zeroAddress,
659
+ chainId: fromChainId,
660
+ })
661
+ originNativeTokenPriceUsd = nativePrice?.priceUsd ?? 0
662
+ logger.console.log(
663
+ "[trails-sdk] [useQuote] Origin native token price:",
664
+ {
665
+ chainId: fromChainId,
666
+ symbol: nativeTokenSymbol,
667
+ priceUsd: originNativeTokenPriceUsd,
668
+ },
686
669
  )
687
- return null
688
- }
689
-
690
- // For native tokens, return 18 decimals
691
- if (tokenAddress.toLowerCase() === zeroAddress.toLowerCase()) {
692
- const chainInfo = getChainInfo(chainId)
693
- return chainInfo?.nativeCurrency.decimals ?? 18
694
670
  }
695
-
696
- const decimals = await publicClient.readContract({
697
- address: tokenAddress as `0x${string}`,
698
- abi: erc20Abi,
699
- functionName: "decimals",
700
- })
701
-
702
- logger.console.log(
703
- `[trails-sdk] Fetched decimals on-chain for token ${tokenAddress} on chain ${chainId}: ${decimals}`,
704
- )
705
- return decimals
706
671
  } catch (error) {
707
672
  logger.console.error(
708
- `[trails-sdk] Error fetching decimals on-chain for token ${tokenAddress} on chain ${chainId}:`,
673
+ "[trails-sdk] [useQuote] Error getting origin native token price:",
709
674
  error,
710
675
  )
711
- return null
712
676
  }
713
- }
714
677
 
715
- const originToken = supportedTokens?.find(
716
- (token) =>
717
- token.contractAddress?.toLowerCase() ===
718
- fromTokenAddress?.toLowerCase() && token.chainId === fromChainId,
719
- )
720
- const destinationToken = supportedTokens?.find(
721
- (token) =>
722
- token.contractAddress?.toLowerCase() ===
723
- toTokenAddress?.toLowerCase() && token.chainId === toChainId,
724
- )
678
+ // Helper function to fetch decimals on-chain if not found in token list
679
+ const fetchDecimalsOnChain = async (
680
+ tokenAddress: string,
681
+ chainId: number,
682
+ ): Promise<number | null> => {
683
+ try {
684
+ // Use the hook-based RPC clients that are already available
685
+ const publicClient =
686
+ chainId === fromChainId
687
+ ? originPublicClient
688
+ : chainId === toChainId
689
+ ? destinationPublicClient
690
+ : null
725
691
 
726
- let sourceTokenDecimals = originToken?.decimals
727
- if (!sourceTokenDecimals && fromTokenAddress && fromChainId) {
728
- logger.console.warn(
729
- "[trails-sdk] [useQuote] Source token decimals not found in token list, fetching on-chain:",
730
- {
731
- originToken,
732
- fromTokenAddress,
733
- fromChainId,
734
- },
692
+ if (!publicClient) {
693
+ logger.console.warn(
694
+ `[trails-sdk] No RPC client available for chain ${chainId}`,
695
+ )
696
+ return null
697
+ }
698
+
699
+ // For native tokens, return 18 decimals
700
+ if (tokenAddress.toLowerCase() === zeroAddress.toLowerCase()) {
701
+ const chainInfo = getChainInfo(chainId)
702
+ return chainInfo?.nativeCurrency.decimals ?? 18
703
+ }
704
+
705
+ const decimals = await publicClient.readContract({
706
+ address: tokenAddress as `0x${string}`,
707
+ abi: erc20Abi,
708
+ functionName: "decimals",
709
+ })
710
+
711
+ logger.console.log(
712
+ `[trails-sdk] Fetched decimals on-chain for token ${tokenAddress} on chain ${chainId}: ${decimals}`,
713
+ )
714
+ return decimals
715
+ } catch (error) {
716
+ logger.console.error(
717
+ `[trails-sdk] Error fetching decimals on-chain for token ${tokenAddress} on chain ${chainId}:`,
718
+ error,
719
+ )
720
+ return null
721
+ }
722
+ }
723
+
724
+ const originToken = supportedTokens?.find(
725
+ (token) =>
726
+ token.contractAddress?.toLowerCase() ===
727
+ fromTokenAddress?.toLowerCase() &&
728
+ token.chainId === fromChainId,
735
729
  )
736
- const onChainDecimals = await fetchDecimalsOnChain(
737
- fromTokenAddress,
738
- fromChainId,
730
+ const destinationToken = supportedTokens?.find(
731
+ (token) =>
732
+ token.contractAddress?.toLowerCase() ===
733
+ toTokenAddress?.toLowerCase() && token.chainId === toChainId,
739
734
  )
740
- if (onChainDecimals !== null) {
741
- sourceTokenDecimals = onChainDecimals
742
- }
743
- }
744
- if (!sourceTokenDecimals) {
745
- logger.console.error(
746
- "[trails-sdk] [useQuote] Source token decimals not found:",
747
- {
748
- originToken,
735
+
736
+ let sourceTokenDecimals = originToken?.decimals
737
+ if (!sourceTokenDecimals && fromTokenAddress && fromChainId) {
738
+ logger.console.warn(
739
+ "[trails-sdk] [useQuote] Source token decimals not found in token list, fetching on-chain:",
740
+ {
741
+ originToken,
742
+ fromTokenAddress,
743
+ fromChainId,
744
+ },
745
+ )
746
+ const onChainDecimals = await fetchDecimalsOnChain(
749
747
  fromTokenAddress,
750
748
  fromChainId,
751
- },
752
- )
753
- throw new Error("Source token decimals not found")
754
- }
755
- let destinationTokenDecimals = destinationToken?.decimals
756
- if (!destinationTokenDecimals && toTokenAddress && toChainId) {
757
- logger.console.warn(
758
- "[trails-sdk] Destination token decimals not found in token list, fetching on-chain:",
759
- {
760
- destinationToken,
761
- toTokenAddress,
762
- toChainId,
763
- },
764
- )
765
- const onChainDecimals = await fetchDecimalsOnChain(
766
- toTokenAddress,
767
- toChainId,
768
- )
769
- if (onChainDecimals !== null) {
770
- destinationTokenDecimals = onChainDecimals
749
+ )
750
+ if (onChainDecimals !== null) {
751
+ sourceTokenDecimals = onChainDecimals
752
+ }
771
753
  }
772
- }
773
- if (!destinationTokenDecimals) {
774
- logger.console.error(
775
- "[trails-sdk] Destination token decimals not found:",
776
- {
777
- destinationToken,
754
+ if (!sourceTokenDecimals) {
755
+ logger.console.error(
756
+ "[trails-sdk] [useQuote] Source token decimals not found:",
757
+ {
758
+ originToken,
759
+ fromTokenAddress,
760
+ fromChainId,
761
+ },
762
+ )
763
+ throw new Error("Source token decimals not found")
764
+ }
765
+ let destinationTokenDecimals = destinationToken?.decimals
766
+ if (!destinationTokenDecimals && toTokenAddress && toChainId) {
767
+ logger.console.warn(
768
+ "[trails-sdk] Destination token decimals not found in token list, fetching on-chain:",
769
+ {
770
+ destinationToken,
771
+ toTokenAddress,
772
+ toChainId,
773
+ },
774
+ )
775
+ const onChainDecimals = await fetchDecimalsOnChain(
778
776
  toTokenAddress,
779
777
  toChainId,
780
- },
781
- )
782
- throw new Error("Destination token decimals not found")
783
- }
784
- const destinationTokenSymbol = destinationToken?.symbol ?? ""
785
- const originTokenSymbol = originToken?.symbol ?? ""
778
+ )
779
+ if (onChainDecimals !== null) {
780
+ destinationTokenDecimals = onChainDecimals
781
+ }
782
+ }
783
+ if (!destinationTokenDecimals) {
784
+ logger.console.error(
785
+ "[trails-sdk] Destination token decimals not found:",
786
+ {
787
+ destinationToken,
788
+ toTokenAddress,
789
+ toChainId,
790
+ },
791
+ )
792
+ throw new Error("Destination token decimals not found")
793
+ }
794
+ const destinationTokenSymbol = destinationToken?.symbol ?? ""
795
+ const originTokenSymbol = originToken?.symbol ?? ""
786
796
 
787
- // For qr-code and exchange fund methods, use a default amount of 100 tokens
788
- // since the user will deposit from an external wallet (their connected wallet balance may be 0)
789
- const effectiveOriginTokenBalance =
790
- fundMethod === "qr-code" || fundMethod === "onramp-exchange"
791
- ? parseUnits("100", sourceTokenDecimals).toString()
792
- : originTokenBalanceAmount
797
+ // For qr-code and exchange fund methods, use a default amount of 100 tokens
798
+ // since the user will deposit from an external wallet (their connected wallet balance may be 0)
799
+ const effectiveOriginTokenBalance =
800
+ fundMethod === "qr-code" || fundMethod === "onramp-exchange"
801
+ ? parseUnits("100", sourceTokenDecimals).toString()
802
+ : originTokenBalanceAmount
793
803
 
794
- const options: PrepareSendOptions = {
795
- account: walletClient.account!,
796
- originTokenAddress: fromTokenAddress,
797
- originChainId: fromChainId,
798
- originTokenBalance: effectiveOriginTokenBalance,
799
- destinationChainId: toChainId,
800
- recipient: effectiveToAddress,
801
- destinationTokenAddress: toTokenAddress,
802
- swapAmount: debouncedSwapAmount.toString(),
803
- tradeType: tradeType ?? TradeType.EXACT_OUTPUT,
804
- originTokenSymbol: originTokenSymbol,
805
- destinationTokenSymbol: destinationTokenSymbol,
806
- destinationCalldata: toCalldata as string,
807
- client: walletClient,
808
- trailsClient,
809
- sourceTokenDecimals,
810
- destinationTokenDecimals,
811
- onTransactionStateChange: onStatusUpdate ?? (() => {}),
812
- slippageTolerance: slippageTolerance?.toString(),
813
- swapProvider: effectiveSwapProvider,
814
- bridgeProvider: effectiveBridgeProvider,
815
- paymasterUrl: paymasterUrl,
816
- selectedFeeOption: selectedFeeOption ?? null,
817
- abortSignal: combinedAbortSignal,
818
- originNativeTokenPriceUsd: originNativeTokenPriceUsd,
819
- commitIntentFn: commitIntentMutation.mutateAsync,
820
- executeIntentFn: executeIntentMutation.mutateAsync,
821
- checkoutOnHandlers,
822
- sequenceIndexerUrl,
823
- sequenceProjectAccessKey,
824
- originPublicClient: originPublicClient ?? undefined,
825
- destinationPublicClient: destinationPublicClient ?? undefined,
826
- isSmartWallet: isSmartWallet ?? undefined,
827
- trailsApiKey,
828
- trailsApiUrl,
829
- fundMethod: fundMethod ?? undefined,
830
- onramp: onramp ?? undefined,
831
- }
804
+ const options: PrepareSendOptions = {
805
+ account: walletClient.account!,
806
+ originTokenAddress: fromTokenAddress,
807
+ originChainId: fromChainId,
808
+ originTokenBalance: effectiveOriginTokenBalance,
809
+ destinationChainId: toChainId,
810
+ recipient: effectiveToAddress,
811
+ destinationTokenAddress: toTokenAddress,
812
+ swapAmount: debouncedSwapAmount.toString(),
813
+ tradeType: tradeType ?? TradeType.EXACT_OUTPUT,
814
+ originTokenSymbol: originTokenSymbol,
815
+ destinationTokenSymbol: destinationTokenSymbol,
816
+ destinationCalldata: toCalldata as string,
817
+ client: walletClient,
818
+ trailsClient,
819
+ sourceTokenDecimals,
820
+ destinationTokenDecimals,
821
+ onTransactionStateChange: onStatusUpdate ?? (() => {}),
822
+ slippageTolerance: slippageTolerance?.toString(),
823
+ swapProvider: effectiveSwapProvider,
824
+ bridgeProvider: effectiveBridgeProvider,
825
+ paymasterUrl: paymasterUrl,
826
+ selectedFeeOption: selectedFeeOption ?? null,
827
+ abortSignal: combinedAbortSignal,
828
+ originNativeTokenPriceUsd: originNativeTokenPriceUsd,
829
+ commitIntentFn: commitIntentMutation.mutateAsync,
830
+ executeIntentFn: executeIntentMutation.mutateAsync,
831
+ checkoutOnHandlers,
832
+ sequenceIndexerUrl,
833
+ sequenceProjectAccessKey,
834
+ originPublicClient: originPublicClient ?? undefined,
835
+ destinationPublicClient: destinationPublicClient ?? undefined,
836
+ isSmartWallet: isSmartWallet ?? undefined,
837
+ trailsApiKey,
838
+ trailsApiUrl,
839
+ fundMethod: fundMethod ?? undefined,
840
+ onramp: onramp ?? undefined,
841
+ }
832
842
 
833
- logger.console.log("[trails-sdk] options", options)
843
+ logger.console.log("[trails-sdk] options", options)
834
844
 
835
- const {
836
- quote: prepareSendQuote,
837
- send: prepareSendSend,
838
- feeOptions: prepareSendFeeOptions,
839
- } = await prepareSend(options)
845
+ const {
846
+ quote: prepareSendQuote,
847
+ send: prepareSendSend,
848
+ feeOptions: prepareSendFeeOptions,
849
+ } = await prepareSend(options)
840
850
 
841
- const quote: Quote = {
842
- // Backward compatible fields
843
- fromAmount: prepareSendQuote.originAmount,
844
- toAmount: prepareSendQuote.destinationAmount,
845
- fromAmountMin: prepareSendQuote.originAmountMin,
846
- toAmountMin: prepareSendQuote.destinationAmountMin,
847
- fromAmountUsdDisplay: prepareSendQuote.originAmountUsdDisplay ?? "",
848
- toAmountUsdDisplay:
849
- prepareSendQuote.destinationAmountUsdDisplay ?? "",
850
- toAmountMinUsdDisplay:
851
- prepareSendQuote.destinationAmountMinUsdDisplay ?? "",
852
- // PrepareSendQuote compatible fields
853
- originAmount: prepareSendQuote.originAmount,
854
- originAmountMin: prepareSendQuote.originAmountMin,
855
- destinationAmount: prepareSendQuote.destinationAmount,
856
- destinationAmountMin: prepareSendQuote.destinationAmountMin,
857
- originAmountUsdDisplay: prepareSendQuote.originAmountUsdDisplay ?? "",
858
- destinationAmountUsdDisplay:
859
- prepareSendQuote.destinationAmountUsdDisplay ?? "",
860
- originAmountDisplay: prepareSendQuote.originAmountDisplay ?? "",
861
- destinationAmountDisplay:
862
- prepareSendQuote.destinationAmountDisplay ?? "",
863
- originAmountMinDisplay: prepareSendQuote.originAmountMinDisplay ?? "",
864
- originAmountMinUsdFormatted:
865
- prepareSendQuote.originAmountMinUsdFormatted ?? "",
866
- originAmountMinUsdDisplay:
867
- prepareSendQuote.originAmountMinUsdDisplay ?? "",
868
- destinationAmountMinDisplay:
869
- prepareSendQuote.destinationAmountMinDisplay ?? "",
870
- destinationAmountMinUsdFormatted:
871
- prepareSendQuote.destinationAmountMinUsdFormatted ?? "",
872
- destinationAmountMinUsdDisplay:
873
- prepareSendQuote.destinationAmountMinUsdDisplay ?? "",
874
- originAmountUsdFormatted:
875
- prepareSendQuote.originAmountUsdFormatted ?? "",
876
- destinationAmountUsdFormatted:
877
- prepareSendQuote.destinationAmountUsdFormatted ?? "",
878
- // Common fields
879
- originToken: prepareSendQuote.originToken,
880
- destinationToken: prepareSendQuote.destinationToken,
881
- originChain: prepareSendQuote.originChain,
882
- destinationChain: prepareSendQuote.destinationChain,
883
- fees: prepareSendQuote.fees,
884
- priceImpact: prepareSendQuote.priceImpact,
885
- priceImpactUsd: prepareSendQuote.priceImpactUsd ?? null,
886
- priceImpactUsdDisplay: prepareSendQuote.priceImpactUsdDisplay ?? "",
887
- completionEstimateSeconds: prepareSendQuote.completionEstimateSeconds,
888
- completionEstimateDisplay:
889
- prepareSendQuote.completionEstimateDisplay ?? "",
890
- slippageTolerance: prepareSendQuote.slippageTolerance,
891
- transactionStates: prepareSendQuote.transactionStates ?? [],
892
- originTokenRate: prepareSendQuote.originTokenRate ?? "",
893
- destinationTokenRate: prepareSendQuote.destinationTokenRate ?? "",
894
- originTokenPriceUsd: prepareSendQuote.originTokenPriceUsd ?? 0,
895
- destinationTokenPriceUsd:
896
- prepareSendQuote.destinationTokenPriceUsd ?? 0,
897
- routeProviders: prepareSendQuote.routeProviders ?? [],
898
- gasCostUsd: prepareSendQuote.gasCostUsd ?? null,
899
- gasCostUsdDisplay: prepareSendQuote.gasCostUsdDisplay ?? "",
900
- gasCost: prepareSendQuote.gasCost ?? "",
901
- gasCostFormatted: prepareSendQuote.gasCostFormatted ?? "",
902
- totalFeesUsd: prepareSendQuote.totalFeesUsd ?? null,
903
- totalFeesUsdDisplay: prepareSendQuote.totalFeesUsdDisplay ?? "",
904
- totalGasUsd: prepareSendQuote.totalGasUsd ?? null,
905
- totalGasUsdDisplay: prepareSendQuote.totalGasUsdDisplay ?? "",
906
- intentId: prepareSendQuote.intentId ?? null,
907
- originAmountFormatted: prepareSendQuote.originAmountFormatted ?? "",
908
- destinationAmountFormatted:
909
- prepareSendQuote.destinationAmountFormatted ?? "",
910
- originDepositAddress: prepareSendQuote.originDepositAddress ?? "",
911
- destinationDepositAddress:
912
- prepareSendQuote.destinationDepositAddress ?? "",
913
- destinationAddress: prepareSendQuote.destinationAddress ?? "",
914
- destinationCalldata: prepareSendQuote.destinationCalldata ?? "",
915
- // Fee breakdown fields
916
- trailsFeeBreakdown: prepareSendQuote.trailsFeeBreakdown ?? null,
917
- originGasUsd: prepareSendQuote.originGasUsd ?? null,
918
- originGasUsdDisplay: prepareSendQuote.originGasUsdDisplay ?? "",
919
- destinationGasUsd: prepareSendQuote.destinationGasUsd ?? null,
920
- destinationGasUsdDisplay:
921
- prepareSendQuote.destinationGasUsdDisplay ?? "",
922
- providerFeeUsd: prepareSendQuote.providerFeeUsd ?? null,
923
- providerFeeUsdDisplay: prepareSendQuote.providerFeeUsdDisplay ?? "",
924
- trailsFeeUsd: prepareSendQuote.trailsFeeUsd ?? null,
925
- trailsFeeUsdDisplay: prepareSendQuote.trailsFeeUsdDisplay ?? "",
926
- totalProviderFeesUsd: prepareSendQuote.totalProviderFeesUsd ?? null,
927
- totalProviderFeesUsdDisplay:
928
- prepareSendQuote.totalProviderFeesUsdDisplay ?? "",
929
- noSufficientBalance: prepareSendQuote.noSufficientBalance ?? false,
930
- expiresAt: prepareSendQuote.expiresAt ?? null,
931
- }
851
+ const quote: Quote = {
852
+ // Backward compatible fields
853
+ fromAmount: prepareSendQuote.originAmount,
854
+ toAmount: prepareSendQuote.destinationAmount,
855
+ fromAmountMin: prepareSendQuote.originAmountMin,
856
+ toAmountMin: prepareSendQuote.destinationAmountMin,
857
+ fromAmountUsdDisplay: prepareSendQuote.originAmountUsdDisplay ?? "",
858
+ toAmountUsdDisplay:
859
+ prepareSendQuote.destinationAmountUsdDisplay ?? "",
860
+ toAmountMinUsdDisplay:
861
+ prepareSendQuote.destinationAmountMinUsdDisplay ?? "",
862
+ // PrepareSendQuote compatible fields
863
+ originAmount: prepareSendQuote.originAmount,
864
+ originAmountMin: prepareSendQuote.originAmountMin,
865
+ destinationAmount: prepareSendQuote.destinationAmount,
866
+ destinationAmountMin: prepareSendQuote.destinationAmountMin,
867
+ originAmountUsdDisplay:
868
+ prepareSendQuote.originAmountUsdDisplay ?? "",
869
+ destinationAmountUsdDisplay:
870
+ prepareSendQuote.destinationAmountUsdDisplay ?? "",
871
+ originAmountDisplay: prepareSendQuote.originAmountDisplay ?? "",
872
+ destinationAmountDisplay:
873
+ prepareSendQuote.destinationAmountDisplay ?? "",
874
+ originAmountMinDisplay:
875
+ prepareSendQuote.originAmountMinDisplay ?? "",
876
+ originAmountMinUsdFormatted:
877
+ prepareSendQuote.originAmountMinUsdFormatted ?? "",
878
+ originAmountMinUsdDisplay:
879
+ prepareSendQuote.originAmountMinUsdDisplay ?? "",
880
+ destinationAmountMinDisplay:
881
+ prepareSendQuote.destinationAmountMinDisplay ?? "",
882
+ destinationAmountMinUsdFormatted:
883
+ prepareSendQuote.destinationAmountMinUsdFormatted ?? "",
884
+ destinationAmountMinUsdDisplay:
885
+ prepareSendQuote.destinationAmountMinUsdDisplay ?? "",
886
+ originAmountUsdFormatted:
887
+ prepareSendQuote.originAmountUsdFormatted ?? "",
888
+ destinationAmountUsdFormatted:
889
+ prepareSendQuote.destinationAmountUsdFormatted ?? "",
890
+ // Common fields
891
+ originToken: prepareSendQuote.originToken,
892
+ destinationToken: prepareSendQuote.destinationToken,
893
+ originChain: prepareSendQuote.originChain,
894
+ destinationChain: prepareSendQuote.destinationChain,
895
+ fees: prepareSendQuote.fees,
896
+ priceImpact: prepareSendQuote.priceImpact,
897
+ priceImpactUsd: prepareSendQuote.priceImpactUsd ?? null,
898
+ priceImpactUsdDisplay: prepareSendQuote.priceImpactUsdDisplay ?? "",
899
+ completionEstimateSeconds:
900
+ prepareSendQuote.completionEstimateSeconds,
901
+ completionEstimateDisplay:
902
+ prepareSendQuote.completionEstimateDisplay ?? "",
903
+ slippageTolerance: prepareSendQuote.slippageTolerance,
904
+ transactionStates: prepareSendQuote.transactionStates ?? [],
905
+ originTokenRate: prepareSendQuote.originTokenRate ?? "",
906
+ destinationTokenRate: prepareSendQuote.destinationTokenRate ?? "",
907
+ originTokenPriceUsd: prepareSendQuote.originTokenPriceUsd ?? 0,
908
+ destinationTokenPriceUsd:
909
+ prepareSendQuote.destinationTokenPriceUsd ?? 0,
910
+ routeProviders: prepareSendQuote.routeProviders ?? [],
911
+ gasCostUsd: prepareSendQuote.gasCostUsd ?? null,
912
+ gasCostUsdDisplay: prepareSendQuote.gasCostUsdDisplay ?? "",
913
+ gasCost: prepareSendQuote.gasCost ?? "",
914
+ gasCostFormatted: prepareSendQuote.gasCostFormatted ?? "",
915
+ totalFeesUsd: prepareSendQuote.totalFeesUsd ?? null,
916
+ totalFeesUsdDisplay: prepareSendQuote.totalFeesUsdDisplay ?? "",
917
+ totalGasUsd: prepareSendQuote.totalGasUsd ?? null,
918
+ totalGasUsdDisplay: prepareSendQuote.totalGasUsdDisplay ?? "",
919
+ intentId: prepareSendQuote.intentId ?? null,
920
+ originAmountFormatted: prepareSendQuote.originAmountFormatted ?? "",
921
+ destinationAmountFormatted:
922
+ prepareSendQuote.destinationAmountFormatted ?? "",
923
+ originDepositAddress: prepareSendQuote.originDepositAddress ?? "",
924
+ destinationDepositAddress:
925
+ prepareSendQuote.destinationDepositAddress ?? "",
926
+ destinationAddress: prepareSendQuote.destinationAddress ?? "",
927
+ destinationCalldata: prepareSendQuote.destinationCalldata ?? "",
928
+ // Fee breakdown fields
929
+ trailsFeeBreakdown: prepareSendQuote.trailsFeeBreakdown ?? null,
930
+ originGasUsd: prepareSendQuote.originGasUsd ?? null,
931
+ originGasUsdDisplay: prepareSendQuote.originGasUsdDisplay ?? "",
932
+ destinationGasUsd: prepareSendQuote.destinationGasUsd ?? null,
933
+ destinationGasUsdDisplay:
934
+ prepareSendQuote.destinationGasUsdDisplay ?? "",
935
+ providerFeeUsd: prepareSendQuote.providerFeeUsd ?? null,
936
+ providerFeeUsdDisplay: prepareSendQuote.providerFeeUsdDisplay ?? "",
937
+ trailsFeeUsd: prepareSendQuote.trailsFeeUsd ?? null,
938
+ trailsFeeUsdDisplay: prepareSendQuote.trailsFeeUsdDisplay ?? "",
939
+ totalProviderFeesUsd: prepareSendQuote.totalProviderFeesUsd ?? null,
940
+ totalProviderFeesUsdDisplay:
941
+ prepareSendQuote.totalProviderFeesUsdDisplay ?? "",
942
+ noSufficientBalance: prepareSendQuote.noSufficientBalance ?? false,
943
+ expiresAt: prepareSendQuote.expiresAt ?? null,
944
+ }
932
945
 
933
- const sendTransaction = async (
934
- options?: SendOptions,
935
- ): Promise<SwapReturn> => {
936
- // Use fee option from send() call if provided, otherwise fall back to prop value
937
- const effectiveFeeOption =
938
- options?.selectedFeeOption !== undefined
939
- ? options.selectedFeeOption
940
- : (selectedFeeOption ?? null)
946
+ const sendTransaction = async (
947
+ options?: SendOptions,
948
+ ): Promise<SwapReturn> => {
949
+ // Use fee option from send() call if provided, otherwise fall back to prop value
950
+ const effectiveFeeOption =
951
+ options?.selectedFeeOption !== undefined
952
+ ? options.selectedFeeOption
953
+ : (selectedFeeOption ?? null)
941
954
 
942
- const {
943
- depositUserTxnReceipt,
944
- destinationIntentTransaction,
945
- totalCompletionSeconds,
946
- } = await prepareSendSend({
947
- selectedFeeOption: effectiveFeeOption,
948
- onOriginSend: options?.onOriginSend,
949
- depositTransactionHash: options?.depositTransactionHash,
950
- skipCommit: options?.skipCommit,
951
- commitOnly: options?.commitOnly,
952
- })
955
+ const {
956
+ depositUserTxnReceipt,
957
+ destinationIntentTransaction,
958
+ totalCompletionSeconds,
959
+ } = await prepareSendSend({
960
+ selectedFeeOption: effectiveFeeOption,
961
+ onOriginSend: options?.onOriginSend,
962
+ depositTransactionHash: options?.depositTransactionHash,
963
+ skipCommit: options?.skipCommit,
964
+ commitOnly: options?.commitOnly,
965
+ })
953
966
 
954
- return {
955
- originTransaction: {
956
- transactionHash: depositUserTxnReceipt?.transactionHash,
957
- explorerUrl: getExplorerUrl({
958
- txHash: depositUserTxnReceipt?.transactionHash as string,
959
- chainId: fromChainId,
960
- }),
961
- receipt: depositUserTxnReceipt,
962
- },
963
- destinationTransaction: {
964
- transactionHash: destinationIntentTransaction?.txnHash,
965
- explorerUrl: getExplorerUrl({
966
- txHash: destinationIntentTransaction?.txnHash as string,
967
- chainId: toChainId,
968
- }),
969
- receipt: destinationIntentTransaction,
970
- },
971
- totalCompletionSeconds,
967
+ return {
968
+ originTransaction: {
969
+ transactionHash: depositUserTxnReceipt?.transactionHash,
970
+ explorerUrl: getExplorerUrl({
971
+ txHash: depositUserTxnReceipt?.transactionHash as string,
972
+ chainId: fromChainId,
973
+ }),
974
+ receipt: depositUserTxnReceipt,
975
+ },
976
+ destinationTransaction: {
977
+ transactionHash: destinationIntentTransaction?.txnHash,
978
+ explorerUrl: getExplorerUrl({
979
+ txHash: destinationIntentTransaction?.txnHash as string,
980
+ chainId: toChainId,
981
+ }),
982
+ receipt: destinationIntentTransaction,
983
+ },
984
+ totalCompletionSeconds,
985
+ }
972
986
  }
973
- }
974
987
 
975
- return {
976
- quote,
977
- send: sendTransaction,
978
- feeOptions: prepareSendFeeOptions?.feeOptions ?? [],
988
+ // Clear the timeout on successful completion
989
+ clearTimeout(timeoutId)
990
+
991
+ return {
992
+ quote,
993
+ send: sendTransaction,
994
+ feeOptions: prepareSendFeeOptions?.feeOptions ?? [],
995
+ }
996
+ } finally {
997
+ // Always clear the timeout
998
+ clearTimeout(timeoutId)
979
999
  }
980
1000
  } catch (error) {
1001
+ // Check if this was aborted due to timeout
1002
+ if (
1003
+ (error as any)?.name === "AbortError" ||
1004
+ abortControllerRef.current.signal.aborted
1005
+ ) {
1006
+ logger.console.error(
1007
+ "[trails-sdk] [useQuote] Quote request timed out:",
1008
+ error,
1009
+ )
1010
+ throw new Error("No route available")
1011
+ }
1012
+
981
1013
  logger.console.error(
982
1014
  "[trails-sdk] [useQuote] Error getting quote:",
983
1015
  error,
@@ -1004,7 +1036,7 @@ export function useQuote({
1004
1036
  refetchOnWindowFocus: false, // Don't refetch when window regains focus
1005
1037
  refetchOnMount: "always", // Always refetch on component remount to ensure fresh quote
1006
1038
  refetchInterval: false, // Disable automatic polling
1007
- retry: 2, // Limit retry attempts
1039
+ retry: false, // Disable automatic retries - only make 1 request
1008
1040
  refetchOnReconnect: true, // Refetch when network reconnects
1009
1041
  })
1010
1042