diff --git a/src/api/accounts/getAccount.ts b/src/api/accounts/getAccount.ts index b1bdb98f..d531a34f 100644 --- a/src/api/accounts/getAccount.ts +++ b/src/api/accounts/getAccount.ts @@ -1,5 +1,6 @@ import { cacheFn, positionsCache } from 'api/cache' import { getCreditManagerQueryClient } from 'api/cosmwasm-client' +import getPrices from 'api/prices/getPrices' import getDepositedVaults from 'api/vaults/getDepositedVaults' import { BNCoin } from 'types/classes/BNCoin' import { Positions } from 'types/generated/mars-credit-manager/MarsCreditManager.types' @@ -19,6 +20,8 @@ export default async function getAccount( `${chainConfig.id}/account/${accountId}`, ) + const prices = await getPrices(chainConfig) + const accountKind = await creditManagerQueryClient.accountKind({ accountId: accountId }) const depositedVaults = await getDepositedVaults(accountId, chainConfig, accountPosition) @@ -30,7 +33,7 @@ export default async function getAccount( lends: accountPosition.lends.map((lend) => new BNCoin(lend)), deposits: accountPosition.deposits.map((deposit) => new BNCoin(deposit)), vaults: depositedVaults, - perps: resolvePerpsPositions(accountPosition.perps), + perps: resolvePerpsPositions(accountPosition.perps, prices), kind: accountKind, } } diff --git a/src/components/account/AccountPerpPositionTable/Columns/Asset.tsx b/src/components/account/AccountPerpPositionTable/Columns/Asset.tsx index ac3fb504..992cd349 100644 --- a/src/components/account/AccountPerpPositionTable/Columns/Asset.tsx +++ b/src/components/account/AccountPerpPositionTable/Columns/Asset.tsx @@ -1,15 +1,16 @@ import { ReactNode } from 'react' +import AssetImage from 'components/common/assets/AssetImage' 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 AssetImage from 'components/common/assets/AssetImage' 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', @@ -58,7 +59,12 @@ function TooltipContent(props: TooltipProps) { /> - + ) diff --git a/src/components/account/AccountPerpPositionTable/Columns/TotalPnL.tsx b/src/components/account/AccountPerpPositionTable/Columns/TotalPnL.tsx index 10632fd9..27fdeb83 100644 --- a/src/components/account/AccountPerpPositionTable/Columns/TotalPnL.tsx +++ b/src/components/account/AccountPerpPositionTable/Columns/TotalPnL.tsx @@ -1,10 +1,9 @@ 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 + pnl: PerpsPnL } export default function TotalPnL(props: Props) { @@ -13,7 +12,7 @@ export default function TotalPnL(props: Props) { return ( { - const positiveOrNegativePrefix = isProfitOrLoss + const positiveOrNegativePrefix = showSignPrefix ? amount > 0 ? '+' : amount < 0 @@ -72,7 +82,7 @@ export default function DisplayCurrency(props: Props) { return isUSD ? `${approximationPrefix}${smallerThanPrefix}${positiveOrNegativePrefix}$` : `${approximationPrefix}${smallerThanPrefix}${positiveOrNegativePrefix}` - }, [isUSD, isApproximation, showZero, isProfitOrLoss, amount, isLessThanACent]) + }, [isUSD, isApproximation, showZero, showSignPrefix, amount, isLessThanACent]) const suffix = isUSD ? '' diff --git a/src/components/common/Tooltip/TooltipContent.tsx b/src/components/common/Tooltip/TooltipContent.tsx index b72af6b9..f351409b 100644 --- a/src/components/common/Tooltip/TooltipContent.tsx +++ b/src/components/common/Tooltip/TooltipContent.tsx @@ -16,8 +16,10 @@ export default function TooltipContent(props: Props) {
- } - type='info' - underline - > - + } type='info' underline> + ) } -type PnLTooltipProps = { - realized: BNCoin - unrealized: BNCoin -} - -function PnLTooltip(props: PnLTooltipProps) { +function PnLTooltip(props: Props) { return ( -
- {[props.realized, props.unrealized].map((coin, i) => ( -
- - {i === 0 ? 'Realized' : 'Unrealized'} PnL - - -
+
+ {[props.pnl.realized, props.pnl.unrealized].map((coins, i) => ( + <> +
+ + {i === 0 ? 'Realized' : 'Unrealized'} PnL + + +
+ + + + {i === 0 && } + ))}
) } + +type PnLRowProps = { + coin: BNCoin + text: string + showSignPrefix?: boolean + className?: string +} + +function PnLRow(props: PnLRowProps) { + return ( +
+ + {props.text} + + +
+ ) +} diff --git a/src/components/perps/BalancesTable/usePerpsBalancesData.ts b/src/components/perps/BalancesTable/usePerpsBalancesData.ts index de9e7d0b..6731e1dd 100644 --- a/src/components/perps/BalancesTable/usePerpsBalancesData.ts +++ b/src/components/perps/BalancesTable/usePerpsBalancesData.ts @@ -21,7 +21,8 @@ export default function usePerpsBalancesTable() { const netValue = getAccountNetValue(currentAccount, prices, allAssets) return currentAccount.perps.map((position) => { - const price = prices.find(byDenom(position.denom))?.amount ?? BN_ZERO + const perpPrice = prices.find(byDenom(position.denom))?.amount ?? BN_ZERO + const basePrice = prices.find(byDenom(position.baseDenom))?.amount ?? BN_ZERO const asset = perpAssets.find(byDenom(position.denom))! return { @@ -31,7 +32,11 @@ export default function usePerpsBalancesTable() { pnl: position.pnl, entryPrice: position.entryPrice, liquidationPrice: position.entryPrice, // TODO: 📈 Get actual liquidation price from HC - leverage: price.times(demagnify(position.amount, asset)).div(netValue).plus(1).toNumber(), + leverage: perpPrice + .times(demagnify(position.amount, asset)) + .div(netValue) + .plus(1) + .toNumber(), } as PerpPositionRow }) }, [allAssets, currentAccount, perpAssets, prices]) diff --git a/src/types/interfaces/account.d.ts b/src/types/interfaces/account.d.ts index 9dc7f9fc..46bb4842 100644 --- a/src/types/interfaces/account.d.ts +++ b/src/types/interfaces/account.d.ts @@ -7,7 +7,7 @@ interface Account { debts: BNCoin[] lends: BNCoin[] vaults: DepositedVault[] - perps: PerpPosition[] + perps: PerpsPosition[] kind: AccountKind } diff --git a/src/types/interfaces/perps.d.ts b/src/types/interfaces/perps.d.ts index fa315ff0..c1ba768f 100644 --- a/src/types/interfaces/perps.d.ts +++ b/src/types/interfaces/perps.d.ts @@ -12,7 +12,7 @@ interface PerpsPosition { tradeDirection: TradeDirection amount: BigNumber closingFee: BNCoin - pnl: BNCoin + pnl: PerpsPnL entryPrice: BigNumber } @@ -21,3 +21,16 @@ interface PerpPositionRow extends PerpsPosition { liquidationPrice: BigNumber leverage: number } + +interface PerpsPnL { + net: BNCoin + realized: PerpsPnLCoins + unrealized: PerpsPnLCoins +} + +interface PerpsPnLCoins { + fees: BNCoin + funding: BNCoin + net: BNCoin + price: BNCoin +} diff --git a/src/utils/getPerpsPosition.ts b/src/utils/getPerpsPosition.ts index ec7e2725..dd152930 100644 --- a/src/utils/getPerpsPosition.ts +++ b/src/utils/getPerpsPosition.ts @@ -1,6 +1,6 @@ import BigNumber from 'bignumber.js' -import { BN_ONE } from 'constants/math' +import { BN_ONE, BN_ZERO } from 'constants/math' import { BNCoin } from 'types/classes/BNCoin' export default function getPerpsPosition( @@ -9,15 +9,27 @@ export default function getPerpsPosition( tradeDirection: TradeDirection, ) { const perpsBaseDenom = 'ibc/F91EA2C0A23697A1048E08C2F787E3A58AC6F706A1CD2257A504925158CFC0F3' - const perpsPosition = { + return { amount, closingFee: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ONE), - pnl: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ONE.negated()), + pnl: { + net: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ONE), + realized: { + net: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ZERO), + price: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ZERO), + funding: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ZERO), + fees: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ZERO.times(-1)), + }, + unrealized: { + net: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ZERO), + price: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ZERO), + funding: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ZERO), + fees: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ZERO.times(-1)), + }, + }, entryPrice: BN_ONE, baseDenom: perpsBaseDenom, denom: asset.denom, tradeDirection, } - - return perpsPosition } diff --git a/src/utils/resolvers.ts b/src/utils/resolvers.ts index e24b032b..70121f16 100644 --- a/src/utils/resolvers.ts +++ b/src/utils/resolvers.ts @@ -1,6 +1,6 @@ import { BN_ZERO } from 'constants/math' import { BNCoin } from 'types/classes/BNCoin' -import { PnL, Positions } from 'types/generated/mars-credit-manager/MarsCreditManager.types' +import { Positions } from 'types/generated/mars-credit-manager/MarsCreditManager.types' import { AssetParamsBaseForAddr as AssetParams, AssetParamsBaseForAddr, @@ -104,8 +104,14 @@ export function resolveHLSStrategies( return HLSStakingStrategies } -export function resolvePerpsPositions(perpPositions: Positions['perps']): PerpsPosition[] { +export function resolvePerpsPositions( + perpPositions: Positions['perps'], + prices: BNCoin[], +): PerpsPosition[] { if (!perpPositions) return [] + const basePrice = + prices.find((price) => price.denom === perpPositions[0].base_denom)?.amount ?? BN_ZERO + return perpPositions.map((position) => { return { denom: position.denom, @@ -113,22 +119,37 @@ export function resolvePerpsPositions(perpPositions: Positions['perps']): PerpsP 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), + pnl: { + net: BNCoin.fromDenomAndBigNumber( + position.base_denom, + BN(position.pnl.values.pnl as any).plus(BN_ZERO), + ), + realized: { + net: BNCoin.fromDenomAndBigNumber(position.base_denom, BN_ZERO), + price: BNCoin.fromDenomAndBigNumber(position.base_denom, BN_ZERO), + funding: BNCoin.fromDenomAndBigNumber(position.base_denom, BN_ZERO), + fees: BNCoin.fromDenomAndBigNumber(position.base_denom, BN_ZERO.times(-1)), + }, + unrealized: { + net: BNCoin.fromDenomAndBigNumber( + position.base_denom, + BN(position.pnl.values.pnl as any), + ), + price: BNCoin.fromDenomAndBigNumber( + position.base_denom, + BN(position.pnl.values.price_pnl as any), + ), + funding: BNCoin.fromDenomAndBigNumber( + position.base_denom, + BN(position.pnl.values.accrued_funding as any), + ), + fees: BNCoin.fromDenomAndBigNumber( + position.base_denom, + BN(position.pnl.values.closing_fee as any).times(-1), + ), + }, + }, entryPrice: BN(position.entry_price), } }) } - -function getPnlCoin(pnl: PnL, denom: string): BNCoin { - let amount = BN_ZERO - - if (pnl === 'break_even') return BNCoin.fromDenomAndBigNumber(denom, amount) - - if ('loss' in (pnl as any)) { - amount = BN((pnl as any).loss.amount).times(-1) - } else if ('profit' in (pnl as { profit: Coin })) { - amount = BN((pnl as any).profit.amount) - } - - return BNCoin.fromDenomAndBigNumber(denom, amount) -}