Compare commits
12 Commits
main
...
mp-2171-in
Author | SHA1 | Date | |
---|---|---|---|
|
fb701d871b | ||
|
6389155b5a | ||
|
5846e893d1 | ||
|
e3b5e330ee | ||
|
7eac8e7a35 | ||
|
af478c56d5 | ||
|
a6f4c24f15 | ||
|
6946ceddfc | ||
|
0154065ffb | ||
|
4f64234a75 | ||
|
26f1ef4a2c | ||
|
3f28ccd09c |
@ -14,7 +14,7 @@ type Props = {
|
||||
|
||||
export default function PnL(props: Props) {
|
||||
return (
|
||||
<Tooltip content={<PnLTooltip {...props} />} type='info' underline>
|
||||
<Tooltip content={<PnLTooltip {...props} />} type='info' underline className='w-min ml-auto'>
|
||||
<DisplayCurrency
|
||||
className='inline text-xs'
|
||||
coin={props.pnl.net}
|
||||
|
@ -104,7 +104,7 @@ export function PerpsModule() {
|
||||
/>
|
||||
<AssetAmountInput
|
||||
label='Amount'
|
||||
max={BN(100000000)} // TODO: Implement max calculation
|
||||
max={BN(10000000000)} // TODO: Implement max calculation
|
||||
amount={amount.abs()}
|
||||
setAmount={onChangeAmount}
|
||||
asset={perpsAsset}
|
||||
|
@ -3,6 +3,7 @@ import BigNumber from 'bignumber.js'
|
||||
import { CircularProgress } from 'components/common/CircularProgress'
|
||||
import DisplayCurrency from 'components/common/DisplayCurrency'
|
||||
import useTradingFeeAndPrice from 'hooks/perps/useTradingFeeAndPrice'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
|
||||
type Props = {
|
||||
denom: string
|
||||
@ -20,5 +21,12 @@ export default function TradingFee(props: Props) {
|
||||
if (isLoading) return <CircularProgress className='h-full' size={12} />
|
||||
if (props.newAmount.isEqualTo(props.previousAmount) || !tradingFeeAndPrice?.fee) return '-'
|
||||
|
||||
return <DisplayCurrency coin={tradingFeeAndPrice.fee} />
|
||||
return (
|
||||
<DisplayCurrency
|
||||
coin={BNCoin.fromDenomAndBigNumber(
|
||||
tradingFeeAndPrice.baseDenom,
|
||||
tradingFeeAndPrice.fee.opening.plus(tradingFeeAndPrice.fee.closing),
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import useCurrentAccount from 'hooks/accounts/useCurrentAccount'
|
||||
import useChainConfig from 'hooks/useChainConfig'
|
||||
import useClients from 'hooks/useClients'
|
||||
import useDebounce from 'hooks/useDebounce'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export default function useTradingFeeAndPrice(
|
||||
@ -34,14 +33,15 @@ export default function useTradingFeeAndPrice(
|
||||
})
|
||||
|
||||
return {
|
||||
baseDenom: positionFees.base_denom,
|
||||
price: positionFees.opening_exec_price
|
||||
? BN(positionFees.opening_exec_price)
|
||||
: BN(positionFees.closing_exec_price ?? BN_ZERO),
|
||||
fee: BNCoin.fromDenomAndBigNumber(
|
||||
positionFees.base_denom,
|
||||
BN(positionFees.opening_fee).plus(positionFees.closing_fee),
|
||||
),
|
||||
rate: BN(0.005),
|
||||
fee: {
|
||||
opening: BN(positionFees.opening_fee),
|
||||
closing: BN(positionFees.closing_fee),
|
||||
},
|
||||
rate: BN(0.0005),
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,15 +61,13 @@ export default function useTradingFeeAndPrice(
|
||||
|
||||
return await Promise.all([closingPositionFees$, openingPositionFees$]).then(
|
||||
([closingPositionFees, openingPositionFees]) => ({
|
||||
baseDenom: openingPositionFees.base_denom,
|
||||
price: BN(openingPositionFees.opening_exec_price ?? 0),
|
||||
fee: BNCoin.fromDenomAndBigNumber(
|
||||
closingPositionFees.base_denom,
|
||||
BN(closingPositionFees.opening_fee)
|
||||
.plus(closingPositionFees.closing_fee)
|
||||
.plus(openingPositionFees.opening_fee)
|
||||
.plus(openingPositionFees.closing_fee),
|
||||
),
|
||||
rate: BN(0.005),
|
||||
fee: {
|
||||
opening: BN(closingPositionFees.opening_fee).plus(openingPositionFees.opening_fee),
|
||||
closing: BN(closingPositionFees.closing_fee).plus(openingPositionFees.closing_fee),
|
||||
},
|
||||
rate: BN(0.0005), // TODO: Make this rate the actula rate again!
|
||||
}),
|
||||
)
|
||||
},
|
||||
|
@ -14,6 +14,7 @@ import { VaultConfigBaseForString } from 'types/generated/mars-params/MarsParams
|
||||
import {
|
||||
AssetParamsBaseForAddr,
|
||||
HealthComputer,
|
||||
Positions,
|
||||
} from 'types/generated/mars-rover-health-computer/MarsRoverHealthComputer.types'
|
||||
import { convertAccountToPositions } from 'utils/accounts'
|
||||
import { byDenom } from 'utils/array'
|
||||
@ -32,7 +33,8 @@ import { BN } from 'utils/helpers'
|
||||
|
||||
// Pyth returns prices with up to 32 decimals. Javascript only supports 18 decimals. So we need to scale by 14 t
|
||||
// avoid "too many decimals" errors.
|
||||
const VALUE_SCALE_FACTOR = 14
|
||||
// TODO: Remove adjustment properly (after testing). We will just ignore the last 14 decimals.
|
||||
const VALUE_SCALE_FACTOR = 0
|
||||
|
||||
export default function useHealthComputer(account?: Account) {
|
||||
const assets = useAllAssets()
|
||||
@ -42,10 +44,10 @@ export default function useHealthComputer(account?: Account) {
|
||||
const [slippage] = useLocalStorage<number>(LocalStorageKeys.SLIPPAGE, DEFAULT_SETTINGS.slippage)
|
||||
|
||||
const [healthFactor, setHealthFactor] = useState(0)
|
||||
const positions: PositionsWithoutPerps | null = useMemo(() => {
|
||||
const positions: Positions | null = useMemo(() => {
|
||||
if (!account) return null
|
||||
return convertAccountToPositions(account)
|
||||
}, [account])
|
||||
return convertAccountToPositions(account, prices)
|
||||
}, [account, prices])
|
||||
|
||||
const vaultPositionValues = useMemo(() => {
|
||||
if (!account?.vaults) return null
|
||||
@ -87,6 +89,7 @@ export default function useHealthComputer(account?: Account) {
|
||||
prev[curr.denom] = curr.amount
|
||||
.shiftedBy(VALUE_SCALE_FACTOR)
|
||||
.shiftedBy(-decimals + 6)
|
||||
.decimalPlaces(18)
|
||||
.toString()
|
||||
return prev
|
||||
},
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ActionCoin } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||
import { ActionCoin, PnL } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export class BNCoin {
|
||||
@ -23,7 +23,7 @@ export class BNCoin {
|
||||
toCoin(): Coin {
|
||||
return {
|
||||
denom: this.denom,
|
||||
amount: this.amount.toString(),
|
||||
amount: this.amount.integerValue().toString(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ export class BNCoin {
|
||||
amount: max
|
||||
? 'account_balance'
|
||||
: {
|
||||
exact: this.amount.toString(),
|
||||
exact: this.amount.integerValue().toString(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -41,7 +41,23 @@ export class BNCoin {
|
||||
toSignedCoin(): any {
|
||||
return {
|
||||
denom: this.denom,
|
||||
size: this.amount.toString(),
|
||||
size: this.amount.integerValue().toString(),
|
||||
}
|
||||
}
|
||||
|
||||
toPnLCoin(): PnL {
|
||||
if (this.amount.isZero()) {
|
||||
return 'break_even'
|
||||
}
|
||||
|
||||
if (this.amount.isPositive()) {
|
||||
return {
|
||||
profit: this.toCoin(),
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
loss: this.abs().toCoin(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,7 @@ import {
|
||||
Positions,
|
||||
DebtAmount,
|
||||
PerpPosition,
|
||||
PnlAmounts,
|
||||
PositionPnl,
|
||||
PnlCoins,
|
||||
PnlValues,
|
||||
|
@ -623,11 +623,11 @@ export interface PerpPosition {
|
||||
denom: string
|
||||
entry_exec_price: Decimal
|
||||
entry_price: Decimal
|
||||
realised_pnl: RealizedPnlAmounts
|
||||
realised_pnl: PnlAmounts
|
||||
size: SignedDecimal
|
||||
unrealised_pnl: PositionPnl
|
||||
}
|
||||
export interface RealizedPnlAmounts {
|
||||
export interface PnlAmounts {
|
||||
accrued_funding: SignedDecimal
|
||||
closing_fee: SignedDecimal
|
||||
opening_fee: SignedDecimal
|
||||
@ -635,6 +635,7 @@ export interface RealizedPnlAmounts {
|
||||
price_pnl: SignedDecimal
|
||||
}
|
||||
export interface PositionPnl {
|
||||
amounts: PnlAmounts
|
||||
coins: PnlCoins
|
||||
values: PnlValues
|
||||
}
|
||||
|
@ -27,10 +27,11 @@ import {
|
||||
DebtAmount,
|
||||
Coin,
|
||||
PerpPosition,
|
||||
PnlAmounts,
|
||||
SignedDecimal,
|
||||
PositionPnl,
|
||||
PnlCoins,
|
||||
PnlValues,
|
||||
SignedDecimal,
|
||||
VaultPosition,
|
||||
LockingVaultAmount,
|
||||
VaultUnlockingPosition,
|
||||
|
@ -27,10 +27,11 @@ import {
|
||||
DebtAmount,
|
||||
Coin,
|
||||
PerpPosition,
|
||||
PnlAmounts,
|
||||
SignedDecimal,
|
||||
PositionPnl,
|
||||
PnlCoins,
|
||||
PnlValues,
|
||||
SignedDecimal,
|
||||
VaultPosition,
|
||||
LockingVaultAmount,
|
||||
VaultUnlockingPosition,
|
||||
|
@ -41,7 +41,7 @@ export type UnlockingPositions = VaultUnlockingPosition[]
|
||||
export interface HealthComputer {
|
||||
denoms_data: DenomsData
|
||||
kind: AccountKind
|
||||
positions: PositionsWithoutPerps
|
||||
positions: Positions
|
||||
vaults_data: VaultsData
|
||||
}
|
||||
export interface DenomsData {
|
||||
@ -102,13 +102,29 @@ export interface Coin {
|
||||
export interface PerpPosition {
|
||||
base_denom: string
|
||||
closing_fee_rate: Decimal
|
||||
current_exec_price: Decimal
|
||||
current_price: Decimal
|
||||
denom: string
|
||||
entry_exec_price: Decimal
|
||||
entry_price: Decimal
|
||||
pnl: PositionPnl
|
||||
realised_pnl: PnlAmounts
|
||||
size: SignedDecimal
|
||||
unrealised_pnl: PositionPnl
|
||||
}
|
||||
export interface PnlAmounts {
|
||||
accrued_funding: SignedDecimal
|
||||
closing_fee: SignedDecimal
|
||||
opening_fee: SignedDecimal
|
||||
pnl: SignedDecimal
|
||||
price_pnl: SignedDecimal
|
||||
}
|
||||
export interface SignedDecimal {
|
||||
abs: Decimal
|
||||
negative: boolean
|
||||
[k: string]: unknown
|
||||
}
|
||||
export interface PositionPnl {
|
||||
amounts: PnlAmounts
|
||||
coins: PnlCoins
|
||||
values: PnlValues
|
||||
}
|
||||
@ -122,11 +138,6 @@ export interface PnlValues {
|
||||
pnl: SignedDecimal
|
||||
price_pnl: SignedDecimal
|
||||
}
|
||||
export interface SignedDecimal {
|
||||
abs: Decimal
|
||||
negative: boolean
|
||||
[k: string]: unknown
|
||||
}
|
||||
export interface VaultPosition {
|
||||
amount: VaultPositionAmount
|
||||
vault: VaultBaseForAddr
|
||||
|
7
src/types/interfaces/perps.d.ts
vendored
7
src/types/interfaces/perps.d.ts
vendored
@ -1,11 +1,5 @@
|
||||
type TradeDirection = 'long' | 'short'
|
||||
|
||||
// TODO: 📈Remove this type when healthcomputer is implemented
|
||||
type PositionsWithoutPerps = Omit<
|
||||
import('types/generated/mars-credit-manager/MarsCreditManager.types').Positions,
|
||||
'perps'
|
||||
>
|
||||
|
||||
interface PerpsPosition {
|
||||
denom: string
|
||||
baseDenom: string
|
||||
@ -13,6 +7,7 @@ interface PerpsPosition {
|
||||
amount: BigNumber
|
||||
pnl: PerpsPnL
|
||||
entryPrice: BigNumber
|
||||
closingFeeRate: BigNumber
|
||||
}
|
||||
|
||||
interface PerpPositionRow extends PerpsPosition {
|
||||
|
@ -4,6 +4,7 @@ import { BN_ZERO } from 'constants/math'
|
||||
import { ORACLE_DENOM } from 'constants/oracle'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { VaultPosition } from 'types/generated/mars-credit-manager/MarsCreditManager.types'
|
||||
import { Positions } from 'types/generated/mars-rover-health-computer/MarsRoverHealthComputer.types'
|
||||
import { byDenom } from 'utils/array'
|
||||
import { BN } from 'utils/helpers'
|
||||
import { convertApyToApr } from 'utils/parsers'
|
||||
@ -174,7 +175,7 @@ export function accumulateAmounts(denom: string, coins: BNCoin[]): BigNumber {
|
||||
}
|
||||
|
||||
// TODO: 📈 Add correct type mapping
|
||||
export function convertAccountToPositions(account: Account): PositionsWithoutPerps {
|
||||
export function convertAccountToPositions(account: Account, prices: BNCoin[]): Positions {
|
||||
return {
|
||||
account_id: account.id,
|
||||
debts: account.debts.map((debt) => ({
|
||||
@ -188,6 +189,66 @@ export function convertAccountToPositions(account: Account): PositionsWithoutPer
|
||||
amount: lend.amount.toString(),
|
||||
denom: lend.denom,
|
||||
})),
|
||||
perps: account.perps.map((perpPosition) => {
|
||||
// TODO: Check if this needs to be converted (in regards to HC decimal scaling)
|
||||
const currentPrice = prices.find(byDenom(perpPosition.denom))?.amount ?? BN_ZERO
|
||||
return {
|
||||
// Used
|
||||
base_denom: perpPosition.baseDenom,
|
||||
// Used
|
||||
closing_fee_rate: perpPosition.closingFeeRate.toString(),
|
||||
// Used
|
||||
current_price: currentPrice.toString(), // Check what prices we should pass to current and entry prices. Entry price will change when modifying positionl
|
||||
current_exec_price: currentPrice.toString(), // TODO: 📈 This needs to be queried
|
||||
denom: perpPosition.denom,
|
||||
// Used (for now, this might be changed)
|
||||
entry_price: currentPrice.toString(),
|
||||
// Used (not actually used, but it's in todo)
|
||||
entry_exec_price: currentPrice.toString(), // TODO: 📈 Check if this matters (currently just using entry price)
|
||||
// Used
|
||||
size: perpPosition.amount.toString() as any,
|
||||
unrealised_pnl: {
|
||||
coins: {
|
||||
closing_fee: perpPosition.pnl.unrealized.fees.abs().toCoin(),
|
||||
// Used
|
||||
pnl: perpPosition.pnl.unrealized.net.toPnLCoin(), // Used
|
||||
},
|
||||
amounts: {
|
||||
// CHeck if these are correct
|
||||
accrued_funding: perpPosition.pnl.unrealized.funding.amount
|
||||
.integerValue()
|
||||
.toString() as any,
|
||||
opening_fee: perpPosition.pnl.unrealized.fees.amount
|
||||
.abs()
|
||||
.integerValue()
|
||||
.toString() as any, // Add openning fee for modifying position
|
||||
closing_fee: perpPosition.pnl.unrealized.fees.amount
|
||||
.abs()
|
||||
.integerValue()
|
||||
.toString() as any, // Add closing fee for modifying position
|
||||
pnl: perpPosition.pnl.unrealized.net.amount.integerValue().toString() as any,
|
||||
price_pnl: perpPosition.pnl.unrealized.price.amount.integerValue().toString() as any,
|
||||
},
|
||||
values: {
|
||||
// This does not matter for health calculation
|
||||
accrued_funding: perpPosition.pnl.unrealized.funding.amount
|
||||
.integerValue()
|
||||
.toString() as any,
|
||||
closing_fee: perpPosition.pnl.unrealized.fees.amount.integerValue().toString() as any,
|
||||
pnl: perpPosition.pnl.unrealized.net.amount.integerValue().toString() as any,
|
||||
price_pnl: perpPosition.pnl.unrealized.price.amount.integerValue().toString() as any,
|
||||
},
|
||||
},
|
||||
realised_pnl: {
|
||||
// This does not matter for the health calculation
|
||||
accrued_funding: perpPosition.pnl.realized.funding.amount.toString() as any,
|
||||
closing_fee: perpPosition.pnl.realized.fees.amount.toString() as any,
|
||||
opening_fee: perpPosition.pnl.realized.fees.amount.toString() as any,
|
||||
pnl: perpPosition.pnl.realized.net.amount.toString() as any,
|
||||
price_pnl: perpPosition.pnl.realized.price.amount.toString() as any,
|
||||
},
|
||||
}
|
||||
}),
|
||||
vaults: account.vaults.map(
|
||||
(vault) =>
|
||||
({
|
||||
|
@ -2,16 +2,17 @@ import BigNumber from 'bignumber.js'
|
||||
|
||||
import { BN_ONE, BN_ZERO } from 'constants/math'
|
||||
import { BNCoin } from 'types/classes/BNCoin'
|
||||
import { BN } from 'utils/helpers'
|
||||
|
||||
export default function getPerpsPosition(
|
||||
asset: Asset,
|
||||
amount: BigNumber,
|
||||
tradeDirection: TradeDirection,
|
||||
) {
|
||||
): PerpsPosition {
|
||||
const perpsBaseDenom = 'ibc/F91EA2C0A23697A1048E08C2F787E3A58AC6F706A1CD2257A504925158CFC0F3'
|
||||
return {
|
||||
amount,
|
||||
closingFee: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ONE),
|
||||
closingFeeRate: BN(0.0005), // TODO: Pass the actual rate
|
||||
pnl: {
|
||||
net: BNCoin.fromDenomAndBigNumber(perpsBaseDenom, BN_ONE),
|
||||
realized: {
|
||||
|
2
src/utils/health_computer/index.d.ts
vendored
2
src/utils/health_computer/index.d.ts
vendored
@ -96,10 +96,10 @@ export interface InitOutput {
|
||||
h: number,
|
||||
) => void
|
||||
readonly liquidation_price_js: (a: number, b: number, c: number, d: number, e: number) => void
|
||||
readonly interface_version_8: () => void
|
||||
readonly allocate: (a: number) => number
|
||||
readonly deallocate: (a: number) => void
|
||||
readonly requires_iterator: () => void
|
||||
readonly interface_version_8: () => void
|
||||
readonly __wbindgen_malloc: (a: number, b: number) => number
|
||||
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number
|
||||
readonly __wbindgen_add_to_stack_pointer: (a: number) => number
|
||||
|
@ -296,6 +296,7 @@ async function __wbg_load(module, imports) {
|
||||
function __wbg_get_imports() {
|
||||
const imports = {}
|
||||
imports.wbg = {}
|
||||
imports.wbg.__wbg_log_117d9799fa4f6287 = function (arg0, arg1, arg2, arg3) {}
|
||||
imports.wbg.__wbindgen_object_clone_ref = function (arg0) {
|
||||
const ret = getObject(arg0)
|
||||
return addHeapObject(ret)
|
||||
|
Binary file not shown.
2
src/utils/health_computer/index_bg.wasm.d.ts
vendored
2
src/utils/health_computer/index_bg.wasm.d.ts
vendored
@ -15,10 +15,10 @@ export function max_swap_estimate_js(
|
||||
h: number,
|
||||
): void
|
||||
export function liquidation_price_js(a: number, b: number, c: number, d: number, e: number): void
|
||||
export function interface_version_8(): void
|
||||
export function allocate(a: number): number
|
||||
export function deallocate(a: number): void
|
||||
export function requires_iterator(): void
|
||||
export function interface_version_8(): void
|
||||
export function __wbindgen_malloc(a: number, b: number): number
|
||||
export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number
|
||||
export function __wbindgen_add_to_stack_pointer(a: number): number
|
||||
|
@ -118,7 +118,7 @@ export function resolvePerpsPositions(
|
||||
baseDenom: position.base_denom,
|
||||
amount: BN(position.size as any), // Amount is negative for SHORT positions
|
||||
tradeDirection: BN(position.size as any).isNegative() ? 'short' : 'long',
|
||||
// closingFee: BNCoin.fromCoin(position.pnl.coins.closing_fee),
|
||||
closingFeeRate: BN(position.closing_fee_rate),
|
||||
pnl: {
|
||||
net: BNCoin.fromDenomAndBigNumber(
|
||||
position.base_denom,
|
||||
|
Loading…
Reference in New Issue
Block a user