From 0ccb29154ac85029f0f626c9a695920a6dc8307a Mon Sep 17 00:00:00 2001 From: Linkie Link Date: Tue, 23 Jan 2024 15:14:48 +0100 Subject: [PATCH] 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 --- src/api/hls/getHLSStakingAccounts.ts | 2 +- src/api/perps/getOpeningFee.ts | 8 ++- .../Modals/AssetAmountSelectActionModal.tsx | 7 +- src/components/Modals/HLS/Manage/Repay.tsx | 2 +- src/components/Modals/HLS/Manage/Withdraw.tsx | 3 +- .../Modals/LendAndReclaim/DetailsHeader.tsx | 4 +- .../AccountBalancesTable/Columns/Apy.tsx | 4 +- .../AccountBalancesTable/Columns/Asset.tsx | 9 +-- .../AccountBalancesTable/Columns/LiqPrice.tsx | 4 +- .../AccountBalancesTable/Columns/Price.tsx | 2 +- .../AccountBalancesTable/Columns/Size.tsx | 2 +- .../AccountBalancesTable/Columns/Value.tsx | 19 +++-- .../Columns/useAccountBalancesColumns.tsx | 4 +- .../account/AccountBalancesTable/functions.ts | 10 ++- .../account/AccountBalancesTable/index.tsx | 2 +- .../useAccountBalanceData.tsx | 6 +- .../account/AccountDetails/index.tsx | 14 +++- .../Columns/Asset.tsx | 71 +++++++++++++++++++ .../Columns/TotalPnL.tsx | 22 ++++++ .../Columns/useAccountPerpsColumns.tsx | 52 ++++++++++++++ .../AccountPerpPositionTable/functions.ts | 20 ++++++ .../AccountPerpPositionTable/index.tsx | 37 ++++++++++ .../useAccountPerpData.tsx | 30 ++++++++ src/components/account/AccountSummary.tsx | 13 +++- src/components/common/DisplayCurrency.tsx | 36 ++++++---- src/components/common/Table/Row.tsx | 47 ++++++------ src/components/common/Table/index.tsx | 6 +- .../earn/lend/Table/Columns/DepositValue.tsx | 7 +- .../perps/BalancesTable/Columns/Manage.tsx | 3 +- .../perps/BalancesTable/Columns/PnL.tsx | 15 ++-- .../perps/BalancesTable/Columns/Size.tsx | 6 +- .../BalancesTable/Columns/TradeDirection.tsx | 13 ++-- .../Columns/usePerpsBalancesColumns.tsx | 3 +- .../BalancesTable/usePerpsBalancesData.ts | 16 +---- .../PerpsManageModule/usePerpsManageModule.ts | 2 +- src/components/perps/PerpsPositions.tsx | 2 +- .../portfolio/Account/PerpPositions.tsx | 50 +++++++++++++ .../AssetSelector/AssetOverlay/index.tsx | 3 +- src/constants/defaultSettings.ts | 2 +- src/hooks/perps/usePerpPosition.ts | 3 +- src/hooks/useLendingMarketAssetsTableData.ts | 11 +-- src/pages/PortfolioAccountPage.tsx | 6 +- src/types/generated.d.ts | 4 +- .../mars-red-bank/MarsRedBank.types.ts | 2 +- src/types/interfaces/account.d.ts | 16 ++++- src/types/interfaces/asset.d.ts | 2 +- src/types/interfaces/perps.d.ts | 15 ++-- src/types/interfaces/store/broadcast.d.ts | 3 - src/utils/accounts.ts | 18 ++--- src/utils/resolvers.ts | 2 +- 50 files changed, 488 insertions(+), 152 deletions(-) create mode 100644 src/components/account/AccountPerpPositionTable/Columns/Asset.tsx create mode 100644 src/components/account/AccountPerpPositionTable/Columns/TotalPnL.tsx create mode 100644 src/components/account/AccountPerpPositionTable/Columns/useAccountPerpsColumns.tsx create mode 100644 src/components/account/AccountPerpPositionTable/functions.ts create mode 100644 src/components/account/AccountPerpPositionTable/index.tsx create mode 100644 src/components/account/AccountPerpPositionTable/useAccountPerpData.tsx create mode 100644 src/components/portfolio/Account/PerpPositions.tsx diff --git a/src/api/hls/getHLSStakingAccounts.ts b/src/api/hls/getHLSStakingAccounts.ts index 1da5fb3b..8431253c 100644 --- a/src/api/hls/getHLSStakingAccounts.ts +++ b/src/api/hls/getHLSStakingAccounts.ts @@ -17,7 +17,7 @@ export default async function getHLSStakingAccounts( if (account.deposits.length === 0) return const strategy = hlsStrategies.find( - (strategy) => strategy.denoms.deposit === account.deposits.at(0).denom, + (strategy) => strategy.denoms.deposit === account.deposits[0].denom, ) if (!strategy) return diff --git a/src/api/perps/getOpeningFee.ts b/src/api/perps/getOpeningFee.ts index 26051538..f89d41c6 100644 --- a/src/api/perps/getOpeningFee.ts +++ b/src/api/perps/getOpeningFee.ts @@ -1,10 +1,14 @@ import { getPerpsQueryClient } from 'api/cosmwasm-client' 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) return perpsClient - .openingFee({ denom, size: size as any }) + .openingFee({ denom, size: amount as any }) .then((resp) => BNCoin.fromCoin(resp.fee)) } diff --git a/src/components/Modals/AssetAmountSelectActionModal.tsx b/src/components/Modals/AssetAmountSelectActionModal.tsx index 7792fc7d..a8f1f2c2 100644 --- a/src/components/Modals/AssetAmountSelectActionModal.tsx +++ b/src/components/Modals/AssetAmountSelectActionModal.tsx @@ -1,22 +1,23 @@ import { useCallback, useState } from 'react' +import Modal from 'components/Modals/Modal' import CurrentAccountSummary from 'components/account/CurrentAccountSummary' -import AssetImage from 'components/common/assets/AssetImage' import Button from 'components/common/Button' import Card from 'components/common/Card' import Divider from 'components/common/Divider' import { ArrowRight } from 'components/common/Icons' -import Modal from 'components/Modals/Modal' import Text from 'components/common/Text' import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider' +import AssetImage from 'components/common/assets/AssetImage' import { BN_ZERO } from 'constants/math' +import { BNCoin } from 'types/classes/BNCoin' import { byDenom } from 'utils/array' import { BN } from 'utils/helpers' interface Props { asset: Asset title: string - coinBalances: Coin[] + coinBalances: BNCoin[] actionButtonText: string contentHeader?: JSX.Element onClose: () => void diff --git a/src/components/Modals/HLS/Manage/Repay.tsx b/src/components/Modals/HLS/Manage/Repay.tsx index 292fd33c..3dbf2ebf 100644 --- a/src/components/Modals/HLS/Manage/Repay.tsx +++ b/src/components/Modals/HLS/Manage/Repay.tsx @@ -28,7 +28,7 @@ export default function Repay(props: Props) { const repay = useStore((s) => s.repay) 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], ) diff --git a/src/components/Modals/HLS/Manage/Withdraw.tsx b/src/components/Modals/HLS/Manage/Withdraw.tsx index 3adbe65e..42121ae3 100644 --- a/src/components/Modals/HLS/Manage/Withdraw.tsx +++ b/src/components/Modals/HLS/Manage/Withdraw.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useMemo } from 'react' +import { useCallback, useMemo } from 'react' import Button from 'components/common/Button' import TokenInputWithSlider from 'components/common/TokenInput/TokenInputWithSlider' @@ -42,6 +42,7 @@ export default function Withdraw(props: Props) { const onClick = useCallback(() => { useStore.setState({ hlsManageModal: null }) + if (!removedDeposit) return withdraw({ accountId: props.account.id, coins: [{ coin: removedDeposit }], diff --git a/src/components/Modals/LendAndReclaim/DetailsHeader.tsx b/src/components/Modals/LendAndReclaim/DetailsHeader.tsx index 8a906bb7..c713a65c 100644 --- a/src/components/Modals/LendAndReclaim/DetailsHeader.tsx +++ b/src/components/Modals/LendAndReclaim/DetailsHeader.tsx @@ -15,7 +15,7 @@ function DetailsHeader({ data }: Props) { const balanceInWallet = useCurrentWalletBalance(asset.denom) return ( -
+
{assetApy && ( <> } sub={'Deposited'} diff --git a/src/components/account/AccountBalancesTable/Columns/Apy.tsx b/src/components/account/AccountBalancesTable/Columns/Apy.tsx index d54ee089..68e40cf0 100644 --- a/src/components/account/AccountBalancesTable/Columns/Apy.tsx +++ b/src/components/account/AccountBalancesTable/Columns/Apy.tsx @@ -7,7 +7,7 @@ interface Props { apy: number markets: Market[] denom: string - type: 'deposits' | 'borrowing' | 'lending' | 'vault' + type: PositionType } export default function Apr(props: Props) { @@ -20,7 +20,7 @@ export default function Apr(props: Props) { diff --git a/src/components/account/AccountBalancesTable/Columns/Asset.tsx b/src/components/account/AccountBalancesTable/Columns/Asset.tsx index 486c032d..75314b1c 100644 --- a/src/components/account/AccountBalancesTable/Columns/Asset.tsx +++ b/src/components/account/AccountBalancesTable/Columns/Asset.tsx @@ -3,19 +3,16 @@ export const ASSET_META = { accessorKey: 'symbol', header: 'Asset', id: 'symbol' interface Props { 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) { const { symbol, type } = props return ( {symbol} - {type === 'borrowing' && (debt)} - {type === 'lending' && (lent)} + {type === 'borrow' && (debt)} + {type === 'lend' && (lent)} {type === 'vault' && (farm)} ) diff --git a/src/components/account/AccountBalancesTable/Columns/LiqPrice.tsx b/src/components/account/AccountBalancesTable/Columns/LiqPrice.tsx index 11230cc3..5ab28ef2 100644 --- a/src/components/account/AccountBalancesTable/Columns/LiqPrice.tsx +++ b/src/components/account/AccountBalancesTable/Columns/LiqPrice.tsx @@ -20,7 +20,7 @@ interface Props { amount: number computeLiquidationPrice: (denom: string, kind: LiquidationPriceKind) => number | null denom: string - type: 'deposits' | 'borrowing' | 'lending' | 'vault' + type: PositionType account: Account } @@ -31,7 +31,7 @@ export default function LiqPrice(props: Props) { const liqPrice = useMemo(() => { 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]) const { liquidationPrice } = useLiquidationPrice(liqPrice) diff --git a/src/components/account/AccountBalancesTable/Columns/Price.tsx b/src/components/account/AccountBalancesTable/Columns/Price.tsx index d51ffe1b..63b09bca 100644 --- a/src/components/account/AccountBalancesTable/Columns/Price.tsx +++ b/src/components/account/AccountBalancesTable/Columns/Price.tsx @@ -8,7 +8,7 @@ export const PRICE_META = { id: 'price', header: 'Price', meta: { className: 'w- interface Props { amount: number denom: string - type: 'deposits' | 'borrowing' | 'lending' | 'vault' + type: PositionType } export default function Price(props: Props) { diff --git a/src/components/account/AccountBalancesTable/Columns/Size.tsx b/src/components/account/AccountBalancesTable/Columns/Size.tsx index 87c3a91d..329444bb 100644 --- a/src/components/account/AccountBalancesTable/Columns/Size.tsx +++ b/src/components/account/AccountBalancesTable/Columns/Size.tsx @@ -12,7 +12,7 @@ interface Props { size: number amountChange: BigNumber denom: string - type: 'deposits' | 'borrowing' | 'lending' | 'vault' + type: PositionType } export const sizeSortingFn = (a: Row, b: Row): number => { diff --git a/src/components/account/AccountBalancesTable/Columns/Value.tsx b/src/components/account/AccountBalancesTable/Columns/Value.tsx index 5aef40fd..b1f36d03 100644 --- a/src/components/account/AccountBalancesTable/Columns/Value.tsx +++ b/src/components/account/AccountBalancesTable/Columns/Value.tsx @@ -12,10 +12,19 @@ export const VALUE_META = { accessorKey: 'value', header: 'Value' } interface Props { amountChange: BigNumber value: string - type: 'deposits' | 'borrowing' | 'lending' | 'vault' + type: PositionType } -export const valueSortingFn = (a: Row, b: Row): number => { +export const valueBalancesSortingFn = ( + a: Row, + b: Row, +): number => { + const valueA = BN(a.original.value) + const valueB = BN(b.original.value) + return valueA.minus(valueB).toNumber() +} + +export const valuePerpSortingFn = (a: Row, b: Row): number => { const valueA = BN(a.original.value) const valueB = BN(b.original.value) return valueA.minus(valueB).toNumber() @@ -30,10 +39,6 @@ export default function Value(props: Props) { }) return ( - + ) } diff --git a/src/components/account/AccountBalancesTable/Columns/useAccountBalancesColumns.tsx b/src/components/account/AccountBalancesTable/Columns/useAccountBalancesColumns.tsx index 04abd7fd..5f488a1e 100644 --- a/src/components/account/AccountBalancesTable/Columns/useAccountBalancesColumns.tsx +++ b/src/components/account/AccountBalancesTable/Columns/useAccountBalancesColumns.tsx @@ -11,7 +11,7 @@ import Size, { } from 'components/account/AccountBalancesTable/Columns/Size' import Value, { VALUE_META, - valueSortingFn, + valueBalancesSortingFn, } from 'components/account/AccountBalancesTable/Columns/Value' import useMarketAssets from 'hooks/markets/useMarketAssets' import useHealthComputer from 'hooks/useHealthComputer' @@ -41,7 +41,7 @@ export default function useAccountBalancesColumns( type={row.original.type} /> ), - sortingFn: valueSortingFn, + sortingFn: valueBalancesSortingFn, }, { ...SIZE_META, diff --git a/src/components/account/AccountBalancesTable/functions.ts b/src/components/account/AccountBalancesTable/functions.ts index 6f09b555..b523cb4d 100644 --- a/src/components/account/AccountBalancesTable/functions.ts +++ b/src/components/account/AccountBalancesTable/functions.ts @@ -3,7 +3,7 @@ import { BNCoin } from 'types/classes/BNCoin' import { demagnify, getCoinValue } from 'utils/formatters' export function getAssetAccountBalanceRow( - type: 'deposits' | 'borrowing' | 'lending', + type: 'deposit' | 'borrow' | 'lend', asset: Asset, prices: BNCoin[], assets: Asset[], @@ -57,11 +57,9 @@ export function getVaultAccountBalanceRow( } } -export function getAmountChangeColor( - type: 'deposits' | 'borrowing' | 'lending' | 'vault', - amount: BigNumber, -) { - if (type === 'borrowing') { +export function getAmountChangeColor(type: PositionType, amount: BigNumber) { + if (type === 'perp') return '' + if (type === 'borrow') { if (amount.isGreaterThan(0)) return 'text-loss' if (amount.isLessThan(0)) return 'text-profit' } diff --git a/src/components/account/AccountBalancesTable/index.tsx b/src/components/account/AccountBalancesTable/index.tsx index 5c5b60f2..aeedfa3d 100644 --- a/src/components/account/AccountBalancesTable/index.tsx +++ b/src/components/account/AccountBalancesTable/index.tsx @@ -89,7 +89,7 @@ export default function AccountBalancesTable(props: Props) { initialSorting={[]} spacingClassName='p-2' hideCard={hideCard} - isBalancesTable + type='balances' /> ) } diff --git a/src/components/account/AccountBalancesTable/useAccountBalanceData.tsx b/src/components/account/AccountBalancesTable/useAccountBalanceData.tsx index 8478afd8..73391524 100644 --- a/src/components/account/AccountBalancesTable/useAccountBalanceData.tsx +++ b/src/components/account/AccountBalancesTable/useAccountBalanceData.tsx @@ -38,7 +38,7 @@ export default function useAccountBalanceData(props: Props) { : 0 const prevDeposit = updatedAccount ? account?.deposits.find(byDenom(deposit.denom)) : deposit 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 ? account?.lends.find((position) => position.denom === lending.denom) : lending - return getAssetAccountBalanceRow('lending', asset, prices, assets, lending, apy, prevLending) + return getAssetAccountBalanceRow('lend', asset, prices, assets, lending, apy, prevLending) }) const vaults = accountVaults.map((vault) => { @@ -67,7 +67,7 @@ export default function useAccountBalanceData(props: Props) { const prevDebt = updatedAccount ? account?.debts.find((position) => position.denom === debt.denom) : debt - return getAssetAccountBalanceRow('borrowing', asset, prices, assets, debt, apy, prevDebt) + return getAssetAccountBalanceRow('borrow', asset, prices, assets, debt, apy, prevDebt) }) return [...deposits, ...lends, ...vaults, ...debts] }, [ diff --git a/src/components/account/AccountDetails/index.tsx b/src/components/account/AccountDetails/index.tsx index a1c5a49c..5192d760 100644 --- a/src/components/account/AccountDetails/index.tsx +++ b/src/components/account/AccountDetails/index.tsx @@ -6,6 +6,7 @@ import AccountBalancesTable from 'components/account/AccountBalancesTable' import AccountComposition from 'components/account/AccountComposition' import AccountDetailsLeverage from 'components/account/AccountDetails/AccountDetailsLeverage' import Skeleton from 'components/account/AccountDetails/Skeleton' +import AccountPerpPositionTable from 'components/account/AccountPerpPositionTable' import { HealthGauge } from 'components/account/Health/HealthGauge' import EscButton from 'components/common/Button/EscButton' import { glowElement } from 'components/common/Button/utils' @@ -24,8 +25,8 @@ import useLocalStorage from 'hooks/localStorage/useLocalStorage' import useAccountId from 'hooks/useAccountId' import useBorrowMarketAssetsTableData from 'hooks/useBorrowMarketAssetsTableData' import useCurrentAccount from 'hooks/useCurrentAccount' -import useHealthComputer from 'hooks/useHealthComputer' import useHLSStakingAssets from 'hooks/useHLSStakingAssets' +import useHealthComputer from 'hooks/useHealthComputer' import useLendingMarketAssetsTableData from 'hooks/useLendingMarketAssetsTableData' import usePrices from 'hooks/usePrices' import useStore from 'store' @@ -114,7 +115,10 @@ function AccountDetails(props: Props) { ), [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() { const onClose = useCallback(() => useStore.setState({ accountDetailsExpanded: false }), []) @@ -215,6 +219,12 @@ function AccountDetails(props: Props) { lendingData={lendingAssetsData} hideCard /> + {account.perps.length > 0 && ( + <> + Perp Positions + + + )}
diff --git a/src/components/account/AccountPerpPositionTable/Columns/Asset.tsx b/src/components/account/AccountPerpPositionTable/Columns/Asset.tsx new file mode 100644 index 00000000..4294f544 --- /dev/null +++ b/src/components/account/AccountPerpPositionTable/Columns/Asset.tsx @@ -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 ( +
+ + {label} + + {children} +
+ ) +} + +function TooltipContent(props: Props) { + const { row } = props + const assets = usePerpsEnabledAssets() + const asset = assets.find((asset) => asset.symbol === row.symbol) + if (!asset) return null + + return ( +
+ + + + + {demagnify(row.amount, asset)} + + + + + + + +
+ ) +} + +export default function Asset(props: Props) { + const { row } = props + return ( + } type='info'> + + + {row.symbol} + + + + + ) +} diff --git a/src/components/account/AccountPerpPositionTable/Columns/TotalPnL.tsx b/src/components/account/AccountPerpPositionTable/Columns/TotalPnL.tsx new file mode 100644 index 00000000..10632fd9 --- /dev/null +++ b/src/components/account/AccountPerpPositionTable/Columns/TotalPnL.tsx @@ -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 ( + + ) +} diff --git a/src/components/account/AccountPerpPositionTable/Columns/useAccountPerpsColumns.tsx b/src/components/account/AccountPerpPositionTable/Columns/useAccountPerpsColumns.tsx new file mode 100644 index 00000000..ad409f4f --- /dev/null +++ b/src/components/account/AccountPerpPositionTable/Columns/useAccountPerpsColumns.tsx @@ -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[]>(() => { + return [ + { + ...ASSET_META, + cell: ({ row }) => , + }, + { + ...VALUE_META, + cell: ({ row }) => ( + + ), + sortingFn: valuePerpSortingFn, + }, + { + ...LIQ_META, + header: 'Liq. Price', + enableSorting: false, + cell: ({ row }) => ( + + ), + }, + { + ...PNL_META, + cell: ({ row }) => , + }, + ] + }, [computeLiquidationPrice, account, updatedAccount]) +} diff --git a/src/components/account/AccountPerpPositionTable/functions.ts b/src/components/account/AccountPerpPositionTable/functions.ts new file mode 100644 index 00000000..bd34577c --- /dev/null +++ b/src/components/account/AccountPerpPositionTable/functions.ts @@ -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, + } +} diff --git a/src/components/account/AccountPerpPositionTable/index.tsx b/src/components/account/AccountPerpPositionTable/index.tsx new file mode 100644 index 00000000..6cbffd34 --- /dev/null +++ b/src/components/account/AccountPerpPositionTable/index.tsx @@ -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 ( + + ) +} diff --git a/src/components/account/AccountPerpPositionTable/useAccountPerpData.tsx b/src/components/account/AccountPerpPositionTable/useAccountPerpData.tsx new file mode 100644 index 00000000..5ace49e5 --- /dev/null +++ b/src/components/account/AccountPerpPositionTable/useAccountPerpData.tsx @@ -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(() => { + 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]) +} diff --git a/src/components/account/AccountSummary.tsx b/src/components/account/AccountSummary.tsx index a7f011fc..9bdb5cdf 100644 --- a/src/components/account/AccountSummary.tsx +++ b/src/components/account/AccountSummary.tsx @@ -1,10 +1,11 @@ import classNames from 'classnames' import { HTMLAttributes, useCallback, useMemo } from 'react' -import Accordion from 'components/common/Accordion' import AccountBalancesTable from 'components/account/AccountBalancesTable' import AccountComposition from 'components/account/AccountComposition' +import AccountPerpPositionTable from 'components/account/AccountPerpPositionTable' import HealthBar from 'components/account/Health/HealthBar' +import Accordion from 'components/common/Accordion' import Card from 'components/common/Card' import DisplayCurrency from 'components/common/DisplayCurrency' import { FormattedNumber } from 'components/common/FormattedNumber' @@ -150,6 +151,16 @@ export default function AccountSummary(props: Props) { toggleOpen: (index: number) => handleToggle(index), renderSubTitle: () => <>, }, + { + title: 'Perp Positions', + renderContent: () => + props.account && props.account.perps.length > 0 ? ( + + ) : null, + isOpen: accountSummaryTabs[2] ?? false, + toggleOpen: (index: number) => handleToggle(index), + renderSubTitle: () => <>, + }, ]} allowMultipleOpen /> diff --git a/src/components/common/DisplayCurrency.tsx b/src/components/common/DisplayCurrency.tsx index 3deb0b16..d2b43796 100644 --- a/src/components/common/DisplayCurrency.tsx +++ b/src/components/common/DisplayCurrency.tsx @@ -22,6 +22,7 @@ interface Props { } export default function DisplayCurrency(props: Props) { + const { coin, className, isApproximation, parentheses, showZero, options, isProfitOrLoss } = props const displayCurrencies = useDisplayCurrencyAssets() const assets = useAllAssets() const [displayCurrency] = useDisplayCurrency() @@ -36,7 +37,7 @@ export default function DisplayCurrency(props: Props) { const isUSD = displayCurrencyAsset.id === 'USD' 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()] @@ -50,18 +51,29 @@ export default function DisplayCurrency(props: Props) { const amount = coinValue.div(displayPrice).toNumber() return [amount, Math.abs(amount)] - }, [assets, displayCurrency, displayCurrencyAsset.decimals, prices, props.coin]) + }, [assets, displayCurrency, displayCurrencyAsset.decimals, prices, coin]) const isLessThanACent = useMemo( () => isUSD && absoluteAmount < 0.01 && absoluteAmount > 0, [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 ? '' : ` ${displayCurrencyAsset.symbol ? ` ${displayCurrencyAsset.symbol}` : ''}` @@ -69,19 +81,19 @@ export default function DisplayCurrency(props: Props) { return ( 0 && 'text-profit', )} amount={isLessThanACent ? 0.01 : absoluteAmount} options={{ minDecimals: isUSD ? 2 : 0, maxDecimals: 2, abbreviated: true, - prefix, suffix, - ...props.options, + ...options, + prefix, }} animate /> diff --git a/src/components/common/Table/Row.tsx b/src/components/common/Table/Row.tsx index 5fe731a1..c7f44d3e 100644 --- a/src/components/common/Table/Row.tsx +++ b/src/components/common/Table/Row.tsx @@ -7,51 +7,56 @@ interface Props { renderExpanded?: (row: TanstackRow, table: TanstackTable) => JSX.Element rowClassName?: string spacingClassName?: string - isBalancesTable?: boolean className?: string isSelectable?: boolean + type?: TableType } -function getBorderColor(row: AccountBalanceRow) { - return row.type === 'borrowing' ? 'border-loss' : 'border-profit' +function getBorderColor(type: TableType, row: AccountBalanceRow | AccountPerpRow) { + 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(props: Props) { - const canExpand = !!props.renderExpanded + const { renderExpanded, table, row, type, spacingClassName, isSelectable } = props + const canExpand = !!renderExpanded + return ( <> { e.preventDefault() - if (props.isSelectable) { - props.row.toggleSelected() + if (isSelectable) { + row.toggleSelected() } if (canExpand) { - const isExpanded = props.row.getIsExpanded() - props.table.resetExpanded() - !isExpanded && props.row.toggleExpanded() + const isExpanded = row.getIsExpanded() + table.resetExpanded() + !isExpanded && row.toggleExpanded() } }} > - {props.row.getVisibleCells().map((cell) => { + {row.getVisibleCells().map((cell) => { 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 ( - {props.row.getIsExpanded() && - props.renderExpanded && - props.renderExpanded(props.row, props.table)} + {row.getIsExpanded() && renderExpanded && renderExpanded(row, table)} ) } diff --git a/src/components/common/Table/index.tsx b/src/components/common/Table/index.tsx index e0e2cbd7..660d2fdc 100644 --- a/src/components/common/Table/index.tsx +++ b/src/components/common/Table/index.tsx @@ -27,7 +27,7 @@ interface Props { renderExpanded?: (row: TanstackRow, table: TanstackTable) => JSX.Element tableBodyClassName?: string spacingClassName?: string - isBalancesTable?: boolean + type?: TableType hideCard?: boolean setRowSelection?: OnChangeFn selectedRows?: RowSelectionState @@ -55,7 +55,7 @@ export default function Table(props: Props) { condition={!props.hideCard} wrapper={(children) => ( {children} @@ -118,8 +118,8 @@ export default function Table(props: Props) { table={table} renderExpanded={props.renderExpanded} spacingClassName={props.spacingClassName} - isBalancesTable={props.isBalancesTable} isSelectable={!!props.setRowSelection} + type={props.type} /> ))} diff --git a/src/components/earn/lend/Table/Columns/DepositValue.tsx b/src/components/earn/lend/Table/Columns/DepositValue.tsx index 4a2cfff9..54f5d33b 100644 --- a/src/components/earn/lend/Table/Columns/DepositValue.tsx +++ b/src/components/earn/lend/Table/Columns/DepositValue.tsx @@ -20,13 +20,10 @@ export const depositedSortingFn = ( interface Props { asset: Asset - lentAmount?: string + lentAmount?: BigNumber } export default function DepositValue(props: Props) { return ( - + ) } diff --git a/src/components/perps/BalancesTable/Columns/Manage.tsx b/src/components/perps/BalancesTable/Columns/Manage.tsx index 5fe11c77..e1e1f89b 100644 --- a/src/components/perps/BalancesTable/Columns/Manage.tsx +++ b/src/components/perps/BalancesTable/Columns/Manage.tsx @@ -1,9 +1,8 @@ -import React, { useMemo } from 'react' +import { useMemo } from 'react' import { useSearchParams } from 'react-router-dom' import DropDownButton from 'components/common/Button/DropDownButton' import { Cross, Edit } from 'components/common/Icons' -import { PerpPositionRow } from 'components/perps/BalancesTable/usePerpsBalancesData' import useCurrentAccount from 'hooks/useCurrentAccount' import useStore from 'store' import { SearchParams } from 'types/enums/searchParams' diff --git a/src/components/perps/BalancesTable/Columns/PnL.tsx b/src/components/perps/BalancesTable/Columns/PnL.tsx index 0bc06a75..18a8fd91 100644 --- a/src/components/perps/BalancesTable/Columns/PnL.tsx +++ b/src/components/perps/BalancesTable/Columns/PnL.tsx @@ -22,7 +22,7 @@ export default function PnL(props: Props) { type='info' underline > - + ) } @@ -34,13 +34,18 @@ type PnLTooltipProps = { function PnLTooltip(props: PnLTooltipProps) { return ( -
+
{[props.realized, props.unrealized].map((coin, i) => ( -
- +
+ {i === 0 ? 'Realized' : 'Unrealized'} PnL - +
))}
diff --git a/src/components/perps/BalancesTable/Columns/Size.tsx b/src/components/perps/BalancesTable/Columns/Size.tsx index b48d41c6..06b61bd9 100644 --- a/src/components/perps/BalancesTable/Columns/Size.tsx +++ b/src/components/perps/BalancesTable/Columns/Size.tsx @@ -19,7 +19,7 @@ export const SIZE_META = { } type Props = { - size: BigNumber + amount: BigNumber asset: Asset } @@ -27,8 +27,8 @@ export default function Size(props: Props) { const price = usePrice(props.asset.denom) const amount = useMemo( - () => demagnify(props.size.toString(), props.asset), - [props.asset, props.size], + () => demagnify(props.amount.toString(), props.asset), + [props.asset, props.amount], ) const value = useMemo(() => price.times(amount).toNumber(), [amount, price]) return ( diff --git a/src/components/perps/BalancesTable/Columns/TradeDirection.tsx b/src/components/perps/BalancesTable/Columns/TradeDirection.tsx index 713a311f..24223075 100644 --- a/src/components/perps/BalancesTable/Columns/TradeDirection.tsx +++ b/src/components/perps/BalancesTable/Columns/TradeDirection.tsx @@ -1,25 +1,24 @@ import classNames from 'classnames' -import Text from 'components/common/Text' - export const PERP_TYPE_META = { accessorKey: 'tradeDirection', header: 'Side' } type Props = { tradeDirection: TradeDirection + className?: string } export default function TradeDirection(props: Props) { - const { tradeDirection } = props + const { tradeDirection, className } = props return ( - {tradeDirection} - + ) } diff --git a/src/components/perps/BalancesTable/Columns/usePerpsBalancesColumns.tsx b/src/components/perps/BalancesTable/Columns/usePerpsBalancesColumns.tsx index 9731434a..84b25d04 100644 --- a/src/components/perps/BalancesTable/Columns/usePerpsBalancesColumns.tsx +++ b/src/components/perps/BalancesTable/Columns/usePerpsBalancesColumns.tsx @@ -10,7 +10,6 @@ import Size, { SIZE_META } from 'components/perps/BalancesTable/Columns/Size' import TradeDirection, { PERP_TYPE_META, } from 'components/perps/BalancesTable/Columns/TradeDirection' -import { PerpPositionRow } from 'components/perps/BalancesTable/usePerpsBalancesData' export default function usePerpsBalancesTable() { return useMemo[]>(() => { @@ -25,7 +24,7 @@ export default function usePerpsBalancesTable() { }, { ...SIZE_META, - cell: ({ row }) => , + cell: ({ row }) => , }, { ...LEVERAGE_META, diff --git a/src/components/perps/BalancesTable/usePerpsBalancesData.ts b/src/components/perps/BalancesTable/usePerpsBalancesData.ts index 43b1a807..234ed854 100644 --- a/src/components/perps/BalancesTable/usePerpsBalancesData.ts +++ b/src/components/perps/BalancesTable/usePerpsBalancesData.ts @@ -5,7 +5,6 @@ import useAllAssets from 'hooks/assets/useAllAssets' import usePerpsEnabledAssets from 'hooks/assets/usePerpsEnabledAssets' import useCurrentAccount from 'hooks/useCurrentAccount' import usePrices from 'hooks/usePrices' -import { BNCoin } from 'types/classes/BNCoin' import { getAccountNetValue } from 'utils/accounts' import { byDenom } from 'utils/array' import { demagnify } from 'utils/formatters' @@ -24,25 +23,16 @@ export default function usePerpsBalancesTable() { return currentAccount.perps.map((position) => { const price = prices.find(byDenom(position.denom))?.amount ?? BN_ZERO const asset = perpAssets.find(byDenom(position.denom))! + return { asset, tradeDirection: position.tradeDirection, - size: position.size, + amount: position.amount, pnl: position.pnl, entryPrice: position.entryPrice, 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 }) }, [allAssets, currentAccount, perpAssets, prices]) } - -export type PerpPositionRow = { - asset: Asset - tradeDirection: TradeDirection - size: BigNumber - pnl: BNCoin - entryPrice: BigNumber - liquidationPrice: BigNumber - leverage: number -} diff --git a/src/components/perps/Module/PerpsManageModule/usePerpsManageModule.ts b/src/components/perps/Module/PerpsManageModule/usePerpsManageModule.ts index f8e6c401..b6a8614b 100644 --- a/src/components/perps/Module/PerpsManageModule/usePerpsManageModule.ts +++ b/src/components/perps/Module/PerpsManageModule/usePerpsManageModule.ts @@ -35,7 +35,7 @@ export default function usePerpsManageModule(amount: BigNumber | null) { }) }, [searchParams, setSearchParams]) - const previousAmount = useMemo(() => perpPosition?.size ?? BN_ZERO, [perpPosition?.size]) + const previousAmount = useMemo(() => perpPosition?.amount ?? BN_ZERO, [perpPosition?.amount]) const previousTradeDirection = useMemo( () => perpPosition?.tradeDirection || 'long', [perpPosition?.tradeDirection], diff --git a/src/components/perps/PerpsPositions.tsx b/src/components/perps/PerpsPositions.tsx index af09211a..b97d16e9 100644 --- a/src/components/perps/PerpsPositions.tsx +++ b/src/components/perps/PerpsPositions.tsx @@ -1,4 +1,4 @@ -import PerpsBalancesTable from './BalancesTable' +import PerpsBalancesTable from 'components/perps/BalancesTable' export function PerpsPositions() { return diff --git a/src/components/portfolio/Account/PerpPositions.tsx b/src/components/portfolio/Account/PerpPositions.tsx new file mode 100644 index 00000000..d33c9f89 --- /dev/null +++ b/src/components/portfolio/Account/PerpPositions.tsx @@ -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 ( + + + + ) +} + +export default function PerpPositions(props: Props) { + return ( + }> + + + ) +} + +interface SkeletonProps { + children?: React.ReactNode +} + +function Skeleton(props: SkeletonProps) { + return ( +
+ Perp Positions + + {props.children ? ( + props.children + ) : ( + + )} + +
+ ) +} diff --git a/src/components/trade/TradeModule/AssetSelector/AssetOverlay/index.tsx b/src/components/trade/TradeModule/AssetSelector/AssetOverlay/index.tsx index 7a2d4322..b0aea29f 100644 --- a/src/components/trade/TradeModule/AssetSelector/AssetOverlay/index.tsx +++ b/src/components/trade/TradeModule/AssetSelector/AssetOverlay/index.tsx @@ -6,12 +6,11 @@ import Overlay from 'components/common/Overlay' import SearchBar from 'components/common/SearchBar' import Text from 'components/common/Text' 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 useAllAssets from 'hooks/assets/useAllAssets' import useFilteredAssets from 'hooks/useFilteredAssets' -import StablesFilter from './StablesFilter' - interface Props { state: OverlayState buyAsset: Asset diff --git a/src/constants/defaultSettings.ts b/src/constants/defaultSettings.ts index c2a42113..f47d6d66 100644 --- a/src/constants/defaultSettings.ts +++ b/src/constants/defaultSettings.ts @@ -8,7 +8,7 @@ const enabledMarketAssets = useStore .chainConfig.assets.filter((asset) => asset.isEnabled && asset.isMarket) export const DEFAULT_SETTINGS: Settings = { - accountSummaryTabs: [true, true], + accountSummaryTabs: [true, true, false], reduceMotion: false, enableAutoLendGlobal: true, tradingPairSimple: { diff --git a/src/hooks/perps/usePerpPosition.ts b/src/hooks/perps/usePerpPosition.ts index 5b78b380..f2a966db 100644 --- a/src/hooks/perps/usePerpPosition.ts +++ b/src/hooks/perps/usePerpPosition.ts @@ -1,9 +1,8 @@ import { useMemo } from 'react' +import useCurrentAccount from 'hooks/useCurrentAccount' import { byDenom } from 'utils/array' -import useCurrentAccount from '../useCurrentAccount' - export default function usePerpPosition(denom: string): PerpsPosition | undefined { const account = useCurrentAccount() diff --git a/src/hooks/useLendingMarketAssetsTableData.ts b/src/hooks/useLendingMarketAssetsTableData.ts index 41221daf..4badcd68 100644 --- a/src/hooks/useLendingMarketAssetsTableData.ts +++ b/src/hooks/useLendingMarketAssetsTableData.ts @@ -1,5 +1,6 @@ import { useMemo } from 'react' +import { BN_ZERO } from 'constants/math' import useAllAssets from 'hooks/assets/useAllAssets' import useMarketDeposits from 'hooks/markets/useMarketDeposits' import useMarketLiquidities from 'hooks/markets/useMarketLiquidities' @@ -29,7 +30,7 @@ function useLendingMarketAssetsTableData(): { const asset = assets.find(byDenom(denom)) as Asset const marketDepositAmount = BN(marketDeposits.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 ? convertAmount(asset, accountLentAmount) : undefined @@ -46,9 +47,11 @@ function useLendingMarketAssetsTableData(): { cap, } - ;(lendingMarketAsset.accountLentValue ? accountLentAssets : availableAssets).push( - lendingMarketAsset, - ) + if (lendingMarketAsset.accountLentAmount?.isZero()) { + availableAssets.push(lendingMarketAsset) + } else { + accountLentAssets.push(lendingMarketAsset) + } }) return { diff --git a/src/pages/PortfolioAccountPage.tsx b/src/pages/PortfolioAccountPage.tsx index abb6ffe1..8e2e7275 100644 --- a/src/pages/PortfolioAccountPage.tsx +++ b/src/pages/PortfolioAccountPage.tsx @@ -1,14 +1,17 @@ import { useNavigate, useParams, useSearchParams } from 'react-router-dom' import MigrationBanner from 'components/common/MigrationBanner' +import ShareBar from 'components/common/ShareBar' import Balances from 'components/portfolio/Account/Balances' import BreadCrumbs from 'components/portfolio/Account/BreadCrumbs' +import PerpPositions from 'components/portfolio/Account/PerpPositions' import Summary from 'components/portfolio/Account/Summary' -import ShareBar from 'components/common/ShareBar' import useAccountId from 'hooks/useAccountId' +import useStore from 'store' import { getRoute } from 'utils/route' export default function PortfolioAccountPage() { + const chainConfig = useStore((s) => s.chainConfig) const selectedAccountId = useAccountId() const { address, accountId } = useParams() const navigate = useNavigate() @@ -25,6 +28,7 @@ export default function PortfolioAccountPage() { + {chainConfig.perps && }
) diff --git a/src/types/generated.d.ts b/src/types/generated.d.ts index 664ebf23..80198dce 100644 --- a/src/types/generated.d.ts +++ b/src/types/generated.d.ts @@ -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 diff --git a/src/types/generated/mars-red-bank/MarsRedBank.types.ts b/src/types/generated/mars-red-bank/MarsRedBank.types.ts index fb915743..2b574363 100644 --- a/src/types/generated/mars-red-bank/MarsRedBank.types.ts +++ b/src/types/generated/mars-red-bank/MarsRedBank.types.ts @@ -264,7 +264,7 @@ export interface UserDebtResponse { } export type ArrayOfUserDebtResponse = UserDebtResponse[] export type UserHealthStatus = - | 'not_borrowing' + | 'not_borrow' | { borrowing: { liq_threshold_hf: Decimal diff --git a/src/types/interfaces/account.d.ts b/src/types/interfaces/account.d.ts index 85d5096c..d801fd68 100644 --- a/src/types/interfaces/account.d.ts +++ b/src/types/interfaces/account.d.ts @@ -1,4 +1,7 @@ -interface Account extends AccountChange { +type PositionType = 'deposit' | 'borrow' | 'lend' | 'vault' | 'perp' +type TableType = 'balances' | 'perps' + +interface Account { id: string deposits: BNCoin[] debts: BNCoin[] @@ -8,7 +11,7 @@ interface Account extends AccountChange { kind: AccountKind } -interface AccountChange { +interface AccountChange extends Account { deposits?: BNCoin[] debts?: BNCoin[] lends?: BNCoin[] @@ -21,7 +24,14 @@ interface AccountBalanceRow { denom: string size: number symbol: string - type: 'deposits' | 'borrowing' | 'lending' | 'vault' + type: PositionType + value: string + amountChange: BigNumber +} + +interface AccountPerpRow extends PerpsPosition { + amount: BigNumber + symbol: string value: string amountChange: BigNumber } diff --git a/src/types/interfaces/asset.d.ts b/src/types/interfaces/asset.d.ts index 21c81919..e829447d 100644 --- a/src/types/interfaces/asset.d.ts +++ b/src/types/interfaces/asset.d.ts @@ -59,7 +59,7 @@ interface BorrowMarketTableData extends MarketTableData { } interface LendingMarketTableData extends MarketTableData { - accountLentAmount?: string + accountLentAmount?: BigNumber accountLentValue?: BigNumber borrowEnabled: boolean cap: DepositCap diff --git a/src/types/interfaces/perps.d.ts b/src/types/interfaces/perps.d.ts index 5d1cc462..fa315ff0 100644 --- a/src/types/interfaces/perps.d.ts +++ b/src/types/interfaces/perps.d.ts @@ -1,5 +1,3 @@ -const BNCoin = import('types/classes/BNCoin').BNCoin - type TradeDirection = 'long' | 'short' // TODO: 📈Remove this type when healthcomputer is implemented @@ -8,9 +6,18 @@ type PositionsWithoutPerps = Omit< 'perps' > -type PerpsPosition = { +interface PerpsPosition { denom: string baseDenom: string tradeDirection: TradeDirection - size: BigNumber + amount: BigNumber + closingFee: BNCoin + pnl: BNCoin + entryPrice: BigNumber +} + +interface PerpPositionRow extends PerpsPosition { + asset: Asset + liquidationPrice: BigNumber + leverage: number } diff --git a/src/types/interfaces/store/broadcast.d.ts b/src/types/interfaces/store/broadcast.d.ts index 7528c184..36f4deaf 100644 --- a/src/types/interfaces/store/broadcast.d.ts +++ b/src/types/interfaces/store/broadcast.d.ts @@ -1,6 +1,3 @@ -const BNCoin = import('types/classes/BNCoin').BNCoin -const ActionCoin = import('types/generated').ActionCoin - interface BroadcastResult { result?: import('@delphi-labs/shuttle-react').BroadcastResult error?: string diff --git a/src/utils/accounts.ts b/src/utils/accounts.ts index fb0b5ca1..e3df2167 100644 --- a/src/utils/accounts.ts +++ b/src/utils/accounts.ts @@ -53,14 +53,16 @@ export const calculateAccountValue = ( ) } - return account[type]?.reduce((acc, position) => { - const asset = assets.find(byDenom(position.denom)) - if (!asset) return acc - const price = prices.find((price) => price.denom === position.denom)?.amount ?? 0 - const amount = BN(position.amount).shiftedBy(-asset.decimals) - const positionValue = amount.multipliedBy(price) - return acc.plus(positionValue) - }, BN_ZERO) + return ( + account[type]?.reduce((acc, position) => { + const asset = assets.find(byDenom(position.denom)) + if (!asset) return acc + const price = prices.find((price) => price.denom === position.denom)?.amount ?? 0 + const amount = BN(position.amount).shiftedBy(-asset.decimals) + const positionValue = amount.multipliedBy(price) + return acc.plus(positionValue) + }, BN_ZERO) ?? BN_ZERO + ) } export const calculateAccountApr = ( diff --git a/src/utils/resolvers.ts b/src/utils/resolvers.ts index a4c6969a..43b179c7 100644 --- a/src/utils/resolvers.ts +++ b/src/utils/resolvers.ts @@ -83,7 +83,7 @@ export function resolvePerpsPositions(perpPositions: Positions['perps']): PerpsP return { denom: position.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', closingFee: BNCoin.fromCoin(position.pnl.coins.closing_fee), pnl: getPnlCoin(position.pnl.coins.pnl, position.base_denom),
@@ -60,9 +65,7 @@ export default function Row(props: Props) { ) })}