0xtrails 0.5.0 → 0.6.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 (189) hide show
  1. package/dist/analytics.d.ts +8 -3
  2. package/dist/analytics.d.ts.map +1 -1
  3. package/dist/{ccip-DhEkQ6QC.js → ccip-Dw5AN7oU.js} +1 -1
  4. package/dist/cctp.d.ts +0 -149
  5. package/dist/cctp.d.ts.map +1 -1
  6. package/dist/chains.d.ts +28 -3
  7. package/dist/chains.d.ts.map +1 -1
  8. package/dist/config.d.ts +11 -0
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/constants.d.ts +1 -1
  11. package/dist/constants.d.ts.map +1 -1
  12. package/dist/contractUtils.d.ts.map +1 -1
  13. package/dist/estimate.d.ts.map +1 -1
  14. package/dist/fees.d.ts.map +1 -1
  15. package/dist/gasless.d.ts +12 -0
  16. package/dist/gasless.d.ts.map +1 -1
  17. package/dist/{index-MhD2DA7_.js → index-BtVUTbEZ.js} +30984 -38945
  18. package/dist/index.d.ts +7 -5
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +108 -107
  21. package/dist/indexerClient.d.ts +2 -2
  22. package/dist/intents.d.ts +0 -17
  23. package/dist/intents.d.ts.map +1 -1
  24. package/dist/mutations.d.ts.map +1 -1
  25. package/dist/paymasterSend.d.ts.map +1 -1
  26. package/dist/prepareSend.d.ts +1 -1
  27. package/dist/prepareSend.d.ts.map +1 -1
  28. package/dist/sendUserOp.d.ts +0 -18
  29. package/dist/sendUserOp.d.ts.map +1 -1
  30. package/dist/tokenBalances.d.ts.map +1 -1
  31. package/dist/tokens.d.ts +10 -8
  32. package/dist/tokens.d.ts.map +1 -1
  33. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +4 -5
  34. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -1
  35. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts +4 -5
  36. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts.map +1 -1
  37. package/dist/transactionIntent/deposits/standardDeposit.d.ts +2 -2
  38. package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -1
  39. package/dist/transactionIntent/execution/transactionState.d.ts +2 -2
  40. package/dist/transactionIntent/execution/transactionState.d.ts.map +1 -1
  41. package/dist/transactionIntent/handlers/crossChain.d.ts +4 -4
  42. package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -1
  43. package/dist/transactionIntent/handlers/index.d.ts +0 -1
  44. package/dist/transactionIntent/handlers/index.d.ts.map +1 -1
  45. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts +4 -34
  46. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -1
  47. package/dist/transactionIntent/quote/normalizeQuote.d.ts.map +1 -1
  48. package/dist/transactionIntent/quote/quoteHelpers.d.ts +2 -1
  49. package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -1
  50. package/dist/transactionIntent/types.d.ts +6 -19
  51. package/dist/transactionIntent/types.d.ts.map +1 -1
  52. package/dist/transactionIntent/utils/index.d.ts +0 -1
  53. package/dist/transactionIntent/utils/index.d.ts.map +1 -1
  54. package/dist/transactions.d.ts +2 -20
  55. package/dist/transactions.d.ts.map +1 -1
  56. package/dist/utils.d.ts +8 -2
  57. package/dist/utils.d.ts.map +1 -1
  58. package/dist/walletUtils.d.ts +21 -0
  59. package/dist/walletUtils.d.ts.map +1 -0
  60. package/dist/wallets.d.ts +33 -240
  61. package/dist/wallets.d.ts.map +1 -1
  62. package/dist/widget/components/AccountIntentTransactionHistory.d.ts.map +1 -1
  63. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  64. package/dist/widget/components/FeeOption.d.ts +8 -13
  65. package/dist/widget/components/FeeOption.d.ts.map +1 -1
  66. package/dist/widget/components/FeeOptions.d.ts +11 -5
  67. package/dist/widget/components/FeeOptions.d.ts.map +1 -1
  68. package/dist/widget/components/NativeGasOption.d.ts.map +1 -1
  69. package/dist/widget/components/Pay.d.ts.map +1 -1
  70. package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
  71. package/dist/widget/components/QRCodeDeposit.d.ts +5 -0
  72. package/dist/widget/components/QRCodeDeposit.d.ts.map +1 -1
  73. package/dist/widget/components/QRCodeWalletSelect.d.ts +13 -0
  74. package/dist/widget/components/QRCodeWalletSelect.d.ts.map +1 -0
  75. package/dist/widget/components/QrCode.d.ts.map +1 -1
  76. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  77. package/dist/widget/components/Receipt.d.ts.map +1 -1
  78. package/dist/widget/components/ScreenHeader.d.ts +1 -1
  79. package/dist/widget/components/ScreenHeader.d.ts.map +1 -1
  80. package/dist/widget/components/Toast.d.ts.map +1 -1
  81. package/dist/widget/components/TokenImage.d.ts.map +1 -1
  82. package/dist/widget/css/compiled.css +1 -1
  83. package/dist/widget/hooks/useCheckout.d.ts +15 -1
  84. package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
  85. package/dist/widget/hooks/useCurrentScreen.d.ts +1 -1
  86. package/dist/widget/hooks/useCurrentScreen.d.ts.map +1 -1
  87. package/dist/widget/hooks/useDebugScreens.d.ts +1 -1
  88. package/dist/widget/hooks/useDebugScreens.d.ts.map +1 -1
  89. package/dist/widget/hooks/useIntentTransactionHistory.d.ts.map +1 -1
  90. package/dist/widget/hooks/useIsConnectedWalletSmartContract.d.ts +7 -0
  91. package/dist/widget/hooks/useIsConnectedWalletSmartContract.d.ts.map +1 -0
  92. package/dist/widget/hooks/useIsSequenceWallet.d.ts +6 -0
  93. package/dist/widget/hooks/useIsSequenceWallet.d.ts.map +1 -0
  94. package/dist/widget/hooks/useQuote.d.ts +5 -8
  95. package/dist/widget/hooks/useQuote.d.ts.map +1 -1
  96. package/dist/widget/hooks/useRecentTokens.d.ts.map +1 -1
  97. package/dist/widget/hooks/useSelectedFeeOption.d.ts +30 -0
  98. package/dist/widget/hooks/useSelectedFeeOption.d.ts.map +1 -0
  99. package/dist/widget/hooks/useSendForm.d.ts +6 -15
  100. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  101. package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
  102. package/dist/widget/index.js +1 -1
  103. package/dist/widget/providers/TrailsProvider.d.ts +23 -12
  104. package/dist/widget/providers/TrailsProvider.d.ts.map +1 -1
  105. package/dist/widget/widget.d.ts +11 -0
  106. package/dist/widget/widget.d.ts.map +1 -1
  107. package/package.json +8 -8
  108. package/src/analytics.ts +53 -21
  109. package/src/cctp.ts +0 -1016
  110. package/src/chains.ts +93 -39
  111. package/src/config.ts +24 -6
  112. package/src/constants.ts +1 -4
  113. package/src/contractUtils.ts +6 -6
  114. package/src/estimate.ts +3 -6
  115. package/src/fees.ts +5 -10
  116. package/src/gasless.ts +45 -0
  117. package/src/index.ts +7 -6
  118. package/src/indexerClient.ts +2 -2
  119. package/src/intents.ts +52 -206
  120. package/src/mutations.ts +3 -2
  121. package/src/paymasterSend.ts +2 -5
  122. package/src/prepareSend.ts +9 -12
  123. package/src/sendUserOp.ts +3 -64
  124. package/src/tokenBalances.ts +2 -1
  125. package/src/tokens.ts +62 -133
  126. package/src/trailsClient.ts +1 -1
  127. package/src/transactionIntent/deposits/depositOrchestrator.ts +14 -15
  128. package/src/transactionIntent/deposits/gaslessDeposit.ts +70 -100
  129. package/src/transactionIntent/deposits/standardDeposit.ts +22 -28
  130. package/src/transactionIntent/execution/transactionState.ts +2 -2
  131. package/src/transactionIntent/handlers/crossChain.ts +165 -385
  132. package/src/transactionIntent/handlers/index.ts +0 -1
  133. package/src/transactionIntent/handlers/sameChainSameToken.ts +228 -94
  134. package/src/transactionIntent/quote/normalizeQuote.ts +4 -6
  135. package/src/transactionIntent/quote/quoteHelpers.ts +35 -3
  136. package/src/transactionIntent/types.ts +6 -27
  137. package/src/transactionIntent/utils/index.ts +0 -1
  138. package/src/transactions.ts +6 -203
  139. package/src/umd.tsx +1 -3
  140. package/src/utils.ts +28 -8
  141. package/src/walletUtils.ts +42 -0
  142. package/src/wallets.ts +361 -203
  143. package/src/widget/compiled.css +1 -1
  144. package/src/widget/components/AccountIntentTransactionHistory.tsx +73 -4
  145. package/src/widget/components/AccountSettings.tsx +17 -17
  146. package/src/widget/components/ChainList.tsx +3 -3
  147. package/src/widget/components/ClassicSwap.tsx +19 -10
  148. package/src/widget/components/ConfigDisplay.tsx +1 -1
  149. package/src/widget/components/FeeOption.tsx +63 -20
  150. package/src/widget/components/FeeOptions.tsx +54 -123
  151. package/src/widget/components/NativeGasOption.tsx +3 -1
  152. package/src/widget/components/Pay.tsx +18 -11
  153. package/src/widget/components/PoolDeposit.tsx +23 -10
  154. package/src/widget/components/QRCodeDeposit.tsx +50 -30
  155. package/src/widget/components/QRCodeWalletSelect.tsx +77 -0
  156. package/src/widget/components/QrCode.tsx +188 -233
  157. package/src/widget/components/QuoteDetails.tsx +48 -2
  158. package/src/widget/components/Receipt.tsx +5 -2
  159. package/src/widget/components/ScreenHeader.tsx +10 -8
  160. package/src/widget/components/Toast.tsx +10 -0
  161. package/src/widget/components/TokenImage.tsx +56 -13
  162. package/src/widget/hooks/useCheckout.ts +71 -0
  163. package/src/widget/hooks/useCurrentScreen.tsx +1 -0
  164. package/src/widget/hooks/useDebugScreens.ts +5 -0
  165. package/src/widget/hooks/useIntentTransactionHistory.ts +788 -418
  166. package/src/widget/hooks/useIsConnectedWalletSmartContract.ts +43 -0
  167. package/src/widget/hooks/useIsSequenceWallet.ts +17 -0
  168. package/src/widget/hooks/useQuote.ts +16 -17
  169. package/src/widget/hooks/useRecentTokens.ts +2 -1
  170. package/src/widget/hooks/useSelectedFeeOption.tsx +257 -0
  171. package/src/widget/hooks/useSendForm.ts +172 -47
  172. package/src/widget/hooks/useTokenList.ts +15 -2
  173. package/src/widget/providers/TrailsProvider.tsx +53 -25
  174. package/src/widget/widget.tsx +119 -48
  175. package/dist/cctpqueue.d.ts +0 -18
  176. package/dist/cctpqueue.d.ts.map +0 -1
  177. package/dist/preconditions.d.ts +0 -12
  178. package/dist/preconditions.d.ts.map +0 -1
  179. package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts +0 -62
  180. package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts.map +0 -1
  181. package/dist/transactionIntent/utils/lifiHelpers.d.ts +0 -10
  182. package/dist/transactionIntent/utils/lifiHelpers.d.ts.map +0 -1
  183. package/dist/widget/hooks/useSelectedFeeToken.d.ts +0 -33
  184. package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +0 -1
  185. package/src/cctpqueue.ts +0 -69
  186. package/src/preconditions.ts +0 -47
  187. package/src/transactionIntent/handlers/sameChainDifferentToken.ts +0 -323
  188. package/src/transactionIntent/utils/lifiHelpers.ts +0 -68
  189. package/src/widget/hooks/useSelectedFeeToken.tsx +0 -288
@@ -1,323 +0,0 @@
1
- import type { Account, PublicClient, WalletClient } from "viem"
2
- import { zeroAddress, decodeFunctionData, erc20Abi, formatUnits } from "viem"
3
- import type { TransactionState } from "../../transactions.js"
4
- import type { PrepareSendReturn, SendReturn, TradeType } from "../types.js"
5
- import { logger } from "../../logger.js"
6
- import { getIsCustomCalldata } from "../../contractUtils.js"
7
- import {
8
- getRelaySDKQuote,
9
- executeSimpleRelayTransaction,
10
- getTxHashFromRelayResult,
11
- type RelayTradeType,
12
- } from "../../relaySdk.js"
13
- import { getNormalizedQuoteObject } from "../quote/normalizeQuote.js"
14
- import {
15
- getFeesFromRelaySdkQuote,
16
- getSlippageToleranceFromRelaySdkQuote,
17
- getPriceImpactFromRelaySdkQuote,
18
- getPriceImpactUsdFromRelaySdkQuote,
19
- } from "../quote/feeExtractors.js"
20
- import { checkAccountBalance } from "../utils/balanceChecker.js"
21
- import { attemptSwitchChain } from "../../chainSwitch.js"
22
- import { getTransactionStateFromReceipt } from "../execution/transactionState.js"
23
- import { calcAmountUsdPrice } from "../../prices.js"
24
- import { trackPaymentCompleted, trackPaymentError } from "../../analytics.js"
25
- import { TradeType as LocalTradeType } from "../types.js"
26
-
27
- /**
28
- * @description
29
- * This handler manages same-chain token swaps (e.g., ETH to WETH on the same chain).
30
- * It leverages the Relay SDK for quote and transaction execution.
31
- *
32
- * Key characteristics:
33
- * - Uses Relay SDK directly for quote fetching and transaction execution
34
- * - Single transaction leg (swap on origin chain)
35
- * - No cross-chain bridging required
36
- * - Supports various token pair combinations on the same chain
37
- *
38
- * Transaction Flow:
39
- * 1. Fetch quote via getRelaySDKQuote (Relay SDK API)
40
- * 2. Create intent via createIntent (Intent object created)
41
- * 3. Execute swap via executeSimpleRelayTransaction (User submits swap transaction)
42
- * 4. Monitor via waitIntentReceipt API for transaction completion
43
- * 5. Update transaction state and invoke callbacks
44
- *
45
- * Relay SDK Integration:
46
- * - Direct integration with Relay SDK for quote and transaction submission
47
- * - Transaction hash extracted via getTxHashFromRelayResult
48
- * - Receipt polling via Trails API for consistent monitoring
49
- *
50
- * Error Handling:
51
- * - Balance validation before transaction submission
52
- * - Chain switching if user is on wrong network
53
- * - Relay SDK error handling with proper error propagation
54
- * - Checkout error callbacks for UI feedback
55
- *
56
- * State Management:
57
- * - transactionStates[0]: Swap transaction
58
- * - Updates propagated via onTransactionStateChange callback
59
- * - Analytics tracking for payment completion or errors
60
- */
61
- export async function handleSameChainDifferentToken({
62
- originTokenAddress,
63
- originTokenDecimals,
64
- swapAmount,
65
- destinationTokenAddress,
66
- destinationTokenDecimals,
67
- destinationCalldata,
68
- recipient,
69
- originChainId,
70
- walletClient,
71
- publicClient,
72
- account,
73
- tradeType = LocalTradeType.EXACT_OUTPUT,
74
- slippageTolerance,
75
- onTransactionStateChange,
76
- transactionStates,
77
- sourceTokenPriceUsd,
78
- destinationTokenPriceUsd,
79
- originNativeTokenPriceUsd,
80
- mode,
81
- fundMethod,
82
- originTokenSymbol,
83
- destinationTokenSymbol,
84
- }: {
85
- originTokenAddress: string
86
- originTokenDecimals: number
87
- swapAmount: string
88
- destinationTokenAddress: string
89
- destinationTokenDecimals: number
90
- destinationCalldata?: string
91
- recipient: string
92
- originChainId: number
93
- walletClient: WalletClient
94
- publicClient: PublicClient
95
- account: Account
96
- tradeType?: TradeType
97
- slippageTolerance?: string
98
- onTransactionStateChange: (transactionStates: TransactionState[]) => void
99
- transactionStates: TransactionState[]
100
- sourceTokenPriceUsd?: number | null
101
- destinationTokenPriceUsd?: number | null
102
- originNativeTokenPriceUsd?: number | null
103
- mode?: "pay" | "fund" | "earn" | "swap" | "receive"
104
- fundMethod?: string
105
- originTokenSymbol: string
106
- destinationTokenSymbol: string
107
- }): Promise<PrepareSendReturn> {
108
- const destinationTxs: { to: string; value: string; data: string }[] = []
109
- const hasCustomCalldata = getIsCustomCalldata(destinationCalldata)
110
- if (hasCustomCalldata && tradeType === LocalTradeType.EXACT_OUTPUT) {
111
- destinationTxs.push({
112
- to: recipient,
113
- value: destinationTokenAddress === zeroAddress ? swapAmount : "0",
114
- data: destinationCalldata as `0x${string}`,
115
- })
116
- } else if (hasCustomCalldata && tradeType === LocalTradeType.EXACT_INPUT) {
117
- destinationTxs.push({
118
- to: recipient,
119
- value: "0",
120
- data: destinationCalldata as `0x${string}`,
121
- })
122
- }
123
-
124
- const quote = await getRelaySDKQuote({
125
- wallet: walletClient,
126
- chainId: originChainId,
127
- amount: swapAmount,
128
- currency: originTokenAddress,
129
- toCurrency: destinationTokenAddress,
130
- txs: destinationTxs,
131
- tradeType: tradeType as unknown as RelayTradeType,
132
- slippageTolerance: slippageTolerance,
133
- recipient: hasCustomCalldata ? recipient : undefined,
134
- })
135
-
136
- logger.console.log("[trails-sdk] relaysdk quote", quote)
137
- let depositAmount = "0"
138
- let destinationTokenAmount = "0"
139
-
140
- if (tradeType === LocalTradeType.EXACT_INPUT) {
141
- depositAmount = swapAmount
142
- destinationTokenAmount = quote?.details?.currencyOut?.amount?.toString()
143
- } else {
144
- try {
145
- destinationTokenAmount = swapAmount
146
- depositAmount = quote.steps?.[0]?.items?.[0]?.data?.value
147
- if (originTokenAddress !== zeroAddress) {
148
- const decoded = decodeFunctionData({
149
- abi: erc20Abi,
150
- data: quote.steps?.[0]?.items?.[0]?.data?.data,
151
- })
152
- if (decoded.functionName === "approve") {
153
- depositAmount = decoded.args[1].toString()
154
- }
155
- if (decoded.functionName === "transfer") {
156
- depositAmount = decoded.args[1].toString()
157
- }
158
- }
159
- } catch (error) {
160
- logger.console.error("[trails-sdk] Error decoding function data:", error)
161
- }
162
- }
163
-
164
- const depositOriginAddress =
165
- quote?.steps?.[quote?.steps?.length - 1]?.items?.[
166
- quote?.steps?.[quote?.steps?.length - 1]?.items?.length - 1
167
- ]?.data?.to
168
-
169
- if (
170
- quote?.details?.currencyIn?.amountFormatted &&
171
- quote?.details?.currencyIn?.amountUsd
172
- ) {
173
- const quoteProviderSourceTokenPriceUsd =
174
- Number(quote.details.currencyIn.amountUsd) /
175
- Number(quote.details.currencyIn.amountFormatted)
176
- if (quoteProviderSourceTokenPriceUsd) {
177
- sourceTokenPriceUsd = quoteProviderSourceTokenPriceUsd
178
- }
179
- }
180
-
181
- if (
182
- quote?.details?.currencyOut?.amountFormatted &&
183
- quote?.details?.currencyOut?.amountUsd
184
- ) {
185
- const quoteProviderDestinationTokenPriceUsd =
186
- Number(quote.details.currencyOut.amountUsd) /
187
- Number(quote.details.currencyOut.amountFormatted)
188
- if (quoteProviderDestinationTokenPriceUsd) {
189
- destinationTokenPriceUsd = quoteProviderDestinationTokenPriceUsd
190
- }
191
- }
192
-
193
- const normalizedQuote = await getNormalizedQuoteObject({
194
- originDepositAddress: depositOriginAddress,
195
- destinationDepositAddress: recipient,
196
- destinationAddress: recipient,
197
- destinationCalldata,
198
- originAmount: depositAmount,
199
- destinationAmount: destinationTokenAmount,
200
- originTokenAddress: originTokenAddress,
201
- destinationTokenAddress: destinationTokenAddress,
202
- originTokenPriceUsd: sourceTokenPriceUsd?.toString() || null,
203
- destinationTokenPriceUsd: destinationTokenPriceUsd?.toString() || null,
204
- fees: getFeesFromRelaySdkQuote(quote),
205
- slippageTolerance: getSlippageToleranceFromRelaySdkQuote(quote),
206
- priceImpact: getPriceImpactFromRelaySdkQuote(quote),
207
- priceImpactUsd: getPriceImpactUsdFromRelaySdkQuote(quote),
208
- transactionStates,
209
- originChainId,
210
- destinationChainId: originChainId,
211
- originNativeTokenPriceUsd,
212
- quoteProvider: "relay",
213
- intent: undefined,
214
- })
215
-
216
- return {
217
- quote: normalizedQuote,
218
- send: async ({
219
- onOriginSend,
220
- }: {
221
- onOriginSend?: () => void
222
- }): Promise<SendReturn> => {
223
- const { hasEnoughBalance, balanceError } = await checkAccountBalance({
224
- account,
225
- tokenAddress: originTokenAddress,
226
- depositAmount,
227
- publicClient,
228
- })
229
-
230
- if (!hasEnoughBalance) {
231
- throw balanceError
232
- }
233
-
234
- await attemptSwitchChain({
235
- walletClient,
236
- desiredChainId: originChainId,
237
- })
238
-
239
- const result = await executeSimpleRelayTransaction(quote, walletClient)
240
- logger.console.log("[trails-sdk] relaysdk result", result)
241
-
242
- const txHash = getTxHashFromRelayResult(result)
243
-
244
- if (onOriginSend) {
245
- onOriginSend()
246
- }
247
-
248
- const depositUserTxnReceipt =
249
- await publicClient.waitForTransactionReceipt({
250
- hash: txHash as `0x${string}`,
251
- })
252
-
253
- transactionStates[0] = getTransactionStateFromReceipt(
254
- depositUserTxnReceipt,
255
- originChainId,
256
- transactionStates[0]?.label,
257
- )
258
-
259
- try {
260
- onTransactionStateChange(transactionStates)
261
- } catch (error) {
262
- logger.console.error(
263
- "[trails-sdk] Error calling onTransactionStateChange:",
264
- error,
265
- )
266
- }
267
-
268
- const depositAmountFormatted = Number(
269
- formatUnits(BigInt(depositAmount), originTokenDecimals),
270
- )
271
-
272
- const depositAmountUsd = calcAmountUsdPrice({
273
- amount: depositAmountFormatted,
274
- usdPrice: sourceTokenPriceUsd,
275
- })
276
-
277
- const destinationTokenAmountFormatted = Number(
278
- formatUnits(BigInt(destinationTokenAmount), destinationTokenDecimals),
279
- )
280
-
281
- const destinationTokenAmountUsd = calcAmountUsdPrice({
282
- amount: Number(destinationTokenAmountFormatted),
283
- usdPrice: destinationTokenPriceUsd,
284
- })
285
-
286
- // Track payment completion for same-chain different-token transaction
287
- if (depositUserTxnReceipt && depositUserTxnReceipt.status === "success") {
288
- trackPaymentCompleted({
289
- userAddress: account.address,
290
- originTxHash: depositUserTxnReceipt.transactionHash,
291
- originChainId,
292
- destinationChainId: originChainId, // Same chain
293
- mode,
294
- fundMethod,
295
- originTokenAddress,
296
- originTokenSymbol,
297
- destinationTokenAddress,
298
- destinationTokenSymbol,
299
- depositTokenAmountUsd: depositAmountUsd?.toString(),
300
- destinationTokenAmountUsd: destinationTokenAmountUsd?.toString(),
301
- })
302
- } else if (depositUserTxnReceipt) {
303
- trackPaymentError({
304
- error: "Relay transaction failed",
305
- userAddress: account.address,
306
- mode,
307
- fundMethod,
308
- originTokenAddress,
309
- originTokenSymbol,
310
- destinationTokenAddress,
311
- destinationTokenSymbol,
312
- })
313
- }
314
-
315
- return {
316
- depositUserTxnReceipt: depositUserTxnReceipt,
317
- originMetaTxnReceipt: null,
318
- destinationMetaTxnReceipt: null,
319
- totalCompletionSeconds: 0,
320
- }
321
- },
322
- }
323
- }
@@ -1,68 +0,0 @@
1
- import { formatUnits, zeroAddress } from "viem"
2
- import { calcAmountUsdPrice } from "../../prices.js"
3
- import { logger } from "../../logger.js"
4
-
5
- // ETH fee required by some bridges for low token amounts
6
- // TODO: update backend API to return the native fee requirement, if any
7
- export function getNeedsLifiNativeFee({
8
- originTokenAddress,
9
- destinationTokenAmount,
10
- destinationTokenDecimals,
11
- sourceTokenDecimals,
12
- sourceTokenPriceUsd,
13
- destinationTokenPriceUsd,
14
- depositAmount,
15
- }: {
16
- originTokenAddress: string
17
- destinationTokenAmount: string
18
- destinationTokenDecimals: number
19
- sourceTokenDecimals: number
20
- sourceTokenPriceUsd: number | null
21
- destinationTokenPriceUsd: number | null
22
- depositAmount: string
23
- }): boolean {
24
- let needsNativeFee = false
25
- if (
26
- originTokenAddress !== zeroAddress &&
27
- sourceTokenPriceUsd &&
28
- destinationTokenPriceUsd &&
29
- depositAmount &&
30
- destinationTokenDecimals !== undefined &&
31
- sourceTokenDecimals !== undefined
32
- ) {
33
- // Convert from wei to token units using formatUnits
34
- const destinationAmount = Number(
35
- formatUnits(BigInt(destinationTokenAmount), destinationTokenDecimals),
36
- )
37
- const depositAmountFormatted = Number(
38
- formatUnits(BigInt(depositAmount), sourceTokenDecimals),
39
- )
40
- logger.console.log("[trails-sdk] destinationAmount", destinationAmount)
41
- logger.console.log(
42
- "[trails-sdk] depositAmountFormatted",
43
- depositAmountFormatted,
44
- )
45
- const destinationAmountUsd = calcAmountUsdPrice({
46
- amount: destinationAmount,
47
- usdPrice: destinationTokenPriceUsd,
48
- })
49
- const depositAmountUsd = calcAmountUsdPrice({
50
- amount: depositAmountFormatted,
51
- usdPrice: sourceTokenPriceUsd,
52
- })
53
- const diff = depositAmountUsd - destinationAmountUsd
54
- logger.console.log(
55
- "[trails-sdk] destinationAmountUsd",
56
- destinationAmountUsd,
57
- "[trails-sdk] depositAmountUsd",
58
- depositAmountUsd,
59
- "[trails-sdk] diff",
60
- diff,
61
- )
62
- if (diff >= 0 && diff <= 0.02) {
63
- needsNativeFee = true
64
- }
65
- }
66
-
67
- return needsNativeFee
68
- }
@@ -1,288 +0,0 @@
1
- import React, {
2
- createContext,
3
- useContext,
4
- useState,
5
- useCallback,
6
- useEffect,
7
- useMemo,
8
- type ReactNode,
9
- } from "react"
10
- import { logger } from "../../logger.js"
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
- }
24
-
25
- // Define the FeeOption interface with balance check properties
26
- export interface FeeOption {
27
- tokenAddress: string
28
- tokenSymbol: string
29
- tokenDecimals: number
30
- amount: string
31
- amountUSD: number
32
- notEnoughBalance?: boolean
33
- tokenImageUrl?: string
34
- chainId?: number
35
- amountUsdDisplay?: string // Formatted USD display like "≈ $0.39"
36
- }
37
-
38
- // Token type with balance information
39
- export interface TokenWithBalance {
40
- chainId: number
41
- contractAddress?: string
42
- balance?: string
43
- imageUrl?: string
44
- }
45
-
46
- interface SelectedFeeTokenContextType {
47
- selectedFeeToken: FeeOption | null
48
- setSelectedFeeToken: (token: FeeOption | null) => void
49
- clearSelectedFeeToken: () => void
50
- processedFeeOptions: FeeOption[]
51
- setRawFeeOptions: (
52
- feeOptions: any[] | null | undefined,
53
- originChainId: number | undefined,
54
- availableTokens: TokenWithBalance[],
55
- ) => void
56
- }
57
-
58
- const SelectedFeeTokenContext = createContext<
59
- SelectedFeeTokenContextType | undefined
60
- >(undefined)
61
-
62
- interface SelectedFeeTokenProviderProps {
63
- children: ReactNode
64
- initialToken?: FeeOption | null
65
- }
66
-
67
- export const SelectedFeeTokenProvider: React.FC<
68
- SelectedFeeTokenProviderProps
69
- > = ({ children, initialToken = null }) => {
70
- const [selectedFeeToken, setSelectedFeeTokenInternalRaw] =
71
- useState<FeeOption | null>(initialToken)
72
- const [hasUserSelectedFeeOption, setHasUserSelectedFeeOption] =
73
- useState(false)
74
- const [rawFeeOptions, setRawFeeOptionsInternal] = useState<any[]>([])
75
- const [originTokenChainId, setOriginTokenChainId] = useState<
76
- number | undefined
77
- >(undefined)
78
- const [availableTokens, setAvailableTokens] = useState<TokenWithBalance[]>([])
79
-
80
- // Wrapper to log all state changes to selectedFeeToken
81
- const setSelectedFeeTokenInternal = useCallback((token: FeeOption | null) => {
82
- logger.console.log(
83
- "[trails-sdk] [FEE-SELECT] selectedFeeToken state changing:",
84
- {
85
- to: token,
86
- toNull: token === null,
87
- },
88
- )
89
- setSelectedFeeTokenInternalRaw(token)
90
- }, [])
91
-
92
- // Wrapper to track when user makes an explicit selection
93
- const setSelectedFeeToken = useCallback(
94
- (token: FeeOption | null) => {
95
- logger.console.log(
96
- "[trails-sdk] [FEE-SELECT] setSelectedFeeToken called (user selection):",
97
- {
98
- token,
99
- isNull: token === null,
100
- isUndefined: token === undefined,
101
- },
102
- )
103
- setSelectedFeeTokenInternal(token)
104
- setHasUserSelectedFeeOption(true)
105
- },
106
- [setSelectedFeeTokenInternal],
107
- )
108
-
109
- const clearSelectedFeeToken = useCallback(() => {
110
- logger.console.log("[trails-sdk] [FEE-SELECT] Clearing selected fee token")
111
- setSelectedFeeTokenInternal(null)
112
- setHasUserSelectedFeeOption(false)
113
- }, [setSelectedFeeTokenInternal])
114
-
115
- // Process raw fee options with balance checks
116
- const processedFeeOptions = useMemo(() => {
117
- if (!rawFeeOptions || rawFeeOptions.length === 0) {
118
- return []
119
- }
120
-
121
- logger.console.log("[trails-sdk] [FEE-SELECT] Processing fee options:", {
122
- rawFeeOptions,
123
- originTokenChainId,
124
- availableTokensCount: availableTokens.length,
125
- })
126
-
127
- // Add balance check and additional properties to each fee option
128
- const feeOptionsWithBalanceCheck = rawFeeOptions.map((option: any) => {
129
- // For native token (zero/ETH address), check if user has enough native balance
130
- if (isNativeTokenAddress(option.tokenAddress)) {
131
- // Find the native token balance for the origin chain
132
- const nativeTokenInfo = availableTokens.find(
133
- (token) =>
134
- token.chainId === originTokenChainId &&
135
- (isNativeTokenAddress(token.contractAddress) ||
136
- !token.contractAddress),
137
- )
138
-
139
- const nativeBalance = nativeTokenInfo?.balance || "0"
140
- const requiredAmount = option.amount
141
- const notEnoughBalance = BigInt(nativeBalance) < BigInt(requiredAmount)
142
-
143
- return {
144
- ...option,
145
- notEnoughBalance,
146
- tokenImageUrl: nativeTokenInfo?.imageUrl,
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
150
- }
151
- }
152
-
153
- // For ERC-20 tokens, check user's token balances
154
- const userTokenBalance = availableTokens.find(
155
- (token) =>
156
- token.contractAddress?.toLowerCase() ===
157
- option.tokenAddress.toLowerCase() &&
158
- token.chainId === originTokenChainId,
159
- )
160
-
161
- if (userTokenBalance) {
162
- const userBalance = userTokenBalance.balance || "0"
163
- const requiredAmount = option.amount
164
- const notEnoughBalance = BigInt(userBalance) < BigInt(requiredAmount)
165
-
166
- return {
167
- ...option,
168
- notEnoughBalance,
169
- tokenImageUrl: userTokenBalance.imageUrl,
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
173
- }
174
- }
175
-
176
- // If token balance not found, assume insufficient balance
177
- return {
178
- ...option,
179
- notEnoughBalance: true,
180
- tokenImageUrl: undefined,
181
- chainId: originTokenChainId, // Fallback to origin chain
182
- amountUsdDisplay: formatUsdAmountDisplay(option.amountUsd),
183
- amountUSD: option.amountUsd, // Normalize to uppercase for consistency
184
- }
185
- })
186
-
187
- // Sort fee options: available options first, then disabled options at the bottom
188
- const sortedFeeOptions = feeOptionsWithBalanceCheck.sort(
189
- (a: FeeOption, b: FeeOption) => {
190
- // If both have the same balance status, maintain original order
191
- if (a.notEnoughBalance === b.notEnoughBalance) {
192
- return 0
193
- }
194
- // Put available options (notEnoughBalance: false) before disabled options (notEnoughBalance: true)
195
- return a.notEnoughBalance ? 1 : -1
196
- },
197
- )
198
-
199
- logger.console.log(
200
- "[trails-sdk] [FEE-SELECT] Processed and sorted fee options:",
201
- sortedFeeOptions,
202
- )
203
-
204
- return sortedFeeOptions
205
- }, [rawFeeOptions, originTokenChainId, availableTokens])
206
-
207
- // Auto-select first ERC20 fee option with sufficient balance
208
- // Only auto-select if user hasn't made an explicit selection yet
209
- useEffect(() => {
210
- if (
211
- processedFeeOptions.length > 0 &&
212
- !hasUserSelectedFeeOption &&
213
- !selectedFeeToken
214
- ) {
215
- // Find first token option with sufficient balance
216
- const firstValidOption = processedFeeOptions.find(
217
- (option: FeeOption) => !option.notEnoughBalance,
218
- )
219
-
220
- if (firstValidOption) {
221
- logger.console.log(
222
- "[trails-sdk] [FEE-SELECT] Auto-selecting first valid fee option:",
223
- firstValidOption,
224
- )
225
- // Use internal setter to avoid marking as user selection
226
- setSelectedFeeTokenInternal({
227
- tokenAddress: firstValidOption.tokenAddress,
228
- tokenSymbol: firstValidOption.tokenSymbol,
229
- tokenDecimals: firstValidOption.tokenDecimals,
230
- amount: firstValidOption.amount,
231
- amountUSD: firstValidOption.amountUSD,
232
- })
233
- }
234
- }
235
- }, [
236
- processedFeeOptions,
237
- selectedFeeToken,
238
- hasUserSelectedFeeOption,
239
- setSelectedFeeTokenInternal,
240
- ])
241
-
242
- // Function to set raw fee options and process them
243
- const setRawFeeOptions = useCallback(
244
- (
245
- feeOptions: any[] | null | undefined,
246
- originChainId: number | undefined,
247
- tokens: TokenWithBalance[],
248
- ) => {
249
- const apiFeeOptions = feeOptions ?? []
250
- setRawFeeOptionsInternal(apiFeeOptions)
251
- setOriginTokenChainId(originChainId)
252
- setAvailableTokens(tokens)
253
-
254
- logger.console.log("[trails-sdk] [FEE-SELECT] Raw fee options set:", {
255
- feeOptionsCount: apiFeeOptions.length,
256
- originChainId: originChainId,
257
- tokensCount: tokens.length,
258
- })
259
- },
260
- [],
261
- )
262
-
263
- const value: SelectedFeeTokenContextType = {
264
- selectedFeeToken,
265
- setSelectedFeeToken,
266
- clearSelectedFeeToken,
267
- processedFeeOptions,
268
- setRawFeeOptions,
269
- }
270
-
271
- return (
272
- <SelectedFeeTokenContext.Provider value={value}>
273
- {children}
274
- </SelectedFeeTokenContext.Provider>
275
- )
276
- }
277
-
278
- export const useSelectedFeeToken = (): SelectedFeeTokenContextType => {
279
- const context = useContext(SelectedFeeTokenContext)
280
-
281
- if (context === undefined) {
282
- throw new Error(
283
- "useSelectedFeeToken must be used within a SelectedFeeTokenProvider",
284
- )
285
- }
286
-
287
- return context
288
- }