diff --git a/src/features/wallet/index.ts b/src/features/wallet/index.ts
index 04a174d..b2a287e 100644
--- a/src/features/wallet/index.ts
+++ b/src/features/wallet/index.ts
@@ -1,3 +1,3 @@
-export { useAllWalletBalances, usePrices, useSendWallet, useWalletAddresses, useWalletBalance, usePortfolio, useTokensList, useRelayQuote, useExecuteRelaySwap, useSignSwap, useTrxSwapQuote, useFetchTrxQuote, useExecuteTrxSwap, useJumperTokens, useFetchJumperQuote, useExecuteBridge, useCreateWallet, useRevealMnemonic } from './model/useWalletData'
+export { useAllWalletBalances, usePrices, useSendWallet, useWalletAddresses, useWalletBalance, usePortfolio, useTokensList, useRelayQuote, useExecuteRelaySwap, useSignSwap, useTrxSwapQuote, useFetchTrxQuote, useExecuteTrxSwap, useJumperTokens, useJumperQuote, useFetchJumperQuote, useExecuteBridge, useCreateWallet, useRevealMnemonic } from './model/useWalletData'
export type { Chain, FormattedAmount, WalletBalanceData, PriceEntry, SendWalletPayload, SendWalletResponse, WalletAddress, PortfolioData, PortfolioChain, PortfolioNative, PortfolioToken, TokenInfo, RelayQuotePayload, RelayQuoteResponse, RelaySwapResponse, RelaySwapStep, TrxSwapQuotePayload, TrxSwapQuoteData, JumperToken, JumperTokensMap, JumperQuote, JumperQuotePayload, JumperQuoteToken, JumperFeeCost, BridgeExecutePayload, BridgeExecuteResult } from './api/walletApi'
export { CHAINS } from './api/walletApi'
diff --git a/src/features/wallet/model/useWalletData.ts b/src/features/wallet/model/useWalletData.ts
index bd60693..ac0136f 100644
--- a/src/features/wallet/model/useWalletData.ts
+++ b/src/features/wallet/model/useWalletData.ts
@@ -66,6 +66,19 @@ export function useJumperTokens() {
})
}
+export function useJumperQuote(payload: JumperQuotePayload | null) {
+ return useQuery({
+ queryKey: ['wallet', 'jumper', 'quote',
+ payload?.fromChain, payload?.toChain,
+ payload?.fromToken, payload?.toToken,
+ payload?.fromAmount, payload?.fromAddress, payload?.toAddress,
+ ],
+ queryFn: () => getJumperQuote(payload!),
+ enabled: !!payload,
+ staleTime: 10_000,
+ })
+}
+
export function useFetchJumperQuote() {
return useMutation({ mutationFn: (payload: JumperQuotePayload) => getJumperQuote(payload) })
}
diff --git a/src/widgets/bridge-form/ui/BridgeForm.tsx b/src/widgets/bridge-form/ui/BridgeForm.tsx
index 48b0d74..86fd0ba 100644
--- a/src/widgets/bridge-form/ui/BridgeForm.tsx
+++ b/src/widgets/bridge-form/ui/BridgeForm.tsx
@@ -2,12 +2,14 @@ import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useQueryClient } from '@tanstack/react-query'
import {
- useJumperTokens, useWalletBalance, useWalletAddresses, useFetchJumperQuote, useExecuteBridge,
- type Chain, type JumperToken, type WalletBalanceData, type JumperQuote,
+ useJumperTokens, useWalletBalance, useWalletAddresses, useJumperQuote, useFetchJumperQuote, useExecuteBridge,
+ type Chain, type JumperToken, type WalletBalanceData, type JumperQuote, type JumperQuotePayload,
} from '@features/wallet'
import { Notification, PrimaryButton } from '@shared/ui'
import { ROUTES } from '@shared/config/routes'
-import { toBaseUnits } from '@shared/lib/utils/baseUnits'
+import { useDebounce } from '@shared/lib/hooks/useDebounce'
+import { toBaseUnits, fromBaseUnits } from '@shared/lib/utils/baseUnits'
+import { truncateDecimals } from '@shared/lib/utils/truncateDecimals'
import {
TOKEN_META, buildTokensFromBalance, useSwapForm,
type Token,
@@ -93,32 +95,41 @@ export function BridgeForm() {
setToToken(t => toTokenOptions.find(o => o.symbol === t.symbol) ?? toTokenOptions[0])
}, [jumperData, toWalletData, toNetwork])
+ const debouncedAmount = useDebounce(fromAmount, 500)
+ const parsedAmount = parseFloat(debouncedAmount)
+
const fromJumper = jumperData?.[CHAIN_ID_BY_NET[fromNetwork]]?.find(t => t.symbol === fromToken.symbol)
const toJumper = jumperData?.[CHAIN_ID_BY_NET[toNetwork]]?.find(t => t.symbol === toToken.symbol)
const fromAddress = addresses?.find(a => a.chain === fromNetwork)?.address
const toAddress = addresses?.find(a => a.chain === toNetwork)?.address
- const parsedAmount = parseFloat(fromAmount)
- const canQuote = !!fromJumper && !!toJumper && !!fromAddress && !!toAddress && parsedAmount > 0
- function handleConfirm() {
- if (!fromJumper || !toJumper || !fromAddress || !toAddress) return
- setErrorMessage(null)
- fetchQuote(
- {
+ const quotePayload: JumperQuotePayload | null =
+ fromJumper && toJumper && fromAddress && toAddress && parsedAmount > 0
+ ? {
fromChain: CHAIN_ID_BY_NET[fromNetwork],
toChain: CHAIN_ID_BY_NET[toNetwork],
fromToken: fromJumper.address,
toToken: toJumper.address,
- fromAmount: toBaseUnits(fromAmount, fromToken.decimals),
+ fromAmount: toBaseUnits(debouncedAmount, fromToken.decimals),
fromAddress,
toAddress,
slippage: 0.005,
- },
- {
- onSuccess: (q) => setQuote(q),
- onError: (err) => setErrorMessage(err instanceof Error ? err.message : 'Не удалось получить котировку'),
- },
- )
+ }
+ : null
+
+ const { data: quoteData, isFetching: isQuoting } = useJumperQuote(quotePayload)
+
+ const displayToAmount = quoteData
+ ? truncateDecimals(fromBaseUnits(quoteData.estimate.toAmount, quoteData.action.toToken.decimals), 8)
+ : '0'
+
+ function handleConfirm() {
+ if (!quotePayload) return
+ setErrorMessage(null)
+ fetchQuote(quotePayload, {
+ onSuccess: (q) => setQuote(q),
+ onError: (err) => setErrorMessage(err instanceof Error ? err.message : 'Не удалось получить котировку'),
+ })
}
function handleExecute() {
@@ -183,12 +194,12 @@ export function BridgeForm() {
mode="to"
token={toToken}
tokenOptions={toTokenOptions}
- amount="0"
+ amount={displayToAmount}
onTokenChange={setToToken}
hideNetworkSelect
/>
-
+
{quote && (