UX/UI finetuning (#672)
* feat: added Buy/Sell token ratio to the TradingView header * fix: changed the order in the trading view description * feat: added minute timeframe to the chart * fix: changed WBTC to WBTC/USD pyth price feed * fix: adjusted HLS health curve * fix: made HLS accounts unselectable * copy: changed the APY range and Strategy text * tidy: fix the tables layout to be more readable * fix: change the precision of the Trading chart header * feat: added summary collapsable * fix: removed Debt Column for active HLS positions * fix: added Memo to TVChart * fix: adjust Trade page layout * tidy: refactor table meta * fix: DisplayCurrency is able to take options now * tidy: remove unneeded typesafety * fix: adjusted according feedback * env: enabled autoRepay and updated version
This commit is contained in:
parent
f46591be17
commit
f24d96ad75
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mars-v2-frontend",
|
||||
"version": "2.1.0",
|
||||
"version": "2.1.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "yarn validate-env && next build",
|
||||
|
@ -39,7 +39,7 @@ export default function AccountDetailsController() {
|
||||
const address = useStore((s) => s.address)
|
||||
const isHLS = useStore((s) => s.isHLS)
|
||||
const { data: accounts, isLoading } = useAccounts('default', address)
|
||||
const { data: accountIds } = useAccountIds(address, false)
|
||||
const { data: accountIds } = useAccountIds(address, false, true)
|
||||
const accountId = useAccountId()
|
||||
|
||||
const account = useCurrentAccount()
|
||||
|
@ -31,7 +31,7 @@ export default function AccountMenuContent() {
|
||||
const navigate = useNavigate()
|
||||
const { pathname } = useLocation()
|
||||
const address = useStore((s) => s.address)
|
||||
const { data: accountIds } = useAccountIds(address)
|
||||
const { data: accountIds } = useAccountIds(address, true, true)
|
||||
const accountId = useAccountId()
|
||||
|
||||
const createAccount = useStore((s) => s.createAccount)
|
||||
|
@ -1,7 +1,11 @@
|
||||
import { FormattedNumber } from 'components/FormattedNumber'
|
||||
import Loading from 'components/Loading'
|
||||
|
||||
export const BORROW_RATE_META = { accessorKey: 'borrowRate', header: 'Borrow Rate APY' }
|
||||
export const BORROW_RATE_META = {
|
||||
accessorKey: 'borrowRate',
|
||||
header: 'Borrow Rate APY',
|
||||
meta: { className: 'w-40' },
|
||||
}
|
||||
|
||||
interface Props {
|
||||
borrowRate: number | null
|
||||
|
@ -11,6 +11,7 @@ export const LIQUIDITY_META = {
|
||||
accessorKey: 'liquidity',
|
||||
header: 'Liquidity Available',
|
||||
id: 'liquidity',
|
||||
meta: { className: 'w-40' },
|
||||
}
|
||||
|
||||
export const liquiditySortingFn = (
|
||||
|
@ -1,8 +1,11 @@
|
||||
import React from 'react'
|
||||
|
||||
import { ChevronDown, ChevronUp } from 'components/Icons'
|
||||
|
||||
export const MANAGE_META = { accessorKey: 'manage', enableSorting: false, header: 'Manage' }
|
||||
export const MANAGE_META = {
|
||||
accessorKey: 'manage',
|
||||
enableSorting: false,
|
||||
header: 'Manage',
|
||||
meta: { className: 'w-30' },
|
||||
}
|
||||
|
||||
interface Props {
|
||||
isExpanded: boolean
|
||||
|
@ -18,6 +18,7 @@ interface Props {
|
||||
isApproximation?: boolean
|
||||
parentheses?: boolean
|
||||
showZero?: boolean
|
||||
options?: FormatOptions
|
||||
}
|
||||
|
||||
export default function DisplayCurrency(props: Props) {
|
||||
@ -73,6 +74,7 @@ export default function DisplayCurrency(props: Props) {
|
||||
abbreviated: true,
|
||||
prefix,
|
||||
suffix,
|
||||
...props.options,
|
||||
}}
|
||||
animate
|
||||
/>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import AssetRate from 'components/Asset/AssetRate'
|
||||
import Loading from 'components/Loading'
|
||||
|
||||
export const APY_META = { accessorKey: 'apy.deposit', header: 'APY' }
|
||||
export const APY_META = { accessorKey: 'apy.deposit', header: 'APY', meta: { className: 'w-40' } }
|
||||
|
||||
interface Props {
|
||||
apy: number
|
||||
|
@ -9,6 +9,7 @@ export const DEPOSIT_CAP_META = {
|
||||
accessorKey: 'marketDepositCap',
|
||||
header: 'Deposit Cap',
|
||||
id: 'marketDepositCap',
|
||||
meta: { className: 'w-40' },
|
||||
}
|
||||
|
||||
export const marketDepositCapSortingFn = (
|
||||
|
@ -1,8 +1,13 @@
|
||||
import React from 'react'
|
||||
|
||||
import { ChevronDown, ChevronUp } from 'components/Icons'
|
||||
|
||||
export const MANAGE_META = { accessorKey: 'manage', enableSorting: false, header: 'Manage' }
|
||||
export const MANAGE_META = {
|
||||
accessorKey: 'manage',
|
||||
enableSorting: false,
|
||||
header: 'Manage',
|
||||
meta: {
|
||||
className: 'w-30',
|
||||
},
|
||||
}
|
||||
|
||||
interface Props {
|
||||
isExpanded: boolean
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Row } from '@tanstack/react-table'
|
||||
import React from 'react'
|
||||
|
||||
import { FormattedNumber } from 'components/FormattedNumber'
|
||||
import Loading from 'components/Loading'
|
||||
@ -35,13 +34,13 @@ export default function ApyRange(props: Props) {
|
||||
<TitleAndSubCell
|
||||
title={
|
||||
<>
|
||||
<FormattedNumber amount={minApy} options={{ suffix: ' - ' }} className='inline' />
|
||||
<FormattedNumber amount={minApy} options={{ suffix: '% to ' }} className='inline' />
|
||||
<FormattedNumber amount={maxApy} options={{ suffix: '%' }} className='inline' />
|
||||
</>
|
||||
}
|
||||
sub={
|
||||
<>
|
||||
<FormattedNumber amount={minApy / 365} options={{ suffix: '-' }} className='inline' />
|
||||
<FormattedNumber amount={minApy / 365} options={{ suffix: '% to ' }} className='inline' />
|
||||
<FormattedNumber
|
||||
amount={maxApy / 365}
|
||||
options={{ suffix: '% daily' }}
|
||||
|
@ -1,5 +1,3 @@
|
||||
import React from 'react'
|
||||
|
||||
import DoubleLogo from 'components/DoubleLogo'
|
||||
import Loading from 'components/Loading'
|
||||
import TitleAndSubCell from 'components/TitleAndSubCell'
|
||||
@ -22,7 +20,7 @@ export default function Name(props: Props) {
|
||||
<TitleAndSubCell
|
||||
className='ml-2 mr-2 text-left'
|
||||
title={`${depositAsset.symbol} - ${borrowAsset.symbol}`}
|
||||
sub='Via MARS'
|
||||
sub='Via Mars Protocol'
|
||||
/>
|
||||
) : (
|
||||
<Loading />
|
||||
|
@ -1,15 +1,11 @@
|
||||
import { ColumnDef } from '@tanstack/react-table'
|
||||
import React, { useMemo } from 'react'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import Account, { ACCOUNT_META } from 'components/HLS/Staking/Table/Columns/Account'
|
||||
import ActiveApy, {
|
||||
ACTIVE_APY_META,
|
||||
activeApySortingFn,
|
||||
} from 'components/HLS/Staking/Table/Columns/ActiveApy'
|
||||
import DebtValue, {
|
||||
DEBT_VAL_META,
|
||||
debtValueSorting,
|
||||
} from 'components/HLS/Staking/Table/Columns/DebtValue'
|
||||
import DepositCap, {
|
||||
CAP_META,
|
||||
depositCapSortingFn,
|
||||
@ -59,11 +55,6 @@ export default function useDepositedColumns(props: Props) {
|
||||
cell: ({ row }) => <NetValue account={row.original} />,
|
||||
sortingFn: netValueSorting,
|
||||
},
|
||||
{
|
||||
...DEBT_VAL_META,
|
||||
cell: ({ row }) => <DebtValue account={row.original} />,
|
||||
sortingFn: debtValueSorting,
|
||||
},
|
||||
{
|
||||
...CAP_META,
|
||||
cell: ({ row }) => <DepositCap account={row.original} />,
|
||||
|
@ -9,6 +9,7 @@ interface Props<T> {
|
||||
rowClickHandler?: () => void
|
||||
spacingClassName?: string
|
||||
isBalancesTable?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
function getBorderColor(row: AccountBalanceRow) {
|
||||
@ -17,7 +18,6 @@ function getBorderColor(row: AccountBalanceRow) {
|
||||
|
||||
export default function Row<T>(props: Props<T>) {
|
||||
const canExpand = !!props.renderExpanded
|
||||
|
||||
return (
|
||||
<>
|
||||
<tr
|
||||
@ -47,6 +47,7 @@ export default function Row<T>(props: Props<T>) {
|
||||
isSymbolOrName ? 'text-left' : 'text-right',
|
||||
props.spacingClassName ?? 'px-3 py-4',
|
||||
borderClasses,
|
||||
cell.column.columnDef.meta?.className,
|
||||
)}
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
|
@ -68,6 +68,7 @@ export default function Table<T>(props: Props<T>) {
|
||||
props.spacingClassName ?? 'px-4 py-3',
|
||||
header.column.getCanSort() && 'hover:cursor-pointer',
|
||||
header.id === 'symbol' || header.id === 'name' ? 'text-left' : 'text-right',
|
||||
header.column.columnDef.meta?.className,
|
||||
)}
|
||||
>
|
||||
<div
|
||||
|
@ -55,6 +55,8 @@ export class DataFeed implements IDatafeedChartApi {
|
||||
'1D': '1d',
|
||||
}
|
||||
millisecondsPerInterval: { [key: string]: number } = {
|
||||
'1': MILLISECONDS_PER_MINUTE * 1,
|
||||
'5': MILLISECONDS_PER_MINUTE * 5,
|
||||
'15': MILLISECONDS_PER_MINUTE * 15,
|
||||
'30': MILLISECONDS_PER_MINUTE * 30,
|
||||
'60': MILLISECONDS_PER_MINUTE * 60,
|
||||
@ -64,7 +66,7 @@ export class DataFeed implements IDatafeedChartApi {
|
||||
pairs: { baseAsset: string; quoteAsset: string }[] = []
|
||||
pairsWithData: string[] = []
|
||||
supportedPools: string[] = []
|
||||
supportedResolutions = ['15', '30', '60', '240', 'D'] as ResolutionString[]
|
||||
supportedResolutions = ['1', '5', '15', '30', '60', '240', 'D'] as ResolutionString[]
|
||||
|
||||
constructor(debug = false, baseDecimals: number, baseDenom: string) {
|
||||
if (debug) console.log('Start charting library datafeed')
|
||||
@ -78,12 +80,11 @@ export class DataFeed implements IDatafeedChartApi {
|
||||
.filter((poolId) => typeof poolId === 'string') as string[]
|
||||
}
|
||||
|
||||
getDescription(pairName: string) {
|
||||
const denom1 = pairName.split(PAIR_SEPARATOR)[0]
|
||||
const denom2 = pairName.split(PAIR_SEPARATOR)[1]
|
||||
getDescription(pairName: string, inverted: boolean) {
|
||||
const [denom1, denom2] = pairName.split(PAIR_SEPARATOR)
|
||||
const asset1 = ASSETS.find(byDenom(denom1))
|
||||
const asset2 = ASSETS.find(byDenom(denom2))
|
||||
return `${asset2?.symbol}/${asset1?.symbol}`
|
||||
return inverted ? `${asset2?.symbol}/${asset1?.symbol}` : `${asset1?.symbol}/${asset2?.symbol}`
|
||||
}
|
||||
|
||||
async getPairsWithData() {
|
||||
@ -111,9 +112,10 @@ export class DataFeed implements IDatafeedChartApi {
|
||||
.then((res) => res.json())
|
||||
.then((json) => {
|
||||
this.pairs = json.data.pairs
|
||||
|
||||
this.pairsWithData = json.data.pairs.map(
|
||||
(pair: { baseAsset: string; quoteAsset: string }) => {
|
||||
return `${pair.baseAsset}${PAIR_SEPARATOR}${pair.quoteAsset}`
|
||||
return `${pair.quoteAsset}${PAIR_SEPARATOR}${pair.baseAsset}`
|
||||
},
|
||||
)
|
||||
})
|
||||
@ -139,14 +141,14 @@ export class DataFeed implements IDatafeedChartApi {
|
||||
setTimeout(() => {
|
||||
const info: LibrarySymbolInfo = {
|
||||
...defaultSymbolInfo,
|
||||
name: this.getDescription(pairName),
|
||||
full_name: this.getDescription(pairName),
|
||||
description: this.getDescription(pairName),
|
||||
ticker: this.getDescription(pairName),
|
||||
name: this.getDescription(pairName, false),
|
||||
full_name: this.getDescription(pairName, true),
|
||||
description: this.getDescription(pairName, true),
|
||||
ticker: this.getDescription(pairName, false),
|
||||
exchange: this.getExchangeName(pairName),
|
||||
listed_exchange: this.getExchangeName(pairName),
|
||||
supported_resolutions: this.supportedResolutions,
|
||||
base_name: [this.getDescription(pairName)],
|
||||
base_name: [this.getDescription(pairName, false)],
|
||||
pricescale: this.getPriceScale(pairName),
|
||||
} as LibrarySymbolInfo
|
||||
onResolve(info)
|
||||
@ -470,7 +472,13 @@ export class DataFeed implements IDatafeedChartApi {
|
||||
}
|
||||
|
||||
getPythFeedIds(name: string) {
|
||||
if (name.includes(PAIR_SEPARATOR)) return []
|
||||
if (name.includes(PAIR_SEPARATOR)) {
|
||||
const [denom1, denom2] = name.split(PAIR_SEPARATOR)
|
||||
const denomFeedId1 = ASSETS.find((asset) => asset.denom === denom1)?.pythHistoryFeedId
|
||||
const denomFeedId2 = ASSETS.find((asset) => asset.denom === denom2)?.pythHistoryFeedId
|
||||
return [denomFeedId1, denomFeedId2]
|
||||
}
|
||||
|
||||
const [symbol1, symbol2] = name.split('/')
|
||||
const feedId1 = ASSETS.find((asset) => asset.symbol === symbol1)?.pythHistoryFeedId
|
||||
const feedId2 = ASSETS.find((asset) => asset.symbol === symbol2)?.pythHistoryFeedId
|
||||
|
@ -1,9 +1,17 @@
|
||||
import { useEffect, useMemo, useRef } from 'react'
|
||||
|
||||
import Card from 'components/Card'
|
||||
import { disabledFeatures, enabledFeatures, overrides } from 'components/Trade/TradeChart/constants'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import { FormattedNumber } from 'components/FormattedNumber'
|
||||
import Loading from 'components/Loading'
|
||||
import Text from 'components/Text'
|
||||
import { DataFeed, PAIR_SEPARATOR } from 'components/Trade/TradeChart/DataFeed'
|
||||
import { disabledFeatures, enabledFeatures, overrides } from 'components/Trade/TradeChart/constants'
|
||||
import { BN_ZERO } from 'constants/math'
|
||||
import usePrices from 'hooks/usePrices'
|
||||
import useStore from 'store'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { byDenom } from 'utils/array'
|
||||
import {
|
||||
ChartingLibraryWidgetOptions,
|
||||
IChartingLibraryWidget,
|
||||
@ -11,6 +19,7 @@ import {
|
||||
Timezone,
|
||||
widget,
|
||||
} from 'utils/charting_library'
|
||||
import { magnify } from 'utils/formatters'
|
||||
|
||||
interface Props {
|
||||
buyAsset: Asset
|
||||
@ -28,6 +37,14 @@ export const TVChartContainer = (props: Props) => {
|
||||
() => new DataFeed(false, baseCurrency.decimals, baseCurrency.denom),
|
||||
[baseCurrency],
|
||||
)
|
||||
const { data: prices, isLoading } = usePrices()
|
||||
const ratio = useMemo(() => {
|
||||
const priceBuyAsset = prices.find(byDenom(props.buyAsset.denom))?.amount
|
||||
const priceSellAsset = prices.find(byDenom(props.sellAsset.denom))?.amount
|
||||
|
||||
if (!priceBuyAsset || !priceSellAsset) return BN_ZERO
|
||||
return priceBuyAsset.dividedBy(priceSellAsset)
|
||||
}, [prices, props.buyAsset.denom, props.sellAsset.denom])
|
||||
|
||||
useEffect(() => {
|
||||
const widgetOptions: ChartingLibraryWidgetOptions = {
|
||||
@ -102,7 +119,45 @@ export const TVChartContainer = (props: Props) => {
|
||||
}, [props.buyAsset.denom, props.sellAsset.denom])
|
||||
|
||||
return (
|
||||
<Card title='Trading Chart' contentClassName='px-0.5 pb-0.5 h-full' className='h-full'>
|
||||
<Card
|
||||
title={
|
||||
<div className='flex items-center w-full bg-white/10'>
|
||||
<Text size='lg' className='flex items-center flex-1 p-4 font-semibold'>
|
||||
Trading Chart
|
||||
</Text>
|
||||
{ratio.isZero() || isLoading ? (
|
||||
<Loading className='h-4 mr-4 w-60' />
|
||||
) : (
|
||||
<div className='flex items-center gap-1 p-4'>
|
||||
<Text size='sm'>1 {props.buyAsset.symbol}</Text>
|
||||
<FormattedNumber
|
||||
className='text-sm'
|
||||
amount={Number(ratio.toPrecision(6))}
|
||||
options={{
|
||||
prefix: '= ',
|
||||
suffix: ` ${props.sellAsset.symbol}`,
|
||||
abbreviated: false,
|
||||
maxDecimals: props.sellAsset.decimals,
|
||||
}}
|
||||
/>
|
||||
<DisplayCurrency
|
||||
parentheses
|
||||
options={{ abbreviated: false }}
|
||||
className='justify-end pl-2 text-sm text-white/50'
|
||||
coin={
|
||||
new BNCoin({
|
||||
denom: props.buyAsset.denom,
|
||||
amount: magnify(1, props.buyAsset).toString(),
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
contentClassName='px-0.5 pb-0.5 h-full'
|
||||
className='min-h-[55vh]'
|
||||
>
|
||||
<div ref={chartContainerRef} className='h-full overflow-hidden rounded-b-base' />
|
||||
</Card>
|
||||
)
|
||||
|
@ -4,6 +4,8 @@ import { useState } from 'react'
|
||||
|
||||
import Card from 'components/Card'
|
||||
import { CircularProgress } from 'components/CircularProgress'
|
||||
import Loading from 'components/Loading'
|
||||
import Text from 'components/Text'
|
||||
|
||||
const TVChartContainer = dynamic(
|
||||
() => import('components/Trade/TradeChart/TVChartContainer').then((mod) => mod.TVChartContainer),
|
||||
@ -33,7 +35,18 @@ export default function TradeChart(props: Props) {
|
||||
{isScriptReady ? (
|
||||
<TVChartContainer buyAsset={props.buyAsset} sellAsset={props.sellAsset} />
|
||||
) : (
|
||||
<Card title='Trading Chart' contentClassName='px-0.5 pb-0.5 h-full'>
|
||||
<Card
|
||||
title={
|
||||
<div className='flex items-center w-full bg-white/10'>
|
||||
<Text size='lg' className='flex items-center flex-1 p-4 font-semibold'>
|
||||
Trading Chart
|
||||
</Text>
|
||||
<Loading className='h-4 mr-4 w-60' />
|
||||
</div>
|
||||
}
|
||||
contentClassName='px-0.5 pb-0.5 h-full'
|
||||
className='min-h-[55vh]'
|
||||
>
|
||||
<div className='flex items-center justify-center w-full h-full rounded-b-base bg-chart'>
|
||||
<CircularProgress size={60} className='opacity-50' />
|
||||
</div>
|
||||
|
@ -7,11 +7,14 @@ import { CircularProgress } from 'components/CircularProgress'
|
||||
import DisplayCurrency from 'components/DisplayCurrency'
|
||||
import Divider from 'components/Divider'
|
||||
import { FormattedNumber } from 'components/FormattedNumber'
|
||||
import { ChevronDown } from 'components/Icons'
|
||||
import Text from 'components/Text'
|
||||
import { DEFAULT_SETTINGS } from 'constants/defaultSettings'
|
||||
import { LocalStorageKeys } from 'constants/localStorageKeys'
|
||||
import useLocalStorage from 'hooks/useLocalStorage'
|
||||
import usePrice from 'hooks/usePrice'
|
||||
import useSwapFee from 'hooks/useSwapFee'
|
||||
import useToggle from 'hooks/useToggle'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { getAssetByDenom } from 'utils/assets'
|
||||
import { formatAmountWithSymbol, formatPercent } from 'utils/formatters'
|
||||
@ -55,6 +58,7 @@ export default function TradeSummary(props: Props) {
|
||||
|
||||
const sellAssetPrice = usePrice(sellAsset.denom)
|
||||
const swapFee = useSwapFee(route.map((r) => r.pool_id))
|
||||
const [showSummary, setShowSummary] = useToggle()
|
||||
const [liquidationPrice, setLiquidationPrice] = useState<number | null>(null)
|
||||
const [isUpdatingLiquidationPrice, setIsUpdatingLiquidationPrice] = useState(false)
|
||||
const debouncedSetLiqPrice = useMemo(
|
||||
@ -99,7 +103,22 @@ export default function TradeSummary(props: Props) {
|
||||
)}
|
||||
>
|
||||
<div className='flex flex-col flex-1 m-3'>
|
||||
<span className='mb-2 text-xs font-bold'>Summary</span>
|
||||
<SummaryLine label='Liquidation Price'>
|
||||
<div className='flex h-2'>
|
||||
{isUpdatingLiquidationPrice ? (
|
||||
<CircularProgress className='opacity-50' />
|
||||
) : liquidationPrice === null || liquidationPrice === 0 ? (
|
||||
'-'
|
||||
) : (
|
||||
<FormattedNumber
|
||||
className='inline'
|
||||
amount={liquidationPrice}
|
||||
options={{ abbreviated: true, prefix: `${props.buyAsset.symbol} = $ ` }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</SummaryLine>
|
||||
<Divider className='my-2' />
|
||||
{isMargin && (
|
||||
<>
|
||||
<SummaryLine label='Borrowing'>
|
||||
@ -122,38 +141,45 @@ export default function TradeSummary(props: Props) {
|
||||
<Divider className='my-2' />
|
||||
</>
|
||||
)}
|
||||
<>
|
||||
<SummaryLine label='Liquidation Price'>
|
||||
<div className='flex h-2'>
|
||||
{isUpdatingLiquidationPrice ? (
|
||||
<CircularProgress className='opacity-50' />
|
||||
) : liquidationPrice === null || liquidationPrice === 0 ? (
|
||||
'-'
|
||||
) : (
|
||||
<FormattedNumber
|
||||
className='inline'
|
||||
amount={liquidationPrice}
|
||||
options={{ abbreviated: true, prefix: `${props.buyAsset.symbol} = $ ` }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</SummaryLine>
|
||||
<Divider className='my-2' />
|
||||
</>
|
||||
<SummaryLine label={`Swap fees (${(swapFee || 0.002) * 100}%)`}>
|
||||
<DisplayCurrency coin={BNCoin.fromDenomAndBigNumber(sellAsset.denom, swapFeeValue)} />
|
||||
</SummaryLine>
|
||||
<SummaryLine label='Transaction fees'>
|
||||
<span>{formatAmountWithSymbol(estimatedFee.amount[0])}</span>
|
||||
</SummaryLine>
|
||||
<SummaryLine label={`Min receive (${slippage * 100}% slippage)`}>
|
||||
<FormattedNumber
|
||||
amount={minReceive.toNumber()}
|
||||
options={{ decimals: buyAsset.decimals, suffix: ` ${buyAsset.symbol}`, maxDecimals: 6 }}
|
||||
/>
|
||||
</SummaryLine>
|
||||
<Divider className='my-2' />
|
||||
<SummaryLine label='Route'>{parsedRoutes}</SummaryLine>
|
||||
<div
|
||||
className='relative w-full pr-4 hover:pointer'
|
||||
role='button'
|
||||
onClick={() => setShowSummary(!showSummary)}
|
||||
>
|
||||
<Text size='xs' className='font-bold'>
|
||||
Summary
|
||||
</Text>
|
||||
<div
|
||||
className={classNames(
|
||||
'absolute right-0 w-3 text-center top-1',
|
||||
showSummary && 'rotate-180',
|
||||
)}
|
||||
>
|
||||
<ChevronDown />
|
||||
</div>
|
||||
</div>
|
||||
{showSummary && (
|
||||
<>
|
||||
<SummaryLine label={`Swap fees (${(swapFee || 0.002) * 100}%)`} className='mt-2'>
|
||||
<DisplayCurrency coin={BNCoin.fromDenomAndBigNumber(sellAsset.denom, swapFeeValue)} />
|
||||
</SummaryLine>
|
||||
<SummaryLine label='Transaction fees'>
|
||||
<span>{formatAmountWithSymbol(estimatedFee.amount[0])}</span>
|
||||
</SummaryLine>
|
||||
<SummaryLine label={`Min receive (${slippage * 100}% slippage)`}>
|
||||
<FormattedNumber
|
||||
amount={minReceive.toNumber()}
|
||||
options={{
|
||||
decimals: buyAsset.decimals,
|
||||
suffix: ` ${buyAsset.symbol}`,
|
||||
maxDecimals: 6,
|
||||
}}
|
||||
/>
|
||||
</SummaryLine>
|
||||
<Divider className='my-2' />
|
||||
<SummaryLine label='Route'>{parsedRoutes}</SummaryLine>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<ActionButton
|
||||
disabled={buyButtonDisabled}
|
||||
@ -171,10 +197,11 @@ export default function TradeSummary(props: Props) {
|
||||
interface SummaryLineProps {
|
||||
children: React.ReactNode
|
||||
label: string
|
||||
className?: string
|
||||
}
|
||||
function SummaryLine(props: SummaryLineProps) {
|
||||
return (
|
||||
<div className={infoLineClasses}>
|
||||
<div className={classNames(infoLineClasses, props.className)}>
|
||||
<span className='opacity-40'>{props.label}</span>
|
||||
<span>{props.children}</span>
|
||||
</div>
|
||||
|
@ -12,15 +12,16 @@ export default function TradeModule(props: Props) {
|
||||
const { buyAsset, sellAsset } = props
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'relative isolate max-w-full overflow-hidden rounded-base pb-4 z-30',
|
||||
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:rounded-base before:p-[1px] before:border-glas',
|
||||
'h-full',
|
||||
)}
|
||||
>
|
||||
<AssetSelector buyAsset={buyAsset} sellAsset={sellAsset} />
|
||||
<SwapForm buyAsset={buyAsset} sellAsset={sellAsset} />
|
||||
<div className='row-span-2'>
|
||||
<div
|
||||
className={classNames(
|
||||
'relative isolate max-w-full overflow-hidden rounded-base pb-4 z-30',
|
||||
'before:content-[" "] before:absolute before:inset-0 before:-z-1 before:rounded-base before:p-[1px] before:border-glas',
|
||||
)}
|
||||
>
|
||||
<AssetSelector buyAsset={buyAsset} sellAsset={sellAsset} />
|
||||
<SwapForm buyAsset={buyAsset} sellAsset={sellAsset} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -32,7 +32,11 @@ function Content() {
|
||||
const urlAccountId = useAccountId()
|
||||
const navigate = useNavigate()
|
||||
const { pathname } = useLocation()
|
||||
const { data: accountIds, isLoading: isLoadingAccounts } = useAccountIds(address || '')
|
||||
const { data: accountIds, isLoading: isLoadingAccounts } = useAccountIds(
|
||||
address || '',
|
||||
true,
|
||||
true,
|
||||
)
|
||||
const { data: walletBalances, isLoading: isLoadingBalances } = useWalletBalances(address)
|
||||
const baseAsset = getBaseAsset()
|
||||
|
||||
@ -54,7 +58,9 @@ function Content() {
|
||||
accountIds.length !== 0 &&
|
||||
BN(baseBalance).isGreaterThanOrEqualTo(defaultFee.amount[0].amount)
|
||||
) {
|
||||
navigate(getRoute(page, address, urlAccountId ?? accountIds[0]))
|
||||
const currentAccountIsHLS = urlAccountId && !accountIds.includes(urlAccountId)
|
||||
const currentAccount = currentAccountIsHLS || !urlAccountId ? accountIds[0] : urlAccountId
|
||||
navigate(getRoute(page, address, currentAccount))
|
||||
useStore.setState({ balances: walletBalances, focusComponent: null })
|
||||
}
|
||||
}, [
|
||||
|
@ -83,8 +83,8 @@ export const ASSETS: Asset[] = [
|
||||
isDisplayCurrency: true,
|
||||
isAutoLendEnabled: true,
|
||||
isBorrowEnabled: true,
|
||||
pythPriceFeedId: 'e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43',
|
||||
pythHistoryFeedId: 'Crypto.BTC/USD',
|
||||
pythPriceFeedId: 'c9d8b075a5c69303365ae23633d4e085199bf5c520a3b90fed1322a0342ffc33',
|
||||
pythHistoryFeedId: 'Crypto.WBTC/USD',
|
||||
poolId: 712,
|
||||
},
|
||||
{
|
||||
|
@ -4,7 +4,7 @@ import getAccountIds from 'api/wallets/getAccountIds'
|
||||
|
||||
export default function useAccountIdsAndKinds(address?: string, suspense = true, noHls = false) {
|
||||
return useSWR(
|
||||
`wallets/${address}/account-ids`,
|
||||
`wallets/${address}/account-ids${noHls && '-without-hls'}`,
|
||||
() =>
|
||||
getAccountIds(address).then((accountIdsAndKinds) => {
|
||||
if (noHls) {
|
||||
|
@ -216,8 +216,9 @@ export default function useHealthComputer(account?: Account) {
|
||||
)
|
||||
|
||||
const health = useMemo(() => {
|
||||
const slope = account?.kind === 'high_levered_strategy' ? 1.2 : 3.5
|
||||
const convertedHealth = BN(Math.log(healthFactor))
|
||||
.dividedBy(Math.log(3.5))
|
||||
.dividedBy(Math.log(slope))
|
||||
.multipliedBy(100)
|
||||
.integerValue()
|
||||
.toNumber()
|
||||
@ -226,7 +227,7 @@ export default function useHealthComputer(account?: Account) {
|
||||
if (convertedHealth === 0 && healthFactor > 1) return 1
|
||||
if (convertedHealth < 0) return 0
|
||||
return convertedHealth
|
||||
}, [healthFactor])
|
||||
}, [healthFactor, account?.kind])
|
||||
|
||||
return {
|
||||
health,
|
||||
|
@ -34,7 +34,6 @@ export default function TradePage() {
|
||||
<div className='grid h-full w-full grid-cols-[346px_auto] gap-4'>
|
||||
<TradeModule buyAsset={buyAsset} sellAsset={sellAsset} />
|
||||
<TradeChart buyAsset={buyAsset} sellAsset={sellAsset} />
|
||||
<div />
|
||||
<AccountDetailsCard />
|
||||
</div>
|
||||
{assetOverlayState !== 'closed' && (
|
||||
|
8
src/types/custom.d.ts
vendored
8
src/types/custom.d.ts
vendored
@ -1,4 +1,12 @@
|
||||
import '@tanstack/react-table'
|
||||
|
||||
declare module '*.svg' {
|
||||
const content: React.FunctionComponent<React.SVGAttributes<SVGElement>>
|
||||
export default content
|
||||
}
|
||||
|
||||
declare module '@tanstack/table-core' {
|
||||
interface ColumnMeta<TData extends RowData, TValue> {
|
||||
className?: string
|
||||
}
|
||||
}
|
||||
|
@ -22,4 +22,4 @@ export const DEFAULT_PORTFOLIO_STATS = [
|
||||
|
||||
export const ENABLE_HLS = true
|
||||
export const ENABLE_PERPS = false
|
||||
export const ENABLE_AUTO_REPAY = false
|
||||
export const ENABLE_AUTO_REPAY = true
|
||||
|
Loading…
Reference in New Issue
Block a user