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.
- package/dist/aave.d.ts.map +1 -1
- package/dist/{ccip-BpQGQiWq.js → ccip-Dl3umoGg.js} +5 -5
- package/dist/{index-DsJM5F-V.js → index-sMS_ge1R.js} +13958 -13860
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +596 -565
- package/dist/intents.d.ts +1 -1
- package/dist/intents.d.ts.map +1 -1
- package/dist/morpho.d.ts.map +1 -1
- package/dist/mutations.d.ts +2 -2
- package/dist/mutations.d.ts.map +1 -1
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/trails.d.ts +9 -10
- package/dist/trails.d.ts.map +1 -1
- package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +3 -2
- package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -1
- package/dist/transactionIntent/deposits/gaslessDeposit.d.ts +1 -1
- package/dist/transactionIntent/deposits/gaslessDeposit.d.ts.map +1 -1
- package/dist/transactionIntent/deposits/standardDeposit.d.ts +3 -2
- package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -1
- package/dist/transactionIntent/handlers/crossChain.d.ts +1 -1
- package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -1
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts +3 -2
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -1
- package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -1
- package/dist/transactionIntent/types.d.ts +1 -1
- package/dist/transactionIntent/types.d.ts.map +1 -1
- package/dist/widget/components/FeeOptions.d.ts +2 -1
- package/dist/widget/components/FeeOptions.d.ts.map +1 -1
- package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
- package/dist/widget/hooks/useQuote.d.ts +32 -1
- package/dist/widget/hooks/useQuote.d.ts.map +1 -1
- package/dist/widget/hooks/useSendForm.d.ts +1 -1
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/index.js +1 -1
- package/package.json +7 -7
- package/src/aave.ts +1 -0
- package/src/index.ts +1 -1
- package/src/indexerClient.ts +1 -1
- package/src/intents.ts +2 -2
- package/src/morpho.ts +3 -2
- package/src/mutations.ts +53 -5
- package/src/prepareSend.ts +12 -1
- package/src/trails.ts +57 -65
- package/src/trailsClient.ts +1 -1
- package/src/transactionIntent/deposits/depositOrchestrator.ts +4 -1
- package/src/transactionIntent/deposits/gaslessDeposit.ts +1 -1
- package/src/transactionIntent/deposits/standardDeposit.ts +124 -3
- package/src/transactionIntent/handlers/crossChain.ts +14 -9
- package/src/transactionIntent/handlers/sameChainSameToken.ts +32 -12
- package/src/transactionIntent/quote/quoteHelpers.ts +4 -11
- package/src/transactionIntent/types.ts +1 -1
- package/src/widget/components/FeeOptions.tsx +2 -1
- package/src/widget/components/PoolDeposit.tsx +68 -4
- package/src/widget/hooks/useDebugScreens.ts +11 -11
- package/src/widget/hooks/useQuote.ts +54 -5
- 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:
|
|
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
|
-
|
|
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
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
"",
|
|
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
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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]
|
|
192
|
-
logger.console.log("[trails-sdk]
|
|
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:
|
|
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
|
-
|
|
24
|
-
|
|
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:
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
505
|
+
label: "Deposit",
|
|
506
506
|
},
|
|
507
507
|
{
|
|
508
508
|
transactionHash:
|