fix
This commit is contained in:
@@ -1,9 +1,16 @@
|
|||||||
import { COIN_ICONS } from '@shared/assets/coins'
|
import { COIN_ICONS } from '@shared/assets/coins'
|
||||||
|
|
||||||
|
/** Wrapper-токены → их нативные аналоги (WETH→ETH, WBTC→BTC). */
|
||||||
|
const NATIVE_SYMBOL: Record<string, string> = { WETH: 'ETH', WBTC: 'BTC' }
|
||||||
|
|
||||||
|
/** Отображаемый символ: wrapper-токены показываем как нативные (WETH→ETH, WBTC→BTC). */
|
||||||
|
export function displaySymbol(symbol: string): string {
|
||||||
|
return NATIVE_SYMBOL[symbol] ?? symbol
|
||||||
|
}
|
||||||
|
|
||||||
/** Иконка по символу токена: WETH→ETH, WBTC→BTC, иначе по тикеру (может вернуть undefined). */
|
/** Иконка по символу токена: WETH→ETH, WBTC→BTC, иначе по тикеру (может вернуть undefined). */
|
||||||
export function coinIcon(symbol: string): string | undefined {
|
export function coinIcon(symbol: string): string | undefined {
|
||||||
const map: Record<string, string> = { WETH: 'ETH', WBTC: 'BTC' }
|
return COIN_ICONS[displaySymbol(symbol)]
|
||||||
return COIN_ICONS[map[symbol] ?? symbol]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** feeTier (сотые доли процента) → человекочитаемые проценты: 3000 → «0.3%». */
|
/** feeTier (сотые доли процента) → человекочитаемые проценты: 3000 → «0.3%». */
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { PrimaryButton } from '@shared/ui'
|
|||||||
import { truncateDecimals } from '@shared/lib/utils/truncateDecimals'
|
import { truncateDecimals } from '@shared/lib/utils/truncateDecimals'
|
||||||
import type { Pool, LpQuote } from '@features/pools'
|
import type { Pool, LpQuote } from '@features/pools'
|
||||||
import { useWalletBalance, type WalletBalanceData } from '@features/wallet'
|
import { useWalletBalance, type WalletBalanceData } from '@features/wallet'
|
||||||
import { formatFeeTier } from '../model/meta'
|
import { formatFeeTier, displaySymbol } from '../model/meta'
|
||||||
import styles from './LpDepositCard.module.css'
|
import styles from './LpDepositCard.module.css'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -26,10 +26,11 @@ interface Props {
|
|||||||
const DASH = '—'
|
const DASH = '—'
|
||||||
const decimalRe = /^(\d+\.?\d*|\.?\d*)$/
|
const decimalRe = /^(\d+\.?\d*|\.?\d*)$/
|
||||||
|
|
||||||
// Баланс ноги по символу: нативный токен (chain === символ) берём из native, остальное — из tokens.
|
// Баланс ноги по символу. Wrapper-токен нативной монеты (WETH на ETH) показываем как баланс
|
||||||
|
// нативной монеты; остальные токены берём из tokens по исходному символу.
|
||||||
function legBalance(wb: WalletBalanceData | undefined, symbol: string): string {
|
function legBalance(wb: WalletBalanceData | undefined, symbol: string): string {
|
||||||
if (!wb) return '0'
|
if (!wb) return '0'
|
||||||
if (symbol === wb.chain) return wb.native.formatted
|
if (displaySymbol(symbol) === wb.chain) return wb.native.formatted
|
||||||
return wb.tokens[symbol]?.formatted ?? '0'
|
return wb.tokens[symbol]?.formatted ?? '0'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +142,7 @@ export function LpDepositCard({
|
|||||||
<div className={styles.card}>
|
<div className={styles.card}>
|
||||||
<div className={styles.top}>
|
<div className={styles.top}>
|
||||||
<span className={styles.pair}>
|
<span className={styles.pair}>
|
||||||
{pool.symbol0}/{pool.symbol1}
|
{displaySymbol(pool.symbol0)}/{displaySymbol(pool.symbol1)}
|
||||||
</span>
|
</span>
|
||||||
<span className={styles.fee}>{formatFeeTier(pool.feeTier)}</span>
|
<span className={styles.fee}>{formatFeeTier(pool.feeTier)}</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -149,20 +150,20 @@ export function LpDepositCard({
|
|||||||
<span className={styles.tag}>Суммы взноса</span>
|
<span className={styles.tag}>Суммы взноса</span>
|
||||||
<div className={styles.amounts}>
|
<div className={styles.amounts}>
|
||||||
<AmountInput
|
<AmountInput
|
||||||
symbol={pool.symbol0}
|
symbol={displaySymbol(pool.symbol0)}
|
||||||
value={amount0}
|
value={amount0}
|
||||||
onChange={onAmount0Change}
|
onChange={onAmount0Change}
|
||||||
balance={legBalance(walletBalance, pool.symbol0)}
|
balance={legBalance(walletBalance, pool.symbol0)}
|
||||||
/>
|
/>
|
||||||
<AmountInput
|
<AmountInput
|
||||||
symbol={pool.symbol1}
|
symbol={displaySymbol(pool.symbol1)}
|
||||||
value={amount1}
|
value={amount1}
|
||||||
onChange={onAmount1Change}
|
onChange={onAmount1Change}
|
||||||
balance={legBalance(walletBalance, pool.symbol1)}
|
balance={legBalance(walletBalance, pool.symbol1)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span className={styles.tag}>Диапазон цен ({pool.symbol1} за {pool.symbol0})</span>
|
<span className={styles.tag}>Диапазон цен ({displaySymbol(pool.symbol1)} за {displaySymbol(pool.symbol0)})</span>
|
||||||
<div className={styles.range}>
|
<div className={styles.range}>
|
||||||
<PriceInput label="Мин." value={priceLower} onChange={onPriceLowerChange} />
|
<PriceInput label="Мин." value={priceLower} onChange={onPriceLowerChange} />
|
||||||
<PriceInput label="Макс." value={priceUpper} onChange={onPriceUpperChange} />
|
<PriceInput label="Макс." value={priceUpper} onChange={onPriceUpperChange} />
|
||||||
@@ -184,11 +185,11 @@ export function LpDepositCard({
|
|||||||
|
|
||||||
<div className={styles.quote} data-loading={quoteFetching ? 'true' : undefined}>
|
<div className={styles.quote} data-loading={quoteFetching ? 'true' : undefined}>
|
||||||
<div className={styles.quoteRow}>
|
<div className={styles.quoteRow}>
|
||||||
<span className={styles.quoteLabel}>Взнос {pool.symbol0}</span>
|
<span className={styles.quoteLabel}>Взнос {displaySymbol(pool.symbol0)}</span>
|
||||||
<span className={styles.quoteValue}>{amount0Out}</span>
|
<span className={styles.quoteValue}>{amount0Out}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.quoteRow}>
|
<div className={styles.quoteRow}>
|
||||||
<span className={styles.quoteLabel}>Взнос {pool.symbol1}</span>
|
<span className={styles.quoteLabel}>Взнос {displaySymbol(pool.symbol1)}</span>
|
||||||
<span className={styles.quoteValue}>{amount1Out}</span>
|
<span className={styles.quoteValue}>{amount1Out}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.quoteRow}>
|
<div className={styles.quoteRow}>
|
||||||
@@ -203,7 +204,7 @@ export function LpDepositCard({
|
|||||||
|
|
||||||
{insufficient && (
|
{insufficient && (
|
||||||
<p className={styles.warning}>
|
<p className={styles.warning}>
|
||||||
Недостаточно средств{shortLeg ? `: не хватает ${shortLeg.symbol}` : ''}. Пополните баланс.
|
Недостаточно средств{shortLeg ? `: не хватает ${displaySymbol(shortLeg.symbol)}` : ''}. Пополните баланс.
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Spinner } from '@shared/ui'
|
import { Spinner } from '@shared/ui'
|
||||||
import { truncateDecimals } from '@shared/lib/utils/truncateDecimals'
|
import { truncateDecimals } from '@shared/lib/utils/truncateDecimals'
|
||||||
import type { LpPosition } from '@features/pools'
|
import type { LpPosition } from '@features/pools'
|
||||||
import { formatFeeTier } from '../model/meta'
|
import { formatFeeTier, displaySymbol } from '../model/meta'
|
||||||
import styles from './LpPositionsPanel.module.css'
|
import styles from './LpPositionsPanel.module.css'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -43,7 +43,7 @@ export function LpPositionsPanel({ positions, onRemove, removePending, isLoading
|
|||||||
<div key={p.tokenId} className={styles.pos}>
|
<div key={p.tokenId} className={styles.pos}>
|
||||||
<div className={styles.posTop}>
|
<div className={styles.posTop}>
|
||||||
<span className={styles.coin}>
|
<span className={styles.coin}>
|
||||||
{p.symbol0}/{p.symbol1}
|
{displaySymbol(p.symbol0)}/{displaySymbol(p.symbol1)}
|
||||||
<span className={styles.fee}>{formatFeeTier(p.feeTier)}</span>
|
<span className={styles.fee}>{formatFeeTier(p.feeTier)}</span>
|
||||||
</span>
|
</span>
|
||||||
<span className={`${styles.badge} ${p.inRange ? styles.badgeActive : styles.badgeWarn}`}>
|
<span className={`${styles.badge} ${p.inRange ? styles.badgeActive : styles.badgeWarn}`}>
|
||||||
@@ -59,17 +59,17 @@ export function LpPositionsPanel({ positions, onRemove, removePending, isLoading
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.row}>
|
<div className={styles.row}>
|
||||||
<span className={styles.label}>{p.symbol0}</span>
|
<span className={styles.label}>{displaySymbol(p.symbol0)}</span>
|
||||||
<span className={styles.value}>{truncateDecimals(p.currentAmount0Human, 8)}</span>
|
<span className={styles.value}>{truncateDecimals(p.currentAmount0Human, 8)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.row}>
|
<div className={styles.row}>
|
||||||
<span className={styles.label}>{p.symbol1}</span>
|
<span className={styles.label}>{displaySymbol(p.symbol1)}</span>
|
||||||
<span className={styles.value}>{truncateDecimals(p.currentAmount1Human, 8)}</span>
|
<span className={styles.value}>{truncateDecimals(p.currentAmount1Human, 8)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.row}>
|
<div className={styles.row}>
|
||||||
<span className={styles.label}>Комиссии к выводу</span>
|
<span className={styles.label}>Комиссии к выводу</span>
|
||||||
<span className={`${styles.value} ${styles.success}`}>
|
<span className={`${styles.value} ${styles.success}`}>
|
||||||
{truncateDecimals(p.feesOwed0Human, 8)} {p.symbol0} · {truncateDecimals(p.feesOwed1Human, 8)} {p.symbol1}
|
{truncateDecimals(p.feesOwed0Human, 8)} {displaySymbol(p.symbol0)} · {truncateDecimals(p.feesOwed1Human, 8)} {displaySymbol(p.symbol1)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import type { LpPosition } from '@features/pools'
|
import type { LpPosition } from '@features/pools'
|
||||||
import { formatFeeTier } from '../model/meta'
|
import { formatFeeTier, displaySymbol } from '../model/meta'
|
||||||
import styles from './LpRemoveModal.module.css'
|
import styles from './LpRemoveModal.module.css'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -36,7 +36,7 @@ export function LpRemoveModal({ position, pending, onConfirm, onClose }: Props)
|
|||||||
<div className={styles.token}>
|
<div className={styles.token}>
|
||||||
<span className={styles.tokenLabel}>Позиция</span>
|
<span className={styles.tokenLabel}>Позиция</span>
|
||||||
<span className={styles.tokenAmount}>
|
<span className={styles.tokenAmount}>
|
||||||
{position.symbol0}/{position.symbol1}
|
{displaySymbol(position.symbol0)}/{displaySymbol(position.symbol1)}
|
||||||
</span>
|
</span>
|
||||||
<span className={styles.tokenMeta}>
|
<span className={styles.tokenMeta}>
|
||||||
{formatFeeTier(position.feeTier)} · #{position.tokenId}
|
{formatFeeTier(position.feeTier)} · #{position.tokenId}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useMemo, useState } from 'react'
|
import { useMemo, useState } from 'react'
|
||||||
import { Spinner } from '@shared/ui'
|
import { Spinner } from '@shared/ui'
|
||||||
import type { Pool } from '@features/pools'
|
import type { Pool } from '@features/pools'
|
||||||
import { formatFeeTier } from '../model/meta'
|
import { formatFeeTier, displaySymbol } from '../model/meta'
|
||||||
import styles from './PoolsTable.module.css'
|
import styles from './PoolsTable.module.css'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -35,7 +35,7 @@ function formatApr(value: number | null): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function pairName(p: Pool): string {
|
function pairName(p: Pool): string {
|
||||||
return `${p.symbol0}/${p.symbol1}`
|
return `${displaySymbol(p.symbol0)}/${displaySymbol(p.symbol1)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Числовые поля могут быть null — null уходит вниз независимо от направления.
|
// Числовые поля могут быть null — null уходит вниз независимо от направления.
|
||||||
@@ -140,7 +140,7 @@ export function PoolsTable({ pools, selected, onSelect, loading, error }: Props)
|
|||||||
>
|
>
|
||||||
<td className={styles.tdLeft}>
|
<td className={styles.tdLeft}>
|
||||||
<span className={styles.pairName}>
|
<span className={styles.pairName}>
|
||||||
{p.symbol0}/{p.symbol1}
|
{displaySymbol(p.symbol0)}/{displaySymbol(p.symbol1)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
type LpDepositInput,
|
type LpDepositInput,
|
||||||
type LpPosition,
|
type LpPosition,
|
||||||
} from '@features/pools'
|
} from '@features/pools'
|
||||||
|
import { displaySymbol } from '../model/meta'
|
||||||
import { PoolsTable } from './PoolsTable'
|
import { PoolsTable } from './PoolsTable'
|
||||||
import { LpDepositCard } from './LpDepositCard'
|
import { LpDepositCard } from './LpDepositCard'
|
||||||
import { LpPositionsPanel } from './LpPositionsPanel'
|
import { LpPositionsPanel } from './LpPositionsPanel'
|
||||||
@@ -103,7 +104,7 @@ export function PoolsWidget() {
|
|||||||
setToast({ status: 'info', message: 'Внесение в пул может занять несколько минут…' })
|
setToast({ status: 'info', message: 'Внесение в пул может занять несколько минут…' })
|
||||||
addM.mutate(input, {
|
addM.mutate(input, {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
setToast({ status: 'success', message: `Депозит в пул ${pool.symbol0}/${pool.symbol1} выполнен` })
|
setToast({ status: 'success', message: `Депозит в пул ${displaySymbol(pool.symbol0)}/${displaySymbol(pool.symbol1)} выполнен` })
|
||||||
setAmount0('')
|
setAmount0('')
|
||||||
setAmount1('')
|
setAmount1('')
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user