pub struct HealthCache {
    pub token_infos: Vec<TokenInfo>,
    /* private fields */
}
Expand description

Store information needed to compute account health

This is called a cache, because it extracts information from a MangoAccount and the Bank, Perp, oracle accounts once and then allows computing different types of health.

For compute-saving reasons, it also allows applying adjustments to the extracted positions. That’s often helpful for instructions that want to re-compute health after having made small, well-known changes to an account. Recomputing the HealthCache from scratch would be significantly more expensive.

However, there’s a real risk of getting the adjustments wrong and computing an inconsistent result, so particular care needs to be taken when this is done.

Fields§

§token_infos: Vec<TokenInfo>

Implementations§

source§

impl HealthCache

source

pub fn health(&self, health_type: HealthType) -> I80F48

source

pub fn health_ratio(&self, health_type: HealthType) -> I80F48

The health ratio is

  • 0 if health is 0 - meaning assets = liabs
  • 100 if there’s 2x as many assets as liabs
  • 200 if there’s 3x as many assets as liabs
  • MAX if liabs = 0

Maybe talking about the collateralization ratio assets/liabs is more intuitive?

source

pub fn health_assets_and_liabs_stable_assets( &self, health_type: HealthType ) -> (I80F48, I80F48)

source

pub fn health_assets_and_liabs_stable_liabs( &self, health_type: HealthType ) -> (I80F48, I80F48)

source

pub fn assets_and_liabs(&self) -> (I80F48, I80F48)

Computes the account assets and liabilities marked to market.

Contrary to health_assets_and_liabs, there’s no health weighing or adjustment for stable prices. It uses oracle prices directly.

Returns (assets, liabilities)

source

pub fn leverage(&self) -> I80F48

Computes the account leverage as ratio of liabs / (assets - liabs)

The goal of this function is to provide a quick overview over the accounts balance sheet. It’s not actually used to make any margin decisions internally and doesn’t account for open orders or stable / oracle price differences. Use health_ratio to make risk decisions.

source

pub fn token_info(&self, token_index: TokenIndex) -> Result<&TokenInfo>

source

pub fn token_info_index(&self, token_index: TokenIndex) -> Result<usize>

source

pub fn has_token_info(&self, token_index: TokenIndex) -> bool

source

pub fn perp_info(&self, perp_market_index: PerpMarketIndex) -> Result<&PerpInfo>

source

pub fn adjust_token_balance( &mut self, bank: &Bank, change: I80F48 ) -> Result<()>

Changes the cached user account token balance.

source

pub fn recompute_serum3_info( &mut self, serum_account: &Serum3Orders, open_orders: &OpenOrdersSlim, free_base_change: I80F48, free_quote_change: I80F48 ) -> Result<()>

Recompute the cached information about a serum market.

WARNING: You must also call recompute_token_weights() after all bank deposit/withdraw changes!

source

pub fn recompute_openbook_v2_info( &mut self, open_orders: &OpenbookV2Orders, open_orders_account: &OpenOrdersAccount, free_base_change: I80F48, free_quote_change: I80F48 ) -> Result<()>

Recompute the cached information about a serum market.

WARNING: You must also call recompute_token_weights() after all bank deposit/withdraw changes!

source

pub fn recompute_perp_info( &mut self, perp_position: &PerpPosition, perp_market: &PerpMarket ) -> Result<()>

source

pub fn has_liq_spot_assets(&self) -> bool

Liquidatable spot assets mean: actual token deposits and also a positive effective token balance and is available for asset liquidation

source

pub fn has_liq_spot_borrows(&self) -> bool

Liquidatable spot borrows mean: actual token borrows plus a negative effective token balance

source

pub fn has_possible_spot_liquidations(&self) -> bool

source

pub fn has_spot_open_orders_funds(&self) -> bool

source

pub fn has_perp_open_orders(&self) -> bool

source

pub fn has_perp_base_positions(&self) -> bool

source

pub fn has_perp_open_fills(&self) -> bool

source

pub fn has_perp_positive_pnl_no_base(&self) -> bool

source

pub fn has_perp_negative_pnl_no_base(&self) -> bool

source

pub fn has_phase1_liquidatable(&self) -> bool

Phase1 is spot/perp order cancellation and spot settlement since neither of these come at a cost to the liqee

source

pub fn require_after_phase1_liquidation(&self) -> Result<()>

source

pub fn in_phase1_liquidation(&self) -> bool

source

pub fn has_phase2_liquidatable(&self) -> bool

Phase2 is for:

  • token-token liquidation
  • liquidation of perp base positions (an open fill isn’t liquidatable, but it changes the base position, so need to wait for it to be processed…)
  • bringing positive trusted perp pnl into the spot realm
source

pub fn require_after_phase2_liquidation(&self) -> Result<()>

source

pub fn in_phase2_liquidation(&self) -> bool

source

pub fn has_phase3_liquidatable(&self) -> bool

Phase3 is bankruptcy:

  • token bankruptcy
  • perp bankruptcy
source

pub fn in_phase3_liquidation(&self) -> bool

source

pub fn effective_token_balances( &self, health_type: HealthType ) -> Vec<TokenBalance>

Returns token balances that account for spot and perp contributions

Spot contributions are just the regular deposits or borrows, as well as from free funds on spot open orders accounts.

Perp contributions come from perp positions in markets that use the token as a settle token: For these the hupnl is added to the total because that’s the risk-adjusted expected to be gained or lost from settlement.

source

pub fn perp_max_settle(&self, settle_token_index: TokenIndex) -> Result<I80F48>

Returns how much pnl is settleable for a given settle token.

The idea of this limit is that settlement is only permissible as long as there are non-perp assets that back it. If an account with 1 USD deposited somehow gets a large negative perp upnl, it should not be allowed to settle that perp loss into the spot world fully (because of perp/spot isolation, translating perp losses and gains into tokens is restricted). Only 1 USD worth would be allowed.

Effectively, there’s a health variant “perp settle health” that ignores negative token contributions from perp markets. Settlement is allowed as long as perp settle health remains >= 0.

For example, if perp_settle_health is 50 USD, then the settleable amount in SOL would depend on the SOL price, the user’s current spot balance and the SOL weights: We need to compute how much the user’s spot SOL balance may decrease before the perp_settle_health becomes zero.

Note that the account’s actual health would not change during settling negative upnl: the spot balance goes down but the perp hupnl goes up accordingly.

Examples:

  • An account may have maint_health < 0, but settling perp pnl could still be allowed. (+100 USDC health, -50 USDT health, -50 perp health -> allow settling 50 health worth)
  • Positive health from trusted pnl markets counts
  • If overall health is 0 with two trusted perp pnl < 0, settling may still be possible. (+100 USDC health, -150 perp1 health, -150 perp2 health -> allow settling 100 health worth)
  • Positive trusted perp pnl can enable settling. (+100 trusted perp1 health, -100 perp2 health -> allow settling of 100 health worth)
source

pub fn total_spot_potential( &self, health_type: HealthType, token_index: TokenIndex ) -> Result<I80F48>

source

pub fn check_has_all_spot_infos_for_token( &self, account: &MangoAccountRef<'_>, token_index: TokenIndex ) -> Result<()>

Verifies that the health cache has information on all account’s active spot markets that touch the token_index

source§

impl HealthCache

source

pub fn is_liquidatable(&self) -> bool

source

pub fn max_swap_source_for_health_ratio_ignoring_limits( &self, account: &MangoAccountValue, source_bank: &Bank, source_oracle_price: I80F48, target_bank: &Bank, price: I80F48, min_ratio: I80F48 ) -> Result<I80F48>

Verifies neither the net borrow or deposit limits

source

pub fn max_swap_source_for_health_ratio_with_limits( &self, account: &MangoAccountValue, source_bank: &Bank, source_oracle_price: I80F48, target_bank: &Bank, price: I80F48, min_ratio: I80F48 ) -> Result<I80F48>

source

pub fn max_swap_source_for_health_fn( &self, account: &MangoAccountValue, source_bank: &Bank, source_oracle_price: I80F48, target_bank: &Bank, price: I80F48, min_fn_value: I80F48, target_fn: fn(_: &HealthCache) -> I80F48 ) -> Result<I80F48>

How many source native tokens may be swapped for target tokens while staying above the min_ratio health ratio.

price: The amount of target native you receive for one source native. So if we swap BTC -> SOL and they’re at ui prices of $20000 and $40, that means price should be 500000 native_SOL for a native_BTC. Because 1 BTC gives you 500 SOL so 1e6 native_BTC gives you 500e9 native_SOL.

Positions for the source and deposit token index must already exist in the account.

NOTE: keep getMaxSourceForTokenSwap in ts/client in sync with changes here

source

pub fn max_perp_for_health_ratio( &self, perp_market_index: PerpMarketIndex, price: I80F48, side: PerpOrderSide, min_ratio: I80F48 ) -> Result<i64>

NOTE: keep getMaxSourceForTokenSwap in ts/client in sync with changes here

source

pub fn max_borrow_for_health_ratio( &self, account: &MangoAccountValue, bank: &Bank, min_ratio: I80F48 ) -> Result<I80F48>

Trait Implementations§

source§

impl Clone for HealthCache

source§

fn clone(&self) -> HealthCache

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for HealthCache

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere T: 'a,

§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

§

impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere T: 'a,

§

fn implicit( self, class: Class, constructed: bool, tag: u32 ) -> TaggedParser<'a, Implicit, Self, E>

source§

impl<T> Az for T

source§

fn az<Dst>(self) -> Dstwhere T: Cast<Dst>,

Casts the value.
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

const: unstable · source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

const: unstable · source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<Src, Dst> CastFrom<Src> for Dstwhere Src: Cast<Dst>,

source§

fn cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> CheckedAs for T

source§

fn checked_as<Dst>(self) -> Option<Dst>where T: CheckedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere Src: CheckedCast<Dst>,

source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
source§

impl<T> DynClone for Twhere T: Clone,

source§

fn __clone_box(&self, _: Private) -> *mut ()

source§

impl<T> From<T> for T

const: unstable · source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for Twhere U: From<T>,

const: unstable · source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere Dst: LosslessTryFrom<Src>,

source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
source§

impl<Src, Dst> LossyInto<Dst> for Srcwhere Dst: LossyFrom<Src>,

source§

fn lossy_into(self) -> Dst

Performs the conversion.
source§

impl<T> OverflowingAs for T

source§

fn overflowing_as<Dst>(self) -> (Dst, bool)where T: OverflowingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere Src: OverflowingCast<Dst>,

source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
§

impl<T> Pointable for T

§

const ALIGN: usize = mem::align_of::<T>()

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T> SaturatingAs for T

source§

fn saturating_as<Dst>(self) -> Dstwhere T: SaturatingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere Src: SaturatingCast<Dst>,

source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
source§

impl<T> ToOwned for Twhere T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
const: unstable · source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
const: unstable · source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> UnwrappedAs for T

source§

fn unwrapped_as<Dst>(self) -> Dstwhere T: UnwrappedCast<Dst>,

Casts the value.
source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere Src: UnwrappedCast<Dst>,

source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
§

impl<V, T> VZip<V> for Twhere V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

impl<T> WrappingAs for T

source§

fn wrapping_as<Dst>(self) -> Dstwhere T: WrappingCast<Dst>,

Casts the value.
source§

impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere Src: WrappingCast<Dst>,

source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.