0xtrails 0.2.2 → 0.2.5

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 (194) hide show
  1. package/dist/aave.d.ts +8 -0
  2. package/dist/aave.d.ts.map +1 -1
  3. package/dist/{ccip-ConT1gDe.js → ccip-CXlshvBY.js} +1 -1
  4. package/dist/chains.d.ts +5 -1
  5. package/dist/chains.d.ts.map +1 -1
  6. package/dist/config.d.ts +1 -1
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/constants.d.ts +5 -4
  9. package/dist/constants.d.ts.map +1 -1
  10. package/dist/error.d.ts +1 -0
  11. package/dist/error.d.ts.map +1 -1
  12. package/dist/estimate.d.ts +52 -0
  13. package/dist/estimate.d.ts.map +1 -1
  14. package/dist/{index-CMh8uEbV.js → index-_QuyGrjU.js} +86304 -83380
  15. package/dist/index.d.ts +4 -3
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +2 -2
  18. package/dist/intentEntrypoint.d.ts +0 -8
  19. package/dist/intentEntrypoint.d.ts.map +1 -1
  20. package/dist/intents.d.ts +40 -0
  21. package/dist/intents.d.ts.map +1 -1
  22. package/dist/metaTxnMonitor.d.ts +5 -4
  23. package/dist/metaTxnMonitor.d.ts.map +1 -1
  24. package/dist/metaTxns.d.ts +3 -3
  25. package/dist/metaTxns.d.ts.map +1 -1
  26. package/dist/morpho.d.ts +8 -0
  27. package/dist/morpho.d.ts.map +1 -1
  28. package/dist/prepareSend.d.ts +16 -6
  29. package/dist/prepareSend.d.ts.map +1 -1
  30. package/dist/queryParams.d.ts.map +1 -1
  31. package/dist/relayer.d.ts +10 -7
  32. package/dist/relayer.d.ts.map +1 -1
  33. package/dist/sequenceWallet.d.ts +3 -2
  34. package/dist/sequenceWallet.d.ts.map +1 -1
  35. package/dist/tokenBalances.d.ts +7 -0
  36. package/dist/tokenBalances.d.ts.map +1 -1
  37. package/dist/tokens.d.ts +2 -1
  38. package/dist/tokens.d.ts.map +1 -1
  39. package/dist/trails.d.ts +2 -2
  40. package/dist/trails.d.ts.map +1 -1
  41. package/dist/wallets.d.ts.map +1 -1
  42. package/dist/widget/components/AccountActionsDropdown.d.ts.map +1 -1
  43. package/dist/widget/components/AccountSettings.d.ts.map +1 -1
  44. package/dist/widget/components/ClassicSwap.d.ts +2 -0
  45. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  46. package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
  47. package/dist/widget/components/ConnectedWallets.d.ts +4 -0
  48. package/dist/widget/components/ConnectedWallets.d.ts.map +1 -1
  49. package/dist/widget/components/Earn.d.ts.map +1 -1
  50. package/dist/widget/components/EarnPools.d.ts.map +1 -1
  51. package/dist/widget/components/Fund.d.ts +1 -0
  52. package/dist/widget/components/Fund.d.ts.map +1 -1
  53. package/dist/widget/components/FundMethods.d.ts.map +1 -1
  54. package/dist/widget/components/{FundSendForm.d.ts → FundSwap.d.ts} +11 -5
  55. package/dist/widget/components/FundSwap.d.ts.map +1 -0
  56. package/dist/widget/components/FundingMethodSelectorButton.d.ts +4 -0
  57. package/dist/widget/components/FundingMethodSelectorButton.d.ts.map +1 -0
  58. package/dist/widget/components/Modal.d.ts.map +1 -1
  59. package/dist/widget/components/Pay.d.ts +1 -0
  60. package/dist/widget/components/Pay.d.ts.map +1 -1
  61. package/dist/widget/components/PercentageMaxButtons.d.ts +12 -0
  62. package/dist/widget/components/PercentageMaxButtons.d.ts.map +1 -0
  63. package/dist/widget/components/{PaySendForm.d.ts → PoolDeposit.d.ts} +11 -34
  64. package/dist/widget/components/PoolDeposit.d.ts.map +1 -0
  65. package/dist/widget/components/{SimpleSwap.d.ts → PoolWithdraw.d.ts} +16 -8
  66. package/dist/widget/components/PoolWithdraw.d.ts.map +1 -0
  67. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  68. package/dist/widget/components/Receive.d.ts.map +1 -1
  69. package/dist/widget/components/RecipientSelectorButton.d.ts +4 -0
  70. package/dist/widget/components/RecipientSelectorButton.d.ts.map +1 -0
  71. package/dist/widget/components/Recipients.d.ts.map +1 -1
  72. package/dist/widget/components/RefundWarning.d.ts +1 -0
  73. package/dist/widget/components/RefundWarning.d.ts.map +1 -1
  74. package/dist/widget/components/RequiredPropsError.d.ts +8 -0
  75. package/dist/widget/components/RequiredPropsError.d.ts.map +1 -0
  76. package/dist/widget/components/ScreenHeader.d.ts.map +1 -1
  77. package/dist/widget/components/SlippageToleranceSettings.d.ts.map +1 -1
  78. package/dist/widget/components/Swap.d.ts +1 -0
  79. package/dist/widget/components/Swap.d.ts.map +1 -1
  80. package/dist/widget/components/SwapSettings.d.ts.map +1 -1
  81. package/dist/widget/components/TokenImage.d.ts +1 -0
  82. package/dist/widget/components/TokenImage.d.ts.map +1 -1
  83. package/dist/widget/components/TokenList.d.ts.map +1 -1
  84. package/dist/widget/components/TokenSelector.d.ts.map +1 -1
  85. package/dist/widget/components/TokenSelectorButton.d.ts +16 -0
  86. package/dist/widget/components/TokenSelectorButton.d.ts.map +1 -0
  87. package/dist/widget/components/UserPreferences.d.ts.map +1 -1
  88. package/dist/widget/components/WaasFeeOptions.d.ts +8 -0
  89. package/dist/widget/components/WaasFeeOptions.d.ts.map +1 -0
  90. package/dist/widget/components/WalletConfirmation.d.ts.map +1 -1
  91. package/dist/widget/components/WalletList.d.ts.map +1 -1
  92. package/dist/widget/css/compiled.css +2 -0
  93. package/dist/widget/css/index.css +554 -0
  94. package/dist/widget/hooks/useBack.d.ts +6 -0
  95. package/dist/widget/hooks/useBack.d.ts.map +1 -1
  96. package/dist/widget/hooks/useCheckout.d.ts +1 -1
  97. package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
  98. package/dist/widget/hooks/useCurrentScreen.d.ts +1 -1
  99. package/dist/widget/hooks/useCurrentScreen.d.ts.map +1 -1
  100. package/dist/widget/hooks/useDefaultTokenSelection.d.ts +3 -3
  101. package/dist/widget/hooks/useDefaultTokenSelection.d.ts.map +1 -1
  102. package/dist/widget/hooks/useInitialRedirect.d.ts +7 -0
  103. package/dist/widget/hooks/useInitialRedirect.d.ts.map +1 -0
  104. package/dist/widget/hooks/usePayMessage.d.ts.map +1 -1
  105. package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +1 -1
  106. package/dist/widget/hooks/useSelectedFundMethod.d.ts +12 -0
  107. package/dist/widget/hooks/useSelectedFundMethod.d.ts.map +1 -0
  108. package/dist/widget/hooks/useSelectedRecipient.d.ts.map +1 -1
  109. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  110. package/dist/widget/index.js +1 -1
  111. package/dist/widget/widget.d.ts +4 -4
  112. package/dist/widget/widget.d.ts.map +1 -1
  113. package/package.json +30 -23
  114. package/src/aave.ts +32 -0
  115. package/src/chains.ts +23 -3
  116. package/src/config.ts +12 -4
  117. package/src/constants.ts +11 -16
  118. package/src/error.ts +20 -2
  119. package/src/estimate.ts +416 -5
  120. package/src/index.ts +8 -3
  121. package/src/intentEntrypoint.ts +0 -15
  122. package/src/intents.ts +161 -11
  123. package/src/metaTxnMonitor.ts +28 -22
  124. package/src/metaTxns.ts +3 -3
  125. package/src/morpho.ts +32 -0
  126. package/src/prepareSend.ts +710 -458
  127. package/src/queryParams.ts +2 -1
  128. package/src/relayer.ts +15 -16
  129. package/src/sequenceWallet.ts +7 -3
  130. package/src/tokenBalances.ts +47 -0
  131. package/src/tokens.ts +17 -1
  132. package/src/trails.ts +2 -2
  133. package/src/wallets.ts +8 -0
  134. package/src/widget/compiled.css +2 -2
  135. package/src/widget/components/AccountActionsDropdown.tsx +9 -15
  136. package/src/widget/components/AccountIntentTransactionHistory.tsx +1 -1
  137. package/src/widget/components/AccountSettings.tsx +10 -27
  138. package/src/widget/components/ChainFilterDropdown.tsx +1 -1
  139. package/src/widget/components/ChainList.tsx +1 -1
  140. package/src/widget/components/ClassicSwap.tsx +111 -155
  141. package/src/widget/components/ConnectWallet.tsx +10 -39
  142. package/src/widget/components/ConnectedWallets.tsx +113 -58
  143. package/src/widget/components/Earn.tsx +73 -589
  144. package/src/widget/components/EarnPools.tsx +2 -1
  145. package/src/widget/components/Fund.tsx +81 -109
  146. package/src/widget/components/FundMethods.tsx +82 -159
  147. package/src/widget/components/FundSwap.tsx +52 -0
  148. package/src/widget/components/FundingMethodSelectorButton.tsx +60 -0
  149. package/src/widget/components/Modal.tsx +6 -2
  150. package/src/widget/components/Pay.tsx +198 -200
  151. package/src/widget/components/PercentageMaxButtons.tsx +77 -0
  152. package/src/widget/components/PoolDeposit.tsx +593 -0
  153. package/src/widget/components/PoolWithdraw.tsx +903 -0
  154. package/src/widget/components/QuoteDetails.tsx +22 -8
  155. package/src/widget/components/Receive.tsx +1 -3
  156. package/src/widget/components/RecipientSelectorButton.tsx +42 -0
  157. package/src/widget/components/Recipients.tsx +64 -156
  158. package/src/widget/components/RefundWarning.tsx +5 -1
  159. package/src/widget/components/RequiredPropsError.tsx +33 -0
  160. package/src/widget/components/ScreenHeader.tsx +5 -1
  161. package/src/widget/components/SlippageToleranceSettings.tsx +2 -1
  162. package/src/widget/components/Swap.tsx +2 -43
  163. package/src/widget/components/SwapSettings.tsx +3 -15
  164. package/src/widget/components/TokenImage.tsx +21 -4
  165. package/src/widget/components/TokenList.tsx +0 -1
  166. package/src/widget/components/TokenSelector.tsx +2 -1
  167. package/src/widget/components/TokenSelectorButton.tsx +75 -0
  168. package/src/widget/components/UserPreferences.tsx +6 -24
  169. package/src/widget/components/WaasFeeOptions.tsx +331 -0
  170. package/src/widget/components/WalletConfirmation.tsx +55 -3
  171. package/src/widget/components/WalletList.tsx +7 -5
  172. package/src/widget/hooks/useBack.tsx +113 -9
  173. package/src/widget/hooks/useCheckout.ts +36 -20
  174. package/src/widget/hooks/useCurrentScreen.tsx +1 -0
  175. package/src/widget/hooks/useDefaultTokenSelection.tsx +104 -28
  176. package/src/widget/hooks/useInitialRedirect.tsx +70 -0
  177. package/src/widget/hooks/usePayMessage.tsx +86 -11
  178. package/src/widget/hooks/useSelectedFeeToken.tsx +10 -16
  179. package/src/widget/hooks/useSelectedFundMethod.tsx +41 -0
  180. package/src/widget/hooks/useSelectedRecipient.tsx +10 -0
  181. package/src/widget/hooks/useSendForm.ts +34 -12
  182. package/src/widget/hooks/useTokenList.ts +1 -1
  183. package/src/widget/index.css +27 -0
  184. package/src/widget/widget.tsx +245 -208
  185. package/dist/widget/components/FundSendForm.d.ts.map +0 -1
  186. package/dist/widget/components/PaySendForm.d.ts.map +0 -1
  187. package/dist/widget/components/SimpleSwap.d.ts.map +0 -1
  188. package/dist/widget/hooks/useSwapSettings.d.ts +0 -16
  189. package/dist/widget/hooks/useSwapSettings.d.ts.map +0 -1
  190. package/src/widget/components/FundSendForm.tsx +0 -903
  191. package/src/widget/components/PaySendForm.tsx +0 -869
  192. package/src/widget/components/SimpleSwap.tsx +0 -983
  193. package/src/widget/hooks/useSwapSettings.tsx +0 -100
  194. /package/dist/{style.css → 0xtrails.css} +0 -0
@@ -0,0 +1,70 @@
1
+ import { useEffect, useState } from "react"
2
+ import { useCurrentScreen, type Screen } from "./useCurrentScreen.js"
3
+ import { useBack } from "./useBack.js"
4
+ import { logger } from "../../logger.js"
5
+ import type { Mode } from "../../mode.js"
6
+
7
+ export function useInitialRedirect(
8
+ isConnected: boolean,
9
+ currentMode: Mode,
10
+ getInitialScreenForMode: (mode: Mode) => Screen,
11
+ ) {
12
+ const { setCurrentScreen } = useCurrentScreen()
13
+ const { getBreadcrumbHistory } = useBack()
14
+ const [hasConnectedBefore, setHasConnectedBefore] = useState(false)
15
+ const [isInitialScreenSet, setIsInitialScreenSet] = useState(false)
16
+
17
+ useEffect(() => {
18
+ if (!isConnected || isInitialScreenSet) {
19
+ return
20
+ }
21
+
22
+ // Check if this is the first time connecting (no previous wallet connected)
23
+ const isFirstTimeConnection = !hasConnectedBefore
24
+
25
+ if (isFirstTimeConnection) {
26
+ // First time connecting - go to appropriate mode screen
27
+ const initialScreen = getInitialScreenForMode(currentMode)
28
+ logger.console.log(
29
+ "[trails-sdk] First time connection, redirecting to:",
30
+ initialScreen,
31
+ )
32
+ setCurrentScreen(initialScreen)
33
+ setHasConnectedBefore(true)
34
+ } else {
35
+ // Subsequent connections - check if user came from account-settings
36
+ const breadcrumbHistory = getBreadcrumbHistory()
37
+ const lastBreadcrumbScreen =
38
+ breadcrumbHistory.length > 0
39
+ ? breadcrumbHistory[breadcrumbHistory.length - 1]
40
+ : null
41
+
42
+ if (lastBreadcrumbScreen === "account-settings") {
43
+ // User came from account-settings, return there
44
+ logger.console.log(
45
+ "[trails-sdk] Returning to account-settings after wallet connection",
46
+ )
47
+ setCurrentScreen("account-settings")
48
+ } else {
49
+ // User came from elsewhere, go to appropriate mode screen
50
+ const initialScreen = getInitialScreenForMode(currentMode)
51
+ logger.console.log(
52
+ "[trails-sdk] Subsequent connection, redirecting to:",
53
+ initialScreen,
54
+ )
55
+ setCurrentScreen(initialScreen)
56
+ }
57
+ setIsInitialScreenSet(true)
58
+ }
59
+ }, [
60
+ isConnected,
61
+ currentMode,
62
+ hasConnectedBefore,
63
+ getInitialScreenForMode,
64
+ setCurrentScreen,
65
+ getBreadcrumbHistory,
66
+ isInitialScreenSet,
67
+ ])
68
+
69
+ return { hasConnectedBefore, isInitialScreenSet }
70
+ }
@@ -8,6 +8,7 @@ import { truncateAddress } from "../../utils.js"
8
8
  import { getExplorerUrlForAddress } from "../../explorer.js"
9
9
  import ChainImage from "../components/ChainImage.js"
10
10
  import TokenImage from "../components/TokenImage.js"
11
+ import { Identicon } from "../components/Identicon.js"
11
12
  import { logger } from "../../logger.js"
12
13
 
13
14
  export interface PayMessagePart {
@@ -85,25 +86,23 @@ export function usePayMessage(): UsePayMessageReturn {
85
86
  })
86
87
 
87
88
  const parsed = useMemo(() => {
88
- // Default message if no payMessage provided
89
- const defaultMessage = appName
90
- ? `Pay {APP_IMAGE} {APP_NAME} {TO_AMOUNT_USD}`
91
- : `Pay {TO_AMOUNT_USD}`
92
-
93
- const template = payMessage || defaultMessage
89
+ // If no payMessage provided, return empty parts (default layout handled separately)
90
+ if (!payMessage) {
91
+ return []
92
+ }
94
93
 
95
94
  // Parse the template into parts
96
95
  const parts: PayMessagePart[] = []
97
96
  const regex = /\{([^}]+)\}/g
98
97
  let lastIndex = 0
99
- let match: RegExpExecArray | null = regex.exec(template)
98
+ let match: RegExpExecArray | null = regex.exec(payMessage)
100
99
 
101
100
  while (match !== null) {
102
101
  // Add text before the placeholder
103
102
  if (match.index > lastIndex) {
104
103
  parts.push({
105
104
  type: "text",
106
- value: template.substring(lastIndex, match.index),
105
+ value: payMessage.substring(lastIndex, match.index),
107
106
  })
108
107
  }
109
108
 
@@ -176,14 +175,14 @@ export function usePayMessage(): UsePayMessageReturn {
176
175
  }
177
176
 
178
177
  lastIndex = regex.lastIndex
179
- match = regex.exec(template)
178
+ match = regex.exec(payMessage)
180
179
  }
181
180
 
182
181
  // Add remaining text
183
- if (lastIndex < template.length) {
182
+ if (lastIndex < payMessage.length) {
184
183
  parts.push({
185
184
  type: "text",
186
- value: template.substring(lastIndex),
185
+ value: payMessage.substring(lastIndex),
187
186
  })
188
187
  }
189
188
 
@@ -206,6 +205,78 @@ export function usePayMessage(): UsePayMessageReturn {
206
205
 
207
206
  // Render the message
208
207
  const message = useMemo(() => {
208
+ // If no payMessage provided, render default layout
209
+ if (!payMessage) {
210
+ return (
211
+ <div className="flex flex-col items-center justify-center px-8 py-4 space-y-4 min-w-full">
212
+ {/* App image above the amount if it exists */}
213
+ {appImageUrl && (
214
+ <img
215
+ src={appImageUrl}
216
+ alt={appName || "App"}
217
+ className="w-12 h-12 rounded-lg"
218
+ onError={(e) => {
219
+ logger.console.error(
220
+ `Error loading app image: ${e}, appImageUrl: ${appImageUrl}`,
221
+ )
222
+ // Hide image on error
223
+ e.currentTarget.style.display = "none"
224
+ }}
225
+ />
226
+ )}
227
+
228
+ {/* Large amount in center */}
229
+ <div className="font-bold text-center">
230
+ {(() => {
231
+ const amountToShow = targetAmountUsdFormatted || toAmount || "0"
232
+ const tokenSymbol = tokenInfo?.symbol || ""
233
+ const displayText = targetAmountUsdFormatted
234
+ ? amountToShow
235
+ : `${amountToShow} ${tokenSymbol}`.trim()
236
+
237
+ // Dynamic font size based on text length
238
+ const textLength = displayText.length
239
+ let fontSize = "text-6xl" // Default large size
240
+
241
+ if (textLength > 12) {
242
+ fontSize = "text-2xl"
243
+ } else if (textLength > 10) {
244
+ fontSize = "text-3xl"
245
+ } else if (textLength > 8) {
246
+ fontSize = "text-4xl"
247
+ } else if (textLength > 6) {
248
+ fontSize = "text-5xl"
249
+ }
250
+
251
+ return <div className={fontSize}>{displayText}</div>
252
+ })()}
253
+ </div>
254
+
255
+ {/* Recipient info below */}
256
+ {toAddress && (
257
+ <div className="flex items-center space-x-2 text-center">
258
+ <span className="text-sm text-gray-600 dark:text-gray-400">
259
+ to
260
+ </span>
261
+ <Identicon value={toAddress} size={20} />
262
+ <a
263
+ href={getExplorerUrlForAddress({
264
+ address: toAddress,
265
+ chainId: toChainId ? Number(toChainId) : 1,
266
+ })}
267
+ target="_blank"
268
+ rel="noopener noreferrer"
269
+ className="text-sm hover:underline cursor-pointer text-blue-600 dark:text-blue-400"
270
+ >
271
+ {truncateAddress(toAddress)}
272
+ </a>
273
+ </div>
274
+ )}
275
+ </div>
276
+ )
277
+ }
278
+
279
+ // Render user-provided message with handlebar interpolation
209
280
  return (
210
281
  <>
211
282
  {parsed.map((part) => {
@@ -354,6 +425,7 @@ export function usePayMessage(): UsePayMessageReturn {
354
425
  </>
355
426
  )
356
427
  }, [
428
+ payMessage,
357
429
  parsed,
358
430
  appName,
359
431
  appUrl,
@@ -361,6 +433,9 @@ export function usePayMessage(): UsePayMessageReturn {
361
433
  appDescription,
362
434
  tokenInfo,
363
435
  toChainId,
436
+ toAddress,
437
+ targetAmountUsdFormatted,
438
+ toAmount,
364
439
  ])
365
440
 
366
441
  return {
@@ -65,22 +65,16 @@ export const SelectedFeeTokenProvider: React.FC<
65
65
  const [availableTokens, setAvailableTokens] = useState<TokenWithBalance[]>([])
66
66
 
67
67
  // Wrapper to log all state changes to selectedFeeToken
68
- const setSelectedFeeTokenInternal = useCallback(
69
- (token: FeeOption | null) => {
70
- logger.console.log(
71
- "[trails-sdk] [FEE-SELECT] selectedFeeToken state changing:",
72
- {
73
- from: selectedFeeToken,
74
- to: token,
75
- fromNull: selectedFeeToken === null,
76
- toNull: token === null,
77
- stackTrace: new Error().stack?.split("\n").slice(2, 5).join("\n"), // Get call stack
78
- },
79
- )
80
- setSelectedFeeTokenInternalRaw(token)
81
- },
82
- [selectedFeeToken],
83
- )
68
+ const setSelectedFeeTokenInternal = useCallback((token: FeeOption | null) => {
69
+ logger.console.log(
70
+ "[trails-sdk] [FEE-SELECT] selectedFeeToken state changing:",
71
+ {
72
+ to: token,
73
+ toNull: token === null,
74
+ },
75
+ )
76
+ setSelectedFeeTokenInternalRaw(token)
77
+ }, [])
84
78
 
85
79
  // Wrapper to track when user makes an explicit selection
86
80
  const setSelectedFeeToken = useCallback(
@@ -0,0 +1,41 @@
1
+ import { createContext, useContext, useState, type ReactNode } from "react"
2
+
3
+ interface SelectedFundMethodContextType {
4
+ selectedFundMethod: string
5
+ setSelectedFundMethod: (method: string) => void
6
+ }
7
+
8
+ const SelectedFundMethodContext = createContext<
9
+ SelectedFundMethodContextType | undefined
10
+ >(undefined)
11
+
12
+ interface SelectedFundMethodProviderProps {
13
+ children: ReactNode
14
+ }
15
+
16
+ export const SelectedFundMethodProvider = ({
17
+ children,
18
+ }: SelectedFundMethodProviderProps) => {
19
+ const [selectedFundMethod, setSelectedFundMethod] = useState<string>("wallet")
20
+
21
+ const value: SelectedFundMethodContextType = {
22
+ selectedFundMethod,
23
+ setSelectedFundMethod,
24
+ }
25
+
26
+ return (
27
+ <SelectedFundMethodContext.Provider value={value}>
28
+ {children}
29
+ </SelectedFundMethodContext.Provider>
30
+ )
31
+ }
32
+
33
+ export const useSelectedFundMethod = (): SelectedFundMethodContextType => {
34
+ const context = useContext(SelectedFundMethodContext)
35
+ if (context === undefined) {
36
+ throw new Error(
37
+ "useSelectedFundMethod must be used within a SelectedFundMethodProvider",
38
+ )
39
+ }
40
+ return context
41
+ }
@@ -2,8 +2,10 @@ import React, {
2
2
  createContext,
3
3
  useContext,
4
4
  useState,
5
+ useEffect,
5
6
  type ReactNode,
6
7
  } from "react"
8
+ import { useAccount } from "wagmi"
7
9
 
8
10
  interface SelectedRecipientContextType {
9
11
  selectedRecipient: string | null
@@ -21,10 +23,18 @@ interface SelectedRecipientProviderProps {
21
23
  export const SelectedRecipientProvider: React.FC<
22
24
  SelectedRecipientProviderProps
23
25
  > = ({ children }) => {
26
+ const { address } = useAccount()
24
27
  const [selectedRecipient, setSelectedRecipient] = useState<string | null>(
25
28
  null,
26
29
  )
27
30
 
31
+ // Set recipient to address only if address exists and no recipient is selected
32
+ useEffect(() => {
33
+ if (address && !selectedRecipient) {
34
+ setSelectedRecipient(address)
35
+ }
36
+ }, [address, selectedRecipient])
37
+
28
38
  return (
29
39
  <SelectedRecipientContext.Provider
30
40
  value={{
@@ -1,6 +1,6 @@
1
1
  import type { TokenPrice } from "@0xsequence/trails-api"
2
2
  import type React from "react"
3
- import { useCallback, useEffect, useMemo, useState } from "react"
3
+ import { useCallback, useEffect, useMemo, useState, useRef } from "react"
4
4
  import {
5
5
  type Account,
6
6
  getAddress,
@@ -9,6 +9,7 @@ import {
9
9
  type WalletClient,
10
10
  zeroAddress,
11
11
  } from "viem"
12
+ import { useAccount } from "wagmi"
12
13
  import { useAPIClient } from "../../apiClient.js"
13
14
  import { getChainInfo, useSupportedChains } from "../../chains.js"
14
15
  import { getFullErrorMessage, getPrettifiedErrorMessage } from "../../error.js"
@@ -207,6 +208,10 @@ export function useSendForm({
207
208
  checkoutOnHandlers,
208
209
  refetchTrigger = 0,
209
210
  }: UseSendProps): UseSendReturn {
211
+ // Get the active wallet ID from wagmi
212
+ const { connector } = useAccount()
213
+ const walletId = connector?.id
214
+
210
215
  // Auto-set quoteProvider to "lifi" if either from or to chain is etherlink
211
216
  const effectiveQuoteProvider = useMemo(() => {
212
217
  if (!quoteProvider || quoteProvider === "auto") {
@@ -441,6 +446,12 @@ export function useSendForm({
441
446
  allSupportedTokens: true, // Get all tokens for balance checking
442
447
  })
443
448
 
449
+ // Use ref to store latest filteredTokensFormatted without triggering re-renders
450
+ const filteredTokensFormattedRef = useRef(filteredTokensFormatted)
451
+ useEffect(() => {
452
+ filteredTokensFormattedRef.current = filteredTokensFormatted
453
+ }, [filteredTokensFormatted])
454
+
444
455
  const destTokenAddress = useTokenAddress({
445
456
  chainId: selectedDestinationChain?.id,
446
457
  tokenSymbol: selectedDestToken?.symbol,
@@ -798,6 +809,9 @@ export function useSendForm({
798
809
  nativeTokenPriceUsd = nativePrice?.price?.value ?? 0
799
810
  }
800
811
 
812
+ // Disable gasless for sequence-waas wallet
813
+ const effectiveGasless = walletId === "sequence-waas" ? false : gasless
814
+
801
815
  const options = {
802
816
  account,
803
817
  originTokenAddress: selectedToken.contractAddress,
@@ -834,13 +848,14 @@ export function useSendForm({
834
848
  paymasterUrls?.find(
835
849
  (p) => p.chainId.toString() === selectedToken.chainId.toString(),
836
850
  )?.url ?? undefined,
837
- gasless,
851
+ gasless: effectiveGasless,
838
852
  originNativeTokenPriceUsd: nativeTokenPriceUsd,
839
853
  quoteProvider: effectiveQuoteProvider,
840
854
  mode,
841
855
  fundMethod,
842
856
  checkoutOnHandlers,
843
857
  selectedFeeToken,
858
+ walletId,
844
859
  }
845
860
 
846
861
  logger.console.log(
@@ -895,6 +910,7 @@ export function useSendForm({
895
910
  checkoutOnHandlers,
896
911
  mode,
897
912
  selectedFeeToken,
913
+ walletId,
898
914
  ])
899
915
 
900
916
  // Auto-fetch quotes when inputs change (debounced)
@@ -945,7 +961,7 @@ export function useSendForm({
945
961
  return formatAmountDisplay(quotedDestinationAmount || "0")
946
962
  }, [quotedDestinationAmount])
947
963
 
948
- // Set raw fee options in the hook whenever prepareSendResult or tokens change
964
+ // Set raw fee options in the hook whenever prepareSendResult changes
949
965
  useEffect(() => {
950
966
  const apiFeeOptions = prepareSendResult?.feeOptions?.feeOptions ?? []
951
967
  logger.console.log(
@@ -961,15 +977,9 @@ export function useSendForm({
961
977
  setRawFeeOptions(
962
978
  apiFeeOptions,
963
979
  selectedToken?.chainId,
964
- filteredTokensFormatted,
980
+ filteredTokensFormattedRef.current,
965
981
  )
966
- // eslint-disable-next-line react-hooks/exhaustive-deps
967
- }, [
968
- prepareSendResult,
969
- selectedToken?.chainId,
970
- filteredTokensFormatted,
971
- setRawFeeOptions,
972
- ])
982
+ }, [prepareSendResult, selectedToken?.chainId, setRawFeeOptions])
973
983
 
974
984
  const processSend = useCallback(async () => {
975
985
  try {
@@ -1194,7 +1204,19 @@ export function useSendForm({
1194
1204
  }
1195
1205
 
1196
1206
  if (!fundMethod || fundMethod === "wallet") {
1197
- return `Continue on wallet`
1207
+ if (mode === "pay") {
1208
+ return `Pay`
1209
+ } else if (mode === "fund") {
1210
+ return `Fund`
1211
+ } else if (mode === "swap") {
1212
+ return `Swap`
1213
+ } else if (mode === "earn") {
1214
+ return `Deposit`
1215
+ } else if (mode === "receive") {
1216
+ return `Pay`
1217
+ } else {
1218
+ return `Continue on wallet`
1219
+ }
1198
1220
  }
1199
1221
 
1200
1222
  if (mode === "swap") {
@@ -405,7 +405,7 @@ export function useTokenList({
405
405
  return sortedTokens
406
406
  }
407
407
 
408
- const query = searchQuery.toLowerCase().trim()
408
+ const query = searchQuery.trim().toLowerCase()
409
409
  const queryParts = query.split(/\s+/).filter((part) => part.length > 0)
410
410
 
411
411
  const matchingTokens = sortedTokens.filter(
@@ -39,6 +39,11 @@
39
39
  --trails-modal-button-hover-bg: var(--trails-primary-hover, rgb(17 75 202)); /* Defaults to primary hover */
40
40
  --trails-modal-button-text: rgb(255 255 255); /* white text */
41
41
  --trails-modal-button-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); /* subtle shadow */
42
+
43
+ /* Percentage Button Colors - Customizable percentage buttons */
44
+ --trails-percentage-button-bg: rgb(228 228 231); /* #E4E4E7 - Light gray background */
45
+ --trails-percentage-button-text: rgb(113 113 123); /* #71717B - Dark gray text */
46
+ --trails-percentage-button-hover-bg: rgb(212 212 216); /* #D4D4D8 - Slightly darker on hover */
42
47
  }
43
48
 
44
49
  /* Utility Classes that use CSS Variables */
@@ -110,6 +115,18 @@
110
115
  color: var(--trails-hover-text);
111
116
  }
112
117
 
118
+ .trails-bg-percentage-button {
119
+ background-color: var(--trails-percentage-button-bg);
120
+ }
121
+
122
+ .trails-text-percentage-button {
123
+ color: var(--trails-percentage-button-text);
124
+ }
125
+
126
+ .trails-hover-percentage-button:hover {
127
+ background-color: var(--trails-percentage-button-hover-bg);
128
+ }
129
+
113
130
 
114
131
 
115
132
  /* Font Family Utility Class */
@@ -304,6 +321,11 @@
304
321
  /* Shadow */
305
322
  --trails-shadow:
306
323
  0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
324
+
325
+ /* Percentage Button Colors - Light Mode */
326
+ --trails-percentage-button-bg: rgb(228 228 231); /* #E4E4E7 - Light gray background */
327
+ --trails-percentage-button-text: rgb(113 113 123); /* #71717B - Dark gray text */
328
+ --trails-percentage-button-hover-bg: rgb(212 212 216); /* #D4D4D8 - Slightly darker on hover */
307
329
  }
308
330
 
309
331
  /* Dark Mode Theme Variables */
@@ -391,6 +413,11 @@
391
413
  /* Shadow */
392
414
  --trails-shadow:
393
415
  0 1px 3px 0 rgb(0 0 0 / 0.3), 0 1px 2px -1px rgb(0 0 0 / 0.3);
416
+
417
+ /* Percentage Button Colors - Dark Mode */
418
+ --trails-percentage-button-bg: rgb(55 65 81); /* gray-700 - Dark gray background */
419
+ --trails-percentage-button-text: rgb(209 213 219); /* gray-300 - Light gray text */
420
+ --trails-percentage-button-hover-bg: rgb(75 85 99); /* gray-600 - Slightly lighter on hover */
394
421
  }
395
422
 
396
423
  /* Custom Scrollbar Styles */