14.05.2026 rip
This commit is contained in:
@@ -151,3 +151,39 @@ export async function getPortfolio(): Promise<PortfolioData> {
|
||||
const res = await walletGet<{ success: boolean; data: PortfolioData }>('/api/wallets/portfolio')
|
||||
return res.data
|
||||
}
|
||||
|
||||
export interface TokenInfo {
|
||||
chain: string
|
||||
symbol: string
|
||||
name: string
|
||||
contract: string | null
|
||||
}
|
||||
|
||||
export interface RelayQuotePayload {
|
||||
user: string
|
||||
recipient: string
|
||||
originChainId: number
|
||||
destinationChainId: number
|
||||
originCurrency: string
|
||||
destinationCurrency: string
|
||||
amount: string
|
||||
tradeType: 'EXACT_INPUT'
|
||||
}
|
||||
|
||||
export interface RelayQuoteResponse {
|
||||
details: {
|
||||
currencyOut: {
|
||||
amountFormatted: string
|
||||
amountUsd: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function getTokensList(): Promise<TokenInfo[]> {
|
||||
const res = await walletGet<{ success: boolean; data: TokenInfo[] }>('/api/tokens')
|
||||
return res.data
|
||||
}
|
||||
|
||||
export async function getRelayQuote(payload: RelayQuotePayload): Promise<RelayQuoteResponse> {
|
||||
return walletPost<RelayQuoteResponse>('/api/relay/quote', payload)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export { useAllWalletBalances, usePrices, useSendWallet, useWalletAddresses, useWalletBalance, usePortfolio } from './model/useWalletData'
|
||||
export type { Chain, FormattedAmount, WalletBalanceData, PriceEntry, SendWalletPayload, SendWalletResponse, WalletAddress, PortfolioData, PortfolioChain, PortfolioNative, PortfolioToken } from './api/walletApi'
|
||||
export { useAllWalletBalances, usePrices, useSendWallet, useWalletAddresses, useWalletBalance, usePortfolio, useTokensList, useRelayQuote } from './model/useWalletData'
|
||||
export type { Chain, FormattedAmount, WalletBalanceData, PriceEntry, SendWalletPayload, SendWalletResponse, WalletAddress, PortfolioData, PortfolioChain, PortfolioNative, PortfolioToken, TokenInfo, RelayQuotePayload, RelayQuoteResponse } from './api/walletApi'
|
||||
export { CHAINS } from './api/walletApi'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery, useQueries, useMutation } from '@tanstack/react-query'
|
||||
import { getWalletBalance, getPrices, sendWallet, getWalletAddresses, getPortfolio, CHAINS, type Chain, type SendWalletPayload } from '../api/walletApi'
|
||||
import { getWalletBalance, getPrices, sendWallet, getWalletAddresses, getPortfolio, getTokensList, getRelayQuote, CHAINS, type Chain, type SendWalletPayload, type RelayQuotePayload } from '../api/walletApi'
|
||||
|
||||
export function useWalletBalance(chain: Chain) {
|
||||
return useQuery({
|
||||
@@ -49,3 +49,23 @@ export function usePortfolio() {
|
||||
staleTime: 30_000,
|
||||
})
|
||||
}
|
||||
|
||||
export function useTokensList() {
|
||||
return useQuery({
|
||||
queryKey: ['wallet', 'tokens'],
|
||||
queryFn: getTokensList,
|
||||
staleTime: 10 * 60 * 1000,
|
||||
})
|
||||
}
|
||||
|
||||
export function useRelayQuote(payload: RelayQuotePayload | null) {
|
||||
return useQuery({
|
||||
queryKey: ['relay', 'quote',
|
||||
payload?.originChainId, payload?.originCurrency,
|
||||
payload?.destinationCurrency, payload?.amount,
|
||||
],
|
||||
queryFn: () => getRelayQuote(payload!),
|
||||
enabled: !!payload,
|
||||
staleTime: 10_000,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -14,16 +14,17 @@ export interface Token {
|
||||
network: string
|
||||
balance: number
|
||||
usdRate: number
|
||||
decimals: number
|
||||
}
|
||||
|
||||
const TOKENS: Record<string, Token> = {
|
||||
BTC: { symbol: 'BTC', letter: '₿', logo: btc, color: '#F7931A', network: 'BITCOIN', balance: 0, usdRate: 67412 },
|
||||
ETH: { symbol: 'ETH', letter: 'E', logo: eth, color: '#627EEA', network: 'ETHEREUM', balance: 0, usdRate: 3521 },
|
||||
SOL: { symbol: 'SOL', letter: 'S', logo: sol, color: '#9945FF', network: 'SOLANA', balance: 0.994, usdRate: 163.84 },
|
||||
TRX: { symbol: 'TRX', letter: 'T', logo: trx, color: '#FF060A', network: 'TRON', balance: 0, usdRate: 0.12 },
|
||||
ARB: { symbol: 'ARB', letter: 'A', logo: arb, color: '#4A6DFF', network: 'ARBITRUM', balance: 0, usdRate: 0.92 },
|
||||
USDC: { symbol: 'USDC', letter: '$', color: '#2775CA', network: 'SOLANA', balance: 0, usdRate: 1 },
|
||||
USDT: { symbol: 'USDT', letter: '$', color: '#26A17B', network: 'ETHEREUM', balance: 0, usdRate: 1 },
|
||||
BTC: { symbol: 'BTC', letter: '₿', logo: btc, color: '#F7931A', network: 'BITCOIN', balance: 0, usdRate: 67412, decimals: 8 },
|
||||
ETH: { symbol: 'ETH', letter: 'E', logo: eth, color: '#627EEA', network: 'ETHEREUM', balance: 0, usdRate: 3521, decimals: 18 },
|
||||
SOL: { symbol: 'SOL', letter: 'S', logo: sol, color: '#9945FF', network: 'SOLANA', balance: 0.994, usdRate: 163.84, decimals: 9 },
|
||||
TRX: { symbol: 'TRX', letter: 'T', logo: trx, color: '#FF060A', network: 'TRON', balance: 0, usdRate: 0.12, decimals: 6 },
|
||||
ARB: { symbol: 'ARB', letter: 'A', logo: arb, color: '#4A6DFF', network: 'ARBITRUM', balance: 0, usdRate: 0.92, decimals: 18 },
|
||||
USDC: { symbol: 'USDC', letter: '$', color: '#2775CA', network: 'SOLANA', balance: 0, usdRate: 1, decimals: 6 },
|
||||
USDT: { symbol: 'USDT', letter: '$', color: '#26A17B', network: 'ETHEREUM', balance: 0, usdRate: 1, decimals: 6 },
|
||||
}
|
||||
|
||||
export const TOKENS_LIST: Token[] = Object.values(TOKENS)
|
||||
@@ -80,6 +81,7 @@ export function buildTokensFromBalance(data: WalletBalanceData): Token[] {
|
||||
network: data.chain,
|
||||
balance: parseFloat(data.native.formatted),
|
||||
usdRate: data.native.usdPrice,
|
||||
decimals: data.native.decimals,
|
||||
})
|
||||
|
||||
for (const [sym, info] of Object.entries(data.tokens)) {
|
||||
@@ -92,6 +94,7 @@ export function buildTokensFromBalance(data: WalletBalanceData): Token[] {
|
||||
network: data.chain,
|
||||
balance: parseFloat(info.formatted),
|
||||
usdRate: info.usdPrice,
|
||||
decimals: info.decimals,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { PrimaryButton } from '@shared/ui'
|
||||
import { useWalletBalance, type Chain } from '@features/wallet'
|
||||
import { useWalletBalance, useWalletAddresses, useTokensList, useRelayQuote, type Chain } from '@features/wallet'
|
||||
import { useDebounce } from '@shared/lib/hooks/useDebounce'
|
||||
import { TOKENS_LIST, buildTokensFromBalance, useSwapForm } from '../model/useSwapForm'
|
||||
import { RateRow } from './RateRow'
|
||||
import { SwapCard } from './SwapCard'
|
||||
@@ -10,6 +11,15 @@ import styles from './SwapForm.module.css'
|
||||
|
||||
const RATE = 82.2578
|
||||
|
||||
const CHAIN_ID: Record<string, number> = { ETH: 1, BSC: 56, SOL: 792703809 }
|
||||
const NATIVE_ADDR: Record<string, string> = {
|
||||
SOL: '11111111111111111111111111111111',
|
||||
DEFAULT: '0x0000000000000000000000000000000000000000',
|
||||
}
|
||||
function nativeAddr(chain: string) {
|
||||
return NATIVE_ADDR[chain] ?? NATIVE_ADDR.DEFAULT
|
||||
}
|
||||
|
||||
export function SwapForm() {
|
||||
const {
|
||||
fromAmount, toAmount, fromUsd, toUsd,
|
||||
@@ -30,6 +40,34 @@ export function SwapForm() {
|
||||
setToToken(t => tokenOptions.find(o => o.symbol === t.symbol) ?? (tokenOptions[1] ?? tokenOptions[0]))
|
||||
}, [walletData, fromNetwork])
|
||||
|
||||
const debouncedAmount = useDebounce(fromAmount, 500)
|
||||
const { data: addresses } = useWalletAddresses()
|
||||
const { data: tokensList } = useTokensList()
|
||||
|
||||
const chainId = CHAIN_ID[fromNetwork]
|
||||
const walletAddress = addresses?.find(a => a.chain === fromNetwork)?.address
|
||||
const fromContract = tokensList?.find(t => t.chain === fromNetwork && t.symbol === fromToken.symbol)?.contract ?? nativeAddr(fromNetwork)
|
||||
const toContract = tokensList?.find(t => t.chain === fromNetwork && t.symbol === toToken.symbol)?.contract ?? nativeAddr(fromNetwork)
|
||||
|
||||
const parsedAmount = parseFloat(debouncedAmount)
|
||||
const quotePayload = chainId && walletAddress && parsedAmount > 0
|
||||
? {
|
||||
user: walletAddress,
|
||||
recipient: walletAddress,
|
||||
originChainId: chainId,
|
||||
destinationChainId: chainId,
|
||||
originCurrency: fromContract,
|
||||
destinationCurrency: toContract,
|
||||
amount: Math.round(parsedAmount * Math.pow(10, fromToken.decimals)).toString(),
|
||||
tradeType: 'EXACT_INPUT' as const,
|
||||
}
|
||||
: null
|
||||
|
||||
const { data: quoteData } = useRelayQuote(quotePayload)
|
||||
|
||||
const displayToAmount = quoteData?.details.currencyOut.amountFormatted ?? toAmount
|
||||
const displayToUsd = quoteData?.details.currencyOut.amountUsd ?? toUsd
|
||||
|
||||
return (
|
||||
<div className={styles.form}>
|
||||
<SwapCard
|
||||
@@ -51,8 +89,8 @@ export function SwapForm() {
|
||||
mode="to"
|
||||
token={toToken}
|
||||
tokenOptions={tokenOptions}
|
||||
amount={toAmount}
|
||||
usd={toUsd}
|
||||
amount={displayToAmount}
|
||||
usd={displayToUsd}
|
||||
slippage="−0.16%"
|
||||
onTokenChange={setToToken}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user