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,3 +1,2 @@
1
1
  export * from "./sameChainSameToken.js"
2
- export * from "./sameChainDifferentToken.js"
3
2
  export * from "./crossChain.js"
@@ -1,7 +1,9 @@
1
1
  import type { Account, Chain, WalletClient, TransactionReceipt } from "viem"
2
- import { createPublicClient, http, formatUnits, ethAddress } from "viem"
3
- import type { TrailsApi } from "@0xsequence/trails-api"
4
- import type { MetaTxnReceipt, PrepareSendReturn, SendReturn } from "../types.js"
2
+ import { formatUnits } from "viem"
3
+ import { getPublicRpcClient } from "../../chains.js"
4
+ import type { FeeOption, TrailsApi } from "@0xsequence/trails-api"
5
+ import type { PrepareSendReturn, SendReturn } from "../types.js"
6
+ import type { IntentTransaction } from "@0xsequence/trails-api"
5
7
  import type { TransactionState } from "../../transactions.js"
6
8
  import type { CheckoutOnHandlers } from "../../widget/hooks/useCheckout.js"
7
9
  import type {
@@ -10,7 +12,6 @@ import type {
10
12
  DepositSignature,
11
13
  ExecuteIntentResponse,
12
14
  } from "@0xsequence/trails-api"
13
- import type { SelectedFeeToken } from "../types.js"
14
15
  import { logger } from "../../logger.js"
15
16
  import {
16
17
  isTestnetDebugMode,
@@ -36,39 +37,10 @@ import { getChainInfo } from "../../chains.js"
36
37
  import { getTransactionStateFromReceipt } from "../execution/transactionState.js"
37
38
  import { calcAmountUsdPrice } from "../../prices.js"
38
39
  import { pollIntentReceipt } from "../../intentReceiptPoller.js"
39
- import { zeroAddress } from "viem"
40
-
41
- /**
42
- * @description
43
- * This handler manages simple same-chain token transfers (e.g., using USDC to transact with USDC on the same chain).
44
- * It supports both standard transfers and custom calldata execution.
45
- *
46
- * Key characteristics:
47
- * - Uses the Trails API with getIntent and commitIntent for setup
48
- * - Single transaction leg (user transfer)
49
- * - No cross-chain bridging or token swapping required
50
- * - Direct transaction submission via attemptUserDepositTx (simpler than cross-chain polling)
51
- * - Supports both gasless and standard fee payment modes
52
- *
53
- * Transaction Flow:
54
- * 1. Get intent via getIntent (Intent object with validation)
55
- * 2. Commit intent via commitIntent (Record created in backend)
56
- * 3. User submits transaction via attemptUserDepositTx (handles both gasless and standard)
57
- * 4. Wait for transaction receipt (direct receipt polling, not via waitIntentReceipt API)
58
- * 5. Update transaction state and invoke callbacks
59
- *
60
- * Error Handling:
61
- * - Balance validation before transaction submission
62
- * - Gas estimation for accurate fee calculation
63
- * - Proper error propagation with checkout error callbacks
64
- * - Fallback logging for debugging
65
- *
66
- * State Management:
67
- * - transactionStates[0]: User transfer transaction
68
- * - Updates propagated via onTransactionStateChange callback
69
- * - Analytics tracking for payment completion or errors
70
- * - Support for gasless fee options via gasFeeOptions
71
- */
40
+ import { isNativeToken } from "../../utils.js"
41
+ import { getAccountTransactionHistory } from "../../transactions.js"
42
+ import { POLLING_INTERVALS } from "../constants.js"
43
+
72
44
  export async function handleSameChainSameToken({
73
45
  mainSignerAddress,
74
46
  originTokenAddress,
@@ -93,12 +65,13 @@ export async function handleSameChainSameToken({
93
65
  mode,
94
66
  fundMethod,
95
67
  paymasterUrl,
96
- selectedFeeToken,
97
68
  walletId,
98
69
  trailsClient,
99
70
  abortSignal,
100
71
  commitIntentFn,
101
72
  executeIntentFn,
73
+ sequenceProjectAccessKey,
74
+ sequenceIndexerUrl,
102
75
  }: {
103
76
  mainSignerAddress: string
104
77
  originTokenAddress: string
@@ -124,7 +97,6 @@ export async function handleSameChainSameToken({
124
97
  mode?: "pay" | "fund" | "earn" | "swap" | "receive"
125
98
  fundMethod?: string
126
99
  paymasterUrl?: string
127
- selectedFeeToken?: SelectedFeeToken
128
100
  walletId?: string
129
101
  trailsClient: TrailsApi
130
102
  abortSignal?: AbortSignal
@@ -134,6 +106,8 @@ export async function handleSameChainSameToken({
134
106
  depositTransactionHash?: string
135
107
  depositSignature?: DepositSignature
136
108
  }) => Promise<ExecuteIntentResponse>
109
+ sequenceProjectAccessKey?: string
110
+ sequenceIndexerUrl?: string
137
111
  }): Promise<PrepareSendReturn> {
138
112
  logger.console.log("[trails-sdk] isToSameToken && isToSameChain")
139
113
  const testnet = isTestnetDebugMode()
@@ -142,10 +116,7 @@ export async function handleSameChainSameToken({
142
116
  const effectiveOriginTokenAddress = testnet
143
117
  ? getTestnetOriginTokenAddress(effectiveOriginChainId)
144
118
  : originTokenAddress
145
- const effectivePublicClient = createPublicClient({
146
- chain: effectiveOriginChain,
147
- transport: http(),
148
- })
119
+ const effectivePublicClient = getPublicRpcClient(effectiveOriginChain)
149
120
 
150
121
  let noSufficientBalance = false
151
122
 
@@ -163,8 +134,8 @@ export async function handleSameChainSameToken({
163
134
  const hasCustomCalldata = getIsCustomCalldata(destinationCalldata)
164
135
 
165
136
  // For same-chain transactions, use Intent flow to support gasless deposits
166
- const destinationSalt = Date.now().toString()
167
- const intentArgs = getIntentArgs(
137
+ const salt = Date.now().toString()
138
+ const intentArgs = await getIntentArgs(
168
139
  mainSignerAddress,
169
140
  effectiveOriginChainId,
170
141
  effectiveOriginTokenAddress,
@@ -174,10 +145,12 @@ export async function handleSameChainSameToken({
174
145
  "0", // destinationTokenAmount (exact input)
175
146
  recipient,
176
147
  destinationCalldata,
177
- destinationSalt,
148
+ salt,
178
149
  slippageTolerance,
179
150
  TradeType.EXACT_INPUT,
180
151
  quoteProvider || "",
152
+ undefined, // connector - not available in this context
153
+ walletId, // walletId - use this to check for Sequence wallets
181
154
  )
182
155
 
183
156
  logger.console.log(
@@ -198,7 +171,7 @@ export async function handleSameChainSameToken({
198
171
  logger.console.log("[trails-sdk] Quote intent:", intent)
199
172
  logger.console.log("[trails-sdk] Quote intent gasFeeOptions:", gasFeeOptions)
200
173
 
201
- if (!intent.preconditions?.length || !intent.calls?.length) {
174
+ if (!intent.originPrecondition || !intent.originCalls) {
202
175
  throw new Error("Invalid intent")
203
176
  }
204
177
 
@@ -279,36 +252,29 @@ export async function handleSameChainSameToken({
279
252
  feeOptions: gasFeeOptions,
280
253
  send: async ({
281
254
  onOriginSend,
282
- selectedFeeToken: runtimeSelectedFeeToken,
255
+ selectedFeeOption: runtimeSelectedFeeOption,
283
256
  }: {
284
257
  onOriginSend?: () => void
285
- selectedFeeToken?: any
258
+ selectedFeeOption?: FeeOption | null
286
259
  }): Promise<SendReturn> => {
287
- // Use runtime selectedFeeToken if provided, otherwise fall back to the one from prepareSend
288
- const effectiveSelectedFeeToken =
289
- runtimeSelectedFeeToken ?? selectedFeeToken
260
+ // Use runtime selectedFeeOption (passed at execution time, always up-to-date)
261
+ const effectiveSelectedFeeOption = runtimeSelectedFeeOption
290
262
  // Check if gasless flow is enabled:
291
- // - selectedFeeToken must exist and not be null/undefined
263
+ // - selectedFeeOption must exist and not be null/undefined
292
264
  // - tokenAddress must not be native token (zeroAddress or ethAddress)
293
265
  // - walletId must not be sequence-waas
294
266
  const effectiveGasless =
295
- effectiveSelectedFeeToken !== null &&
296
- effectiveSelectedFeeToken !== undefined &&
297
- effectiveSelectedFeeToken.tokenAddress !== undefined &&
298
- effectiveSelectedFeeToken.tokenAddress !== null &&
299
- effectiveSelectedFeeToken.tokenAddress !== zeroAddress &&
300
- effectiveSelectedFeeToken.tokenAddress.toLowerCase() !==
301
- zeroAddress.toLowerCase() &&
302
- effectiveSelectedFeeToken.tokenAddress !== ethAddress &&
303
- effectiveSelectedFeeToken.tokenAddress.toLowerCase() !==
304
- ethAddress.toLowerCase() &&
267
+ effectiveSelectedFeeOption !== null &&
268
+ effectiveSelectedFeeOption !== undefined &&
269
+ effectiveSelectedFeeOption.tokenAddress !== undefined &&
270
+ effectiveSelectedFeeOption.tokenAddress !== null &&
271
+ !isNativeToken(effectiveSelectedFeeOption.tokenAddress) &&
305
272
  walletId !== "sequence-waas"
306
273
  logger.console.log(
307
274
  "[trails-sdk] [FEE-SELECT] [GASLESS-FLOW] send() called for same-chain:",
308
275
  {
309
- runtimeSelectedFeeToken,
310
- prepareTimeSelectedFeeToken: selectedFeeToken,
311
- effectiveSelectedFeeToken,
276
+ runtimeSelectedFeeOption,
277
+ effectiveSelectedFeeOption,
312
278
  effectiveGasless,
313
279
  },
314
280
  )
@@ -365,8 +331,8 @@ export async function handleSameChainSameToken({
365
331
  logger.console.log("[trails-sdk] origin call params", originCallParams)
366
332
 
367
333
  let depositUserTxnReceipt: TransactionReceipt | null = null
368
- const originMetaTxnReceipt: MetaTxnReceipt | null = null
369
- const destinationMetaTxnReceipt: MetaTxnReceipt | null = null
334
+ let originIntentTransaction: IntentTransaction | null = null
335
+ const destinationIntentTransaction: IntentTransaction | null = null
370
336
 
371
337
  // Commit the intent
372
338
  const commitIntentFnToUse =
@@ -444,7 +410,7 @@ export async function handleSameChainSameToken({
444
410
  paymasterUrl,
445
411
  chain: effectiveOriginChain,
446
412
  account,
447
- firstPreconditionMin: swapAmount,
413
+ depositAmount: swapAmount,
448
414
  originIntentAddress: intent.originIntentAddress,
449
415
  onOriginSend,
450
416
  publicClient: effectivePublicClient,
@@ -464,7 +430,7 @@ export async function handleSameChainSameToken({
464
430
  depositAmountUsd,
465
431
  feeOptions: gasFeeOptions,
466
432
  trailsClient,
467
- selectedFeeToken: effectiveSelectedFeeToken,
433
+ selectedFeeOption: effectiveSelectedFeeOption,
468
434
  walletId,
469
435
  abortSignal,
470
436
  checkoutOnHandlers,
@@ -482,8 +448,187 @@ export async function handleSameChainSameToken({
482
448
  isGasless: effectiveGasless,
483
449
  })
484
450
 
485
- // For gasless flows, start polling for both deposit and origin transactions via API
486
- if (effectiveGasless && !depositUserTxnReceipt) {
451
+ // For QR code mode, we need to detect the deposit first, call executeIntent, then start polling
452
+ // For gasless flows, we can start polling immediately
453
+ if (fundMethod === "qr-code" || fundMethod === "exchange") {
454
+ logger.console.log(
455
+ "[trails-sdk] QR code mode: waiting for deposit transaction before starting polling",
456
+ )
457
+ // Use the same approach as cross-chain: check for deposit via indexer
458
+ const checkForDepositTx = async () => {
459
+ while (true) {
460
+ // Check if we should abort
461
+ if (abortSignal?.aborted) {
462
+ logger.console.log(
463
+ "[trails-sdk] Aborting deposit tx check due to abort signal",
464
+ )
465
+ return null
466
+ }
467
+
468
+ try {
469
+ if (!sequenceIndexerUrl) {
470
+ throw new Error(
471
+ "sequenceIndexerUrl is required for QR code mode",
472
+ )
473
+ }
474
+ if (!sequenceProjectAccessKey) {
475
+ throw new Error(
476
+ "sequenceProjectAccessKey is required for QR code mode",
477
+ )
478
+ }
479
+ const response = await getAccountTransactionHistory({
480
+ chainId: effectiveOriginChainId,
481
+ accountAddress: intent.originIntentAddress,
482
+ abortSignal,
483
+ apiKey: sequenceProjectAccessKey,
484
+ indexerUrl: sequenceIndexerUrl,
485
+ })
486
+ logger.console.log(
487
+ "[trails-sdk] getAccountTransactionHistory response",
488
+ response,
489
+ )
490
+ if (response.transactions.length > 0) {
491
+ const tx = response.transactions[0]
492
+ if (!tx?.txnHash) {
493
+ await new Promise((resolve) =>
494
+ setTimeout(
495
+ resolve,
496
+ POLLING_INTERVALS.TRANSACTION_HISTORY,
497
+ ),
498
+ )
499
+ continue
500
+ }
501
+ const depositTxReceipt =
502
+ await effectivePublicClient.getTransactionReceipt({
503
+ hash: tx.txnHash as `0x${string}`,
504
+ })
505
+
506
+ depositUserTxnReceipt = depositTxReceipt
507
+
508
+ localTransactionStates[0] = getTransactionStateFromReceipt(
509
+ depositTxReceipt,
510
+ effectiveOriginChainId,
511
+ localTransactionStates[0]?.label,
512
+ )
513
+ onTransactionStateChange(localTransactionStates)
514
+ if (checkoutOnHandlers?.triggerCheckoutStatusUpdate) {
515
+ checkoutOnHandlers.triggerCheckoutStatusUpdate(
516
+ localTransactionStates,
517
+ )
518
+ }
519
+
520
+ // Call executeIntent after detecting deposit transaction (for QR code mode)
521
+ // This triggers the backend to start executing the intent
522
+ // Must be called BEFORE waitIntentReceipt polling starts
523
+ if (
524
+ depositTxReceipt.status === "success" &&
525
+ intent.intentId
526
+ ) {
527
+ logger.console.log(
528
+ "[trails-sdk] Calling executeIntent with detected deposit transaction hash (QR code mode)",
529
+ {
530
+ intentId: intent.intentId,
531
+ txHash: depositTxReceipt.transactionHash,
532
+ fundMethod,
533
+ },
534
+ )
535
+ try {
536
+ const executeIntentFnToUse =
537
+ executeIntentFn ||
538
+ trailsClient.executeIntent.bind(trailsClient)
539
+ await executeIntentFnToUse({
540
+ intentId: intent.intentId,
541
+ depositTransactionHash:
542
+ depositTxReceipt.transactionHash,
543
+ })
544
+ logger.console.log(
545
+ "[trails-sdk] executeIntent completed successfully (QR code mode)",
546
+ )
547
+
548
+ // Now start polling for intent receipt
549
+ break
550
+ } catch (error) {
551
+ logger.console.error(
552
+ "[trails-sdk] Error calling executeIntent (QR code mode):",
553
+ error,
554
+ )
555
+ }
556
+ }
557
+
558
+ if (onOriginSend) {
559
+ onOriginSend()
560
+ }
561
+ break
562
+ }
563
+ } catch (error) {
564
+ logger.console.error("Error checking for deposit tx", error)
565
+ }
566
+ await new Promise((resolve) =>
567
+ setTimeout(resolve, POLLING_INTERVALS.TRANSACTION_HISTORY),
568
+ )
569
+ }
570
+ }
571
+
572
+ // Wait for deposit and executeIntent
573
+ await checkForDepositTx()
574
+
575
+ // Now start polling for intent receipt after executeIntent has been called
576
+ logger.console.log(
577
+ "[trails-sdk] Starting polling for intent receipt after executeIntent (QR code mode)",
578
+ )
579
+ try {
580
+ await pollIntentReceipt({
581
+ intentId: intent.intentId,
582
+ trailsClient,
583
+ callbacks: {
584
+ onOriginTransactionFound: async (originTxHash) => {
585
+ logger.console.log(
586
+ "[trails-sdk] Origin intent transaction discovered for same-chain QR code flow",
587
+ { originTxHash },
588
+ )
589
+
590
+ if (localTransactionStates[1]) {
591
+ try {
592
+ const originTxReceipt =
593
+ await effectivePublicClient.getTransactionReceipt({
594
+ hash: originTxHash as `0x${string}`,
595
+ })
596
+
597
+ localTransactionStates[1] =
598
+ getTransactionStateFromReceipt(
599
+ originTxReceipt,
600
+ effectiveOriginChainId,
601
+ localTransactionStates[1]?.label,
602
+ )
603
+ onTransactionStateChange(localTransactionStates)
604
+ if (checkoutOnHandlers?.triggerCheckoutStatusUpdate) {
605
+ checkoutOnHandlers.triggerCheckoutStatusUpdate(
606
+ localTransactionStates,
607
+ )
608
+ }
609
+
610
+ originIntentTransaction = {
611
+ txnHash: originTxHash,
612
+ } as IntentTransaction
613
+ } catch (error) {
614
+ logger.console.error(
615
+ "[trails-sdk] Error fetching origin transaction receipt:",
616
+ error,
617
+ )
618
+ }
619
+ }
620
+ },
621
+ },
622
+ maxWaitTime: 120000, // 120 seconds max wait
623
+ })
624
+ } catch (error) {
625
+ logger.console.error(
626
+ "[trails-sdk] Error polling for intent receipt (QR code mode):",
627
+ error,
628
+ )
629
+ }
630
+ } else if (effectiveGasless && !depositUserTxnReceipt) {
631
+ // For gasless flows (non-QR code), start polling immediately
487
632
  logger.console.log(
488
633
  "[trails-sdk] Starting unified polling for gasless same-chain transaction with 2 states",
489
634
  )
@@ -504,14 +649,6 @@ export async function handleSameChainSameToken({
504
649
  await effectivePublicClient.getTransactionReceipt({
505
650
  hash: txHash as `0x${string}`,
506
651
  })
507
- logger.console.log(
508
- "[trails-sdk] Deposit transaction receipt fetched",
509
- {
510
- txHash,
511
- blockNumber: depositTxReceipt?.blockNumber,
512
- status: depositTxReceipt?.status,
513
- },
514
- )
515
652
 
516
653
  localTransactionStates[0] =
517
654
  getTransactionStateFromReceipt(
@@ -520,12 +657,13 @@ export async function handleSameChainSameToken({
520
657
  localTransactionStates[0]?.label,
521
658
  )
522
659
  onTransactionStateChange(localTransactionStates)
523
- // Also trigger checkout status update if handler is provided
524
660
  if (checkoutOnHandlers?.triggerCheckoutStatusUpdate) {
525
661
  checkoutOnHandlers.triggerCheckoutStatusUpdate(
526
662
  localTransactionStates,
527
663
  )
528
664
  }
665
+
666
+ depositUserTxnReceipt = depositTxReceipt
529
667
  } catch (error) {
530
668
  logger.console.error(
531
669
  "[trails-sdk] Error fetching deposit transaction receipt:",
@@ -540,21 +678,12 @@ export async function handleSameChainSameToken({
540
678
  { originTxHash },
541
679
  )
542
680
 
543
- // For same-chain gasless, localTransactionStates[1] is the origin intent transaction
544
681
  if (localTransactionStates[1]) {
545
682
  try {
546
683
  const originTxReceipt =
547
684
  await effectivePublicClient.getTransactionReceipt({
548
685
  hash: originTxHash as `0x${string}`,
549
686
  })
550
- logger.console.log(
551
- "[trails-sdk] Origin transaction receipt fetched",
552
- {
553
- originTxHash,
554
- blockNumber: originTxReceipt?.blockNumber,
555
- status: originTxReceipt?.status,
556
- },
557
- )
558
687
 
559
688
  localTransactionStates[1] =
560
689
  getTransactionStateFromReceipt(
@@ -563,12 +692,15 @@ export async function handleSameChainSameToken({
563
692
  localTransactionStates[1]?.label,
564
693
  )
565
694
  onTransactionStateChange(localTransactionStates)
566
- // Also trigger checkout status update if handler is provided
567
695
  if (checkoutOnHandlers?.triggerCheckoutStatusUpdate) {
568
696
  checkoutOnHandlers.triggerCheckoutStatusUpdate(
569
697
  localTransactionStates,
570
698
  )
571
699
  }
700
+
701
+ originIntentTransaction = {
702
+ txnHash: originTxHash,
703
+ } as IntentTransaction
572
704
  } catch (error) {
573
705
  logger.console.error(
574
706
  "[trails-sdk] Error fetching origin transaction receipt:",
@@ -588,7 +720,9 @@ export async function handleSameChainSameToken({
588
720
  }
589
721
  }
590
722
 
591
- if (depositUserTxnReceipt) {
723
+ // For non-gasless flows, update the transaction state with the deposit receipt
724
+ // For gasless flows, skip this as localTransactionStates is already maintained by polling
725
+ if (depositUserTxnReceipt && !effectiveGasless) {
592
726
  try {
593
727
  const updatedStates = [
594
728
  getTransactionStateFromReceipt(
@@ -718,8 +852,8 @@ export async function handleSameChainSameToken({
718
852
 
719
853
  return {
720
854
  depositUserTxnReceipt,
721
- originMetaTxnReceipt,
722
- destinationMetaTxnReceipt,
855
+ originIntentTransaction,
856
+ destinationIntentTransaction,
723
857
  totalCompletionSeconds: 0,
724
858
  }
725
859
  } catch (error) {
@@ -2,10 +2,10 @@ import type { Intent } from "@0xsequence/trails-api"
2
2
  import type { TransactionState } from "../../transactions.js"
3
3
  import type { PrepareSendQuote, PrepareSendFees } from "../types.js"
4
4
  import type { QuoteProviderInfo } from "../../widget/hooks/useQuote.js"
5
- import { createPublicClient, formatUnits, http } from "viem"
5
+ import { formatUnits } from "viem"
6
6
  import { mainnet } from "viem/chains"
7
7
  import { getTokenInfo } from "../../tokens.js"
8
- import { getChainInfo } from "../../chains.js"
8
+ import { getChainInfo, getPublicRpcClient } from "../../chains.js"
9
9
  import { logger } from "../../logger.js"
10
10
  import {
11
11
  formatRawAmount,
@@ -186,10 +186,7 @@ export async function getNormalizedQuoteObject({
186
186
 
187
187
  const hasCustomCalldata = getIsCustomCalldata(destinationCalldata)
188
188
 
189
- const publicClient = createPublicClient({
190
- chain: originChain,
191
- transport: http(),
192
- })
189
+ const publicClient = getPublicRpcClient(originChain)
193
190
 
194
191
  let gasCostUsd: number = 0
195
192
  let gasCostUsdDisplay: string = "0"
@@ -291,6 +288,7 @@ export async function getNormalizedQuoteObject({
291
288
  destinationDepositAddress: destinationDepositAddress || "",
292
289
  destinationAddress: destinationAddress || "",
293
290
  destinationCalldata: hasCustomCalldata ? destinationCalldata || "" : "",
291
+ intentId: intent?.intentId ?? null,
294
292
  originAmount: originAmount || "0",
295
293
  originAmountMin: originAmountMin || originAmount || "0",
296
294
  originAmountMinUsdFormatted: originAmountMinUsdFormatted || "0",
@@ -1,8 +1,15 @@
1
1
  import type { QuoteIntentRequest } from "@0xsequence/trails-api"
2
+ import type { Connector } from "wagmi"
2
3
  import { getIsCustomCalldata } from "../../contractUtils.js"
4
+ import {
5
+ isSequenceWallet,
6
+ isSequenceWalletById,
7
+ isSmartContractWallet,
8
+ } from "../../walletUtils.js"
3
9
  import type { TradeType } from "../types.js"
10
+ import { logger } from "../../logger.js"
4
11
 
5
- export function getIntentArgs(
12
+ export async function getIntentArgs(
6
13
  mainSignerAddress: string,
7
14
  originChainId: number,
8
15
  originTokenAddress: string,
@@ -16,7 +23,9 @@ export function getIntentArgs(
16
23
  slippageTolerance: string, // 0.03 = 3%
17
24
  tradeType: TradeType,
18
25
  provider?: string | null,
19
- ): QuoteIntentRequest {
26
+ connector?: Connector | undefined,
27
+ walletId?: string | undefined,
28
+ ): Promise<QuoteIntentRequest> {
20
29
  const hasCustomCalldata = getIsCustomCalldata(destinationCalldata)
21
30
 
22
31
  let effectiveProvider = provider
@@ -24,6 +33,28 @@ export function getIntentArgs(
24
33
  effectiveProvider = undefined
25
34
  }
26
35
 
36
+ // Check if wallet is Sequence wallet (via connector or walletId)
37
+ const isSequence = connector
38
+ ? isSequenceWallet(connector)
39
+ : isSequenceWalletById(walletId)
40
+
41
+ // Check if wallet is smart contract wallet
42
+ const isSmartContract = await isSmartContractWallet(
43
+ mainSignerAddress,
44
+ originChainId,
45
+ )
46
+
47
+ // Set onlyNativeGasFee to true if wallet is Sequence or smart contract
48
+ const onlyNativeGasFee = isSequence || isSmartContract
49
+
50
+ logger.console.log("[trails-sdk] Wallet check for onlyNativeGasFee:", {
51
+ isSequence,
52
+ isSmartContract,
53
+ onlyNativeGasFee,
54
+ walletId,
55
+ connectorName: connector?.name,
56
+ })
57
+
27
58
  const intentArgs: QuoteIntentRequest = {
28
59
  ownerAddress: mainSignerAddress,
29
60
  originChainId,
@@ -34,7 +65,8 @@ export function getIntentArgs(
34
65
  destinationTokenAddress: destinationTokenAddress,
35
66
  destinationTokenAmount: BigInt(destinationTokenAmount),
36
67
  destinationCallData: hasCustomCalldata ? destinationCalldata : "0x",
37
- destinationCallValue: "0",
68
+ destinationCallValue: BigInt("0"),
69
+ onlyNativeGasFee,
38
70
  options: {
39
71
  slippageTolerance: Number(slippageTolerance),
40
72
  quoteProvider: effectiveProvider || undefined,
@@ -15,28 +15,6 @@ import type { QuoteProviderInfo } from "../widget/hooks/useQuote.js"
15
15
  import type { TrailsFeeBreakdown } from "../fees.js"
16
16
  import type { IntentTransaction } from "@0xsequence/trails-api"
17
17
 
18
- // Use native IntentTransaction from trails-api instead of deprecated MetaTxnReceipt
19
- export type MetaTxnReceipt = IntentTransaction
20
-
21
- // Flexible fee token type that accepts both full FeeOption and minimal fee token objects
22
- // Also accepts objects with amountUSD for widget components
23
- export type SelectedFeeToken =
24
- | FeeOption
25
- | {
26
- tokenAddress: string
27
- tokenSymbol?: string
28
- }
29
- | {
30
- tokenAddress: string
31
- tokenSymbol: string
32
- tokenDecimals: number
33
- amount: string
34
- amountUSD: number
35
- notEnoughBalance?: boolean
36
- tokenImageUrl?: string
37
- chainId?: number
38
- }
39
-
40
18
  export enum TradeType {
41
19
  EXACT_INPUT = "EXACT_INPUT",
42
20
  EXACT_OUTPUT = "EXACT_OUTPUT",
@@ -75,7 +53,7 @@ export type PrepareSendOptions = {
75
53
  mode?: "pay" | "fund" | "earn" | "swap" | "receive"
76
54
  checkoutOnHandlers?: Partial<CheckoutOnHandlers>
77
55
  refundAddress?: string
78
- selectedFeeToken?: SelectedFeeToken
56
+ selectedFeeOption?: FeeOption | null
79
57
  walletId?: string
80
58
  abortSignal?: AbortSignal
81
59
  // Optional mutation callbacks for React Query integration
@@ -99,6 +77,7 @@ export type PrepareSendQuote = {
99
77
  destinationDepositAddress: string
100
78
  destinationAddress: string
101
79
  destinationCalldata: string
80
+ intentId?: string | null
102
81
  originChain: Chain
103
82
  destinationChain: Chain
104
83
  originAmount: string
@@ -143,16 +122,16 @@ export type PrepareSendReturn = {
143
122
  feeOptions?: GasFeeOptions
144
123
  send: ({
145
124
  onOriginSend,
146
- selectedFeeToken,
125
+ selectedFeeOption,
147
126
  }: {
148
127
  onOriginSend?: () => void
149
- selectedFeeToken?: SelectedFeeToken
128
+ selectedFeeOption?: FeeOption | null
150
129
  }) => Promise<SendReturn>
151
130
  }
152
131
 
153
132
  export type SendReturn = {
154
133
  depositUserTxnReceipt: TransactionReceipt | null
155
- originMetaTxnReceipt: MetaTxnReceipt | null
156
- destinationMetaTxnReceipt: MetaTxnReceipt | null
134
+ originIntentTransaction: IntentTransaction | null
135
+ destinationIntentTransaction: IntentTransaction | null
157
136
  totalCompletionSeconds?: number
158
137
  }
@@ -1,3 +1,2 @@
1
1
  export * from "./testnetHelpers.js"
2
2
  export * from "./balanceChecker.js"
3
- export * from "./lifiHelpers.js"