0xtrails 0.12.2 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/dist/abis/trailsHydrate.d.ts.map +1 -1
  2. package/dist/analytics.d.ts +41 -0
  3. package/dist/analytics.d.ts.map +1 -1
  4. package/dist/{ccip-62W6LwH2.js → ccip-Cg9-lJ6K.js} +16 -16
  5. package/dist/chainSwitch.d.ts.map +1 -1
  6. package/dist/chains.d.ts +9 -3
  7. package/dist/chains.d.ts.map +1 -1
  8. package/dist/error.d.ts +1 -0
  9. package/dist/error.d.ts.map +1 -1
  10. package/dist/{index-C0QTNYIA.js → index-DEojZg7b.js} +50431 -50424
  11. package/dist/index.d.ts +1 -3
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +377 -421
  14. package/dist/intentReceiptPoller.d.ts.map +1 -1
  15. package/dist/intents.d.ts +1 -3
  16. package/dist/intents.d.ts.map +1 -1
  17. package/dist/mutations.d.ts +1 -4
  18. package/dist/mutations.d.ts.map +1 -1
  19. package/dist/prepareSend.d.ts.map +1 -1
  20. package/dist/query/balance.hooks.d.ts.map +1 -1
  21. package/dist/query/chains.hooks.d.ts.map +1 -1
  22. package/dist/query/chains.queries.d.ts +4 -1
  23. package/dist/query/chains.queries.d.ts.map +1 -1
  24. package/dist/queryParams.d.ts.map +1 -1
  25. package/dist/recover.d.ts.map +1 -1
  26. package/dist/tokens.d.ts.map +1 -1
  27. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -1
  28. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts.map +1 -1
  29. package/dist/transactionIntent/deposits/standardDeposit.d.ts +1 -7
  30. package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -1
  31. package/dist/transactionIntent/handlers/intentHandler.d.ts.map +1 -1
  32. package/dist/transactionIntent/helpers/transactionStateHelpers.d.ts +10 -1
  33. package/dist/transactionIntent/helpers/transactionStateHelpers.d.ts.map +1 -1
  34. package/dist/transactionIntent/types.d.ts +3 -6
  35. package/dist/transactionIntent/types.d.ts.map +1 -1
  36. package/dist/transactionIntent/utils/resilientDepositTracker.d.ts +3 -3
  37. package/dist/transactionIntent/utils/resilientDepositTracker.d.ts.map +1 -1
  38. package/dist/transactions.d.ts +2 -0
  39. package/dist/transactions.d.ts.map +1 -1
  40. package/dist/umd/trails.min.js +200 -200
  41. package/dist/walletUtils.d.ts +4 -0
  42. package/dist/walletUtils.d.ts.map +1 -1
  43. package/dist/wallets.d.ts +2 -1
  44. package/dist/wallets.d.ts.map +1 -1
  45. package/dist/widget/components/AccountActionsDropdown.d.ts.map +1 -1
  46. package/dist/widget/components/AccountIntentTransactionHistoryButton.d.ts.map +1 -1
  47. package/dist/widget/components/AccountSettings.d.ts.map +1 -1
  48. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  49. package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
  50. package/dist/widget/components/ConnectedWallets.d.ts +5 -1
  51. package/dist/widget/components/ConnectedWallets.d.ts.map +1 -1
  52. package/dist/widget/components/DepositTracker.d.ts +1 -1
  53. package/dist/widget/components/DepositTracker.d.ts.map +1 -1
  54. package/dist/widget/components/DirectTransfer.d.ts +0 -8
  55. package/dist/widget/components/DirectTransfer.d.ts.map +1 -1
  56. package/dist/widget/components/Fund.d.ts +1 -1
  57. package/dist/widget/components/Fund.d.ts.map +1 -1
  58. package/dist/widget/components/FundMethods.d.ts.map +1 -1
  59. package/dist/widget/components/FundWalletSelection.d.ts +0 -8
  60. package/dist/widget/components/FundWalletSelection.d.ts.map +1 -1
  61. package/dist/widget/components/FundingMethodSelectorButton.d.ts +1 -1
  62. package/dist/widget/components/FundingMethodSelectorButton.d.ts.map +1 -1
  63. package/dist/widget/components/MeldStepsFlow.d.ts.map +1 -1
  64. package/dist/widget/components/OnrampErrorScreen.d.ts.map +1 -1
  65. package/dist/widget/components/OnrampPaymentMethods.d.ts.map +1 -1
  66. package/dist/widget/components/OnrampProviderConfirmation.d.ts +0 -6
  67. package/dist/widget/components/OnrampProviderConfirmation.d.ts.map +1 -1
  68. package/dist/widget/components/Pay.d.ts.map +1 -1
  69. package/dist/widget/components/QrCode.d.ts.map +1 -1
  70. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  71. package/dist/widget/components/Receipt.d.ts.map +1 -1
  72. package/dist/widget/components/ReceiptRecoverableFunds.d.ts +25 -0
  73. package/dist/widget/components/ReceiptRecoverableFunds.d.ts.map +1 -0
  74. package/dist/widget/components/RecipientSelectorButton.d.ts +3 -1
  75. package/dist/widget/components/RecipientSelectorButton.d.ts.map +1 -1
  76. package/dist/widget/components/Recipients.d.ts.map +1 -1
  77. package/dist/widget/components/Swap.d.ts +2 -16
  78. package/dist/widget/components/Swap.d.ts.map +1 -1
  79. package/dist/widget/components/TokenSelector.d.ts.map +1 -1
  80. package/dist/widget/components/TransactionDetails.d.ts.map +1 -1
  81. package/dist/widget/components/TransactionHistoryItem.d.ts.map +1 -1
  82. package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -1
  83. package/dist/widget/components/TruncatedTransactionHash.d.ts.map +1 -1
  84. package/dist/widget/components/WalletConfirmation.d.ts.map +1 -1
  85. package/dist/widget/components/WalletConnect.d.ts.map +1 -1
  86. package/dist/widget/components/WidgetProviders.d.ts.map +1 -1
  87. package/dist/widget/components/Withdraw.d.ts.map +1 -1
  88. package/dist/widget/css/compiled.css +1 -1
  89. package/dist/widget/hooks/useClickTracking.d.ts.map +1 -1
  90. package/dist/widget/hooks/useDebugScreens.d.ts +1 -10
  91. package/dist/widget/hooks/useDebugScreens.d.ts.map +1 -1
  92. package/dist/widget/hooks/useDepositMonitor.d.ts +2 -4
  93. package/dist/widget/hooks/useDepositMonitor.d.ts.map +1 -1
  94. package/dist/widget/hooks/useExternalFundingReceiptSync.d.ts +11 -0
  95. package/dist/widget/hooks/useExternalFundingReceiptSync.d.ts.map +1 -0
  96. package/dist/widget/hooks/useIntentReceiptBalances.d.ts +16 -0
  97. package/dist/widget/hooks/useIntentReceiptBalances.d.ts.map +1 -0
  98. package/dist/widget/hooks/useQuote.d.ts +0 -4
  99. package/dist/widget/hooks/useQuote.d.ts.map +1 -1
  100. package/dist/widget/hooks/useScreenTracking.d.ts +2 -0
  101. package/dist/widget/hooks/useScreenTracking.d.ts.map +1 -0
  102. package/dist/widget/hooks/useSelectedFundMethod.d.ts +0 -2
  103. package/dist/widget/hooks/useSelectedFundMethod.d.ts.map +1 -1
  104. package/dist/widget/hooks/useSendForm.d.ts +0 -4
  105. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  106. package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
  107. package/dist/widget/hooks/useTrailsSendTransaction.d.ts.map +1 -1
  108. package/dist/widget/hooks/useViewManager.d.ts +89 -0
  109. package/dist/widget/hooks/useViewManager.d.ts.map +1 -0
  110. package/dist/widget/hooks/useWalletConnectUri.d.ts.map +1 -1
  111. package/dist/widget/hooks/useWalletConnectionContext.d.ts +1 -1
  112. package/dist/widget/hooks/useWalletConnectionContext.d.ts.map +1 -1
  113. package/dist/widget/index.d.ts +1 -1
  114. package/dist/widget/index.d.ts.map +1 -1
  115. package/dist/widget/index.js +7 -6
  116. package/dist/widget/providers/TrailsProvider.d.ts.map +1 -1
  117. package/dist/widget/types/commonProps.d.ts +1 -6
  118. package/dist/widget/types/commonProps.d.ts.map +1 -1
  119. package/dist/widget/utils/forexRateStore.d.ts.map +1 -1
  120. package/dist/widget/utils/fundMethodSwitchState.d.ts +10 -0
  121. package/dist/widget/utils/fundMethodSwitchState.d.ts.map +1 -0
  122. package/dist/widget/utils/localeStore.d.ts.map +1 -1
  123. package/dist/widget/utils/viewManagerGuards.d.ts +5 -0
  124. package/dist/widget/utils/viewManagerGuards.d.ts.map +1 -0
  125. package/dist/widget/widget.d.ts +23 -2
  126. package/dist/widget/widget.d.ts.map +1 -1
  127. package/package.json +2 -2
  128. package/src/abis/trailsHydrate.ts +2 -1
  129. package/src/analytics.ts +60 -0
  130. package/src/chainSwitch.ts +11 -8
  131. package/src/chains.ts +82 -37
  132. package/src/constants.ts +2 -2
  133. package/src/error.ts +8 -0
  134. package/src/index.ts +1 -12
  135. package/src/intentReceiptPoller.ts +27 -0
  136. package/src/intents.ts +36 -87
  137. package/src/mutations.ts +11 -102
  138. package/src/onramp-client/index.ts +3 -3
  139. package/src/prepareSend.ts +6 -2
  140. package/src/query/balance.hooks.ts +31 -10
  141. package/src/query/chains.hooks.ts +7 -1
  142. package/src/query/chains.queries.ts +8 -5
  143. package/src/queryParams.ts +8 -6
  144. package/src/recover.ts +9 -9
  145. package/src/tokens.ts +4 -2
  146. package/src/transactionIntent/deposits/depositOrchestrator.ts +0 -2
  147. package/src/transactionIntent/deposits/gaslessDeposit.ts +8 -0
  148. package/src/transactionIntent/deposits/standardDeposit.ts +25 -35
  149. package/src/transactionIntent/handlers/intentHandler.ts +234 -138
  150. package/src/transactionIntent/helpers/transactionStateHelpers.ts +108 -1
  151. package/src/transactionIntent/types.ts +14 -8
  152. package/src/transactionIntent/utils/resilientDepositTracker.ts +72 -183
  153. package/src/transactions.ts +16 -0
  154. package/src/walletUtils.ts +188 -1
  155. package/src/wallets.ts +50 -15
  156. package/src/widget/compiled.css +1 -1
  157. package/src/widget/components/AccountActionsDropdown.tsx +4 -6
  158. package/src/widget/components/AccountIntentTransactionHistoryButton.tsx +4 -6
  159. package/src/widget/components/AccountSettings.tsx +36 -22
  160. package/src/widget/components/ClassicSwap.tsx +67 -9
  161. package/src/widget/components/ConnectWallet.tsx +5 -7
  162. package/src/widget/components/ConnectedWallets.tsx +143 -82
  163. package/src/widget/components/DepositTracker.tsx +4 -5
  164. package/src/widget/components/DirectTransfer.tsx +85 -84
  165. package/src/widget/components/Earn.tsx +3 -3
  166. package/src/widget/components/Fund.tsx +90 -17
  167. package/src/widget/components/FundMethods.tsx +77 -43
  168. package/src/widget/components/FundWalletSelection.tsx +13 -397
  169. package/src/widget/components/FundingMethodSelectorButton.tsx +11 -10
  170. package/src/widget/components/MeldStepsFlow.tsx +64 -30
  171. package/src/widget/components/OnrampErrorScreen.tsx +2 -18
  172. package/src/widget/components/OnrampPaymentMethods.tsx +4 -6
  173. package/src/widget/components/OnrampProviderConfirmation.tsx +91 -110
  174. package/src/widget/components/OriginTransferInformation.tsx +2 -2
  175. package/src/widget/components/Pay.tsx +27 -7
  176. package/src/widget/components/PaymentMethods.tsx +10 -10
  177. package/src/widget/components/PoolDeposit.tsx +2 -2
  178. package/src/widget/components/QrCode.tsx +13 -11
  179. package/src/widget/components/QuoteDetails.tsx +16 -6
  180. package/src/widget/components/Receipt.tsx +66 -6
  181. package/src/widget/components/ReceiptRecoverableFunds.tsx +135 -0
  182. package/src/widget/components/RecipientSelectorButton.tsx +6 -17
  183. package/src/widget/components/Recipients.tsx +38 -29
  184. package/src/widget/components/Swap.tsx +2 -25
  185. package/src/widget/components/TokenList.tsx +2 -2
  186. package/src/widget/components/TokenSelector.tsx +11 -11
  187. package/src/widget/components/TokenSelectorButton.tsx +3 -3
  188. package/src/widget/components/TrailsHookModal.tsx +1 -1
  189. package/src/widget/components/TransactionDetails.tsx +43 -37
  190. package/src/widget/components/TransactionHistoryItem.tsx +1 -42
  191. package/src/widget/components/TransferPendingVertical.tsx +11 -4
  192. package/src/widget/components/TruncatedTransactionHash.tsx +5 -0
  193. package/src/widget/components/WalletConfirmation.tsx +5 -8
  194. package/src/widget/components/WalletConnect.tsx +6 -2
  195. package/src/widget/components/WidgetProviders.tsx +34 -43
  196. package/src/widget/components/Withdraw.tsx +25 -11
  197. package/src/widget/hooks/useClickTracking.ts +5 -0
  198. package/src/widget/hooks/useDebugScreens.ts +40 -86
  199. package/src/widget/hooks/useDepositMonitor.ts +14 -149
  200. package/src/widget/hooks/useExternalFundingReceiptSync.ts +79 -0
  201. package/src/widget/hooks/useIntentReceiptBalances.ts +141 -0
  202. package/src/widget/hooks/useQuote.ts +7 -16
  203. package/src/widget/hooks/useScreenTracking.ts +14 -0
  204. package/src/widget/hooks/useSelectedFundMethod.tsx +0 -5
  205. package/src/widget/hooks/useSendForm.ts +5 -14
  206. package/src/widget/hooks/useTokenList.ts +3 -16
  207. package/src/widget/hooks/useTrailsSendTransaction.ts +1 -5
  208. package/src/widget/hooks/useViewManager.tsx +505 -0
  209. package/src/widget/hooks/useWalletConnectUri.tsx +77 -18
  210. package/src/widget/hooks/useWalletConnectionContext.tsx +1 -1
  211. package/src/widget/index.tsx +1 -0
  212. package/src/widget/providers/TrailsProvider.tsx +0 -41
  213. package/src/widget/styles.ts +1 -1
  214. package/src/widget/types/commonProps.ts +0 -8
  215. package/src/widget/utils/forexRateStore.ts +0 -2
  216. package/src/widget/utils/fundMethodSwitchState.ts +25 -0
  217. package/src/widget/utils/localeStore.ts +0 -1
  218. package/src/widget/utils/viewManagerGuards.ts +49 -0
  219. package/src/widget/widget.tsx +405 -316
  220. package/dist/intentStorage.d.ts +0 -24
  221. package/dist/intentStorage.d.ts.map +0 -1
  222. package/dist/mode.d.ts +0 -2
  223. package/dist/mode.d.ts.map +0 -1
  224. package/dist/widget/hooks/useBack.d.ts +0 -22
  225. package/dist/widget/hooks/useBack.d.ts.map +0 -1
  226. package/dist/widget/hooks/useCurrentScreen.d.ts +0 -13
  227. package/dist/widget/hooks/useCurrentScreen.d.ts.map +0 -1
  228. package/dist/widget/hooks/useInitialRedirect.d.ts +0 -7
  229. package/dist/widget/hooks/useInitialRedirect.d.ts.map +0 -1
  230. package/dist/widget/hooks/useMode.d.ts +0 -20
  231. package/dist/widget/hooks/useMode.d.ts.map +0 -1
  232. package/dist/widget/hooks/usePreviousScreen.d.ts +0 -12
  233. package/dist/widget/hooks/usePreviousScreen.d.ts.map +0 -1
  234. package/dist/widget/workers/intentExecutionWorker.d.ts +0 -73
  235. package/dist/widget/workers/intentExecutionWorker.d.ts.map +0 -1
  236. package/src/intentStorage.ts +0 -106
  237. package/src/mode.ts +0 -1
  238. package/src/widget/hooks/useBack.tsx +0 -210
  239. package/src/widget/hooks/useCurrentScreen.tsx +0 -73
  240. package/src/widget/hooks/useInitialRedirect.tsx +0 -70
  241. package/src/widget/hooks/useMode.tsx +0 -51
  242. package/src/widget/hooks/usePreviousScreen.ts +0 -36
  243. package/src/widget/workers/intentExecutionWorker.ts +0 -502
@@ -1,4 +1,4 @@
1
- import { ChevronRight, Search } from "lucide-react"
1
+ import { ArrowLeftRight, ChevronRight, Search } from "lucide-react"
2
2
  import type React from "react"
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from "react"
4
4
  import { getChainInfo } from "../../chains.js"
@@ -9,11 +9,10 @@ import { formatUsdAmountLocaleDisplay } from "../../utils/format.js"
9
9
  import type { Token } from "../../tokens.js"
10
10
  import { isPassthroughEligible } from "../../utils/passthrough.js"
11
11
  import { useClickTracking } from "../hooks/useClickTracking.js"
12
- import { useCurrentScreen } from "../hooks/useCurrentScreen.js"
13
12
  import { useDefaultDestinationToken } from "../hooks/useDefaultDestinationToken.js"
14
13
  import { useDefaultOriginToken } from "../hooks/useDefaultOriginToken.js"
15
14
  import { useDestinationSelectedToken } from "../hooks/useDestinationSelectedToken.js"
16
- import { useMode } from "../hooks/useMode.js"
15
+ import { useViewManager } from "../hooks/useViewManager.js"
17
16
  import { useOriginSelectedToken } from "../hooks/useOriginSelectedToken.js"
18
17
  import { usePayMessage } from "../hooks/usePayMessage.js"
19
18
  import type { ProcessedFeeOption } from "../hooks/useSelectedFeeOption.js"
@@ -76,7 +75,7 @@ export const Pay: React.FC<PayProps> = ({
76
75
  toCalldata,
77
76
  onAmountUpdate,
78
77
  }) => {
79
- const { mode } = useMode()
78
+ const { mode, navigate } = useViewManager()
80
79
  const { selectedToken: globalOriginToken, setSelectedToken: setOriginToken } =
81
80
  useOriginSelectedToken()
82
81
  const {
@@ -86,7 +85,6 @@ export const Pay: React.FC<PayProps> = ({
86
85
  } = useDestinationSelectedToken()
87
86
  const { selectedRecipient, setSelectedRecipient } = useSelectedRecipient()
88
87
  const { setAmount: setGlobalAmount, clearAmount } = useSwapAmount()
89
- const { setCurrentScreen } = useCurrentScreen()
90
88
  const { targetAmountUsd } = useTargetAmount()
91
89
  const { enterFormMode } = useSwapState()
92
90
 
@@ -552,7 +550,7 @@ export const Pay: React.FC<PayProps> = ({
552
550
  setShowOriginChainList(true)
553
551
  }}
554
552
  onNavigateToFundMethods={() => {
555
- setCurrentScreen("payment-methods")
553
+ navigate("payment-methods")
556
554
  }}
557
555
  />
558
556
  </div>
@@ -611,6 +609,17 @@ export const Pay: React.FC<PayProps> = ({
611
609
  headerContent="Pay"
612
610
  headerContentAlign="left"
613
611
  showAccountActions={true}
612
+ customActions={
613
+ <button
614
+ type="button"
615
+ onClick={() => navigate("swap", { backTarget: "send-form" })}
616
+ className="flex h-8 px-3 justify-center items-center gap-1.5 rounded-full bg-gray-50 dark:bg-gray-700 cursor-pointer transition-colors text-gray-900 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
617
+ title="Swap"
618
+ >
619
+ <ArrowLeftRight className="h-4 w-4" />
620
+ <span className="text-sm font-medium">Swap</span>
621
+ </button>
622
+ }
614
623
  />
615
624
  <RequiredPropsError
616
625
  missingProps={missingRequiredProps}
@@ -627,6 +636,17 @@ export const Pay: React.FC<PayProps> = ({
627
636
  headerContent="Pay"
628
637
  headerContentAlign="left"
629
638
  showAccountActions={true}
639
+ customActions={
640
+ <button
641
+ type="button"
642
+ onClick={() => navigate("swap", { backTarget: "send-form" })}
643
+ className="flex h-8 px-3 justify-center items-center gap-1.5 rounded-full bg-gray-50 dark:bg-gray-700 cursor-pointer transition-colors text-gray-900 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
644
+ title="Swap"
645
+ >
646
+ <ArrowLeftRight className="h-4 w-4" />
647
+ <span className="text-sm font-medium">Swap</span>
648
+ </button>
649
+ }
630
650
  />
631
651
 
632
652
  {isPaymentRequest ? (
@@ -851,7 +871,7 @@ export const Pay: React.FC<PayProps> = ({
851
871
  /* Interactive button - user can select recipient */
852
872
  <button
853
873
  type="button"
854
- onClick={() => setCurrentScreen("recipients")}
874
+ onClick={() => navigate("recipients")}
855
875
  className="w-full flex items-center justify-between space-x-3 hover:trails-hover-bg hover:bg-gray-50 dark:hover:bg-gray-700 trails-border-radius-list-button px-4 py-2 transition-all duration-200 cursor-pointer"
856
876
  >
857
877
  <div className="text-left">
@@ -3,7 +3,6 @@ import { QrCode, ArrowLeftRight, ChevronRight } from "lucide-react"
3
3
  import { useSwitchAccount } from "wagmi"
4
4
  import { ScreenHeader } from "./ScreenHeader.js"
5
5
  import { ConnectedWallets } from "./ConnectedWallets.js"
6
- import { useCurrentScreen } from "../hooks/useCurrentScreen.js"
7
6
  import { useConnections } from "wagmi"
8
7
  import { logger } from "../../logger.js"
9
8
  import { useSelectedFundMethod } from "../hooks/useSelectedFundMethod.js"
@@ -11,7 +10,8 @@ import {
11
10
  type PaymentMethod,
12
11
  useOnRampPaymentMethods,
13
12
  } from "../hooks/useOnRampPaymentMethods.js"
14
- import { useMode } from "../hooks/useMode.js"
13
+ import { useViewManager } from "../hooks/useViewManager.js"
14
+ import { useWidgetProps } from "../hooks/useWidgetProps.js"
15
15
 
16
16
  export interface PaymentMethodsProps {
17
17
  onBack?: () => void
@@ -26,10 +26,10 @@ const PaymentMethods: React.FC<PaymentMethodsProps> = ({
26
26
  }) => {
27
27
  const { switchAccount } = useSwitchAccount()
28
28
  const connections = useConnections()
29
- const { setCurrentScreen } = useCurrentScreen()
30
- const { setSelectedFundMethod, setIsMeldOnRamp, setPaymentMethod } =
31
- useSelectedFundMethod()
32
- const { mode } = useMode()
29
+ const { mode, goHome } = useViewManager()
30
+ const { setSelectedFundMethod, setPaymentMethod } = useSelectedFundMethod()
31
+ const { fundOptions } = useWidgetProps()
32
+ const hideWallets = fundOptions?.hideWallets ?? []
33
33
 
34
34
  // Only call useOnRampPaymentMethods if onramp is enabled
35
35
  const { paymentMethods, isLoading, error } = useOnRampPaymentMethods({
@@ -59,7 +59,7 @@ const PaymentMethods: React.FC<PaymentMethodsProps> = ({
59
59
  setSelectedFundMethod("wallet")
60
60
 
61
61
  // Navigate to home screen which will redirect to the appropriate mode screen
62
- setCurrentScreen("home")
62
+ goHome()
63
63
  }
64
64
  } catch (error) {
65
65
  logger.console.error("[trails-sdk] Failed to switch wallet:", error)
@@ -82,6 +82,7 @@ const PaymentMethods: React.FC<PaymentMethodsProps> = ({
82
82
  showConnectNewWallet={true}
83
83
  onWalletSelect={handleWalletSelect}
84
84
  backScreen="payment-methods"
85
+ hiddenWallets={hideWallets as string[]}
85
86
  />
86
87
 
87
88
  {/* Divider */}
@@ -120,12 +121,11 @@ const PaymentMethods: React.FC<PaymentMethodsProps> = ({
120
121
  type="button"
121
122
  onClick={() => {
122
123
  setSelectedFundMethod("onramp-meld")
123
- setIsMeldOnRamp(true)
124
124
  setPaymentMethod({
125
125
  id: method.paymentMethod,
126
126
  name: method.name,
127
127
  })
128
- setCurrentScreen("home")
128
+ goHome()
129
129
  }}
130
130
  className="w-full text-left px-3 py-4 text-sm flex items-center justify-between cursor-pointer transition-colors trails-text-primary trails-hover-bg"
131
131
  >
@@ -157,7 +157,7 @@ const PaymentMethods: React.FC<PaymentMethodsProps> = ({
157
157
  setSelectedFundMethod("onramp-mesh")
158
158
  // Navigate to home screen so user can fill out the form
159
159
  // When they click "Continue to Exchange", it will navigate to onramp screen
160
- setCurrentScreen("home")
160
+ goHome()
161
161
  }}
162
162
  className="w-full text-left px-3 py-4 text-sm flex items-center justify-between cursor-pointer transition-colors trails-text-primary trails-hover-bg"
163
163
  >
@@ -22,7 +22,7 @@ import { useAmountUsd } from "../hooks/useAmountUsd.js"
22
22
  import { useBalanceVisible } from "../hooks/useBalanceVisible.js"
23
23
  import type { CheckoutOnHandlers } from "../hooks/useCheckout.js"
24
24
  import { useEarnPool } from "../hooks/useEarnPool.js"
25
- import { useMode } from "../hooks/useMode.js"
25
+ import { useViewManager } from "../hooks/useViewManager.js"
26
26
  import { useOriginSelectedToken } from "../hooks/useOriginSelectedToken.js"
27
27
  import type { ProcessedFeeOption } from "../hooks/useSelectedFeeOption.js"
28
28
  import type { OnCompleteProps } from "../hooks/useSendForm.js"
@@ -88,7 +88,7 @@ export const PoolDeposit: React.FC<PoolDepositProps> = ({
88
88
  onTrackToken,
89
89
  onPoolSelectorStateChange,
90
90
  }) => {
91
- const { mode } = useMode()
91
+ const { mode } = useViewManager()
92
92
  const { isBalanceVisible } = useBalanceVisible()
93
93
  const { selectedToken: originToken, setSelectedToken: setOriginToken } =
94
94
  useOriginSelectedToken()
@@ -54,12 +54,14 @@ export const QrCode: React.FC<QrCodeProps> = ({
54
54
  const matrixSize = matrix.length
55
55
  if (!matrixSize) return
56
56
 
57
- const padding = 4
57
+ const quietZoneModules = 4
58
58
  const fillColor = "#000000"
59
59
  const backgroundColor = "#ffffff"
60
- const cellSize = (size - padding * 2) / matrixSize
60
+ const cellSize = size / (matrixSize + quietZoneModules * 2)
61
+ const qrOrigin = quietZoneModules * cellSize
62
+ const qrCodeSize = matrixSize * cellSize
61
63
  const shouldReserveLogoSpace = Boolean(imageUrl)
62
- const logoSize = shouldReserveLogoSpace ? size * 0.2 : 0
64
+ const logoSize = shouldReserveLogoSpace ? qrCodeSize * 0.2 : 0
63
65
  const logoMatrixSize = shouldReserveLogoSpace
64
66
  ? Math.max(2, Math.floor(logoSize / cellSize))
65
67
  : 0
@@ -111,9 +113,9 @@ export const QrCode: React.FC<QrCodeProps> = ({
111
113
  )
112
114
  rect.setAttribute(
113
115
  "x",
114
- (padding + currentRunStart * cellSize).toFixed(3),
116
+ (qrOrigin + currentRunStart * cellSize).toFixed(3),
115
117
  )
116
- rect.setAttribute("y", (padding + rowIndex * cellSize).toFixed(3))
118
+ rect.setAttribute("y", (qrOrigin + rowIndex * cellSize).toFixed(3))
117
119
  rect.setAttribute("width", (runLength * cellSize).toFixed(3))
118
120
  rect.setAttribute("height", cellSize.toFixed(3))
119
121
  rect.setAttribute("fill", fillColor)
@@ -138,9 +140,9 @@ export const QrCode: React.FC<QrCodeProps> = ({
138
140
  )
139
141
  rect.setAttribute(
140
142
  "x",
141
- (padding + currentRunStart * cellSize).toFixed(3),
143
+ (qrOrigin + currentRunStart * cellSize).toFixed(3),
142
144
  )
143
- rect.setAttribute("y", (padding + rowIndex * cellSize).toFixed(3))
145
+ rect.setAttribute("y", (qrOrigin + rowIndex * cellSize).toFixed(3))
144
146
  rect.setAttribute("width", (runLength * cellSize).toFixed(3))
145
147
  rect.setAttribute("height", cellSize.toFixed(3))
146
148
  rect.setAttribute("fill", fillColor)
@@ -159,9 +161,9 @@ export const QrCode: React.FC<QrCodeProps> = ({
159
161
  )
160
162
  rect.setAttribute(
161
163
  "x",
162
- (padding + currentRunStart * cellSize).toFixed(3),
164
+ (qrOrigin + currentRunStart * cellSize).toFixed(3),
163
165
  )
164
- rect.setAttribute("y", (padding + rowIndex * cellSize).toFixed(3))
166
+ rect.setAttribute("y", (qrOrigin + rowIndex * cellSize).toFixed(3))
165
167
  rect.setAttribute("width", (runLength * cellSize).toFixed(3))
166
168
  rect.setAttribute("height", cellSize.toFixed(3))
167
169
  rect.setAttribute("fill", fillColor)
@@ -170,8 +172,8 @@ export const QrCode: React.FC<QrCodeProps> = ({
170
172
  })
171
173
 
172
174
  if (imageUrl) {
173
- const logoX = (size - logoSize) / 2
174
- const logoY = (size - logoSize) / 2
175
+ const logoX = qrOrigin + (qrCodeSize - logoSize) / 2
176
+ const logoY = qrOrigin + (qrCodeSize - logoSize) / 2
175
177
 
176
178
  const logoBackground = document.createElementNS(
177
179
  "http://www.w3.org/2000/svg",
@@ -15,7 +15,10 @@ import {
15
15
  formatUsdAmountDisplay,
16
16
  formatUsdAmountLocaleDisplay,
17
17
  } from "../../utils/format.js"
18
- import type { TransactionState } from "../../transactions.js"
18
+ import {
19
+ type TransactionState,
20
+ isDisplayableTransactionHash,
21
+ } from "../../transactions.js"
19
22
  import { isNativeToken, truncateAddress } from "../../utils/address.js"
20
23
  import { isSameChainSameToken } from "../../utils/passthrough.js"
21
24
  import { usePriceImpactWarning } from "../hooks/usePriceImpactWarning.js"
@@ -77,9 +80,11 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
77
80
  ? onRampQuote?.totalFee / (fiatToUsdExchangeRate ?? 1)
78
81
  : 0
79
82
 
80
- logger.console.log("[trails-sdk] OnRamp Quote", {
81
- onRampQuote,
82
- })
83
+ if (onRampQuote) {
84
+ logger.console.log("[trails-sdk] OnRamp Quote", {
85
+ onRampQuote,
86
+ })
87
+ }
83
88
 
84
89
  // Sync with initialExpanded prop changes
85
90
  useEffect(() => {
@@ -1078,10 +1083,15 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
1078
1083
  {displayStates.map((txState, index) => {
1079
1084
  const liveTxState = txState as TransactionState
1080
1085
  const hasTxHash =
1081
- hasLiveStates && liveTxState.transactionHash
1086
+ hasLiveStates &&
1087
+ isDisplayableTransactionHash(
1088
+ liveTxState.transactionHash,
1089
+ )
1082
1090
  const txExplorerUrl =
1083
1091
  liveTxState.explorerUrl ||
1084
- (liveTxState.transactionHash && liveTxState.chainId
1092
+ (isDisplayableTransactionHash(
1093
+ liveTxState.transactionHash,
1094
+ ) && liveTxState.chainId
1085
1095
  ? getExplorerUrl({
1086
1096
  txHash: liveTxState.transactionHash,
1087
1097
  chainId: liveTxState.chainId,
@@ -2,20 +2,26 @@ import { useQuery } from "@tanstack/react-query"
2
2
  import type React from "react"
3
3
  import type { ReactNode } from "react"
4
4
  import { useEffect, useMemo, useState } from "react"
5
+ import { useAccount } from "wagmi"
5
6
  import { getChainInfo } from "../../chains.js"
6
7
  import { getExplorerUrl } from "../../explorer.js"
7
8
  import { logger } from "../../logger.js"
8
9
  import type { PrepareSendQuote } from "../../prepareSend.js"
9
- import type { TransactionState } from "../../transactions.js"
10
+ import {
11
+ type TransactionState,
12
+ isDisplayableTransactionHash,
13
+ } from "../../transactions.js"
10
14
  import { getTxTimeDiff } from "../../transactions.js"
11
- import { formatDuration } from "../../utils/time.js"
15
+ import { SECOND_MS, formatDuration } from "../../utils/time.js"
12
16
  import { hasMetaTxError } from "../../utils/passthrough.js"
17
+ import { useIntentReceiptBalances } from "../hooks/useIntentReceiptBalances.js"
13
18
  import type { OnrampQuote } from "../hooks/useOnRampQuote.js"
14
19
  import { useTrails } from "../providers/TrailsProvider.js"
15
20
  import { hasAnyFailedOrAbortedTransactions } from "../utils/transactionFailure.js"
16
21
  import { ChainImage } from "./ChainImage.js"
17
22
  import { GreenCheckAnimation } from "./GreenCheckAnimation.js"
18
23
  import { QuoteDetails } from "./QuoteDetails.js"
24
+ import ReceiptRecoverableFunds from "./ReceiptRecoverableFunds.js"
19
25
  import { ScreenHeader } from "./ScreenHeader.js"
20
26
  import { YellowWarningAnimation } from "./YellowWarningAnimation.js"
21
27
 
@@ -73,12 +79,15 @@ function useReceipt(transactionStates?: TransactionState[]) {
73
79
  const latestTxWithHash = (transactionStates || [])
74
80
  .slice()
75
81
  .reverse()
76
- .find((tx) => tx.transactionHash && tx.chainId)
82
+ .find(
83
+ (tx) => isDisplayableTransactionHash(tx.transactionHash) && tx.chainId,
84
+ )
77
85
 
78
86
  // Generate explorer URL if we have a hash but no URL
79
87
  const finalExplorerUrl =
80
88
  latestTxWithHash?.explorerUrl ||
81
- (latestTxWithHash?.transactionHash && latestTxWithHash?.chainId
89
+ (isDisplayableTransactionHash(latestTxWithHash?.transactionHash) &&
90
+ latestTxWithHash?.chainId
82
91
  ? getExplorerUrl({
83
92
  txHash: latestTxWithHash.transactionHash,
84
93
  chainId: latestTxWithHash.chainId,
@@ -110,6 +119,7 @@ export const Receipt: React.FC<ReceiptProps> = ({
110
119
  actionButtonText,
111
120
  onRampQuote,
112
121
  }) => {
122
+ const { address } = useAccount()
113
123
  const { trailsAppUrl } = useTrails()
114
124
  const [showContent, setShowContent] = useState(false)
115
125
  const [showRefundInfo, setShowRefundInfo] = useState(false)
@@ -208,6 +218,38 @@ export const Receipt: React.FC<ReceiptProps> = ({
208
218
  if (!trailsAppUrl || !quote?.intentId) return null
209
219
  return `${trailsAppUrl}/intent/${quote.intentId}`
210
220
  }
221
+ const trailsIntentUrl = intentReceiptUrl()
222
+ const [isRecoverableFundsDelayElapsed, setIsRecoverableFundsDelayElapsed] =
223
+ useState(false)
224
+
225
+ useEffect(() => {
226
+ if (!quote?.intentId) {
227
+ setIsRecoverableFundsDelayElapsed(false)
228
+ return
229
+ }
230
+
231
+ setIsRecoverableFundsDelayElapsed(false)
232
+
233
+ const timeoutId = setTimeout(() => {
234
+ setIsRecoverableFundsDelayElapsed(true)
235
+ }, 2 * SECOND_MS)
236
+
237
+ return () => {
238
+ clearTimeout(timeoutId)
239
+ }
240
+ }, [quote?.intentId])
241
+
242
+ const {
243
+ chainGroups: recoverableChainGroups,
244
+ hasRecoverableFunds,
245
+ isLoading: isRecoverableFundsLoading,
246
+ error: recoverableFundsError,
247
+ refetch: refetchRecoverableFunds,
248
+ } = useIntentReceiptBalances({
249
+ intentId: quote?.intentId ?? undefined,
250
+ ownerAddress: address,
251
+ enabled: isRecoverableFundsDelayElapsed && !!quote?.intentId,
252
+ })
211
253
 
212
254
  // Use provided totalCompletionSeconds if available, otherwise use calculated time
213
255
  const completionTimeSeconds =
@@ -256,8 +298,8 @@ export const Receipt: React.FC<ReceiptProps> = ({
256
298
  )
257
299
 
258
300
  // Only show error state if we truly have no transaction hash at all OR if any transaction is aborted
259
- const hasAnyTransactionHash = transactionStates.some(
260
- (tx) => tx.transactionHash,
301
+ const hasAnyTransactionHash = transactionStates.some((tx) =>
302
+ isDisplayableTransactionHash(tx.transactionHash),
261
303
  )
262
304
 
263
305
  // Log intent ID if available when aborted (for debugging)
@@ -358,6 +400,15 @@ export const Receipt: React.FC<ReceiptProps> = ({
358
400
  </div>
359
401
  )}
360
402
 
403
+ <ReceiptRecoverableFunds
404
+ hasRecoverableFunds={hasRecoverableFunds}
405
+ chainGroups={recoverableChainGroups}
406
+ isLoading={isRecoverableFundsLoading}
407
+ error={recoverableFundsError?.message || null}
408
+ trailsIntentUrl={trailsIntentUrl}
409
+ onRefresh={refetchRecoverableFunds}
410
+ />
411
+
361
412
  {/* Quote Details - Show even in failed state */}
362
413
  {quoteDetailsSection}
363
414
 
@@ -604,6 +655,15 @@ export const Receipt: React.FC<ReceiptProps> = ({
604
655
  </div>
605
656
  )}
606
657
 
658
+ <ReceiptRecoverableFunds
659
+ hasRecoverableFunds={hasRecoverableFunds}
660
+ chainGroups={recoverableChainGroups}
661
+ isLoading={isRecoverableFundsLoading}
662
+ error={recoverableFundsError?.message || null}
663
+ trailsIntentUrl={trailsIntentUrl}
664
+ onRefresh={refetchRecoverableFunds}
665
+ />
666
+
607
667
  {/* Quote Details */}
608
668
  {quoteDetailsSection}
609
669
 
@@ -0,0 +1,135 @@
1
+ import type React from "react"
2
+ import { getChainInfo } from "../../chains.js"
3
+ import { ChainImage } from "./ChainImage.js"
4
+
5
+ export type RecoverableToken = {
6
+ chainId: number
7
+ contractAddress: string
8
+ symbol: string
9
+ decimals: number
10
+ rawBalance: string
11
+ formattedBalance: string
12
+ }
13
+
14
+ export type RecoverableChainGroup = {
15
+ intentAddress: string
16
+ chainId: number
17
+ tokens: RecoverableToken[]
18
+ }
19
+
20
+ interface ReceiptRecoverableFundsProps {
21
+ hasRecoverableFunds: boolean
22
+ chainGroups: RecoverableChainGroup[]
23
+ isLoading?: boolean
24
+ error?: string | null
25
+ trailsIntentUrl?: string | null
26
+ onRefresh?: () => void
27
+ }
28
+
29
+ export const ReceiptRecoverableFunds: React.FC<
30
+ ReceiptRecoverableFundsProps
31
+ > = ({
32
+ hasRecoverableFunds,
33
+ chainGroups,
34
+ isLoading = false,
35
+ error = null,
36
+ trailsIntentUrl,
37
+ onRefresh,
38
+ }) => {
39
+ if (isLoading) return null
40
+
41
+ if (error) {
42
+ return (
43
+ <div className="rounded-xl bg-gray-100 dark:bg-gray-800 p-3">
44
+ <p className="text-sm text-gray-600 dark:text-gray-400">
45
+ Could not verify remaining funds right now.
46
+ </p>
47
+ {onRefresh && (
48
+ <button
49
+ type="button"
50
+ onClick={onRefresh}
51
+ className="mt-2 text-sm font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300 cursor-pointer"
52
+ >
53
+ Retry
54
+ </button>
55
+ )}
56
+ </div>
57
+ )
58
+ }
59
+
60
+ if (!hasRecoverableFunds || chainGroups.length === 0) {
61
+ return null
62
+ }
63
+
64
+ return (
65
+ <div className="rounded-xl bg-warning p-[1px]">
66
+ <div className="rounded-xl bg-background-overlay p-4">
67
+ <div className="flex items-center justify-between gap-3">
68
+ <h3 className="text-sm font-semibold text-gray-900 dark:text-white">
69
+ Funds available to recover
70
+ </h3>
71
+ {trailsIntentUrl && (
72
+ <a
73
+ href={trailsIntentUrl}
74
+ target="_blank"
75
+ rel="noopener noreferrer"
76
+ className="inline-flex items-center gap-1 text-xs font-medium text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
77
+ >
78
+ Recover
79
+ <svg
80
+ className="w-3 h-3 text-blue-600 dark:text-blue-400"
81
+ fill="none"
82
+ viewBox="0 0 24 24"
83
+ stroke="currentColor"
84
+ aria-hidden="true"
85
+ >
86
+ <title>External Link</title>
87
+ <path
88
+ strokeLinecap="round"
89
+ strokeLinejoin="round"
90
+ strokeWidth={2}
91
+ d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
92
+ />
93
+ </svg>
94
+ </a>
95
+ )}
96
+ </div>
97
+
98
+ <div className="mt-3 space-y-3">
99
+ {chainGroups.map((group) => {
100
+ const chainName = getChainInfo(group.chainId)?.name || "Unknown"
101
+
102
+ return (
103
+ <div key={`${group.intentAddress}-${group.chainId}`}>
104
+ <div className="mb-2 flex items-center gap-2">
105
+ <ChainImage chainId={group.chainId} size={14} />
106
+ <span className="text-xs font-medium text-gray-700 dark:text-gray-300">
107
+ {chainName}
108
+ </span>
109
+ </div>
110
+
111
+ <div className="space-y-1">
112
+ {group.tokens.map((token) => (
113
+ <div
114
+ key={`${token.chainId}-${token.contractAddress}`}
115
+ className="flex items-center justify-between rounded-lg bg-gray-100 dark:bg-gray-800 px-2 py-1.5"
116
+ >
117
+ <span className="text-xs text-gray-600 dark:text-gray-400 truncate">
118
+ {token.symbol}
119
+ </span>
120
+ <span className="text-xs font-medium text-gray-900 dark:text-white">
121
+ {token.formattedBalance}
122
+ </span>
123
+ </div>
124
+ ))}
125
+ </div>
126
+ </div>
127
+ )
128
+ })}
129
+ </div>
130
+ </div>
131
+ </div>
132
+ )
133
+ }
134
+
135
+ export default ReceiptRecoverableFunds
@@ -1,27 +1,16 @@
1
1
  import { ChevronRight } from "lucide-react"
2
2
  import type React from "react"
3
- import { useBack } from "../hooks/useBack.js"
4
- import { useCurrentScreen } from "../hooks/useCurrentScreen.js"
5
- import { useMode } from "../hooks/useMode.js"
6
- import { useSelectedRecipient } from "../hooks/useSelectedRecipient.js"
3
+ import { useViewManager } from "../hooks/useViewManager.js"
7
4
  import { AddressOrEnsName } from "./AddressOrEnsName.js"
8
5
  import { AddressWalletIcon } from "./AddressWalletIcon.js"
9
6
 
10
- export const RecipientSelectorButton: React.FC = () => {
11
- const { setCurrentScreenWithBack } = useBack()
12
- const { mode } = useMode()
13
- const { currentScreen } = useCurrentScreen()
14
- const { selectedRecipient } = useSelectedRecipient()
7
+ export const RecipientSelectorButton: React.FC<{
8
+ selectedRecipient: string | null
9
+ }> = ({ selectedRecipient }) => {
10
+ const { navigate, screen } = useViewManager()
15
11
 
16
12
  const handleClick = () => {
17
- // Determine back screen based on current screen or mode
18
- let backScreen: "fund-form" | "withdraw" | "home" = "home"
19
- if (currentScreen === "withdraw") {
20
- backScreen = "withdraw"
21
- } else if (mode === "fund" || currentScreen === "fund-form") {
22
- backScreen = "fund-form"
23
- }
24
- setCurrentScreenWithBack("recipients", backScreen)
13
+ navigate("recipients", { backTarget: screen })
25
14
  }
26
15
 
27
16
  return (