0xtrails 0.4.3 → 0.6.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/analytics.d.ts +8 -3
- package/dist/analytics.d.ts.map +1 -1
- package/dist/{ccip-C9CA3tIi.js → ccip-Dw5AN7oU.js} +27 -27
- package/dist/cctp.d.ts +0 -149
- package/dist/cctp.d.ts.map +1 -1
- package/dist/chains.d.ts +31 -4
- package/dist/chains.d.ts.map +1 -1
- package/dist/config.d.ts +28 -52
- package/dist/config.d.ts.map +1 -1
- package/dist/constants.d.ts +1 -7
- package/dist/constants.d.ts.map +1 -1
- package/dist/contractUtils.d.ts.map +1 -1
- package/dist/estimate.d.ts.map +1 -1
- package/dist/fees.d.ts.map +1 -1
- package/dist/gasless.d.ts +12 -0
- package/dist/gasless.d.ts.map +1 -1
- package/dist/{index-CNB57v0n.js → index-BtVUTbEZ.js} +32255 -40547
- package/dist/index.d.ts +13 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +320 -944
- package/dist/indexerClient.d.ts +9 -6
- package/dist/indexerClient.d.ts.map +1 -1
- package/dist/intents.d.ts +0 -18
- package/dist/intents.d.ts.map +1 -1
- package/dist/mutations.d.ts.map +1 -1
- package/dist/paymasterSend.d.ts.map +1 -1
- package/dist/prepareSend.d.ts +1 -1
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/sendUserOp.d.ts +0 -18
- package/dist/sendUserOp.d.ts.map +1 -1
- package/dist/sequenceWallet.d.ts +1 -1
- package/dist/sequenceWallet.d.ts.map +1 -1
- package/dist/tokenBalances.d.ts.map +1 -1
- package/dist/tokens.d.ts +10 -8
- package/dist/tokens.d.ts.map +1 -1
- package/dist/trailsClient.d.ts +3 -3
- package/dist/trailsClient.d.ts.map +1 -1
- package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +4 -5
- package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -1
- package/dist/transactionIntent/deposits/gaslessDeposit.d.ts +4 -5
- package/dist/transactionIntent/deposits/gaslessDeposit.d.ts.map +1 -1
- package/dist/transactionIntent/deposits/standardDeposit.d.ts +2 -2
- package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -1
- package/dist/transactionIntent/execution/transactionState.d.ts +2 -2
- package/dist/transactionIntent/execution/transactionState.d.ts.map +1 -1
- package/dist/transactionIntent/handlers/crossChain.d.ts +6 -4
- package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -1
- package/dist/transactionIntent/handlers/index.d.ts +0 -1
- package/dist/transactionIntent/handlers/index.d.ts.map +1 -1
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts +4 -34
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -1
- package/dist/transactionIntent/quote/normalizeQuote.d.ts.map +1 -1
- package/dist/transactionIntent/quote/quoteHelpers.d.ts +2 -1
- package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -1
- package/dist/transactionIntent/types.d.ts +7 -19
- package/dist/transactionIntent/types.d.ts.map +1 -1
- package/dist/transactionIntent/utils/index.d.ts +0 -1
- package/dist/transactionIntent/utils/index.d.ts.map +1 -1
- package/dist/transactions.d.ts +6 -18
- package/dist/transactions.d.ts.map +1 -1
- package/dist/utils.d.ts +8 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/walletUtils.d.ts +21 -0
- package/dist/walletUtils.d.ts.map +1 -0
- package/dist/wallets.d.ts +33 -240
- package/dist/wallets.d.ts.map +1 -1
- package/dist/widget/components/AccountIntentTransactionHistory.d.ts.map +1 -1
- package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
- package/dist/widget/components/ConfigDisplay.d.ts.map +1 -1
- package/dist/widget/components/FeeOption.d.ts +8 -13
- package/dist/widget/components/FeeOption.d.ts.map +1 -1
- package/dist/widget/components/FeeOptions.d.ts +11 -5
- package/dist/widget/components/FeeOptions.d.ts.map +1 -1
- package/dist/widget/components/NativeGasOption.d.ts.map +1 -1
- package/dist/widget/components/Pay.d.ts.map +1 -1
- package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
- package/dist/widget/components/QRCodeDeposit.d.ts +5 -0
- package/dist/widget/components/QRCodeDeposit.d.ts.map +1 -1
- package/dist/widget/components/QRCodeWalletSelect.d.ts +13 -0
- package/dist/widget/components/QRCodeWalletSelect.d.ts.map +1 -0
- package/dist/widget/components/QrCode.d.ts.map +1 -1
- package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
- package/dist/widget/components/Receipt.d.ts.map +1 -1
- package/dist/widget/components/ScreenHeader.d.ts +1 -1
- package/dist/widget/components/ScreenHeader.d.ts.map +1 -1
- package/dist/widget/components/SlippageToleranceSettings.d.ts +1 -0
- package/dist/widget/components/SlippageToleranceSettings.d.ts.map +1 -1
- package/dist/widget/components/Toast.d.ts.map +1 -1
- package/dist/widget/components/TokenImage.d.ts.map +1 -1
- package/dist/widget/components/WalletConnect.d.ts.map +1 -1
- package/dist/widget/css/compiled.css +1 -1
- package/dist/widget/hooks/useCheckout.d.ts +15 -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/useDebugScreens.d.ts +1 -1
- package/dist/widget/hooks/useDebugScreens.d.ts.map +1 -1
- package/dist/widget/hooks/useIntentTransactionHistory.d.ts.map +1 -1
- package/dist/widget/hooks/useIsConnectedWalletSmartContract.d.ts +7 -0
- package/dist/widget/hooks/useIsConnectedWalletSmartContract.d.ts.map +1 -0
- package/dist/widget/hooks/useIsSequenceWallet.d.ts +6 -0
- package/dist/widget/hooks/useIsSequenceWallet.d.ts.map +1 -0
- package/dist/widget/hooks/useQuote.d.ts +6 -11
- package/dist/widget/hooks/useQuote.d.ts.map +1 -1
- package/dist/widget/hooks/useRecentTokens.d.ts.map +1 -1
- package/dist/widget/hooks/useSelectedFeeOption.d.ts +30 -0
- package/dist/widget/hooks/useSelectedFeeOption.d.ts.map +1 -0
- package/dist/widget/hooks/useSendForm.d.ts +6 -15
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
- package/dist/widget/index.d.ts +1 -0
- package/dist/widget/index.d.ts.map +1 -1
- package/dist/widget/index.js +4 -2
- package/dist/widget/providers/TrailsProvider.d.ts +29 -0
- package/dist/widget/providers/TrailsProvider.d.ts.map +1 -0
- package/dist/widget/widget.d.ts +14 -3
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +9 -8
- package/src/analytics.ts +53 -21
- package/src/cctp.ts +0 -1016
- package/src/chains.ts +155 -68
- package/src/config.ts +51 -207
- package/src/constants.ts +1 -13
- package/src/contractUtils.ts +6 -6
- package/src/estimate.ts +3 -6
- package/src/fees.ts +5 -10
- package/src/gasless.ts +45 -0
- package/src/index.ts +18 -40
- package/src/indexerClient.ts +39 -48
- package/src/intents.ts +51 -226
- package/src/mutations.ts +3 -2
- package/src/paymasterSend.ts +2 -5
- package/src/prepareSend.ts +21 -14
- package/src/sendUserOp.ts +3 -64
- package/src/sequenceWallet.ts +1 -2
- package/src/tokenBalances.ts +2 -1
- package/src/tokens.ts +62 -133
- package/src/trailsClient.ts +17 -12
- package/src/transactionIntent/deposits/depositOrchestrator.ts +14 -15
- package/src/transactionIntent/deposits/gaslessDeposit.ts +70 -100
- package/src/transactionIntent/deposits/standardDeposit.ts +22 -28
- package/src/transactionIntent/execution/transactionState.ts +2 -2
- package/src/transactionIntent/handlers/crossChain.ts +179 -381
- package/src/transactionIntent/handlers/index.ts +0 -1
- package/src/transactionIntent/handlers/sameChainSameToken.ts +228 -94
- package/src/transactionIntent/quote/normalizeQuote.ts +4 -6
- package/src/transactionIntent/quote/quoteHelpers.ts +35 -3
- package/src/transactionIntent/types.ts +7 -27
- package/src/transactionIntent/utils/index.ts +0 -1
- package/src/transactions.ts +19 -118
- package/src/umd.tsx +1 -3
- package/src/utils.ts +28 -8
- package/src/walletUtils.ts +42 -0
- package/src/wallets.ts +365 -208
- package/src/widget/compiled.css +1 -1
- package/src/widget/components/AccountIntentTransactionHistory.tsx +78 -4
- package/src/widget/components/AccountSettings.tsx +17 -17
- package/src/widget/components/ChainList.tsx +3 -3
- package/src/widget/components/ClassicSwap.tsx +19 -10
- package/src/widget/components/ConfigDisplay.tsx +19 -59
- package/src/widget/components/FeeOption.tsx +63 -20
- package/src/widget/components/FeeOptions.tsx +54 -123
- package/src/widget/components/NativeGasOption.tsx +3 -1
- package/src/widget/components/Pay.tsx +18 -11
- package/src/widget/components/PoolDeposit.tsx +23 -10
- package/src/widget/components/QRCodeDeposit.tsx +50 -30
- package/src/widget/components/QRCodeWalletSelect.tsx +77 -0
- package/src/widget/components/QrCode.tsx +188 -233
- package/src/widget/components/QuoteDetails.tsx +48 -2
- package/src/widget/components/Receipt.tsx +5 -2
- package/src/widget/components/ScreenHeader.tsx +10 -8
- package/src/widget/components/SlippageToleranceSettings.tsx +63 -14
- package/src/widget/components/Toast.tsx +10 -0
- package/src/widget/components/TokenImage.tsx +56 -13
- package/src/widget/components/WalletConnect.tsx +37 -99
- package/src/widget/hooks/useCheckout.ts +71 -0
- package/src/widget/hooks/useCurrentScreen.tsx +1 -0
- package/src/widget/hooks/useDebugScreens.ts +5 -0
- package/src/widget/hooks/useIntentTransactionHistory.ts +790 -412
- package/src/widget/hooks/useIsConnectedWalletSmartContract.ts +43 -0
- package/src/widget/hooks/useIsSequenceWallet.ts +17 -0
- package/src/widget/hooks/useQuote.ts +27 -34
- package/src/widget/hooks/useRecentTokens.ts +2 -1
- package/src/widget/hooks/useSelectedFeeOption.tsx +257 -0
- package/src/widget/hooks/useSendForm.ts +175 -46
- package/src/widget/hooks/useTokenList.ts +15 -2
- package/src/widget/index.tsx +8 -0
- package/src/widget/providers/TrailsProvider.tsx +123 -0
- package/src/widget/widget.tsx +165 -143
- package/dist/cctpqueue.d.ts +0 -18
- package/dist/cctpqueue.d.ts.map +0 -1
- package/dist/preconditions.d.ts +0 -12
- package/dist/preconditions.d.ts.map +0 -1
- package/dist/trails.d.ts +0 -110
- package/dist/trails.d.ts.map +0 -1
- package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts +0 -62
- package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts.map +0 -1
- package/dist/transactionIntent/utils/lifiHelpers.d.ts +0 -10
- package/dist/transactionIntent/utils/lifiHelpers.d.ts.map +0 -1
- package/dist/widget/hooks/useSelectedFeeToken.d.ts +0 -33
- package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +0 -1
- package/src/cctpqueue.ts +0 -66
- package/src/preconditions.ts +0 -47
- package/src/trails.ts +0 -1303
- package/src/transactionIntent/handlers/sameChainDifferentToken.ts +0 -323
- package/src/transactionIntent/utils/lifiHelpers.ts +0 -68
- package/src/widget/hooks/useSelectedFeeToken.tsx +0 -288
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { TokenPrice } from "@0xsequence/trails-api"
|
|
1
|
+
import type { TokenPrice, FeeOption } from "@0xsequence/trails-api"
|
|
2
|
+
import { JsonEncode } from "@0xsequence/trails-api"
|
|
2
3
|
import type React from "react"
|
|
3
4
|
import { useCallback, useEffect, useMemo, useState, useRef } from "react"
|
|
4
5
|
import {
|
|
@@ -17,7 +18,6 @@ import {
|
|
|
17
18
|
TradeType,
|
|
18
19
|
type PrepareSendReturn,
|
|
19
20
|
type PrepareSendQuote,
|
|
20
|
-
type SelectedFeeToken,
|
|
21
21
|
} from "../../prepareSend.js"
|
|
22
22
|
import type { TransactionState } from "../../transactions.js"
|
|
23
23
|
import { getTokenPrice, useTokenPrices, normalizeNumber } from "../../prices.js"
|
|
@@ -40,8 +40,12 @@ import { etherlink } from "viem/chains"
|
|
|
40
40
|
import { logger } from "../../logger.js"
|
|
41
41
|
import { getIsContract } from "../../contractUtils.js"
|
|
42
42
|
import { useTrailsClient } from "../../trailsClient.js"
|
|
43
|
+
import { useTrails } from "../providers/TrailsProvider.js"
|
|
43
44
|
import { useTokenList } from "./useTokenList.js"
|
|
44
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
useSelectedFeeOption,
|
|
47
|
+
type ProcessedFeeOption,
|
|
48
|
+
} from "./useSelectedFeeOption.js"
|
|
45
49
|
|
|
46
50
|
export interface Token {
|
|
47
51
|
id: number
|
|
@@ -117,17 +121,6 @@ export type UseSendProps = {
|
|
|
117
121
|
refetchTrigger?: number
|
|
118
122
|
}
|
|
119
123
|
|
|
120
|
-
export type FeeOption = {
|
|
121
|
-
tokenAddress: string
|
|
122
|
-
tokenSymbol: string
|
|
123
|
-
tokenDecimals: number
|
|
124
|
-
amount: string
|
|
125
|
-
amountUSD: number
|
|
126
|
-
notEnoughBalance?: boolean
|
|
127
|
-
tokenImageUrl?: string
|
|
128
|
-
chainId?: number
|
|
129
|
-
}
|
|
130
|
-
|
|
131
124
|
export type UseSendReturn = {
|
|
132
125
|
amount: string
|
|
133
126
|
amountRaw: string
|
|
@@ -152,8 +145,8 @@ export type UseSendReturn = {
|
|
|
152
145
|
setRecipientInput: (recipientInput: string) => void
|
|
153
146
|
setSelectedDestinationChain: (chain: ChainInfo) => void
|
|
154
147
|
setSelectedDestToken: (token: TokenInfo) => void
|
|
155
|
-
|
|
156
|
-
|
|
148
|
+
setSelectedFeeOption: (token: FeeOption | null) => void
|
|
149
|
+
processedFeeOptions: ProcessedFeeOption[]
|
|
157
150
|
supportedTokens: SupportedToken[]
|
|
158
151
|
supportedChains: ChainInfo[]
|
|
159
152
|
ensAddress: string | null
|
|
@@ -163,7 +156,7 @@ export type UseSendReturn = {
|
|
|
163
156
|
destTokenPrices: TokenPrice[] | null
|
|
164
157
|
sourceTokenPrices: TokenPrice[] | null
|
|
165
158
|
selectedToken?: Token
|
|
166
|
-
|
|
159
|
+
selectedFeeOption: FeeOption | null
|
|
167
160
|
setIsChainDropdownOpen: (isOpen: boolean) => void
|
|
168
161
|
setIsTokenDropdownOpen: (isOpen: boolean) => void
|
|
169
162
|
toAmountFormatted: string
|
|
@@ -433,6 +426,7 @@ export function useSendForm({
|
|
|
433
426
|
}, [selectedDestToken, defaultDestToken])
|
|
434
427
|
|
|
435
428
|
const trailsClient = useTrailsClient()
|
|
429
|
+
const { trailsApiKey, sequenceIndexerUrl } = useTrails()
|
|
436
430
|
|
|
437
431
|
// Get user's token balances for balance checking
|
|
438
432
|
const { filteredTokensFormatted } = useTokenList({
|
|
@@ -545,6 +539,10 @@ export function useSendForm({
|
|
|
545
539
|
const [isLoadingQuote, setIsLoadingQuote] = useState(false)
|
|
546
540
|
const [prepareSendResult, setPrepareSendResult] =
|
|
547
541
|
useState<PrepareSendReturn | null>(null)
|
|
542
|
+
const latestResolvedIntentIdRef = useRef<string | null>(null)
|
|
543
|
+
const quoteInputsFingerprintRef = useRef<string | null>(null)
|
|
544
|
+
const preparedQuoteFingerprintRef = useRef<string | null>(null)
|
|
545
|
+
|
|
548
546
|
// Create a stable callback for transaction state changes
|
|
549
547
|
const handleTransactionStateChange = useCallback(
|
|
550
548
|
(transactionStates: TransactionState[]) => {
|
|
@@ -583,11 +581,11 @@ export function useSendForm({
|
|
|
583
581
|
|
|
584
582
|
// Use the fee token selection hook
|
|
585
583
|
const {
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
processedFeeOptions
|
|
589
|
-
|
|
590
|
-
} =
|
|
584
|
+
selectedFeeOption,
|
|
585
|
+
setSelectedFeeOption,
|
|
586
|
+
processedFeeOptions,
|
|
587
|
+
setFeeOptions,
|
|
588
|
+
} = useSelectedFeeOption()
|
|
591
589
|
|
|
592
590
|
const [isRecipientContract, setIsRecipientContract] = useState(false)
|
|
593
591
|
const [isSenderContractOnOrigin, setIsSenderContractOnOrigin] =
|
|
@@ -684,6 +682,34 @@ export function useSendForm({
|
|
|
684
682
|
tradeType,
|
|
685
683
|
])
|
|
686
684
|
|
|
685
|
+
const buildQuoteInputsFingerprint = useCallback(
|
|
686
|
+
() =>
|
|
687
|
+
JSON.stringify({
|
|
688
|
+
originTokenAddress: selectedToken?.contractAddress?.toLowerCase() ?? "",
|
|
689
|
+
originChainId: selectedToken?.chainId ?? "",
|
|
690
|
+
destinationTokenSymbol: selectedDestToken?.symbol ?? "",
|
|
691
|
+
destinationChainId: selectedDestinationChain?.id ?? "",
|
|
692
|
+
destinationTokenAddress: destinationTokenAddress?.toLowerCase() ?? "",
|
|
693
|
+
amount: amount || "",
|
|
694
|
+
amountRaw: amountRaw || "",
|
|
695
|
+
recipient: recipient?.toLowerCase() ?? "",
|
|
696
|
+
tradeType,
|
|
697
|
+
toCalldata: toCalldata ?? "",
|
|
698
|
+
}),
|
|
699
|
+
[
|
|
700
|
+
amount,
|
|
701
|
+
amountRaw,
|
|
702
|
+
destinationTokenAddress,
|
|
703
|
+
recipient,
|
|
704
|
+
selectedDestinationChain?.id,
|
|
705
|
+
selectedDestToken?.symbol,
|
|
706
|
+
selectedToken?.chainId,
|
|
707
|
+
selectedToken?.contractAddress,
|
|
708
|
+
toCalldata,
|
|
709
|
+
tradeType,
|
|
710
|
+
],
|
|
711
|
+
)
|
|
712
|
+
|
|
687
713
|
// Get quote automatically when inputs change
|
|
688
714
|
const getQuote = useCallback(async () => {
|
|
689
715
|
// Only get quote if all required inputs are present
|
|
@@ -713,9 +739,16 @@ export function useSendForm({
|
|
|
713
739
|
)
|
|
714
740
|
setQuoteError(null)
|
|
715
741
|
setPrepareSendResult(null)
|
|
742
|
+
preparedQuoteFingerprintRef.current = null
|
|
716
743
|
return
|
|
717
744
|
}
|
|
718
745
|
|
|
746
|
+
latestResolvedIntentIdRef.current = null
|
|
747
|
+
let requestFingerprint = quoteInputsFingerprintRef.current
|
|
748
|
+
if (!requestFingerprint) {
|
|
749
|
+
requestFingerprint = buildQuoteInputsFingerprint()
|
|
750
|
+
quoteInputsFingerprintRef.current = requestFingerprint
|
|
751
|
+
}
|
|
719
752
|
try {
|
|
720
753
|
setIsLoadingQuote(true)
|
|
721
754
|
setError(null)
|
|
@@ -733,6 +766,8 @@ export function useSendForm({
|
|
|
733
766
|
tradeType,
|
|
734
767
|
})
|
|
735
768
|
setPrepareSendResult(null)
|
|
769
|
+
preparedQuoteFingerprintRef.current = null
|
|
770
|
+
latestResolvedIntentIdRef.current = null
|
|
736
771
|
setIsLoadingQuote(false)
|
|
737
772
|
return
|
|
738
773
|
}
|
|
@@ -847,30 +882,66 @@ export function useSendForm({
|
|
|
847
882
|
mode,
|
|
848
883
|
fundMethod,
|
|
849
884
|
checkoutOnHandlers,
|
|
850
|
-
|
|
885
|
+
selectedFeeOption: selectedFeeOption ?? null,
|
|
851
886
|
walletId,
|
|
887
|
+
sequenceIndexerUrl,
|
|
888
|
+
sequenceProjectAccessKey: trailsApiKey,
|
|
852
889
|
}
|
|
853
890
|
|
|
854
891
|
logger.console.log(
|
|
855
|
-
"[trails-sdk] [FEE-SELECT] getQuote using
|
|
892
|
+
"[trails-sdk] [FEE-SELECT] getQuote using selectedFeeOption:",
|
|
856
893
|
{
|
|
857
|
-
|
|
894
|
+
selectedFeeOption,
|
|
858
895
|
},
|
|
859
896
|
)
|
|
860
897
|
|
|
861
898
|
const result = await prepareSend(options)
|
|
862
899
|
|
|
900
|
+
if (requestFingerprint !== quoteInputsFingerprintRef.current) {
|
|
901
|
+
logger.console.log(
|
|
902
|
+
"[trails-sdk] Ignoring stale quote result (fingerprint mismatch)",
|
|
903
|
+
{
|
|
904
|
+
requestFingerprint,
|
|
905
|
+
currentFingerprint: quoteInputsFingerprintRef.current,
|
|
906
|
+
},
|
|
907
|
+
)
|
|
908
|
+
return
|
|
909
|
+
}
|
|
910
|
+
|
|
863
911
|
logger.console.log("[trails-sdk] prepareSend quote:", result.quote)
|
|
864
912
|
|
|
913
|
+
// Track the intentId returned by the most recent quote so we never execute a stale CommitIntent
|
|
914
|
+
// even when the quote inputs (fingerprint) are identical between retries.
|
|
915
|
+
const quoteIntentId = result.quote.intentId ?? null
|
|
916
|
+
|
|
917
|
+
logger.console.log("[trails-sdk] Resolved quote intentId:", quoteIntentId)
|
|
918
|
+
|
|
919
|
+
latestResolvedIntentIdRef.current = quoteIntentId
|
|
865
920
|
setPrepareSendResult(result)
|
|
921
|
+
preparedQuoteFingerprintRef.current = requestFingerprint
|
|
866
922
|
setIsLoadingQuote(false)
|
|
867
923
|
} catch (error) {
|
|
924
|
+
if (requestFingerprint !== quoteInputsFingerprintRef.current) {
|
|
925
|
+
logger.console.log(
|
|
926
|
+
"[trails-sdk] Ignoring quote error (fingerprint mismatch)",
|
|
927
|
+
{
|
|
928
|
+
requestFingerprint,
|
|
929
|
+
currentFingerprint: quoteInputsFingerprintRef.current,
|
|
930
|
+
},
|
|
931
|
+
)
|
|
932
|
+
return
|
|
933
|
+
}
|
|
934
|
+
|
|
868
935
|
logger.console.error("[trails-sdk] Error getting quote:", error)
|
|
869
|
-
|
|
936
|
+
const errorMessage = getFullErrorMessage(error)
|
|
937
|
+
setQuoteError(errorMessage)
|
|
870
938
|
setPrepareSendResult(null)
|
|
939
|
+
preparedQuoteFingerprintRef.current = null
|
|
940
|
+
latestResolvedIntentIdRef.current = null
|
|
871
941
|
setIsLoadingQuote(false)
|
|
872
942
|
}
|
|
873
943
|
}, [
|
|
944
|
+
trailsApiKey,
|
|
874
945
|
tradeType,
|
|
875
946
|
isDryMode,
|
|
876
947
|
account,
|
|
@@ -879,6 +950,7 @@ export function useSendForm({
|
|
|
879
950
|
selectedDestToken?.decimals,
|
|
880
951
|
recipient,
|
|
881
952
|
destinationTokenAddress,
|
|
953
|
+
sequenceIndexerUrl,
|
|
882
954
|
selectedDestToken?.symbol,
|
|
883
955
|
selectedDestinationChain?.id,
|
|
884
956
|
selectedToken?.contractAddress,
|
|
@@ -900,8 +972,9 @@ export function useSendForm({
|
|
|
900
972
|
amountRaw,
|
|
901
973
|
checkoutOnHandlers,
|
|
902
974
|
mode,
|
|
903
|
-
|
|
975
|
+
selectedFeeOption,
|
|
904
976
|
walletId,
|
|
977
|
+
buildQuoteInputsFingerprint,
|
|
905
978
|
])
|
|
906
979
|
|
|
907
980
|
// Auto-fetch quotes when inputs change (debounced)
|
|
@@ -913,12 +986,29 @@ export function useSendForm({
|
|
|
913
986
|
!destinationTokenAddress ||
|
|
914
987
|
!isValidRecipient ||
|
|
915
988
|
!selectedDestToken?.symbol ||
|
|
916
|
-
!selectedDestinationChain?.id
|
|
989
|
+
!selectedDestinationChain?.id ||
|
|
990
|
+
!selectedToken
|
|
917
991
|
) {
|
|
918
992
|
setPrepareSendResult(null)
|
|
993
|
+
latestResolvedIntentIdRef.current = null
|
|
994
|
+
quoteInputsFingerprintRef.current = null
|
|
995
|
+
preparedQuoteFingerprintRef.current = null
|
|
996
|
+
setIsLoadingQuote(false)
|
|
919
997
|
return
|
|
920
998
|
}
|
|
921
999
|
|
|
1000
|
+
const nextQuoteInputsFingerprint = buildQuoteInputsFingerprint()
|
|
1001
|
+
|
|
1002
|
+
// Fingerprint all quote-driving inputs so we can invalidate debounced quotes immediately when
|
|
1003
|
+
// the user switches tokens; this fixes the stale quote so that it stays loading until the new quote is ready.
|
|
1004
|
+
if (quoteInputsFingerprintRef.current !== nextQuoteInputsFingerprint) {
|
|
1005
|
+
quoteInputsFingerprintRef.current = nextQuoteInputsFingerprint
|
|
1006
|
+
latestResolvedIntentIdRef.current = null
|
|
1007
|
+
setPrepareSendResult(null)
|
|
1008
|
+
preparedQuoteFingerprintRef.current = null
|
|
1009
|
+
setIsLoadingQuote(true)
|
|
1010
|
+
}
|
|
1011
|
+
|
|
922
1012
|
const timeoutId = setTimeout(() => {
|
|
923
1013
|
getQuote()
|
|
924
1014
|
}, 500) // Debounce by 500ms
|
|
@@ -932,12 +1022,15 @@ export function useSendForm({
|
|
|
932
1022
|
selectedDestinationChain?.id,
|
|
933
1023
|
toCalldata,
|
|
934
1024
|
refetchTrigger,
|
|
1025
|
+
amountRaw,
|
|
1026
|
+
tradeType,
|
|
935
1027
|
selectedToken?.contractAddress,
|
|
936
1028
|
selectedToken?.chainId,
|
|
937
1029
|
selectedToken?.balance,
|
|
938
1030
|
selectedToken?.tokenPriceUsd,
|
|
939
1031
|
recipient, // Add recipient to trigger quote re-fetch when it changes
|
|
940
|
-
//
|
|
1032
|
+
// selectedFeeOption is passed to send() at execution time, not needed here
|
|
1033
|
+
buildQuoteInputsFingerprint,
|
|
941
1034
|
])
|
|
942
1035
|
|
|
943
1036
|
// Calculate destination amount from quote if available
|
|
@@ -967,12 +1060,12 @@ export function useSendForm({
|
|
|
967
1060
|
},
|
|
968
1061
|
)
|
|
969
1062
|
|
|
970
|
-
|
|
1063
|
+
setFeeOptions(
|
|
971
1064
|
apiFeeOptions,
|
|
972
1065
|
selectedToken?.chainId,
|
|
973
1066
|
filteredTokensFormattedRef.current,
|
|
974
1067
|
)
|
|
975
|
-
}, [prepareSendResult, selectedToken?.chainId,
|
|
1068
|
+
}, [prepareSendResult, selectedToken?.chainId, setFeeOptions])
|
|
976
1069
|
|
|
977
1070
|
const processSend = useCallback(async () => {
|
|
978
1071
|
try {
|
|
@@ -981,6 +1074,41 @@ export function useSendForm({
|
|
|
981
1074
|
return
|
|
982
1075
|
}
|
|
983
1076
|
|
|
1077
|
+
const currentQuoteInputsFingerprint = buildQuoteInputsFingerprint()
|
|
1078
|
+
if (
|
|
1079
|
+
!preparedQuoteFingerprintRef.current ||
|
|
1080
|
+
preparedQuoteFingerprintRef.current !== currentQuoteInputsFingerprint
|
|
1081
|
+
) {
|
|
1082
|
+
logger.console.warn(
|
|
1083
|
+
"[trails-sdk] Blocking send because quote fingerprint is stale",
|
|
1084
|
+
{
|
|
1085
|
+
prepared: preparedQuoteFingerprintRef.current,
|
|
1086
|
+
current: currentQuoteInputsFingerprint,
|
|
1087
|
+
},
|
|
1088
|
+
)
|
|
1089
|
+
setPrepareSendResult(null)
|
|
1090
|
+
preparedQuoteFingerprintRef.current = null
|
|
1091
|
+
latestResolvedIntentIdRef.current = null
|
|
1092
|
+
setIsLoadingQuote(true)
|
|
1093
|
+
return
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
const quoteIntentId = prepareSendResult.quote.intentId ?? null
|
|
1097
|
+
if (
|
|
1098
|
+
quoteIntentId &&
|
|
1099
|
+
latestResolvedIntentIdRef.current !== quoteIntentId
|
|
1100
|
+
) {
|
|
1101
|
+
logger.console.error(
|
|
1102
|
+
"[trails-sdk] Quote intentId has changed, waiting for latest quote",
|
|
1103
|
+
{
|
|
1104
|
+
current: latestResolvedIntentIdRef.current,
|
|
1105
|
+
prepareSend: quoteIntentId,
|
|
1106
|
+
},
|
|
1107
|
+
)
|
|
1108
|
+
setError("Quote is updating. Please wait for the latest quote.")
|
|
1109
|
+
return
|
|
1110
|
+
}
|
|
1111
|
+
|
|
984
1112
|
setError(null)
|
|
985
1113
|
setIsSubmitting(true)
|
|
986
1114
|
|
|
@@ -1059,28 +1187,28 @@ export function useSendForm({
|
|
|
1059
1187
|
"[trails-sdk] [FEE-SELECT] [GASLESS-FLOW] handleSend called, about to call send()",
|
|
1060
1188
|
)
|
|
1061
1189
|
logger.console.log(
|
|
1062
|
-
"[trails-sdk] [FEE-SELECT] [GASLESS-FLOW]
|
|
1190
|
+
"[trails-sdk] [FEE-SELECT] [GASLESS-FLOW] selectedFeeOption value at send() call time:",
|
|
1063
1191
|
{
|
|
1064
|
-
|
|
1065
|
-
isNull:
|
|
1066
|
-
isUndefined:
|
|
1067
|
-
type: typeof
|
|
1068
|
-
stringified:
|
|
1192
|
+
selectedFeeOption,
|
|
1193
|
+
isNull: selectedFeeOption === null,
|
|
1194
|
+
isUndefined: selectedFeeOption === undefined,
|
|
1195
|
+
type: typeof selectedFeeOption,
|
|
1196
|
+
stringified: JsonEncode(selectedFeeOption),
|
|
1069
1197
|
},
|
|
1070
1198
|
)
|
|
1071
1199
|
// Wait for full send to complete
|
|
1072
1200
|
const {
|
|
1073
1201
|
depositUserTxnReceipt,
|
|
1074
|
-
|
|
1075
|
-
|
|
1202
|
+
originIntentTransaction,
|
|
1203
|
+
destinationIntentTransaction,
|
|
1076
1204
|
} = await send({
|
|
1077
1205
|
onOriginSend,
|
|
1078
|
-
|
|
1206
|
+
selectedFeeOption: selectedFeeOption ?? null, // Pass current value at execution time
|
|
1079
1207
|
})
|
|
1080
1208
|
logger.console.log("[trails-sdk] send() completed, receipts:", {
|
|
1081
1209
|
depositUserTxnReceipt,
|
|
1082
|
-
|
|
1083
|
-
|
|
1210
|
+
originIntentTransaction,
|
|
1211
|
+
destinationIntentTransaction,
|
|
1084
1212
|
})
|
|
1085
1213
|
|
|
1086
1214
|
// Move to receipt screen
|
|
@@ -1136,7 +1264,8 @@ export function useSendForm({
|
|
|
1136
1264
|
onError,
|
|
1137
1265
|
fundMethod,
|
|
1138
1266
|
onNavigateToMeshConnect,
|
|
1139
|
-
|
|
1267
|
+
selectedFeeOption, // Include so handleSend captures latest value
|
|
1268
|
+
buildQuoteInputsFingerprint,
|
|
1140
1269
|
])
|
|
1141
1270
|
|
|
1142
1271
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
@@ -1325,8 +1454,8 @@ export function useSendForm({
|
|
|
1325
1454
|
setRecipientInput,
|
|
1326
1455
|
setSelectedDestinationChain,
|
|
1327
1456
|
setSelectedDestToken,
|
|
1328
|
-
|
|
1329
|
-
|
|
1457
|
+
setSelectedFeeOption,
|
|
1458
|
+
processedFeeOptions,
|
|
1330
1459
|
supportedTokens,
|
|
1331
1460
|
supportedChains,
|
|
1332
1461
|
ensAddress: ensAddress ?? null,
|
|
@@ -1336,7 +1465,7 @@ export function useSendForm({
|
|
|
1336
1465
|
destTokenPrices: destTokenPrices ?? null,
|
|
1337
1466
|
sourceTokenPrices: sourceTokenPrices ?? null,
|
|
1338
1467
|
selectedToken,
|
|
1339
|
-
|
|
1468
|
+
selectedFeeOption: selectedFeeOption ?? null,
|
|
1340
1469
|
setIsChainDropdownOpen,
|
|
1341
1470
|
setIsTokenDropdownOpen,
|
|
1342
1471
|
toAmountFormatted: quotedDestinationAmount,
|
|
@@ -15,7 +15,11 @@ import {
|
|
|
15
15
|
useHasSufficientBalanceUsd,
|
|
16
16
|
useTokenBalances,
|
|
17
17
|
} from "../../tokenBalances.js"
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
getFormatttedTokenName,
|
|
20
|
+
useSupportedTokens,
|
|
21
|
+
useGetTokenImageUrl,
|
|
22
|
+
} from "../../tokens.js"
|
|
19
23
|
import { useIndexerGatewayClient } from "../../indexerClient.js"
|
|
20
24
|
import { useTrailsClient } from "../../trailsClient.js"
|
|
21
25
|
import { useTokenPrices } from "../../prices.js"
|
|
@@ -137,6 +141,7 @@ export function useTokenList({
|
|
|
137
141
|
const { address } = useAccount()
|
|
138
142
|
const indexerGatewayClient = useIndexerGatewayClient()
|
|
139
143
|
const trailsClient = useTrailsClient()
|
|
144
|
+
const { getTokenImageUrl } = useGetTokenImageUrl()
|
|
140
145
|
const {
|
|
141
146
|
sortedTokens: allSortedTokens,
|
|
142
147
|
isLoadingSortedTokens,
|
|
@@ -536,7 +541,14 @@ export function useTokenList({
|
|
|
536
541
|
if (tokenSymbol === "WETH") {
|
|
537
542
|
imageContractAddress = zeroAddress
|
|
538
543
|
}
|
|
539
|
-
const
|
|
544
|
+
const fallbackImageUrl =
|
|
545
|
+
(token as TokenBalanceWithPrice).contractInfo?.logoURI || ""
|
|
546
|
+
const imageUrl = getTokenImageUrl({
|
|
547
|
+
chainId: token.chainId,
|
|
548
|
+
contractAddress: imageContractAddress,
|
|
549
|
+
symbol: tokenSymbol,
|
|
550
|
+
fallbackImageUrl: fallbackImageUrl || undefined,
|
|
551
|
+
})
|
|
540
552
|
const currentTokenName =
|
|
541
553
|
(token as TokenBalanceWithPrice).contractInfo?.name || ""
|
|
542
554
|
const tokenName = getFormatttedTokenName(
|
|
@@ -771,6 +783,7 @@ export function useTokenList({
|
|
|
771
783
|
supportedTokens,
|
|
772
784
|
supportedTokenPrices,
|
|
773
785
|
searchQuery,
|
|
786
|
+
getTokenImageUrl,
|
|
774
787
|
])
|
|
775
788
|
|
|
776
789
|
const showInsufficientBalance = useMemo(() => {
|
package/src/widget/index.tsx
CHANGED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { SequenceHooksProvider } from "@0xsequence/hooks"
|
|
2
|
+
import { createContext, useContext, useMemo, useEffect } from "react"
|
|
3
|
+
import type { ComponentProps } from "react"
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_SLIPPAGE_TOLERANCE,
|
|
6
|
+
DEFAULT_WALLETCONNECT_PROJECT_ID,
|
|
7
|
+
PROD_SEQUENCE_INDEXER_URL,
|
|
8
|
+
PROD_SEQUENCE_NODE_GATEWAY_URL,
|
|
9
|
+
PROD_SEQUENCE_METADATA_URL,
|
|
10
|
+
PROD_TRAILS_API_URL,
|
|
11
|
+
} from "../../constants.js"
|
|
12
|
+
import {
|
|
13
|
+
declareCommitHash,
|
|
14
|
+
setGlobalDebug,
|
|
15
|
+
updateGlobalConfig,
|
|
16
|
+
} from "../../config.js"
|
|
17
|
+
import { logger } from "../../logger.js"
|
|
18
|
+
import { getQueryParam } from "../../queryParams.js"
|
|
19
|
+
|
|
20
|
+
export type SequenceEnv = "prod" | "dev" | "local" | "cors-anywhere"
|
|
21
|
+
|
|
22
|
+
export interface TrailsConfig {
|
|
23
|
+
trailsApiKey: string
|
|
24
|
+
trailsApiUrl: string
|
|
25
|
+
sequenceIndexerUrl: string
|
|
26
|
+
sequenceNodeGatewayUrl: string
|
|
27
|
+
sequenceMetadataUrl: string
|
|
28
|
+
walletConnectProjectId: string
|
|
29
|
+
slippageTolerance: string | number
|
|
30
|
+
debug: boolean
|
|
31
|
+
commitHash: string | undefined
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface TrailsProviderProps {
|
|
35
|
+
children: React.ReactNode
|
|
36
|
+
config: {
|
|
37
|
+
trailsApiKey: string
|
|
38
|
+
trailsApiUrl?: string
|
|
39
|
+
sequenceIndexerUrl?: string
|
|
40
|
+
sequenceNodeGatewayUrl?: string
|
|
41
|
+
sequenceMetadataUrl?: string
|
|
42
|
+
walletConnectProjectId?: string
|
|
43
|
+
slippageTolerance?: string | number
|
|
44
|
+
debug?: boolean
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const TrailsContext = createContext<TrailsConfig | null>(null)
|
|
49
|
+
|
|
50
|
+
export const TrailsProvider = ({ children, config }: TrailsProviderProps) => {
|
|
51
|
+
// Populate the trails config with default values if not provided
|
|
52
|
+
const trailsConfig: TrailsConfig = useMemo(() => {
|
|
53
|
+
return {
|
|
54
|
+
trailsApiKey: config.trailsApiKey,
|
|
55
|
+
trailsApiUrl: config.trailsApiUrl || PROD_TRAILS_API_URL,
|
|
56
|
+
sequenceIndexerUrl:
|
|
57
|
+
config.sequenceIndexerUrl || PROD_SEQUENCE_INDEXER_URL,
|
|
58
|
+
sequenceNodeGatewayUrl:
|
|
59
|
+
config.sequenceNodeGatewayUrl || PROD_SEQUENCE_NODE_GATEWAY_URL,
|
|
60
|
+
sequenceMetadataUrl:
|
|
61
|
+
config.sequenceMetadataUrl || PROD_SEQUENCE_METADATA_URL,
|
|
62
|
+
walletConnectProjectId:
|
|
63
|
+
config.walletConnectProjectId || DEFAULT_WALLETCONNECT_PROJECT_ID,
|
|
64
|
+
slippageTolerance: config.slippageTolerance ?? DEFAULT_SLIPPAGE_TOLERANCE,
|
|
65
|
+
debug: (config.debug ?? false) || getQueryParam("debug") === "true",
|
|
66
|
+
commitHash: declareCommitHash(),
|
|
67
|
+
} satisfies TrailsConfig
|
|
68
|
+
}, [
|
|
69
|
+
config.trailsApiKey,
|
|
70
|
+
config.trailsApiUrl,
|
|
71
|
+
config.sequenceIndexerUrl,
|
|
72
|
+
config.sequenceMetadataUrl,
|
|
73
|
+
config.sequenceNodeGatewayUrl,
|
|
74
|
+
config.walletConnectProjectId,
|
|
75
|
+
config.slippageTolerance,
|
|
76
|
+
config.debug,
|
|
77
|
+
])
|
|
78
|
+
|
|
79
|
+
// Set global debug mode for backward compatibility with getDebug()
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
setGlobalDebug(trailsConfig.debug ?? false)
|
|
82
|
+
}, [trailsConfig.debug])
|
|
83
|
+
|
|
84
|
+
// Update global config when trails config changes (temporary solution)
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
updateGlobalConfig({
|
|
87
|
+
trailsApiKey: trailsConfig.trailsApiKey,
|
|
88
|
+
sequenceNodeGatewayUrl: trailsConfig.sequenceNodeGatewayUrl,
|
|
89
|
+
})
|
|
90
|
+
}, [trailsConfig.trailsApiKey, trailsConfig.sequenceNodeGatewayUrl])
|
|
91
|
+
|
|
92
|
+
// Create a sequence hooks config based on the trails config
|
|
93
|
+
const sequenceHooksConfig = useMemo(() => {
|
|
94
|
+
return {
|
|
95
|
+
projectAccessKey: trailsConfig.trailsApiKey || "",
|
|
96
|
+
env: {
|
|
97
|
+
apiUrl: trailsConfig.trailsApiUrl,
|
|
98
|
+
indexerUrl: trailsConfig.sequenceIndexerUrl,
|
|
99
|
+
indexerGatewayUrl: trailsConfig.sequenceIndexerUrl,
|
|
100
|
+
},
|
|
101
|
+
} satisfies ComponentProps<typeof SequenceHooksProvider>["config"]
|
|
102
|
+
}, [trailsConfig])
|
|
103
|
+
|
|
104
|
+
logger.console.log("sequenceHooksConfig", sequenceHooksConfig)
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<TrailsContext.Provider value={trailsConfig}>
|
|
108
|
+
<SequenceHooksProvider config={sequenceHooksConfig}>
|
|
109
|
+
{children}
|
|
110
|
+
</SequenceHooksProvider>
|
|
111
|
+
</TrailsContext.Provider>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export const useTrails = (): Readonly<TrailsConfig> => {
|
|
116
|
+
const context = useContext(TrailsContext)
|
|
117
|
+
|
|
118
|
+
if (!context) {
|
|
119
|
+
throw new Error("useTrails must be used within a TrailsProvider")
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return context
|
|
123
|
+
}
|