0xtrails 0.4.1 → 0.4.2

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 (55) hide show
  1. package/dist/aave.d.ts.map +1 -1
  2. package/dist/{ccip-Bc-mZIIK.js → ccip-Dl3umoGg.js} +5 -5
  3. package/dist/{index-BWGjgMLm.js → index-sMS_ge1R.js} +13956 -13858
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +501 -474
  7. package/dist/intents.d.ts +1 -1
  8. package/dist/intents.d.ts.map +1 -1
  9. package/dist/morpho.d.ts.map +1 -1
  10. package/dist/mutations.d.ts +2 -2
  11. package/dist/mutations.d.ts.map +1 -1
  12. package/dist/prepareSend.d.ts.map +1 -1
  13. package/dist/trails.d.ts +9 -10
  14. package/dist/trails.d.ts.map +1 -1
  15. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +3 -2
  16. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -1
  17. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts +1 -1
  18. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts.map +1 -1
  19. package/dist/transactionIntent/deposits/standardDeposit.d.ts +3 -2
  20. package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -1
  21. package/dist/transactionIntent/handlers/crossChain.d.ts +1 -1
  22. package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -1
  23. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts +3 -2
  24. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -1
  25. package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -1
  26. package/dist/transactionIntent/types.d.ts +1 -1
  27. package/dist/transactionIntent/types.d.ts.map +1 -1
  28. package/dist/widget/components/FeeOptions.d.ts +2 -1
  29. package/dist/widget/components/FeeOptions.d.ts.map +1 -1
  30. package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
  31. package/dist/widget/hooks/useQuote.d.ts +31 -1
  32. package/dist/widget/hooks/useQuote.d.ts.map +1 -1
  33. package/dist/widget/hooks/useSendForm.d.ts +1 -1
  34. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  35. package/dist/widget/index.js +1 -1
  36. package/package.json +7 -7
  37. package/src/aave.ts +1 -0
  38. package/src/index.ts +1 -1
  39. package/src/intents.ts +2 -2
  40. package/src/morpho.ts +3 -2
  41. package/src/mutations.ts +53 -5
  42. package/src/prepareSend.ts +12 -1
  43. package/src/trails.ts +57 -65
  44. package/src/transactionIntent/deposits/depositOrchestrator.ts +4 -1
  45. package/src/transactionIntent/deposits/gaslessDeposit.ts +1 -1
  46. package/src/transactionIntent/deposits/standardDeposit.ts +124 -3
  47. package/src/transactionIntent/handlers/crossChain.ts +14 -9
  48. package/src/transactionIntent/handlers/sameChainSameToken.ts +32 -12
  49. package/src/transactionIntent/quote/quoteHelpers.ts +4 -11
  50. package/src/transactionIntent/types.ts +1 -1
  51. package/src/widget/components/FeeOptions.tsx +2 -1
  52. package/src/widget/components/PoolDeposit.tsx +68 -4
  53. package/src/widget/hooks/useDebugScreens.ts +11 -11
  54. package/src/widget/hooks/useQuote.ts +37 -2
  55. package/src/widget/hooks/useSendForm.ts +2 -2
package/src/mutations.ts CHANGED
@@ -8,6 +8,11 @@ import {
8
8
  trackIntentCommitCompleted,
9
9
  trackIntentCommitError,
10
10
  } from "./analytics.js"
11
+ import {
12
+ type ExecuteIntentResponse,
13
+ type IntentStatus,
14
+ IntentStatusError,
15
+ } from "@0xsequence/trails-api"
11
16
 
12
17
  /**
13
18
  * Hook for committing an intent to the Trails API
@@ -109,11 +114,54 @@ export function useExecuteIntent() {
109
114
  )
110
115
  }
111
116
 
112
- const response = await trailsClient.executeIntent({
113
- intentId,
114
- depositTransactionHash,
115
- depositSignature,
116
- })
117
+ let response: ExecuteIntentResponse
118
+
119
+ try {
120
+ response = await trailsClient.executeIntent({
121
+ intentId,
122
+ depositTransactionHash,
123
+ depositSignature,
124
+ })
125
+ } catch (error) {
126
+ logger.console.error(
127
+ "[trails-sdk] useExecuteIntent: Error executing intent",
128
+ {
129
+ intentId,
130
+ error,
131
+ errorJSON: JSON.stringify(error, null, 2),
132
+ },
133
+ )
134
+ if (
135
+ (error instanceof Error &&
136
+ error?.message?.includes("status=SUCCEEDED")) ||
137
+ (error instanceof Error &&
138
+ (error?.cause as Error)?.message?.includes("status=SUCCEEDED")) ||
139
+ (error instanceof Error &&
140
+ JSON.stringify(error).includes("status=SUCCEEDED")) ||
141
+ (error instanceof IntentStatusError &&
142
+ error?.cause?.toString().includes("status=SUCCEEDED")) ||
143
+ JSON.stringify(error).includes("status=SUCCEEDED")
144
+ ) {
145
+ logger.console.error(
146
+ "[trails-sdk] useExecuteIntent: Intent already succeeded, treating as success",
147
+ { intentId },
148
+ )
149
+ return {
150
+ intentId,
151
+ intentStatus: "SUCCEEDED" as IntentStatus,
152
+ }
153
+ } else {
154
+ logger.console.error(
155
+ "[trails-sdk] useExecuteIntent did not throw IntentStatusError and is not a SUCCEEDED intent",
156
+ {
157
+ intentId,
158
+ error,
159
+ errorJSON: JSON.stringify(error, null, 2),
160
+ },
161
+ )
162
+ throw error
163
+ }
164
+ }
117
165
 
118
166
  logger.console.log(
119
167
  "[trails-sdk] useExecuteIntent: Execution successful",
@@ -128,6 +128,16 @@ export async function prepareSend(
128
128
  }
129
129
 
130
130
  if (hasCustomCalldata && tradeType === TradeType.EXACT_INPUT) {
131
+ logger.console.log("[trails-sdk] Wrapping calldata with Trails Router", {
132
+ destinationTokenAddress,
133
+ effectiveDestinationAddress,
134
+ effectiveDestinationCalldata,
135
+ swapAmount,
136
+ originChainId,
137
+ destinationChainId,
138
+ originTokenAddress,
139
+ })
140
+
131
141
  const wrapResult = wrapCalldataWithTrailsRouterIfNeeded({
132
142
  token: destinationTokenAddress,
133
143
  target: effectiveDestinationAddress,
@@ -261,7 +271,7 @@ export async function prepareSend(
261
271
  explorerUrl: "",
262
272
  chainId: originChainId,
263
273
  state: "pending",
264
- label: isToSameChain && isToSameToken ? "Execute" : "Transfer",
274
+ label: isToSameChain && isToSameToken ? "Execute" : "Deposit",
265
275
  })
266
276
 
267
277
  // swap (+ bridge tx) - skip for same-chain-same-token as there's no second transaction
@@ -353,6 +363,7 @@ export async function prepareSend(
353
363
  slippageTolerance: slippageTolerance,
354
364
  checkoutOnHandlers,
355
365
  paymasterUrl,
366
+ quoteProvider,
356
367
  selectedFeeToken,
357
368
  walletId,
358
369
  trailsClient,
package/src/trails.ts CHANGED
@@ -36,7 +36,7 @@ import type {
36
36
  import {
37
37
  calculateIntentAddress,
38
38
  calculateOriginAndDestinationIntentAddresses,
39
- getIntent as getIntentFromIntents,
39
+ quoteIntent as quoteIntentFromIntents,
40
40
  } from "./intents.js"
41
41
  import {
42
42
  useIntentReceiptMonitor,
@@ -64,7 +64,7 @@ export type UseTrailsConfig = {
64
64
  export type UseTrailsReturn = {
65
65
  trailsClient: TrailsClient
66
66
  metaTxns: MetaTxn[] | null
67
- intentCallsPayloads: IntentCalls[] | null
67
+ intentCalls: IntentCalls[] | null
68
68
  intentPreconditions: TransactionPrecondition[] | null
69
69
  trailsFee: LocalTrailsFee | null
70
70
  txnHash: Hex | undefined
@@ -82,8 +82,8 @@ export type UseTrailsReturn = {
82
82
  estimateError: Error | null
83
83
  calculateIntentAddress: typeof calculateIntentAddress
84
84
  calculateOriginAndDestinationIntentAddresses: typeof calculateOriginAndDestinationIntentAddresses
85
- committedIntentConfig: Intent | undefined
86
- isLoadingCommittedConfig: boolean
85
+ committedIntent: Intent | undefined
86
+ isLoadingCommittedIntent: boolean
87
87
  committedConfigError: Error | null
88
88
  commitIntent: (intent: Intent) => void
89
89
  commitIntentPending: boolean
@@ -97,9 +97,8 @@ export type UseTrailsReturn = {
97
97
  executeIntentPending: boolean
98
98
  executeIntentSuccess: boolean
99
99
  executeIntentError: Error | null
100
- getIntent: (args: QuoteIntentRequest) => Promise<Intent>
100
+ getIntentFromQuoteIntent: (args: QuoteIntentRequest) => Promise<Intent>
101
101
  operationHashes: { [key: string]: Hex }
102
- callIntentCallsPayload: (args: QuoteIntentRequest) => void
103
102
  sendOriginTransaction: () => Promise<void>
104
103
  switchChain: any // TODO: Add proper type
105
104
  isSwitchingChain: boolean
@@ -135,11 +134,11 @@ export type UseTrailsReturn = {
135
134
  sentMetaTxns: { [key: string]: number }
136
135
  clearIntent: () => void
137
136
  intentReceiptStatus: IntentReceiptStatus | null
138
- createIntent: (args: QuoteIntentRequest) => void
139
- createIntentPending: boolean
140
- createIntentSuccess: boolean
141
- createIntentError: Error | null
142
- createIntentArgs: QuoteIntentRequest | undefined
137
+ quoteIntent: (args: QuoteIntentRequest) => void
138
+ quoteIntentPending: boolean
139
+ quoteIntentSuccess: boolean
140
+ quoteIntentError: Error | null
141
+ quoteIntentArgs: QuoteIntentRequest | undefined
143
142
  originCallParams: OriginCallParams | null
144
143
  updateOriginCallParams: (
145
144
  args: { originChainId: number; tokenAddress: string } | null,
@@ -159,7 +158,7 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
159
158
  sequenceProjectAccessKey,
160
159
  } = config
161
160
  const trailsClient = useTrailsClient({
162
- projectAccessKey: sequenceProjectAccessKey,
161
+ apiKey: sequenceProjectAccessKey,
163
162
  })
164
163
 
165
164
  const [isAutoExecute, setIsAutoExecute] = useState(!disableAutoExecute)
@@ -172,14 +171,12 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
172
171
 
173
172
  // State declarations
174
173
  const [metaTxns, setMetaTxns] = useState<MetaTxn[] | null>(null)
175
- const [intentCallsPayloads, setIntentCallsPayloads] = useState<
176
- IntentCalls[] | null
177
- >(null)
174
+ const [intentCalls, setIntentCalls] = useState<IntentCalls[] | null>(null)
178
175
  const [intentPreconditions, setIntentPreconditions] = useState<
179
176
  TransactionPrecondition[] | null
180
177
  >(null)
181
178
  const [trailsFee, setTrailsFee] = useState<LocalTrailsFee | null>(null)
182
- const [quoteIntent, setQuoteIntent] = useState<Intent | null>(null)
179
+ const [intent, setIntent] = useState<Intent | null>(null)
183
180
  const [txnHash, setTxnHash] = useState<Hex | undefined>()
184
181
  const [committedOriginIntentAddress, setCommittedOriginIntentAddress] =
185
182
  useState<string | null>(null)
@@ -262,9 +259,9 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
262
259
  )
263
260
 
264
261
  try {
265
- const originChainId = createIntentMutation.variables?.originChainId
262
+ const originChainId = quoteIntentMutation.variables?.originChainId
266
263
  const destinationChainId =
267
- createIntentMutation.variables?.destinationChainId
264
+ quoteIntentMutation.variables?.destinationChainId
268
265
 
269
266
  if (!originChainId || !destinationChainId) {
270
267
  logger.console.error(
@@ -347,7 +344,7 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
347
344
  )
348
345
  }
349
346
 
350
- // Commit the intent that was returned from quoteIntent
347
+ // Commit the intent that was returned from intent
351
348
  logger.console.log("[useTrails] Committing intent to API...")
352
349
  const response = await baseCommitIntentMutation.mutateAsync(intent)
353
350
  logger.console.log("[useTrails] API Commit Response:", response)
@@ -385,8 +382,8 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
385
382
 
386
383
  // New Query to fetch committed intent config
387
384
  const {
388
- data: committedIntentConfig,
389
- isLoading: isLoadingCommittedConfig,
385
+ data: committedIntent,
386
+ isLoading: isLoadingCommittedIntent,
390
387
  error: committedConfigError,
391
388
  } = useQuery<Intent, Error>({
392
389
  queryKey: ["getIntent", committedOriginIntentAddress],
@@ -411,13 +408,13 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
411
408
  retry: 1,
412
409
  })
413
410
 
414
- async function getIntent(args: QuoteIntentRequest) {
415
- const { intent } = await getIntentFromIntents(trailsClient, args)
411
+ async function getIntentFromQuoteIntent(args: QuoteIntentRequest) {
412
+ const { intent } = await quoteIntentFromIntents(trailsClient, args)
416
413
  return intent
417
414
  }
418
415
 
419
416
  // TODO: Add type for args
420
- const createIntentMutation = useMutation<Intent, Error, QuoteIntentRequest>({
417
+ const quoteIntentMutation = useMutation<Intent, Error, QuoteIntentRequest>({
421
418
  mutationFn: async (args: QuoteIntentRequest) => {
422
419
  if (
423
420
  args.originChainId === args.destinationChainId &&
@@ -439,20 +436,20 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
439
436
  setVerificationStatus(null)
440
437
  setTrailsFee(null)
441
438
  setMetaTxns(null)
442
- setIntentCallsPayloads(null)
439
+ setIntentCalls(null)
443
440
  setIntentPreconditions(null)
444
441
  setOriginIntentAddress(null)
445
442
  setDestinationIntentAddress(null)
446
443
 
447
- const { intent: data } = await getIntentFromIntents(trailsClient, args)
444
+ const { intent: data } = await quoteIntentFromIntents(trailsClient, args)
448
445
 
449
446
  setMetaTxns(data.metaTxns)
450
- setIntentCallsPayloads(data.calls)
447
+ setIntentCalls(data.calls)
451
448
  setIntentPreconditions(data.preconditions)
452
449
  setTrailsFee(data.fees as any)
453
450
  setOriginIntentAddress(data.originIntentAddress)
454
451
  setDestinationIntentAddress(data.destinationIntentAddress)
455
- setQuoteIntent(data)
452
+ setIntent(data)
456
453
  setCommittedOriginIntentAddress(null)
457
454
  setCommittedDestinationIntentAddress(null)
458
455
 
@@ -474,19 +471,19 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
474
471
  data.metaTxns &&
475
472
  data.metaTxns.length > 0
476
473
  ) {
477
- setIntentCallsPayloads(data.calls)
474
+ setIntentCalls(data.calls)
478
475
  setIntentPreconditions(data.preconditions)
479
476
  setMetaTxns(data.metaTxns)
480
477
  } else {
481
478
  logger.console.warn("API returned success but no operations found.")
482
- setIntentCallsPayloads(null)
479
+ setIntentCalls(null)
483
480
  setIntentPreconditions(null)
484
481
  setMetaTxns(null)
485
482
  }
486
483
  },
487
484
  onError: (error) => {
488
485
  console.error("Intent Config Error:", error)
489
- setIntentCallsPayloads(null)
486
+ setIntentCalls(null)
490
487
  setIntentPreconditions(null)
491
488
  setMetaTxns(null)
492
489
  setTrailsFee(null)
@@ -495,13 +492,9 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
495
492
  },
496
493
  })
497
494
 
498
- function callIntentCallsPayload(args: QuoteIntentRequest) {
499
- createIntentMutation.mutate(args)
500
- }
501
-
502
495
  const clearIntent = useCallback(() => {
503
496
  logger.console.log("[Trails] Clearing intent state")
504
- setIntentCallsPayloads(null)
497
+ setIntentCalls(null)
505
498
  setIntentPreconditions(null)
506
499
  setMetaTxns(null)
507
500
  setTrailsFee(null)
@@ -940,7 +933,7 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
940
933
  useEffect(() => {
941
934
  if (
942
935
  isAutoExecute &&
943
- intentCallsPayloads &&
936
+ intentCalls &&
944
937
  intentPreconditions &&
945
938
  trailsFee &&
946
939
  account.address &&
@@ -949,14 +942,14 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
949
942
  !commitIntentMutation.isSuccess
950
943
  ) {
951
944
  logger.console.log("Auto-committing intent configuration...")
952
- if (quoteIntent) {
953
- commitIntentMutation.mutate(quoteIntent)
945
+ if (intent) {
946
+ commitIntentMutation.mutate(intent)
954
947
  }
955
948
  }
956
949
  }, [
957
950
  isAutoExecute,
958
- quoteIntent,
959
- intentCallsPayloads,
951
+ intent,
952
+ intentCalls,
960
953
  intentPreconditions,
961
954
  trailsFee,
962
955
  account.address,
@@ -970,7 +963,7 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
970
963
  useEffect(() => {
971
964
  if (
972
965
  !originIntentAddress ||
973
- !intentCallsPayloads?.[0]?.chainId ||
966
+ !intentCalls?.[0]?.chainId ||
974
967
  !tokenAddress ||
975
968
  !originChainId ||
976
969
  !intentPreconditions ||
@@ -1053,7 +1046,7 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
1053
1046
  })
1054
1047
  }
1055
1048
  }, [
1056
- intentCallsPayloads,
1049
+ intentCalls,
1057
1050
  tokenAddress,
1058
1051
  originChainId,
1059
1052
  intentPreconditions,
@@ -1158,23 +1151,23 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
1158
1151
  const providerFromQuote = trailsFee?.quoteProvider
1159
1152
  ? String(trailsFee.quoteProvider).toLowerCase()
1160
1153
  : undefined
1161
- const providerFromArgs = createIntentMutation.variables?.options
1154
+ const providerFromArgs = quoteIntentMutation.variables?.options
1162
1155
  ?.quoteProvider
1163
1156
  ? String(
1164
- createIntentMutation.variables.options.quoteProvider,
1157
+ quoteIntentMutation.variables.options.quoteProvider,
1165
1158
  ).toLowerCase()
1166
1159
  : undefined
1167
1160
  const isCctp =
1168
1161
  providerFromQuote === "cctp" || providerFromArgs === "cctp"
1169
1162
 
1170
- if (isCctp && createIntentMutation.variables) {
1163
+ if (isCctp && quoteIntentMutation.variables) {
1171
1164
  try {
1172
1165
  queueCCTPTransfer({
1173
1166
  sourceTxHash: intentReceiptStatus.intentReceipt.originTransaction
1174
1167
  .txnHash as `0x${string}`,
1175
- sourceChainId: createIntentMutation.variables.originChainId,
1168
+ sourceChainId: quoteIntentMutation.variables.originChainId,
1176
1169
  destinationChainId:
1177
- createIntentMutation.variables.destinationChainId,
1170
+ quoteIntentMutation.variables.destinationChainId,
1178
1171
  trailsClient,
1179
1172
  })
1180
1173
  } catch (error) {
@@ -1188,7 +1181,7 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
1188
1181
  intentReceiptStatus.intentReceipt,
1189
1182
  committedOriginIntentAddress,
1190
1183
  trailsFee,
1191
- createIntentMutation.variables,
1184
+ quoteIntentMutation.variables,
1192
1185
  trailsClient,
1193
1186
  ])
1194
1187
 
@@ -1196,8 +1189,8 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
1196
1189
  setIsAutoExecute(enabled)
1197
1190
  }
1198
1191
 
1199
- function createIntent(args: QuoteIntentRequest) {
1200
- createIntentMutation.mutate(args)
1192
+ function quoteIntent(args: QuoteIntentRequest) {
1193
+ quoteIntentMutation.mutate(args)
1201
1194
  }
1202
1195
 
1203
1196
  function commitIntent(intent: Intent) {
@@ -1221,10 +1214,10 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
1221
1214
 
1222
1215
  const originChainIdFromParams = originCallParams?.chainId
1223
1216
 
1224
- const createIntentPending = createIntentMutation.isPending
1225
- const createIntentSuccess = createIntentMutation.isSuccess
1226
- const createIntentError = createIntentMutation.error
1227
- const createIntentArgs = createIntentMutation.variables
1217
+ const quoteIntentPending = quoteIntentMutation.isPending
1218
+ const quoteIntentSuccess = quoteIntentMutation.isSuccess
1219
+ const quoteIntentError = quoteIntentMutation.error
1220
+ const quoteIntentArgs = quoteIntentMutation.variables
1228
1221
 
1229
1222
  const commitIntentPending = commitIntentMutation.isPending
1230
1223
  const commitIntentSuccess = commitIntentMutation.isSuccess
@@ -1245,7 +1238,7 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
1245
1238
  return {
1246
1239
  trailsClient,
1247
1240
  metaTxns,
1248
- intentCallsPayloads,
1241
+ intentCalls,
1249
1242
  intentPreconditions,
1250
1243
  trailsFee,
1251
1244
  txnHash,
@@ -1257,8 +1250,8 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
1257
1250
  estimateError,
1258
1251
  calculateIntentAddress,
1259
1252
  calculateOriginAndDestinationIntentAddresses,
1260
- committedIntentConfig,
1261
- isLoadingCommittedConfig,
1253
+ committedIntent,
1254
+ isLoadingCommittedIntent,
1262
1255
  committedConfigError,
1263
1256
  commitIntent,
1264
1257
  commitIntentPending,
@@ -1269,9 +1262,8 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
1269
1262
  executeIntentPending,
1270
1263
  executeIntentSuccess,
1271
1264
  executeIntentError,
1272
- getIntent,
1265
+ getIntentFromQuoteIntent,
1273
1266
  operationHashes,
1274
- callIntentCallsPayload,
1275
1267
  sendOriginTransaction,
1276
1268
  switchChain,
1277
1269
  isSwitchingChain,
@@ -1296,11 +1288,11 @@ export function useTrails(config: UseTrailsConfig): UseTrailsReturn {
1296
1288
  sentMetaTxns,
1297
1289
  clearIntent,
1298
1290
  intentReceiptStatus,
1299
- createIntent,
1300
- createIntentPending,
1301
- createIntentSuccess,
1302
- createIntentError,
1303
- createIntentArgs,
1291
+ quoteIntent,
1292
+ quoteIntentPending,
1293
+ quoteIntentSuccess,
1294
+ quoteIntentError,
1295
+ quoteIntentArgs,
1304
1296
  originCallParams,
1305
1297
  updateOriginCallParams,
1306
1298
  originBlockTimestamp,
@@ -52,6 +52,7 @@ export async function attemptUserDepositTx({
52
52
  executeIntentFn,
53
53
  depositRecipientOverride,
54
54
  isSameChainSameToken,
55
+ destinationCalldata,
55
56
  }: {
56
57
  originTokenAddress: string
57
58
  paymasterUrl?: string
@@ -80,7 +81,7 @@ export async function attemptUserDepositTx({
80
81
  selectedFeeToken?: SelectedFeeToken
81
82
  walletId?: string
82
83
  abortSignal?: AbortSignal
83
- checkoutOnHandlers?: CheckoutOnHandlers
84
+ checkoutOnHandlers?: Partial<CheckoutOnHandlers>
84
85
  intentId?: string
85
86
  executeIntentFn?: (params: {
86
87
  intentId: string
@@ -89,6 +90,7 @@ export async function attemptUserDepositTx({
89
90
  }) => Promise<ExecuteIntentResponse>
90
91
  depositRecipientOverride?: string
91
92
  isSameChainSameToken?: boolean
93
+ destinationCalldata?: string
92
94
  }): Promise<TransactionReceipt | null> {
93
95
  let depositUserTxnReceipt: TransactionReceipt | null = null
94
96
  const originChainId = chain.id
@@ -203,6 +205,7 @@ export async function attemptUserDepositTx({
203
205
  checkoutOnHandlers,
204
206
  isSameChainSameToken,
205
207
  recipient: effectiveDepositRecipient,
208
+ destinationCalldata,
206
209
  })
207
210
  }
208
211
 
@@ -62,7 +62,7 @@ export async function attemptGaslessDeposit({
62
62
  feeOptions?: GasFeeOptions
63
63
  selectedFeeToken?: SelectedFeeToken
64
64
  abortSignal?: AbortSignal
65
- checkoutOnHandlers?: CheckoutOnHandlers
65
+ checkoutOnHandlers?: Partial<CheckoutOnHandlers>
66
66
  intentId?: string
67
67
  onTransactionStateChange?: (transactionStates: TransactionState[]) => void
68
68
  transactionStates?: TransactionState[]
@@ -5,7 +5,7 @@ import type {
5
5
  WalletClient,
6
6
  TransactionReceipt,
7
7
  } from "viem"
8
- import { parseUnits } from "viem"
8
+ import { parseUnits, encodeFunctionData } from "viem"
9
9
  import type { TransactionState } from "../../transactions.js"
10
10
  import type { CheckoutOnHandlers } from "../../widget/hooks/useCheckout.js"
11
11
  import { logger } from "../../logger.js"
@@ -15,12 +15,14 @@ import {
15
15
  buildSameChainSameTokenTransactionParams,
16
16
  sendOriginTransaction,
17
17
  } from "../../intents.js"
18
+ import { getIsCustomCalldata } from "../../contractUtils.js"
18
19
  import { estimateGasLimit } from "../../estimate.js"
19
20
  import { attemptSwitchChain } from "../../chainSwitch.js"
20
21
  import { requestWithTimeout } from "../../utils.js"
21
22
  import { updatePersistentToast } from "../../toast.js"
22
23
  import { getChainInfo } from "../../chains.js"
23
24
  import { trackTransactionConfirmed } from "../../analytics.js"
25
+ import { zeroAddress } from "viem"
24
26
 
25
27
  export async function attemptStandardDeposit({
26
28
  originTokenAddress,
@@ -47,6 +49,7 @@ export async function attemptStandardDeposit({
47
49
  checkoutOnHandlers,
48
50
  isSameChainSameToken,
49
51
  recipient,
52
+ destinationCalldata,
50
53
  }: {
51
54
  originTokenAddress: string
52
55
  firstPreconditionMin: string
@@ -69,9 +72,10 @@ export async function attemptStandardDeposit({
69
72
  originTokenSymbol: string
70
73
  destinationTokenSymbol: string
71
74
  depositAmountUsd: number
72
- checkoutOnHandlers?: CheckoutOnHandlers
75
+ checkoutOnHandlers?: Partial<CheckoutOnHandlers>
73
76
  isSameChainSameToken?: boolean
74
77
  recipient?: string
78
+ destinationCalldata?: string
75
79
  }): Promise<TransactionReceipt | null> {
76
80
  let depositUserTxnReceipt: TransactionReceipt | null = null
77
81
  const usingLIfi = false
@@ -100,9 +104,10 @@ export async function attemptStandardDeposit({
100
104
  // For cross-chain deposits, send to intent address for backend processing
101
105
  const originCallParamsBase = isSameChainSameToken
102
106
  ? buildSameChainSameTokenTransactionParams({
103
- hasCustomCalldata: false,
107
+ hasCustomCalldata: getIsCustomCalldata(destinationCalldata),
104
108
  recipient: recipient || originIntentAddress,
105
109
  effectiveOriginTokenAddress: originTokenAddress,
110
+ destinationCalldata,
106
111
  swapAmount: firstPreconditionMin,
107
112
  effectiveOriginChainId: originChainId,
108
113
  effectiveOriginChain: chain,
@@ -116,6 +121,122 @@ export async function attemptStandardDeposit({
116
121
  chain,
117
122
  })
118
123
 
124
+ const hasCustomCalldata = isSameChainSameToken
125
+ ? getIsCustomCalldata(destinationCalldata)
126
+ : false
127
+
128
+ if (
129
+ isSameChainSameToken &&
130
+ originTokenAddress !== zeroAddress &&
131
+ hasCustomCalldata &&
132
+ !dryMode &&
133
+ recipient
134
+ ) {
135
+ // ERC20 custom calldata requires approval to the recipient contract
136
+ const erc20Abi = [
137
+ {
138
+ name: "allowance",
139
+ type: "function",
140
+ stateMutability: "view",
141
+ inputs: [
142
+ { name: "owner", type: "address" },
143
+ { name: "spender", type: "address" },
144
+ ],
145
+ outputs: [{ type: "uint256" }],
146
+ } as const,
147
+ {
148
+ name: "approve",
149
+ type: "function",
150
+ stateMutability: "nonpayable",
151
+ inputs: [
152
+ { name: "spender", type: "address" },
153
+ { name: "amount", type: "uint256" },
154
+ ],
155
+ outputs: [{ type: "bool" }],
156
+ } as const,
157
+ ] as const
158
+
159
+ const currentAllowance = (await publicClient.readContract({
160
+ address: originTokenAddress as `0x${string}`,
161
+ abi: erc20Abi,
162
+ functionName: "allowance",
163
+ args: [account.address, recipient as `0x${string}`],
164
+ })) as bigint
165
+
166
+ const requiredAmount = BigInt(firstPreconditionMin)
167
+
168
+ if (currentAllowance < requiredAmount) {
169
+ logger.console.log(
170
+ "[trails-sdk] Insufficient allowance, sending approve transaction...",
171
+ )
172
+
173
+ const approveData = encodeFunctionData({
174
+ abi: erc20Abi,
175
+ functionName: "approve",
176
+ args: [recipient as `0x${string}`, requiredAmount],
177
+ }) as `0x${string}`
178
+
179
+ const approveHash = await sendOriginTransaction(
180
+ account,
181
+ walletClient,
182
+ {
183
+ to: originTokenAddress as `0x${string}`,
184
+ data: approveData,
185
+ value: 0n,
186
+ chain,
187
+ },
188
+ {
189
+ transactionType: "token_approve",
190
+ depositTokenAmountUsd: depositAmountUsd?.toString(),
191
+ },
192
+ )
193
+
194
+ const approveReceipt = await publicClient.waitForTransactionReceipt({
195
+ hash: approveHash,
196
+ })
197
+
198
+ logger.console.log(
199
+ "[trails-sdk] Approve transaction confirmed:",
200
+ approveReceipt,
201
+ )
202
+
203
+ // Poll to ensure allowance is updated on-chain before proceeding
204
+ let updatedAllowance = currentAllowance
205
+ const maxPollAttempts = 15 // 30 seconds at 2s intervals
206
+ let pollAttempts = 0
207
+
208
+ while (
209
+ updatedAllowance < requiredAmount &&
210
+ pollAttempts < maxPollAttempts
211
+ ) {
212
+ await new Promise((resolve) => setTimeout(resolve, 2000)) // Wait 2 seconds
213
+ updatedAllowance = (await publicClient.readContract({
214
+ address: originTokenAddress as `0x${string}`,
215
+ abi: erc20Abi,
216
+ functionName: "allowance",
217
+ args: [account.address, recipient as `0x${string}`],
218
+ })) as bigint
219
+ pollAttempts++
220
+ logger.console.log(
221
+ `[trails-sdk] Polling allowance (attempt ${pollAttempts}): ${updatedAllowance.toString()}`,
222
+ )
223
+ }
224
+
225
+ if (updatedAllowance < requiredAmount) {
226
+ throw new Error(
227
+ "Allowance not updated after approve transaction - RPC may be delayed or transaction failed",
228
+ )
229
+ }
230
+
231
+ logger.console.log(
232
+ "[trails-sdk] Allowance confirmed updated:",
233
+ updatedAllowance.toString(),
234
+ )
235
+ } else {
236
+ logger.console.log("[trails-sdk] Sufficient allowance, skipping approve")
237
+ }
238
+ }
239
+
119
240
  // Estimate gas limit for consistency with actual transaction
120
241
  const gasLimit = await estimateGasLimit(
121
242
  publicClient,