0xtrails 0.2.4 → 0.2.5
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 +8 -0
- package/dist/aave.d.ts.map +1 -1
- package/dist/{ccip-BlV1Mry3.js → ccip-CXlshvBY.js} +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/error.d.ts +1 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/estimate.d.ts +52 -0
- package/dist/estimate.d.ts.map +1 -1
- package/dist/{index-BNWCIGfQ.js → index-_QuyGrjU.js} +72332 -72246
- package/dist/index.js +2 -2
- package/dist/intents.d.ts +40 -0
- package/dist/intents.d.ts.map +1 -1
- package/dist/metaTxnMonitor.d.ts +3 -3
- package/dist/metaTxnMonitor.d.ts.map +1 -1
- package/dist/metaTxns.d.ts +3 -3
- package/dist/metaTxns.d.ts.map +1 -1
- package/dist/morpho.d.ts +8 -0
- package/dist/morpho.d.ts.map +1 -1
- package/dist/prepareSend.d.ts +16 -6
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/queryParams.d.ts.map +1 -1
- package/dist/relayer.d.ts +6 -6
- package/dist/relayer.d.ts.map +1 -1
- package/dist/sequenceWallet.d.ts +2 -2
- package/dist/sequenceWallet.d.ts.map +1 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/wallets.d.ts.map +1 -1
- package/dist/widget/components/AccountActionsDropdown.d.ts.map +1 -1
- package/dist/widget/components/AccountSettings.d.ts.map +1 -1
- package/dist/widget/components/ClassicSwap.d.ts +2 -0
- package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
- package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
- package/dist/widget/components/ConnectedWallets.d.ts +4 -0
- package/dist/widget/components/ConnectedWallets.d.ts.map +1 -1
- package/dist/widget/components/Earn.d.ts.map +1 -1
- package/dist/widget/components/Fund.d.ts.map +1 -1
- package/dist/widget/components/FundMethods.d.ts.map +1 -1
- package/dist/widget/components/{FundSendForm.d.ts → FundSwap.d.ts} +11 -5
- package/dist/widget/components/FundSwap.d.ts.map +1 -0
- package/dist/widget/components/FundingMethodSelectorButton.d.ts +4 -0
- package/dist/widget/components/FundingMethodSelectorButton.d.ts.map +1 -0
- package/dist/widget/components/Modal.d.ts.map +1 -1
- package/dist/widget/components/Pay.d.ts.map +1 -1
- package/dist/widget/components/PercentageMaxButtons.d.ts +12 -0
- package/dist/widget/components/PercentageMaxButtons.d.ts.map +1 -0
- package/dist/widget/components/{PaySendForm.d.ts → PoolDeposit.d.ts} +11 -34
- package/dist/widget/components/PoolDeposit.d.ts.map +1 -0
- package/dist/widget/components/{SimpleSwap.d.ts → PoolWithdraw.d.ts} +16 -8
- package/dist/widget/components/PoolWithdraw.d.ts.map +1 -0
- package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
- package/dist/widget/components/Receive.d.ts.map +1 -1
- package/dist/widget/components/RecipientSelectorButton.d.ts +4 -0
- package/dist/widget/components/RecipientSelectorButton.d.ts.map +1 -0
- package/dist/widget/components/Recipients.d.ts.map +1 -1
- package/dist/widget/components/RequiredPropsError.d.ts +8 -0
- package/dist/widget/components/RequiredPropsError.d.ts.map +1 -0
- package/dist/widget/components/ScreenHeader.d.ts.map +1 -1
- package/dist/widget/components/SlippageToleranceSettings.d.ts.map +1 -1
- package/dist/widget/components/Swap.d.ts +1 -0
- package/dist/widget/components/Swap.d.ts.map +1 -1
- package/dist/widget/components/SwapSettings.d.ts.map +1 -1
- package/dist/widget/components/TokenImage.d.ts +1 -0
- package/dist/widget/components/TokenImage.d.ts.map +1 -1
- package/dist/widget/components/TokenList.d.ts.map +1 -1
- package/dist/widget/components/TokenSelector.d.ts.map +1 -1
- package/dist/widget/components/TokenSelectorButton.d.ts +16 -0
- package/dist/widget/components/TokenSelectorButton.d.ts.map +1 -0
- package/dist/widget/components/UserPreferences.d.ts.map +1 -1
- package/dist/widget/components/WaasFeeOptions.d.ts +8 -0
- package/dist/widget/components/WaasFeeOptions.d.ts.map +1 -0
- package/dist/widget/components/WalletConfirmation.d.ts.map +1 -1
- package/dist/widget/components/WalletList.d.ts.map +1 -1
- package/dist/widget/css/compiled.css +2 -0
- package/dist/widget/css/index.css +554 -0
- package/dist/widget/hooks/useBack.d.ts +1 -0
- package/dist/widget/hooks/useBack.d.ts.map +1 -1
- package/dist/widget/hooks/useCheckout.d.ts +1 -1
- package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
- package/dist/widget/hooks/useCurrentScreen.d.ts +1 -1
- package/dist/widget/hooks/useCurrentScreen.d.ts.map +1 -1
- package/dist/widget/hooks/useDefaultTokenSelection.d.ts +3 -3
- package/dist/widget/hooks/useDefaultTokenSelection.d.ts.map +1 -1
- package/dist/widget/hooks/usePayMessage.d.ts.map +1 -1
- package/dist/widget/hooks/useSelectedFundMethod.d.ts +12 -0
- package/dist/widget/hooks/useSelectedFundMethod.d.ts.map +1 -0
- package/dist/widget/hooks/useSelectedRecipient.d.ts.map +1 -1
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/index.js +1 -1
- package/dist/widget/widget.d.ts +4 -4
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +18 -12
- package/src/aave.ts +32 -0
- package/src/config.ts +12 -4
- package/src/constants.ts +2 -0
- package/src/error.ts +19 -1
- package/src/estimate.ts +416 -5
- package/src/intents.ts +161 -11
- package/src/metaTxnMonitor.ts +3 -3
- package/src/metaTxns.ts +3 -5
- package/src/morpho.ts +32 -0
- package/src/prepareSend.ts +503 -166
- package/src/queryParams.ts +2 -1
- package/src/relayer.ts +11 -11
- package/src/sequenceWallet.ts +2 -2
- package/src/tokens.ts +7 -1
- package/src/wallets.ts +8 -0
- package/src/widget/compiled.css +2 -2
- package/src/widget/components/AccountActionsDropdown.tsx +3 -13
- package/src/widget/components/AccountSettings.tsx +6 -24
- package/src/widget/components/ClassicSwap.tsx +111 -155
- package/src/widget/components/ConnectWallet.tsx +4 -37
- package/src/widget/components/ConnectedWallets.tsx +113 -58
- package/src/widget/components/Earn.tsx +73 -589
- package/src/widget/components/Fund.tsx +31 -82
- package/src/widget/components/FundMethods.tsx +82 -159
- package/src/widget/components/FundSwap.tsx +52 -0
- package/src/widget/components/FundingMethodSelectorButton.tsx +60 -0
- package/src/widget/components/Modal.tsx +6 -2
- package/src/widget/components/Pay.tsx +183 -208
- package/src/widget/components/PercentageMaxButtons.tsx +77 -0
- package/src/widget/components/PoolDeposit.tsx +593 -0
- package/src/widget/components/PoolWithdraw.tsx +903 -0
- package/src/widget/components/QuoteDetails.tsx +22 -8
- package/src/widget/components/Receive.tsx +0 -2
- package/src/widget/components/RecipientSelectorButton.tsx +42 -0
- package/src/widget/components/Recipients.tsx +62 -156
- package/src/widget/components/RequiredPropsError.tsx +33 -0
- package/src/widget/components/ScreenHeader.tsx +5 -1
- package/src/widget/components/SlippageToleranceSettings.tsx +2 -1
- package/src/widget/components/Swap.tsx +2 -43
- package/src/widget/components/SwapSettings.tsx +2 -14
- package/src/widget/components/TokenImage.tsx +21 -4
- package/src/widget/components/TokenList.tsx +0 -1
- package/src/widget/components/TokenSelector.tsx +1 -0
- package/src/widget/components/TokenSelectorButton.tsx +75 -0
- package/src/widget/components/UserPreferences.tsx +6 -24
- package/src/widget/components/WaasFeeOptions.tsx +331 -0
- package/src/widget/components/WalletConfirmation.tsx +55 -3
- package/src/widget/components/WalletList.tsx +4 -2
- package/src/widget/hooks/useBack.tsx +2 -0
- package/src/widget/hooks/useCheckout.ts +36 -20
- package/src/widget/hooks/useCurrentScreen.tsx +1 -0
- package/src/widget/hooks/useDefaultTokenSelection.tsx +104 -28
- package/src/widget/hooks/usePayMessage.tsx +86 -11
- package/src/widget/hooks/useSelectedFundMethod.tsx +41 -0
- package/src/widget/hooks/useSelectedRecipient.tsx +10 -0
- package/src/widget/hooks/useSendForm.ts +24 -2
- package/src/widget/index.css +27 -0
- package/src/widget/widget.tsx +169 -111
- package/dist/widget/components/FundSendForm.d.ts.map +0 -1
- package/dist/widget/components/PaySendForm.d.ts.map +0 -1
- package/dist/widget/components/SimpleSwap.d.ts.map +0 -1
- package/dist/widget/hooks/useSwapSettings.d.ts +0 -16
- package/dist/widget/hooks/useSwapSettings.d.ts.map +0 -1
- package/src/widget/components/FundSendForm.tsx +0 -903
- package/src/widget/components/PaySendForm.tsx +0 -869
- package/src/widget/components/SimpleSwap.tsx +0 -983
- package/src/widget/hooks/useSwapSettings.tsx +0 -100
package/src/prepareSend.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
IntentPrecondition,
|
|
5
5
|
} from "@0xsequence/trails-api"
|
|
6
6
|
import type { TrailsAPIClient } from "@0xsequence/trails-api"
|
|
7
|
+
import type { Relayer } from "@0xsequence/relayer"
|
|
7
8
|
import { useQuery } from "@tanstack/react-query"
|
|
8
9
|
import type {
|
|
9
10
|
Account,
|
|
@@ -62,7 +63,12 @@ import {
|
|
|
62
63
|
} from "./decoders.js"
|
|
63
64
|
import { getERC20TransferData } from "./encoders.js"
|
|
64
65
|
import { getFullErrorMessage, InsufficientBalanceError } from "./error.js"
|
|
65
|
-
import {
|
|
66
|
+
import {
|
|
67
|
+
estimateGasCost,
|
|
68
|
+
estimateGasCostUsd,
|
|
69
|
+
estimateGasLimit,
|
|
70
|
+
DEFAULT_MIN_GASLIMIT,
|
|
71
|
+
} from "./estimate.js"
|
|
66
72
|
import { getExplorerUrl } from "./explorer.js"
|
|
67
73
|
import {
|
|
68
74
|
getNeedsIntentEntrypointApproval,
|
|
@@ -73,6 +79,8 @@ import {
|
|
|
73
79
|
import { getIntentEntrypointFeeOptions } from "./intentEntrypoint.js"
|
|
74
80
|
import { useIndexerGatewayClient } from "./indexerClient.js"
|
|
75
81
|
import {
|
|
82
|
+
buildSameChainTransactionParams,
|
|
83
|
+
buildCrossChainDepositParams,
|
|
76
84
|
commitIntentConfig,
|
|
77
85
|
getIntentCallsPayloads as getIntentCallsPayloadsFromIntents,
|
|
78
86
|
sendOriginTransaction,
|
|
@@ -131,7 +139,6 @@ import {
|
|
|
131
139
|
getPaymasterGaslessTransaction,
|
|
132
140
|
sendPaymasterGaslessTransaction,
|
|
133
141
|
} from "./paymasterSend.js"
|
|
134
|
-
import type { RpcRelayer } from "@0xsequence/relayer"
|
|
135
142
|
|
|
136
143
|
export enum TradeType {
|
|
137
144
|
EXACT_INPUT = "EXACT_INPUT",
|
|
@@ -156,8 +163,8 @@ export type PrepareSendOptions = {
|
|
|
156
163
|
dryMode: boolean
|
|
157
164
|
apiClient: SequenceAPIClient
|
|
158
165
|
trailsClient: TrailsAPIClient
|
|
159
|
-
originRelayer:
|
|
160
|
-
destinationRelayer:
|
|
166
|
+
originRelayer: Relayer.RpcRelayer
|
|
167
|
+
destinationRelayer: Relayer.RpcRelayer
|
|
161
168
|
destinationCalldata?: string
|
|
162
169
|
onTransactionStateChange: (transactionStates: TransactionState[]) => void
|
|
163
170
|
sourceTokenPriceUsd?: number | null
|
|
@@ -174,6 +181,7 @@ export type PrepareSendOptions = {
|
|
|
174
181
|
checkoutOnHandlers?: CheckoutOnHandlers
|
|
175
182
|
refundAddress?: string
|
|
176
183
|
selectedFeeToken?: any
|
|
184
|
+
walletId?: string
|
|
177
185
|
}
|
|
178
186
|
|
|
179
187
|
export type PrepareSendFees = {
|
|
@@ -218,6 +226,8 @@ export type PrepareSendQuote = {
|
|
|
218
226
|
transactionStates: TransactionState[]
|
|
219
227
|
gasCostUsd: number
|
|
220
228
|
gasCostUsdDisplay: string
|
|
229
|
+
gasCost: string
|
|
230
|
+
gasCostFormatted: string
|
|
221
231
|
originTokenRate: string
|
|
222
232
|
destinationTokenRate: string
|
|
223
233
|
quoteProvider: QuoteProviderInfo | null
|
|
@@ -385,6 +395,7 @@ export async function prepareSend(
|
|
|
385
395
|
mode,
|
|
386
396
|
checkoutOnHandlers,
|
|
387
397
|
selectedFeeToken,
|
|
398
|
+
walletId,
|
|
388
399
|
} = options
|
|
389
400
|
let { sourceTokenPriceUsd, destinationTokenPriceUsd } = options
|
|
390
401
|
|
|
@@ -568,18 +579,20 @@ export async function prepareSend(
|
|
|
568
579
|
label: isToSameChain && isToSameToken ? "Execute" : "Transfer",
|
|
569
580
|
})
|
|
570
581
|
|
|
571
|
-
// swap (+ bridge tx)
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
582
|
+
// swap (+ bridge tx) - skip for same-chain-same-token as there's no second transaction
|
|
583
|
+
if (!(isToSameChain && isToSameToken)) {
|
|
584
|
+
transactionStates.push({
|
|
585
|
+
transactionHash: "",
|
|
586
|
+
explorerUrl: "",
|
|
587
|
+
chainId: originChainId,
|
|
588
|
+
state: "pending",
|
|
589
|
+
label: isToSameToken
|
|
590
|
+
? "Bridge"
|
|
591
|
+
: isToSameChain && !isToSameToken
|
|
592
|
+
? "Swap"
|
|
593
|
+
: "Swap & Bridge",
|
|
594
|
+
})
|
|
595
|
+
}
|
|
583
596
|
|
|
584
597
|
// additional execute tx on same chain if needed
|
|
585
598
|
if (isToSameChain && hasCustomCalldata && !isToSameToken) {
|
|
@@ -652,6 +665,13 @@ export async function prepareSend(
|
|
|
652
665
|
originNativeTokenPriceUsd,
|
|
653
666
|
slippageTolerance,
|
|
654
667
|
checkoutOnHandlers,
|
|
668
|
+
gasless,
|
|
669
|
+
paymasterUrl,
|
|
670
|
+
selectedFeeToken,
|
|
671
|
+
trailsClient,
|
|
672
|
+
originRelayer,
|
|
673
|
+
mode,
|
|
674
|
+
fundMethod,
|
|
655
675
|
})
|
|
656
676
|
}
|
|
657
677
|
|
|
@@ -693,6 +713,7 @@ export async function prepareSend(
|
|
|
693
713
|
mode,
|
|
694
714
|
checkoutOnHandlers,
|
|
695
715
|
selectedFeeToken,
|
|
716
|
+
walletId,
|
|
696
717
|
})
|
|
697
718
|
}
|
|
698
719
|
|
|
@@ -733,6 +754,7 @@ async function sendHandlerForDifferentChainDifferentToken({
|
|
|
733
754
|
mode,
|
|
734
755
|
checkoutOnHandlers,
|
|
735
756
|
selectedFeeToken,
|
|
757
|
+
walletId,
|
|
736
758
|
}: {
|
|
737
759
|
mainSignerAddress: string
|
|
738
760
|
originChainId: number
|
|
@@ -753,8 +775,8 @@ async function sendHandlerForDifferentChainDifferentToken({
|
|
|
753
775
|
destinationTokenDecimals: number
|
|
754
776
|
gasless: boolean
|
|
755
777
|
paymasterUrl?: string
|
|
756
|
-
originRelayer:
|
|
757
|
-
destinationRelayer:
|
|
778
|
+
originRelayer: Relayer.RpcRelayer
|
|
779
|
+
destinationRelayer: Relayer.RpcRelayer
|
|
758
780
|
walletClient: WalletClient
|
|
759
781
|
publicClient: PublicClient
|
|
760
782
|
chain: Chain
|
|
@@ -771,6 +793,7 @@ async function sendHandlerForDifferentChainDifferentToken({
|
|
|
771
793
|
mode?: "pay" | "fund" | "earn" | "swap" | "receive"
|
|
772
794
|
checkoutOnHandlers?: CheckoutOnHandlers
|
|
773
795
|
selectedFeeToken?: any
|
|
796
|
+
walletId?: string
|
|
774
797
|
}): Promise<PrepareSendReturn> {
|
|
775
798
|
const testnet = isTestnetDebugMode()
|
|
776
799
|
const useCctp = getUseCctp(
|
|
@@ -1120,6 +1143,42 @@ async function sendHandlerForDifferentChainDifferentToken({
|
|
|
1120
1143
|
}
|
|
1121
1144
|
}
|
|
1122
1145
|
|
|
1146
|
+
// Estimate gas limit for the quote (same logic as in attemptNonGaslessUserDeposit)
|
|
1147
|
+
const originCallParamsForEstimate = buildCrossChainDepositParams({
|
|
1148
|
+
originTokenAddress,
|
|
1149
|
+
originIntentAddress,
|
|
1150
|
+
depositAmount: firstPreconditionMin,
|
|
1151
|
+
fee,
|
|
1152
|
+
originChainId,
|
|
1153
|
+
chain,
|
|
1154
|
+
})
|
|
1155
|
+
|
|
1156
|
+
logger.console.log(
|
|
1157
|
+
"[trails-sdk][gas-estimation] About to estimate gas limit for cross-chain quote with params:",
|
|
1158
|
+
{
|
|
1159
|
+
account: account.address,
|
|
1160
|
+
to: originCallParamsForEstimate.to,
|
|
1161
|
+
data: originCallParamsForEstimate.data,
|
|
1162
|
+
value: originCallParamsForEstimate.value,
|
|
1163
|
+
},
|
|
1164
|
+
)
|
|
1165
|
+
|
|
1166
|
+
const estimatedGasLimitForQuote = await estimateGasLimit(
|
|
1167
|
+
publicClient,
|
|
1168
|
+
{
|
|
1169
|
+
account: account.address,
|
|
1170
|
+
to: originCallParamsForEstimate.to,
|
|
1171
|
+
data: originCallParamsForEstimate.data,
|
|
1172
|
+
value: BigInt(originCallParamsForEstimate.value),
|
|
1173
|
+
},
|
|
1174
|
+
"quote",
|
|
1175
|
+
)
|
|
1176
|
+
|
|
1177
|
+
logger.console.log(
|
|
1178
|
+
"[trails-sdk][gas-estimation] Estimated gas limit for cross-chain quote:",
|
|
1179
|
+
estimatedGasLimitForQuote,
|
|
1180
|
+
)
|
|
1181
|
+
|
|
1123
1182
|
const quote = await getNormalizedQuoteObject({
|
|
1124
1183
|
originDepositAddress: originIntentAddress,
|
|
1125
1184
|
destinationDepositAddress: intent.payloads.destinationIntentAddress,
|
|
@@ -1147,6 +1206,7 @@ async function sendHandlerForDifferentChainDifferentToken({
|
|
|
1147
1206
|
originNativeTokenPriceUsd,
|
|
1148
1207
|
quoteProvider: intent.payloads?.quote?.quoteProvider,
|
|
1149
1208
|
noSufficientBalance,
|
|
1209
|
+
estimatedGasLimit: estimatedGasLimitForQuote,
|
|
1150
1210
|
})
|
|
1151
1211
|
|
|
1152
1212
|
// Call onCheckoutQuote callback if provided
|
|
@@ -1154,12 +1214,15 @@ async function sendHandlerForDifferentChainDifferentToken({
|
|
|
1154
1214
|
checkoutOnHandlers.triggerCheckoutQuote(quote)
|
|
1155
1215
|
}
|
|
1156
1216
|
|
|
1157
|
-
// Get intent entrypoint fee options if supported
|
|
1217
|
+
// Get intent entrypoint fee options if supported and gasless is enabled
|
|
1218
|
+
// Note: We fetch fee options whenever gasless is true, regardless of fundMethod,
|
|
1219
|
+
// because gasless scenarios (including tests) need fee collector information
|
|
1220
|
+
// Skip gasless fee options for sequence-waas wallet
|
|
1158
1221
|
let intentEntrypointFeeOptions: any = null
|
|
1159
|
-
if (gasless &&
|
|
1222
|
+
if (gasless && walletId !== "sequence-waas") {
|
|
1160
1223
|
try {
|
|
1161
1224
|
logger.console.log(
|
|
1162
|
-
"[trails-sdk] [GASLESS-FLOW] [FEE-SELECT] Gasless enabled
|
|
1225
|
+
"[trails-sdk] [GASLESS-FLOW] [FEE-SELECT] Gasless enabled, checking intent entrypoint support for chain:",
|
|
1163
1226
|
originChainId,
|
|
1164
1227
|
)
|
|
1165
1228
|
|
|
@@ -1181,9 +1244,13 @@ async function sendHandlerForDifferentChainDifferentToken({
|
|
|
1181
1244
|
error,
|
|
1182
1245
|
)
|
|
1183
1246
|
}
|
|
1247
|
+
} else if (walletId === "sequence-waas") {
|
|
1248
|
+
logger.console.log(
|
|
1249
|
+
"[trails-sdk] [GASLESS-FLOW] [FEE-SELECT] Skipping gasless fee options for sequence-waas wallet",
|
|
1250
|
+
)
|
|
1184
1251
|
} else {
|
|
1185
1252
|
logger.console.log(
|
|
1186
|
-
"[trails-sdk] [GASLESS-FLOW] [FEE-SELECT] Gasless disabled
|
|
1253
|
+
"[trails-sdk] [GASLESS-FLOW] [FEE-SELECT] Gasless disabled, skipping intent entrypoint fee options fetch",
|
|
1187
1254
|
)
|
|
1188
1255
|
}
|
|
1189
1256
|
|
|
@@ -1349,6 +1416,7 @@ async function sendHandlerForDifferentChainDifferentToken({
|
|
|
1349
1416
|
feeOptions: intentEntrypointFeeOptions,
|
|
1350
1417
|
trailsClient,
|
|
1351
1418
|
selectedFeeToken: effectiveSelectedFeeToken,
|
|
1419
|
+
walletId,
|
|
1352
1420
|
})
|
|
1353
1421
|
|
|
1354
1422
|
if (!originUserTxReceipt) {
|
|
@@ -1801,7 +1869,7 @@ async function sendHandlerForDifferentChainDifferentToken({
|
|
|
1801
1869
|
}
|
|
1802
1870
|
|
|
1803
1871
|
checkForDepositTx().catch((error) => {
|
|
1804
|
-
console.error("Error checking for deposit tx", error)
|
|
1872
|
+
logger.console.error("Error checking for deposit tx", error)
|
|
1805
1873
|
})
|
|
1806
1874
|
|
|
1807
1875
|
// Phase 1: Send meta transactions and queue CCTP
|
|
@@ -2019,11 +2087,14 @@ async function sendHandlerForDifferentChainDifferentToken({
|
|
|
2019
2087
|
|
|
2020
2088
|
onTransactionStateChange(transactionStates)
|
|
2021
2089
|
} catch (error) {
|
|
2022
|
-
console.error(
|
|
2090
|
+
logger.console.error(
|
|
2091
|
+
"Error decoding destination tx events",
|
|
2092
|
+
error,
|
|
2093
|
+
)
|
|
2023
2094
|
}
|
|
2024
2095
|
}
|
|
2025
2096
|
} catch (error) {
|
|
2026
|
-
console.error(
|
|
2097
|
+
logger.console.error(
|
|
2027
2098
|
"[trails-sdk] Error waiting for destination receipt:",
|
|
2028
2099
|
error,
|
|
2029
2100
|
)
|
|
@@ -2059,6 +2130,17 @@ async function sendHandlerForDifferentChainDifferentToken({
|
|
|
2059
2130
|
|
|
2060
2131
|
// Track payment completion for different chain and different token
|
|
2061
2132
|
if (originUserTxReceipt && destinationMetaTxnReceipt) {
|
|
2133
|
+
// Check if any transaction failed or was refunded
|
|
2134
|
+
const hasAnyCallFailed = transactionStates.some((tx) =>
|
|
2135
|
+
tx?.decodedGuestModuleEvents?.some(
|
|
2136
|
+
(e: any) => e?.type === "CallFailed",
|
|
2137
|
+
),
|
|
2138
|
+
)
|
|
2139
|
+
const hasAnyRefunded = transactionStates.some((tx) => tx?.refunded)
|
|
2140
|
+
const txStatus =
|
|
2141
|
+
!hasAnyCallFailed && !hasAnyRefunded ? "success" : "fail"
|
|
2142
|
+
|
|
2143
|
+
// Always track payment completion regardless of success/failure
|
|
2062
2144
|
trackPaymentCompleted({
|
|
2063
2145
|
userAddress: account.address,
|
|
2064
2146
|
originIntentAddress,
|
|
@@ -2079,9 +2161,9 @@ async function sendHandlerForDifferentChainDifferentToken({
|
|
|
2079
2161
|
effectiveDestinationTokenAmountUsd?.toString(),
|
|
2080
2162
|
})
|
|
2081
2163
|
|
|
2082
|
-
// Call onCheckoutComplete callback
|
|
2164
|
+
// Call onCheckoutComplete callback with transaction status
|
|
2083
2165
|
if (checkoutOnHandlers?.triggerCheckoutComplete) {
|
|
2084
|
-
checkoutOnHandlers.triggerCheckoutComplete()
|
|
2166
|
+
checkoutOnHandlers.triggerCheckoutComplete(txStatus)
|
|
2085
2167
|
}
|
|
2086
2168
|
} else {
|
|
2087
2169
|
if (
|
|
@@ -2190,6 +2272,11 @@ async function sendHandlerForSameChainSameToken({
|
|
|
2190
2272
|
checkoutOnHandlers,
|
|
2191
2273
|
mode,
|
|
2192
2274
|
fundMethod,
|
|
2275
|
+
gasless,
|
|
2276
|
+
paymasterUrl,
|
|
2277
|
+
selectedFeeToken,
|
|
2278
|
+
trailsClient,
|
|
2279
|
+
originRelayer,
|
|
2193
2280
|
}: {
|
|
2194
2281
|
originTokenAddress: string
|
|
2195
2282
|
originTokenDecimals: number
|
|
@@ -2211,6 +2298,11 @@ async function sendHandlerForSameChainSameToken({
|
|
|
2211
2298
|
checkoutOnHandlers?: CheckoutOnHandlers
|
|
2212
2299
|
mode?: "pay" | "fund" | "earn" | "swap" | "receive"
|
|
2213
2300
|
fundMethod?: string
|
|
2301
|
+
gasless?: boolean
|
|
2302
|
+
paymasterUrl?: string
|
|
2303
|
+
selectedFeeToken?: any
|
|
2304
|
+
trailsClient: TrailsAPIClient
|
|
2305
|
+
originRelayer: Relayer.RpcRelayer
|
|
2214
2306
|
}): Promise<PrepareSendReturn> {
|
|
2215
2307
|
logger.console.log("[trails-sdk] isToSameToken && isToSameChain")
|
|
2216
2308
|
const testnet = isTestnetDebugMode()
|
|
@@ -2237,6 +2329,44 @@ async function sendHandlerForSameChainSameToken({
|
|
|
2237
2329
|
noSufficientBalance = true
|
|
2238
2330
|
}
|
|
2239
2331
|
|
|
2332
|
+
// Build origin call params and estimate gas limit for the quote
|
|
2333
|
+
const hasCustomCalldata = getIsCustomCalldata(destinationCalldata)
|
|
2334
|
+
const originCallParamsBase = buildSameChainTransactionParams({
|
|
2335
|
+
hasCustomCalldata,
|
|
2336
|
+
recipient,
|
|
2337
|
+
effectiveOriginTokenAddress,
|
|
2338
|
+
destinationCalldata,
|
|
2339
|
+
swapAmount,
|
|
2340
|
+
effectiveOriginChainId,
|
|
2341
|
+
effectiveOriginChain,
|
|
2342
|
+
})
|
|
2343
|
+
|
|
2344
|
+
logger.console.log(
|
|
2345
|
+
"[trails-sdk][gas-estimation] About to estimate gas limit for quote with params:",
|
|
2346
|
+
{
|
|
2347
|
+
account: account.address,
|
|
2348
|
+
to: originCallParamsBase.to,
|
|
2349
|
+
data: originCallParamsBase.data,
|
|
2350
|
+
value: originCallParamsBase.value,
|
|
2351
|
+
},
|
|
2352
|
+
)
|
|
2353
|
+
|
|
2354
|
+
const estimatedGasLimitForQuote = await estimateGasLimit(
|
|
2355
|
+
effectivePublicClient,
|
|
2356
|
+
{
|
|
2357
|
+
account: account.address,
|
|
2358
|
+
to: originCallParamsBase.to,
|
|
2359
|
+
data: originCallParamsBase.data,
|
|
2360
|
+
value: BigInt(originCallParamsBase.value),
|
|
2361
|
+
},
|
|
2362
|
+
"quote",
|
|
2363
|
+
)
|
|
2364
|
+
|
|
2365
|
+
logger.console.log(
|
|
2366
|
+
"[trails-sdk][gas-estimation] Estimated gas limit for quote:",
|
|
2367
|
+
estimatedGasLimitForQuote,
|
|
2368
|
+
)
|
|
2369
|
+
|
|
2240
2370
|
const quote = await getNormalizedQuoteObject({
|
|
2241
2371
|
originDepositAddress: recipient,
|
|
2242
2372
|
destinationDepositAddress: recipient,
|
|
@@ -2255,6 +2385,7 @@ async function sendHandlerForSameChainSameToken({
|
|
|
2255
2385
|
slippageTolerance,
|
|
2256
2386
|
quoteProvider: "",
|
|
2257
2387
|
noSufficientBalance,
|
|
2388
|
+
estimatedGasLimit: estimatedGasLimitForQuote,
|
|
2258
2389
|
})
|
|
2259
2390
|
|
|
2260
2391
|
// Call onCheckoutQuote callback if provided
|
|
@@ -2290,26 +2421,33 @@ async function sendHandlerForSameChainSameToken({
|
|
|
2290
2421
|
})
|
|
2291
2422
|
|
|
2292
2423
|
const hasCustomCalldata = getIsCustomCalldata(destinationCalldata)
|
|
2424
|
+
|
|
2425
|
+
// Build origin call params (reusing the same logic as quote estimation)
|
|
2426
|
+
const originCallParamsBase = buildSameChainTransactionParams({
|
|
2427
|
+
hasCustomCalldata,
|
|
2428
|
+
recipient,
|
|
2429
|
+
effectiveOriginTokenAddress,
|
|
2430
|
+
destinationCalldata,
|
|
2431
|
+
swapAmount,
|
|
2432
|
+
effectiveOriginChainId,
|
|
2433
|
+
effectiveOriginChain,
|
|
2434
|
+
})
|
|
2435
|
+
|
|
2436
|
+
// Estimate gas limit for consistency with actual transaction
|
|
2437
|
+
const gasLimit = await estimateGasLimit(
|
|
2438
|
+
effectivePublicClient,
|
|
2439
|
+
{
|
|
2440
|
+
account: account.address,
|
|
2441
|
+
to: originCallParamsBase.to,
|
|
2442
|
+
data: originCallParamsBase.data,
|
|
2443
|
+
value: BigInt(originCallParamsBase.value),
|
|
2444
|
+
},
|
|
2445
|
+
"send",
|
|
2446
|
+
)
|
|
2447
|
+
|
|
2293
2448
|
const originCallParams = {
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
: effectiveOriginTokenAddress === zeroAddress
|
|
2297
|
-
? recipient
|
|
2298
|
-
: effectiveOriginTokenAddress,
|
|
2299
|
-
data: hasCustomCalldata
|
|
2300
|
-
? destinationCalldata
|
|
2301
|
-
: effectiveOriginTokenAddress === zeroAddress
|
|
2302
|
-
? "0x"
|
|
2303
|
-
: getERC20TransferData({
|
|
2304
|
-
recipient,
|
|
2305
|
-
amount: BigInt(swapAmount),
|
|
2306
|
-
}),
|
|
2307
|
-
value:
|
|
2308
|
-
effectiveOriginTokenAddress === zeroAddress
|
|
2309
|
-
? BigInt(swapAmount)
|
|
2310
|
-
: "0",
|
|
2311
|
-
chainId: effectiveOriginChainId,
|
|
2312
|
-
chain: effectiveOriginChain,
|
|
2449
|
+
...originCallParamsBase,
|
|
2450
|
+
gasLimit,
|
|
2313
2451
|
}
|
|
2314
2452
|
|
|
2315
2453
|
logger.console.log("[trails-sdk] origin call params", originCallParams)
|
|
@@ -2340,105 +2478,207 @@ async function sendHandlerForSameChainSameToken({
|
|
|
2340
2478
|
)
|
|
2341
2479
|
}
|
|
2342
2480
|
|
|
2343
|
-
|
|
2481
|
+
// For gasless transactions with custom calldata, use the gasless deposit flow
|
|
2482
|
+
if (gasless && hasCustomCalldata) {
|
|
2483
|
+
logger.console.log(
|
|
2484
|
+
"[trails-sdk] Using gasless intent entrypoint flow for same-chain transaction with custom calldata",
|
|
2485
|
+
)
|
|
2486
|
+
|
|
2487
|
+
// Fetch fee options for gasless deposit
|
|
2488
|
+
let feeOptions: any = null
|
|
2344
2489
|
try {
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2490
|
+
feeOptions = await getIntentEntrypointFeeOptions({
|
|
2491
|
+
trailsClient,
|
|
2492
|
+
userAddress: account.address as `0x${string}`,
|
|
2493
|
+
tokenAddress: effectiveOriginTokenAddress as `0x${string}`,
|
|
2494
|
+
amount: swapAmount,
|
|
2495
|
+
intentAddress: recipient as `0x${string}`,
|
|
2496
|
+
chainId: effectiveOriginChainId,
|
|
2497
|
+
})
|
|
2498
|
+
logger.console.log(
|
|
2499
|
+
"[trails-sdk] [GASLESS-FLOW] Fetched intent entrypoint fee options for same-chain transaction:",
|
|
2500
|
+
feeOptions,
|
|
2501
|
+
)
|
|
2502
|
+
} catch (error) {
|
|
2503
|
+
logger.console.error(
|
|
2504
|
+
"[trails-sdk] [GASLESS-FLOW] Error fetching fee options for same-chain gasless transaction:",
|
|
2505
|
+
error,
|
|
2506
|
+
)
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
const receipt = await attemptGaslessDeposit({
|
|
2510
|
+
account,
|
|
2511
|
+
walletClient,
|
|
2512
|
+
chain: effectiveOriginChain,
|
|
2513
|
+
depositTokenAddress: effectiveOriginTokenAddress,
|
|
2514
|
+
depositTokenAmount: swapAmount,
|
|
2515
|
+
depositRecipient: recipient,
|
|
2516
|
+
onOriginSend: () => {}, // No-op callback
|
|
2517
|
+
feeOptions,
|
|
2518
|
+
paymasterUrl,
|
|
2519
|
+
selectedFeeToken,
|
|
2520
|
+
trailsClient,
|
|
2521
|
+
originRelayer,
|
|
2522
|
+
})
|
|
2523
|
+
|
|
2524
|
+
if (receipt) {
|
|
2525
|
+
originUserTxReceipt = receipt
|
|
2526
|
+
|
|
2527
|
+
// Track the confirmed transaction
|
|
2528
|
+
trackTransactionConfirmed({
|
|
2529
|
+
transactionHash: receipt.transactionHash,
|
|
2530
|
+
chainId: effectiveOriginChainId,
|
|
2531
|
+
userAddress: account.address,
|
|
2532
|
+
blockNumber: Number(receipt.blockNumber),
|
|
2533
|
+
originTokenAddress,
|
|
2534
|
+
depositTokenAmountUsd: depositAmountUsd?.toString(),
|
|
2351
2535
|
})
|
|
2352
2536
|
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2537
|
+
// Toast will be shown after transaction state analysis
|
|
2538
|
+
|
|
2539
|
+
// Update transaction state
|
|
2540
|
+
try {
|
|
2541
|
+
onTransactionStateChange([
|
|
2542
|
+
getTransactionStateFromReceipt(
|
|
2543
|
+
receipt,
|
|
2544
|
+
effectiveOriginChainId,
|
|
2545
|
+
transactionStates[0]?.label,
|
|
2546
|
+
),
|
|
2547
|
+
])
|
|
2548
|
+
} catch (error) {
|
|
2549
|
+
logger.console.error(
|
|
2550
|
+
"[trails-sdk] Error calling onTransactionStateChange:",
|
|
2551
|
+
error,
|
|
2552
|
+
)
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
} else {
|
|
2556
|
+
// Non-gasless flow: handle approval if needed
|
|
2557
|
+
if (hasCustomCalldata) {
|
|
2558
|
+
try {
|
|
2559
|
+
const needsApproval = await getNeedsApproval({
|
|
2560
|
+
publicClient: effectivePublicClient,
|
|
2561
|
+
token: effectiveOriginTokenAddress,
|
|
2562
|
+
account: account.address,
|
|
2357
2563
|
spender: recipient,
|
|
2358
2564
|
amount: maxUint256,
|
|
2359
|
-
chain: effectiveOriginChain,
|
|
2360
2565
|
})
|
|
2361
2566
|
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2567
|
+
if (needsApproval) {
|
|
2568
|
+
const txHash = await approveERC20({
|
|
2569
|
+
walletClient,
|
|
2570
|
+
tokenAddress: effectiveOriginTokenAddress,
|
|
2571
|
+
spender: recipient,
|
|
2572
|
+
amount: maxUint256,
|
|
2573
|
+
chain: effectiveOriginChain,
|
|
2574
|
+
})
|
|
2575
|
+
|
|
2576
|
+
logger.console.log("waiting for approve", txHash)
|
|
2577
|
+
await effectivePublicClient.waitForTransactionReceipt({
|
|
2578
|
+
hash: txHash,
|
|
2579
|
+
})
|
|
2580
|
+
logger.console.log("approve done")
|
|
2581
|
+
}
|
|
2582
|
+
} catch (error) {
|
|
2583
|
+
logger.console.error(
|
|
2584
|
+
"[trails-sdk] Error approving ERC20",
|
|
2585
|
+
error,
|
|
2586
|
+
)
|
|
2367
2587
|
}
|
|
2368
|
-
} catch (error) {
|
|
2369
|
-
logger.console.error("[trails-sdk] Error approving ERC20", error)
|
|
2370
2588
|
}
|
|
2371
|
-
}
|
|
2372
2589
|
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2590
|
+
// Show persistent toast for checkout flow
|
|
2591
|
+
updatePersistentToast(
|
|
2592
|
+
"Payment Started",
|
|
2593
|
+
"Waiting for wallet confirmation...",
|
|
2594
|
+
"info",
|
|
2595
|
+
)
|
|
2379
2596
|
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2597
|
+
logger.console.log(
|
|
2598
|
+
"[trails-sdk] origin call params",
|
|
2599
|
+
originCallParams,
|
|
2600
|
+
)
|
|
2601
|
+
const txHash = await sendOriginTransaction(
|
|
2602
|
+
account,
|
|
2603
|
+
walletClient,
|
|
2604
|
+
originCallParams as any,
|
|
2605
|
+
{
|
|
2606
|
+
depositTokenAmountUsd: depositAmountUsd?.toString(),
|
|
2607
|
+
},
|
|
2608
|
+
) // TODO: Add proper type
|
|
2392
2609
|
|
|
2393
|
-
|
|
2610
|
+
logger.console.log("[trails-sdk] origin tx", txHash)
|
|
2394
2611
|
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2612
|
+
if (onOriginSend) {
|
|
2613
|
+
onOriginSend()
|
|
2614
|
+
}
|
|
2398
2615
|
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
originUserTxReceipt = receipt
|
|
2616
|
+
// Wait for transaction receipt
|
|
2617
|
+
const receipt =
|
|
2618
|
+
await effectivePublicClient.waitForTransactionReceipt({
|
|
2619
|
+
hash: txHash,
|
|
2620
|
+
})
|
|
2621
|
+
logger.console.log("[trails-sdk] receipt", receipt)
|
|
2622
|
+
originUserTxReceipt = receipt
|
|
2407
2623
|
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2624
|
+
trackTransactionConfirmed({
|
|
2625
|
+
transactionHash: txHash,
|
|
2626
|
+
chainId: effectiveOriginChainId,
|
|
2627
|
+
userAddress: account.address,
|
|
2628
|
+
blockNumber: Number(receipt.blockNumber),
|
|
2629
|
+
originTokenAddress,
|
|
2630
|
+
depositTokenAmountUsd: depositAmountUsd?.toString(),
|
|
2631
|
+
})
|
|
2416
2632
|
|
|
2417
|
-
|
|
2418
|
-
const chainInfo = getChainInfo(effectiveOriginChainId)
|
|
2419
|
-
updatePersistentToast(
|
|
2420
|
-
"Transfer Confirmed",
|
|
2421
|
-
`Your transaction on ${chainInfo?.name || "chain"} has been confirmed`,
|
|
2422
|
-
"info",
|
|
2423
|
-
)
|
|
2633
|
+
// Toast will be shown after transaction state analysis
|
|
2424
2634
|
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2635
|
+
try {
|
|
2636
|
+
onTransactionStateChange([
|
|
2637
|
+
getTransactionStateFromReceipt(
|
|
2638
|
+
originUserTxReceipt,
|
|
2639
|
+
effectiveOriginChainId,
|
|
2640
|
+
transactionStates[0]?.label,
|
|
2641
|
+
),
|
|
2642
|
+
])
|
|
2643
|
+
} catch (error) {
|
|
2644
|
+
logger.console.error(
|
|
2645
|
+
"[trails-sdk] Error calling onTransactionStateChange:",
|
|
2646
|
+
error,
|
|
2647
|
+
)
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2651
|
+
// Show conditional toast based on transaction status
|
|
2652
|
+
const chainInfo = getChainInfo(effectiveOriginChainId)
|
|
2653
|
+
if (originUserTxReceipt) {
|
|
2654
|
+
if (originUserTxReceipt?.status === "success") {
|
|
2655
|
+
updatePersistentToast(
|
|
2656
|
+
"Transfer Confirmed",
|
|
2657
|
+
`Your transaction on ${chainInfo?.name || "chain"} has been confirmed`,
|
|
2658
|
+
"info",
|
|
2659
|
+
)
|
|
2660
|
+
} else {
|
|
2661
|
+
updatePersistentToast(
|
|
2662
|
+
"Transfer Failed",
|
|
2663
|
+
`Your transaction on ${chainInfo?.name || "chain"} failed`,
|
|
2664
|
+
"error",
|
|
2665
|
+
)
|
|
2666
|
+
}
|
|
2438
2667
|
}
|
|
2439
2668
|
|
|
2440
2669
|
// Track payment completion for same-chain same-token transaction
|
|
2441
2670
|
if (originUserTxReceipt && originUserTxReceipt.status === "success") {
|
|
2671
|
+
// Check if any transaction failed or was refunded
|
|
2672
|
+
const hasAnyCallFailed = transactionStates.some((tx) =>
|
|
2673
|
+
tx?.decodedGuestModuleEvents?.some(
|
|
2674
|
+
(e: any) => e?.type === "CallFailed",
|
|
2675
|
+
),
|
|
2676
|
+
)
|
|
2677
|
+
const hasAnyRefunded = transactionStates.some((tx) => tx?.refunded)
|
|
2678
|
+
const txStatus =
|
|
2679
|
+
!hasAnyCallFailed && !hasAnyRefunded ? "success" : "fail"
|
|
2680
|
+
|
|
2681
|
+
// Always track payment completion regardless of success/failure
|
|
2442
2682
|
trackPaymentCompleted({
|
|
2443
2683
|
userAddress: account.address,
|
|
2444
2684
|
originTxHash: originUserTxReceipt.transactionHash,
|
|
@@ -2450,9 +2690,9 @@ async function sendHandlerForSameChainSameToken({
|
|
|
2450
2690
|
destinationTokenAmountUsd: depositAmountUsd?.toString(), // same as deposit amount
|
|
2451
2691
|
})
|
|
2452
2692
|
|
|
2453
|
-
// Call onCheckoutComplete callback
|
|
2693
|
+
// Call onCheckoutComplete callback with transaction status
|
|
2454
2694
|
if (checkoutOnHandlers?.triggerCheckoutComplete) {
|
|
2455
|
-
checkoutOnHandlers.triggerCheckoutComplete()
|
|
2695
|
+
checkoutOnHandlers.triggerCheckoutComplete(txStatus)
|
|
2456
2696
|
}
|
|
2457
2697
|
} else if (originUserTxReceipt) {
|
|
2458
2698
|
trackPaymentError({
|
|
@@ -2607,7 +2847,7 @@ async function _sendHandlerForSameChainDifferentToken({
|
|
|
2607
2847
|
}
|
|
2608
2848
|
}
|
|
2609
2849
|
} catch (error) {
|
|
2610
|
-
console.error("[trails-sdk] Error decoding function data:", error)
|
|
2850
|
+
logger.console.error("[trails-sdk] Error decoding function data:", error)
|
|
2611
2851
|
}
|
|
2612
2852
|
}
|
|
2613
2853
|
|
|
@@ -2793,7 +3033,7 @@ async function attemptGaslessDeposit({
|
|
|
2793
3033
|
chain: Chain
|
|
2794
3034
|
account: Account
|
|
2795
3035
|
trailsClient: TrailsAPIClient
|
|
2796
|
-
originRelayer:
|
|
3036
|
+
originRelayer: Relayer.RpcRelayer
|
|
2797
3037
|
feeOptions: any
|
|
2798
3038
|
selectedFeeToken?: any
|
|
2799
3039
|
}): Promise<TransactionReceipt | null> {
|
|
@@ -2900,7 +3140,7 @@ async function attemptGaslessDeposit({
|
|
|
2900
3140
|
feeOptions && feeOptions.feeOptions?.length > 0,
|
|
2901
3141
|
)
|
|
2902
3142
|
|
|
2903
|
-
// 1. Check if we need approval - check if we have enough allowance for this transaction (deposit + fee)
|
|
3143
|
+
// 1. Check if we need approval - check if we have enough allowance for this transaction (deposit + fee if same token)
|
|
2904
3144
|
let requiredAmount = BigInt(depositTokenAmount)
|
|
2905
3145
|
|
|
2906
3146
|
// Match selectedFeeToken by tokenAddress to get the latest fee amount from feeOptions
|
|
@@ -2930,14 +3170,36 @@ async function attemptGaslessDeposit({
|
|
|
2930
3170
|
)
|
|
2931
3171
|
}
|
|
2932
3172
|
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
3173
|
+
// Only include fee in required amount if the fee token is the same as the deposit token
|
|
3174
|
+
if (selectedFeeOption?.amount && selectedFeeOption?.tokenAddress) {
|
|
3175
|
+
const feeTokenIsSameAsDepositToken =
|
|
3176
|
+
selectedFeeOption.tokenAddress.toLowerCase() ===
|
|
3177
|
+
depositTokenAddress.toLowerCase()
|
|
3178
|
+
|
|
3179
|
+
if (feeTokenIsSameAsDepositToken) {
|
|
3180
|
+
requiredAmount = requiredAmount + BigInt(selectedFeeOption.amount)
|
|
3181
|
+
logger.console.log(
|
|
3182
|
+
"[trails-sdk] Fee token matches deposit token, including fee in required approval amount:",
|
|
3183
|
+
{
|
|
3184
|
+
depositAmount: depositTokenAmount,
|
|
3185
|
+
feeAmount: selectedFeeOption.amount,
|
|
3186
|
+
feeTokenAddress: selectedFeeOption.tokenAddress,
|
|
3187
|
+
depositTokenAddress,
|
|
3188
|
+
totalRequired: requiredAmount.toString(),
|
|
3189
|
+
},
|
|
3190
|
+
)
|
|
3191
|
+
} else {
|
|
3192
|
+
logger.console.log(
|
|
3193
|
+
"[trails-sdk] Fee token differs from deposit token, separate approval will be needed:",
|
|
3194
|
+
{
|
|
3195
|
+
depositAmount: depositTokenAmount,
|
|
3196
|
+
depositTokenAddress,
|
|
3197
|
+
feeAmount: selectedFeeOption.amount,
|
|
3198
|
+
feeTokenAddress: selectedFeeOption.tokenAddress,
|
|
3199
|
+
depositTokenRequired: requiredAmount.toString(),
|
|
3200
|
+
},
|
|
3201
|
+
)
|
|
3202
|
+
}
|
|
2941
3203
|
}
|
|
2942
3204
|
|
|
2943
3205
|
const needsApproval = await getNeedsIntentEntrypointApproval({
|
|
@@ -2962,13 +3224,14 @@ async function attemptGaslessDeposit({
|
|
|
2962
3224
|
},
|
|
2963
3225
|
)
|
|
2964
3226
|
|
|
2965
|
-
// 2. Get permit signature if approval needed
|
|
3227
|
+
// 2. Get permit signature if approval needed for deposit token
|
|
3228
|
+
// Note: Fee payment is handled by the backend/relayer, we only need permit for the deposit token
|
|
2966
3229
|
let permitSignature: string | undefined
|
|
2967
3230
|
let permitDeadline: number | undefined
|
|
2968
3231
|
|
|
2969
3232
|
if (needsApproval) {
|
|
2970
3233
|
logger.console.log(
|
|
2971
|
-
"[trails-sdk] Getting permit signature for infinite approval",
|
|
3234
|
+
"[trails-sdk] Getting permit signature for deposit token infinite approval",
|
|
2972
3235
|
)
|
|
2973
3236
|
|
|
2974
3237
|
// Use infinite approval (maxUint256) so user doesn't need to approve again
|
|
@@ -2977,6 +3240,7 @@ async function attemptGaslessDeposit({
|
|
|
2977
3240
|
"[trails-sdk] Using infinite approval for gasless deposits",
|
|
2978
3241
|
{
|
|
2979
3242
|
depositAmount: depositTokenAmount,
|
|
3243
|
+
depositTokenAddress,
|
|
2980
3244
|
permitAmount: permitAmount.toString(),
|
|
2981
3245
|
},
|
|
2982
3246
|
)
|
|
@@ -2994,7 +3258,7 @@ async function attemptGaslessDeposit({
|
|
|
2994
3258
|
permitSignature = permitSig.signature
|
|
2995
3259
|
permitDeadline = Number(permitSig.deadline)
|
|
2996
3260
|
logger.console.log(
|
|
2997
|
-
"[trails-sdk]
|
|
3261
|
+
"[trails-sdk] Deposit token permit signature obtained for infinite approval",
|
|
2998
3262
|
)
|
|
2999
3263
|
}
|
|
3000
3264
|
|
|
@@ -3221,24 +3485,31 @@ export async function attemptNonGaslessUserDeposit({
|
|
|
3221
3485
|
|
|
3222
3486
|
logger.console.log("[trails-sdk] needsNativeFee", needsNativeFee)
|
|
3223
3487
|
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
? "0x"
|
|
3232
|
-
: getERC20TransferData({
|
|
3233
|
-
recipient: originIntentAddress,
|
|
3234
|
-
amount: BigInt(firstPreconditionMin) + BigInt(fee),
|
|
3235
|
-
}),
|
|
3236
|
-
value:
|
|
3237
|
-
originTokenAddress === zeroAddress
|
|
3238
|
-
? BigInt(firstPreconditionMin) + BigInt(fee)
|
|
3239
|
-
: "0",
|
|
3240
|
-
chainId: originChainId,
|
|
3488
|
+
// Build origin call params
|
|
3489
|
+
const originCallParamsBase = buildCrossChainDepositParams({
|
|
3490
|
+
originTokenAddress,
|
|
3491
|
+
originIntentAddress,
|
|
3492
|
+
depositAmount: firstPreconditionMin,
|
|
3493
|
+
fee,
|
|
3494
|
+
originChainId,
|
|
3241
3495
|
chain,
|
|
3496
|
+
})
|
|
3497
|
+
|
|
3498
|
+
// Estimate gas limit for consistency with actual transaction
|
|
3499
|
+
const gasLimit = await estimateGasLimit(
|
|
3500
|
+
publicClient,
|
|
3501
|
+
{
|
|
3502
|
+
account: account.address,
|
|
3503
|
+
to: originCallParamsBase.to,
|
|
3504
|
+
data: originCallParamsBase.data,
|
|
3505
|
+
value: BigInt(originCallParamsBase.value),
|
|
3506
|
+
},
|
|
3507
|
+
"deposit",
|
|
3508
|
+
)
|
|
3509
|
+
|
|
3510
|
+
const originCallParams = {
|
|
3511
|
+
...originCallParamsBase,
|
|
3512
|
+
gasLimit,
|
|
3242
3513
|
}
|
|
3243
3514
|
|
|
3244
3515
|
await attemptSwitchChain({
|
|
@@ -3494,13 +3765,14 @@ async function attemptUserDepositTx({
|
|
|
3494
3765
|
feeOptions,
|
|
3495
3766
|
trailsClient,
|
|
3496
3767
|
selectedFeeToken,
|
|
3768
|
+
walletId,
|
|
3497
3769
|
}: {
|
|
3498
3770
|
originTokenAddress: string
|
|
3499
3771
|
gasless: boolean
|
|
3500
3772
|
paymasterUrl?: string
|
|
3501
3773
|
chain: Chain
|
|
3502
3774
|
account: Account
|
|
3503
|
-
originRelayer:
|
|
3775
|
+
originRelayer: Relayer.RpcRelayer
|
|
3504
3776
|
firstPreconditionMin: string
|
|
3505
3777
|
originIntentAddress: string
|
|
3506
3778
|
onOriginSend?: () => void
|
|
@@ -3522,6 +3794,7 @@ async function attemptUserDepositTx({
|
|
|
3522
3794
|
feeOptions?: any
|
|
3523
3795
|
trailsClient: TrailsAPIClient
|
|
3524
3796
|
selectedFeeToken?: any
|
|
3797
|
+
walletId?: string
|
|
3525
3798
|
}): Promise<TransactionReceipt | null> {
|
|
3526
3799
|
let originUserTxReceipt: TransactionReceipt | null = null
|
|
3527
3800
|
const originChainId = chain.id
|
|
@@ -3545,6 +3818,7 @@ async function attemptUserDepositTx({
|
|
|
3545
3818
|
gasless,
|
|
3546
3819
|
feeOptions,
|
|
3547
3820
|
selectedFeeToken,
|
|
3821
|
+
walletId,
|
|
3548
3822
|
)
|
|
3549
3823
|
logger.console.log(
|
|
3550
3824
|
"[trails-sdk] [GASLESS-FLOW] [FEE-SELECT] doGasless check results:",
|
|
@@ -3587,12 +3861,15 @@ async function attemptUserDepositTx({
|
|
|
3587
3861
|
})
|
|
3588
3862
|
} catch (error) {
|
|
3589
3863
|
logger.console.log("[trails-sdk] gassless attempt failed", error)
|
|
3590
|
-
throw error
|
|
3864
|
+
// In strict gasless mode, re-throw error instead of falling back
|
|
3865
|
+
if (gasless) {
|
|
3866
|
+
throw error
|
|
3867
|
+
}
|
|
3591
3868
|
}
|
|
3592
3869
|
}
|
|
3593
3870
|
|
|
3594
3871
|
// If gasless attempt failed, try to send a regular transaction
|
|
3595
|
-
if (!originUserTxReceipt) {
|
|
3872
|
+
if (!originUserTxReceipt && !gasless) {
|
|
3596
3873
|
originUserTxReceipt = await attemptNonGaslessUserDeposit({
|
|
3597
3874
|
originTokenAddress,
|
|
3598
3875
|
firstPreconditionMin,
|
|
@@ -3626,7 +3903,16 @@ export function getDoGasless(
|
|
|
3626
3903
|
gasless: boolean,
|
|
3627
3904
|
feeOptions?: any,
|
|
3628
3905
|
selectedFeeToken?: any,
|
|
3906
|
+
walletId?: string,
|
|
3629
3907
|
): boolean {
|
|
3908
|
+
// Don't use gasless flow for sequence-waas wallet
|
|
3909
|
+
if (walletId === "sequence-waas") {
|
|
3910
|
+
logger.console.log(
|
|
3911
|
+
"[trails-sdk] [GASLESS-FLOW] getDoGasless: Skipping gasless flow for sequence-waas wallet",
|
|
3912
|
+
)
|
|
3913
|
+
return false
|
|
3914
|
+
}
|
|
3915
|
+
|
|
3630
3916
|
const hasFeeOptions = Boolean(feeOptions && feeOptions.feeOptions?.length > 0)
|
|
3631
3917
|
|
|
3632
3918
|
// Important: The UI passes selectedFeeToken in these states:
|
|
@@ -3763,7 +4049,7 @@ async function sendMetaTxAndWaitForReceipt({
|
|
|
3763
4049
|
feeQuote,
|
|
3764
4050
|
}: {
|
|
3765
4051
|
metaTx: MetaTxn
|
|
3766
|
-
relayer:
|
|
4052
|
+
relayer: Relayer.RpcRelayer
|
|
3767
4053
|
precondition: IntentPrecondition | null
|
|
3768
4054
|
feeQuote?: string
|
|
3769
4055
|
}): Promise<{
|
|
@@ -3922,7 +4208,7 @@ async function checkAccountBalance({
|
|
|
3922
4208
|
balanceError,
|
|
3923
4209
|
}
|
|
3924
4210
|
} catch (error) {
|
|
3925
|
-
console.error("[trails-sdk] Error checking account balance:", error)
|
|
4211
|
+
logger.console.error("[trails-sdk] Error checking account balance:", error)
|
|
3926
4212
|
return {
|
|
3927
4213
|
hasEnoughBalance: false,
|
|
3928
4214
|
balance: BigInt(0),
|
|
@@ -4014,6 +4300,10 @@ export type UseQuoteProps = {
|
|
|
4014
4300
|
quoteProvider?: string | null
|
|
4015
4301
|
gasless?: boolean
|
|
4016
4302
|
paymasterUrl?: string
|
|
4303
|
+
selectedFeeToken?: {
|
|
4304
|
+
tokenAddress: string
|
|
4305
|
+
tokenSymbol?: string
|
|
4306
|
+
} | null
|
|
4017
4307
|
}
|
|
4018
4308
|
|
|
4019
4309
|
export type SwapReturn = {
|
|
@@ -4057,6 +4347,8 @@ export type Quote = {
|
|
|
4057
4347
|
toAmountUsdDisplay?: string
|
|
4058
4348
|
gasCostUsd?: number
|
|
4059
4349
|
gasCostUsdDisplay?: string
|
|
4350
|
+
gasCost?: string
|
|
4351
|
+
gasCostFormatted?: string
|
|
4060
4352
|
}
|
|
4061
4353
|
|
|
4062
4354
|
export type UseQuoteReturn = {
|
|
@@ -4082,6 +4374,7 @@ export function useQuote({
|
|
|
4082
4374
|
quoteProvider,
|
|
4083
4375
|
gasless,
|
|
4084
4376
|
paymasterUrl,
|
|
4377
|
+
selectedFeeToken,
|
|
4085
4378
|
relayerEnv,
|
|
4086
4379
|
nodeGatewayEnv,
|
|
4087
4380
|
}: Partial<
|
|
@@ -4223,6 +4516,7 @@ export function useQuote({
|
|
|
4223
4516
|
quoteProvider: quoteProvider,
|
|
4224
4517
|
gasless: gasless ?? false,
|
|
4225
4518
|
paymasterUrl: paymasterUrl,
|
|
4519
|
+
selectedFeeToken: selectedFeeToken ?? undefined,
|
|
4226
4520
|
}
|
|
4227
4521
|
|
|
4228
4522
|
logger.console.log("[trails-sdk] options", options)
|
|
@@ -4252,6 +4546,8 @@ export function useQuote({
|
|
|
4252
4546
|
prepareSendQuote.destinationAmountUsdDisplay ?? undefined,
|
|
4253
4547
|
gasCostUsd: prepareSendQuote.gasCostUsd ?? undefined,
|
|
4254
4548
|
gasCostUsdDisplay: prepareSendQuote.gasCostUsdDisplay ?? undefined,
|
|
4549
|
+
gasCost: prepareSendQuote.gasCost ?? undefined,
|
|
4550
|
+
gasCostFormatted: prepareSendQuote.gasCostFormatted ?? undefined,
|
|
4255
4551
|
}
|
|
4256
4552
|
|
|
4257
4553
|
const swap = async (): Promise<SwapReturn> => {
|
|
@@ -4259,7 +4555,9 @@ export function useQuote({
|
|
|
4259
4555
|
originUserTxReceipt,
|
|
4260
4556
|
destinationMetaTxnReceipt,
|
|
4261
4557
|
totalCompletionSeconds,
|
|
4262
|
-
} = await send({
|
|
4558
|
+
} = await send({
|
|
4559
|
+
selectedFeeToken: selectedFeeToken ?? undefined,
|
|
4560
|
+
})
|
|
4263
4561
|
|
|
4264
4562
|
return {
|
|
4265
4563
|
originTransaction: {
|
|
@@ -4447,6 +4745,7 @@ export async function getNormalizedQuoteObject({
|
|
|
4447
4745
|
originNativeTokenPriceUsd,
|
|
4448
4746
|
quoteProvider,
|
|
4449
4747
|
noSufficientBalance,
|
|
4748
|
+
estimatedGasLimit,
|
|
4450
4749
|
}: {
|
|
4451
4750
|
originDepositAddress?: string
|
|
4452
4751
|
destinationDepositAddress?: string
|
|
@@ -4470,6 +4769,7 @@ export async function getNormalizedQuoteObject({
|
|
|
4470
4769
|
originNativeTokenPriceUsd?: number | null
|
|
4471
4770
|
quoteProvider?: string
|
|
4472
4771
|
noSufficientBalance?: boolean
|
|
4772
|
+
estimatedGasLimit?: bigint
|
|
4473
4773
|
}): Promise<PrepareSendQuote> {
|
|
4474
4774
|
if (!destinationChainId) {
|
|
4475
4775
|
throw new Error("Destination chain id is required")
|
|
@@ -4497,7 +4797,7 @@ export async function getNormalizedQuoteObject({
|
|
|
4497
4797
|
const destinationChain = getChainInfo(destinationChainId)
|
|
4498
4798
|
|
|
4499
4799
|
if (!originToken || !destinationToken || !originChain || !destinationChain) {
|
|
4500
|
-
console.error("[trails-sdk] Token or chain not found", {
|
|
4800
|
+
logger.console.error("[trails-sdk] Token or chain not found", {
|
|
4501
4801
|
originToken,
|
|
4502
4802
|
destinationToken,
|
|
4503
4803
|
originChain,
|
|
@@ -4571,17 +4871,52 @@ export async function getNormalizedQuoteObject({
|
|
|
4571
4871
|
|
|
4572
4872
|
let gasCostUsd: number = 0
|
|
4573
4873
|
let gasCostUsdDisplay: string = "0"
|
|
4874
|
+
let gasCost: string = "0"
|
|
4875
|
+
let gasCostFormatted: string = "0"
|
|
4574
4876
|
try {
|
|
4575
4877
|
if (originNativeTokenPriceUsd) {
|
|
4878
|
+
// Use the actual estimated gas limit if provided, otherwise use default
|
|
4879
|
+
// This ensures the quote gas cost matches what will be used in the actual transaction
|
|
4880
|
+
const gasLimitForCost = estimatedGasLimit || DEFAULT_MIN_GASLIMIT
|
|
4881
|
+
|
|
4882
|
+
logger.console.log(
|
|
4883
|
+
"[trails-sdk][gas-estimation] Calculating gas cost for quote with gasLimit:",
|
|
4884
|
+
gasLimitForCost,
|
|
4885
|
+
"(estimated:",
|
|
4886
|
+
estimatedGasLimit,
|
|
4887
|
+
"default:",
|
|
4888
|
+
DEFAULT_MIN_GASLIMIT,
|
|
4889
|
+
")",
|
|
4890
|
+
)
|
|
4891
|
+
|
|
4892
|
+
const gasCostWei = await estimateGasCost(publicClient, gasLimitForCost)
|
|
4893
|
+
gasCost = gasCostWei.toString()
|
|
4894
|
+
gasCostFormatted = formatUnits(gasCostWei, 18) // Native tokens always use 18 decimals
|
|
4895
|
+
|
|
4896
|
+
// Calculate USD value
|
|
4576
4897
|
gasCostUsd = await estimateGasCostUsd(
|
|
4577
4898
|
publicClient,
|
|
4578
4899
|
originNativeTokenPriceUsd,
|
|
4579
|
-
|
|
4900
|
+
gasLimitForCost,
|
|
4580
4901
|
)
|
|
4581
4902
|
gasCostUsdDisplay = formatUsdAmountDisplay(gasCostUsd)
|
|
4903
|
+
|
|
4904
|
+
logger.console.log(
|
|
4905
|
+
"[trails-sdk][gas-estimation] Quote gas cost calculated:",
|
|
4906
|
+
{
|
|
4907
|
+
gasCostWei,
|
|
4908
|
+
gasCost,
|
|
4909
|
+
gasCostFormatted,
|
|
4910
|
+
gasCostUsd,
|
|
4911
|
+
gasCostUsdDisplay,
|
|
4912
|
+
},
|
|
4913
|
+
)
|
|
4582
4914
|
}
|
|
4583
4915
|
} catch (error) {
|
|
4584
|
-
console.error(
|
|
4916
|
+
logger.console.error(
|
|
4917
|
+
"[trails-sdk][gas-estimation] Error estimating gas cost for quote display",
|
|
4918
|
+
error,
|
|
4919
|
+
)
|
|
4585
4920
|
}
|
|
4586
4921
|
|
|
4587
4922
|
// Calculate exchange rates
|
|
@@ -4657,6 +4992,8 @@ export async function getNormalizedQuoteObject({
|
|
|
4657
4992
|
transactionStates: transactionStates || [],
|
|
4658
4993
|
gasCostUsd,
|
|
4659
4994
|
gasCostUsdDisplay,
|
|
4995
|
+
gasCost,
|
|
4996
|
+
gasCostFormatted,
|
|
4660
4997
|
originTokenRate: exchangeRates.originTokenRate,
|
|
4661
4998
|
destinationTokenRate: exchangeRates.destinationTokenRate,
|
|
4662
4999
|
originAmountDisplay: formatAmountDisplay(originAmountFormatted),
|