0xtrails 0.4.0 → 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 (57) hide show
  1. package/dist/aave.d.ts.map +1 -1
  2. package/dist/{ccip-BpQGQiWq.js → ccip-Dl3umoGg.js} +5 -5
  3. package/dist/{index-DsJM5F-V.js → index-sMS_ge1R.js} +13958 -13860
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +596 -565
  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 +32 -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/indexerClient.ts +1 -1
  40. package/src/intents.ts +2 -2
  41. package/src/morpho.ts +3 -2
  42. package/src/mutations.ts +53 -5
  43. package/src/prepareSend.ts +12 -1
  44. package/src/trails.ts +57 -65
  45. package/src/trailsClient.ts +1 -1
  46. package/src/transactionIntent/deposits/depositOrchestrator.ts +4 -1
  47. package/src/transactionIntent/deposits/gaslessDeposit.ts +1 -1
  48. package/src/transactionIntent/deposits/standardDeposit.ts +124 -3
  49. package/src/transactionIntent/handlers/crossChain.ts +14 -9
  50. package/src/transactionIntent/handlers/sameChainSameToken.ts +32 -12
  51. package/src/transactionIntent/quote/quoteHelpers.ts +4 -11
  52. package/src/transactionIntent/types.ts +1 -1
  53. package/src/widget/components/FeeOptions.tsx +2 -1
  54. package/src/widget/components/PoolDeposit.tsx +68 -4
  55. package/src/widget/hooks/useDebugScreens.ts +11 -11
  56. package/src/widget/hooks/useQuote.ts +54 -5
  57. package/src/widget/hooks/useSendForm.ts +2 -2
@@ -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,
@@ -43,7 +43,7 @@ import {
43
43
  } from "../../sequenceWallet.js"
44
44
  import { getIntentArgs } from "../quote/quoteHelpers.js"
45
45
  import {
46
- getIntent,
46
+ quoteIntent,
47
47
  commitIntent,
48
48
  buildCrossChainDepositParams,
49
49
  } from "../../intents.js"
@@ -177,7 +177,7 @@ export async function handleCrossChain({
177
177
  quoteProvider?: string | null
178
178
  fundMethod?: string
179
179
  mode?: "pay" | "fund" | "earn" | "swap" | "receive"
180
- checkoutOnHandlers?: CheckoutOnHandlers
180
+ checkoutOnHandlers?: Partial<CheckoutOnHandlers>
181
181
  selectedFeeToken?: SelectedFeeToken
182
182
  walletId?: string
183
183
  abortSignal?: AbortSignal
@@ -438,13 +438,17 @@ export async function handleCrossChain({
438
438
 
439
439
  logger.console.log("[trails-sdk] Creating intent with args:", intentArgs)
440
440
 
441
- const { intent, gasFeeOptions } = await getIntent(trailsClient, intentArgs, {
442
- originTokenSymbol,
443
- destinationTokenSymbol,
444
- feeTokenSymbol: originTokenSymbol,
445
- })
446
- logger.console.log("[trails-sdk] Got intent:", intent)
447
- logger.console.log("[trails-sdk] Got gasFeeOptions:", gasFeeOptions)
441
+ const { intent, gasFeeOptions } = await quoteIntent(
442
+ trailsClient,
443
+ intentArgs,
444
+ {
445
+ originTokenSymbol,
446
+ destinationTokenSymbol,
447
+ feeTokenSymbol: originTokenSymbol,
448
+ },
449
+ )
450
+ logger.console.log("[trails-sdk] Quote intent:", intent)
451
+ logger.console.log("[trails-sdk] Quote intent gasFeeOptions:", gasFeeOptions)
448
452
 
449
453
  if (!intent.preconditions?.length || !intent.calls?.length) {
450
454
  throw new Error("Invalid intent")
@@ -779,6 +783,7 @@ export async function handleCrossChain({
779
783
  walletId,
780
784
  abortSignal,
781
785
  intentId: intent.intentId,
786
+ executeIntentFn,
782
787
  })
783
788
 
784
789
  // In gasless mode, depositUserTxnReceipt will be null because the transaction
@@ -1,5 +1,5 @@
1
1
  import type { Account, Chain, WalletClient, TransactionReceipt } from "viem"
2
- import { createPublicClient, http, formatUnits } from "viem"
2
+ import { createPublicClient, http, formatUnits, ethAddress } from "viem"
3
3
  import type { TrailsApi } from "@0xsequence/trails-api"
4
4
  import type { MetaTxnReceipt, PrepareSendReturn, SendReturn } from "../types.js"
5
5
  import type { TransactionState } from "../../transactions.js"
@@ -21,7 +21,7 @@ import { getTestnetChainInfo } from "../../chains.js"
21
21
  import { getIsCustomCalldata } from "../../contractUtils.js"
22
22
  import {
23
23
  buildSameChainSameTokenTransactionParams,
24
- getIntent,
24
+ quoteIntent,
25
25
  commitIntent,
26
26
  } from "../../intents.js"
27
27
  import { estimateGasLimit } from "../../estimate.js"
@@ -36,6 +36,7 @@ import { getChainInfo } from "../../chains.js"
36
36
  import { getTransactionStateFromReceipt } from "../execution/transactionState.js"
37
37
  import { calcAmountUsdPrice } from "../../prices.js"
38
38
  import { pollIntentReceipt } from "../../intentReceiptPoller.js"
39
+ import { zeroAddress } from "viem"
39
40
 
40
41
  /**
41
42
  * @description
@@ -87,6 +88,7 @@ export async function handleSameChainSameToken({
87
88
  destinationTokenPriceUsd,
88
89
  originNativeTokenPriceUsd,
89
90
  slippageTolerance,
91
+ quoteProvider,
90
92
  checkoutOnHandlers,
91
93
  mode,
92
94
  fundMethod,
@@ -117,7 +119,8 @@ export async function handleSameChainSameToken({
117
119
  destinationTokenPriceUsd?: number | null
118
120
  originNativeTokenPriceUsd?: number | null
119
121
  slippageTolerance: string
120
- checkoutOnHandlers?: CheckoutOnHandlers
122
+ quoteProvider?: string | null
123
+ checkoutOnHandlers?: Partial<CheckoutOnHandlers>
121
124
  mode?: "pay" | "fund" | "earn" | "swap" | "receive"
122
125
  fundMethod?: string
123
126
  paymasterUrl?: string
@@ -174,7 +177,7 @@ export async function handleSameChainSameToken({
174
177
  destinationSalt,
175
178
  slippageTolerance,
176
179
  TradeType.EXACT_INPUT,
177
- "", // quoteProvider - empty for same-chain
180
+ quoteProvider || "",
178
181
  )
179
182
 
180
183
  logger.console.log(
@@ -182,14 +185,18 @@ export async function handleSameChainSameToken({
182
185
  intentArgs,
183
186
  )
184
187
 
185
- const { intent, gasFeeOptions } = await getIntent(trailsClient, intentArgs, {
186
- originTokenSymbol,
187
- destinationTokenSymbol,
188
- feeTokenSymbol: originTokenSymbol,
189
- })
188
+ const { intent, gasFeeOptions } = await quoteIntent(
189
+ trailsClient,
190
+ intentArgs,
191
+ {
192
+ originTokenSymbol,
193
+ destinationTokenSymbol,
194
+ feeTokenSymbol: originTokenSymbol,
195
+ },
196
+ )
190
197
 
191
- logger.console.log("[trails-sdk] Got intent:", intent)
192
- logger.console.log("[trails-sdk] Got gasFeeOptions:", gasFeeOptions)
198
+ logger.console.log("[trails-sdk] Quote intent:", intent)
199
+ logger.console.log("[trails-sdk] Quote intent gasFeeOptions:", gasFeeOptions)
193
200
 
194
201
  if (!intent.preconditions?.length || !intent.calls?.length) {
195
202
  throw new Error("Invalid intent")
@@ -280,9 +287,21 @@ export async function handleSameChainSameToken({
280
287
  // Use runtime selectedFeeToken if provided, otherwise fall back to the one from prepareSend
281
288
  const effectiveSelectedFeeToken =
282
289
  runtimeSelectedFeeToken ?? selectedFeeToken
290
+ // Check if gasless flow is enabled:
291
+ // - selectedFeeToken must exist and not be null/undefined
292
+ // - tokenAddress must not be native token (zeroAddress or ethAddress)
293
+ // - walletId must not be sequence-waas
283
294
  const effectiveGasless =
284
295
  effectiveSelectedFeeToken !== null &&
285
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() &&
286
305
  walletId !== "sequence-waas"
287
306
  logger.console.log(
288
307
  "[trails-sdk] [FEE-SELECT] [GASLESS-FLOW] send() called for same-chain:",
@@ -379,7 +398,7 @@ export async function handleSameChainSameToken({
379
398
  explorerUrl: "",
380
399
  chainId: effectiveOriginChainId,
381
400
  state: "pending",
382
- label: effectiveGasless ? "Deposit" : "Execute",
401
+ label: "Deposit",
383
402
  }
384
403
 
385
404
  const executeState: TransactionState = {
@@ -447,6 +466,7 @@ export async function handleSameChainSameToken({
447
466
  executeIntentFn,
448
467
  depositRecipientOverride: recipient,
449
468
  isSameChainSameToken: true,
469
+ destinationCalldata,
450
470
  })
451
471
 
452
472
  // attemptUserDepositTx handles both gasless and non-gasless flows
@@ -1,5 +1,4 @@
1
1
  import type { QuoteIntentRequest } from "@0xsequence/trails-api"
2
- import { QuoteProviderType } from "@0xsequence/trails-api"
3
2
  import { getIsCustomCalldata } from "../../contractUtils.js"
4
3
  import type { TradeType } from "../types.js"
5
4
 
@@ -20,8 +19,9 @@ export function getIntentArgs(
20
19
  ): QuoteIntentRequest {
21
20
  const hasCustomCalldata = getIsCustomCalldata(destinationCalldata)
22
21
 
23
- if (!provider || provider === "auto") {
24
- provider = undefined
22
+ let effectiveProvider = provider
23
+ if (provider === "auto") {
24
+ effectiveProvider = undefined
25
25
  }
26
26
 
27
27
  const intentArgs: QuoteIntentRequest = {
@@ -37,14 +37,7 @@ export function getIntentArgs(
37
37
  destinationCallValue: "0",
38
38
  options: {
39
39
  slippageTolerance: Number(slippageTolerance),
40
- quoteProvider:
41
- provider === "relay"
42
- ? QuoteProviderType.RELAY
43
- : provider === "cctp"
44
- ? QuoteProviderType.CCTPV2
45
- : provider === "lifi"
46
- ? QuoteProviderType.LIFI
47
- : undefined,
40
+ quoteProvider: effectiveProvider || undefined,
48
41
  },
49
42
  tradeType,
50
43
  }
@@ -72,7 +72,7 @@ export type PrepareSendOptions = {
72
72
  quoteProvider?: string | null
73
73
  fundMethod?: string
74
74
  mode?: "pay" | "fund" | "earn" | "swap" | "receive"
75
- checkoutOnHandlers?: CheckoutOnHandlers
75
+ checkoutOnHandlers?: Partial<CheckoutOnHandlers>
76
76
  refundAddress?: string
77
77
  selectedFeeToken?: SelectedFeeToken
78
78
  walletId?: string
@@ -11,6 +11,7 @@ import { getTokenImageUrl } from "../../tokens.js"
11
11
  import { TokenImage } from "./TokenImage.js"
12
12
  import { ethAddress, zeroAddress } from "viem"
13
13
  import type { FeeOption as APIFeeOption } from "../../widget/hooks/useSelectedFeeToken.js"
14
+ import { SelectedFeeToken } from "../../prepareSend.js"
14
15
 
15
16
  const ZERO_ADDRESS = zeroAddress.toLowerCase()
16
17
  const ETH_ADDRESS = ethAddress.toLowerCase()
@@ -67,7 +68,7 @@ const safeFormatUsdDisplay = (option: APIFeeOption): string => {
67
68
 
68
69
  interface FeeOptionsProps {
69
70
  feeOptions: APIFeeOption[]
70
- selectedFeeToken: APIFeeOption | null
71
+ selectedFeeToken: APIFeeOption | SelectedFeeToken | null
71
72
  setSelectedFeeToken: (token: APIFeeOption | null) => void
72
73
  chainId?: number
73
74
  isRefetching?: boolean // When true, the fee quote is stale and being refreshed, so hide the component
@@ -5,10 +5,10 @@ import {
5
5
  Search,
6
6
  Loader2,
7
7
  } from "lucide-react"
8
- import { useEffect, useState, useRef } from "react"
8
+ import { useEffect, useState, useRef, useMemo } from "react"
9
9
  import type React from "react"
10
10
  import type { Account, WalletClient } from "viem"
11
- import { zeroAddress } from "viem"
11
+ import { parseUnits, zeroAddress } from "viem"
12
12
  import type { TransactionState } from "../../transactions.js"
13
13
  import type { OnCompleteProps } from "../hooks/useSendForm.js"
14
14
  import type { CheckoutOnHandlers } from "../hooks/useCheckout.js"
@@ -36,6 +36,9 @@ import type { SupportedToken } from "../../tokens.js"
36
36
  import { logger } from "../../logger.js"
37
37
  import { DynamicSizeInputField } from "./DynamicSizeInputField.js"
38
38
  import { FeeOptions } from "./FeeOptions.js"
39
+ import { generateAaveDepositCalldata } from "../../aave.js"
40
+ import { generateMorphoDepositCalldata } from "../../morpho.js"
41
+ import { TRAILS_ROUTER_PLACEHOLDER_AMOUNT } from "../../trailsRouter.js"
39
42
 
40
43
  interface PoolDepositProps {
41
44
  account?: Account
@@ -106,6 +109,67 @@ export const PoolDeposit: React.FC<PoolDepositProps> = ({
106
109
  allSupportedTokens: false,
107
110
  })
108
111
 
112
+ // Memoized generated calldata
113
+ const generatedDepositCalldata = useMemo(() => {
114
+ if (!selectedPool || !amount || !walletClient || Number(amount) <= 0) {
115
+ logger.console.log(
116
+ "Skipping calldata generation: missing pool/amount/wallet or invalid amount",
117
+ )
118
+ return undefined
119
+ }
120
+
121
+ try {
122
+ const decimals = selectedPool.token.decimals
123
+ if (typeof decimals !== "number" || decimals < 0 || decimals > 18) {
124
+ throw new Error(`Invalid decimals: ${decimals}`)
125
+ }
126
+
127
+ // Check if same-chain same-token for direct amount usage
128
+ const isSameChainSameToken =
129
+ originToken &&
130
+ originToken.chainId === selectedPool.chainId &&
131
+ (originToken.contractAddress ?? zeroAddress).toLowerCase() ===
132
+ selectedPool.token.address.toLowerCase()
133
+
134
+ let amountForCalldata: string
135
+ if (isSameChainSameToken) {
136
+ // Parse real amount with pool decimals for direct deposit
137
+ const parsedAmount = parseUnits(amount, decimals)
138
+ amountForCalldata = parsedAmount.toString()
139
+ logger.console.log(
140
+ `Same-chain same-token deposit: Parsed amount: ${amount} -> ${parsedAmount} wei (decimals: ${decimals})`,
141
+ )
142
+ } else {
143
+ // Use placeholder for wrapping in routed flows
144
+ amountForCalldata = TRAILS_ROUTER_PLACEHOLDER_AMOUNT.toString()
145
+ logger.console.log(
146
+ `Routed deposit (different-token or cross-chain): Using placeholder for ${selectedPool.protocol} pool: ${selectedPool.name}`,
147
+ )
148
+ }
149
+
150
+ logger.console.log(
151
+ `Generating deposit calldata for ${selectedPool.protocol} pool: ${selectedPool.name} (amount: ${amountForCalldata})`,
152
+ )
153
+
154
+ switch (selectedPool.protocol.toLowerCase()) {
155
+ case "aave":
156
+ return generateAaveDepositCalldata(
157
+ walletClient,
158
+ selectedPool,
159
+ amountForCalldata,
160
+ )
161
+ case "morpho":
162
+ return generateMorphoDepositCalldata(walletClient, amountForCalldata)
163
+ default:
164
+ logger.console.warn(`Unsupported protocol: ${selectedPool.protocol}`)
165
+ return undefined
166
+ }
167
+ } catch (error) {
168
+ logger.console.error("Error generating deposit calldata:", error)
169
+ return undefined
170
+ }
171
+ }, [walletClient, selectedPool, amount, originToken])
172
+
109
173
  // Use useSendForm for quote functionality when both token and pool are selected
110
174
  const {
111
175
  balanceFormatted,
@@ -125,7 +189,7 @@ export const PoolDeposit: React.FC<PoolDepositProps> = ({
125
189
  toRecipient: selectedPool?.depositAddress,
126
190
  toChainId: selectedPool?.chainId,
127
191
  toToken: selectedPool?.token.address,
128
- toCalldata: undefined,
192
+ toCalldata: generatedDepositCalldata,
129
193
  walletClient,
130
194
  onTransactionStateChange,
131
195
  onError,
@@ -521,7 +585,7 @@ export const PoolDeposit: React.FC<PoolDepositProps> = ({
521
585
  {/* Fee Options */}
522
586
  <FeeOptions
523
587
  feeOptions={feeOptions || []}
524
- selectedFeeToken={selectedFeeToken}
588
+ selectedFeeToken={selectedFeeToken as any}
525
589
  setSelectedFeeToken={(token) => setSelectedFeeToken(token as any)}
526
590
  chainId={originToken?.chainId}
527
591
  isRefetching={isLoadingQuote}
@@ -182,7 +182,7 @@ export const useDebugScreens = ({
182
182
  "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
183
183
  chainId: 137,
184
184
  state: "pending",
185
- label: "Transfer",
185
+ label: "Deposit",
186
186
  },
187
187
  {
188
188
  transactionHash:
@@ -207,7 +207,7 @@ export const useDebugScreens = ({
207
207
  "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
208
208
  chainId: 137,
209
209
  state: "confirmed",
210
- label: "Transfer",
210
+ label: "Deposit",
211
211
  },
212
212
  {
213
213
  transactionHash:
@@ -232,7 +232,7 @@ export const useDebugScreens = ({
232
232
  "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
233
233
  chainId: 137,
234
234
  state: "confirmed",
235
- label: "Transfer",
235
+ label: "Deposit",
236
236
  },
237
237
  {
238
238
  transactionHash:
@@ -257,7 +257,7 @@ export const useDebugScreens = ({
257
257
  "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
258
258
  chainId: 137,
259
259
  state: "pending",
260
- label: "Transfer",
260
+ label: "Deposit",
261
261
  },
262
262
  {
263
263
  transactionHash:
@@ -291,7 +291,7 @@ export const useDebugScreens = ({
291
291
  "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
292
292
  chainId: 137,
293
293
  state: "confirmed",
294
- label: "Transfer",
294
+ label: "Deposit",
295
295
  },
296
296
  {
297
297
  transactionHash:
@@ -325,7 +325,7 @@ export const useDebugScreens = ({
325
325
  "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
326
326
  chainId: 137,
327
327
  state: "confirmed",
328
- label: "Transfer",
328
+ label: "Deposit",
329
329
  },
330
330
  {
331
331
  transactionHash:
@@ -359,7 +359,7 @@ export const useDebugScreens = ({
359
359
  "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
360
360
  chainId: 137,
361
361
  state: "confirmed",
362
- label: "Transfer",
362
+ label: "Deposit",
363
363
  },
364
364
  {
365
365
  transactionHash:
@@ -393,7 +393,7 @@ export const useDebugScreens = ({
393
393
  "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
394
394
  chainId: 137,
395
395
  state: "confirmed",
396
- label: "Transfer",
396
+ label: "Deposit",
397
397
  },
398
398
  {
399
399
  transactionHash:
@@ -436,7 +436,7 @@ export const useDebugScreens = ({
436
436
  "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
437
437
  chainId: 137,
438
438
  state: "confirmed",
439
- label: "Transfer",
439
+ label: "Deposit",
440
440
  },
441
441
  {
442
442
  transactionHash:
@@ -470,7 +470,7 @@ export const useDebugScreens = ({
470
470
  "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
471
471
  chainId: 137,
472
472
  state: "confirmed",
473
- label: "Transfer",
473
+ label: "Deposit",
474
474
  },
475
475
  {
476
476
  transactionHash:
@@ -502,7 +502,7 @@ export const useDebugScreens = ({
502
502
  "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
503
503
  chainId: 137,
504
504
  state: "confirmed",
505
- label: "Transfer",
505
+ label: "Deposit",
506
506
  },
507
507
  {
508
508
  transactionHash: