add perp liquidations

This commit is contained in:
saml33 2023-03-23 12:26:02 +11:00
parent 7750942ca5
commit e75cb06eb2
8 changed files with 318 additions and 89 deletions

View File

@ -7,10 +7,14 @@ import dayjs from 'dayjs'
import useLocalStorageState from 'hooks/useLocalStorageState'
import { useTranslation } from 'next-i18next'
import Image from 'next/legacy/image'
import { useState } from 'react'
import { useMemo, useState } from 'react'
import { PREFERRED_EXPLORER_KEY } from 'utils/constants'
import ActivityFeedTable from './ActivityFeedTable'
import { LiquidationActivity } from 'types'
import {
isPerpLiquidation,
LiquidationActivity,
SpotOrPerpLiquidationItem,
} from 'types'
const ActivityFeed = () => {
const activityFeed = mangoStore((s) => s.activityFeed.feed)
@ -27,7 +31,7 @@ const ActivityFeed = () => {
handleShowActivityDetails={handleShowActivityDetails}
/>
) : (
<ActivityDetails
<LiquidationDetails
activity={showActivityDetail}
setShowActivityDetail={setShowActivityDetail}
/>
@ -36,97 +40,231 @@ const ActivityFeed = () => {
export default ActivityFeed
const ActivityDetails = ({
const LiquidationDetails = ({
activity,
setShowActivityDetail,
}: {
activity: LiquidationActivity
setShowActivityDetail: (x: LiquidationActivity | undefined) => void
}) => {
console.log(activity)
const { t } = useTranslation(['common', 'activity', 'settings'])
const [preferredExplorer] = useLocalStorageState(
PREFERRED_EXPLORER_KEY,
EXPLORERS[0]
)
const { block_datetime, activity_type } = activity
const {
asset_amount,
asset_price,
asset_symbol,
liab_amount,
liab_price,
liab_symbol,
signature,
} = activity.activity_details
const { block_datetime } = activity
const getAssetLiquidatedReturned = (details: SpotOrPerpLiquidationItem) => {
const assets = {
liquidated: { amount: 0, symbol: '', value: 0 },
returned: { amount: 0, symbol: '', value: 0 },
}
if (isPerpLiquidation(details)) {
const {
base_transfer,
pnl_settle_limit_transfer,
pnl_transfer,
price,
quote_transfer,
side,
} = details
if (side === 'liqee') {
const returnedAmount =
pnl_settle_limit_transfer + pnl_transfer + quote_transfer
const liquidatedAmount = base_transfer * price
assets.liquidated.amount = liquidatedAmount
assets.liquidated.value = liquidatedAmount
assets.returned.amount = returnedAmount
assets.returned.value = returnedAmount
} else {
const liquidatedAmount =
pnl_settle_limit_transfer + pnl_transfer + quote_transfer
const returnedAmount = base_transfer * price
assets.liquidated.amount = liquidatedAmount
assets.liquidated.value = liquidatedAmount
assets.returned.amount = returnedAmount
assets.returned.value = returnedAmount
}
} else {
const {
side,
liab_amount,
liab_price,
liab_symbol,
asset_amount,
asset_price,
asset_symbol,
} = details
if (side === 'liqee') {
assets.liquidated.amount = asset_amount
assets.liquidated.symbol = asset_symbol
assets.liquidated.value = asset_amount * asset_price
assets.returned.amount = liab_amount
assets.returned.symbol = liab_symbol
assets.returned.value = liab_amount * liab_price
} else {
assets.liquidated.amount = liab_amount
assets.liquidated.symbol = liab_symbol
assets.liquidated.value = liab_amount * liab_price
assets.returned.amount = asset_amount
assets.returned.symbol = asset_symbol
assets.returned.value = asset_amount * asset_price
}
}
return assets
}
const [
assetLiquidated,
assetReturned,
assetLiquidatedSymbol,
assetReturnedSymbol,
liquidatedValue,
returnedValue,
] = useMemo(() => {
if (!activity) return [0, 0, '', '', 0, 0]
const values = getAssetLiquidatedReturned(activity.activity_details)
return [
values?.liquidated.amount,
values?.returned.amount,
values?.liquidated.symbol,
values?.returned.symbol,
values?.liquidated.value,
values?.returned.value,
]
}, [activity])
console.log(
assetLiquidated,
assetReturned,
assetLiquidatedSymbol,
assetReturnedSymbol
)
return (
<div>
<div className="flex items-center p-6">
<IconButton
className="mr-4"
onClick={() => setShowActivityDetail(undefined)}
size="small"
>
<ArrowLeftIcon className="h-5 w-5" />
</IconButton>
<h2 className="text-lg">{t('activity:liquidation-details')}</h2>
</div>
<div className="grid grid-cols-1 gap-4 px-6 md:grid-cols-2">
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('date')}</p>
<p className="text-th-fgd-1">
{dayjs(block_datetime).format('ddd D MMM')}
</p>
<p className="text-xs text-th-fgd-3">
{dayjs(block_datetime).format('h:mma')}
</p>
</div>
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('activity:liquidation-type')}</p>
<p className="text-th-fgd-1">
{activity_type === 'liquidate_token_with_token'
? t('spot')
: t('perp')}
</p>
</div>
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('activity:asset-liquidated')}</p>
<p className="font-mono text-th-fgd-1">
<FormatNumericValue value={asset_amount} />{' '}
<span className="font-body">{asset_symbol}</span>
<span className="ml-2 font-body text-th-fgd-3">at</span>{' '}
<FormatNumericValue value={asset_price} isUsd />
</p>
<p className="font-mono text-xs text-th-fgd-3">
<FormatNumericValue value={asset_price * asset_amount} isUsd />
</p>
</div>
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('activity:asset-returned')}</p>
<p className="font-mono text-th-fgd-1">
<FormatNumericValue value={liab_amount} />{' '}
<span className="font-body">{liab_symbol}</span>
<span className="ml-2 font-body text-th-fgd-3">at</span>{' '}
<FormatNumericValue value={liab_price} isUsd />
</p>
<p className="font-mono text-xs text-th-fgd-3">
<FormatNumericValue value={liab_price * liab_amount} isUsd />
</p>
</div>
</div>
<div className="col-span-3 mt-8 flex justify-center border-y border-th-bkg-3 py-3">
<a
className="default-transition flex items-center text-th-fgd-2 hover:text-th-fgd-3"
href={`${preferredExplorer.url}${signature}`}
target="_blank"
rel="noopener noreferrer"
>
<Image
alt=""
width="20"
height="20"
src={`/explorer-logos/${preferredExplorer.name}.png`}
/>
<span className="ml-2 text-base">{t('view-transaction')}</span>
</a>
{isPerpLiquidation(activity.activity_details) ? (
<>
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('date')}</p>
<p className="text-th-fgd-1">
{dayjs(block_datetime).format('ddd D MMM')}
</p>
<p className="text-xs text-th-fgd-3">
{dayjs(block_datetime).format('h:mma')}
</p>
</div>
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('activity:liquidation-type')}</p>
<p className="text-th-fgd-1">{t('perp')}</p>
</div>
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('activity:asset-liquidated')}</p>
<p className="font-mono text-th-fgd-1">
<FormatNumericValue value={assetLiquidated} />{' '}
<span className="font-body">{assetLiquidatedSymbol}</span>
</p>
<p className="font-mono text-xs text-th-fgd-3">
<FormatNumericValue value={liquidatedValue} isUsd />
</p>
</div>
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('activity:asset-returned')}</p>
<p className="font-mono text-th-fgd-1">
<FormatNumericValue value={assetReturned} />{' '}
<span className="font-body">{assetReturnedSymbol}</span>
</p>
<p className="font-mono text-xs text-th-fgd-3">
<FormatNumericValue value={returnedValue} isUsd />
</p>
</div>
</>
) : (
<>
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('date')}</p>
<p className="text-th-fgd-1">
{dayjs(block_datetime).format('ddd D MMM')}
</p>
<p className="text-xs text-th-fgd-3">
{dayjs(block_datetime).format('h:mma')}
</p>
</div>
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('activity:liquidation-type')}</p>
<p className="text-th-fgd-1">{t('spot')}</p>
</div>
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('activity:asset-liquidated')}</p>
<p className="font-mono text-th-fgd-1">
<FormatNumericValue value={assetLiquidated} />{' '}
<span className="font-body">{assetLiquidatedSymbol}</span>
<span className="ml-2 font-body text-th-fgd-3">at</span>{' '}
<FormatNumericValue
value={activity.activity_details.asset_price}
isUsd
/>
</p>
<p className="font-mono text-xs text-th-fgd-3">
<FormatNumericValue value={liquidatedValue} isUsd />
</p>
</div>
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('activity:asset-returned')}</p>
<p className="font-mono text-th-fgd-1">
<FormatNumericValue value={assetReturned} />{' '}
<span className="font-body">{assetReturnedSymbol}</span>
<span className="ml-2 font-body text-th-fgd-3">at</span>{' '}
<FormatNumericValue
value={activity.activity_details.liab_price}
isUsd
/>
</p>
<p className="font-mono text-xs text-th-fgd-3">
<FormatNumericValue value={returnedValue} isUsd />
</p>
</div>
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('activity:liquidation-side')}</p>
<p className="text-th-fgd-1">
{activity.activity_details.side === 'liqor'
? t('activity:liquidator')
: t('activity:liquidated')}
</p>
</div>
<div className="col-span-1">
<p className="mb-0.5 text-sm">{t('transaction')}</p>
<a
className="default-transition flex items-center text-th-fgd-2 hover:text-th-fgd-3"
href={`${preferredExplorer.url}${activity.activity_details.signature}`}
target="_blank"
rel="noopener noreferrer"
>
<Image
alt=""
width="20"
height="20"
src={`/explorer-logos/${preferredExplorer.name}.png`}
/>
<span className="ml-2 text-sm">
{t(`settings:${preferredExplorer.name}`)}
</span>
</a>
</div>
</>
)}
</div>
</div>
)

View File

@ -77,6 +77,31 @@ const getCreditAndDebit = (activity: any) => {
debit = { value: formatNumericValue(liab_amount), symbol: liab_symbol }
}
}
if (activity_type === 'liquidate_perp_base_position_or_positive_pnl') {
const {
base_transfer,
pnl_settle_limit_transfer,
pnl_transfer,
price,
quote_transfer,
side,
} = activity.activity_details
const rawCredit = pnl_settle_limit_transfer + pnl_transfer + quote_transfer
const rawDebit = base_transfer * price
if (side === 'liqee') {
credit = { value: formatNumericValue(rawCredit), symbol: '' }
debit = {
value: formatNumericValue(rawDebit),
symbol: '',
}
} else {
credit = {
value: formatNumericValue(rawDebit),
symbol: '',
}
debit = { value: formatNumericValue(rawCredit), symbol: '' }
}
}
if (activity_type === 'deposit') {
const { symbol, quantity } = activity.activity_details
credit = { value: formatNumericValue(quantity), symbol }
@ -132,9 +157,30 @@ const getValue = (activity: any) => {
const { side, liab_amount, liab_price, asset_amount, asset_price } =
activity.activity_details
if (side === 'liqee') {
value = asset_amount * asset_price
value =
Math.abs(liab_amount) * liab_price -
Math.abs(asset_amount) * asset_price
} else {
value = liab_amount * liab_price
value =
Math.abs(asset_amount) * asset_price -
Math.abs(liab_amount) * liab_price
}
}
if (activity_type === 'liquidate_perp_base_position_or_positive_pnl') {
const {
base_transfer,
pnl_settle_limit_transfer,
pnl_transfer,
price,
quote_transfer,
side,
} = activity.activity_details
const rawCredit = pnl_settle_limit_transfer + pnl_transfer + quote_transfer
const rawDebit = base_transfer * price
if (side === 'liqee') {
value = Math.abs(rawCredit) - Math.abs(rawDebit)
} else {
value = Math.abs(rawDebit) - Math.abs(rawCredit)
}
}
if (activity_type === 'deposit' || activity_type === 'withdraw') {
@ -216,8 +262,6 @@ const ActivityFeedTable = ({
{activityFeed.map((activity, index: number) => {
const { activity_type, block_datetime } = activity
const { signature } = activity.activity_details
const isLiquidation =
activity_type === 'liquidate_token_with_token'
const isOpenbook = activity_type === 'openbook_trade'
const amounts = getCreditAndDebit(activity)
const value = getValue(activity)
@ -226,7 +270,7 @@ const ActivityFeedTable = ({
<TrBody
key={signature + index}
className={`default-transition text-sm hover:bg-th-bkg-2 ${
isLiquidation ? 'cursor-pointer' : ''
isLiquidationFeedItem(activity) ? 'cursor-pointer' : ''
}`}
onClick={
isLiquidationFeedItem(activity)
@ -285,7 +329,7 @@ const ActivityFeedTable = ({
<FormatNumericValue value={value} isUsd />
</Td>
<Td>
{activity_type !== 'liquidate_token_with_token' ? (
{!isLiquidationFeedItem(activity) ? (
<div className="flex items-center justify-end">
<Tooltip
content={`View on ${t(
@ -376,7 +420,6 @@ const MobileActivityFeedItem = ({
)
const { activity_type, block_datetime } = activity
const { signature } = activity.activity_details
const isLiquidation = activity_type === 'liquidate_token_with_token'
const isSwap = activity_type === 'swap'
const isOpenbook = activity_type === 'openbook_trade'
const isPerp = activity_type === 'perp_trade'
@ -399,7 +442,7 @@ const MobileActivityFeedItem = ({
{t(`activity:${activity_type}`)}
</p>
<p className="text-right font-mono text-sm text-th-fgd-1">
{isLiquidation ? (
{isLiquidationFeedItem(activity) ? (
<FormatNumericValue value={value} isUsd />
) : isSwap ? (
<>
@ -471,7 +514,7 @@ const MobileActivityFeedItem = ({
)}
</p>
</div>
{isLiquidation ? (
{isLiquidationFeedItem(activity) ? (
<IconButton
onClick={() => setExpandActivityDetails((prev) => !prev)}
>

View File

@ -11,11 +11,15 @@
"deposit": "Deposit",
"deposits": "Deposits",
"filter-results": "Filter",
"liquidate_perp_base_position_or_positive_pnl": "Perp Liquidation",
"liquidate_token_with_token": "Spot Liquidation",
"liquidated": "Liquidated",
"liquidation": "Liquidation",
"liquidation-type": "Liquidation Type",
"liquidation-side": "Liquidation Side",
"liquidations": "Liquidations",
"liquidation-details": "Liquidation Details",
"liquidate_token_with_token": "Spot Liquidation",
"liquidator": "Liquidator",
"no-activity": "No account activity",
"openbook_trade": "Spot Trade",
"perps": "Perps",

View File

@ -11,11 +11,15 @@
"deposit": "Deposit",
"deposits": "Deposits",
"filter-results": "Filter",
"liquidate_perp_base_position_or_positive_pnl": "Perp Liquidation",
"liquidate_token_with_token": "Spot Liquidation",
"liquidated": "Liquidated",
"liquidation": "Liquidation",
"liquidation-type": "Liquidation Type",
"liquidation-side": "Liquidation Side",
"liquidations": "Liquidations",
"liquidation-details": "Liquidation Details",
"liquidate_token_with_token": "Spot Liquidation",
"liquidator": "Liquidator",
"no-activity": "No account activity",
"openbook_trade": "Spot Trade",
"perps": "Perps",

View File

@ -11,11 +11,15 @@
"deposit": "Deposit",
"deposits": "Deposits",
"filter-results": "Filter",
"liquidate_perp_base_position_or_positive_pnl": "Perp Liquidation",
"liquidate_token_with_token": "Spot Liquidation",
"liquidated": "Liquidated",
"liquidation": "Liquidation",
"liquidation-type": "Liquidation Type",
"liquidation-side": "Liquidation Side",
"liquidations": "Liquidations",
"liquidation-details": "Liquidation Details",
"liquidate_token_with_token": "Spot Liquidation",
"liquidator": "Liquidator",
"no-activity": "No account activity",
"openbook_trade": "Spot Trade",
"perps": "Perps",

View File

@ -11,11 +11,15 @@
"deposit": "Deposit",
"deposits": "Deposits",
"filter-results": "Filter",
"liquidate_perp_base_position_or_positive_pnl": "Perp Liquidation",
"liquidate_token_with_token": "Spot Liquidation",
"liquidated": "Liquidated",
"liquidation": "Liquidation",
"liquidation-type": "Liquidation Type",
"liquidation-side": "Liquidation Side",
"liquidations": "Liquidations",
"liquidation-details": "Liquidation Details",
"liquidate_token_with_token": "Spot Liquidation",
"liquidator": "Liquidator",
"no-activity": "No account activity",
"openbook_trade": "Spot Trade",
"perps": "Perps",

View File

@ -11,11 +11,15 @@
"deposit": "Deposit",
"deposits": "Deposits",
"filter-results": "Filter",
"liquidate_perp_base_position_or_positive_pnl": "Perp Liquidation",
"liquidate_token_with_token": "Spot Liquidation",
"liquidated": "Liquidated",
"liquidation": "Liquidation",
"liquidation-type": "Liquidation Type",
"liquidation-side": "Liquidation Side",
"liquidations": "Liquidations",
"liquidation-details": "Liquidation Details",
"liquidate_token_with_token": "Spot Liquidation",
"liquidator": "Liquidator",
"no-activity": "No account activity",
"openbook_trade": "Spot Trade",
"perps": "Perps",

View File

@ -113,7 +113,7 @@ export interface DepositWithdrawFeedItem {
wallet_pk: string
}
export interface LiquidationFeedItem {
export interface SpotLiquidationFeedItem {
asset_amount: number
asset_price: number
asset_symbol: string
@ -123,12 +123,30 @@ export interface LiquidationFeedItem {
liab_symbol: string
mango_account: string
mango_group: string
side: string
side: 'liqor' | 'liqee'
signature: string
}
export interface PerpLiquidationFeedItem {
base_transfer: -0.5
block_datetime: string
counterparty: string
mango_account: string
mango_group: string
pnl_settle_limit_transfer: number
pnl_transfer: number
price: number
quote_transfer: number
side: 'liqor' | 'liqee'
signature: string
}
export type SpotOrPerpLiquidationItem =
| SpotLiquidationFeedItem
| PerpLiquidationFeedItem
export interface LiquidationActivity {
activity_details: LiquidationFeedItem
activity_details: SpotOrPerpLiquidationItem
block_datetime: string
activity_type: string
symbol: string
@ -143,6 +161,15 @@ export function isLiquidationFeedItem(
return false
}
export function isPerpLiquidation(
activityDetails: SpotOrPerpLiquidationItem
): activityDetails is PerpLiquidationFeedItem {
if ((activityDetails as PerpLiquidationFeedItem).base_transfer) {
return true
}
return false
}
export interface SwapHistoryItem {
block_datetime: string
mango_account: string
@ -183,7 +210,8 @@ export type ActivityFeed = {
symbol: string
activity_details:
| DepositWithdrawFeedItem
| LiquidationFeedItem
| SpotLiquidationFeedItem
| PerpLiquidationFeedItem
| SwapHistoryItem
| PerpTradeHistory
| SpotTradeHistory