0xtrails 0.1.13 → 0.2.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 (216) hide show
  1. package/dist/aave.d.ts.map +1 -1
  2. package/dist/analytics.d.ts +11 -2
  3. package/dist/analytics.d.ts.map +1 -1
  4. package/dist/apiClient.d.ts +1 -1
  5. package/dist/apiClient.d.ts.map +1 -1
  6. package/dist/{proxyCaller.d.ts → balanceInjector.d.ts} +5 -4
  7. package/dist/balanceInjector.d.ts.map +1 -0
  8. package/dist/{ccip-D3gTQONK.js → ccip-D6ToCrWc.js} +12 -12
  9. package/dist/cctp.d.ts.map +1 -1
  10. package/dist/cctpqueue.d.ts +3 -3
  11. package/dist/cctpqueue.d.ts.map +1 -1
  12. package/dist/chains.d.ts.map +1 -1
  13. package/dist/config.d.ts +17 -3
  14. package/dist/config.d.ts.map +1 -1
  15. package/dist/constants.d.ts +5 -4
  16. package/dist/constants.d.ts.map +1 -1
  17. package/dist/contractUtils.d.ts +2 -0
  18. package/dist/contractUtils.d.ts.map +1 -1
  19. package/dist/customChains.d.ts +24 -0
  20. package/dist/customChains.d.ts.map +1 -0
  21. package/dist/{index-CnUM7lKf.js → index-BqgeTLL8.js} +34072 -30146
  22. package/dist/index.d.ts +5 -3
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +411 -400
  25. package/dist/intentEntrypoint.d.ts +96 -0
  26. package/dist/intentEntrypoint.d.ts.map +1 -0
  27. package/dist/intents.d.ts +5 -3
  28. package/dist/intents.d.ts.map +1 -1
  29. package/dist/metaTxnMonitor.d.ts.map +1 -1
  30. package/dist/morpho.d.ts.map +1 -1
  31. package/dist/pools.d.ts +3 -1
  32. package/dist/pools.d.ts.map +1 -1
  33. package/dist/prepareSend.d.ts +8 -2
  34. package/dist/prepareSend.d.ts.map +1 -1
  35. package/dist/prices.d.ts +1 -1
  36. package/dist/prices.d.ts.map +1 -1
  37. package/dist/relaySdk.d.ts.map +1 -1
  38. package/dist/relayer.d.ts.map +1 -1
  39. package/dist/toast.d.ts +9 -0
  40. package/dist/toast.d.ts.map +1 -0
  41. package/dist/tokenBalances.d.ts +6 -2
  42. package/dist/tokenBalances.d.ts.map +1 -1
  43. package/dist/tokens.d.ts.map +1 -1
  44. package/dist/trails.d.ts +6 -5
  45. package/dist/trails.d.ts.map +1 -1
  46. package/dist/trailsClient.d.ts +12 -0
  47. package/dist/trailsClient.d.ts.map +1 -0
  48. package/dist/transactions.d.ts +8 -0
  49. package/dist/transactions.d.ts.map +1 -1
  50. package/dist/wallets.d.ts.map +1 -1
  51. package/dist/widget/components/AccountActionsDropdown.d.ts.map +1 -1
  52. package/dist/widget/components/AccountIntentTransactionHistory.d.ts.map +1 -1
  53. package/dist/widget/components/AccountSettings.d.ts +7 -0
  54. package/dist/widget/components/AccountSettings.d.ts.map +1 -0
  55. package/dist/widget/components/ChainList.d.ts +0 -1
  56. package/dist/widget/components/ChainList.d.ts.map +1 -1
  57. package/dist/widget/components/ClassicSwap.d.ts +46 -0
  58. package/dist/widget/components/ClassicSwap.d.ts.map +1 -0
  59. package/dist/widget/components/ConfigDisplay.d.ts.map +1 -1
  60. package/dist/widget/components/ConnectedWallets.d.ts +9 -0
  61. package/dist/widget/components/ConnectedWallets.d.ts.map +1 -0
  62. package/dist/widget/components/DebugMenu.d.ts.map +1 -1
  63. package/dist/widget/components/DebugScreensList.d.ts.map +1 -1
  64. package/dist/widget/components/DebugToast.d.ts +3 -0
  65. package/dist/widget/components/DebugToast.d.ts.map +1 -0
  66. package/dist/widget/components/Earn.d.ts.map +1 -1
  67. package/dist/widget/components/EarnPools.d.ts.map +1 -1
  68. package/dist/widget/components/Fund.d.ts +44 -0
  69. package/dist/widget/components/Fund.d.ts.map +1 -0
  70. package/dist/widget/components/Identicon.d.ts +9 -0
  71. package/dist/widget/components/Identicon.d.ts.map +1 -0
  72. package/dist/widget/components/Pay.d.ts +46 -0
  73. package/dist/widget/components/Pay.d.ts.map +1 -0
  74. package/dist/widget/components/Receive.d.ts.map +1 -1
  75. package/dist/widget/components/RecentTokens.d.ts.map +1 -1
  76. package/dist/widget/components/Recipients.d.ts +9 -0
  77. package/dist/widget/components/Recipients.d.ts.map +1 -0
  78. package/dist/widget/components/RefundWarning.d.ts +9 -0
  79. package/dist/widget/components/RefundWarning.d.ts.map +1 -0
  80. package/dist/widget/components/SimpleSwap.d.ts.map +1 -1
  81. package/dist/widget/components/Swap.d.ts.map +1 -1
  82. package/dist/widget/components/SwapSettings.d.ts +1 -5
  83. package/dist/widget/components/SwapSettings.d.ts.map +1 -1
  84. package/dist/widget/components/ThemeProvider.d.ts.map +1 -1
  85. package/dist/widget/components/ThemeSyncer.d.ts +6 -0
  86. package/dist/widget/components/ThemeSyncer.d.ts.map +1 -0
  87. package/dist/widget/components/Toast.d.ts +24 -0
  88. package/dist/widget/components/Toast.d.ts.map +1 -0
  89. package/dist/widget/components/TokenList.d.ts.map +1 -1
  90. package/dist/widget/components/TransactionDetails.d.ts.map +1 -1
  91. package/dist/widget/components/TruncatedAddress.d.ts +2 -0
  92. package/dist/widget/components/TruncatedAddress.d.ts.map +1 -1
  93. package/dist/widget/components/UserPreferences.d.ts +7 -0
  94. package/dist/widget/components/UserPreferences.d.ts.map +1 -0
  95. package/dist/widget/hooks/useBalanceVisible.d.ts +1 -0
  96. package/dist/widget/hooks/useBalanceVisible.d.ts.map +1 -1
  97. package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
  98. package/dist/widget/hooks/useCurrentScreen.d.ts +1 -1
  99. package/dist/widget/hooks/useCurrentScreen.d.ts.map +1 -1
  100. package/dist/widget/hooks/useDebugScreens.d.ts +1 -1
  101. package/dist/widget/hooks/useDebugScreens.d.ts.map +1 -1
  102. package/dist/widget/hooks/useDefaultTokenSelection.d.ts +54 -0
  103. package/dist/widget/hooks/useDefaultTokenSelection.d.ts.map +1 -0
  104. package/dist/widget/hooks/useIntentTransactionHistory.d.ts.map +1 -1
  105. package/dist/widget/hooks/usePayMessage.d.ts +34 -0
  106. package/dist/widget/hooks/usePayMessage.d.ts.map +1 -0
  107. package/dist/widget/hooks/useRecipients.d.ts +17 -0
  108. package/dist/widget/hooks/useRecipients.d.ts.map +1 -0
  109. package/dist/widget/hooks/useSelectedRecipient.d.ts +12 -0
  110. package/dist/widget/hooks/useSelectedRecipient.d.ts.map +1 -0
  111. package/dist/widget/hooks/useSendForm.d.ts +2 -0
  112. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  113. package/dist/widget/hooks/useSwapAmount.d.ts +13 -0
  114. package/dist/widget/hooks/useSwapAmount.d.ts.map +1 -0
  115. package/dist/widget/hooks/useSwapSettings.d.ts +16 -0
  116. package/dist/widget/hooks/useSwapSettings.d.ts.map +1 -0
  117. package/dist/widget/hooks/useTargetAmount.d.ts +5 -0
  118. package/dist/widget/hooks/useTargetAmount.d.ts.map +1 -0
  119. package/dist/widget/hooks/useTheme.d.ts +14 -0
  120. package/dist/widget/hooks/useTheme.d.ts.map +1 -0
  121. package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
  122. package/dist/widget/index.js +2 -2
  123. package/dist/widget/widget.d.ts +9 -0
  124. package/dist/widget/widget.d.ts.map +1 -1
  125. package/package.json +29 -28
  126. package/src/aave.ts +6 -1
  127. package/src/analytics.ts +103 -53
  128. package/src/apiClient.ts +1 -1
  129. package/src/{proxyCaller.ts → balanceInjector.ts} +22 -17
  130. package/src/cctp.ts +6 -2
  131. package/src/cctpqueue.ts +7 -7
  132. package/src/chains.ts +8 -0
  133. package/src/config.ts +40 -9
  134. package/src/constants.ts +11 -8
  135. package/src/contractUtils.ts +33 -2
  136. package/src/customChains.ts +24 -0
  137. package/src/index.ts +11 -1
  138. package/src/intentEntrypoint.ts +253 -0
  139. package/src/intents.ts +87 -54
  140. package/src/metaTxnMonitor.ts +1 -0
  141. package/src/morpho.ts +13 -2
  142. package/src/pools.ts +68 -86
  143. package/src/prepareSend.ts +437 -207
  144. package/src/prices.ts +51 -7
  145. package/src/relaySdk.ts +6 -4
  146. package/src/relayer.ts +2 -0
  147. package/src/toast.ts +110 -0
  148. package/src/tokenBalances.ts +112 -20
  149. package/src/tokens.ts +70 -7
  150. package/src/trails.ts +80 -77
  151. package/src/trailsClient.ts +45 -0
  152. package/src/transactions.ts +27 -35
  153. package/src/umd.tsx +1 -1
  154. package/src/wallets.ts +2 -1
  155. package/src/widget/assets/sequence-logo.svg +15 -0
  156. package/src/widget/compiled.css +2 -2
  157. package/src/widget/components/AccountActionsDropdown.tsx +18 -159
  158. package/src/widget/components/AccountIntentTransactionHistory.tsx +346 -63
  159. package/src/widget/components/AccountSettings.tsx +96 -0
  160. package/src/widget/components/ChainFilterDropdown.tsx +1 -1
  161. package/src/widget/components/ChainList.tsx +10 -20
  162. package/src/widget/components/ClassicSwap.tsx +923 -0
  163. package/src/widget/components/ConfigDisplay.tsx +8 -5
  164. package/src/widget/components/ConnectedWallets.tsx +260 -0
  165. package/src/widget/components/DebugMenu.tsx +2 -0
  166. package/src/widget/components/DebugScreensList.tsx +3 -0
  167. package/src/widget/components/DebugToast.tsx +63 -0
  168. package/src/widget/components/Earn.tsx +108 -116
  169. package/src/widget/components/EarnPools.tsx +2 -4
  170. package/src/widget/components/EarnPoolsFilters.tsx +6 -6
  171. package/src/widget/components/Fund.tsx +1245 -0
  172. package/src/widget/components/FundMethods.tsx +1 -1
  173. package/src/widget/components/FundSendForm.tsx +1 -1
  174. package/src/widget/components/Identicon.tsx +158 -0
  175. package/src/widget/components/Pay.tsx +1088 -0
  176. package/src/widget/components/PaySendForm.tsx +1 -1
  177. package/src/widget/components/QuoteDetails.tsx +1 -1
  178. package/src/widget/components/Receipt.tsx +1 -1
  179. package/src/widget/components/Receive.tsx +4 -2
  180. package/src/widget/components/RecentTokens.tsx +2 -1
  181. package/src/widget/components/Recipients.tsx +448 -0
  182. package/src/widget/components/RefundWarning.tsx +61 -0
  183. package/src/widget/components/ScreenHeader.tsx +1 -1
  184. package/src/widget/components/SimpleSwap.tsx +74 -58
  185. package/src/widget/components/Swap.tsx +35 -853
  186. package/src/widget/components/SwapSettings.tsx +5 -11
  187. package/src/widget/components/ThemeProvider.tsx +32 -0
  188. package/src/widget/components/ThemeSyncer.tsx +47 -0
  189. package/src/widget/components/Toast.tsx +315 -0
  190. package/src/widget/components/TokenList.tsx +2 -34
  191. package/src/widget/components/TokenSelector.tsx +3 -3
  192. package/src/widget/components/TransactionDetails.tsx +153 -13
  193. package/src/widget/components/TruncatedAddress.tsx +5 -1
  194. package/src/widget/components/UserPreferences.tsx +156 -0
  195. package/src/widget/components/WalletList.tsx +1 -1
  196. package/src/widget/hooks/useBalanceVisible.tsx +40 -2
  197. package/src/widget/hooks/useCheckout.ts +13 -0
  198. package/src/widget/hooks/useCurrentScreen.tsx +3 -0
  199. package/src/widget/hooks/useDebugScreens.ts +12 -2
  200. package/src/widget/hooks/useDefaultTokenSelection.tsx +475 -0
  201. package/src/widget/hooks/useIntentTransactionHistory.ts +212 -0
  202. package/src/widget/hooks/usePayMessage.tsx +370 -0
  203. package/src/widget/hooks/useRecipients.ts +168 -0
  204. package/src/widget/hooks/useSelectedRecipient.tsx +48 -0
  205. package/src/widget/hooks/useSendForm.ts +179 -26
  206. package/src/widget/hooks/useSwapAmount.tsx +50 -0
  207. package/src/widget/hooks/useSwapSettings.tsx +100 -0
  208. package/src/widget/hooks/useTargetAmount.ts +23 -0
  209. package/src/widget/hooks/useTheme.tsx +80 -0
  210. package/src/widget/hooks/useTokenList.ts +20 -11
  211. package/src/widget/index.css +45 -21
  212. package/src/widget/widget.tsx +164 -68
  213. package/dist/address.d.ts +0 -2
  214. package/dist/address.d.ts.map +0 -1
  215. package/dist/proxyCaller.d.ts.map +0 -1
  216. package/src/address.ts +0 -6
@@ -1,9 +1,9 @@
1
1
  import type {
2
- GetIntentCallsPayloadsArgs,
2
+ GetIntentCallsPayloadParams,
3
3
  GetIntentCallsPayloadsReturn,
4
4
  IntentPrecondition,
5
- SequenceAPIClient,
6
5
  } from "@0xsequence/trails-api"
6
+ import type { TrailsAPIClient } from "@0xsequence/trails-api"
7
7
  import type { Relayer } from "@0xsequence/wallet-core"
8
8
  import { useQuery } from "@tanstack/react-query"
9
9
  import type {
@@ -51,11 +51,7 @@ import {
51
51
  import { queueCCTPTransfer } from "./cctpqueue.js"
52
52
  import { getChainInfo, getTestnetChainInfo } from "./chains.js"
53
53
  import { attemptSwitchChain } from "./chainSwitch.js"
54
- import {
55
- getSameChainSwapDifferentIntentAddresses,
56
- getSequenceEnv,
57
- getSlippageTolerance,
58
- } from "./config.js"
54
+ import { getSequenceEnv, getSlippageTolerance } from "./config.js"
59
55
  import { intentEntrypoints, MINIMUM_USD_AMOUNT_FOR_SWAP } from "./constants.js"
60
56
  import {
61
57
  decodeGuestModuleEvents,
@@ -66,9 +62,10 @@ import { InsufficientBalanceError } from "./error.js"
66
62
  import { estimateGasCostUsd } from "./estimate.js"
67
63
  import { getExplorerUrl } from "./explorer.js"
68
64
  import {
69
- getDepositToIntentCalls,
65
+ getNeedsIntentEntrypointApproval,
70
66
  getPermitCalls,
71
67
  getPermitSignature,
68
+ signIntent,
72
69
  } from "./gasless.js"
73
70
  import { useIndexerGatewayClient } from "./indexerClient.js"
74
71
  import {
@@ -89,8 +86,8 @@ import { findFirstPreconditionForChainId } from "./preconditions.js"
89
86
  import { calcAmountUsdPrice, getTokenPrice } from "./prices.js"
90
87
  import {
91
88
  TRAILS_CONTRACT_PLACEHOLDER_AMOUNT,
92
- wrapCalldataWithProxyCallerIfNeeded,
93
- } from "./proxyCaller.js"
89
+ wrapCalldataWithBalanceInjectorIfNeeded,
90
+ } from "./balanceInjector.js"
94
91
  import { getQueryParam } from "./queryParams.js"
95
92
  import type { MetaTxnReceipt, RelayerEnv } from "./relayer.js"
96
93
  import { useRelayers } from "./relayer.js"
@@ -127,6 +124,9 @@ import { requestWithTimeout } from "./utils.js"
127
124
  import type { CheckoutOnHandlers } from "./widget/hooks/useCheckout.js"
128
125
  import { logger } from "./logger.js"
129
126
  import { getIsCustomCalldata } from "./contractUtils.js"
127
+ import type { SequenceAPIClient } from "@0xsequence/api"
128
+ import { useTrailsClient } from "./trailsClient.js"
129
+ import { updatePersistentToast } from "./toast.js"
130
130
 
131
131
  export enum TradeType {
132
132
  EXACT_INPUT = "EXACT_INPUT",
@@ -150,6 +150,7 @@ export type PrepareSendOptions = {
150
150
  client?: WalletClient
151
151
  dryMode: boolean
152
152
  apiClient: SequenceAPIClient
153
+ trailsClient: TrailsAPIClient
153
154
  originRelayer: Relayer.Standard.Rpc.RpcRelayer
154
155
  destinationRelayer: Relayer.Standard.Rpc.RpcRelayer
155
156
  destinationCalldata?: string
@@ -316,7 +317,7 @@ function getIntentArgs(
316
317
  slippageTolerance: string, // 0.03 = 3%
317
318
  tradeType: TradeType,
318
319
  provider?: string | null,
319
- ): GetIntentCallsPayloadsArgs {
320
+ ): GetIntentCallsPayloadParams {
320
321
  const hasCustomCalldata = getIsCustomCalldata(destinationCalldata)
321
322
 
322
323
  if (!provider || provider === "auto") {
@@ -363,6 +364,7 @@ export async function prepareSend(
363
364
  client: walletClient,
364
365
  dryMode = false,
365
366
  apiClient,
367
+ trailsClient,
366
368
  originRelayer,
367
369
  destinationRelayer,
368
370
  destinationCalldata,
@@ -380,10 +382,22 @@ export async function prepareSend(
380
382
  } = options
381
383
  let { sourceTokenPriceUsd, destinationTokenPriceUsd } = options
382
384
 
385
+ if (!sourceTokenDecimals) {
386
+ throw new Error("Source token decimals not provided")
387
+ }
388
+ if (!destinationTokenDecimals) {
389
+ throw new Error("Destination token decimals not provided")
390
+ }
391
+
383
392
  let hasCustomCalldata = getIsCustomCalldata(destinationCalldata)
384
393
  const mainSignerAddress = account.address
385
394
  const transactionStates: TransactionState[] = []
386
395
 
396
+ // Validate recipient is not zero address
397
+ if (recipient === zeroAddress) {
398
+ throw new Error("Recipient address cannot be zero address")
399
+ }
400
+
387
401
  // Validate CCTP destination token requirement
388
402
  validateCctpDestinationToken(
389
403
  destinationTokenAddress,
@@ -394,7 +408,11 @@ export async function prepareSend(
394
408
  let effectiveDestinationAddress = recipient
395
409
  let effectiveDestinationCalldata = destinationCalldata
396
410
 
397
- if (!hasCustomCalldata && tradeType === TradeType.EXACT_INPUT) {
411
+ if (
412
+ !hasCustomCalldata &&
413
+ tradeType === TradeType.EXACT_INPUT &&
414
+ destinationTokenAddress !== zeroAddress
415
+ ) {
398
416
  // we need to set custom calldata for the cctp transfer in order to have destination intent adddress execution needed for metatxn tracking
399
417
  effectiveDestinationCalldata = getERC20TransferData({
400
418
  recipient,
@@ -404,12 +422,8 @@ export async function prepareSend(
404
422
  hasCustomCalldata = true
405
423
  }
406
424
 
407
- if (
408
- hasCustomCalldata &&
409
- destinationTokenAddress !== zeroAddress &&
410
- tradeType === TradeType.EXACT_INPUT
411
- ) {
412
- const wrapResult = wrapCalldataWithProxyCallerIfNeeded({
425
+ if (hasCustomCalldata && tradeType === TradeType.EXACT_INPUT) {
426
+ const wrapResult = wrapCalldataWithBalanceInjectorIfNeeded({
413
427
  token: destinationTokenAddress,
414
428
  target: effectiveDestinationAddress,
415
429
  calldata: effectiveDestinationCalldata as `0x${string}`,
@@ -421,7 +435,7 @@ export async function prepareSend(
421
435
  })
422
436
 
423
437
  if (wrapResult) {
424
- effectiveDestinationAddress = wrapResult.proxyCallerAddress
438
+ effectiveDestinationAddress = wrapResult.balanceInjectorAddress
425
439
  effectiveDestinationCalldata = wrapResult.encodedCalldata
426
440
  }
427
441
  }
@@ -562,13 +576,7 @@ export async function prepareSend(
562
576
  })
563
577
 
564
578
  // additional execute tx on same chain if needed
565
- if (
566
- isToSameChain &&
567
- hasCustomCalldata &&
568
- !isToSameToken &&
569
- // TODO: remove this once it's stable https://github.com/0xsequence/stack/pull/1273
570
- getSameChainSwapDifferentIntentAddresses()
571
- ) {
579
+ if (isToSameChain && hasCustomCalldata && !isToSameToken) {
572
580
  transactionStates.push({
573
581
  transactionHash: "",
574
582
  explorerUrl: "",
@@ -654,6 +662,7 @@ export async function prepareSend(
654
662
  recipient: effectiveDestinationAddress,
655
663
  destinationCalldata: effectiveDestinationCalldata,
656
664
  apiClient,
665
+ trailsClient,
657
666
  sourceTokenPriceUsd,
658
667
  destinationTokenPriceUsd,
659
668
  sourceTokenDecimals,
@@ -692,7 +701,7 @@ async function sendHandlerForDifferentChainDifferentToken({
692
701
  destinationTokenSymbol,
693
702
  recipient,
694
703
  destinationCalldata,
695
- apiClient,
704
+ trailsClient,
696
705
  sourceTokenPriceUsd,
697
706
  destinationTokenPriceUsd,
698
707
  sourceTokenDecimals,
@@ -729,6 +738,7 @@ async function sendHandlerForDifferentChainDifferentToken({
729
738
  recipient: string
730
739
  destinationCalldata?: string
731
740
  apiClient: SequenceAPIClient
741
+ trailsClient: TrailsAPIClient
732
742
  sourceTokenPriceUsd?: number | null
733
743
  destinationTokenPriceUsd?: number | null
734
744
  sourceTokenDecimals: number
@@ -993,8 +1003,10 @@ async function sendHandlerForDifferentChainDifferentToken({
993
1003
  logger.console.log("[trails-sdk] Creating intent with args:", intentArgs)
994
1004
 
995
1005
  const intent = await getIntentCallsPayloadsFromIntents(
996
- apiClient,
997
- intentArgs,
1006
+ trailsClient,
1007
+ {
1008
+ params: intentArgs,
1009
+ },
998
1010
  {
999
1011
  originTokenSymbol,
1000
1012
  destinationTokenSymbol,
@@ -1003,18 +1015,21 @@ async function sendHandlerForDifferentChainDifferentToken({
1003
1015
  )
1004
1016
  logger.console.log("[trails-sdk] Got intent:", intent)
1005
1017
 
1006
- if (!intent.preconditions?.length || !intent.calls?.length) {
1018
+ if (
1019
+ !intent.payloads.preconditions?.length ||
1020
+ !intent.payloads.calls?.length
1021
+ ) {
1007
1022
  throw new Error("Invalid intent")
1008
1023
  }
1009
1024
 
1010
- const originIntentAddress = intent.originIntentAddress
1025
+ const originIntentAddress = intent.payloads.originIntentAddress
1011
1026
  logger.console.log(
1012
1027
  "[trails-sdk] origin intent address:",
1013
1028
  originIntentAddress.toString(),
1014
1029
  )
1015
1030
 
1016
1031
  const firstPrecondition = findFirstPreconditionForChainId(
1017
- intent.preconditions,
1032
+ intent.payloads.preconditions,
1018
1033
  originChainId,
1019
1034
  )
1020
1035
 
@@ -1025,8 +1040,8 @@ async function sendHandlerForDifferentChainDifferentToken({
1025
1040
  const firstPreconditionMin = firstPrecondition?.data?.min?.toString()
1026
1041
  const depositAmount = firstPreconditionMin
1027
1042
 
1028
- const quoteToAmount = intent.quote.toAmount
1029
- const quoteToAmountMin = intent.quote.toAmountMin
1043
+ const quoteToAmount = intent.payloads.quote.toAmount
1044
+ const quoteToAmountMin = intent.payloads.quote.toAmountMin
1030
1045
 
1031
1046
  const originSendAmountFormatted = formatRawAmount(
1032
1047
  depositAmount,
@@ -1091,7 +1106,7 @@ async function sendHandlerForDifferentChainDifferentToken({
1091
1106
 
1092
1107
  const quote = await getNormalizedQuoteObject({
1093
1108
  originDepositAddress: originIntentAddress,
1094
- destinationDepositAddress: intent.destinationIntentAddress,
1109
+ destinationDepositAddress: intent.payloads.destinationIntentAddress,
1095
1110
  destinationAddress: recipient,
1096
1111
  destinationCalldata,
1097
1112
  originAmount: depositAmount,
@@ -1114,7 +1129,7 @@ async function sendHandlerForDifferentChainDifferentToken({
1114
1129
  priceImpactUsd: getPriceImpactUsdFromIntent(intent),
1115
1130
  transactionStates,
1116
1131
  originNativeTokenPriceUsd,
1117
- quoteProvider: intent?.quote?.quoteProvider,
1132
+ quoteProvider: intent.payloads?.quote?.quoteProvider,
1118
1133
  noSufficientBalance,
1119
1134
  minimumNotMet,
1120
1135
  })
@@ -1161,10 +1176,10 @@ async function sendHandlerForDifferentChainDifferentToken({
1161
1176
  feeTokenAddress?: string | null
1162
1177
  }): Promise<SendReturn> => {
1163
1178
  await commitIntentConfig(
1164
- apiClient,
1179
+ trailsClient,
1165
1180
  mainSignerAddress,
1166
- intent.calls,
1167
- intent.preconditions,
1181
+ intent.payloads.calls,
1182
+ intent.payloads.preconditions,
1168
1183
  {
1169
1184
  originTokenSymbol,
1170
1185
  destinationTokenSymbol,
@@ -1291,6 +1306,7 @@ async function sendHandlerForDifferentChainDifferentToken({
1291
1306
  originTokenSymbol,
1292
1307
  destinationTokenSymbol,
1293
1308
  depositAmountUsd,
1309
+ trailsClient,
1294
1310
  })
1295
1311
 
1296
1312
  if (!originUserTxReceipt) {
@@ -1303,6 +1319,15 @@ async function sendHandlerForDifferentChainDifferentToken({
1303
1319
  transactionStates[0]?.label,
1304
1320
  )
1305
1321
  onTransactionStateChange(transactionStates)
1322
+
1323
+ setTimeout(() => {
1324
+ const destinationChain = getChainInfo(destinationChainId)
1325
+ updatePersistentToast(
1326
+ "In Progress",
1327
+ `Your transaction to ${destinationChain?.name || "chain"} is in progress`,
1328
+ "info",
1329
+ )
1330
+ }, 1000)
1306
1331
  }
1307
1332
 
1308
1333
  const checkForDepositTx = async () => {
@@ -1361,8 +1386,8 @@ async function sendHandlerForDifferentChainDifferentToken({
1361
1386
  try {
1362
1387
  const response = await getAccountTransactionHistory({
1363
1388
  chainId: destinationChainId,
1364
- accountAddress:
1365
- intent.destinationIntentAddress as `0x${string}`,
1389
+ accountAddress: intent.payloads
1390
+ .destinationIntentAddress as `0x${string}`,
1366
1391
  })
1367
1392
  logger.console.log(
1368
1393
  "[trails-sdk] getAccountTransactionHistory response",
@@ -1414,16 +1439,16 @@ async function sendHandlerForDifferentChainDifferentToken({
1414
1439
  // First phase: Send meta transactions and queue CCTP
1415
1440
  const originSendMetaTxnPromise = async () => {
1416
1441
  logger.console.log("[trails-sdk] Starting originSendMetaTxnPromise", {
1417
- hasMetaTxn: !!intent.metaTxns[0],
1418
- hasPrecondition: !!intent.preconditions[0],
1419
- metaTxnId: intent.metaTxns[0]?.id,
1420
- chainId: intent.metaTxns[0]?.chainId,
1442
+ hasMetaTxn: !!intent.payloads.metaTxns[0],
1443
+ hasPrecondition: !!intent.payloads.preconditions[0],
1444
+ metaTxnId: intent.payloads.metaTxns[0]?.id,
1445
+ chainId: intent.payloads.metaTxns[0]?.chainId,
1421
1446
  })
1422
1447
 
1423
- if (intent.metaTxns[0] && intent.preconditions[0]) {
1448
+ if (intent.payloads.metaTxns[0] && intent.payloads.preconditions[0]) {
1424
1449
  // Extract fee quote from intent response using metatxnid as key
1425
- const metaTxnId = intent.metaTxns[0].id
1426
- const feeQuote = intent.feeQuotes?.[metaTxnId]
1450
+ const metaTxnId = intent.payloads.metaTxns[0].id
1451
+ const feeQuote = intent.payloads.feeQuotes?.[metaTxnId]
1427
1452
  logger.console.log(
1428
1453
  "[trails-sdk] Extracted fee quote for origin meta txn",
1429
1454
  {
@@ -1437,16 +1462,17 @@ async function sendHandlerForDifferentChainDifferentToken({
1437
1462
  "[trails-sdk] Calling sendMetaTxAndWaitForReceipt for origin",
1438
1463
  {
1439
1464
  metaTxnId,
1440
- chainId: intent.metaTxns[0].chainId,
1441
- walletAddress: intent.metaTxns[0].walletAddress,
1442
- contract: intent.metaTxns[0].contract,
1465
+ chainId: intent.payloads.metaTxns[0].chainId,
1466
+ walletAddress: intent.payloads.metaTxns[0].walletAddress,
1467
+ contract: intent.payloads.metaTxns[0].contract,
1443
1468
  },
1444
1469
  )
1445
1470
 
1446
1471
  const { waitForReceipt } = await sendMetaTxAndWaitForReceipt({
1447
- metaTx: intent.metaTxns[0] as MetaTxn,
1472
+ metaTx: intent.payloads.metaTxns[0] as MetaTxn,
1448
1473
  relayer: originRelayer,
1449
- precondition: intent.preconditions[0] as IntentPrecondition,
1474
+ precondition: intent.payloads
1475
+ .preconditions[0] as IntentPrecondition,
1450
1476
  feeQuote: feeQuote,
1451
1477
  })
1452
1478
 
@@ -1463,8 +1489,8 @@ async function sendHandlerForDifferentChainDifferentToken({
1463
1489
  logger.console.warn(
1464
1490
  "[trails-sdk] Skipping origin sendMetaTxn - missing metaTxn or precondition",
1465
1491
  {
1466
- hasMetaTxn: !!intent.metaTxns[0],
1467
- hasPrecondition: !!intent.preconditions[0],
1492
+ hasMetaTxn: !!intent.payloads.metaTxns[0],
1493
+ hasPrecondition: !!intent.payloads.preconditions[0],
1468
1494
  },
1469
1495
  )
1470
1496
  }
@@ -1474,23 +1500,25 @@ async function sendHandlerForDifferentChainDifferentToken({
1474
1500
  logger.console.log(
1475
1501
  "[trails-sdk] Starting destinationSendMetaTxnPromise",
1476
1502
  {
1477
- quoteProvider: intent.quote.quoteProvider,
1478
- hasQuoteProviderRequestId: !!intent.quote.quoteProviderRequestId,
1479
- hasPrecondition1: !!intent.preconditions[1],
1480
- hasMetaTxn1: !!intent.metaTxns[1],
1503
+ quoteProvider: intent.payloads.quote.quoteProvider,
1504
+ hasQuoteProviderRequestId:
1505
+ !!intent.payloads.quote.quoteProviderRequestId,
1506
+ hasPrecondition1: !!intent.payloads.preconditions[1],
1507
+ hasMetaTxn1: !!intent.payloads.metaTxns[1],
1481
1508
  },
1482
1509
  )
1483
1510
 
1484
1511
  if (
1485
- intent.quote.quoteProvider === "relay" &&
1486
- intent.quote.quoteProviderRequestId &&
1487
- !intent.preconditions[1] &&
1488
- !intent.metaTxns[1]
1512
+ intent.payloads.quote.quoteProvider === "relay" &&
1513
+ intent.payloads.quote.quoteProviderRequestId &&
1514
+ !intent.payloads.preconditions[1] &&
1515
+ !intent.payloads.metaTxns[1]
1489
1516
  ) {
1490
1517
  logger.console.log(
1491
1518
  "[trails-sdk] Setting up relay destination promise",
1492
1519
  {
1493
- quoteProviderRequestId: intent.quote.quoteProviderRequestId,
1520
+ quoteProviderRequestId:
1521
+ intent.payloads.quote.quoteProviderRequestId,
1494
1522
  },
1495
1523
  )
1496
1524
  // For relay, we'll wait for the receipt in the wait phase
@@ -1501,7 +1529,8 @@ async function sendHandlerForDifferentChainDifferentToken({
1501
1529
  logger.console.log(
1502
1530
  "[trails-sdk] waitForRelayDestinationTx starting",
1503
1531
  {
1504
- quoteProviderRequestId: intent.quote.quoteProviderRequestId,
1532
+ quoteProviderRequestId:
1533
+ intent.payloads.quote.quoteProviderRequestId,
1505
1534
  aborted: abortSignal?.aborted,
1506
1535
  },
1507
1536
  )
@@ -1515,13 +1544,14 @@ async function sendHandlerForDifferentChainDifferentToken({
1515
1544
  }
1516
1545
 
1517
1546
  const txHash = await waitForRelayDestinationTx(
1518
- intent.quote.quoteProviderRequestId,
1547
+ intent.payloads.quote.quoteProviderRequestId,
1519
1548
  )
1520
1549
  logger.console.log(
1521
1550
  "[trails-sdk] waitForRelayDestinationTx completed",
1522
1551
  {
1523
1552
  txHash,
1524
- quoteProviderRequestId: intent.quote.quoteProviderRequestId,
1553
+ quoteProviderRequestId:
1554
+ intent.payloads.quote.quoteProviderRequestId,
1525
1555
  },
1526
1556
  )
1527
1557
  if (txHash) {
@@ -1559,7 +1589,8 @@ async function sendHandlerForDifferentChainDifferentToken({
1559
1589
  logger.console.warn(
1560
1590
  "[trails-sdk] No txHash returned from waitForRelayDestinationTx",
1561
1591
  {
1562
- quoteProviderRequestId: intent.quote.quoteProviderRequestId,
1592
+ quoteProviderRequestId:
1593
+ intent.payloads.quote.quoteProviderRequestId,
1563
1594
  },
1564
1595
  )
1565
1596
  }
@@ -1568,7 +1599,8 @@ async function sendHandlerForDifferentChainDifferentToken({
1568
1599
  "[trails-sdk] Error waiting for relay destination tx",
1569
1600
  {
1570
1601
  error: error instanceof Error ? error.message : String(error),
1571
- quoteProviderRequestId: intent.quote.quoteProviderRequestId,
1602
+ quoteProviderRequestId:
1603
+ intent.payloads.quote.quoteProviderRequestId,
1572
1604
  },
1573
1605
  )
1574
1606
  if (transactionStates?.[2]) {
@@ -1583,16 +1615,16 @@ async function sendHandlerForDifferentChainDifferentToken({
1583
1615
  logger.console.log(
1584
1616
  "[trails-sdk] Setting up destination meta transaction promise (non-relay)",
1585
1617
  {
1586
- quoteProvider: intent.quote.quoteProvider,
1587
- hasMetaTxn1: !!intent.metaTxns[1],
1588
- hasPrecondition1: !!intent.preconditions[1],
1618
+ quoteProvider: intent.payloads.quote.quoteProvider,
1619
+ hasMetaTxn1: !!intent.payloads.metaTxns[1],
1620
+ hasPrecondition1: !!intent.payloads.preconditions[1],
1589
1621
  },
1590
1622
  )
1591
1623
 
1592
- if (intent.metaTxns[1] && intent.preconditions[1]) {
1624
+ if (intent.payloads.metaTxns[1] && intent.payloads.preconditions[1]) {
1593
1625
  // Extract fee quote from intent response using metatxnid as key
1594
- const metaTxnId = intent.metaTxns[1].id
1595
- const feeQuote = intent.feeQuotes?.[metaTxnId]
1626
+ const metaTxnId = intent.payloads.metaTxns[1].id
1627
+ const feeQuote = intent.payloads.feeQuotes?.[metaTxnId]
1596
1628
  logger.console.log(
1597
1629
  "[trails-sdk] Extracted fee quote for destination meta txn",
1598
1630
  {
@@ -1606,16 +1638,17 @@ async function sendHandlerForDifferentChainDifferentToken({
1606
1638
  "[trails-sdk] Calling sendMetaTxAndWaitForReceipt for destination",
1607
1639
  {
1608
1640
  metaTxnId,
1609
- chainId: intent.metaTxns[1].chainId,
1610
- walletAddress: intent.metaTxns[1].walletAddress,
1611
- contract: intent.metaTxns[1].contract,
1641
+ chainId: intent.payloads.metaTxns[1].chainId,
1642
+ walletAddress: intent.payloads.metaTxns[1].walletAddress,
1643
+ contract: intent.payloads.metaTxns[1].contract,
1612
1644
  },
1613
1645
  )
1614
1646
 
1615
1647
  const { waitForReceipt } = await sendMetaTxAndWaitForReceipt({
1616
- metaTx: intent.metaTxns[1] as MetaTxn,
1648
+ metaTx: intent.payloads.metaTxns[1] as MetaTxn,
1617
1649
  relayer: destinationRelayer,
1618
- precondition: intent.preconditions[1] as IntentPrecondition,
1650
+ precondition: intent.payloads
1651
+ .preconditions[1] as IntentPrecondition,
1619
1652
  feeQuote: feeQuote,
1620
1653
  })
1621
1654
 
@@ -1632,12 +1665,12 @@ async function sendHandlerForDifferentChainDifferentToken({
1632
1665
  logger.console.warn(
1633
1666
  "[trails-sdk] Skipping destination sendMetaTxn - missing metaTxn or precondition",
1634
1667
  {
1635
- hasMetaTxn: !!intent.metaTxns[1],
1636
- hasPrecondition: !!intent.preconditions[1],
1668
+ hasMetaTxn: !!intent.payloads.metaTxns[1],
1669
+ hasPrecondition: !!intent.payloads.preconditions[1],
1637
1670
  },
1638
1671
  )
1639
1672
  }
1640
- // } else if (intent.destinationIntentAddress) {
1673
+ // } else if (intent.payloads.destinationIntentAddress) {
1641
1674
  // destinationMetaTxnReceiptPromise = checkForDestinationDepositTx
1642
1675
  // }
1643
1676
  }
@@ -1645,14 +1678,14 @@ async function sendHandlerForDifferentChainDifferentToken({
1645
1678
 
1646
1679
  let queueCctpPromise: (() => Promise<void>) | null = null
1647
1680
 
1648
- const isCctp = intent.quote.quoteProvider === "cctp"
1681
+ const isCctp = intent.payloads.quote.quoteProvider === "cctp"
1649
1682
  if (isCctp) {
1650
1683
  queueCctpPromise = async () => {
1651
1684
  while (true) {
1652
1685
  const originMetaTxnHash = originMetaTxnReceipt?.txnHash
1653
1686
  if (originMetaTxnHash) {
1654
1687
  await queueCCTPTransfer({
1655
- apiClient,
1688
+ trailsClient,
1656
1689
  sourceTxHash: originMetaTxnHash,
1657
1690
  sourceChainId: originChainId,
1658
1691
  destinationChainId: destinationChainId,
@@ -1814,9 +1847,14 @@ async function sendHandlerForDifferentChainDifferentToken({
1814
1847
  transactionStates[2].decodedTrailsTokenSweeperEvents.findIndex(
1815
1848
  (event) =>
1816
1849
  event.type === "Refund" ||
1817
- event.type === "RefundAndSweep" ||
1818
- event.type === "Sweep",
1819
- ) !== -1
1850
+ event.type === "RefundAndSweep",
1851
+ ) !== -1 ||
1852
+ (transactionStates[2].decodedTrailsTokenSweeperEvents.findIndex(
1853
+ (event) => event.type === "Sweep",
1854
+ ) !== -1 &&
1855
+ transactionStates[2].decodedGuestModuleEvents.findIndex(
1856
+ (event) => event.type === "CallFailed",
1857
+ ) !== -1)
1820
1858
  logger.console.log("[trails-sdk] Destination meta-tx events", {
1821
1859
  chainId: destinationChainId,
1822
1860
  callFailed: (
@@ -1838,7 +1876,7 @@ async function sendHandlerForDifferentChainDifferentToken({
1838
1876
  error,
1839
1877
  )
1840
1878
  // For relay transactions, this might be expected if still waiting
1841
- if (intent.quote.quoteProvider === "relay") {
1879
+ if (intent.payloads.quote.quoteProvider === "relay") {
1842
1880
  logger.console.log(
1843
1881
  "[trails-sdk] Relay transaction still waiting, this is normal",
1844
1882
  )
@@ -1867,7 +1905,7 @@ async function sendHandlerForDifferentChainDifferentToken({
1867
1905
  ])
1868
1906
  logger.console.log("[trails-sdk] Phase 2 completed successfully")
1869
1907
 
1870
- // Track payment completion
1908
+ // Track payment completion for different chain and different token
1871
1909
  if (originUserTxReceipt && destinationMetaTxnReceipt) {
1872
1910
  trackPaymentCompleted({
1873
1911
  userAddress: account.address,
@@ -2126,7 +2164,7 @@ async function sendHandlerForSameChainSameToken({
2126
2164
  token: effectiveOriginTokenAddress,
2127
2165
  account: account.address,
2128
2166
  spender: recipient,
2129
- amount: BigInt(swapAmount),
2167
+ amount: maxUint256,
2130
2168
  })
2131
2169
 
2132
2170
  if (needsApproval) {
@@ -2149,6 +2187,13 @@ async function sendHandlerForSameChainSameToken({
2149
2187
  }
2150
2188
  }
2151
2189
 
2190
+ // Show persistent toast for checkout flow
2191
+ updatePersistentToast(
2192
+ "Payment Started",
2193
+ "Waiting for wallet confirmation...",
2194
+ "info",
2195
+ )
2196
+
2152
2197
  logger.console.log("[trails-sdk] origin call params", originCallParams)
2153
2198
  const txHash = await sendOriginTransaction(
2154
2199
  account,
@@ -2181,6 +2226,14 @@ async function sendHandlerForSameChainSameToken({
2181
2226
  depositTokenAmountUsd: depositAmountUsd?.toString(),
2182
2227
  })
2183
2228
 
2229
+ // Remove persistent toast and show success
2230
+ const chainInfo = getChainInfo(effectiveOriginChainId)
2231
+ updatePersistentToast(
2232
+ "Transfer Confirmed",
2233
+ `Your transaction on ${chainInfo?.name || "chain"} has been confirmed`,
2234
+ "info",
2235
+ )
2236
+
2184
2237
  try {
2185
2238
  onTransactionStateChange([
2186
2239
  getTransactionStateFromReceipt(
@@ -2502,6 +2555,8 @@ async function attemptGaslessDeposit({
2502
2555
  walletClient,
2503
2556
  chain,
2504
2557
  account,
2558
+ trailsClient,
2559
+ originRelayer,
2505
2560
  }: {
2506
2561
  paymasterUrl?: string
2507
2562
  depositTokenAddress: string
@@ -2511,6 +2566,7 @@ async function attemptGaslessDeposit({
2511
2566
  walletClient: WalletClient
2512
2567
  chain: Chain
2513
2568
  account: Account
2569
+ trailsClient: TrailsAPIClient
2514
2570
  originRelayer: Relayer.Standard.Rpc.RpcRelayer
2515
2571
  feeOptions: any
2516
2572
  feeTokenAddress?: string
@@ -2527,30 +2583,24 @@ async function attemptGaslessDeposit({
2527
2583
  const intentEntrypoint = intentEntrypoints[chain.id]
2528
2584
  logger.console.log("[trails-sdk] intentEntrypoint", intentEntrypoint)
2529
2585
 
2530
- let calls: Array<{
2531
- to: string
2532
- data: string
2533
- value: string
2534
- }> = []
2586
+ // If intent entrypoint is not available, fall back to old flow
2587
+ if (!intentEntrypoint) {
2588
+ logger.console.log(
2589
+ "[trails-sdk] No intent entrypoint for chain, using fallback flow",
2590
+ )
2535
2591
 
2536
- if (paymasterUrl) {
2537
- logger.console.log("[trails-sdk] doing gasless with paymaster")
2538
- const delegatorSmartAccount = await getDelegatorSmartAccount({
2539
- publicClient,
2540
- })
2592
+ let calls: Array<{
2593
+ to: string
2594
+ data: string
2595
+ value: string
2596
+ }> = []
2541
2597
 
2542
- if (intentEntrypoint) {
2543
- calls = await getDepositToIntentCalls({
2598
+ if (paymasterUrl) {
2599
+ logger.console.log("[trails-sdk] doing gasless with paymaster")
2600
+ const delegatorSmartAccount = await getDelegatorSmartAccount({
2544
2601
  publicClient,
2545
- walletClient,
2546
- account,
2547
- intentEntrypoint,
2548
- depositTokenAddress: depositTokenAddress as `0x${string}`,
2549
- depositTokenAmount: BigInt(depositTokenAmount),
2550
- depositRecipient: depositRecipient as `0x${string}`,
2551
- chain,
2552
2602
  })
2553
- } else {
2603
+
2554
2604
  calls = await getPaymasterGaslessTransaction({
2555
2605
  walletClient,
2556
2606
  chain,
@@ -2559,65 +2609,52 @@ async function attemptGaslessDeposit({
2559
2609
  recipient: depositRecipient as `0x${string}`,
2560
2610
  delegatorSmartAccount,
2561
2611
  })
2562
- }
2563
2612
 
2564
- logger.console.log("[trails-sdk] calls", calls)
2565
-
2566
- const txHash = await sendPaymasterGaslessTransaction({
2567
- walletClient,
2568
- publicClient,
2569
- chain,
2570
- paymasterUrl,
2571
- delegatorSmartAccount,
2572
- calls,
2573
- })
2613
+ logger.console.log("[trails-sdk] calls", calls)
2574
2614
 
2575
- if (onOriginSend) {
2576
- onOriginSend()
2577
- }
2578
-
2579
- const receipt = await publicClient.waitForTransactionReceipt({
2580
- hash: txHash as `0x${string}`,
2581
- })
2582
- logger.console.log("[trails-sdk] receipt", receipt)
2583
- originUserTxReceipt = receipt
2584
- } else {
2585
- logger.console.log("[trails-sdk] doing gasless with sequence wallet")
2586
- const delegatorPrivateKey = generatePrivateKey()
2587
- const delegatorAccount = privateKeyToAccount(delegatorPrivateKey)
2588
- const delegatorClient = createWalletClient({
2589
- account: delegatorAccount,
2590
- chain,
2591
- transport: http(),
2592
- })
2615
+ const txHash = await sendPaymasterGaslessTransaction({
2616
+ walletClient,
2617
+ publicClient,
2618
+ chain,
2619
+ paymasterUrl,
2620
+ delegatorSmartAccount,
2621
+ calls,
2622
+ })
2593
2623
 
2594
- logger.console.log("[trails-sdk] attempting to switch chain")
2595
- await attemptSwitchChain({
2596
- walletClient,
2597
- desiredChainId: originChainId,
2598
- })
2624
+ if (onOriginSend) {
2625
+ onOriginSend()
2626
+ }
2599
2627
 
2600
- logger.console.log("[trails-sdk] creating sequence wallet")
2601
- const sequenceWalletAddress = await simpleCreateSequenceWallet(
2602
- delegatorAccount as any,
2603
- )
2604
- logger.console.log(
2605
- "[trails-sdk] sequenceWalletAddress",
2606
- sequenceWalletAddress,
2607
- )
2628
+ const receipt = await publicClient.waitForTransactionReceipt({
2629
+ hash: txHash as `0x${string}`,
2630
+ })
2631
+ logger.console.log("[trails-sdk] receipt", receipt)
2632
+ return receipt
2633
+ } else {
2634
+ logger.console.log("[trails-sdk] doing gasless with sequence wallet")
2635
+ const delegatorPrivateKey = generatePrivateKey()
2636
+ const delegatorAccount = privateKeyToAccount(delegatorPrivateKey)
2637
+ const delegatorClient = createWalletClient({
2638
+ account: delegatorAccount,
2639
+ chain,
2640
+ transport: http(),
2641
+ })
2608
2642
 
2609
- if (intentEntrypoint) {
2610
- calls = await getDepositToIntentCalls({
2611
- publicClient,
2643
+ logger.console.log("[trails-sdk] attempting to switch chain")
2644
+ await attemptSwitchChain({
2612
2645
  walletClient,
2613
- account,
2614
- intentEntrypoint,
2615
- depositTokenAddress: depositTokenAddress as `0x${string}`,
2616
- depositTokenAmount: BigInt(depositTokenAmount),
2617
- depositRecipient: depositRecipient as `0x${string}`,
2618
- chain,
2646
+ desiredChainId: originChainId,
2619
2647
  })
2620
- } else {
2648
+
2649
+ logger.console.log("[trails-sdk] creating sequence wallet")
2650
+ const sequenceWalletAddress = await simpleCreateSequenceWallet(
2651
+ delegatorAccount as any,
2652
+ )
2653
+ logger.console.log(
2654
+ "[trails-sdk] sequenceWalletAddress",
2655
+ sequenceWalletAddress,
2656
+ )
2657
+
2621
2658
  const { signature, deadline } = await getPermitSignature({
2622
2659
  publicClient,
2623
2660
  walletClient,
@@ -2637,44 +2674,181 @@ async function attemptGaslessDeposit({
2637
2674
  depositRecipient as `0x${string}`,
2638
2675
  depositTokenAddress as `0x${string}`,
2639
2676
  )
2677
+
2678
+ logger.console.log("[trails-sdk] calls", calls)
2679
+
2680
+ const sequenceTxHash = await sequenceSendTransaction(
2681
+ sequenceWalletAddress,
2682
+ delegatorClient,
2683
+ publicClient,
2684
+ calls,
2685
+ chain,
2686
+ )
2687
+ logger.console.log("[trails-sdk] sequenceTxHash", sequenceTxHash)
2688
+ if (onOriginSend) {
2689
+ onOriginSend()
2690
+ }
2691
+
2692
+ const receipt = await publicClient.waitForTransactionReceipt({
2693
+ hash: sequenceTxHash as `0x${string}`,
2694
+ })
2695
+ logger.console.log("[trails-sdk] receipt", receipt)
2696
+ return receipt
2640
2697
  }
2698
+ }
2641
2699
 
2642
- logger.console.log("[trails-sdk] calls", calls)
2643
-
2644
- // const feeOptions = await getFeeOptions(
2645
- // originRelayer,
2646
- // sequenceWalletAddress,
2647
- // originChainId,
2648
- // calls.map((call) => ({
2649
- // to: call.to,
2650
- // value: BigInt(call.value),
2651
- // data: call.data,
2652
- // gasLimit: BigInt(0),
2653
- // delegateCall: false,
2654
- // onlyFallback: false,
2655
- // behaviorOnError: "revert",
2656
- // })) as Payload.Call[],
2657
- // )
2658
-
2659
- // logger.console.log("[trails-sdk] feeOptions", feeOptions)
2660
-
2661
- const sequenceTxHash = await sequenceSendTransaction(
2662
- sequenceWalletAddress,
2663
- delegatorClient,
2664
- publicClient,
2665
- calls,
2666
- chain,
2700
+ // NEW FLOW: Use Intent Entrypoint API with permit2 support
2701
+ logger.console.log(
2702
+ "[trails-sdk] Using Intent Entrypoint API flow with permit2 support for gasless deposit",
2703
+ )
2704
+
2705
+ try {
2706
+ const deadline = Math.floor(Date.now() / 1000) + 3600 // 1 hour from now
2707
+
2708
+ // 1. Check if we need approval for permit2
2709
+ const needsApproval = await getNeedsIntentEntrypointApproval({
2710
+ client: publicClient,
2711
+ token: depositTokenAddress as `0x${string}`,
2712
+ account: account.address,
2713
+ entrypoint: intentEntrypoint as `0x${string}`,
2714
+ amount: BigInt(depositTokenAmount),
2715
+ })
2716
+
2717
+ logger.console.log("[trails-sdk] Checking permit2 requirements", {
2718
+ userAddress: account.address,
2719
+ tokenAddress: depositTokenAddress,
2720
+ amount: depositTokenAmount,
2721
+ intentAddress: depositRecipient,
2722
+ chainID: originChainId,
2723
+ deadline,
2724
+ needsApproval,
2725
+ })
2726
+
2727
+ // 2. Get permit signature if approval needed
2728
+ let permitSignature: string | undefined
2729
+ let permitDeadline: number | undefined
2730
+
2731
+ if (needsApproval) {
2732
+ logger.console.log("[trails-sdk] Getting permit signature for approval")
2733
+ // NOTE: Currently signing for exact deposit amount because API encodes permitAmount = amount
2734
+ // TODO: Update API to accept permitAmount parameter, then change to maxUint256 for unlimited approval
2735
+ const permitSig = await getPermitSignature({
2736
+ publicClient,
2737
+ walletClient,
2738
+ signer: account.address,
2739
+ spender: intentEntrypoint as `0x${string}`,
2740
+ tokenAddress: depositTokenAddress as `0x${string}`,
2741
+ amount: BigInt(depositTokenAmount), // Sign for exact amount to match API encoding
2742
+ chain,
2743
+ deadline: BigInt(deadline),
2744
+ })
2745
+ permitSignature = permitSig.signature
2746
+ permitDeadline = Number(permitSig.deadline)
2747
+ logger.console.log(
2748
+ "[trails-sdk] Permit signature obtained for amount:",
2749
+ depositTokenAmount,
2750
+ )
2751
+ }
2752
+
2753
+ // 3. Get intent signature
2754
+ logger.console.log("[trails-sdk] Requesting intent signature via EIP-712")
2755
+ const { signature: intentSignature } = await signIntent({
2756
+ client: walletClient,
2757
+ intentParams: {
2758
+ user: account.address,
2759
+ token: depositTokenAddress as `0x${string}`,
2760
+ amount: BigInt(depositTokenAmount),
2761
+ intentAddress: depositRecipient as `0x${string}`,
2762
+ deadline: BigInt(deadline),
2763
+ chainId: originChainId,
2764
+ contractAddress: intentEntrypoint as `0x${string}`,
2765
+ },
2766
+ })
2767
+ logger.console.log("[trails-sdk] Intent signature received")
2768
+
2769
+ // 4. Call the deposit endpoint with permit2 support
2770
+ logger.console.log(
2771
+ "[trails-sdk] Calling getIntentEntrypointDeposit with permit2 enabled",
2772
+ { usePermit: needsApproval },
2667
2773
  )
2668
- logger.console.log("[trails-sdk] sequenceTxHash", sequenceTxHash)
2774
+ const depositDataResponse = await trailsClient.getIntentEntrypointDeposit({
2775
+ params: {
2776
+ userAddress: account.address,
2777
+ tokenAddress: depositTokenAddress,
2778
+ amount: depositTokenAmount,
2779
+ intentAddress: depositRecipient,
2780
+ chainID: originChainId,
2781
+ deadline,
2782
+ intentSignature,
2783
+ usePermit: needsApproval, // Use permit2 if approval needed
2784
+ permitSignature,
2785
+ permitDeadline,
2786
+ },
2787
+ })
2788
+
2789
+ const depositData = depositDataResponse.result
2790
+ logger.console.log("[trails-sdk] Deposit data received:", {
2791
+ depositWalletAddress: depositData.depositWalletAddress,
2792
+ entrypointAddress: depositData.entrypointAddress,
2793
+ metaTxnId: depositData.metaTxn?.id,
2794
+ usedPermit2: needsApproval,
2795
+ })
2796
+
2797
+ // 5. Send meta transaction via relayer
2798
+ logger.console.log("[trails-sdk] Sending meta transaction to relayer")
2799
+ const feeQuoteObj = depositData.feeQuote
2800
+ ? ({
2801
+ _tag: "FeeQuote",
2802
+ _quote: { toJSON: () => depositData.feeQuote },
2803
+ } as any)
2804
+ : undefined
2805
+
2806
+ const opHash = await relayerSendMetaTx(
2807
+ originRelayer,
2808
+ depositData.metaTxn as any,
2809
+ [], // No preconditions for gasless deposit
2810
+ feeQuoteObj,
2811
+ )
2812
+ logger.console.log("[trails-sdk] Meta transaction sent, opHash:", opHash)
2813
+
2669
2814
  if (onOriginSend) {
2670
2815
  onOriginSend()
2671
2816
  }
2672
2817
 
2673
- const receipt = await publicClient.waitForTransactionReceipt({
2674
- hash: sequenceTxHash as `0x${string}`,
2675
- })
2676
- logger.console.log("[trails-sdk] receipt", receipt)
2677
- originUserTxReceipt = receipt
2818
+ // 6. Wait for transaction receipt
2819
+ logger.console.log("[trails-sdk] Waiting for transaction receipt")
2820
+ // eslint-disable-next-line no-constant-condition
2821
+ while (true) {
2822
+ const receipt: any = await getMetaTxStatus(
2823
+ originRelayer,
2824
+ depositData.metaTxn.id,
2825
+ Number(depositData.metaTxn.chainId),
2826
+ )
2827
+ logger.console.log("[trails-sdk] Meta transaction status:", receipt)
2828
+
2829
+ if (receipt?.transactionHash) {
2830
+ const metaTxnReceipt = receipt.data?.receipt
2831
+ if (!metaTxnReceipt) {
2832
+ throw new Error("No meta txn receipt found")
2833
+ }
2834
+
2835
+ // Get the full transaction receipt
2836
+ const txReceipt = await publicClient.getTransactionReceipt({
2837
+ hash: receipt.transactionHash as `0x${string}`,
2838
+ })
2839
+ logger.console.log("[trails-sdk] Transaction receipt:", txReceipt)
2840
+ originUserTxReceipt = txReceipt
2841
+ break
2842
+ }
2843
+
2844
+ await new Promise((resolve) => setTimeout(resolve, 1000))
2845
+ }
2846
+ } catch (error) {
2847
+ logger.console.error(
2848
+ "[trails-sdk] Error in Intent Entrypoint gasless deposit with permit2:",
2849
+ error,
2850
+ )
2851
+ throw error
2678
2852
  }
2679
2853
 
2680
2854
  return originUserTxReceipt
@@ -2835,6 +3009,13 @@ export async function attemptNonGaslessUserDeposit({
2835
3009
  : "0x0",
2836
3010
  })
2837
3011
 
3012
+ // Update persistent toast before wallet interaction
3013
+ updatePersistentToast(
3014
+ "Waiting for Confirmation",
3015
+ "Please confirm the transaction in your wallet...",
3016
+ "info",
3017
+ )
3018
+
2838
3019
  // Send the batched call via EIP-7702
2839
3020
  const result = (await walletClient.request({
2840
3021
  method: "wallet_sendCalls",
@@ -2881,6 +3062,14 @@ export async function attemptNonGaslessUserDeposit({
2881
3062
  onOriginSend()
2882
3063
  }
2883
3064
 
3065
+ // Update persistent toast after transaction sent
3066
+ const chainInfo = getChainInfo(originChainId)
3067
+ updatePersistentToast(
3068
+ "Transaction Submitted",
3069
+ `Waiting for confirmation on ${chainInfo?.name || "chain"}...`,
3070
+ "info",
3071
+ )
3072
+
2884
3073
  const receipt = await publicClient.waitForTransactionReceipt({
2885
3074
  hash: txHash as `0x${string}`,
2886
3075
  })
@@ -2912,6 +3101,13 @@ export async function attemptNonGaslessUserDeposit({
2912
3101
  logger.console.log("[trails-sdk] nativeFeeReceipt", feeReceipt)
2913
3102
  }
2914
3103
 
3104
+ // Show persistent toast for checkout flow
3105
+ updatePersistentToast(
3106
+ "Payment Started",
3107
+ "Waiting for wallet confirmation...",
3108
+ "info",
3109
+ )
3110
+
2915
3111
  const txHash = await sendOriginTransaction(
2916
3112
  account,
2917
3113
  walletClient,
@@ -2944,6 +3140,13 @@ export async function attemptNonGaslessUserDeposit({
2944
3140
  hash: txHash,
2945
3141
  })
2946
3142
 
3143
+ const chainInfo = getChainInfo(originChainId)
3144
+ updatePersistentToast(
3145
+ "Transfer Confirmed",
3146
+ `Your transaction on ${chainInfo?.name || "chain"} has been confirmed`,
3147
+ "info",
3148
+ )
3149
+
2947
3150
  trackTransactionConfirmed({
2948
3151
  transactionHash: txHash,
2949
3152
  chainId: originChainId,
@@ -2990,6 +3193,7 @@ async function attemptUserDepositTx({
2990
3193
  depositAmountUsd,
2991
3194
  feeOptions,
2992
3195
  feeTokenAddress,
3196
+ trailsClient,
2993
3197
  }: {
2994
3198
  originTokenAddress: string
2995
3199
  gasless: boolean
@@ -3017,6 +3221,7 @@ async function attemptUserDepositTx({
3017
3221
  depositAmountUsd: number
3018
3222
  feeOptions?: any
3019
3223
  feeTokenAddress?: string | null
3224
+ trailsClient: TrailsAPIClient
3020
3225
  }): Promise<TransactionReceipt | null> {
3021
3226
  let originUserTxReceipt: TransactionReceipt | null = null
3022
3227
  const originChainId = chain.id
@@ -3050,6 +3255,7 @@ async function attemptUserDepositTx({
3050
3255
  walletClient,
3051
3256
  chain,
3052
3257
  account,
3258
+ trailsClient,
3053
3259
  originRelayer,
3054
3260
  feeOptions,
3055
3261
  feeTokenAddress: feeTokenAddress || "",
@@ -3270,6 +3476,9 @@ async function checkAccountBalance({
3270
3476
  abi: erc20Abi,
3271
3477
  functionName: "decimals",
3272
3478
  })
3479
+ if (!decimals) {
3480
+ throw new Error("Decimals not found")
3481
+ }
3273
3482
  balanceFormatted = formatUnits(balance, decimals)
3274
3483
  requiredAmountFormatted = formatUnits(requiredAmount, decimals)
3275
3484
  }
@@ -3335,7 +3544,7 @@ function getNeedsLifiNativeFee({
3335
3544
  formatUnits(BigInt(destinationTokenAmount), destinationTokenDecimals),
3336
3545
  )
3337
3546
  const depositAmountFormatted = Number(
3338
- formatUnits(BigInt(depositAmount), destinationTokenDecimals),
3547
+ formatUnits(BigInt(depositAmount), sourceTokenDecimals),
3339
3548
  )
3340
3549
  logger.console.log("[trails-sdk] destinationAmount", destinationAmount)
3341
3550
  logger.console.log(
@@ -3380,6 +3589,8 @@ export type UseQuoteProps = {
3380
3589
  slippageTolerance?: string | number | null
3381
3590
  onStatusUpdate?: ((transactionStates: TransactionState[]) => void) | null
3382
3591
  quoteProvider?: string | null
3592
+ gasless?: boolean
3593
+ paymasterUrl?: string
3383
3594
  }
3384
3595
 
3385
3596
  export type SwapReturn = {
@@ -3421,6 +3632,8 @@ export type Quote = {
3421
3632
  destinationTokenRate?: string
3422
3633
  fromAmountUsdDisplay?: string
3423
3634
  toAmountUsdDisplay?: string
3635
+ gasCostUsd?: number
3636
+ gasCostUsdDisplay?: string
3424
3637
  }
3425
3638
 
3426
3639
  export type UseQuoteReturn = {
@@ -3444,8 +3657,11 @@ export function useQuote({
3444
3657
  slippageTolerance,
3445
3658
  onStatusUpdate,
3446
3659
  quoteProvider,
3660
+ gasless,
3661
+ paymasterUrl,
3447
3662
  }: Partial<UseQuoteProps> = {}): UseQuoteReturn {
3448
3663
  const apiClient = useAPIClient()
3664
+ const trailsClient = useTrailsClient()
3449
3665
  const { getRelayer } = useRelayers({
3450
3666
  env: getSequenceEnv() as RelayerEnv,
3451
3667
  })
@@ -3471,6 +3687,7 @@ export function useQuote({
3471
3687
  if (
3472
3688
  !walletClient ||
3473
3689
  !apiClient ||
3690
+ !trailsClient ||
3474
3691
  !fromTokenAddress ||
3475
3692
  !toTokenAddress ||
3476
3693
  !swapAmount ||
@@ -3506,19 +3723,27 @@ export function useQuote({
3506
3723
  // return null
3507
3724
  // }
3508
3725
 
3726
+ // logger.console.log("supportedTokens", supportedTokens)
3727
+
3509
3728
  const originToken = supportedTokens?.find(
3510
3729
  (token) =>
3511
- token.contractAddress === fromTokenAddress &&
3512
- token.chainId === fromChainId,
3730
+ token.contractAddress?.toLowerCase() ===
3731
+ fromTokenAddress?.toLowerCase() && token.chainId === fromChainId,
3513
3732
  )
3514
3733
  const destinationToken = supportedTokens?.find(
3515
3734
  (token) =>
3516
- token.contractAddress === toTokenAddress &&
3517
- token.chainId === toChainId,
3735
+ token.contractAddress?.toLowerCase() ===
3736
+ toTokenAddress?.toLowerCase() && token.chainId === toChainId,
3518
3737
  )
3519
3738
 
3520
- const sourceTokenDecimals = originToken?.decimals ?? 18
3521
- const destinationTokenDecimals = destinationToken?.decimals ?? 18
3739
+ const sourceTokenDecimals = originToken?.decimals
3740
+ if (!sourceTokenDecimals) {
3741
+ throw new Error("Source token decimals not found")
3742
+ }
3743
+ const destinationTokenDecimals = destinationToken?.decimals
3744
+ if (!destinationTokenDecimals) {
3745
+ throw new Error("Destination token decimals not found")
3746
+ }
3522
3747
  const destinationTokenSymbol = destinationToken?.symbol ?? ""
3523
3748
  const originTokenSymbol = originToken?.symbol ?? ""
3524
3749
 
@@ -3537,6 +3762,7 @@ export function useQuote({
3537
3762
  destinationCalldata: toCalldata as string,
3538
3763
  client: walletClient,
3539
3764
  apiClient,
3765
+ trailsClient,
3540
3766
  originRelayer,
3541
3767
  destinationRelayer,
3542
3768
  sourceTokenDecimals,
@@ -3546,6 +3772,8 @@ export function useQuote({
3546
3772
  onTransactionStateChange: onStatusUpdate ?? (() => {}),
3547
3773
  slippageTolerance: slippageTolerance?.toString(),
3548
3774
  quoteProvider: quoteProvider,
3775
+ gasless: gasless ?? false,
3776
+ paymasterUrl: paymasterUrl,
3549
3777
  }
3550
3778
 
3551
3779
  logger.console.log("[trails-sdk] options", options)
@@ -3573,6 +3801,8 @@ export function useQuote({
3573
3801
  prepareSendQuote.originAmountUsdDisplay ?? undefined,
3574
3802
  toAmountUsdDisplay:
3575
3803
  prepareSendQuote.destinationAmountUsdDisplay ?? undefined,
3804
+ gasCostUsd: prepareSendQuote.gasCostUsd ?? undefined,
3805
+ gasCostUsdDisplay: prepareSendQuote.gasCostUsdDisplay ?? undefined,
3576
3806
  }
3577
3807
 
3578
3808
  const swap = async (): Promise<SwapReturn> => {
@@ -3645,7 +3875,7 @@ export function getFeesFromIntent(
3645
3875
  toAmountUsd,
3646
3876
  }: { tradeType: TradeType; fromAmountUsd: number; toAmountUsd: number },
3647
3877
  ): PrepareSendFees {
3648
- const totalFeeAmountUsd = intent?.trailsFee?.totalFeeUSD ?? 0
3878
+ const totalFeeAmountUsd = intent.payloads?.trailsFee?.totalFeeUSD ?? 0
3649
3879
  const totalFeeAmountUsdDisplay = formatUsdAmountDisplay(totalFeeAmountUsd)
3650
3880
 
3651
3881
  logger.console.log("[trails-sdk] getFeesFromIntent", {
@@ -3657,8 +3887,8 @@ export function getFeesFromIntent(
3657
3887
  })
3658
3888
 
3659
3889
  return {
3660
- feeTokenAddress: intent.trailsFee?.feeToken ?? zeroAddress,
3661
- totalFeeAmount: intent.trailsFee?.totalFeeAmount ?? "0",
3890
+ feeTokenAddress: intent.payloads.trailsFee?.feeToken ?? zeroAddress,
3891
+ totalFeeAmount: intent.payloads.trailsFee?.totalFeeAmount ?? "0",
3662
3892
  totalFeeAmountUsd: totalFeeAmountUsd.toString(),
3663
3893
  totalFeeAmountUsdDisplay,
3664
3894
  }
@@ -3667,20 +3897,20 @@ export function getFeesFromIntent(
3667
3897
  export function getSlippageToleranceFromIntent(
3668
3898
  intent: GetIntentCallsPayloadsReturn,
3669
3899
  ): string {
3670
- return intent.quote?.maxSlippage?.toString() ?? "0"
3900
+ return intent.payloads.quote?.maxSlippage?.toString() ?? "0"
3671
3901
  }
3672
3902
 
3673
3903
  export function getPriceImpactFromIntent(
3674
3904
  intent: GetIntentCallsPayloadsReturn,
3675
3905
  ): string {
3676
- return intent?.quote?.priceImpact?.toString() ?? "0"
3906
+ return intent.payloads?.quote?.priceImpact?.toString() ?? "0"
3677
3907
  }
3678
3908
 
3679
3909
  export function getPriceImpactUsdFromIntent(
3680
3910
  intent: GetIntentCallsPayloadsReturn,
3681
3911
  ): string {
3682
3912
  // Temporary type assertion until API types are regenerated
3683
- return (intent?.quote as any)?.priceImpactUsd?.toString() ?? "0"
3913
+ return (intent.payloads?.quote as any)?.priceImpactUsd?.toString() ?? "0"
3684
3914
  }
3685
3915
 
3686
3916
  export function getFeesFromRelaySdkQuote(quote: RelayQuote): PrepareSendFees {