feat: created AccountPerpsPositions for the AccountDetails component (#745)
* feat: created AccountPerpsPositions for the AccountDetails component * fix: type fixing * feat: added ToolTip * tidy: refactor * fix: added unrealized PnL placeholder * tidy: finetune on the border color * fix: fixed tables * fix: adjustments according to feedback * fix: fixed lent assets table * fix: fixed typing * refactor: streamline size to amount
This commit is contained in:
parent
254df8cd6e
commit
0ccb29154a
@ -17,7 +17,7 @@ export default async function getHLSStakingAccounts(
|
|||||||
if (account.deposits.length === 0) return
|
if (account.deposits.length === 0) return
|
||||||
|
|
||||||
const strategy = hlsStrategies.find(
|
const strategy = hlsStrategies.find(
|
||||||
(strategy) => strategy.denoms.deposit === account.deposits.at(0).denom,
|
(strategy) => strategy.denoms.deposit === account.deposits[0].denom,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!strategy) return
|
if (!strategy) return
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import { getPerpsQueryClient } from 'api/cosmwasm-client'
|
import { getPerpsQueryClient } from 'api/cosmwasm-client'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
|
||||||
export default async function getOpeningFee(chainConfig: ChainConfig, denom: string, size: string) {
|
export default async function getOpeningFee(
|
||||||
|
chainConfig: ChainConfig,
|
||||||
|
denom: string,
|
||||||
|
amount: string,
|
||||||
|
) {
|
||||||
const perpsClient = await getPerpsQueryClient(chainConfig)
|
const perpsClient = await getPerpsQueryClient(chainConfig)
|
||||||
|
|
||||||
return perpsClient
|
return perpsClient
|
||||||
.openingFee({ denom, size: size as any })
|
.openingFee({ denom, size: amount as any })
|
||||||
.then((resp) => BNCoin.fromCoin(resp.fee))
|
.then((resp) => BNCoin.fromCoin(resp.fee))
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,23 @@
|
|||||||
import { useCallback, useState } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
|
|
||||||
|
import Modal from 'components/Modals/Modal'
|
||||||
import CurrentAccountSummary from 'components/account/CurrentAccountSummary'
|
import CurrentAccountSummary from 'components/account/CurrentAccountSummary'
|
||||||
import AssetImage from 'components/common/assets/AssetImage'
|
|
||||||
import Button from 'components/common/Button'
|
import Button from 'components/common/Button'
|
||||||
import Card from 'components/common/Card'
|
import Card from 'components/common/Card'
|
||||||
import Divider from 'components/common/Divider'
|
import Divider from 'components/common/Divider'
|
||||||
import { ArrowRight } from 'components/common/Icons'
|
import { ArrowRight } from 'components/common/Icons'
|
||||||
import Modal from 'components/Modals/Modal'
|
|
||||||
import Text from 'components/common/Text'
|
import Text from 'components/common/Text'
|
||||||
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
|
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
|
||||||
|
import AssetImage from 'components/common/assets/AssetImage'
|
||||||
import { BN_ZERO } from 'constants/math'
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { BN } from 'utils/helpers'
|
import { BN } from 'utils/helpers'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
asset: Asset
|
asset: Asset
|
||||||
title: string
|
title: string
|
||||||
coinBalances: Coin[]
|
coinBalances: BNCoin[]
|
||||||
actionButtonText: string
|
actionButtonText: string
|
||||||
contentHeader?: JSX.Element
|
contentHeader?: JSX.Element
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
|
@ -28,7 +28,7 @@ export default function Repay(props: Props) {
|
|||||||
const repay = useStore((s) => s.repay)
|
const repay = useStore((s) => s.repay)
|
||||||
|
|
||||||
const currentDebt: BigNumber = useMemo(
|
const currentDebt: BigNumber = useMemo(
|
||||||
() => props.account.debts.find(byDenom(props.borrowAsset.denom)).amount || BN_ZERO,
|
() => props.account.debts.find(byDenom(props.borrowAsset.denom))?.amount || BN_ZERO,
|
||||||
[props.account.debts, props.borrowAsset.denom],
|
[props.account.debts, props.borrowAsset.denom],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useMemo } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
|
|
||||||
import Button from 'components/common/Button'
|
import Button from 'components/common/Button'
|
||||||
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
|
import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider'
|
||||||
@ -42,6 +42,7 @@ export default function Withdraw(props: Props) {
|
|||||||
|
|
||||||
const onClick = useCallback(() => {
|
const onClick = useCallback(() => {
|
||||||
useStore.setState({ hlsManageModal: null })
|
useStore.setState({ hlsManageModal: null })
|
||||||
|
if (!removedDeposit) return
|
||||||
withdraw({
|
withdraw({
|
||||||
accountId: props.account.id,
|
accountId: props.account.id,
|
||||||
coins: [{ coin: removedDeposit }],
|
coins: [{ coin: removedDeposit }],
|
||||||
|
@ -15,7 +15,7 @@ function DetailsHeader({ data }: Props) {
|
|||||||
const balanceInWallet = useCurrentWalletBalance(asset.denom)
|
const balanceInWallet = useCurrentWalletBalance(asset.denom)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex gap-6 border-b border-white/5 px-6 py-4 gradient-header'>
|
<div className='flex gap-6 px-6 py-4 border-b border-white/5 gradient-header'>
|
||||||
{assetApy && (
|
{assetApy && (
|
||||||
<>
|
<>
|
||||||
<TitleAndSubCell
|
<TitleAndSubCell
|
||||||
@ -40,7 +40,7 @@ function DetailsHeader({ data }: Props) {
|
|||||||
<TitleAndSubCell
|
<TitleAndSubCell
|
||||||
title={
|
title={
|
||||||
<DisplayCurrency
|
<DisplayCurrency
|
||||||
coin={new BNCoin({ denom: asset.denom, amount: accountLentAmount })}
|
coin={new BNCoin({ denom: asset.denom, amount: accountLentAmount.toString() })}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
sub={'Deposited'}
|
sub={'Deposited'}
|
||||||
|
@ -7,7 +7,7 @@ interface Props {
|
|||||||
apy: number
|
apy: number
|
||||||
markets: Market[]
|
markets: Market[]
|
||||||
denom: string
|
denom: string
|
||||||
type: 'deposits' | 'borrowing' | 'lending' | 'vault'
|
type: PositionType
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Apr(props: Props) {
|
export default function Apr(props: Props) {
|
||||||
@ -20,7 +20,7 @@ export default function Apr(props: Props) {
|
|||||||
<AssetRate
|
<AssetRate
|
||||||
className='justify-end text-xs'
|
className='justify-end text-xs'
|
||||||
rate={apy}
|
rate={apy}
|
||||||
isEnabled={type !== 'lending' || isEnabled}
|
isEnabled={type !== 'lend' || isEnabled}
|
||||||
type='apy'
|
type='apy'
|
||||||
orientation='ltr'
|
orientation='ltr'
|
||||||
/>
|
/>
|
||||||
|
@ -3,19 +3,16 @@ export const ASSET_META = { accessorKey: 'symbol', header: 'Asset', id: 'symbol'
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
symbol: string
|
symbol: string
|
||||||
type: 'deposits' | 'borrowing' | 'lending' | 'vault'
|
type: PositionType
|
||||||
}
|
}
|
||||||
|
|
||||||
export const borderColor = (type: Props['type']): string =>
|
|
||||||
type === 'borrowing' ? 'border-loss' : 'border-profit'
|
|
||||||
|
|
||||||
export default function Asset(props: Props) {
|
export default function Asset(props: Props) {
|
||||||
const { symbol, type } = props
|
const { symbol, type } = props
|
||||||
return (
|
return (
|
||||||
<Text size='xs'>
|
<Text size='xs'>
|
||||||
{symbol}
|
{symbol}
|
||||||
{type === 'borrowing' && <span className='ml-1 text-loss'>(debt)</span>}
|
{type === 'borrow' && <span className='ml-1 text-loss'>(debt)</span>}
|
||||||
{type === 'lending' && <span className='ml-1 text-profit'>(lent)</span>}
|
{type === 'lend' && <span className='ml-1 text-profit'>(lent)</span>}
|
||||||
{type === 'vault' && <span className='ml-1 text-profit'>(farm)</span>}
|
{type === 'vault' && <span className='ml-1 text-profit'>(farm)</span>}
|
||||||
</Text>
|
</Text>
|
||||||
)
|
)
|
||||||
|
@ -20,7 +20,7 @@ interface Props {
|
|||||||
amount: number
|
amount: number
|
||||||
computeLiquidationPrice: (denom: string, kind: LiquidationPriceKind) => number | null
|
computeLiquidationPrice: (denom: string, kind: LiquidationPriceKind) => number | null
|
||||||
denom: string
|
denom: string
|
||||||
type: 'deposits' | 'borrowing' | 'lending' | 'vault'
|
type: PositionType
|
||||||
account: Account
|
account: Account
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ export default function LiqPrice(props: Props) {
|
|||||||
|
|
||||||
const liqPrice = useMemo(() => {
|
const liqPrice = useMemo(() => {
|
||||||
if (type === 'vault' || amount === 0) return 0
|
if (type === 'vault' || amount === 0) return 0
|
||||||
return computeLiquidationPrice(denom, type === 'borrowing' ? 'debt' : 'asset')
|
return computeLiquidationPrice(denom, type === 'borrow' ? 'debt' : 'asset')
|
||||||
}, [amount, computeLiquidationPrice, denom, type])
|
}, [amount, computeLiquidationPrice, denom, type])
|
||||||
|
|
||||||
const { liquidationPrice } = useLiquidationPrice(liqPrice)
|
const { liquidationPrice } = useLiquidationPrice(liqPrice)
|
||||||
|
@ -8,7 +8,7 @@ export const PRICE_META = { id: 'price', header: 'Price', meta: { className: 'w-
|
|||||||
interface Props {
|
interface Props {
|
||||||
amount: number
|
amount: number
|
||||||
denom: string
|
denom: string
|
||||||
type: 'deposits' | 'borrowing' | 'lending' | 'vault'
|
type: PositionType
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Price(props: Props) {
|
export default function Price(props: Props) {
|
||||||
|
@ -12,7 +12,7 @@ interface Props {
|
|||||||
size: number
|
size: number
|
||||||
amountChange: BigNumber
|
amountChange: BigNumber
|
||||||
denom: string
|
denom: string
|
||||||
type: 'deposits' | 'borrowing' | 'lending' | 'vault'
|
type: PositionType
|
||||||
}
|
}
|
||||||
|
|
||||||
export const sizeSortingFn = (a: Row<AccountBalanceRow>, b: Row<AccountBalanceRow>): number => {
|
export const sizeSortingFn = (a: Row<AccountBalanceRow>, b: Row<AccountBalanceRow>): number => {
|
||||||
|
@ -12,10 +12,19 @@ export const VALUE_META = { accessorKey: 'value', header: 'Value' }
|
|||||||
interface Props {
|
interface Props {
|
||||||
amountChange: BigNumber
|
amountChange: BigNumber
|
||||||
value: string
|
value: string
|
||||||
type: 'deposits' | 'borrowing' | 'lending' | 'vault'
|
type: PositionType
|
||||||
}
|
}
|
||||||
|
|
||||||
export const valueSortingFn = (a: Row<AccountBalanceRow>, b: Row<AccountBalanceRow>): number => {
|
export const valueBalancesSortingFn = (
|
||||||
|
a: Row<AccountBalanceRow>,
|
||||||
|
b: Row<AccountBalanceRow>,
|
||||||
|
): number => {
|
||||||
|
const valueA = BN(a.original.value)
|
||||||
|
const valueB = BN(b.original.value)
|
||||||
|
return valueA.minus(valueB).toNumber()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const valuePerpSortingFn = (a: Row<AccountPerpRow>, b: Row<AccountPerpRow>): number => {
|
||||||
const valueA = BN(a.original.value)
|
const valueA = BN(a.original.value)
|
||||||
const valueB = BN(b.original.value)
|
const valueB = BN(b.original.value)
|
||||||
return valueA.minus(valueB).toNumber()
|
return valueA.minus(valueB).toNumber()
|
||||||
@ -30,10 +39,6 @@ export default function Value(props: Props) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DisplayCurrency
|
<DisplayCurrency coin={coin} className={classNames('text-xs text-right', color)} showZero />
|
||||||
coin={coin}
|
|
||||||
className={classNames('text-xs text-right', color)}
|
|
||||||
showZero={true}
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import Size, {
|
|||||||
} from 'components/account/AccountBalancesTable/Columns/Size'
|
} from 'components/account/AccountBalancesTable/Columns/Size'
|
||||||
import Value, {
|
import Value, {
|
||||||
VALUE_META,
|
VALUE_META,
|
||||||
valueSortingFn,
|
valueBalancesSortingFn,
|
||||||
} from 'components/account/AccountBalancesTable/Columns/Value'
|
} from 'components/account/AccountBalancesTable/Columns/Value'
|
||||||
import useMarketAssets from 'hooks/markets/useMarketAssets'
|
import useMarketAssets from 'hooks/markets/useMarketAssets'
|
||||||
import useHealthComputer from 'hooks/useHealthComputer'
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
@ -41,7 +41,7 @@ export default function useAccountBalancesColumns(
|
|||||||
type={row.original.type}
|
type={row.original.type}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
sortingFn: valueSortingFn,
|
sortingFn: valueBalancesSortingFn,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...SIZE_META,
|
...SIZE_META,
|
||||||
|
@ -3,7 +3,7 @@ import { BNCoin } from 'types/classes/BNCoin'
|
|||||||
import { demagnify, getCoinValue } from 'utils/formatters'
|
import { demagnify, getCoinValue } from 'utils/formatters'
|
||||||
|
|
||||||
export function getAssetAccountBalanceRow(
|
export function getAssetAccountBalanceRow(
|
||||||
type: 'deposits' | 'borrowing' | 'lending',
|
type: 'deposit' | 'borrow' | 'lend',
|
||||||
asset: Asset,
|
asset: Asset,
|
||||||
prices: BNCoin[],
|
prices: BNCoin[],
|
||||||
assets: Asset[],
|
assets: Asset[],
|
||||||
@ -57,11 +57,9 @@ export function getVaultAccountBalanceRow(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAmountChangeColor(
|
export function getAmountChangeColor(type: PositionType, amount: BigNumber) {
|
||||||
type: 'deposits' | 'borrowing' | 'lending' | 'vault',
|
if (type === 'perp') return ''
|
||||||
amount: BigNumber,
|
if (type === 'borrow') {
|
||||||
) {
|
|
||||||
if (type === 'borrowing') {
|
|
||||||
if (amount.isGreaterThan(0)) return 'text-loss'
|
if (amount.isGreaterThan(0)) return 'text-loss'
|
||||||
if (amount.isLessThan(0)) return 'text-profit'
|
if (amount.isLessThan(0)) return 'text-profit'
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ export default function AccountBalancesTable(props: Props) {
|
|||||||
initialSorting={[]}
|
initialSorting={[]}
|
||||||
spacingClassName='p-2'
|
spacingClassName='p-2'
|
||||||
hideCard={hideCard}
|
hideCard={hideCard}
|
||||||
isBalancesTable
|
type='balances'
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ export default function useAccountBalanceData(props: Props) {
|
|||||||
: 0
|
: 0
|
||||||
const prevDeposit = updatedAccount ? account?.deposits.find(byDenom(deposit.denom)) : deposit
|
const prevDeposit = updatedAccount ? account?.deposits.find(byDenom(deposit.denom)) : deposit
|
||||||
deposits.push(
|
deposits.push(
|
||||||
getAssetAccountBalanceRow('deposits', asset, prices, assets, deposit, apy, prevDeposit),
|
getAssetAccountBalanceRow('deposit', asset, prices, assets, deposit, apy, prevDeposit),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ export default function useAccountBalanceData(props: Props) {
|
|||||||
const prevLending = updatedAccount
|
const prevLending = updatedAccount
|
||||||
? account?.lends.find((position) => position.denom === lending.denom)
|
? account?.lends.find((position) => position.denom === lending.denom)
|
||||||
: lending
|
: lending
|
||||||
return getAssetAccountBalanceRow('lending', asset, prices, assets, lending, apy, prevLending)
|
return getAssetAccountBalanceRow('lend', asset, prices, assets, lending, apy, prevLending)
|
||||||
})
|
})
|
||||||
|
|
||||||
const vaults = accountVaults.map((vault) => {
|
const vaults = accountVaults.map((vault) => {
|
||||||
@ -67,7 +67,7 @@ export default function useAccountBalanceData(props: Props) {
|
|||||||
const prevDebt = updatedAccount
|
const prevDebt = updatedAccount
|
||||||
? account?.debts.find((position) => position.denom === debt.denom)
|
? account?.debts.find((position) => position.denom === debt.denom)
|
||||||
: debt
|
: debt
|
||||||
return getAssetAccountBalanceRow('borrowing', asset, prices, assets, debt, apy, prevDebt)
|
return getAssetAccountBalanceRow('borrow', asset, prices, assets, debt, apy, prevDebt)
|
||||||
})
|
})
|
||||||
return [...deposits, ...lends, ...vaults, ...debts]
|
return [...deposits, ...lends, ...vaults, ...debts]
|
||||||
}, [
|
}, [
|
||||||
|
@ -6,6 +6,7 @@ import AccountBalancesTable from 'components/account/AccountBalancesTable'
|
|||||||
import AccountComposition from 'components/account/AccountComposition'
|
import AccountComposition from 'components/account/AccountComposition'
|
||||||
import AccountDetailsLeverage from 'components/account/AccountDetails/AccountDetailsLeverage'
|
import AccountDetailsLeverage from 'components/account/AccountDetails/AccountDetailsLeverage'
|
||||||
import Skeleton from 'components/account/AccountDetails/Skeleton'
|
import Skeleton from 'components/account/AccountDetails/Skeleton'
|
||||||
|
import AccountPerpPositionTable from 'components/account/AccountPerpPositionTable'
|
||||||
import { HealthGauge } from 'components/account/Health/HealthGauge'
|
import { HealthGauge } from 'components/account/Health/HealthGauge'
|
||||||
import EscButton from 'components/common/Button/EscButton'
|
import EscButton from 'components/common/Button/EscButton'
|
||||||
import { glowElement } from 'components/common/Button/utils'
|
import { glowElement } from 'components/common/Button/utils'
|
||||||
@ -24,8 +25,8 @@ import useLocalStorage from 'hooks/localStorage/useLocalStorage'
|
|||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData'
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
import useHealthComputer from 'hooks/useHealthComputer'
|
|
||||||
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
import useHLSStakingAssets from 'hooks/useHLSStakingAssets'
|
||||||
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
@ -114,7 +115,10 @@ function AccountDetails(props: Props) {
|
|||||||
),
|
),
|
||||||
[account, assets, borrowAssetsData, hlsStrategies, lendingAssetsData, prices, updatedAccount],
|
[account, assets, borrowAssetsData, hlsStrategies, lendingAssetsData, prices, updatedAccount],
|
||||||
)
|
)
|
||||||
const isFullWidth = location.pathname.includes('trade') || location.pathname === '/'
|
const isFullWidth =
|
||||||
|
location.pathname.includes('trade') ||
|
||||||
|
location.pathname === '/' ||
|
||||||
|
location.pathname.includes('perps')
|
||||||
|
|
||||||
function AccountDetailsHeader() {
|
function AccountDetailsHeader() {
|
||||||
const onClose = useCallback(() => useStore.setState({ accountDetailsExpanded: false }), [])
|
const onClose = useCallback(() => useStore.setState({ accountDetailsExpanded: false }), [])
|
||||||
@ -215,6 +219,12 @@ function AccountDetails(props: Props) {
|
|||||||
lendingData={lendingAssetsData}
|
lendingData={lendingAssetsData}
|
||||||
hideCard
|
hideCard
|
||||||
/>
|
/>
|
||||||
|
{account.perps.length > 0 && (
|
||||||
|
<>
|
||||||
|
<Text className='w-full px-4 py-2 text-white bg-white/10'>Perp Positions</Text>
|
||||||
|
<AccountPerpPositionTable account={account} hideCard />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
import { ReactNode } from 'react'
|
||||||
|
|
||||||
|
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||||
|
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||||
|
import Text from 'components/common/Text'
|
||||||
|
import { Tooltip } from 'components/common/Tooltip'
|
||||||
|
import TradeDirection from 'components/perps/BalancesTable/Columns/TradeDirection'
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
|
import usePerpsEnabledAssets from 'hooks/assets/usePerpsEnabledAssets'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { demagnify } from 'utils/formatters'
|
||||||
|
export const ASSET_META = { accessorKey: 'symbol', header: 'Asset', id: 'symbol' }
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
row: AccountPerpRow
|
||||||
|
}
|
||||||
|
|
||||||
|
function LabelAndValue(props: { label: string; children: ReactNode; className?: string }) {
|
||||||
|
const { label, children, className } = props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='flex items-center justify-between'>
|
||||||
|
<Text size='sm' className='text-white/60'>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function TooltipContent(props: Props) {
|
||||||
|
const { row } = props
|
||||||
|
const assets = usePerpsEnabledAssets()
|
||||||
|
const asset = assets.find((asset) => asset.symbol === row.symbol)
|
||||||
|
if (!asset) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='flex flex-col flex-wrap gap-1 w-50'>
|
||||||
|
<LabelAndValue label='Entry Price'>
|
||||||
|
<FormattedNumber amount={row.entryPrice.toNumber()} options={{ prefix: '$' }} />
|
||||||
|
</LabelAndValue>
|
||||||
|
<LabelAndValue label='Size'>
|
||||||
|
<Text size='sm'>{demagnify(row.amount, asset)}</Text>
|
||||||
|
</LabelAndValue>
|
||||||
|
<LabelAndValue label='Realized PnL'>
|
||||||
|
<DisplayCurrency
|
||||||
|
className='text-sm text-right number'
|
||||||
|
coin={BNCoin.fromDenomAndBigNumber('usd', BN_ZERO)}
|
||||||
|
showZero
|
||||||
|
/>
|
||||||
|
</LabelAndValue>
|
||||||
|
<LabelAndValue label='Unrealized PnL'>
|
||||||
|
<DisplayCurrency coin={row.pnl} options={{ abbreviated: false }} showZero isProfitOrLoss />
|
||||||
|
</LabelAndValue>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Asset(props: Props) {
|
||||||
|
const { row } = props
|
||||||
|
return (
|
||||||
|
<Tooltip content={<TooltipContent row={row} />} type='info'>
|
||||||
|
<Text size='xs' className='flex items-center gap-1 no-wrap group/asset hover:cursor-help'>
|
||||||
|
<span className='pb-[1px] border-b border-white/20 border-dashed group-hover/asset:border-transparent'>
|
||||||
|
{row.symbol}
|
||||||
|
</span>
|
||||||
|
<TradeDirection tradeDirection={row.tradeDirection} />
|
||||||
|
</Text>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
|
||||||
|
export const PNL_META = { id: 'pnl', header: 'Total PnL', meta: { className: 'w-30' } }
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
pnl: BNCoin
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function TotalPnL(props: Props) {
|
||||||
|
const { pnl } = props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DisplayCurrency
|
||||||
|
className='text-xs text-right number'
|
||||||
|
coin={pnl}
|
||||||
|
options={{ abbreviated: false }}
|
||||||
|
isProfitOrLoss
|
||||||
|
showZero
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
import { ColumnDef } from '@tanstack/react-table'
|
||||||
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
|
import LiqPrice, { LIQ_META } from 'components/account/AccountBalancesTable/Columns/LiqPrice'
|
||||||
|
import Value, {
|
||||||
|
VALUE_META,
|
||||||
|
valuePerpSortingFn,
|
||||||
|
} from 'components/account/AccountBalancesTable/Columns/Value'
|
||||||
|
import Asset, { ASSET_META } from 'components/account/AccountPerpPositionTable/Columns/Asset'
|
||||||
|
import TotalPnL, { PNL_META } from 'components/account/AccountPerpPositionTable/Columns/TotalPnL'
|
||||||
|
import useHealthComputer from 'hooks/useHealthComputer'
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
|
export default function useAccountPerpsColumns(account: Account, showLiquidationPrice?: boolean) {
|
||||||
|
const updatedAccount = useStore((s) => s.updatedAccount)
|
||||||
|
|
||||||
|
const { computeLiquidationPrice } = useHealthComputer(updatedAccount ?? account)
|
||||||
|
|
||||||
|
return useMemo<ColumnDef<AccountPerpRow>[]>(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
...ASSET_META,
|
||||||
|
cell: ({ row }) => <Asset row={row.original} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...VALUE_META,
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<Value amountChange={row.original.amountChange} value={row.original.value} type='perp' />
|
||||||
|
),
|
||||||
|
sortingFn: valuePerpSortingFn,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...LIQ_META,
|
||||||
|
header: 'Liq. Price',
|
||||||
|
enableSorting: false,
|
||||||
|
cell: ({ row }) => (
|
||||||
|
<LiqPrice
|
||||||
|
denom={row.original.denom}
|
||||||
|
computeLiquidationPrice={computeLiquidationPrice}
|
||||||
|
type='perp'
|
||||||
|
amount={row.original.amount.toNumber()}
|
||||||
|
account={updatedAccount ?? account}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...PNL_META,
|
||||||
|
cell: ({ row }) => <TotalPnL pnl={row.original.pnl} />,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}, [computeLiquidationPrice, account, updatedAccount])
|
||||||
|
}
|
20
src/components/account/AccountPerpPositionTable/functions.ts
Normal file
20
src/components/account/AccountPerpPositionTable/functions.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { BNCoin } from 'types/classes/BNCoin'
|
||||||
|
import { getCoinValue } from 'utils/formatters'
|
||||||
|
|
||||||
|
export function getAssetAccountPerpRow(
|
||||||
|
asset: Asset,
|
||||||
|
prices: BNCoin[],
|
||||||
|
position: PerpsPosition,
|
||||||
|
assets: Asset[],
|
||||||
|
prev?: BNCoin,
|
||||||
|
): AccountPerpRow {
|
||||||
|
const { denom, amount } = position
|
||||||
|
const amountChange = !prev ? position.amount : position.amount.minus(prev.amount)
|
||||||
|
|
||||||
|
return {
|
||||||
|
symbol: asset.symbol,
|
||||||
|
value: getCoinValue(BNCoin.fromDenomAndBigNumber(denom, amount), prices, assets).toString(),
|
||||||
|
amountChange,
|
||||||
|
...position,
|
||||||
|
}
|
||||||
|
}
|
37
src/components/account/AccountPerpPositionTable/index.tsx
Normal file
37
src/components/account/AccountPerpPositionTable/index.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
|
import useAccountPerpsColumns from 'components/account/AccountPerpPositionTable/Columns/useAccountPerpsColumns'
|
||||||
|
import useAccountPerpData from 'components/account/AccountPerpPositionTable/useAccountPerpData'
|
||||||
|
import Table from 'components/common/Table'
|
||||||
|
import useStore from 'store'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
account: Account
|
||||||
|
tableBodyClassName?: string
|
||||||
|
showLiquidationPrice?: boolean
|
||||||
|
hideCard?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AccountPerpPositionTable(props: Props) {
|
||||||
|
const { account, tableBodyClassName, showLiquidationPrice, hideCard } = props
|
||||||
|
const updatedAccount = useStore((s) => s.updatedAccount)
|
||||||
|
const accountPerpData = useAccountPerpData({
|
||||||
|
account,
|
||||||
|
updatedAccount,
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns = useAccountPerpsColumns(account, showLiquidationPrice)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Table
|
||||||
|
title='Perp Positions'
|
||||||
|
columns={columns}
|
||||||
|
data={accountPerpData}
|
||||||
|
tableBodyClassName={classNames(tableBodyClassName, 'text-white/60')}
|
||||||
|
initialSorting={[]}
|
||||||
|
spacingClassName='p-2'
|
||||||
|
hideCard={hideCard}
|
||||||
|
type='perps'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
|
import { getAssetAccountPerpRow } from 'components/account/AccountPerpPositionTable/functions'
|
||||||
|
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||||
|
import usePrices from 'hooks/usePrices'
|
||||||
|
import { byDenom } from 'utils/array'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
account: Account
|
||||||
|
updatedAccount?: Account
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useAccountPerpData(props: Props) {
|
||||||
|
const { account, updatedAccount } = props
|
||||||
|
const { data: prices } = usePrices()
|
||||||
|
const assets = useAllAssets()
|
||||||
|
|
||||||
|
return useMemo<AccountPerpRow[]>(() => {
|
||||||
|
const usedAccount = updatedAccount ?? account
|
||||||
|
const accountPerps = usedAccount?.perps ?? []
|
||||||
|
|
||||||
|
return accountPerps.map((perp) => {
|
||||||
|
const asset = assets.find(byDenom(perp.denom)) ?? assets[0]
|
||||||
|
const prevPerp = updatedAccount
|
||||||
|
? account?.perps.find((position) => position.denom === perp.denom)
|
||||||
|
: perp
|
||||||
|
return getAssetAccountPerpRow(asset, prices, perp, assets, prevPerp)
|
||||||
|
})
|
||||||
|
}, [updatedAccount, account, prices, assets])
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { HTMLAttributes, useCallback, useMemo } from 'react'
|
import { HTMLAttributes, useCallback, useMemo } from 'react'
|
||||||
|
|
||||||
import Accordion from 'components/common/Accordion'
|
|
||||||
import AccountBalancesTable from 'components/account/AccountBalancesTable'
|
import AccountBalancesTable from 'components/account/AccountBalancesTable'
|
||||||
import AccountComposition from 'components/account/AccountComposition'
|
import AccountComposition from 'components/account/AccountComposition'
|
||||||
|
import AccountPerpPositionTable from 'components/account/AccountPerpPositionTable'
|
||||||
import HealthBar from 'components/account/Health/HealthBar'
|
import HealthBar from 'components/account/Health/HealthBar'
|
||||||
|
import Accordion from 'components/common/Accordion'
|
||||||
import Card from 'components/common/Card'
|
import Card from 'components/common/Card'
|
||||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||||
import { FormattedNumber } from 'components/common/FormattedNumber'
|
import { FormattedNumber } from 'components/common/FormattedNumber'
|
||||||
@ -150,6 +151,16 @@ export default function AccountSummary(props: Props) {
|
|||||||
toggleOpen: (index: number) => handleToggle(index),
|
toggleOpen: (index: number) => handleToggle(index),
|
||||||
renderSubTitle: () => <></>,
|
renderSubTitle: () => <></>,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Perp Positions',
|
||||||
|
renderContent: () =>
|
||||||
|
props.account && props.account.perps.length > 0 ? (
|
||||||
|
<AccountPerpPositionTable account={props.account} hideCard />
|
||||||
|
) : null,
|
||||||
|
isOpen: accountSummaryTabs[2] ?? false,
|
||||||
|
toggleOpen: (index: number) => handleToggle(index),
|
||||||
|
renderSubTitle: () => <></>,
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
allowMultipleOpen
|
allowMultipleOpen
|
||||||
/>
|
/>
|
||||||
|
@ -22,6 +22,7 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function DisplayCurrency(props: Props) {
|
export default function DisplayCurrency(props: Props) {
|
||||||
|
const { coin, className, isApproximation, parentheses, showZero, options, isProfitOrLoss } = props
|
||||||
const displayCurrencies = useDisplayCurrencyAssets()
|
const displayCurrencies = useDisplayCurrencyAssets()
|
||||||
const assets = useAllAssets()
|
const assets = useAllAssets()
|
||||||
const [displayCurrency] = useDisplayCurrency()
|
const [displayCurrency] = useDisplayCurrency()
|
||||||
@ -36,7 +37,7 @@ export default function DisplayCurrency(props: Props) {
|
|||||||
const isUSD = displayCurrencyAsset.id === 'USD'
|
const isUSD = displayCurrencyAsset.id === 'USD'
|
||||||
|
|
||||||
const [amount, absoluteAmount] = useMemo(() => {
|
const [amount, absoluteAmount] = useMemo(() => {
|
||||||
const coinValue = getCoinValue(props.coin, prices, assets)
|
const coinValue = getCoinValue(coin, prices, assets)
|
||||||
|
|
||||||
if (displayCurrency === ORACLE_DENOM) return [coinValue.toNumber(), coinValue.abs().toNumber()]
|
if (displayCurrency === ORACLE_DENOM) return [coinValue.toNumber(), coinValue.abs().toNumber()]
|
||||||
|
|
||||||
@ -50,18 +51,29 @@ export default function DisplayCurrency(props: Props) {
|
|||||||
const amount = coinValue.div(displayPrice).toNumber()
|
const amount = coinValue.div(displayPrice).toNumber()
|
||||||
|
|
||||||
return [amount, Math.abs(amount)]
|
return [amount, Math.abs(amount)]
|
||||||
}, [assets, displayCurrency, displayCurrencyAsset.decimals, prices, props.coin])
|
}, [assets, displayCurrency, displayCurrencyAsset.decimals, prices, coin])
|
||||||
|
|
||||||
const isLessThanACent = useMemo(
|
const isLessThanACent = useMemo(
|
||||||
() => isUSD && absoluteAmount < 0.01 && absoluteAmount > 0,
|
() => isUSD && absoluteAmount < 0.01 && absoluteAmount > 0,
|
||||||
[absoluteAmount, isUSD],
|
[absoluteAmount, isUSD],
|
||||||
)
|
)
|
||||||
|
|
||||||
const smallerThanPrefix = isLessThanACent && !props.showZero ? '< ' : ''
|
const prefix = useMemo(() => {
|
||||||
|
const positiveOrNegativePrefix = isProfitOrLoss
|
||||||
|
? amount > 0
|
||||||
|
? '+'
|
||||||
|
: amount < 0
|
||||||
|
? '-'
|
||||||
|
: ''
|
||||||
|
: ''
|
||||||
|
const approximationPrefix = isApproximation ? '~ ' : ''
|
||||||
|
const smallerThanPrefix = isLessThanACent && !showZero ? '< ' : ''
|
||||||
|
|
||||||
|
return isUSD
|
||||||
|
? `${approximationPrefix}${smallerThanPrefix}${positiveOrNegativePrefix}$`
|
||||||
|
: `${approximationPrefix}${smallerThanPrefix}${positiveOrNegativePrefix}`
|
||||||
|
}, [isUSD, isApproximation, showZero, isProfitOrLoss, amount, isLessThanACent])
|
||||||
|
|
||||||
const prefix = isUSD
|
|
||||||
? `${props.isApproximation ? '~ ' : smallerThanPrefix}$`
|
|
||||||
: `${props.isApproximation ? '~ ' : ''}`
|
|
||||||
const suffix = isUSD
|
const suffix = isUSD
|
||||||
? ''
|
? ''
|
||||||
: ` ${displayCurrencyAsset.symbol ? ` ${displayCurrencyAsset.symbol}` : ''}`
|
: ` ${displayCurrencyAsset.symbol ? ` ${displayCurrencyAsset.symbol}` : ''}`
|
||||||
@ -69,19 +81,19 @@ export default function DisplayCurrency(props: Props) {
|
|||||||
return (
|
return (
|
||||||
<FormattedNumber
|
<FormattedNumber
|
||||||
className={classNames(
|
className={classNames(
|
||||||
props.className,
|
className,
|
||||||
props.parentheses && 'before:content-["("] after:content-[")"]',
|
parentheses && 'before:content-["("] after:content-[")"]',
|
||||||
props.isProfitOrLoss && (amount < 0 ? 'text-error' : amount === 0 ? '' : 'text-success'),
|
isProfitOrLoss && amount < 0 && 'text-loss',
|
||||||
props.isProfitOrLoss && amount < 0 && 'before:content-["-"]',
|
isProfitOrLoss && amount > 0 && 'text-profit',
|
||||||
)}
|
)}
|
||||||
amount={isLessThanACent ? 0.01 : absoluteAmount}
|
amount={isLessThanACent ? 0.01 : absoluteAmount}
|
||||||
options={{
|
options={{
|
||||||
minDecimals: isUSD ? 2 : 0,
|
minDecimals: isUSD ? 2 : 0,
|
||||||
maxDecimals: 2,
|
maxDecimals: 2,
|
||||||
abbreviated: true,
|
abbreviated: true,
|
||||||
prefix,
|
|
||||||
suffix,
|
suffix,
|
||||||
...props.options,
|
...options,
|
||||||
|
prefix,
|
||||||
}}
|
}}
|
||||||
animate
|
animate
|
||||||
/>
|
/>
|
||||||
|
@ -7,51 +7,56 @@ interface Props<T> {
|
|||||||
renderExpanded?: (row: TanstackRow<T>, table: TanstackTable<T>) => JSX.Element
|
renderExpanded?: (row: TanstackRow<T>, table: TanstackTable<T>) => JSX.Element
|
||||||
rowClassName?: string
|
rowClassName?: string
|
||||||
spacingClassName?: string
|
spacingClassName?: string
|
||||||
isBalancesTable?: boolean
|
|
||||||
className?: string
|
className?: string
|
||||||
isSelectable?: boolean
|
isSelectable?: boolean
|
||||||
|
type?: TableType
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBorderColor(row: AccountBalanceRow) {
|
function getBorderColor(type: TableType, row: AccountBalanceRow | AccountPerpRow) {
|
||||||
return row.type === 'borrowing' ? 'border-loss' : 'border-profit'
|
if (type === 'balances') {
|
||||||
|
const balancesRow = row as AccountBalanceRow
|
||||||
|
return balancesRow.type === 'borrow' ? 'border-loss' : 'border-profit'
|
||||||
|
}
|
||||||
|
|
||||||
|
const perpRow = row as AccountPerpRow
|
||||||
|
return perpRow.tradeDirection === 'short' ? 'border-loss' : 'border-profit'
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Row<T>(props: Props<T>) {
|
export default function Row<T>(props: Props<T>) {
|
||||||
const canExpand = !!props.renderExpanded
|
const { renderExpanded, table, row, type, spacingClassName, isSelectable } = props
|
||||||
|
const canExpand = !!renderExpanded
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<tr
|
<tr
|
||||||
key={`${props.row.id}-row`}
|
key={`${row.id}-row`}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'group/row transition-bg',
|
'group/row transition-bg',
|
||||||
(props.renderExpanded || props.isSelectable) && 'hover:cursor-pointer',
|
(renderExpanded || isSelectable) && 'hover:cursor-pointer',
|
||||||
canExpand && props.row.getIsExpanded() ? 'is-expanded bg-black/20' : 'hover:bg-white/5',
|
canExpand && row.getIsExpanded() ? 'is-expanded bg-black/20' : 'hover:bg-white/5',
|
||||||
)}
|
)}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (props.isSelectable) {
|
if (isSelectable) {
|
||||||
props.row.toggleSelected()
|
row.toggleSelected()
|
||||||
}
|
}
|
||||||
if (canExpand) {
|
if (canExpand) {
|
||||||
const isExpanded = props.row.getIsExpanded()
|
const isExpanded = row.getIsExpanded()
|
||||||
props.table.resetExpanded()
|
table.resetExpanded()
|
||||||
!isExpanded && props.row.toggleExpanded()
|
!isExpanded && row.toggleExpanded()
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.row.getVisibleCells().map((cell) => {
|
{row.getVisibleCells().map((cell) => {
|
||||||
const isSymbolOrName = cell.column.id === 'symbol' || cell.column.id === 'name'
|
const isSymbolOrName = cell.column.id === 'symbol' || cell.column.id === 'name'
|
||||||
const borderClasses =
|
|
||||||
props.isBalancesTable && isSymbolOrName
|
|
||||||
? classNames('border-l', getBorderColor(cell.row.original as AccountBalanceRow))
|
|
||||||
: ''
|
|
||||||
return (
|
return (
|
||||||
<td
|
<td
|
||||||
key={cell.id}
|
key={cell.id}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
isSymbolOrName ? 'text-left' : 'text-right',
|
isSymbolOrName ? 'text-left' : 'text-right',
|
||||||
props.spacingClassName ?? 'px-3 py-4',
|
spacingClassName ?? 'px-3 py-4',
|
||||||
borderClasses,
|
type && isSymbolOrName && 'border-l',
|
||||||
|
type && getBorderColor(type, cell.row.original as any),
|
||||||
cell.column.columnDef.meta?.className,
|
cell.column.columnDef.meta?.className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@ -60,9 +65,7 @@ export default function Row<T>(props: Props<T>) {
|
|||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</tr>
|
</tr>
|
||||||
{props.row.getIsExpanded() &&
|
{row.getIsExpanded() && renderExpanded && renderExpanded(row, table)}
|
||||||
props.renderExpanded &&
|
|
||||||
props.renderExpanded(props.row, props.table)}
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ interface Props<T> {
|
|||||||
renderExpanded?: (row: TanstackRow<T>, table: TanstackTable<T>) => JSX.Element
|
renderExpanded?: (row: TanstackRow<T>, table: TanstackTable<T>) => JSX.Element
|
||||||
tableBodyClassName?: string
|
tableBodyClassName?: string
|
||||||
spacingClassName?: string
|
spacingClassName?: string
|
||||||
isBalancesTable?: boolean
|
type?: TableType
|
||||||
hideCard?: boolean
|
hideCard?: boolean
|
||||||
setRowSelection?: OnChangeFn<RowSelectionState>
|
setRowSelection?: OnChangeFn<RowSelectionState>
|
||||||
selectedRows?: RowSelectionState
|
selectedRows?: RowSelectionState
|
||||||
@ -55,7 +55,7 @@ export default function Table<T>(props: Props<T>) {
|
|||||||
condition={!props.hideCard}
|
condition={!props.hideCard}
|
||||||
wrapper={(children) => (
|
wrapper={(children) => (
|
||||||
<Card
|
<Card
|
||||||
className={classNames('w-full', !props.isBalancesTable && 'h-fit bg-white/5')}
|
className={classNames('w-full', props.type !== 'balances' && 'h-fit bg-white/5')}
|
||||||
title={props.title}
|
title={props.title}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
@ -118,8 +118,8 @@ export default function Table<T>(props: Props<T>) {
|
|||||||
table={table}
|
table={table}
|
||||||
renderExpanded={props.renderExpanded}
|
renderExpanded={props.renderExpanded}
|
||||||
spacingClassName={props.spacingClassName}
|
spacingClassName={props.spacingClassName}
|
||||||
isBalancesTable={props.isBalancesTable}
|
|
||||||
isSelectable={!!props.setRowSelection}
|
isSelectable={!!props.setRowSelection}
|
||||||
|
type={props.type}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -20,13 +20,10 @@ export const depositedSortingFn = (
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
asset: Asset
|
asset: Asset
|
||||||
lentAmount?: string
|
lentAmount?: BigNumber
|
||||||
}
|
}
|
||||||
export default function DepositValue(props: Props) {
|
export default function DepositValue(props: Props) {
|
||||||
return (
|
return (
|
||||||
<AmountAndValue
|
<AmountAndValue asset={props.asset} amount={props.lentAmount ? props.lentAmount : BN_ZERO} />
|
||||||
asset={props.asset}
|
|
||||||
amount={props.lentAmount ? BN(props.lentAmount) : BN_ZERO}
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import React, { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { useSearchParams } from 'react-router-dom'
|
import { useSearchParams } from 'react-router-dom'
|
||||||
|
|
||||||
import DropDownButton from 'components/common/Button/DropDownButton'
|
import DropDownButton from 'components/common/Button/DropDownButton'
|
||||||
import { Cross, Edit } from 'components/common/Icons'
|
import { Cross, Edit } from 'components/common/Icons'
|
||||||
import { PerpPositionRow } from 'components/perps/BalancesTable/usePerpsBalancesData'
|
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
import useStore from 'store'
|
import useStore from 'store'
|
||||||
import { SearchParams } from 'types/enums/searchParams'
|
import { SearchParams } from 'types/enums/searchParams'
|
||||||
|
@ -22,7 +22,7 @@ export default function PnL(props: Props) {
|
|||||||
type='info'
|
type='info'
|
||||||
underline
|
underline
|
||||||
>
|
>
|
||||||
<DisplayCurrency className='inline text-xs' coin={props.pnl} isProfitOrLoss />
|
<DisplayCurrency className='inline text-xs' coin={props.pnl} isProfitOrLoss showZero />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -34,13 +34,18 @@ type PnLTooltipProps = {
|
|||||||
|
|
||||||
function PnLTooltip(props: PnLTooltipProps) {
|
function PnLTooltip(props: PnLTooltipProps) {
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-2 w-full'>
|
<div className='flex flex-col w-full gap-2'>
|
||||||
{[props.realized, props.unrealized].map((coin, i) => (
|
{[props.realized, props.unrealized].map((coin, i) => (
|
||||||
<div key={i} className='flex w-full text-white/60 space-between items-center gap-8'>
|
<div key={i} className='flex items-center w-full gap-8 space-between'>
|
||||||
<Text className='mr-auto' size='sm'>
|
<Text className='mr-auto text-white/60' size='sm'>
|
||||||
{i === 0 ? 'Realized' : 'Unrealized'} PnL
|
{i === 0 ? 'Realized' : 'Unrealized'} PnL
|
||||||
</Text>
|
</Text>
|
||||||
<DisplayCurrency coin={coin} className='self-end text-end' isProfitOrLoss />
|
<DisplayCurrency
|
||||||
|
coin={coin}
|
||||||
|
className='self-end text-sm text-end'
|
||||||
|
isProfitOrLoss
|
||||||
|
showZero
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,7 +19,7 @@ export const SIZE_META = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
size: BigNumber
|
amount: BigNumber
|
||||||
asset: Asset
|
asset: Asset
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,8 +27,8 @@ export default function Size(props: Props) {
|
|||||||
const price = usePrice(props.asset.denom)
|
const price = usePrice(props.asset.denom)
|
||||||
|
|
||||||
const amount = useMemo(
|
const amount = useMemo(
|
||||||
() => demagnify(props.size.toString(), props.asset),
|
() => demagnify(props.amount.toString(), props.asset),
|
||||||
[props.asset, props.size],
|
[props.asset, props.amount],
|
||||||
)
|
)
|
||||||
const value = useMemo(() => price.times(amount).toNumber(), [amount, price])
|
const value = useMemo(() => price.times(amount).toNumber(), [amount, price])
|
||||||
return (
|
return (
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import Text from 'components/common/Text'
|
|
||||||
|
|
||||||
export const PERP_TYPE_META = { accessorKey: 'tradeDirection', header: 'Side' }
|
export const PERP_TYPE_META = { accessorKey: 'tradeDirection', header: 'Side' }
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
tradeDirection: TradeDirection
|
tradeDirection: TradeDirection
|
||||||
|
className?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function TradeDirection(props: Props) {
|
export default function TradeDirection(props: Props) {
|
||||||
const { tradeDirection } = props
|
const { tradeDirection, className } = props
|
||||||
return (
|
return (
|
||||||
<Text
|
<span
|
||||||
size='xs'
|
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'capitalize px-1 py-0.5 rounded-sm inline-block',
|
'capitalize px-1 py-0.5 rounded-sm inline-block text-xs',
|
||||||
tradeDirection === 'short' && 'text-error bg-error/20',
|
tradeDirection === 'short' && 'text-error bg-error/20',
|
||||||
tradeDirection === 'long' && 'text-success bg-success/20',
|
tradeDirection === 'long' && 'text-success bg-success/20',
|
||||||
|
className,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{tradeDirection}
|
{tradeDirection}
|
||||||
</Text>
|
</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ import Size, { SIZE_META } from 'components/perps/BalancesTable/Columns/Size'
|
|||||||
import TradeDirection, {
|
import TradeDirection, {
|
||||||
PERP_TYPE_META,
|
PERP_TYPE_META,
|
||||||
} from 'components/perps/BalancesTable/Columns/TradeDirection'
|
} from 'components/perps/BalancesTable/Columns/TradeDirection'
|
||||||
import { PerpPositionRow } from 'components/perps/BalancesTable/usePerpsBalancesData'
|
|
||||||
|
|
||||||
export default function usePerpsBalancesTable() {
|
export default function usePerpsBalancesTable() {
|
||||||
return useMemo<ColumnDef<PerpPositionRow>[]>(() => {
|
return useMemo<ColumnDef<PerpPositionRow>[]>(() => {
|
||||||
@ -25,7 +24,7 @@ export default function usePerpsBalancesTable() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
...SIZE_META,
|
...SIZE_META,
|
||||||
cell: ({ row }) => <Size size={row.original.size} asset={row.original.asset} />,
|
cell: ({ row }) => <Size amount={row.original.amount} asset={row.original.asset} />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...LEVERAGE_META,
|
...LEVERAGE_META,
|
||||||
|
@ -5,7 +5,6 @@ import useAllAssets from 'hooks/assets/useAllAssets'
|
|||||||
import usePerpsEnabledAssets from 'hooks/assets/usePerpsEnabledAssets'
|
import usePerpsEnabledAssets from 'hooks/assets/usePerpsEnabledAssets'
|
||||||
import useCurrentAccount from 'hooks/useCurrentAccount'
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
import usePrices from 'hooks/usePrices'
|
import usePrices from 'hooks/usePrices'
|
||||||
import { BNCoin } from 'types/classes/BNCoin'
|
|
||||||
import { getAccountNetValue } from 'utils/accounts'
|
import { getAccountNetValue } from 'utils/accounts'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
import { demagnify } from 'utils/formatters'
|
import { demagnify } from 'utils/formatters'
|
||||||
@ -24,25 +23,16 @@ export default function usePerpsBalancesTable() {
|
|||||||
return currentAccount.perps.map((position) => {
|
return currentAccount.perps.map((position) => {
|
||||||
const price = prices.find(byDenom(position.denom))?.amount ?? BN_ZERO
|
const price = prices.find(byDenom(position.denom))?.amount ?? BN_ZERO
|
||||||
const asset = perpAssets.find(byDenom(position.denom))!
|
const asset = perpAssets.find(byDenom(position.denom))!
|
||||||
|
|
||||||
return {
|
return {
|
||||||
asset,
|
asset,
|
||||||
tradeDirection: position.tradeDirection,
|
tradeDirection: position.tradeDirection,
|
||||||
size: position.size,
|
amount: position.amount,
|
||||||
pnl: position.pnl,
|
pnl: position.pnl,
|
||||||
entryPrice: position.entryPrice,
|
entryPrice: position.entryPrice,
|
||||||
liquidationPrice: position.entryPrice, // TODO: 📈 Get actual liquidation price from HC
|
liquidationPrice: position.entryPrice, // TODO: 📈 Get actual liquidation price from HC
|
||||||
leverage: price.times(demagnify(position.size, asset)).div(netValue).plus(1).toNumber(),
|
leverage: price.times(demagnify(position.amount, asset)).div(netValue).plus(1).toNumber(),
|
||||||
} as PerpPositionRow
|
} as PerpPositionRow
|
||||||
})
|
})
|
||||||
}, [allAssets, currentAccount, perpAssets, prices])
|
}, [allAssets, currentAccount, perpAssets, prices])
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PerpPositionRow = {
|
|
||||||
asset: Asset
|
|
||||||
tradeDirection: TradeDirection
|
|
||||||
size: BigNumber
|
|
||||||
pnl: BNCoin
|
|
||||||
entryPrice: BigNumber
|
|
||||||
liquidationPrice: BigNumber
|
|
||||||
leverage: number
|
|
||||||
}
|
|
||||||
|
@ -35,7 +35,7 @@ export default function usePerpsManageModule(amount: BigNumber | null) {
|
|||||||
})
|
})
|
||||||
}, [searchParams, setSearchParams])
|
}, [searchParams, setSearchParams])
|
||||||
|
|
||||||
const previousAmount = useMemo(() => perpPosition?.size ?? BN_ZERO, [perpPosition?.size])
|
const previousAmount = useMemo(() => perpPosition?.amount ?? BN_ZERO, [perpPosition?.amount])
|
||||||
const previousTradeDirection = useMemo(
|
const previousTradeDirection = useMemo(
|
||||||
() => perpPosition?.tradeDirection || 'long',
|
() => perpPosition?.tradeDirection || 'long',
|
||||||
[perpPosition?.tradeDirection],
|
[perpPosition?.tradeDirection],
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import PerpsBalancesTable from './BalancesTable'
|
import PerpsBalancesTable from 'components/perps/BalancesTable'
|
||||||
|
|
||||||
export function PerpsPositions() {
|
export function PerpsPositions() {
|
||||||
return <PerpsBalancesTable />
|
return <PerpsBalancesTable />
|
||||||
|
50
src/components/portfolio/Account/PerpPositions.tsx
Normal file
50
src/components/portfolio/Account/PerpPositions.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import React, { Suspense } from 'react'
|
||||||
|
|
||||||
|
import AccountPerpPositionTable from 'components/account/AccountPerpPositionTable'
|
||||||
|
import Card from 'components/common/Card'
|
||||||
|
import TableSkeleton from 'components/common/Table/TableSkeleton'
|
||||||
|
import Text from 'components/common/Text'
|
||||||
|
import useAccount from 'hooks/accounts/useAccount'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
accountId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function Content(props: Props) {
|
||||||
|
const { data: account } = useAccount(props.accountId, true)
|
||||||
|
|
||||||
|
if (!account || account.perps.length === 0) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Skeleton>
|
||||||
|
<AccountPerpPositionTable account={account} showLiquidationPrice hideCard />
|
||||||
|
</Skeleton>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function PerpPositions(props: Props) {
|
||||||
|
return (
|
||||||
|
<Suspense fallback={<Skeleton />}>
|
||||||
|
<Content {...props} />
|
||||||
|
</Suspense>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SkeletonProps {
|
||||||
|
children?: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
function Skeleton(props: SkeletonProps) {
|
||||||
|
return (
|
||||||
|
<div className='flex flex-wrap w-full gap-4'>
|
||||||
|
<Text size='2xl'>Perp Positions</Text>
|
||||||
|
<Card className='w-full bg-white/5'>
|
||||||
|
{props.children ? (
|
||||||
|
props.children
|
||||||
|
) : (
|
||||||
|
<TableSkeleton labels={['Asset', 'Value', 'Liq. Price', 'Total PnL']} rowCount={3} />
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -6,12 +6,11 @@ import Overlay from 'components/common/Overlay'
|
|||||||
import SearchBar from 'components/common/SearchBar'
|
import SearchBar from 'components/common/SearchBar'
|
||||||
import Text from 'components/common/Text'
|
import Text from 'components/common/Text'
|
||||||
import AssetList from 'components/trade/TradeModule/AssetSelector/AssetList'
|
import AssetList from 'components/trade/TradeModule/AssetSelector/AssetList'
|
||||||
|
import StablesFilter from 'components/trade/TradeModule/AssetSelector/AssetOverlay/StablesFilter'
|
||||||
import PairsList from 'components/trade/TradeModule/AssetSelector/PairsList'
|
import PairsList from 'components/trade/TradeModule/AssetSelector/PairsList'
|
||||||
import useAllAssets from 'hooks/assets/useAllAssets'
|
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||||
import useFilteredAssets from 'hooks/useFilteredAssets'
|
import useFilteredAssets from 'hooks/useFilteredAssets'
|
||||||
|
|
||||||
import StablesFilter from './StablesFilter'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
state: OverlayState
|
state: OverlayState
|
||||||
buyAsset: Asset
|
buyAsset: Asset
|
||||||
|
@ -8,7 +8,7 @@ const enabledMarketAssets = useStore
|
|||||||
.chainConfig.assets.filter((asset) => asset.isEnabled && asset.isMarket)
|
.chainConfig.assets.filter((asset) => asset.isEnabled && asset.isMarket)
|
||||||
|
|
||||||
export const DEFAULT_SETTINGS: Settings = {
|
export const DEFAULT_SETTINGS: Settings = {
|
||||||
accountSummaryTabs: [true, true],
|
accountSummaryTabs: [true, true, false],
|
||||||
reduceMotion: false,
|
reduceMotion: false,
|
||||||
enableAutoLendGlobal: true,
|
enableAutoLendGlobal: true,
|
||||||
tradingPairSimple: {
|
tradingPairSimple: {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
|
import useCurrentAccount from 'hooks/useCurrentAccount'
|
||||||
import { byDenom } from 'utils/array'
|
import { byDenom } from 'utils/array'
|
||||||
|
|
||||||
import useCurrentAccount from '../useCurrentAccount'
|
|
||||||
|
|
||||||
export default function usePerpPosition(denom: string): PerpsPosition | undefined {
|
export default function usePerpPosition(denom: string): PerpsPosition | undefined {
|
||||||
const account = useCurrentAccount()
|
const account = useCurrentAccount()
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
|
import { BN_ZERO } from 'constants/math'
|
||||||
import useAllAssets from 'hooks/assets/useAllAssets'
|
import useAllAssets from 'hooks/assets/useAllAssets'
|
||||||
import useMarketDeposits from 'hooks/markets/useMarketDeposits'
|
import useMarketDeposits from 'hooks/markets/useMarketDeposits'
|
||||||
import useMarketLiquidities from 'hooks/markets/useMarketLiquidities'
|
import useMarketLiquidities from 'hooks/markets/useMarketLiquidities'
|
||||||
@ -29,7 +30,7 @@ function useLendingMarketAssetsTableData(): {
|
|||||||
const asset = assets.find(byDenom(denom)) as Asset
|
const asset = assets.find(byDenom(denom)) as Asset
|
||||||
const marketDepositAmount = BN(marketDeposits.find(byDenom(denom))?.amount ?? 0)
|
const marketDepositAmount = BN(marketDeposits.find(byDenom(denom))?.amount ?? 0)
|
||||||
const marketLiquidityAmount = BN(marketLiquidities.find(byDenom(denom))?.amount ?? 0)
|
const marketLiquidityAmount = BN(marketLiquidities.find(byDenom(denom))?.amount ?? 0)
|
||||||
const accountLentAmount = accountLentAmounts.find(byDenom(denom))?.amount
|
const accountLentAmount = accountLentAmounts.find(byDenom(denom))?.amount ?? BN_ZERO
|
||||||
const accountLentValue = accountLentAmount
|
const accountLentValue = accountLentAmount
|
||||||
? convertAmount(asset, accountLentAmount)
|
? convertAmount(asset, accountLentAmount)
|
||||||
: undefined
|
: undefined
|
||||||
@ -46,9 +47,11 @@ function useLendingMarketAssetsTableData(): {
|
|||||||
cap,
|
cap,
|
||||||
}
|
}
|
||||||
|
|
||||||
;(lendingMarketAsset.accountLentValue ? accountLentAssets : availableAssets).push(
|
if (lendingMarketAsset.accountLentAmount?.isZero()) {
|
||||||
lendingMarketAsset,
|
availableAssets.push(lendingMarketAsset)
|
||||||
)
|
} else {
|
||||||
|
accountLentAssets.push(lendingMarketAsset)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
|
import { useNavigate, useParams, useSearchParams } from 'react-router-dom'
|
||||||
|
|
||||||
import MigrationBanner from 'components/common/MigrationBanner'
|
import MigrationBanner from 'components/common/MigrationBanner'
|
||||||
|
import ShareBar from 'components/common/ShareBar'
|
||||||
import Balances from 'components/portfolio/Account/Balances'
|
import Balances from 'components/portfolio/Account/Balances'
|
||||||
import BreadCrumbs from 'components/portfolio/Account/BreadCrumbs'
|
import BreadCrumbs from 'components/portfolio/Account/BreadCrumbs'
|
||||||
|
import PerpPositions from 'components/portfolio/Account/PerpPositions'
|
||||||
import Summary from 'components/portfolio/Account/Summary'
|
import Summary from 'components/portfolio/Account/Summary'
|
||||||
import ShareBar from 'components/common/ShareBar'
|
|
||||||
import useAccountId from 'hooks/useAccountId'
|
import useAccountId from 'hooks/useAccountId'
|
||||||
|
import useStore from 'store'
|
||||||
import { getRoute } from 'utils/route'
|
import { getRoute } from 'utils/route'
|
||||||
|
|
||||||
export default function PortfolioAccountPage() {
|
export default function PortfolioAccountPage() {
|
||||||
|
const chainConfig = useStore((s) => s.chainConfig)
|
||||||
const selectedAccountId = useAccountId()
|
const selectedAccountId = useAccountId()
|
||||||
const { address, accountId } = useParams()
|
const { address, accountId } = useParams()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
@ -25,6 +28,7 @@ export default function PortfolioAccountPage() {
|
|||||||
<BreadCrumbs accountId={accountId} />
|
<BreadCrumbs accountId={accountId} />
|
||||||
<Summary accountId={accountId} />
|
<Summary accountId={accountId} />
|
||||||
<Balances accountId={accountId} />
|
<Balances accountId={accountId} />
|
||||||
|
{chainConfig.perps && <PerpPositions accountId={accountId} />}
|
||||||
<ShareBar text={`Have a look at Credit Account ${accountId} on @mars_protocol!`} />
|
<ShareBar text={`Have a look at Credit Account ${accountId} on @mars_protocol!`} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
4
src/types/generated.d.ts
vendored
4
src/types/generated.d.ts
vendored
@ -1 +1,3 @@
|
|||||||
export { ActionCoin } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
type ActionCoin = import('types/generated/mars-credit-manager/MarsCreditManager.types').ActionCoin
|
||||||
|
|
||||||
|
type BNCoin = import('types/classes/BNCoin').BNCoin
|
||||||
|
@ -264,7 +264,7 @@ export interface UserDebtResponse {
|
|||||||
}
|
}
|
||||||
export type ArrayOfUserDebtResponse = UserDebtResponse[]
|
export type ArrayOfUserDebtResponse = UserDebtResponse[]
|
||||||
export type UserHealthStatus =
|
export type UserHealthStatus =
|
||||||
| 'not_borrowing'
|
| 'not_borrow'
|
||||||
| {
|
| {
|
||||||
borrowing: {
|
borrowing: {
|
||||||
liq_threshold_hf: Decimal
|
liq_threshold_hf: Decimal
|
||||||
|
16
src/types/interfaces/account.d.ts
vendored
16
src/types/interfaces/account.d.ts
vendored
@ -1,4 +1,7 @@
|
|||||||
interface Account extends AccountChange {
|
type PositionType = 'deposit' | 'borrow' | 'lend' | 'vault' | 'perp'
|
||||||
|
type TableType = 'balances' | 'perps'
|
||||||
|
|
||||||
|
interface Account {
|
||||||
id: string
|
id: string
|
||||||
deposits: BNCoin[]
|
deposits: BNCoin[]
|
||||||
debts: BNCoin[]
|
debts: BNCoin[]
|
||||||
@ -8,7 +11,7 @@ interface Account extends AccountChange {
|
|||||||
kind: AccountKind
|
kind: AccountKind
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AccountChange {
|
interface AccountChange extends Account {
|
||||||
deposits?: BNCoin[]
|
deposits?: BNCoin[]
|
||||||
debts?: BNCoin[]
|
debts?: BNCoin[]
|
||||||
lends?: BNCoin[]
|
lends?: BNCoin[]
|
||||||
@ -21,7 +24,14 @@ interface AccountBalanceRow {
|
|||||||
denom: string
|
denom: string
|
||||||
size: number
|
size: number
|
||||||
symbol: string
|
symbol: string
|
||||||
type: 'deposits' | 'borrowing' | 'lending' | 'vault'
|
type: PositionType
|
||||||
|
value: string
|
||||||
|
amountChange: BigNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AccountPerpRow extends PerpsPosition {
|
||||||
|
amount: BigNumber
|
||||||
|
symbol: string
|
||||||
value: string
|
value: string
|
||||||
amountChange: BigNumber
|
amountChange: BigNumber
|
||||||
}
|
}
|
||||||
|
2
src/types/interfaces/asset.d.ts
vendored
2
src/types/interfaces/asset.d.ts
vendored
@ -59,7 +59,7 @@ interface BorrowMarketTableData extends MarketTableData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface LendingMarketTableData extends MarketTableData {
|
interface LendingMarketTableData extends MarketTableData {
|
||||||
accountLentAmount?: string
|
accountLentAmount?: BigNumber
|
||||||
accountLentValue?: BigNumber
|
accountLentValue?: BigNumber
|
||||||
borrowEnabled: boolean
|
borrowEnabled: boolean
|
||||||
cap: DepositCap
|
cap: DepositCap
|
||||||
|
15
src/types/interfaces/perps.d.ts
vendored
15
src/types/interfaces/perps.d.ts
vendored
@ -1,5 +1,3 @@
|
|||||||
const BNCoin = import('types/classes/BNCoin').BNCoin
|
|
||||||
|
|
||||||
type TradeDirection = 'long' | 'short'
|
type TradeDirection = 'long' | 'short'
|
||||||
|
|
||||||
// TODO: 📈Remove this type when healthcomputer is implemented
|
// TODO: 📈Remove this type when healthcomputer is implemented
|
||||||
@ -8,9 +6,18 @@ type PositionsWithoutPerps = Omit<
|
|||||||
'perps'
|
'perps'
|
||||||
>
|
>
|
||||||
|
|
||||||
type PerpsPosition = {
|
interface PerpsPosition {
|
||||||
denom: string
|
denom: string
|
||||||
baseDenom: string
|
baseDenom: string
|
||||||
tradeDirection: TradeDirection
|
tradeDirection: TradeDirection
|
||||||
size: BigNumber
|
amount: BigNumber
|
||||||
|
closingFee: BNCoin
|
||||||
|
pnl: BNCoin
|
||||||
|
entryPrice: BigNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PerpPositionRow extends PerpsPosition {
|
||||||
|
asset: Asset
|
||||||
|
liquidationPrice: BigNumber
|
||||||
|
leverage: number
|
||||||
}
|
}
|
||||||
|
3
src/types/interfaces/store/broadcast.d.ts
vendored
3
src/types/interfaces/store/broadcast.d.ts
vendored
@ -1,6 +1,3 @@
|
|||||||
const BNCoin = import('types/classes/BNCoin').BNCoin
|
|
||||||
const ActionCoin = import('types/generated').ActionCoin
|
|
||||||
|
|
||||||
interface BroadcastResult {
|
interface BroadcastResult {
|
||||||
result?: import('@delphi-labs/shuttle-react').BroadcastResult
|
result?: import('@delphi-labs/shuttle-react').BroadcastResult
|
||||||
error?: string
|
error?: string
|
||||||
|
@ -53,14 +53,16 @@ export const calculateAccountValue = (
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return account[type]?.reduce((acc, position) => {
|
return (
|
||||||
|
account[type]?.reduce((acc, position) => {
|
||||||
const asset = assets.find(byDenom(position.denom))
|
const asset = assets.find(byDenom(position.denom))
|
||||||
if (!asset) return acc
|
if (!asset) return acc
|
||||||
const price = prices.find((price) => price.denom === position.denom)?.amount ?? 0
|
const price = prices.find((price) => price.denom === position.denom)?.amount ?? 0
|
||||||
const amount = BN(position.amount).shiftedBy(-asset.decimals)
|
const amount = BN(position.amount).shiftedBy(-asset.decimals)
|
||||||
const positionValue = amount.multipliedBy(price)
|
const positionValue = amount.multipliedBy(price)
|
||||||
return acc.plus(positionValue)
|
return acc.plus(positionValue)
|
||||||
}, BN_ZERO)
|
}, BN_ZERO) ?? BN_ZERO
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const calculateAccountApr = (
|
export const calculateAccountApr = (
|
||||||
|
@ -83,7 +83,7 @@ export function resolvePerpsPositions(perpPositions: Positions['perps']): PerpsP
|
|||||||
return {
|
return {
|
||||||
denom: position.denom,
|
denom: position.denom,
|
||||||
baseDenom: position.base_denom,
|
baseDenom: position.base_denom,
|
||||||
size: BN(position.size as any).abs(),
|
amount: BN(position.size as any).abs(),
|
||||||
tradeDirection: BN(position.size as any).isNegative() ? 'short' : 'long',
|
tradeDirection: BN(position.size as any).isNegative() ? 'short' : 'long',
|
||||||
closingFee: BNCoin.fromCoin(position.pnl.coins.closing_fee),
|
closingFee: BNCoin.fromCoin(position.pnl.coins.closing_fee),
|
||||||
pnl: getPnlCoin(position.pnl.coins.pnl, position.base_denom),
|
pnl: getPnlCoin(position.pnl.coins.pnl, position.base_denom),
|
||||||
|
Loading…
Reference in New Issue
Block a user