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,11 +1,10 @@
1
1
  import type React from "react"
2
2
  import { ChevronRight, CreditCard, Wallet, ZapIcon } from "lucide-react"
3
- import { useAccount } from "wagmi"
3
+ import { useAccount, useConnections, useSwitchAccount } from "wagmi"
4
4
  import { ScreenHeader } from "./ScreenHeader.js"
5
- import { useCurrentScreen } from "../hooks/useCurrentScreen.js"
6
- import { useConnections } from "wagmi"
7
5
  import { useSelectedFundMethod } from "../hooks/useSelectedFundMethod.js"
8
- import { useMode } from "../hooks/useMode.js"
6
+ import { useViewManager } from "../hooks/useViewManager.js"
7
+ import { useWalletConnectionContext } from "../hooks/useWalletConnectionContext.js"
9
8
  import { useWallets, wagmiConnectorToWalletId } from "../../wallets.js"
10
9
  import ExchangeIcon from "../assets/Exchange-icon-black.svg"
11
10
  import WalletChange from "../assets/WalletChange-black.svg"
@@ -13,6 +12,7 @@ import { truncateAddress } from "../../utils/address.js"
13
12
  import { useResolveEns } from "../../ens.js"
14
13
  import { AddressWalletIcon } from "./AddressWalletIcon.js"
15
14
  import { useWidgetProps } from "../hooks/useWidgetProps.js"
15
+ import { useAccountTotalBalanceUsd } from "../../query/balance.hooks.js"
16
16
  import type { FundMethod } from "../../transactionIntent/types.js"
17
17
  import type { FundMethodListOption } from "../widget.js"
18
18
 
@@ -40,14 +40,11 @@ const FundMethods: React.FC<FundMethodsProps> = ({
40
40
  }) => {
41
41
  const { address, connector } = useAccount()
42
42
  const connections = useConnections()
43
- const { setCurrentScreen } = useCurrentScreen()
44
- const {
45
- selectedFundMethod,
46
- setSelectedFundMethod,
47
- setIsMeldOnRamp,
48
- setPaymentMethod,
49
- } = useSelectedFundMethod()
50
- const { mode } = useMode()
43
+ const { switchAccount } = useSwitchAccount()
44
+ const { navigate, mode } = useViewManager()
45
+ const { selectedFundMethod, setSelectedFundMethod, setPaymentMethod } =
46
+ useSelectedFundMethod()
47
+ const { setConnectionContext } = useWalletConnectionContext()
51
48
  const { wallets: allWallets } = useWallets()
52
49
  const { fundOptions } = useWidgetProps()
53
50
  const hideWallets = fundOptions?.hideWallets ?? []
@@ -94,19 +91,28 @@ const FundMethods: React.FC<FundMethodsProps> = ({
94
91
 
95
92
  const connectedWallets = getConnectedWallets()
96
93
 
97
- const activeConnection =
98
- connectedWallets.find((wallet) => wallet.isActive) || connectedWallets[0]
94
+ const eligibleConnectedWallets = connectedWallets.filter((wallet) => {
95
+ if (
96
+ hideWallets.length > 0 &&
97
+ hideWallets.some(
98
+ (addr) => addr.toLowerCase() === wallet.address.toLowerCase(),
99
+ )
100
+ ) {
101
+ return false
102
+ }
103
+ return true
104
+ })
99
105
 
100
- const isActiveWalletHidden =
101
- hideWallets.length > 0 &&
102
- activeConnection?.address &&
103
- hideWallets.some(
104
- (addr) => addr.toLowerCase() === activeConnection.address.toLowerCase(),
105
- )
106
+ const activeConnection =
107
+ eligibleConnectedWallets.find((wallet) => wallet.isActive) ||
108
+ eligibleConnectedWallets[0]
106
109
 
107
- const showWalletInline = activeConnection && !isActiveWalletHidden
110
+ const { data: activeWalletBalanceUsd = 0 } = useAccountTotalBalanceUsd(
111
+ activeConnection?.address || null,
112
+ )
113
+ const hasActiveWalletBalance = activeWalletBalanceUsd > 0
108
114
 
109
- const displayMeshExchange = !!onramp // MeshConnect Exchange enabled when onramp prop is provided
115
+ const showWalletInline = !!activeConnection && hasActiveWalletBalance
110
116
 
111
117
  const fundMethodAliases: Record<FundMethodListOption, FundMethod> = {
112
118
  "connected-wallet": "wallet",
@@ -164,44 +170,68 @@ const FundMethods: React.FC<FundMethodsProps> = ({
164
170
  listedInternalSet.size > 0 &&
165
171
  !listedInternalSet.has(method)
166
172
 
173
+ const displayMeshExchange = !!onramp // MeshConnect Exchange enabled when onramp prop is provided
174
+
167
175
  const renderFundMethod = (method: FundMethod) => {
168
176
  const forceDisabled = isUnlisted(method)
169
177
  if (method === "wallet") {
170
178
  if (showWalletInline) {
179
+ // Inline row only shown when wallet has balance, so always selectable unless unlisted
180
+ const canSelectWallet = !forceDisabled
181
+ const rowDisabled = forceDisabled
171
182
  return (
172
183
  <div
173
184
  key="wallet-inline"
174
185
  onClick={
175
- forceDisabled
176
- ? undefined
177
- : () => {
186
+ canSelectWallet
187
+ ? () => {
178
188
  setSelectedFundMethod("wallet")
189
+ if (
190
+ activeConnection &&
191
+ activeConnection.address?.toLowerCase() !==
192
+ address?.toLowerCase()
193
+ ) {
194
+ switchAccount({ connector: activeConnection.connector })
195
+ }
179
196
  if (onSelectConnectedAccount) {
180
197
  onSelectConnectedAccount()
181
198
  }
182
199
  }
200
+ : undefined
183
201
  }
184
202
  onKeyDown={
185
- forceDisabled
186
- ? undefined
187
- : (e) => {
203
+ canSelectWallet
204
+ ? (e) => {
188
205
  if (e.key === "Enter" || e.key === " ") {
189
206
  e.preventDefault()
190
207
  setSelectedFundMethod("wallet")
208
+ if (
209
+ activeConnection &&
210
+ activeConnection.address?.toLowerCase() !==
211
+ address?.toLowerCase()
212
+ ) {
213
+ switchAccount({
214
+ connector: activeConnection.connector,
215
+ })
216
+ }
191
217
  if (onSelectConnectedAccount) {
192
218
  onSelectConnectedAccount()
193
219
  }
194
220
  }
195
221
  }
222
+ : undefined
196
223
  }
224
+ aria-disabled={!canSelectWallet}
197
225
  className={`w-full text-left px-4 py-3 flex items-center justify-between transition-colors rounded-xl trails-hover-bg ${
198
- forceDisabled
226
+ rowDisabled
199
227
  ? disabledClassname
200
- : `cursor-pointer ${
201
- selectedFundMethod === "wallet"
202
- ? "bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-600"
203
- : ""
204
- }`
228
+ : canSelectWallet
229
+ ? `cursor-pointer ${
230
+ selectedFundMethod === "wallet"
231
+ ? "bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-600"
232
+ : ""
233
+ }`
234
+ : "cursor-default"
205
235
  }`}
206
236
  >
207
237
  <div className="flex items-center gap-3 flex-1">
@@ -222,9 +252,9 @@ const FundMethods: React.FC<FundMethodsProps> = ({
222
252
  type="button"
223
253
  onClick={(e) => {
224
254
  e.stopPropagation()
225
- setCurrentScreen("select-funding-wallet")
255
+ navigate("select-funding-wallet")
226
256
  }}
227
- className="ml-auto mr-2 p-2 rounded-full bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors"
257
+ className="ml-auto mr-2 p-2 rounded-full bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 transition-colors cursor-pointer"
228
258
  title="Switch wallet"
229
259
  >
230
260
  <img
@@ -239,7 +269,6 @@ const FundMethods: React.FC<FundMethodsProps> = ({
239
269
  </div>
240
270
  )
241
271
  }
242
-
243
272
  return (
244
273
  <button
245
274
  key="wallet-button"
@@ -249,7 +278,13 @@ const FundMethods: React.FC<FundMethodsProps> = ({
249
278
  forceDisabled
250
279
  ? undefined
251
280
  : () => {
252
- setCurrentScreen(
281
+ if (!activeConnection) {
282
+ setConnectionContext(
283
+ "fund-method-selection",
284
+ "fund-methods",
285
+ )
286
+ }
287
+ navigate(
253
288
  activeConnection ? "select-funding-wallet" : "wallet-list",
254
289
  )
255
290
  }
@@ -262,7 +297,7 @@ const FundMethods: React.FC<FundMethodsProps> = ({
262
297
  >
263
298
  <div className="flex items-center gap-3">
264
299
  <Wallet className="w-8 h-8 text-gray-700 dark:text-gray-200" />
265
- <span className="text-sm font-medium">Connected wallet</span>
300
+ <span className="text-sm font-medium">Connect wallet</span>
266
301
  </div>
267
302
  <ChevronRight className="w-5 h-5 text-gray-400" />
268
303
  </button>
@@ -271,7 +306,7 @@ const FundMethods: React.FC<FundMethodsProps> = ({
271
306
 
272
307
  if (method === "onramp-meld") {
273
308
  if (!isOnrampEnabled) return null
274
- const disabled = forceDisabled || !activeConnection
309
+ const disabled = forceDisabled
275
310
  return (
276
311
  <button
277
312
  key="onramp-meld"
@@ -282,7 +317,6 @@ const FundMethods: React.FC<FundMethodsProps> = ({
282
317
  ? undefined
283
318
  : () => {
284
319
  setSelectedFundMethod("onramp-meld")
285
- setIsMeldOnRamp(true)
286
320
  setPaymentMethod({
287
321
  id: "CREDIT_DEBIT_CARD",
288
322
  name: "Credit/Debit Card",
@@ -308,7 +342,7 @@ const FundMethods: React.FC<FundMethodsProps> = ({
308
342
  }
309
343
 
310
344
  if (method === "direct-transfer") {
311
- const disabled = forceDisabled || !activeConnection
345
+ const disabled = forceDisabled
312
346
  return (
313
347
  <button
314
348
  key="direct-transfer"
@@ -361,7 +395,7 @@ const FundMethods: React.FC<FundMethodsProps> = ({
361
395
  <img
362
396
  src={ExchangeIcon}
363
397
  alt="Exchange"
364
- className="w-8 h-8 text-gray-700 dark:text-gray-100"
398
+ className="w-8 h-8 dark:invert dark:brightness-150"
365
399
  />
366
400
  <span className="text-sm font-medium">From Exchange</span>
367
401
  </div>
@@ -1,47 +1,23 @@
1
- import { ChevronRight, Wallet, X } from "lucide-react"
2
- import { useEffect, useState } from "react"
3
- import {
4
- useAccount,
5
- useConnections,
6
- useDisconnect,
7
- useSwitchAccount,
8
- } from "wagmi"
9
- import { logger } from "../../logger.js"
10
- import { useAccountTotalBalanceUsd } from "../../query/balance.hooks.js"
11
- import {
12
- formatUsdAmountDisplay,
13
- formatUsdAmountLocaleDisplay,
14
- } from "../../utils/format.js"
15
- import { useWallets, wagmiConnectorToWalletId } from "../../wallets.js"
16
- import { useBack } from "../hooks/useBack.js"
17
- import type { Screen } from "../hooks/useCurrentScreen.js"
18
- import { useCurrentScreen } from "../hooks/useCurrentScreen.js"
19
- import { useMode } from "../hooks/useMode.js"
20
- import { usePreviousScreen } from "../hooks/usePreviousScreen.js"
1
+ import { useConnections, useSwitchAccount } from "wagmi"
2
+ import { ConnectedWallets } from "./ConnectedWallets.js"
3
+ import { useViewManager } from "../hooks/useViewManager.js"
21
4
  import { useSelectedFundMethod } from "../hooks/useSelectedFundMethod.js"
22
- import { useSelectedRecipient } from "../hooks/useSelectedRecipient.js"
23
- import { useWalletConnectionContext } from "../hooks/useWalletConnectionContext.js"
24
5
  import { useWidgetProps } from "../hooks/useWidgetProps.js"
25
- import { AddressOrEnsName } from "./AddressOrEnsName.js"
26
- import { AddressWalletIcon } from "./AddressWalletIcon.js"
27
- import { CopyButton } from "./CopyButton.js"
28
6
  import { ScreenHeader } from "./ScreenHeader.js"
29
7
 
30
8
  export const FundWalletSelection: React.FC = () => {
31
- const { setCurrentScreen } = useCurrentScreen()
32
- const { getPreviousScreen } = useBack()
33
- const { setPreviousScreen } = usePreviousScreen()
9
+ const { navigate, backScreen, mode, goHome } = useViewManager()
34
10
  const connections = useConnections()
35
11
  const { switchAccount } = useSwitchAccount()
36
12
  const { setSelectedFundMethod } = useSelectedFundMethod()
37
- const { mode } = useMode()
38
- const { fundOptions } = useWidgetProps()
13
+ const { fundOptions, hideDisconnect, decoupleWagmi } = useWidgetProps()
39
14
  const hideWallets = fundOptions?.hideWallets ?? []
15
+ const showDisconnect = !hideDisconnect && !decoupleWagmi
40
16
 
41
17
  return (
42
18
  <div className="flex flex-col h-full">
43
19
  <ScreenHeader
44
- onBack={() => setCurrentScreen(getPreviousScreen() ?? "fund-methods")}
20
+ onBack={() => navigate(backScreen ?? "fund-methods")}
45
21
  headerContent="Select a wallet"
46
22
  headerContentAlign="left"
47
23
  rightSideContent={<div className="w-9" />}
@@ -50,9 +26,11 @@ export const FundWalletSelection: React.FC = () => {
50
26
  <div className="flex flex-col gap-1">
51
27
  <ConnectedWallets
52
28
  showConnectNewWallet={true}
53
- hiddenWallets={hideWallets}
29
+ showDisconnect={showDisconnect}
30
+ hiddenWallets={hideWallets as string[]}
31
+ disableZeroBalanceWallets={true}
32
+ showZeroBalanceMessage={true}
54
33
  onWalletSelect={(walletAddress, walletConnector) => {
55
- // Find the connection for this wallet
56
34
  const connection = connections.find(
57
35
  (conn) =>
58
36
  conn.accounts.includes(walletAddress as `0x${string}`) &&
@@ -66,11 +44,10 @@ export const FundWalletSelection: React.FC = () => {
66
44
  // Set funding method to "wallet" since user selected a wallet
67
45
  setSelectedFundMethod("wallet")
68
46
 
69
- setPreviousScreen("select-funding-wallet")
70
47
  if (mode === "fund") {
71
- setCurrentScreen("tokens")
48
+ navigate("tokens")
72
49
  } else {
73
- setCurrentScreen("home")
50
+ goHome()
74
51
  }
75
52
  }
76
53
  }}
@@ -81,364 +58,3 @@ export const FundWalletSelection: React.FC = () => {
81
58
  </div>
82
59
  )
83
60
  }
84
-
85
- export interface ConnectedWalletsProps {
86
- onWalletSwitch?: (address: string) => void
87
- onWalletSelect?: (address: string, connector: any) => void
88
- showActiveWallet?: boolean
89
- showConnectNewWallet?: boolean
90
- backScreen?: string
91
- hiddenWallets?: string[]
92
- }
93
-
94
- const ConnectedWallets: React.FC<ConnectedWalletsProps> = ({
95
- onWalletSwitch,
96
- onWalletSelect,
97
- showActiveWallet = true,
98
- showConnectNewWallet = false,
99
- backScreen = "connect",
100
- hiddenWallets = [],
101
- }) => {
102
- const { address, connector } = useAccount()
103
- const connections = useConnections()
104
- const { switchAccount } = useSwitchAccount()
105
- const { wallets: allWallets } = useWallets()
106
- const { disconnect } = useDisconnect()
107
- const { selectedRecipient, setSelectedRecipient } = useSelectedRecipient()
108
- const { setCurrentScreenWithBack } = useBack()
109
- const { setConnectionContext } = useWalletConnectionContext()
110
- const [error, setError] = useState<string | null>(null)
111
- const { hideAddWallet } = useWidgetProps()
112
-
113
- // If no connections, go back to fund methods
114
- useEffect(() => {
115
- if (connections.length === 0) {
116
- setCurrentScreenWithBack("fund-methods")
117
- }
118
- }, [connections.length, setCurrentScreenWithBack])
119
-
120
- // Get all connected wallets with their details
121
- const getConnectedWallets = () => {
122
- if (connections.length === 0) {
123
- return []
124
- }
125
-
126
- if (!address) {
127
- return []
128
- }
129
-
130
- const walletMap = new Map()
131
-
132
- connections.forEach((connection) => {
133
- // Process each account in the connection
134
- if (!connection || !connection.accounts) return
135
- connection.accounts.forEach((account) => {
136
- if (account && !walletMap.has(account)) {
137
- const walletId = wagmiConnectorToWalletId(connection.connector)
138
- const walletConfig = allWallets.find(
139
- (wallet) => wallet.id === walletId,
140
- )
141
-
142
- walletMap.set(account, {
143
- address: account,
144
- connector: connection.connector,
145
- walletConfig,
146
- walletId,
147
- isActive:
148
- connection.connector.id === connector?.id && account === address,
149
- })
150
- }
151
- })
152
- })
153
-
154
- return Array.from(walletMap.values())
155
- }
156
-
157
- const connectedWallets = getConnectedWallets()
158
-
159
- const visibleWallets = connectedWallets.filter((wallet) => {
160
- if (!showActiveWallet && wallet.isActive) {
161
- return false
162
- }
163
- if (
164
- hiddenWallets.length > 0 &&
165
- hiddenWallets.some(
166
- (addr) => addr.toLowerCase() === wallet.address.toLowerCase(),
167
- )
168
- ) {
169
- return false
170
- }
171
- return true
172
- })
173
-
174
- // Handle switching to a different connected wallet
175
- const handleWalletSwitch = async (
176
- walletAddress: string,
177
- walletConnector: any,
178
- ) => {
179
- if (connections.length === 0) {
180
- return
181
- }
182
-
183
- if (!address) {
184
- return
185
- }
186
-
187
- try {
188
- setError(null)
189
- // Find the connection for this wallet
190
- const connection = connections.find(
191
- (conn) =>
192
- conn.accounts.includes(walletAddress as `0x${string}`) &&
193
- conn.connector.id === walletConnector.id,
194
- )
195
-
196
- if (connection) {
197
- switchAccount({
198
- connector: connection.connector,
199
- })
200
-
201
- // Call the optional callback
202
- if (onWalletSwitch) {
203
- onWalletSwitch(walletAddress)
204
- }
205
- }
206
- } catch (error) {
207
- setError(
208
- error instanceof Error ? error.message : "Failed to switch wallet",
209
- )
210
- }
211
- }
212
-
213
- const handleDisconnect = async (
214
- walletConnector: any,
215
- e: React.MouseEvent,
216
- ) => {
217
- // Check connections first to avoid race condition
218
- if (connections.length === 0) {
219
- return
220
- }
221
-
222
- if (!address) {
223
- return
224
- }
225
-
226
- e.preventDefault()
227
- e.stopPropagation()
228
- try {
229
- setError(null)
230
-
231
- let disconnectedAddress: string | undefined
232
- try {
233
- const accounts = await walletConnector.getAccounts()
234
- disconnectedAddress = accounts?.[0]
235
- } catch (err) {
236
- logger.console.error("[trails-sdk] Failed to get accounts:", err)
237
- const connection = connections.find(
238
- (conn) => conn.connector.id === walletConnector.id,
239
- )
240
- disconnectedAddress = connection?.accounts[0]
241
- }
242
-
243
- disconnect({ connector: walletConnector })
244
-
245
- if (disconnectedAddress && selectedRecipient === disconnectedAddress) {
246
- const remainingWallets = getConnectedWallets()
247
- if (remainingWallets.length > 0) {
248
- const firstRemainingWallet = remainingWallets.find(
249
- (wallet) => wallet.address !== disconnectedAddress,
250
- )
251
- if (firstRemainingWallet) {
252
- setSelectedRecipient(firstRemainingWallet.address)
253
- }
254
- }
255
- }
256
- } catch (error) {
257
- setError(
258
- error instanceof Error ? error.message : "Failed to disconnect wallet",
259
- )
260
- }
261
- }
262
-
263
- if (connections.length === 0 || connectedWallets.length === 0) {
264
- return null
265
- }
266
-
267
- return (
268
- <>
269
- {error && (
270
- <div className="border rounded-lg p-4 bg-red-50 border-red-200 dark:bg-red-900/20 dark:border-red-800 mx-4 mb-2">
271
- <p className="text-sm wrap-break-word text-red-600 dark:text-red-200">
272
- {error}
273
- </p>
274
- </div>
275
- )}
276
-
277
- {/* Connected Wallets List */}
278
- {connectedWallets.map((wallet) => {
279
- // Skip active wallet if showActiveWallet is false
280
- if (!showActiveWallet && wallet.isActive) {
281
- return null
282
- }
283
- if (
284
- hiddenWallets.length > 0 &&
285
- hiddenWallets.some(
286
- (addr) => addr.toLowerCase() === wallet.address.toLowerCase(),
287
- )
288
- ) {
289
- return null
290
- }
291
-
292
- return (
293
- <WalletItem
294
- key={wallet.address}
295
- wallet={wallet}
296
- onWalletSwitch={handleWalletSwitch}
297
- onWalletSelect={onWalletSelect}
298
- onDisconnect={handleDisconnect}
299
- hideActiveState={backScreen === "recipients"}
300
- />
301
- )
302
- })}
303
-
304
- {/* Divider */}
305
- {showConnectNewWallet && !hideAddWallet && visibleWallets.length > 0 && (
306
- <div className="relative flex items-center justify-center my-4 px-4">
307
- <div className="flex-1 border-t border-gray-200 dark:border-gray-700"></div>
308
- <span className="px-4 text-sm text-gray-500 dark:text-gray-400 bg-white dark:bg-gray-900">
309
- or
310
- </span>
311
- <div className="flex-1 border-t border-gray-200 dark:border-gray-700"></div>
312
- </div>
313
- )}
314
-
315
- {/* Connect new wallet Button */}
316
- {showConnectNewWallet && !hideAddWallet && (
317
- <button
318
- type="button"
319
- onClick={() => {
320
- setConnectionContext("fund-method-selection", backScreen as Screen)
321
- setCurrentScreenWithBack(
322
- "wallet-list",
323
- "select-funding-wallet" as Screen,
324
- )
325
- }}
326
- className="w-full text-left px-4 py-3 flex items-center justify-between cursor-pointer transition-colors trails-hover-bg rounded-xl"
327
- >
328
- <div className="flex items-center gap-3">
329
- <Wallet className="w-8 h-8" />
330
- <span className="text-sm font-medium">Connect new wallet</span>
331
- </div>
332
- <ChevronRight className="w-5 h-5 text-gray-400" />
333
- </button>
334
- )}
335
- </>
336
- )
337
- }
338
-
339
- interface WalletItemProps {
340
- wallet: {
341
- address: string
342
- connector: any
343
- walletConfig: any
344
- walletId: string
345
- isActive: boolean
346
- }
347
- onWalletSwitch: (address: string, connector: any) => void
348
- onWalletSelect?: (address: string, connector: any) => void
349
- onDisconnect: (connector: any, e: React.MouseEvent) => void
350
- hideActiveState?: boolean
351
- }
352
-
353
- const WalletItem: React.FC<WalletItemProps> = ({
354
- wallet,
355
- onWalletSwitch,
356
- onWalletSelect,
357
- onDisconnect,
358
- }) => {
359
- const { data: totalBalanceUsd = 0, isLoading: isLoadingTotalBalanceUsd } =
360
- useAccountTotalBalanceUsd(wallet.address)
361
- const totalBalanceUsdFormatted = formatUsdAmountDisplay(totalBalanceUsd)
362
- const totalBalanceUsdLocaleDisplay =
363
- formatUsdAmountLocaleDisplay(totalBalanceUsd)
364
-
365
- const hasZeroBalance = !isLoadingTotalBalanceUsd && totalBalanceUsd === 0
366
-
367
- return (
368
- // biome-ignore lint/a11y/useSemanticElements: span used to avoid invalid nested button (row is already a button)
369
- <div
370
- role="button"
371
- tabIndex={hasZeroBalance ? -1 : 0}
372
- aria-disabled={hasZeroBalance}
373
- onClick={() => {
374
- if (hasZeroBalance) return
375
- if (onWalletSelect) {
376
- onWalletSelect(wallet.address, wallet.connector)
377
- } else if (!wallet.isActive) {
378
- onWalletSwitch(wallet.address, wallet.connector)
379
- }
380
- }}
381
- onKeyDown={(e) => {
382
- if (e.key === "Enter" || e.key === " ") {
383
- e.preventDefault()
384
- if (hasZeroBalance) return
385
- if (onWalletSelect) {
386
- onWalletSelect(wallet.address, wallet.connector)
387
- } else if (!wallet.isActive) {
388
- onWalletSwitch(wallet.address, wallet.connector)
389
- }
390
- }
391
- }}
392
- className={`w-full text-left px-4 py-3 flex items-center justify-between transition-colors rounded-xl ${hasZeroBalance ? "cursor-not-allowed opacity-50" : "cursor-pointer trails-hover-bg"} ${wallet.isActive ?? "bg-blue-50 dark:bg-blue-900/20 text-gray-700 dark:text-gray-300"}`}
393
- >
394
- <div className="flex items-center gap-3 flex-1">
395
- <div className="flex items-center justify-center shrink-0">
396
- <AddressWalletIcon
397
- size={30}
398
- walletAddress={wallet.address as `0x${string}`}
399
- />
400
- </div>
401
- <div className="flex flex-col min-w-0">
402
- <div className="flex items-center gap-1">
403
- <AddressOrEnsName
404
- address={wallet.address}
405
- className="text-sm font-medium"
406
- />
407
- <CopyButton
408
- text={wallet.address}
409
- size="sm"
410
- stopPropagation={true}
411
- className="p-1"
412
- as="span"
413
- />
414
- </div>
415
- {!isLoadingTotalBalanceUsd && hasZeroBalance ? (
416
- <span className="text-xs text-gray-400 dark:text-gray-500">
417
- No balance available for funding
418
- </span>
419
- ) : (
420
- !isLoadingTotalBalanceUsd &&
421
- totalBalanceUsdFormatted && (
422
- <span className="text-xs text-gray-500 dark:text-gray-400">
423
- {totalBalanceUsdLocaleDisplay || totalBalanceUsdFormatted}
424
- </span>
425
- )
426
- )}
427
- </div>
428
- </div>
429
- <div className="flex items-center gap-2">
430
- {onDisconnect && (
431
- <button
432
- type="button"
433
- onClick={(e) => onDisconnect(wallet.connector, e)}
434
- className="p-1 rounded-full hover:bg-gray-200 dark:hover:bg-gray-600 cursor-pointer"
435
- title="Disconnect wallet"
436
- >
437
- <X className="w-4 h-4 text-gray-500 dark:text-gray-400" />
438
- </button>
439
- )}
440
- </div>
441
- {!hasZeroBalance && <ChevronRight className="w-5 h-5 text-gray-400" />}
442
- </div>
443
- )
444
- }