Liq: basic liq_token_bankruptcy use
This commit is contained in:
parent
74873ad46b
commit
bbca1d8763
|
@ -12,7 +12,7 @@ use fixed::types::I80F48;
|
|||
use itertools::Itertools;
|
||||
use mango_v4::instructions::{Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side};
|
||||
use mango_v4::state::{
|
||||
Bank, MangoAccount, MintInfo, PerpMarket, PerpMarketIndex, Serum3Market, TokenIndex,
|
||||
Bank, Group, MangoAccount, MintInfo, PerpMarket, PerpMarketIndex, Serum3Market, TokenIndex,
|
||||
};
|
||||
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
|
@ -34,6 +34,7 @@ pub struct MangoClient {
|
|||
pub admin: Keypair,
|
||||
pub mango_account_cache: (Pubkey, MangoAccount),
|
||||
pub group: Pubkey,
|
||||
pub group_cache: Group,
|
||||
// TODO: future: this may not scale if there's thousands of mints, probably some function
|
||||
// wrapping getMultipleAccounts is needed (or bettew: we provide this data as a service)
|
||||
pub banks_cache: HashMap<String, Vec<(Pubkey, Bank)>>,
|
||||
|
@ -75,6 +76,8 @@ impl MangoClient {
|
|||
)
|
||||
.0;
|
||||
|
||||
let group_data = program.account::<Group>(group)?;
|
||||
|
||||
// Mango Account
|
||||
let mut mango_account_tuples = program.accounts::<MangoAccount>(vec![
|
||||
RpcFilterType::Memcmp(Memcmp {
|
||||
|
@ -238,6 +241,7 @@ impl MangoClient {
|
|||
payer,
|
||||
mango_account_cache,
|
||||
group,
|
||||
group_cache: group_data,
|
||||
banks_cache,
|
||||
banks_cache_by_token_index,
|
||||
mint_infos_cache,
|
||||
|
@ -916,6 +920,73 @@ impl MangoClient {
|
|||
})
|
||||
.send()
|
||||
}
|
||||
|
||||
pub fn liq_token_bankruptcy(
|
||||
&self,
|
||||
liqee: (&Pubkey, &MangoAccount),
|
||||
liab_token_index: TokenIndex,
|
||||
max_liab_transfer: I80F48,
|
||||
) -> Result<Signature, anchor_client::ClientError> {
|
||||
let quote_token_index = 0;
|
||||
|
||||
let (_, quote_mint_info, _) = self
|
||||
.mint_infos_cache_by_token_index
|
||||
.get("e_token_index)
|
||||
.unwrap();
|
||||
let (liab_mint_info_key, liab_mint_info, _) = self
|
||||
.mint_infos_cache_by_token_index
|
||||
.get(&liab_token_index)
|
||||
.unwrap();
|
||||
|
||||
let bank_remaining_ams = liab_mint_info
|
||||
.banks()
|
||||
.iter()
|
||||
.map(|bank_pubkey| AccountMeta {
|
||||
pubkey: *bank_pubkey,
|
||||
is_signer: false,
|
||||
is_writable: true,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let health_remaining_ams = self
|
||||
.derive_liquidation_health_check_remaining_account_metas(
|
||||
liqee.1,
|
||||
quote_token_index,
|
||||
liab_token_index,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
self.program()
|
||||
.request()
|
||||
.instruction(Instruction {
|
||||
program_id: mango_v4::id(),
|
||||
accounts: {
|
||||
let mut ams = anchor_lang::ToAccountMetas::to_account_metas(
|
||||
&mango_v4::accounts::LiqTokenBankruptcy {
|
||||
group: self.group(),
|
||||
liqee: *liqee.0,
|
||||
liqor: self.mango_account_cache.0,
|
||||
liqor_owner: self.payer.pubkey(),
|
||||
liab_mint_info: *liab_mint_info_key,
|
||||
quote_vault: quote_mint_info.first_vault(),
|
||||
insurance_vault: self.group_cache.insurance_vault,
|
||||
token_program: Token::id(),
|
||||
},
|
||||
None,
|
||||
);
|
||||
ams.extend(bank_remaining_ams);
|
||||
ams.extend(health_remaining_ams);
|
||||
ams
|
||||
},
|
||||
data: anchor_lang::InstructionData::data(
|
||||
&mango_v4::instruction::LiqTokenBankruptcy {
|
||||
liab_token_index,
|
||||
max_liab_transfer,
|
||||
},
|
||||
),
|
||||
})
|
||||
.send()
|
||||
}
|
||||
}
|
||||
|
||||
fn from_serum_style_pubkey(d: &[u64; 4]) -> Pubkey {
|
||||
|
|
|
@ -121,6 +121,7 @@ pub fn process_account(
|
|||
) -> anyhow::Result<()> {
|
||||
// TODO: configurable
|
||||
let min_health_ratio = I80F48::from_num(50.0f64);
|
||||
let quote_token_index = 0;
|
||||
|
||||
let account = load_mango_account_from_chain::<MangoAccount>(chain_data, pubkey)?;
|
||||
|
||||
|
@ -129,18 +130,14 @@ pub fn process_account(
|
|||
.expect("always ok")
|
||||
.health(HealthType::Maint);
|
||||
|
||||
// try liquidating
|
||||
if maint_health.is_negative() {
|
||||
// find asset and liab tokens
|
||||
let mut tokens = account
|
||||
.tokens
|
||||
.iter_active()
|
||||
.map(|token| {
|
||||
let mint_info_pk = mint_infos.get(&token.token_index).expect("always Ok");
|
||||
let mint_info =
|
||||
load_mango_account_from_chain::<MintInfo>(chain_data, mint_info_pk)?;
|
||||
let bank =
|
||||
load_mango_account_from_chain::<Bank>(chain_data, &mint_info.first_bank())?;
|
||||
let mint_info = load_mango_account_from_chain::<MintInfo>(chain_data, mint_info_pk)?;
|
||||
let bank = load_mango_account_from_chain::<Bank>(chain_data, &mint_info.first_bank())?;
|
||||
let oracle = chain_data.account(&mint_info.oracle)?;
|
||||
let price = oracle_price(
|
||||
&KeyedAccountSharedData::new(mint_info.oracle, oracle.clone()),
|
||||
|
@ -151,13 +148,8 @@ pub fn process_account(
|
|||
})
|
||||
.collect::<anyhow::Result<Vec<(TokenIndex, &Bank, I80F48)>>>()?;
|
||||
tokens.sort_by(|a, b| a.2.cmp(&b.2));
|
||||
if tokens.len() < 2 {
|
||||
anyhow::bail!("mango account {}, has less than 2 active tokens", pubkey);
|
||||
}
|
||||
let (asset_token_index, _asset_bank, _asset_price) = tokens.last().unwrap();
|
||||
let (liab_token_index, _liab_bank, _liab_price) = tokens.first().unwrap();
|
||||
|
||||
let max_liab_transfer = {
|
||||
let get_max_liab_transfer = |source, target| -> anyhow::Result<I80F48> {
|
||||
let liqor = load_mango_account_from_chain::<MangoAccount>(
|
||||
chain_data,
|
||||
&mango_client.mango_account_cache.0,
|
||||
|
@ -166,13 +158,38 @@ pub fn process_account(
|
|||
let health_cache =
|
||||
new_health_cache_(chain_data, mint_infos, perp_markets, liqor).expect("always ok");
|
||||
|
||||
health_cache.max_swap_source_for_health_ratio(
|
||||
*liab_token_index,
|
||||
*asset_token_index,
|
||||
min_health_ratio,
|
||||
)?
|
||||
let amount =
|
||||
health_cache.max_swap_source_for_health_ratio(source, target, min_health_ratio)?;
|
||||
Ok(amount)
|
||||
};
|
||||
|
||||
// try liquidating
|
||||
if account.is_bankrupt() {
|
||||
if tokens.is_empty() {
|
||||
anyhow::bail!("mango account {}, is bankrupt has no active tokens", pubkey);
|
||||
}
|
||||
let (liab_token_index, _liab_bank, _liab_price) = tokens.first().unwrap();
|
||||
|
||||
let max_liab_transfer = get_max_liab_transfer(*liab_token_index, quote_token_index)?;
|
||||
|
||||
let sig = mango_client
|
||||
.liq_token_bankruptcy((pubkey, account), *liab_token_index, max_liab_transfer)
|
||||
.context("sending liq_token_bankruptcy")?;
|
||||
log::info!(
|
||||
"Liquidated bankruptcy for {}..., maint_health was {}, tx sig {:?}",
|
||||
&pubkey.to_string()[..3],
|
||||
maint_health,
|
||||
sig
|
||||
);
|
||||
} else if maint_health.is_negative() {
|
||||
if tokens.len() < 2 {
|
||||
anyhow::bail!("mango account {}, has less than 2 active tokens", pubkey);
|
||||
}
|
||||
let (asset_token_index, _asset_bank, _asset_price) = tokens.last().unwrap();
|
||||
let (liab_token_index, _liab_bank, _liab_price) = tokens.first().unwrap();
|
||||
|
||||
let max_liab_transfer = get_max_liab_transfer(*liab_token_index, *asset_token_index)?;
|
||||
|
||||
//
|
||||
// TODO: log liqor's assets in UI form
|
||||
// TODO: log liquee's liab_needed, need to refactor program code to be able to be accessed from client side
|
||||
|
@ -189,7 +206,7 @@ pub fn process_account(
|
|||
)
|
||||
.context("sending liq_token_with_token")?;
|
||||
log::info!(
|
||||
"Liquidated {}..., maint_health was {}, tx sig {:?}",
|
||||
"Liquidated token with token for {}..., maint_health was {}, tx sig {:?}",
|
||||
&pubkey.to_string()[..3],
|
||||
maint_health,
|
||||
sig
|
||||
|
|
Loading…
Reference in New Issue