0xtrails 0.2.6 → 0.4.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 (218) hide show
  1. package/dist/aave.d.ts +2 -0
  2. package/dist/aave.d.ts.map +1 -1
  3. package/dist/{ccip-Xjh9d1gb.js → ccip-BpQGQiWq.js} +7 -7
  4. package/dist/config.d.ts +0 -5
  5. package/dist/config.d.ts.map +1 -1
  6. package/dist/constants.d.ts +2 -4
  7. package/dist/constants.d.ts.map +1 -1
  8. package/dist/error.d.ts +4 -1
  9. package/dist/error.d.ts.map +1 -1
  10. package/dist/fees.d.ts +2 -2
  11. package/dist/fees.d.ts.map +1 -1
  12. package/dist/{index-BnhdZ8Ho.js → index-DsJM5F-V.js} +46084 -48697
  13. package/dist/index.d.ts +9 -8
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +741 -923
  16. package/dist/intentReceiptMonitor.d.ts +24 -0
  17. package/dist/intentReceiptMonitor.d.ts.map +1 -0
  18. package/dist/intentReceiptPoller.d.ts +69 -0
  19. package/dist/intentReceiptPoller.d.ts.map +1 -0
  20. package/dist/intents.d.ts +15 -11
  21. package/dist/intents.d.ts.map +1 -1
  22. package/dist/morpho.d.ts +6 -5
  23. package/dist/morpho.d.ts.map +1 -1
  24. package/dist/mutations.d.ts +16 -0
  25. package/dist/mutations.d.ts.map +1 -0
  26. package/dist/preconditions.d.ts +5 -4
  27. package/dist/preconditions.d.ts.map +1 -1
  28. package/dist/prepareSend.d.ts +5 -190
  29. package/dist/prepareSend.d.ts.map +1 -1
  30. package/dist/prices.d.ts +9 -6
  31. package/dist/prices.d.ts.map +1 -1
  32. package/dist/sequenceWallet.d.ts +3 -16
  33. package/dist/sequenceWallet.d.ts.map +1 -1
  34. package/dist/tokenBalances.d.ts +17 -13
  35. package/dist/tokenBalances.d.ts.map +1 -1
  36. package/dist/trails.d.ts +24 -40
  37. package/dist/trails.d.ts.map +1 -1
  38. package/dist/trailsClient.d.ts +5 -6
  39. package/dist/trailsClient.d.ts.map +1 -1
  40. package/dist/transactionIntent/constants.d.ts +7 -0
  41. package/dist/transactionIntent/constants.d.ts.map +1 -0
  42. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +44 -0
  43. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -0
  44. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts +30 -0
  45. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts.map +1 -0
  46. package/dist/transactionIntent/deposits/index.d.ts +4 -0
  47. package/dist/transactionIntent/deposits/index.d.ts.map +1 -0
  48. package/dist/transactionIntent/deposits/standardDeposit.d.ts +30 -0
  49. package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -0
  50. package/dist/transactionIntent/execution/index.d.ts +2 -0
  51. package/dist/transactionIntent/execution/index.d.ts.map +1 -0
  52. package/dist/transactionIntent/execution/transactionState.d.ts +5 -0
  53. package/dist/transactionIntent/execution/transactionState.d.ts.map +1 -0
  54. package/dist/transactionIntent/handlers/crossChain.d.ts +82 -0
  55. package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -0
  56. package/dist/transactionIntent/handlers/index.d.ts +4 -0
  57. package/dist/transactionIntent/handlers/index.d.ts.map +1 -0
  58. package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts +62 -0
  59. package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts.map +1 -0
  60. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts +72 -0
  61. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -0
  62. package/dist/transactionIntent/index.d.ts +9 -0
  63. package/dist/transactionIntent/index.d.ts.map +1 -0
  64. package/dist/transactionIntent/quote/feeExtractors.d.ts +17 -0
  65. package/dist/transactionIntent/quote/feeExtractors.d.ts.map +1 -0
  66. package/dist/transactionIntent/quote/index.d.ts +4 -0
  67. package/dist/transactionIntent/quote/index.d.ts.map +1 -0
  68. package/dist/transactionIntent/quote/normalizeQuote.d.ts +34 -0
  69. package/dist/transactionIntent/quote/normalizeQuote.d.ts.map +1 -0
  70. package/dist/transactionIntent/quote/quoteHelpers.d.ts +5 -0
  71. package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -0
  72. package/dist/transactionIntent/types.d.ts +131 -0
  73. package/dist/transactionIntent/types.d.ts.map +1 -0
  74. package/dist/transactionIntent/utils/balanceChecker.d.ts +18 -0
  75. package/dist/transactionIntent/utils/balanceChecker.d.ts.map +1 -0
  76. package/dist/transactionIntent/utils/index.d.ts +4 -0
  77. package/dist/transactionIntent/utils/index.d.ts.map +1 -0
  78. package/dist/transactionIntent/utils/lifiHelpers.d.ts +10 -0
  79. package/dist/transactionIntent/utils/lifiHelpers.d.ts.map +1 -0
  80. package/dist/transactionIntent/utils/testnetHelpers.d.ts +3 -0
  81. package/dist/transactionIntent/utils/testnetHelpers.d.ts.map +1 -0
  82. package/dist/transactionIntent/validators.d.ts +6 -0
  83. package/dist/transactionIntent/validators.d.ts.map +1 -0
  84. package/dist/transactions.d.ts +2 -1
  85. package/dist/transactions.d.ts.map +1 -1
  86. package/dist/widget/components/AccountSettings.d.ts.map +1 -1
  87. package/dist/widget/components/ClassicSwap.d.ts +0 -1
  88. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  89. package/dist/widget/components/ConfigDisplay.d.ts.map +1 -1
  90. package/dist/widget/components/ConnectedWallets.d.ts.map +1 -1
  91. package/dist/widget/components/DynamicSizeInputField.d.ts +13 -0
  92. package/dist/widget/components/DynamicSizeInputField.d.ts.map +1 -0
  93. package/dist/widget/components/Earn.d.ts +0 -1
  94. package/dist/widget/components/Earn.d.ts.map +1 -1
  95. package/dist/widget/components/FeeOptions.d.ts +5 -13
  96. package/dist/widget/components/FeeOptions.d.ts.map +1 -1
  97. package/dist/widget/components/Fund.d.ts +0 -1
  98. package/dist/widget/components/Fund.d.ts.map +1 -1
  99. package/dist/widget/components/FundMethods.d.ts.map +1 -1
  100. package/dist/widget/components/FundSwap.d.ts +0 -1
  101. package/dist/widget/components/FundSwap.d.ts.map +1 -1
  102. package/dist/widget/components/Pay.d.ts +0 -1
  103. package/dist/widget/components/Pay.d.ts.map +1 -1
  104. package/dist/widget/components/PoolDeposit.d.ts +0 -1
  105. package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
  106. package/dist/widget/components/PoolWithdraw.d.ts +0 -18
  107. package/dist/widget/components/PoolWithdraw.d.ts.map +1 -1
  108. package/dist/widget/components/QuoteDetails.d.ts +1 -0
  109. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  110. package/dist/widget/components/Swap.d.ts +0 -1
  111. package/dist/widget/components/Swap.d.ts.map +1 -1
  112. package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -1
  113. package/dist/widget/components/WaasFeeOptions.d.ts.map +1 -1
  114. package/dist/widget/css/compiled.css +2 -2
  115. package/dist/widget/hooks/useCheckout.d.ts +17 -4
  116. package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
  117. package/dist/widget/hooks/useDefaultTokenSelection.d.ts.map +1 -1
  118. package/dist/widget/hooks/useQuote.d.ts +3 -4
  119. package/dist/widget/hooks/useQuote.d.ts.map +1 -1
  120. package/dist/widget/hooks/useSelectedFeeToken.d.ts +1 -0
  121. package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +1 -1
  122. package/dist/widget/hooks/useSendForm.d.ts +3 -4
  123. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  124. package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
  125. package/dist/widget/hooks/useWalletConnectionContext.d.ts +25 -0
  126. package/dist/widget/hooks/useWalletConnectionContext.d.ts.map +1 -0
  127. package/dist/widget/index.js +1 -1
  128. package/dist/widget/widget.d.ts +12 -7
  129. package/dist/widget/widget.d.ts.map +1 -1
  130. package/package.json +21 -23
  131. package/src/aave.ts +54 -1
  132. package/src/config.ts +57 -58
  133. package/src/constants.ts +8 -9
  134. package/src/error.ts +21 -3
  135. package/src/fees.ts +53 -42
  136. package/src/index.ts +35 -13
  137. package/src/intentReceiptMonitor.ts +102 -0
  138. package/src/intentReceiptPoller.ts +299 -0
  139. package/src/intents.ts +206 -172
  140. package/src/morpho.ts +58 -9
  141. package/src/mutations.ts +129 -0
  142. package/src/preconditions.ts +16 -21
  143. package/src/prepareSend.ts +80 -4514
  144. package/src/prices.ts +26 -22
  145. package/src/relaySdk.ts +2 -2
  146. package/src/sequenceWallet.ts +6 -73
  147. package/src/tokenBalances.ts +175 -69
  148. package/src/trails.ts +230 -722
  149. package/src/trailsClient.ts +10 -23
  150. package/src/transactionIntent/constants.ts +11 -0
  151. package/src/transactionIntent/deposits/depositOrchestrator.ts +210 -0
  152. package/src/transactionIntent/deposits/gaslessDeposit.ts +588 -0
  153. package/src/transactionIntent/deposits/index.ts +3 -0
  154. package/src/transactionIntent/deposits/standardDeposit.ts +379 -0
  155. package/src/transactionIntent/execution/index.ts +1 -0
  156. package/src/transactionIntent/execution/transactionState.ts +35 -0
  157. package/src/transactionIntent/handlers/crossChain.ts +1707 -0
  158. package/src/transactionIntent/handlers/index.ts +3 -0
  159. package/src/transactionIntent/handlers/sameChainDifferentToken.ts +323 -0
  160. package/src/transactionIntent/handlers/sameChainSameToken.ts +712 -0
  161. package/src/transactionIntent/index.ts +9 -0
  162. package/src/transactionIntent/quote/feeExtractors.ts +81 -0
  163. package/src/transactionIntent/quote/index.ts +3 -0
  164. package/src/transactionIntent/quote/normalizeQuote.ts +367 -0
  165. package/src/transactionIntent/quote/quoteHelpers.ts +53 -0
  166. package/src/transactionIntent/types.ts +157 -0
  167. package/src/transactionIntent/utils/balanceChecker.ts +96 -0
  168. package/src/transactionIntent/utils/index.ts +3 -0
  169. package/src/transactionIntent/utils/lifiHelpers.ts +68 -0
  170. package/src/transactionIntent/utils/testnetHelpers.ts +10 -0
  171. package/src/transactionIntent/validators.ts +57 -0
  172. package/src/transactions.ts +36 -53
  173. package/src/widget/compiled.css +2 -2
  174. package/src/widget/components/AccountIntentTransactionHistory.tsx +36 -36
  175. package/src/widget/components/AccountSettings.tsx +23 -6
  176. package/src/widget/components/ClassicSwap.tsx +28 -53
  177. package/src/widget/components/ConfigDisplay.tsx +0 -11
  178. package/src/widget/components/ConnectedWallets.tsx +30 -4
  179. package/src/widget/components/DynamicSizeInputField.tsx +109 -0
  180. package/src/widget/components/Earn.tsx +0 -16
  181. package/src/widget/components/FeeBreakdown.tsx +3 -3
  182. package/src/widget/components/FeeOption.tsx +2 -2
  183. package/src/widget/components/FeeOptions.tsx +151 -112
  184. package/src/widget/components/Fund.tsx +0 -3
  185. package/src/widget/components/FundMethods.tsx +4 -3
  186. package/src/widget/components/FundSwap.tsx +0 -1
  187. package/src/widget/components/Pay.tsx +11 -16
  188. package/src/widget/components/PoolDeposit.tsx +35 -32
  189. package/src/widget/components/PoolWithdraw.tsx +153 -256
  190. package/src/widget/components/QuoteDetails.tsx +899 -494
  191. package/src/widget/components/Swap.tsx +0 -1
  192. package/src/widget/components/TransferPendingVertical.tsx +12 -8
  193. package/src/widget/components/WaasFeeOptions.tsx +23 -7
  194. package/src/widget/components/WalletConfirmation.tsx +1 -1
  195. package/src/widget/hooks/useAmountUsd.ts +9 -9
  196. package/src/widget/hooks/useCheckout.ts +97 -9
  197. package/src/widget/hooks/useDefaultTokenSelection.tsx +27 -21
  198. package/src/widget/hooks/useQuote.ts +86 -33
  199. package/src/widget/hooks/useSelectedFeeToken.tsx +32 -37
  200. package/src/widget/hooks/useSendForm.ts +37 -47
  201. package/src/widget/hooks/useTokenList.ts +34 -26
  202. package/src/widget/hooks/useWalletConnectionContext.tsx +128 -0
  203. package/src/widget/widget.tsx +197 -207
  204. package/dist/apiClient.d.ts +0 -9
  205. package/dist/apiClient.d.ts.map +0 -1
  206. package/dist/intentEntrypoint.d.ts +0 -114
  207. package/dist/intentEntrypoint.d.ts.map +0 -1
  208. package/dist/metaTxnMonitor.d.ts +0 -15
  209. package/dist/metaTxnMonitor.d.ts.map +0 -1
  210. package/dist/metaTxns.d.ts +0 -11
  211. package/dist/metaTxns.d.ts.map +0 -1
  212. package/dist/relayer.d.ts +0 -43
  213. package/dist/relayer.d.ts.map +0 -1
  214. package/src/apiClient.ts +0 -35
  215. package/src/intentEntrypoint.ts +0 -203
  216. package/src/metaTxnMonitor.ts +0 -171
  217. package/src/metaTxns.ts +0 -45
  218. package/src/relayer.ts +0 -289
@@ -8,7 +8,19 @@ import React, {
8
8
  type ReactNode,
9
9
  } from "react"
10
10
  import { logger } from "../../logger.js"
11
- import { zeroAddress } from "viem"
11
+ import { ethAddress, zeroAddress } from "viem"
12
+ import { formatUsdAmountDisplay } from "../../tokenBalances.js"
13
+
14
+ const ZERO_ADDRESS = zeroAddress.toLowerCase()
15
+ const ETH_ADDRESS = ethAddress.toLowerCase()
16
+
17
+ const normalizeAddress = (address?: string | null): string =>
18
+ (address ?? "").toLowerCase()
19
+
20
+ const isNativeTokenAddress = (address?: string | null): boolean => {
21
+ const normalized = normalizeAddress(address)
22
+ return normalized === ZERO_ADDRESS || normalized === ETH_ADDRESS
23
+ }
12
24
 
13
25
  // Define the FeeOption interface with balance check properties
14
26
  export interface FeeOption {
@@ -20,6 +32,7 @@ export interface FeeOption {
20
32
  notEnoughBalance?: boolean
21
33
  tokenImageUrl?: string
22
34
  chainId?: number
35
+ amountUsdDisplay?: string // Formatted USD display like "≈ $0.39"
23
36
  }
24
37
 
25
38
  // Token type with balance information
@@ -113,13 +126,14 @@ export const SelectedFeeTokenProvider: React.FC<
113
126
 
114
127
  // Add balance check and additional properties to each fee option
115
128
  const feeOptionsWithBalanceCheck = rawFeeOptions.map((option: any) => {
116
- // For native token (zero address), check if user has enough native balance
117
- if (option.tokenAddress === zeroAddress) {
129
+ // For native token (zero/ETH address), check if user has enough native balance
130
+ if (isNativeTokenAddress(option.tokenAddress)) {
118
131
  // Find the native token balance for the origin chain
119
132
  const nativeTokenInfo = availableTokens.find(
120
133
  (token) =>
121
- token.contractAddress?.toLowerCase() ===
122
- zeroAddress.toLowerCase() && token.chainId === originTokenChainId,
134
+ token.chainId === originTokenChainId &&
135
+ (isNativeTokenAddress(token.contractAddress) ||
136
+ !token.contractAddress),
123
137
  )
124
138
 
125
139
  const nativeBalance = nativeTokenInfo?.balance || "0"
@@ -131,6 +145,8 @@ export const SelectedFeeTokenProvider: React.FC<
131
145
  notEnoughBalance,
132
146
  tokenImageUrl: nativeTokenInfo?.imageUrl,
133
147
  chainId: originTokenChainId, // Native token is on the same chain as origin
148
+ amountUsdDisplay: formatUsdAmountDisplay(option.amountUsd),
149
+ amountUSD: option.amountUsd, // Normalize to uppercase for consistency
134
150
  }
135
151
  }
136
152
 
@@ -152,6 +168,8 @@ export const SelectedFeeTokenProvider: React.FC<
152
168
  notEnoughBalance,
153
169
  tokenImageUrl: userTokenBalance.imageUrl,
154
170
  chainId: userTokenBalance.chainId, // Use the actual token's chain ID
171
+ amountUsdDisplay: formatUsdAmountDisplay(option.amountUsd),
172
+ amountUSD: option.amountUsd, // Normalize to uppercase for consistency
155
173
  }
156
174
  }
157
175
 
@@ -161,6 +179,8 @@ export const SelectedFeeTokenProvider: React.FC<
161
179
  notEnoughBalance: true,
162
180
  tokenImageUrl: undefined,
163
181
  chainId: originTokenChainId, // Fallback to origin chain
182
+ amountUsdDisplay: formatUsdAmountDisplay(option.amountUsd),
183
+ amountUSD: option.amountUsd, // Normalize to uppercase for consistency
164
184
  }
165
185
  })
166
186
 
@@ -184,36 +204,17 @@ export const SelectedFeeTokenProvider: React.FC<
184
204
  return sortedFeeOptions
185
205
  }, [rawFeeOptions, originTokenChainId, availableTokens])
186
206
 
187
- // Auto-select first fee option with sufficient balance (non-native token)
188
- // Only auto-select on initial load, not when user explicitly chooses native gas
189
- // If no ERC20 fee options are available, selectedFeeToken stays null (native gas)
207
+ // Auto-select first ERC20 fee option with sufficient balance
208
+ // Only auto-select if user hasn't made an explicit selection yet
190
209
  useEffect(() => {
191
- logger.console.log(
192
- "[trails-sdk] [FEE-SELECT] Auto-selection useEffect triggered:",
193
- {
194
- processedFeeOptionsLength: processedFeeOptions.length,
195
- hasUserSelectedFeeOption,
196
- selectedFeeToken,
197
- willAutoSelect:
198
- processedFeeOptions.length > 0 &&
199
- !hasUserSelectedFeeOption &&
200
- !selectedFeeToken,
201
- },
202
- )
203
-
204
- // Only auto-select if:
205
- // 1. We have fee options
206
- // 2. User hasn't made an explicit selection yet
207
- // 3. No fee token is currently selected
208
210
  if (
209
211
  processedFeeOptions.length > 0 &&
210
212
  !hasUserSelectedFeeOption &&
211
213
  !selectedFeeToken
212
214
  ) {
213
- // Find first non-native token option with sufficient balance
215
+ // Find first token option with sufficient balance
214
216
  const firstValidOption = processedFeeOptions.find(
215
- (option: FeeOption) =>
216
- option.tokenAddress !== zeroAddress && !option.notEnoughBalance,
217
+ (option: FeeOption) => !option.notEnoughBalance,
217
218
  )
218
219
 
219
220
  if (firstValidOption) {
@@ -221,20 +222,14 @@ export const SelectedFeeTokenProvider: React.FC<
221
222
  "[trails-sdk] [FEE-SELECT] Auto-selecting first valid fee option:",
222
223
  firstValidOption,
223
224
  )
224
- // Strip extra fields to match the format expected by prepareSend
225
- const cleanOption: FeeOption = {
225
+ // Use internal setter to avoid marking as user selection
226
+ setSelectedFeeTokenInternal({
226
227
  tokenAddress: firstValidOption.tokenAddress,
227
228
  tokenSymbol: firstValidOption.tokenSymbol,
228
229
  tokenDecimals: firstValidOption.tokenDecimals,
229
230
  amount: firstValidOption.amount,
230
231
  amountUSD: firstValidOption.amountUSD,
231
- }
232
- // Use internal setter to avoid marking as user selection
233
- setSelectedFeeTokenInternal(cleanOption)
234
- } else {
235
- logger.console.log(
236
- "[trails-sdk] [FEE-SELECT] No valid ERC20 fee options available, will use native gas",
237
- )
232
+ })
238
233
  }
239
234
  }
240
235
  }, [
@@ -10,7 +10,6 @@ import {
10
10
  zeroAddress,
11
11
  } from "viem"
12
12
  import { useAccount } from "wagmi"
13
- import { useAPIClient } from "../../apiClient.js"
14
13
  import { getChainInfo, useSupportedChains } from "../../chains.js"
15
14
  import { getFullErrorMessage, getPrettifiedErrorMessage } from "../../error.js"
16
15
  import {
@@ -18,11 +17,11 @@ import {
18
17
  TradeType,
19
18
  type PrepareSendReturn,
20
19
  type PrepareSendQuote,
20
+ type SelectedFeeToken,
21
21
  } from "../../prepareSend.js"
22
22
  import type { TransactionState } from "../../transactions.js"
23
23
  import { getTokenPrice, useTokenPrices, normalizeNumber } from "../../prices.js"
24
24
  import { useQueryParams } from "../../queryParams.js"
25
- import { getRelayer } from "../../relayer.js"
26
25
  import {
27
26
  formatRawAmount,
28
27
  formatUsdAmountDisplay,
@@ -96,7 +95,6 @@ export type UseSendProps = {
96
95
  onError: (error: Error | string | null) => void
97
96
  onWaitingForWalletConfirm: (quote: PrepareSendQuote) => void
98
97
  paymasterUrls?: PaymasterUrl[]
99
- gasless?: boolean
100
98
  onSend: (amount: string, recipient: string) => void
101
99
  onConfirm: () => void
102
100
  onComplete: (result: OnCompleteProps) => void
@@ -165,7 +163,7 @@ export type UseSendReturn = {
165
163
  destTokenPrices: TokenPrice[] | null
166
164
  sourceTokenPrices: TokenPrice[] | null
167
165
  selectedToken?: Token
168
- selectedFeeToken: FeeOption | null
166
+ selectedFeeToken: SelectedFeeToken | undefined
169
167
  setIsChainDropdownOpen: (isOpen: boolean) => void
170
168
  setIsTokenDropdownOpen: (isOpen: boolean) => void
171
169
  toAmountFormatted: string
@@ -194,7 +192,6 @@ export function useSendForm({
194
192
  onError,
195
193
  onWaitingForWalletConfirm,
196
194
  paymasterUrls,
197
- gasless,
198
195
  selectedToken,
199
196
  onSend,
200
197
  onConfirm,
@@ -435,7 +432,6 @@ export function useSendForm({
435
432
  }
436
433
  }, [selectedDestToken, defaultDestToken])
437
434
 
438
- const apiClient = useAPIClient()
439
435
  const trailsClient = useTrailsClient()
440
436
 
441
437
  // Get user's token balances for balance checking
@@ -462,8 +458,8 @@ export function useSendForm({
462
458
  selectedDestToken && destTokenAddress && selectedDestinationChain?.id
463
459
  ? [
464
460
  {
465
- tokenId: selectedDestToken.symbol,
466
- contractAddress: destTokenAddress,
461
+ tokenSymbol: selectedDestToken.symbol,
462
+ tokenAddress: destTokenAddress,
467
463
  chainId: selectedDestinationChain.id,
468
464
  },
469
465
  ]
@@ -474,20 +470,20 @@ export function useSendForm({
474
470
 
475
471
  const { tokenPrices: destTokenPrices } = useTokenPrices(
476
472
  destTokenPricesInput,
477
- apiClient,
473
+ trailsClient,
478
474
  )
479
475
 
480
476
  const { tokenPrices: sourceTokenPrices } = useTokenPrices(
481
477
  selectedToken
482
478
  ? [
483
479
  {
484
- tokenId: selectedToken.symbol,
485
- contractAddress: selectedToken.contractAddress,
480
+ tokenSymbol: selectedToken.symbol,
481
+ tokenAddress: selectedToken.contractAddress,
486
482
  chainId: selectedToken.chainId,
487
483
  },
488
484
  ]
489
485
  : [],
490
- apiClient,
486
+ trailsClient,
491
487
  )
492
488
 
493
489
  // Update selectedChain when toChainId prop changes
@@ -569,7 +565,7 @@ export function useSendForm({
569
565
  selectedToken?.balance && selectedToken?.contractInfo?.decimals
570
566
  ? formatRawAmount(
571
567
  selectedToken.balance,
572
- selectedToken.contractInfo?.decimals!,
568
+ selectedToken.contractInfo?.decimals,
573
569
  )
574
570
  : "0"
575
571
  const balanceUsdDisplay = selectedToken?.balanceUsdFormatted ?? ""
@@ -579,8 +575,8 @@ export function useSendForm({
579
575
  const amountUsdDisplay = useMemo(() => {
580
576
  const tokenPrice =
581
577
  tradeType === TradeType.EXACT_INPUT
582
- ? (sourceTokenPrices?.[0]?.price?.value ?? 0) // For fund form, use source token price
583
- : (destTokenPrices?.[0]?.price?.value ?? 0) // For payment form, use dest token price
578
+ ? (sourceTokenPrices?.[0]?.priceUsd ?? 0) // For fund form, use source token price
579
+ : (destTokenPrices?.[0]?.priceUsd ?? 0) // For payment form, use dest token price
584
580
  const amountUsd = Number(amount) * tokenPrice
585
581
  return formatUsdAmountDisplay(amountUsd)
586
582
  }, [amount, destTokenPrices, sourceTokenPrices, tradeType])
@@ -616,6 +612,11 @@ export function useSendForm({
616
612
 
617
613
  // Calculate raw amount (in wei/smallest unit)
618
614
  const amountRaw = useMemo(() => {
615
+ // Skip validation during initialization when no tokens are selected
616
+ if (!selectedToken && !selectedDestToken) {
617
+ return "0"
618
+ }
619
+
619
620
  if (
620
621
  !amount &&
621
622
  !(selectedToken?.contractInfo?.decimals || selectedDestToken?.decimals)
@@ -720,12 +721,6 @@ export function useSendForm({
720
721
  setError(null)
721
722
  setQuoteError(null)
722
723
 
723
- const originRelayer = getRelayer(undefined, selectedToken.chainId)
724
- const destinationRelayer = getRelayer(
725
- undefined,
726
- selectedDestinationChain.id,
727
- )
728
-
729
724
  const sourceTokenDecimals = selectedToken.contractInfo?.decimals
730
725
  const destinationTokenDecimals = selectedDestToken.decimals
731
726
 
@@ -743,12 +738,16 @@ export function useSendForm({
743
738
  }
744
739
 
745
740
  let sourceTokenPriceUsd = selectedToken.tokenPriceUsd ?? null
746
- let destinationTokenPriceUsd = destTokenPrices?.[0]?.price?.value ?? null
741
+ let destinationTokenPriceUsd = destTokenPrices?.[0]?.priceUsd ?? null
747
742
 
748
743
  if (!sourceTokenPriceUsd) {
749
744
  try {
750
- const price = await getTokenPrice(apiClient, selectedToken)
751
- sourceTokenPriceUsd = price?.price?.value ?? null
745
+ const price = await getTokenPrice(trailsClient, {
746
+ tokenAddress: selectedToken.contractAddress,
747
+ tokenSymbol: selectedToken.symbol,
748
+ chainId: selectedToken.chainId,
749
+ })
750
+ sourceTokenPriceUsd = price?.priceUsd ?? null
752
751
  } catch (error) {
753
752
  logger.console.error(
754
753
  "[trails-sdk] Error getting source token price:",
@@ -759,12 +758,12 @@ export function useSendForm({
759
758
 
760
759
  if (!destinationTokenPriceUsd) {
761
760
  try {
762
- const price = await getTokenPrice(apiClient, {
763
- tokenId: selectedDestToken.symbol,
764
- contractAddress: destinationTokenAddress ?? "",
761
+ const price = await getTokenPrice(trailsClient, {
762
+ tokenSymbol: selectedDestToken.symbol,
763
+ tokenAddress: destinationTokenAddress ?? "",
765
764
  chainId: selectedDestinationChain.id,
766
765
  })
767
- destinationTokenPriceUsd = price?.price?.value ?? null
766
+ destinationTokenPriceUsd = price?.priceUsd ?? null
768
767
  } catch (error) {
769
768
  logger.console.error(
770
769
  "[trails-sdk] Error getting destination token price:",
@@ -802,17 +801,14 @@ export function useSendForm({
802
801
  } else {
803
802
  const originChain = getChainInfo(selectedToken.chainId)
804
803
  const nativeTokenSymbol = originChain?.nativeCurrency?.symbol ?? ""
805
- const nativePrice = await getTokenPrice(apiClient, {
806
- tokenId: nativeTokenSymbol,
807
- contractAddress: zeroAddress,
804
+ const nativePrice = await getTokenPrice(trailsClient, {
805
+ tokenSymbol: nativeTokenSymbol,
806
+ tokenAddress: zeroAddress,
808
807
  chainId: selectedToken.chainId,
809
808
  })
810
- nativeTokenPriceUsd = nativePrice?.price?.value ?? 0
809
+ nativeTokenPriceUsd = nativePrice?.priceUsd ?? 0
811
810
  }
812
811
 
813
- // Disable gasless for sequence-waas wallet
814
- const effectiveGasless = walletId === "sequence-waas" ? false : gasless
815
-
816
812
  const options = {
817
813
  account,
818
814
  originTokenAddress: selectedToken.contractAddress,
@@ -833,10 +829,7 @@ export function useSendForm({
833
829
  destinationTokenSymbol: selectedDestToken.symbol,
834
830
  fee: "0",
835
831
  client: walletClient,
836
- apiClient,
837
832
  trailsClient,
838
- originRelayer,
839
- destinationRelayer,
840
833
  destinationCalldata: toCalldata,
841
834
  refundAddress,
842
835
  dryMode: isDryMode,
@@ -849,13 +842,12 @@ export function useSendForm({
849
842
  paymasterUrls?.find(
850
843
  (p) => p.chainId.toString() === selectedToken.chainId.toString(),
851
844
  )?.url ?? undefined,
852
- gasless: effectiveGasless,
853
845
  originNativeTokenPriceUsd: nativeTokenPriceUsd,
854
846
  quoteProvider: effectiveQuoteProvider,
855
847
  mode,
856
848
  fundMethod,
857
849
  checkoutOnHandlers,
858
- selectedFeeToken,
850
+ selectedFeeToken: selectedFeeToken ?? undefined,
859
851
  walletId,
860
852
  }
861
853
 
@@ -883,7 +875,6 @@ export function useSendForm({
883
875
  isDryMode,
884
876
  account,
885
877
  walletClient,
886
- apiClient,
887
878
  trailsClient,
888
879
  selectedDestToken?.decimals,
889
880
  recipient,
@@ -897,10 +888,9 @@ export function useSendForm({
897
888
  toCalldata,
898
889
  refundAddress,
899
890
  paymasterUrls,
900
- gasless,
901
891
  handleTransactionStateChange,
902
892
  isValidRecipient,
903
- destTokenPrices?.[0]?.price?.value,
893
+ destTokenPrices?.[0]?.priceUsd,
904
894
  amount,
905
895
  selectedDestToken,
906
896
  selectedDestinationChain,
@@ -1080,15 +1070,15 @@ export function useSendForm({
1080
1070
  )
1081
1071
  // Wait for full send to complete
1082
1072
  const {
1083
- originUserTxReceipt,
1073
+ depositUserTxnReceipt,
1084
1074
  originMetaTxnReceipt,
1085
1075
  destinationMetaTxnReceipt,
1086
1076
  } = await send({
1087
1077
  onOriginSend,
1088
- selectedFeeToken, // Pass current value at execution time
1078
+ selectedFeeToken: selectedFeeToken ?? undefined, // Pass current value at execution time
1089
1079
  })
1090
1080
  logger.console.log("[trails-sdk] send() completed, receipts:", {
1091
- originUserTxReceipt,
1081
+ depositUserTxnReceipt,
1092
1082
  originMetaTxnReceipt,
1093
1083
  destinationMetaTxnReceipt,
1094
1084
  })
@@ -1346,7 +1336,7 @@ export function useSendForm({
1346
1336
  destTokenPrices: destTokenPrices ?? null,
1347
1337
  sourceTokenPrices: sourceTokenPrices ?? null,
1348
1338
  selectedToken,
1349
- selectedFeeToken,
1339
+ selectedFeeToken: selectedFeeToken ?? undefined,
1350
1340
  setIsChainDropdownOpen,
1351
1341
  setIsTokenDropdownOpen,
1352
1342
  toAmountFormatted: quotedDestinationAmount,
@@ -17,7 +17,7 @@ import {
17
17
  } from "../../tokenBalances.js"
18
18
  import { getFormatttedTokenName, useSupportedTokens } from "../../tokens.js"
19
19
  import { useIndexerGatewayClient } from "../../indexerClient.js"
20
- import { useAPIClient } from "../../apiClient.js"
20
+ import { useTrailsClient } from "../../trailsClient.js"
21
21
  import { useTokenPrices } from "../../prices.js"
22
22
  import { logger } from "../../logger.js"
23
23
 
@@ -136,7 +136,7 @@ export function useTokenList({
136
136
  const [searchQuery, setSearchQuery] = useState("")
137
137
  const { address } = useAccount()
138
138
  const indexerGatewayClient = useIndexerGatewayClient()
139
- const apiClient = useAPIClient()
139
+ const trailsClient = useTrailsClient()
140
140
  const {
141
141
  sortedTokens: allSortedTokens,
142
142
  isLoadingSortedTokens,
@@ -160,8 +160,8 @@ export function useTokenList({
160
160
 
161
161
  return filteredTokens.map((token: any) => ({
162
162
  chainId: token.chainId,
163
- contractAddress: token.contractAddress || zeroAddress,
164
- tokenId: token.symbol,
163
+ tokenAddress: token.contractAddress || zeroAddress,
164
+ tokenSymbol: token.symbol,
165
165
  }))
166
166
  }
167
167
 
@@ -169,15 +169,15 @@ export function useTokenList({
169
169
 
170
170
  return supportedTokens.map((token: any) => ({
171
171
  chainId: token.chainId,
172
- contractAddress: token.contractAddress || zeroAddress,
173
- tokenId: token.symbol,
172
+ tokenAddress: token.contractAddress || zeroAddress,
173
+ tokenSymbol: token.symbol,
174
174
  }))
175
175
  }, [allSupportedTokens, supportedTokens, fundMethod])
176
176
 
177
177
  const {
178
178
  tokenPrices: supportedTokenPrices,
179
179
  isLoadingTokenPrices: isLoadingSupportedTokenPrices,
180
- } = useTokenPrices(supportedTokensForPricing, apiClient)
180
+ } = useTokenPrices(supportedTokensForPricing, trailsClient)
181
181
 
182
182
  // Determine loading state based on fund method and allSupportedTokens
183
183
  const isLoadingTokens =
@@ -222,7 +222,7 @@ export function useTokenList({
222
222
  // Find price data for this token
223
223
  const priceData = supportedTokenPrices?.find(
224
224
  (p: any) =>
225
- p.token.contractAddress?.toLowerCase() ===
225
+ p.token.tokenAddress?.toLowerCase() ===
226
226
  (token.contractAddress || zeroAddress).toLowerCase() &&
227
227
  p.token.chainId === token.chainId,
228
228
  )
@@ -237,10 +237,11 @@ export function useTokenList({
237
237
  balance: "0", // No balance info for QR code and exchange modes
238
238
  balanceUsd: 0,
239
239
  balanceUsdFormatted: "0",
240
- price: priceData?.price || { value: 0, currency: "USD" },
241
- price24hVol:
242
- (priceData as unknown as { price24hVol: { value: number } })
243
- ?.price24hVol?.value || 0,
240
+ price:
241
+ priceData?.priceUsd !== undefined
242
+ ? { value: priceData.priceUsd, currency: "USD" }
243
+ : { value: 0, currency: "USD" },
244
+ price24hVol: 0, // Volume data not available in new API
244
245
  imageUrl: token.imageUrl,
245
246
  symbol: token.symbol,
246
247
  isSufficientBalance: true, // Always true for QR code and exchange modes
@@ -254,10 +255,11 @@ export function useTokenList({
254
255
  balance: "0", // No balance info for QR code and exchange modes
255
256
  balanceUsd: 0,
256
257
  balanceUsdFormatted: "0",
257
- price: priceData?.price || { value: 0, currency: "USD" },
258
- price24hVol:
259
- (priceData as unknown as { price24hVol: { value: number } })
260
- ?.price24hVol?.value || 0,
258
+ price:
259
+ priceData?.priceUsd !== undefined
260
+ ? { value: priceData.priceUsd, currency: "USD" }
261
+ : { value: 0, currency: "USD" },
262
+ price24hVol: 0, // Volume data not available in new API
261
263
  imageUrl: token.imageUrl,
262
264
  contractInfo: {
263
265
  decimals: token.decimals,
@@ -520,8 +522,8 @@ export function useTokenList({
520
522
 
521
523
  const filteredTokensFormatted = useMemo(() => {
522
524
  // Get base formatted tokens
523
- const baseFormattedTokens = filteredTokens.map(
524
- (token: TokenBalanceExtended): TokenFormatted => {
525
+ const baseFormattedTokens = filteredTokens
526
+ .map((token: TokenBalanceExtended): TokenFormatted | null => {
525
527
  const isNative =
526
528
  !("contractAddress" in token) || token.contractAddress === zeroAddress
527
529
  const chainInfo = getChainInfo(token.chainId)
@@ -544,7 +546,15 @@ export function useTokenList({
544
546
  )
545
547
  const decimals = isNative ? 18 : token.contractInfo?.decimals
546
548
  if (!decimals) {
547
- throw new Error("Decimals not found")
549
+ logger.console.warn(
550
+ "[trails-sdk] Missing decimals for token, skipping:",
551
+ {
552
+ token: isNative ? token : token.contractInfo,
553
+ chainId: token.chainId,
554
+ isNative,
555
+ },
556
+ )
557
+ return null // Return null to filter out tokens without decimals
548
558
  }
549
559
  const formattedBalance = formatRawAmount(token.balance, decimals)
550
560
  const priceUsd = Number(token.price?.value) ?? 0
@@ -611,8 +621,8 @@ export function useTokenList({
611
621
  isSufficientBalance,
612
622
  chainName,
613
623
  }
614
- },
615
- )
624
+ })
625
+ .filter(Boolean) as TokenFormatted[] // Filter out null values for tokens without decimals
616
626
 
617
627
  // If allSupportedTokens is true, combine with supported tokens
618
628
  if (allSupportedTokens) {
@@ -641,7 +651,7 @@ export function useTokenList({
641
651
  // Find price data for this supported token
642
652
  const priceData = supportedTokenPrices?.find(
643
653
  (p: any) =>
644
- p.token.contractAddress?.toLowerCase() ===
654
+ p.token.tokenAddress?.toLowerCase() ===
645
655
  (supportedToken.contractAddress || zeroAddress).toLowerCase() &&
646
656
  p.token.chainId === supportedToken.chainId,
647
657
  )
@@ -659,10 +669,8 @@ export function useTokenList({
659
669
  balance: "",
660
670
  balanceFormatted: "",
661
671
  balanceUsdFormatted: "",
662
- priceUsd: priceData?.price?.value || 0,
663
- price24hVol:
664
- (priceData as unknown as { price24hVol: { value: number } })
665
- ?.price24hVol?.value || 0, // Add price data for volume sorting
672
+ priceUsd: priceData?.priceUsd || 0,
673
+ price24hVol: 0, // Volume data not available in new API
666
674
  isSufficientBalance: true,
667
675
  // Use any type to bypass strict type checking for now
668
676
  } as any
@@ -0,0 +1,128 @@
1
+ import {
2
+ createContext,
3
+ useContext,
4
+ useState,
5
+ useCallback,
6
+ type ReactNode,
7
+ } from "react"
8
+ import type { Screen } from "./useCurrentScreen.js"
9
+ import { logger } from "../../logger.js"
10
+
11
+ export type WalletConnectionPurpose =
12
+ | "general" // Default: switch active wallet
13
+ | "recipient-selection" // Don't switch, set as recipient only
14
+ | "fund-method-selection" // Don't switch, use for funding only
15
+
16
+ interface WalletConnectionContextValue {
17
+ purpose: WalletConnectionPurpose
18
+ originScreen: Screen | null
19
+ connectedWalletAddress: string | null
20
+ originalActiveWalletAddress: string | null
21
+ originalActiveConnector: any | null
22
+ }
23
+
24
+ interface WalletConnectionContextType {
25
+ connectionContext: WalletConnectionContextValue
26
+ setConnectionContext: (
27
+ purpose: WalletConnectionPurpose,
28
+ originScreen?: Screen,
29
+ originalActiveWalletAddress?: string,
30
+ originalActiveConnector?: any,
31
+ ) => void
32
+ setConnectedWalletAddress: (address: string) => void
33
+ clearConnectionContext: () => void
34
+ isRecipientSelection: boolean
35
+ isFundMethodSelection: boolean
36
+ }
37
+
38
+ const WalletConnectionContext =
39
+ createContext<WalletConnectionContextType | null>(null)
40
+
41
+ interface WalletConnectionProviderProps {
42
+ children: ReactNode
43
+ }
44
+
45
+ const DEFAULT_CONTEXT: WalletConnectionContextValue = {
46
+ purpose: "general",
47
+ originScreen: null,
48
+ connectedWalletAddress: null,
49
+ originalActiveWalletAddress: null,
50
+ originalActiveConnector: null,
51
+ }
52
+
53
+ export function WalletConnectionProvider({
54
+ children,
55
+ }: WalletConnectionProviderProps) {
56
+ const [connectionContext, setContext] =
57
+ useState<WalletConnectionContextValue>(DEFAULT_CONTEXT)
58
+
59
+ const setConnectionContext = useCallback(
60
+ (
61
+ purpose: WalletConnectionPurpose,
62
+ originScreen?: Screen,
63
+ originalActiveWalletAddress?: string,
64
+ originalActiveConnector?: any,
65
+ ) => {
66
+ logger.console.log("[trails-sdk] Setting wallet connection context:", {
67
+ purpose,
68
+ originScreen,
69
+ originalActiveWalletAddress,
70
+ hasOriginalConnector: !!originalActiveConnector,
71
+ })
72
+ setContext({
73
+ purpose,
74
+ originScreen: originScreen || null,
75
+ connectedWalletAddress: null,
76
+ originalActiveWalletAddress: originalActiveWalletAddress || null,
77
+ originalActiveConnector: originalActiveConnector || null,
78
+ })
79
+ },
80
+ [],
81
+ )
82
+
83
+ const setConnectedWalletAddress = useCallback((address: string) => {
84
+ logger.console.log(
85
+ "[trails-sdk] Setting connected wallet address:",
86
+ address,
87
+ )
88
+ setContext((prev) => ({
89
+ ...prev,
90
+ connectedWalletAddress: address,
91
+ }))
92
+ }, [])
93
+
94
+ const clearConnectionContext = useCallback(() => {
95
+ logger.console.log("[trails-sdk] Clearing wallet connection context")
96
+ setContext(DEFAULT_CONTEXT)
97
+ }, [])
98
+
99
+ const isRecipientSelection =
100
+ connectionContext.purpose === "recipient-selection"
101
+ const isFundMethodSelection =
102
+ connectionContext.purpose === "fund-method-selection"
103
+
104
+ const value: WalletConnectionContextType = {
105
+ connectionContext,
106
+ setConnectionContext,
107
+ setConnectedWalletAddress,
108
+ clearConnectionContext,
109
+ isRecipientSelection,
110
+ isFundMethodSelection,
111
+ }
112
+
113
+ return (
114
+ <WalletConnectionContext.Provider value={value}>
115
+ {children}
116
+ </WalletConnectionContext.Provider>
117
+ )
118
+ }
119
+
120
+ export function useWalletConnectionContext() {
121
+ const context = useContext(WalletConnectionContext)
122
+ if (!context) {
123
+ throw new Error(
124
+ "useWalletConnectionContext must be used within a WalletConnectionProvider",
125
+ )
126
+ }
127
+ return context
128
+ }