diff --git a/centrifuge-app/src/components/Portfolio/CardPortfolioValue.tsx b/centrifuge-app/src/components/Portfolio/CardPortfolioValue.tsx index 37c2e3313..9e4068d0d 100644 --- a/centrifuge-app/src/components/Portfolio/CardPortfolioValue.tsx +++ b/centrifuge-app/src/components/Portfolio/CardPortfolioValue.tsx @@ -73,18 +73,24 @@ export function CardPortfolioValue({ - - Current portfolio value - - {formatBalance(currentPortfolioValue || 0, config.baseCurrency)} - - - {/* - Profit - - + {formatBalance(Dec(portfolioValue || 0), config.baseCurrency)} - - */} + + + Current portfolio value + + {formatBalance(currentPortfolioValue || 0, config.baseCurrency)} + + + + Total P&L + + {formatBalance(currentPortfolioValue || 0, config.baseCurrency)} + + + diff --git a/centrifuge-app/src/components/Portfolio/Holdings.tsx b/centrifuge-app/src/components/Portfolio/Holdings.tsx index 8ea2f99b7..b08fae5b2 100644 --- a/centrifuge-app/src/components/Portfolio/Holdings.tsx +++ b/centrifuge-app/src/components/Portfolio/Holdings.tsx @@ -1,4 +1,4 @@ -import { Token, evmToSubstrateAddress } from '@centrifuge/centrifuge-js' +import { CurrencyBalance, Token, evmToSubstrateAddress } from '@centrifuge/centrifuge-js' import { formatBalance, useBalances, useCentrifuge, useWallet } from '@centrifuge/centrifuge-react' import { Box, Grid, IconDownload, IconMinus, IconPlus, IconSend, Shelf, Text, Thumbnail } from '@centrifuge/fabric' import Decimal from 'decimal.js-light' @@ -36,6 +36,8 @@ type Row = { showActions?: boolean address?: string connectedNetwork?: string | null + realizedProfit?: CurrencyBalance | undefined + unrealizedProfit?: CurrencyBalance | undefined } const columns: Column[] = [ @@ -81,6 +83,30 @@ const columns: Column[] = [ sortKey: 'marketValue', align: 'left', }, + { + header: , + cell: ({ currency, unrealizedProfit }: Row) => { + return ( + + {unrealizedProfit ? formatBalanceAbbreviated(unrealizedProfit, currency?.symbol, 2) : '-'} + + ) + }, + sortKey: 'realizedProfit', + align: 'left', + }, + { + header: , + cell: ({ currency, unrealizedProfit }: Row) => { + return ( + + {unrealizedProfit ? formatBalanceAbbreviated(unrealizedProfit, currency?.symbol, 2) : '-'} + + ) + }, + sortKey: 'unrealizedProfit', + align: 'left', + }, { align: 'left', header: '', // invest redeem buttons diff --git a/centrifuge-app/src/components/Portfolio/usePortfolio.ts b/centrifuge-app/src/components/Portfolio/usePortfolio.ts index baae396c3..33dff4ca0 100644 --- a/centrifuge-app/src/components/Portfolio/usePortfolio.ts +++ b/centrifuge-app/src/components/Portfolio/usePortfolio.ts @@ -147,6 +147,7 @@ export function usePortfolio(substrateAddress?: string) { sumClaimedTrancheTokens trancheId poolId + unrealizedProfit tranche { tokenPrice } @@ -176,6 +177,12 @@ export function usePortfolio(substrateAddress?: string) { trancheId } } + investorTransactions { + nodes { + realizedProfitFifo + trancheId + } + } } }`, { @@ -187,7 +194,12 @@ export function usePortfolio(substrateAddress?: string) { ) const data = useMemo(() => { - const trancheBalances: Record = {} + const trancheBalances: Record< + string, + { totalTrancheTokens: TokenBalance; tokenPrice: Price; unrealizedProfit: CurrencyBalance | undefined } + > = {} + + console.log('sub', subData) subData?.account?.investorPositions.nodes.forEach((position: any) => { const pool = pools?.find((p) => p.id === position.poolId) @@ -196,12 +208,24 @@ export function usePortfolio(substrateAddress?: string) { const tokenPrice = pool?.tranches.find((t) => trancheId === t.id)?.tokenPrice ?? Price.fromFloat(1) const balance = new TokenBalance(position.holdingQuantity, decimals) const existing = trancheBalances[trancheId] + + const unrealizedProfit = subData?.account?.trancheBalances?.nodes.find( + (tb: any) => tb.trancheId === position.trancheId + ) + if (existing) { existing.totalTrancheTokens.iadd(balance) } else { - trancheBalances[trancheId] = { totalTrancheTokens: balance, tokenPrice } + trancheBalances[trancheId] = { + totalTrancheTokens: balance, + tokenPrice, + unrealizedProfit: unrealizedProfit + ? new CurrencyBalance(unrealizedProfit.unrealizedProfit, decimals) + : undefined, + } } }) + // return ( // (subData?.account as undefined | {}) && // (Object.fromEntries( @@ -265,6 +289,7 @@ export function usePortfolio(substrateAddress?: string) { // } // >) // ) + return trancheBalances }, [subData, pools]) @@ -278,6 +303,7 @@ type PortfolioToken = { trancheId: string poolId: string currency: Token['currency'] + unrealizedProfit: CurrencyBalance | undefined } export function usePortfolioTokens(address?: string) { @@ -310,6 +336,7 @@ export function usePortfolioTokens(address?: string) { trancheId: trancheId, poolId: trancheTokenPrices[trancheId].poolId, currency: trancheTokenPrices[trancheId].currency, + unrealizedProfit: tranche.unrealizedProfit, } }, [] as PortfolioToken[]) } diff --git a/centrifuge-app/src/components/Tooltips.tsx b/centrifuge-app/src/components/Tooltips.tsx index e881d0cf9..eb9e48fff 100644 --- a/centrifuge-app/src/components/Tooltips.tsx +++ b/centrifuge-app/src/components/Tooltips.tsx @@ -330,6 +330,14 @@ export const tooltipText = { label: 'Linear accrual', body: 'If enabled, the price of the asset is updated continuously based on linear accrual from the latest known market price to the value at maturity.', }, + unrealizedPL: { + label: 'Unrealized P&L', + body: 'Unrealized profit / loss from current holdings (based on FiFo-weighted sales at the current token price)', + }, + realizedPL: { + label: 'Realized P&L', + body: 'Realized profit / loss from executed redemptions', + }, } export type TooltipsProps = {