Health: cleanup and new functions for ratio and assets/liabs
This commit is contained in:
parent
6f758ff25b
commit
86a84396f5
|
@ -17,8 +17,9 @@ pub fn compute_account_data(ctx: Context<ComputeAccountData>) -> Result<()> {
|
|||
|
||||
let account_retriever = ScanningAccountRetriever::new(ctx.remaining_accounts, &group_pk)?;
|
||||
|
||||
let init_health = compute_health(&account, HealthType::Init, &account_retriever)?;
|
||||
let maint_health = compute_health(&account, HealthType::Maint, &account_retriever)?;
|
||||
let health_cache = new_health_cache(&account, &account_retriever)?;
|
||||
let init_health = health_cache.health(HealthType::Init);
|
||||
let maint_health = health_cache.health(HealthType::Maint);
|
||||
|
||||
let equity = compute_equity(&account, &account_retriever)?;
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ pub fn liq_token_with_token(
|
|||
|
||||
// Initial liqee health check
|
||||
let mut liqee_health_cache = new_health_cache(&liqee, &account_retriever)?;
|
||||
let init_health = liqee_health_cache.health(HealthType::Init)?;
|
||||
let init_health = liqee_health_cache.health(HealthType::Init);
|
||||
if liqee.being_liquidated() {
|
||||
if init_health > I80F48::ZERO {
|
||||
liqee.set_being_liquidated(false);
|
||||
|
@ -54,7 +54,7 @@ pub fn liq_token_with_token(
|
|||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
let maint_health = liqee_health_cache.health(HealthType::Maint)?;
|
||||
let maint_health = liqee_health_cache.health(HealthType::Maint);
|
||||
require!(maint_health < I80F48::ZERO, MangoError::SomeError);
|
||||
liqee.set_being_liquidated(true);
|
||||
}
|
||||
|
@ -211,11 +211,11 @@ pub fn liq_token_with_token(
|
|||
}
|
||||
|
||||
// Check liqee health again
|
||||
let maint_health = liqee_health_cache.health(HealthType::Maint)?;
|
||||
let maint_health = liqee_health_cache.health(HealthType::Maint);
|
||||
if maint_health < I80F48::ZERO {
|
||||
liqee.set_bankrupt(!liqee_health_cache.has_liquidatable_assets());
|
||||
} else {
|
||||
let init_health = liqee_health_cache.health(HealthType::Init)?;
|
||||
let init_health = liqee_health_cache.health(HealthType::Init);
|
||||
|
||||
// this is equivalent to one native USDC or 1e-6 USDC
|
||||
// This is used as threshold to flip flag instead of 0 because of dust issues
|
||||
|
|
|
@ -398,7 +398,7 @@ pub fn compute_health_from_fixed_accounts(
|
|||
begin_perp: cm!(active_token_len * 2),
|
||||
begin_serum3: cm!(active_token_len * 2 + active_perp_len),
|
||||
};
|
||||
new_health_cache(account, &retriever)?.health(health_type)
|
||||
Ok(new_health_cache(account, &retriever)?.health(health_type))
|
||||
}
|
||||
|
||||
/// Compute health with an arbitrary AccountRetriever
|
||||
|
@ -407,7 +407,7 @@ pub fn compute_health(
|
|||
health_type: HealthType,
|
||||
retriever: &impl AccountRetriever,
|
||||
) -> Result<I80F48> {
|
||||
new_health_cache(account, retriever)?.health(health_type)
|
||||
Ok(new_health_cache(account, retriever)?.health(health_type))
|
||||
}
|
||||
|
||||
struct TokenInfo {
|
||||
|
@ -439,6 +439,16 @@ impl TokenInfo {
|
|||
HealthType::Maint => self.maint_liab_weight,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn health_contribution(&self, health_type: HealthType) -> I80F48 {
|
||||
let weight = if self.balance.is_negative() {
|
||||
self.liab_weight(health_type)
|
||||
} else {
|
||||
self.asset_weight(health_type)
|
||||
};
|
||||
cm!(self.balance * weight)
|
||||
}
|
||||
}
|
||||
|
||||
struct Serum3Info {
|
||||
|
@ -532,21 +542,13 @@ pub struct HealthCache {
|
|||
}
|
||||
|
||||
impl HealthCache {
|
||||
pub fn health(&self, health_type: HealthType) -> Result<I80F48> {
|
||||
pub fn health(&self, health_type: HealthType) -> I80F48 {
|
||||
let mut health = I80F48::ZERO;
|
||||
for token_info in self.token_infos.iter() {
|
||||
let contrib = health_contribution(health_type, token_info, token_info.balance)?;
|
||||
let sum = |contrib| {
|
||||
health = cm!(health + contrib);
|
||||
}
|
||||
for serum3_info in self.serum3_infos.iter() {
|
||||
let contrib = serum3_info.health_contribution(health_type, &self.token_infos);
|
||||
health = cm!(health + contrib);
|
||||
}
|
||||
for perp_info in self.perp_infos.iter() {
|
||||
let contrib = perp_info.health_contribution(health_type);
|
||||
health = cm!(health + contrib);
|
||||
}
|
||||
Ok(health)
|
||||
};
|
||||
self.health_sum(health_type, sum);
|
||||
health
|
||||
}
|
||||
|
||||
pub fn adjust_token_balance(&mut self, token_index: TokenIndex, change: I80F48) -> Result<()> {
|
||||
|
@ -580,23 +582,54 @@ impl HealthCache {
|
|||
.any(|p| p.quote.is_negative() || p.base != 0);
|
||||
spot_borrows || perp_borrows
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute health contribution for a given balance
|
||||
/// wart: independent of the balance stored in TokenInfo
|
||||
/// balance is in health-reference-token native units
|
||||
#[inline(always)]
|
||||
fn health_contribution(
|
||||
health_type: HealthType,
|
||||
info: &TokenInfo,
|
||||
balance: I80F48,
|
||||
) -> Result<I80F48> {
|
||||
let weight = if balance.is_negative() {
|
||||
info.liab_weight(health_type)
|
||||
} else {
|
||||
info.asset_weight(health_type)
|
||||
};
|
||||
Ok(cm!(balance * weight))
|
||||
fn health_sum(&self, health_type: HealthType, mut action: impl FnMut(I80F48)) {
|
||||
for token_info in self.token_infos.iter() {
|
||||
let contrib = token_info.health_contribution(health_type);
|
||||
action(contrib);
|
||||
}
|
||||
for serum3_info in self.serum3_infos.iter() {
|
||||
let contrib = serum3_info.health_contribution(health_type, &self.token_infos);
|
||||
action(contrib);
|
||||
}
|
||||
for perp_info in self.perp_infos.iter() {
|
||||
let contrib = perp_info.health_contribution(health_type);
|
||||
action(contrib);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sum of only the positive health components (assets) and
|
||||
/// sum of absolute values of all negative health components (liabs, always >= 0)
|
||||
pub fn health_assets_and_liabs(&self, health_type: HealthType) -> (I80F48, I80F48) {
|
||||
let mut assets = I80F48::ZERO;
|
||||
let mut liabs = I80F48::ZERO;
|
||||
let sum = |contrib| {
|
||||
if contrib > 0 {
|
||||
assets = cm!(assets + contrib);
|
||||
} else {
|
||||
liabs = cm!(liabs - contrib);
|
||||
}
|
||||
};
|
||||
self.health_sum(health_type, sum);
|
||||
(assets, liabs)
|
||||
}
|
||||
|
||||
/// 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?
|
||||
pub fn health_ratio(&self, health_type: HealthType) -> I80F48 {
|
||||
let (assets, liabs) = self.health_assets_and_liabs(health_type);
|
||||
let hundred = I80F48::from(100);
|
||||
if liabs > 0 {
|
||||
cm!(hundred * (assets - liabs) / liabs)
|
||||
} else {
|
||||
I80F48::MAX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a HealthCache for an account and its health accounts.
|
||||
|
|
Loading…
Reference in New Issue