0xtrails 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aave.d.ts +2 -0
- package/dist/aave.d.ts.map +1 -1
- package/dist/abortController.d.ts +8 -0
- package/dist/abortController.d.ts.map +1 -0
- package/dist/{ccip-CXlshvBY.js → ccip-BMB3uDZt.js} +1 -1
- package/dist/config.d.ts +0 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/constants.d.ts +4 -4
- package/dist/constants.d.ts.map +1 -1
- package/dist/error.d.ts +4 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/fees.d.ts +19 -0
- package/dist/fees.d.ts.map +1 -0
- package/dist/{index-_QuyGrjU.js → index-QXPUrZVv.js} +48719 -50852
- package/dist/index.d.ts +9 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +811 -784
- package/dist/intentReceiptMonitor.d.ts +24 -0
- package/dist/intentReceiptMonitor.d.ts.map +1 -0
- package/dist/intentReceiptPoller.d.ts +69 -0
- package/dist/intentReceiptPoller.d.ts.map +1 -0
- package/dist/intents.d.ts +15 -11
- package/dist/intents.d.ts.map +1 -1
- package/dist/morpho.d.ts +6 -5
- package/dist/morpho.d.ts.map +1 -1
- package/dist/mutations.d.ts +16 -0
- package/dist/mutations.d.ts.map +1 -0
- package/dist/preconditions.d.ts +5 -4
- package/dist/preconditions.d.ts.map +1 -1
- package/dist/prepareSend.d.ts +7 -258
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/prices.d.ts +9 -6
- package/dist/prices.d.ts.map +1 -1
- package/dist/sequenceWallet.d.ts +3 -16
- package/dist/sequenceWallet.d.ts.map +1 -1
- package/dist/tokenBalances.d.ts +17 -13
- package/dist/tokenBalances.d.ts.map +1 -1
- package/dist/trails.d.ts +24 -40
- package/dist/trails.d.ts.map +1 -1
- package/dist/transactionIntent/constants.d.ts +7 -0
- package/dist/transactionIntent/constants.d.ts.map +1 -0
- package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +44 -0
- package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -0
- package/dist/transactionIntent/deposits/gaslessDeposit.d.ts +30 -0
- package/dist/transactionIntent/deposits/gaslessDeposit.d.ts.map +1 -0
- package/dist/transactionIntent/deposits/index.d.ts +4 -0
- package/dist/transactionIntent/deposits/index.d.ts.map +1 -0
- package/dist/transactionIntent/deposits/standardDeposit.d.ts +30 -0
- package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -0
- package/dist/transactionIntent/execution/index.d.ts +2 -0
- package/dist/transactionIntent/execution/index.d.ts.map +1 -0
- package/dist/transactionIntent/execution/transactionState.d.ts +5 -0
- package/dist/transactionIntent/execution/transactionState.d.ts.map +1 -0
- package/dist/transactionIntent/handlers/crossChain.d.ts +82 -0
- package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -0
- package/dist/transactionIntent/handlers/index.d.ts +4 -0
- package/dist/transactionIntent/handlers/index.d.ts.map +1 -0
- package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts +62 -0
- package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts.map +1 -0
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts +72 -0
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -0
- package/dist/transactionIntent/index.d.ts +9 -0
- package/dist/transactionIntent/index.d.ts.map +1 -0
- package/dist/transactionIntent/quote/feeExtractors.d.ts +17 -0
- package/dist/transactionIntent/quote/feeExtractors.d.ts.map +1 -0
- package/dist/transactionIntent/quote/index.d.ts +4 -0
- package/dist/transactionIntent/quote/index.d.ts.map +1 -0
- package/dist/transactionIntent/quote/normalizeQuote.d.ts +34 -0
- package/dist/transactionIntent/quote/normalizeQuote.d.ts.map +1 -0
- package/dist/transactionIntent/quote/quoteHelpers.d.ts +5 -0
- package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -0
- package/dist/transactionIntent/types.d.ts +131 -0
- package/dist/transactionIntent/types.d.ts.map +1 -0
- package/dist/transactionIntent/utils/balanceChecker.d.ts +18 -0
- package/dist/transactionIntent/utils/balanceChecker.d.ts.map +1 -0
- package/dist/transactionIntent/utils/index.d.ts +4 -0
- package/dist/transactionIntent/utils/index.d.ts.map +1 -0
- package/dist/transactionIntent/utils/lifiHelpers.d.ts +10 -0
- package/dist/transactionIntent/utils/lifiHelpers.d.ts.map +1 -0
- package/dist/transactionIntent/utils/testnetHelpers.d.ts +3 -0
- package/dist/transactionIntent/utils/testnetHelpers.d.ts.map +1 -0
- package/dist/transactionIntent/validators.d.ts +6 -0
- package/dist/transactionIntent/validators.d.ts.map +1 -0
- package/dist/transactions.d.ts +6 -3
- package/dist/transactions.d.ts.map +1 -1
- package/dist/widget/components/AccountIntentTransactionHistoryButton.d.ts +4 -0
- package/dist/widget/components/AccountIntentTransactionHistoryButton.d.ts.map +1 -0
- package/dist/widget/components/AccountSettings.d.ts.map +1 -1
- package/dist/widget/components/ChainFilterDropdown.d.ts.map +1 -1
- package/dist/widget/components/ClassicSwap.d.ts +2 -3
- package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
- package/dist/widget/components/ConfigDisplay.d.ts.map +1 -1
- package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
- package/dist/widget/components/ConnectedWallets.d.ts.map +1 -1
- package/dist/widget/components/DynamicInputStyles.d.ts +18 -0
- package/dist/widget/components/DynamicInputStyles.d.ts.map +1 -0
- package/dist/widget/components/DynamicSizeInputField.d.ts +13 -0
- package/dist/widget/components/DynamicSizeInputField.d.ts.map +1 -0
- package/dist/widget/components/Earn.d.ts +2 -3
- package/dist/widget/components/Earn.d.ts.map +1 -1
- package/dist/widget/components/ErrorAnimationIcon.d.ts +2 -0
- package/dist/widget/components/ErrorAnimationIcon.d.ts.map +1 -0
- package/dist/widget/components/FeeBreakdown.d.ts +9 -0
- package/dist/widget/components/FeeBreakdown.d.ts.map +1 -0
- package/dist/widget/components/FeeOptions.d.ts +5 -13
- package/dist/widget/components/FeeOptions.d.ts.map +1 -1
- package/dist/widget/components/Fund.d.ts +2 -3
- package/dist/widget/components/Fund.d.ts.map +1 -1
- package/dist/widget/components/FundMethods.d.ts.map +1 -1
- package/dist/widget/components/FundSwap.d.ts +2 -3
- package/dist/widget/components/FundSwap.d.ts.map +1 -1
- package/dist/widget/components/FundingMethodSelectorButton.d.ts.map +1 -1
- package/dist/widget/components/Identicon.d.ts.map +1 -1
- package/dist/widget/components/MeshConnectExchanges.d.ts +0 -3
- package/dist/widget/components/MeshConnectExchanges.d.ts.map +1 -1
- package/dist/widget/components/Modal.d.ts.map +1 -1
- package/dist/widget/components/Pay.d.ts +2 -3
- package/dist/widget/components/Pay.d.ts.map +1 -1
- package/dist/widget/components/PoolDeposit.d.ts +3 -3
- package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
- package/dist/widget/components/PoolWithdraw.d.ts +3 -20
- package/dist/widget/components/PoolWithdraw.d.ts.map +1 -1
- package/dist/widget/components/QuoteDetails.d.ts +2 -0
- package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
- package/dist/widget/components/Receipt.d.ts.map +1 -1
- package/dist/widget/components/RecipientSelectorButton.d.ts.map +1 -1
- package/dist/widget/components/ScreenHeader.d.ts.map +1 -1
- package/dist/widget/components/Swap.d.ts +2 -3
- package/dist/widget/components/Swap.d.ts.map +1 -1
- package/dist/widget/components/ThemeProvider.d.ts.map +1 -1
- package/dist/widget/components/TokenDisplayNonSelectable.d.ts +11 -0
- package/dist/widget/components/TokenDisplayNonSelectable.d.ts.map +1 -0
- package/dist/widget/components/TokenSelector.d.ts.map +1 -1
- package/dist/widget/components/TokenSelectorButton.d.ts.map +1 -1
- package/dist/widget/components/Tooltip.d.ts +9 -0
- package/dist/widget/components/Tooltip.d.ts.map +1 -0
- package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -1
- package/dist/widget/components/WaasFeeOptions.d.ts +1 -0
- package/dist/widget/components/WaasFeeOptions.d.ts.map +1 -1
- package/dist/widget/components/WalletConfirmation.d.ts.map +1 -1
- package/dist/widget/components/WalletConnect.d.ts.map +1 -1
- package/dist/widget/css/compiled.css +2 -2
- package/dist/widget/hooks/useCheckout.d.ts +17 -4
- package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
- package/dist/widget/hooks/useDefaultTokenSelection.d.ts.map +1 -1
- package/dist/widget/hooks/useQuote.d.ts +82 -0
- package/dist/widget/hooks/useQuote.d.ts.map +1 -0
- package/dist/widget/hooks/useSelectedFeeToken.d.ts +1 -0
- package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +1 -1
- package/dist/widget/hooks/useSendForm.d.ts +5 -6
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
- package/dist/widget/hooks/useWalletConnectionContext.d.ts +25 -0
- package/dist/widget/hooks/useWalletConnectionContext.d.ts.map +1 -0
- package/dist/widget/index.js +2 -2
- package/dist/widget/widget.d.ts +17 -7
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +19 -21
- package/src/aave.ts +54 -1
- package/src/abortController.ts +35 -0
- package/src/config.ts +57 -58
- package/src/constants.ts +11 -9
- package/src/error.ts +21 -3
- package/src/fees.ts +210 -0
- package/src/index.ts +35 -13
- package/src/intentReceiptMonitor.ts +102 -0
- package/src/intentReceiptPoller.ts +299 -0
- package/src/intents.ts +205 -171
- package/src/morpho.ts +58 -9
- package/src/mutations.ts +129 -0
- package/src/preconditions.ts +16 -21
- package/src/prepareSend.ts +92 -4699
- package/src/prices.ts +26 -22
- package/src/relaySdk.ts +2 -2
- package/src/sequenceWallet.ts +6 -73
- package/src/tokenBalances.ts +175 -69
- package/src/trails.ts +230 -722
- package/src/transactionIntent/constants.ts +11 -0
- package/src/transactionIntent/deposits/depositOrchestrator.ts +210 -0
- package/src/transactionIntent/deposits/gaslessDeposit.ts +588 -0
- package/src/transactionIntent/deposits/index.ts +3 -0
- package/src/transactionIntent/deposits/standardDeposit.ts +379 -0
- package/src/transactionIntent/execution/index.ts +1 -0
- package/src/transactionIntent/execution/transactionState.ts +35 -0
- package/src/transactionIntent/handlers/crossChain.ts +1707 -0
- package/src/transactionIntent/handlers/index.ts +3 -0
- package/src/transactionIntent/handlers/sameChainDifferentToken.ts +323 -0
- package/src/transactionIntent/handlers/sameChainSameToken.ts +712 -0
- package/src/transactionIntent/index.ts +9 -0
- package/src/transactionIntent/quote/feeExtractors.ts +81 -0
- package/src/transactionIntent/quote/index.ts +3 -0
- package/src/transactionIntent/quote/normalizeQuote.ts +367 -0
- package/src/transactionIntent/quote/quoteHelpers.ts +53 -0
- package/src/transactionIntent/types.ts +157 -0
- package/src/transactionIntent/utils/balanceChecker.ts +96 -0
- package/src/transactionIntent/utils/index.ts +3 -0
- package/src/transactionIntent/utils/lifiHelpers.ts +68 -0
- package/src/transactionIntent/utils/testnetHelpers.ts +10 -0
- package/src/transactionIntent/validators.ts +57 -0
- package/src/transactions.ts +98 -71
- package/src/widget/compiled.css +2 -2
- package/src/widget/components/AccountIntentTransactionHistory.tsx +36 -36
- package/src/widget/components/AccountIntentTransactionHistoryButton.tsx +22 -0
- package/src/widget/components/AccountSettings.tsx +70 -41
- package/src/widget/components/ChainFilterDropdown.tsx +24 -3
- package/src/widget/components/ClassicSwap.tsx +44 -107
- package/src/widget/components/ConfigDisplay.tsx +0 -11
- package/src/widget/components/ConnectWallet.tsx +4 -1
- package/src/widget/components/ConnectedWallets.tsx +51 -25
- package/src/widget/components/DynamicInputStyles.tsx +76 -0
- package/src/widget/components/DynamicSizeInputField.tsx +109 -0
- package/src/widget/components/Earn.tsx +34 -45
- package/src/widget/components/ErrorAnimationIcon.tsx +130 -0
- package/src/widget/components/FeeBreakdown.tsx +155 -0
- package/src/widget/components/FeeOption.tsx +2 -2
- package/src/widget/components/FeeOptions.tsx +151 -112
- package/src/widget/components/Fund.tsx +10 -29
- package/src/widget/components/FundMethods.tsx +4 -3
- package/src/widget/components/FundSwap.tsx +2 -3
- package/src/widget/components/FundingMethodSelectorButton.tsx +24 -14
- package/src/widget/components/Identicon.tsx +164 -95
- package/src/widget/components/MeshConnectExchanges.tsx +2 -15
- package/src/widget/components/Modal.tsx +0 -12
- package/src/widget/components/Pay.tsx +72 -75
- package/src/widget/components/PoolDeposit.tsx +221 -242
- package/src/widget/components/PoolWithdraw.tsx +347 -469
- package/src/widget/components/PriceImpactWarning.tsx +1 -1
- package/src/widget/components/QuoteDetails.tsx +906 -484
- package/src/widget/components/Receipt.tsx +16 -2
- package/src/widget/components/RecipientSelectorButton.tsx +7 -5
- package/src/widget/components/Recipients.tsx +1 -1
- package/src/widget/components/ScreenHeader.tsx +60 -36
- package/src/widget/components/Swap.tsx +2 -3
- package/src/widget/components/ThemeProvider.tsx +2 -1
- package/src/widget/components/TokenDisplayNonSelectable.tsx +40 -0
- package/src/widget/components/TokenImage.tsx +1 -1
- package/src/widget/components/TokenSelector.tsx +62 -53
- package/src/widget/components/TokenSelectorButton.tsx +38 -15
- package/src/widget/components/Tooltip.tsx +51 -0
- package/src/widget/components/TransferPendingVertical.tsx +12 -8
- package/src/widget/components/WaasFeeOptions.tsx +139 -4
- package/src/widget/components/WalletConfirmation.tsx +23 -13
- package/src/widget/components/WalletConnect.tsx +93 -29
- package/src/widget/hooks/useAmountUsd.ts +9 -9
- package/src/widget/hooks/useCheckout.ts +97 -9
- package/src/widget/hooks/useDefaultTokenSelection.tsx +27 -21
- package/src/widget/hooks/useQuote.ts +466 -0
- package/src/widget/hooks/useSelectedFeeToken.tsx +32 -37
- package/src/widget/hooks/useSendForm.ts +45 -51
- package/src/widget/hooks/useTokenList.ts +34 -26
- package/src/widget/hooks/useWalletConnectionContext.tsx +128 -0
- package/src/widget/widget.tsx +365 -390
- package/dist/apiClient.d.ts +0 -9
- package/dist/apiClient.d.ts.map +0 -1
- package/dist/intentEntrypoint.d.ts +0 -114
- package/dist/intentEntrypoint.d.ts.map +0 -1
- package/dist/metaTxnMonitor.d.ts +0 -15
- package/dist/metaTxnMonitor.d.ts.map +0 -1
- package/dist/metaTxns.d.ts +0 -11
- package/dist/metaTxns.d.ts.map +0 -1
- package/dist/relayer.d.ts +0 -43
- package/dist/relayer.d.ts.map +0 -1
- package/src/apiClient.ts +0 -35
- package/src/intentEntrypoint.ts +0 -203
- package/src/metaTxnMonitor.ts +0 -171
- package/src/metaTxns.ts +0 -45
- package/src/relayer.ts +0 -289
|
@@ -0,0 +1,712 @@
|
|
|
1
|
+
import type { Account, Chain, WalletClient, TransactionReceipt } from "viem"
|
|
2
|
+
import { createPublicClient, http, formatUnits } from "viem"
|
|
3
|
+
import type { TrailsAPIClient } from "@0xsequence/trails-api"
|
|
4
|
+
import type { MetaTxnReceipt, PrepareSendReturn, SendReturn } from "../types.js"
|
|
5
|
+
import type { TransactionState } from "../../transactions.js"
|
|
6
|
+
import type { CheckoutOnHandlers } from "../../widget/hooks/useCheckout.js"
|
|
7
|
+
import type {
|
|
8
|
+
Intent,
|
|
9
|
+
CommitIntentResponse,
|
|
10
|
+
DepositSignature,
|
|
11
|
+
ExecuteIntentResponse,
|
|
12
|
+
} from "@0xsequence/trails-api"
|
|
13
|
+
import type { SelectedFeeToken } from "../types.js"
|
|
14
|
+
import { logger } from "../../logger.js"
|
|
15
|
+
import {
|
|
16
|
+
isTestnetDebugMode,
|
|
17
|
+
getTestnetOriginTokenAddress,
|
|
18
|
+
} from "../utils/testnetHelpers.js"
|
|
19
|
+
import { checkAccountBalance } from "../utils/balanceChecker.js"
|
|
20
|
+
import { getTestnetChainInfo } from "../../chains.js"
|
|
21
|
+
import { getIsCustomCalldata } from "../../contractUtils.js"
|
|
22
|
+
import {
|
|
23
|
+
buildSameChainSameTokenTransactionParams,
|
|
24
|
+
getIntent,
|
|
25
|
+
commitIntent,
|
|
26
|
+
} from "../../intents.js"
|
|
27
|
+
import { estimateGasLimit } from "../../estimate.js"
|
|
28
|
+
import { getNormalizedQuoteObject } from "../quote/normalizeQuote.js"
|
|
29
|
+
import { attemptSwitchChain } from "../../chainSwitch.js"
|
|
30
|
+
import { attemptUserDepositTx } from "../deposits/depositOrchestrator.js"
|
|
31
|
+
import { getIntentArgs } from "../quote/quoteHelpers.js"
|
|
32
|
+
import { TradeType } from "../types.js"
|
|
33
|
+
import { trackPaymentCompleted, trackPaymentError } from "../../analytics.js"
|
|
34
|
+
import { updatePersistentToast } from "../../toast.js"
|
|
35
|
+
import { getChainInfo } from "../../chains.js"
|
|
36
|
+
import { getTransactionStateFromReceipt } from "../execution/transactionState.js"
|
|
37
|
+
import { calcAmountUsdPrice } from "../../prices.js"
|
|
38
|
+
import { pollIntentReceipt } from "../../intentReceiptPoller.js"
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @description
|
|
42
|
+
* This handler manages simple same-chain token transfers (e.g., using USDC to transact with USDC on the same chain).
|
|
43
|
+
* It supports both standard transfers and custom calldata execution.
|
|
44
|
+
*
|
|
45
|
+
* Key characteristics:
|
|
46
|
+
* - Uses the Trails API with getIntent and commitIntent for setup
|
|
47
|
+
* - Single transaction leg (user transfer)
|
|
48
|
+
* - No cross-chain bridging or token swapping required
|
|
49
|
+
* - Direct transaction submission via attemptUserDepositTx (simpler than cross-chain polling)
|
|
50
|
+
* - Supports both gasless and standard fee payment modes
|
|
51
|
+
*
|
|
52
|
+
* Transaction Flow:
|
|
53
|
+
* 1. Get intent via getIntent (Intent object with validation)
|
|
54
|
+
* 2. Commit intent via commitIntent (Record created in backend)
|
|
55
|
+
* 3. User submits transaction via attemptUserDepositTx (handles both gasless and standard)
|
|
56
|
+
* 4. Wait for transaction receipt (direct receipt polling, not via waitIntentReceipt API)
|
|
57
|
+
* 5. Update transaction state and invoke callbacks
|
|
58
|
+
*
|
|
59
|
+
* Error Handling:
|
|
60
|
+
* - Balance validation before transaction submission
|
|
61
|
+
* - Gas estimation for accurate fee calculation
|
|
62
|
+
* - Proper error propagation with checkout error callbacks
|
|
63
|
+
* - Fallback logging for debugging
|
|
64
|
+
*
|
|
65
|
+
* State Management:
|
|
66
|
+
* - transactionStates[0]: User transfer transaction
|
|
67
|
+
* - Updates propagated via onTransactionStateChange callback
|
|
68
|
+
* - Analytics tracking for payment completion or errors
|
|
69
|
+
* - Support for gasless fee options via gasFeeOptions
|
|
70
|
+
*/
|
|
71
|
+
export async function handleSameChainSameToken({
|
|
72
|
+
mainSignerAddress,
|
|
73
|
+
originTokenAddress,
|
|
74
|
+
originTokenDecimals,
|
|
75
|
+
originTokenSymbol,
|
|
76
|
+
destinationTokenSymbol,
|
|
77
|
+
swapAmount,
|
|
78
|
+
destinationCalldata,
|
|
79
|
+
recipient,
|
|
80
|
+
walletClient,
|
|
81
|
+
onTransactionStateChange,
|
|
82
|
+
dryMode,
|
|
83
|
+
account,
|
|
84
|
+
chain,
|
|
85
|
+
transactionStates,
|
|
86
|
+
sourceTokenPriceUsd,
|
|
87
|
+
destinationTokenPriceUsd,
|
|
88
|
+
originNativeTokenPriceUsd,
|
|
89
|
+
slippageTolerance,
|
|
90
|
+
checkoutOnHandlers,
|
|
91
|
+
mode,
|
|
92
|
+
fundMethod,
|
|
93
|
+
paymasterUrl,
|
|
94
|
+
selectedFeeToken,
|
|
95
|
+
walletId,
|
|
96
|
+
trailsClient,
|
|
97
|
+
abortSignal,
|
|
98
|
+
commitIntentFn,
|
|
99
|
+
executeIntentFn,
|
|
100
|
+
}: {
|
|
101
|
+
mainSignerAddress: string
|
|
102
|
+
originTokenAddress: string
|
|
103
|
+
originTokenDecimals: number
|
|
104
|
+
originTokenSymbol: string
|
|
105
|
+
destinationTokenSymbol: string
|
|
106
|
+
swapAmount: string
|
|
107
|
+
destinationCalldata?: string
|
|
108
|
+
recipient: string
|
|
109
|
+
originChainId: number
|
|
110
|
+
walletClient: WalletClient
|
|
111
|
+
onTransactionStateChange: (transactionStates: TransactionState[]) => void
|
|
112
|
+
dryMode: boolean
|
|
113
|
+
account: Account
|
|
114
|
+
chain: Chain
|
|
115
|
+
transactionStates: TransactionState[]
|
|
116
|
+
sourceTokenPriceUsd?: number | null
|
|
117
|
+
destinationTokenPriceUsd?: number | null
|
|
118
|
+
originNativeTokenPriceUsd?: number | null
|
|
119
|
+
slippageTolerance: string
|
|
120
|
+
checkoutOnHandlers?: CheckoutOnHandlers
|
|
121
|
+
mode?: "pay" | "fund" | "earn" | "swap" | "receive"
|
|
122
|
+
fundMethod?: string
|
|
123
|
+
paymasterUrl?: string
|
|
124
|
+
selectedFeeToken?: SelectedFeeToken
|
|
125
|
+
walletId?: string
|
|
126
|
+
trailsClient: TrailsAPIClient
|
|
127
|
+
abortSignal?: AbortSignal
|
|
128
|
+
commitIntentFn?: (intent: Intent) => Promise<CommitIntentResponse>
|
|
129
|
+
executeIntentFn?: (params: {
|
|
130
|
+
intentId: string
|
|
131
|
+
depositTransactionHash?: string
|
|
132
|
+
depositSignature?: DepositSignature
|
|
133
|
+
}) => Promise<ExecuteIntentResponse>
|
|
134
|
+
}): Promise<PrepareSendReturn> {
|
|
135
|
+
logger.console.log("[trails-sdk] isToSameToken && isToSameChain")
|
|
136
|
+
const testnet = isTestnetDebugMode()
|
|
137
|
+
const effectiveOriginChain = testnet ? getTestnetChainInfo(chain)! : chain
|
|
138
|
+
const effectiveOriginChainId = effectiveOriginChain.id
|
|
139
|
+
const effectiveOriginTokenAddress = testnet
|
|
140
|
+
? getTestnetOriginTokenAddress(effectiveOriginChainId)
|
|
141
|
+
: originTokenAddress
|
|
142
|
+
const effectivePublicClient = createPublicClient({
|
|
143
|
+
chain: effectiveOriginChain,
|
|
144
|
+
transport: http(),
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
let noSufficientBalance = false
|
|
148
|
+
|
|
149
|
+
const { hasEnoughBalance } = await checkAccountBalance({
|
|
150
|
+
account,
|
|
151
|
+
tokenAddress: originTokenAddress,
|
|
152
|
+
depositAmount: swapAmount,
|
|
153
|
+
publicClient: effectivePublicClient,
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
if (!hasEnoughBalance) {
|
|
157
|
+
noSufficientBalance = true
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const hasCustomCalldata = getIsCustomCalldata(destinationCalldata)
|
|
161
|
+
|
|
162
|
+
// For same-chain transactions, use Intent flow to support gasless deposits
|
|
163
|
+
const destinationSalt = Date.now().toString()
|
|
164
|
+
const intentArgs = getIntentArgs(
|
|
165
|
+
mainSignerAddress,
|
|
166
|
+
effectiveOriginChainId,
|
|
167
|
+
effectiveOriginTokenAddress,
|
|
168
|
+
swapAmount, // originTokenAmount
|
|
169
|
+
effectiveOriginChainId, // same chain
|
|
170
|
+
effectiveOriginTokenAddress, // same token
|
|
171
|
+
"0", // destinationTokenAmount (exact input)
|
|
172
|
+
recipient,
|
|
173
|
+
destinationCalldata,
|
|
174
|
+
destinationSalt,
|
|
175
|
+
slippageTolerance,
|
|
176
|
+
TradeType.EXACT_INPUT,
|
|
177
|
+
"", // quoteProvider - empty for same-chain
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
logger.console.log(
|
|
181
|
+
"[trails-sdk] Creating intent for same-chain with args:",
|
|
182
|
+
intentArgs,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
const { intent, gasFeeOptions } = await getIntent(trailsClient, intentArgs, {
|
|
186
|
+
originTokenSymbol,
|
|
187
|
+
destinationTokenSymbol,
|
|
188
|
+
feeTokenSymbol: originTokenSymbol,
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
logger.console.log("[trails-sdk] Got intent:", intent)
|
|
192
|
+
logger.console.log("[trails-sdk] Got gasFeeOptions:", gasFeeOptions)
|
|
193
|
+
|
|
194
|
+
if (!intent.preconditions?.length || !intent.calls?.length) {
|
|
195
|
+
throw new Error("Invalid intent")
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Build origin call params and estimate gas limit for the quote
|
|
199
|
+
const originCallParamsBase = buildSameChainSameTokenTransactionParams({
|
|
200
|
+
hasCustomCalldata,
|
|
201
|
+
recipient,
|
|
202
|
+
effectiveOriginTokenAddress,
|
|
203
|
+
destinationCalldata,
|
|
204
|
+
swapAmount,
|
|
205
|
+
effectiveOriginChainId,
|
|
206
|
+
effectiveOriginChain,
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
logger.console.log(
|
|
210
|
+
"[trails-sdk][gas-estimation] About to estimate gas limit for quote with params:",
|
|
211
|
+
{
|
|
212
|
+
account: account.address,
|
|
213
|
+
to: originCallParamsBase.to,
|
|
214
|
+
data: originCallParamsBase.data,
|
|
215
|
+
value: originCallParamsBase.value,
|
|
216
|
+
},
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
const estimatedGasLimitForQuote = await estimateGasLimit(
|
|
220
|
+
effectivePublicClient,
|
|
221
|
+
{
|
|
222
|
+
account: account.address,
|
|
223
|
+
to: originCallParamsBase.to,
|
|
224
|
+
data: originCallParamsBase.data,
|
|
225
|
+
value: BigInt(originCallParamsBase.value),
|
|
226
|
+
},
|
|
227
|
+
"quote",
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
logger.console.log(
|
|
231
|
+
"[trails-sdk][gas-estimation] Estimated gas limit for quote:",
|
|
232
|
+
estimatedGasLimitForQuote,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
const quote = await getNormalizedQuoteObject({
|
|
236
|
+
originDepositAddress: intent.originIntentAddress,
|
|
237
|
+
destinationDepositAddress: intent.destinationIntentAddress,
|
|
238
|
+
destinationAddress: recipient,
|
|
239
|
+
destinationCalldata,
|
|
240
|
+
originAmount: swapAmount,
|
|
241
|
+
destinationAmount: swapAmount,
|
|
242
|
+
originTokenPriceUsd: sourceTokenPriceUsd?.toString() || null,
|
|
243
|
+
destinationTokenPriceUsd: destinationTokenPriceUsd?.toString() || null,
|
|
244
|
+
originTokenAddress: effectiveOriginTokenAddress,
|
|
245
|
+
destinationTokenAddress: effectiveOriginTokenAddress,
|
|
246
|
+
transactionStates,
|
|
247
|
+
originChainId: effectiveOriginChainId,
|
|
248
|
+
destinationChainId: effectiveOriginChainId,
|
|
249
|
+
originNativeTokenPriceUsd,
|
|
250
|
+
slippageTolerance,
|
|
251
|
+
quoteProvider: intent.quote?.quoteProvider || "",
|
|
252
|
+
noSufficientBalance,
|
|
253
|
+
estimatedGasLimit: estimatedGasLimitForQuote,
|
|
254
|
+
intent,
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
// Call onCheckoutQuote callback if provided
|
|
258
|
+
if (checkoutOnHandlers?.triggerCheckoutQuote) {
|
|
259
|
+
checkoutOnHandlers.triggerCheckoutQuote(quote)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Log gasless fee options availability
|
|
263
|
+
if (gasFeeOptions && walletId !== "sequence-waas") {
|
|
264
|
+
logger.console.log(
|
|
265
|
+
"[trails-sdk] [GASLESS-FLOW] [FEE-SELECT] Gasless enabled for same-chain. Using gasFeeOptions from QuoteIntent response",
|
|
266
|
+
{ originChainId: effectiveOriginChainId, gasFeeOptions },
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
quote,
|
|
272
|
+
feeOptions: gasFeeOptions,
|
|
273
|
+
send: async ({
|
|
274
|
+
onOriginSend,
|
|
275
|
+
selectedFeeToken: runtimeSelectedFeeToken,
|
|
276
|
+
}: {
|
|
277
|
+
onOriginSend?: () => void
|
|
278
|
+
selectedFeeToken?: any
|
|
279
|
+
}): Promise<SendReturn> => {
|
|
280
|
+
// Use runtime selectedFeeToken if provided, otherwise fall back to the one from prepareSend
|
|
281
|
+
const effectiveSelectedFeeToken =
|
|
282
|
+
runtimeSelectedFeeToken ?? selectedFeeToken
|
|
283
|
+
const effectiveGasless =
|
|
284
|
+
effectiveSelectedFeeToken !== null &&
|
|
285
|
+
effectiveSelectedFeeToken !== undefined &&
|
|
286
|
+
walletId !== "sequence-waas"
|
|
287
|
+
logger.console.log(
|
|
288
|
+
"[trails-sdk] [FEE-SELECT] [GASLESS-FLOW] send() called for same-chain:",
|
|
289
|
+
{
|
|
290
|
+
runtimeSelectedFeeToken,
|
|
291
|
+
prepareTimeSelectedFeeToken: selectedFeeToken,
|
|
292
|
+
effectiveSelectedFeeToken,
|
|
293
|
+
effectiveGasless,
|
|
294
|
+
},
|
|
295
|
+
)
|
|
296
|
+
try {
|
|
297
|
+
const { hasEnoughBalance, balanceError } = await checkAccountBalance({
|
|
298
|
+
account,
|
|
299
|
+
tokenAddress: effectiveOriginTokenAddress,
|
|
300
|
+
depositAmount: swapAmount,
|
|
301
|
+
publicClient: effectivePublicClient,
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
if (!hasEnoughBalance) {
|
|
305
|
+
throw balanceError
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const depositAmountFormatted = Number(
|
|
309
|
+
formatUnits(BigInt(swapAmount), originTokenDecimals),
|
|
310
|
+
)
|
|
311
|
+
const depositAmountUsd = calcAmountUsdPrice({
|
|
312
|
+
amount: depositAmountFormatted,
|
|
313
|
+
usdPrice: sourceTokenPriceUsd,
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
const hasCustomCalldata = getIsCustomCalldata(destinationCalldata)
|
|
317
|
+
|
|
318
|
+
// Build origin call params (reusing the same logic as quote estimation)
|
|
319
|
+
const originCallParamsBase = buildSameChainSameTokenTransactionParams({
|
|
320
|
+
hasCustomCalldata,
|
|
321
|
+
recipient,
|
|
322
|
+
effectiveOriginTokenAddress,
|
|
323
|
+
destinationCalldata,
|
|
324
|
+
swapAmount,
|
|
325
|
+
effectiveOriginChainId,
|
|
326
|
+
effectiveOriginChain,
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
// Estimate gas limit for consistency with actual transaction
|
|
330
|
+
const gasLimit = await estimateGasLimit(
|
|
331
|
+
effectivePublicClient,
|
|
332
|
+
{
|
|
333
|
+
account: account.address,
|
|
334
|
+
to: originCallParamsBase.to,
|
|
335
|
+
data: originCallParamsBase.data,
|
|
336
|
+
value: BigInt(originCallParamsBase.value),
|
|
337
|
+
},
|
|
338
|
+
"send",
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
const originCallParams = {
|
|
342
|
+
...originCallParamsBase,
|
|
343
|
+
gasLimit,
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
logger.console.log("[trails-sdk] origin call params", originCallParams)
|
|
347
|
+
|
|
348
|
+
let depositUserTxnReceipt: TransactionReceipt | null = null
|
|
349
|
+
const originMetaTxnReceipt: MetaTxnReceipt | null = null
|
|
350
|
+
const destinationMetaTxnReceipt: MetaTxnReceipt | null = null
|
|
351
|
+
|
|
352
|
+
// Commit the intent
|
|
353
|
+
const commitIntentFnToUse =
|
|
354
|
+
commitIntentFn ||
|
|
355
|
+
((intent: Intent) =>
|
|
356
|
+
commitIntent(trailsClient, intent, {
|
|
357
|
+
originTokenSymbol,
|
|
358
|
+
destinationTokenSymbol,
|
|
359
|
+
}))
|
|
360
|
+
await commitIntentFnToUse(intent)
|
|
361
|
+
|
|
362
|
+
logger.console.log(
|
|
363
|
+
"[trails-sdk] Intent committed for same-chain transaction",
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
await attemptSwitchChain({
|
|
367
|
+
walletClient,
|
|
368
|
+
desiredChainId: effectiveOriginChainId,
|
|
369
|
+
})
|
|
370
|
+
if (!dryMode) {
|
|
371
|
+
// For gasless flows on same-chain same-token, we need to track 2 transactions:
|
|
372
|
+
// [0] = Deposit transaction (relayed)
|
|
373
|
+
// [1] = Origin intent transaction (executed on chain after deposit is confirmed)
|
|
374
|
+
|
|
375
|
+
// Initialize local transaction states for gasless flows to track both deposit and execute
|
|
376
|
+
const createInitialStates = (): TransactionState[] => {
|
|
377
|
+
const depositState: TransactionState = {
|
|
378
|
+
transactionHash: "",
|
|
379
|
+
explorerUrl: "",
|
|
380
|
+
chainId: effectiveOriginChainId,
|
|
381
|
+
state: "pending",
|
|
382
|
+
label: effectiveGasless ? "Deposit" : "Execute",
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const executeState: TransactionState = {
|
|
386
|
+
transactionHash: "",
|
|
387
|
+
explorerUrl: "",
|
|
388
|
+
chainId: effectiveOriginChainId,
|
|
389
|
+
state: "pending",
|
|
390
|
+
label: "Execute",
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return effectiveGasless
|
|
394
|
+
? [depositState, executeState]
|
|
395
|
+
: [depositState]
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const localTransactionStates = createInitialStates()
|
|
399
|
+
|
|
400
|
+
try {
|
|
401
|
+
onTransactionStateChange(localTransactionStates)
|
|
402
|
+
} catch (error) {
|
|
403
|
+
logger.console.error(
|
|
404
|
+
"[trails-sdk] Error calling onTransactionStateChange:",
|
|
405
|
+
error,
|
|
406
|
+
)
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// For gasless flows, pass the localTransactionStates instead of the input parameter
|
|
410
|
+
// This ensures we track both deposit and execute transactions
|
|
411
|
+
const statesForDeposit = effectiveGasless
|
|
412
|
+
? localTransactionStates
|
|
413
|
+
: transactionStates
|
|
414
|
+
|
|
415
|
+
// Use attemptUserDepositTx which handles both gasless and non-gasless flows
|
|
416
|
+
// For non-gasless same-chain same-token, pass recipient to send directly to user instead of intent contract
|
|
417
|
+
depositUserTxnReceipt = await attemptUserDepositTx({
|
|
418
|
+
originTokenAddress: effectiveOriginTokenAddress,
|
|
419
|
+
paymasterUrl,
|
|
420
|
+
chain: effectiveOriginChain,
|
|
421
|
+
account,
|
|
422
|
+
firstPreconditionMin: swapAmount,
|
|
423
|
+
originIntentAddress: intent.originIntentAddress,
|
|
424
|
+
onOriginSend,
|
|
425
|
+
publicClient: effectivePublicClient,
|
|
426
|
+
walletClient,
|
|
427
|
+
destinationTokenDecimals: originTokenDecimals,
|
|
428
|
+
sourceTokenDecimals: originTokenDecimals,
|
|
429
|
+
fee: "0",
|
|
430
|
+
dryMode,
|
|
431
|
+
sourceTokenPriceUsd: sourceTokenPriceUsd ?? null,
|
|
432
|
+
destinationTokenPriceUsd: destinationTokenPriceUsd ?? null,
|
|
433
|
+
swapAmount,
|
|
434
|
+
onTransactionStateChange,
|
|
435
|
+
transactionStates: statesForDeposit,
|
|
436
|
+
fundMethod,
|
|
437
|
+
originTokenSymbol,
|
|
438
|
+
destinationTokenSymbol,
|
|
439
|
+
depositAmountUsd,
|
|
440
|
+
feeOptions: gasFeeOptions,
|
|
441
|
+
trailsClient,
|
|
442
|
+
selectedFeeToken: effectiveSelectedFeeToken,
|
|
443
|
+
walletId,
|
|
444
|
+
abortSignal,
|
|
445
|
+
checkoutOnHandlers,
|
|
446
|
+
intentId: intent.intentId,
|
|
447
|
+
executeIntentFn,
|
|
448
|
+
depositRecipientOverride: recipient,
|
|
449
|
+
isSameChainSameToken: true,
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
// attemptUserDepositTx handles both gasless and non-gasless flows
|
|
453
|
+
// Transaction state updates and toasts are handled within that function
|
|
454
|
+
logger.console.log("[trails-sdk] Deposit transaction completed", {
|
|
455
|
+
hasReceipt: !!depositUserTxnReceipt,
|
|
456
|
+
isGasless: effectiveGasless,
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
// For gasless flows, start polling for both deposit and origin transactions via API
|
|
460
|
+
if (effectiveGasless && !depositUserTxnReceipt) {
|
|
461
|
+
logger.console.log(
|
|
462
|
+
"[trails-sdk] Starting unified polling for gasless same-chain transaction with 2 states",
|
|
463
|
+
)
|
|
464
|
+
try {
|
|
465
|
+
await pollIntentReceipt({
|
|
466
|
+
intentId: intent.intentId,
|
|
467
|
+
trailsClient,
|
|
468
|
+
callbacks: {
|
|
469
|
+
onDepositTransactionFound: async (txHash) => {
|
|
470
|
+
logger.console.log(
|
|
471
|
+
"[trails-sdk] Deposit transaction discovered for same-chain gasless flow",
|
|
472
|
+
{ txHash },
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
if (localTransactionStates[0]) {
|
|
476
|
+
try {
|
|
477
|
+
const depositTxReceipt =
|
|
478
|
+
await effectivePublicClient.getTransactionReceipt({
|
|
479
|
+
hash: txHash as `0x${string}`,
|
|
480
|
+
})
|
|
481
|
+
logger.console.log(
|
|
482
|
+
"[trails-sdk] Deposit transaction receipt fetched",
|
|
483
|
+
{
|
|
484
|
+
txHash,
|
|
485
|
+
blockNumber: depositTxReceipt?.blockNumber,
|
|
486
|
+
status: depositTxReceipt?.status,
|
|
487
|
+
},
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
localTransactionStates[0] =
|
|
491
|
+
getTransactionStateFromReceipt(
|
|
492
|
+
depositTxReceipt,
|
|
493
|
+
effectiveOriginChainId,
|
|
494
|
+
localTransactionStates[0]?.label,
|
|
495
|
+
)
|
|
496
|
+
onTransactionStateChange(localTransactionStates)
|
|
497
|
+
} catch (error) {
|
|
498
|
+
logger.console.error(
|
|
499
|
+
"[trails-sdk] Error fetching deposit transaction receipt:",
|
|
500
|
+
error,
|
|
501
|
+
)
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
onOriginTransactionFound: async (originTxHash) => {
|
|
506
|
+
logger.console.log(
|
|
507
|
+
"[trails-sdk] Origin intent transaction discovered for same-chain gasless flow",
|
|
508
|
+
{ originTxHash },
|
|
509
|
+
)
|
|
510
|
+
|
|
511
|
+
// For same-chain gasless, localTransactionStates[1] is the origin intent transaction
|
|
512
|
+
if (localTransactionStates[1]) {
|
|
513
|
+
try {
|
|
514
|
+
const originTxReceipt =
|
|
515
|
+
await effectivePublicClient.getTransactionReceipt({
|
|
516
|
+
hash: originTxHash as `0x${string}`,
|
|
517
|
+
})
|
|
518
|
+
logger.console.log(
|
|
519
|
+
"[trails-sdk] Origin transaction receipt fetched",
|
|
520
|
+
{
|
|
521
|
+
originTxHash,
|
|
522
|
+
blockNumber: originTxReceipt?.blockNumber,
|
|
523
|
+
status: originTxReceipt?.status,
|
|
524
|
+
},
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
localTransactionStates[1] =
|
|
528
|
+
getTransactionStateFromReceipt(
|
|
529
|
+
originTxReceipt,
|
|
530
|
+
effectiveOriginChainId,
|
|
531
|
+
localTransactionStates[1]?.label,
|
|
532
|
+
)
|
|
533
|
+
onTransactionStateChange(localTransactionStates)
|
|
534
|
+
} catch (error) {
|
|
535
|
+
logger.console.error(
|
|
536
|
+
"[trails-sdk] Error fetching origin transaction receipt:",
|
|
537
|
+
error,
|
|
538
|
+
)
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
},
|
|
542
|
+
},
|
|
543
|
+
maxWaitTime: 120000, // 120 seconds max wait for both transactions
|
|
544
|
+
})
|
|
545
|
+
} catch (error) {
|
|
546
|
+
logger.console.error(
|
|
547
|
+
"[trails-sdk] Error polling for gasless same-chain transactions:",
|
|
548
|
+
error,
|
|
549
|
+
)
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (depositUserTxnReceipt) {
|
|
554
|
+
try {
|
|
555
|
+
const updatedStates = [
|
|
556
|
+
getTransactionStateFromReceipt(
|
|
557
|
+
depositUserTxnReceipt,
|
|
558
|
+
effectiveOriginChainId,
|
|
559
|
+
transactionStates[0]?.label,
|
|
560
|
+
),
|
|
561
|
+
]
|
|
562
|
+
onTransactionStateChange(updatedStates)
|
|
563
|
+
} catch (error) {
|
|
564
|
+
logger.console.error(
|
|
565
|
+
"[trails-sdk] Error calling onTransactionStateChange:",
|
|
566
|
+
error,
|
|
567
|
+
)
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// Show conditional toast based on transaction status
|
|
572
|
+
const chainInfo = getChainInfo(effectiveOriginChainId)
|
|
573
|
+
if (depositUserTxnReceipt) {
|
|
574
|
+
if (depositUserTxnReceipt?.status === "success") {
|
|
575
|
+
updatePersistentToast(
|
|
576
|
+
"Transfer Confirmed",
|
|
577
|
+
`Your transaction on ${chainInfo?.name || "chain"} has been confirmed`,
|
|
578
|
+
"info",
|
|
579
|
+
)
|
|
580
|
+
} else {
|
|
581
|
+
updatePersistentToast(
|
|
582
|
+
"Transfer Failed",
|
|
583
|
+
`Your transaction on ${chainInfo?.name || "chain"} failed`,
|
|
584
|
+
"error",
|
|
585
|
+
)
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Track payment completion for same-chain same-token transaction
|
|
590
|
+
if (
|
|
591
|
+
depositUserTxnReceipt &&
|
|
592
|
+
depositUserTxnReceipt.status === "success"
|
|
593
|
+
) {
|
|
594
|
+
// Check if any transaction failed or was refunded
|
|
595
|
+
const hasAnyCallFailed = transactionStates.some((tx) =>
|
|
596
|
+
tx?.decodedGuestModuleEvents?.some(
|
|
597
|
+
(e: any) => e?.type === "CallFailed",
|
|
598
|
+
),
|
|
599
|
+
)
|
|
600
|
+
const hasAnyRefunded = transactionStates.some((tx) => tx?.refunded)
|
|
601
|
+
const txStatus =
|
|
602
|
+
!hasAnyCallFailed && !hasAnyRefunded ? "success" : "fail"
|
|
603
|
+
|
|
604
|
+
// Always track payment completion regardless of success/failure
|
|
605
|
+
trackPaymentCompleted({
|
|
606
|
+
userAddress: account.address,
|
|
607
|
+
originTxHash: depositUserTxnReceipt.transactionHash,
|
|
608
|
+
originChainId: effectiveOriginChainId, // Same chain
|
|
609
|
+
mode,
|
|
610
|
+
fundMethod,
|
|
611
|
+
originTokenAddress,
|
|
612
|
+
depositTokenAmountUsd: depositAmountUsd?.toString(),
|
|
613
|
+
destinationTokenAmountUsd: depositAmountUsd?.toString(), // same as deposit amount
|
|
614
|
+
})
|
|
615
|
+
|
|
616
|
+
// Call onCheckoutComplete callback with transaction status
|
|
617
|
+
if (checkoutOnHandlers?.triggerCheckoutComplete) {
|
|
618
|
+
checkoutOnHandlers.triggerCheckoutComplete(
|
|
619
|
+
txStatus,
|
|
620
|
+
account.address,
|
|
621
|
+
)
|
|
622
|
+
}
|
|
623
|
+
} else if (depositUserTxnReceipt) {
|
|
624
|
+
trackPaymentError({
|
|
625
|
+
error: "Transaction failed",
|
|
626
|
+
userAddress: account.address,
|
|
627
|
+
mode,
|
|
628
|
+
fundMethod,
|
|
629
|
+
originTokenAddress,
|
|
630
|
+
})
|
|
631
|
+
|
|
632
|
+
// Call onCheckoutError callback if provided
|
|
633
|
+
if (checkoutOnHandlers?.triggerCheckoutError) {
|
|
634
|
+
checkoutOnHandlers.triggerCheckoutError("Transaction failed")
|
|
635
|
+
}
|
|
636
|
+
} else if (effectiveGasless && !depositUserTxnReceipt) {
|
|
637
|
+
// For gasless flows with polling, check if both transactions are confirmed
|
|
638
|
+
const depositConfirmed =
|
|
639
|
+
localTransactionStates[0]?.state === "confirmed"
|
|
640
|
+
const originConfirmed =
|
|
641
|
+
localTransactionStates[1]?.state === "confirmed"
|
|
642
|
+
|
|
643
|
+
if (depositConfirmed && originConfirmed) {
|
|
644
|
+
logger.console.log(
|
|
645
|
+
"[trails-sdk] Gasless same-chain transaction fully completed via polling",
|
|
646
|
+
)
|
|
647
|
+
const txStatus = "success"
|
|
648
|
+
|
|
649
|
+
trackPaymentCompleted({
|
|
650
|
+
userAddress: account.address,
|
|
651
|
+
originTxHash:
|
|
652
|
+
localTransactionStates[0]?.transactionHash ||
|
|
653
|
+
localTransactionStates[1]?.transactionHash,
|
|
654
|
+
originChainId: effectiveOriginChainId,
|
|
655
|
+
mode,
|
|
656
|
+
fundMethod,
|
|
657
|
+
originTokenAddress,
|
|
658
|
+
depositTokenAmountUsd: depositAmountUsd?.toString(),
|
|
659
|
+
destinationTokenAmountUsd: depositAmountUsd?.toString(),
|
|
660
|
+
})
|
|
661
|
+
|
|
662
|
+
// Call onCheckoutComplete callback with transaction status
|
|
663
|
+
if (checkoutOnHandlers?.triggerCheckoutComplete) {
|
|
664
|
+
checkoutOnHandlers.triggerCheckoutComplete(
|
|
665
|
+
txStatus,
|
|
666
|
+
account.address,
|
|
667
|
+
)
|
|
668
|
+
}
|
|
669
|
+
} else if (depositConfirmed) {
|
|
670
|
+
logger.console.log(
|
|
671
|
+
"[trails-sdk] Gasless same-chain deposit confirmed, waiting for origin transaction",
|
|
672
|
+
)
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
return {
|
|
678
|
+
depositUserTxnReceipt,
|
|
679
|
+
originMetaTxnReceipt,
|
|
680
|
+
destinationMetaTxnReceipt,
|
|
681
|
+
totalCompletionSeconds: 0,
|
|
682
|
+
}
|
|
683
|
+
} catch (error) {
|
|
684
|
+
const errorMessage =
|
|
685
|
+
error instanceof Error
|
|
686
|
+
? error.message
|
|
687
|
+
: "Unknown error occurred during transaction"
|
|
688
|
+
logger.console.error(
|
|
689
|
+
"[trails-sdk] Error in sendHandlerForSameChainSameToken:",
|
|
690
|
+
error,
|
|
691
|
+
)
|
|
692
|
+
|
|
693
|
+
// Track payment error
|
|
694
|
+
trackPaymentError({
|
|
695
|
+
error: errorMessage,
|
|
696
|
+
userAddress: account.address,
|
|
697
|
+
mode,
|
|
698
|
+
fundMethod,
|
|
699
|
+
originTokenAddress,
|
|
700
|
+
})
|
|
701
|
+
|
|
702
|
+
// Call onCheckoutError callback if provided
|
|
703
|
+
if (checkoutOnHandlers?.triggerCheckoutError) {
|
|
704
|
+
checkoutOnHandlers.triggerCheckoutError(errorMessage)
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Re-throw the error so caller can handle if needed
|
|
708
|
+
throw error
|
|
709
|
+
}
|
|
710
|
+
},
|
|
711
|
+
}
|
|
712
|
+
}
|