Serum: health based on worst case order outcome

This commit is contained in:
Christian Kamm 2022-03-17 12:05:07 +01:00
parent 0593aa81f7
commit 9351d0652d
1 changed files with 54 additions and 21 deletions

View File

@ -29,6 +29,25 @@ struct TokenInfo<'a> {
balance: I80F48,
}
fn health_contribution(bank: &Bank, price: I80F48, balance: I80F48) -> Result<I80F48> {
Ok(if balance.is_negative() {
cm!(balance * price * bank.init_liab_weight)
} else {
cm!(balance * price * bank.init_asset_weight)
})
}
fn pair_health(
info1: &TokenInfo,
balance1: I80F48,
info2: &TokenInfo,
balance2: I80F48,
) -> Result<I80F48> {
let health1 = health_contribution(&info1.bank, info1.oracle_price, balance1)?;
let health2 = health_contribution(&info2.bank, info2.oracle_price, balance2)?;
Ok(cm!(health1 + health2))
}
fn strip_dex_padding<'a>(acc: &'a AccountInfo) -> Result<Ref<'a, [u8]>> {
require!(acc.data_len() >= 12, MangoError::SomeError);
let unpadded_data: Ref<[u8]> = Ref::map(acc.try_borrow_data()?, |data| {
@ -103,38 +122,52 @@ fn compute_health_detail(
.position(|ti| ti.bank.token_index == serum_account.quote_token_index)
.ok_or(error!(MangoError::SomeError))?;
let base_info = &token_infos[base_index];
let quote_info = &token_infos[quote_index];
let mut base = base_info.balance;
let mut quote = quote_info.balance;
let oo = load_open_orders(oo_ai)?;
// add the amounts that are freely settleable
token_infos[base_index].balance += I80F48::from_num(oo.native_coin_free);
token_infos[quote_index].balance +=
I80F48::from_num(oo.native_pc_free + oo.referrer_rebates_accrued);
let base_free = I80F48::from_num(oo.native_coin_free);
let quote_free = I80F48::from_num(cm!(oo.native_pc_free + oo.referrer_rebates_accrued));
base = cm!(base + base_free);
quote = cm!(quote + quote_free);
// for the amounts that are reserved for orders, compute the worst case for health
// by checking if everything-is-base or everything-is-quote produces worse
// outcomes
// TODO: that kind of approach may no longer be possible with each
// market potentially having two different tokens involved?
let reserved_base = oo.native_coin_total - oo.native_coin_free;
let reserved_quote = oo.native_pc_total - oo.native_pc_free;
// TODO: do it, this is just a stub
token_infos[base_index].balance += I80F48::from_num(reserved_base);
token_infos[quote_index].balance += I80F48::from_num(reserved_quote);
let reserved_base = I80F48::from_num(cm!(oo.native_coin_total - oo.native_coin_free));
let reserved_quote = I80F48::from_num(cm!(oo.native_pc_total - oo.native_pc_free));
let all_in_base = cm!(base
+ reserved_base
+ reserved_quote * quote_info.oracle_price / base_info.oracle_price);
let all_in_quote = cm!(quote
+ reserved_quote
+ reserved_base * base_info.oracle_price / quote_info.oracle_price);
if pair_health(base_info, all_in_base, quote_info, quote)?
< pair_health(base_info, base, quote_info, all_in_quote)?
{
base = all_in_base;
} else {
quote = all_in_quote;
}
token_infos[base_index].balance = base;
token_infos[quote_index].balance = quote;
}
// convert the token balance to health
let mut asset_health = I80F48::ZERO;
let mut liability_health = I80F48::ZERO; // positive
let mut health = I80F48::ZERO;
for token_info in token_infos.iter() {
let bank = &token_info.bank;
if token_info.balance.is_negative() {
liability_health = cm!(liability_health
- bank.init_liab_weight * token_info.balance * token_info.oracle_price);
} else {
asset_health = cm!(asset_health
+ bank.init_asset_weight * token_info.balance * token_info.oracle_price);
}
let contrib = health_contribution(
&token_info.bank,
token_info.oracle_price,
token_info.balance,
)?;
health = cm!(health + contrib);
}
Ok(cm!(asset_health - liability_health))
Ok(health)
}