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 itertools::Itertools;
|
||||||
use mango_v4::instructions::{Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side};
|
use mango_v4::instructions::{Serum3OrderType, Serum3SelfTradeBehavior, Serum3Side};
|
||||||
use mango_v4::state::{
|
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;
|
use solana_client::rpc_client::RpcClient;
|
||||||
|
@ -34,6 +34,7 @@ pub struct MangoClient {
|
||||||
pub admin: Keypair,
|
pub admin: Keypair,
|
||||||
pub mango_account_cache: (Pubkey, MangoAccount),
|
pub mango_account_cache: (Pubkey, MangoAccount),
|
||||||
pub group: Pubkey,
|
pub group: Pubkey,
|
||||||
|
pub group_cache: Group,
|
||||||
// TODO: future: this may not scale if there's thousands of mints, probably some function
|
// 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)
|
// wrapping getMultipleAccounts is needed (or bettew: we provide this data as a service)
|
||||||
pub banks_cache: HashMap<String, Vec<(Pubkey, Bank)>>,
|
pub banks_cache: HashMap<String, Vec<(Pubkey, Bank)>>,
|
||||||
|
@ -75,6 +76,8 @@ impl MangoClient {
|
||||||
)
|
)
|
||||||
.0;
|
.0;
|
||||||
|
|
||||||
|
let group_data = program.account::<Group>(group)?;
|
||||||
|
|
||||||
// Mango Account
|
// Mango Account
|
||||||
let mut mango_account_tuples = program.accounts::<MangoAccount>(vec![
|
let mut mango_account_tuples = program.accounts::<MangoAccount>(vec![
|
||||||
RpcFilterType::Memcmp(Memcmp {
|
RpcFilterType::Memcmp(Memcmp {
|
||||||
|
@ -238,6 +241,7 @@ impl MangoClient {
|
||||||
payer,
|
payer,
|
||||||
mango_account_cache,
|
mango_account_cache,
|
||||||
group,
|
group,
|
||||||
|
group_cache: group_data,
|
||||||
banks_cache,
|
banks_cache,
|
||||||
banks_cache_by_token_index,
|
banks_cache_by_token_index,
|
||||||
mint_infos_cache,
|
mint_infos_cache,
|
||||||
|
@ -916,6 +920,73 @@ impl MangoClient {
|
||||||
})
|
})
|
||||||
.send()
|
.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 {
|
fn from_serum_style_pubkey(d: &[u64; 4]) -> Pubkey {
|
||||||
|
|
|
@ -121,6 +121,7 @@ pub fn process_account(
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
// TODO: configurable
|
// TODO: configurable
|
||||||
let min_health_ratio = I80F48::from_num(50.0f64);
|
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)?;
|
let account = load_mango_account_from_chain::<MangoAccount>(chain_data, pubkey)?;
|
||||||
|
|
||||||
|
@ -129,18 +130,14 @@ pub fn process_account(
|
||||||
.expect("always ok")
|
.expect("always ok")
|
||||||
.health(HealthType::Maint);
|
.health(HealthType::Maint);
|
||||||
|
|
||||||
// try liquidating
|
|
||||||
if maint_health.is_negative() {
|
|
||||||
// find asset and liab tokens
|
// find asset and liab tokens
|
||||||
let mut tokens = account
|
let mut tokens = account
|
||||||
.tokens
|
.tokens
|
||||||
.iter_active()
|
.iter_active()
|
||||||
.map(|token| {
|
.map(|token| {
|
||||||
let mint_info_pk = mint_infos.get(&token.token_index).expect("always Ok");
|
let mint_info_pk = mint_infos.get(&token.token_index).expect("always Ok");
|
||||||
let mint_info =
|
let mint_info = load_mango_account_from_chain::<MintInfo>(chain_data, mint_info_pk)?;
|
||||||
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 bank =
|
|
||||||
load_mango_account_from_chain::<Bank>(chain_data, &mint_info.first_bank())?;
|
|
||||||
let oracle = chain_data.account(&mint_info.oracle)?;
|
let oracle = chain_data.account(&mint_info.oracle)?;
|
||||||
let price = oracle_price(
|
let price = oracle_price(
|
||||||
&KeyedAccountSharedData::new(mint_info.oracle, oracle.clone()),
|
&KeyedAccountSharedData::new(mint_info.oracle, oracle.clone()),
|
||||||
|
@ -151,13 +148,8 @@ pub fn process_account(
|
||||||
})
|
})
|
||||||
.collect::<anyhow::Result<Vec<(TokenIndex, &Bank, I80F48)>>>()?;
|
.collect::<anyhow::Result<Vec<(TokenIndex, &Bank, I80F48)>>>()?;
|
||||||
tokens.sort_by(|a, b| a.2.cmp(&b.2));
|
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>(
|
let liqor = load_mango_account_from_chain::<MangoAccount>(
|
||||||
chain_data,
|
chain_data,
|
||||||
&mango_client.mango_account_cache.0,
|
&mango_client.mango_account_cache.0,
|
||||||
|
@ -166,13 +158,38 @@ pub fn process_account(
|
||||||
let health_cache =
|
let health_cache =
|
||||||
new_health_cache_(chain_data, mint_infos, perp_markets, liqor).expect("always ok");
|
new_health_cache_(chain_data, mint_infos, perp_markets, liqor).expect("always ok");
|
||||||
|
|
||||||
health_cache.max_swap_source_for_health_ratio(
|
let amount =
|
||||||
*liab_token_index,
|
health_cache.max_swap_source_for_health_ratio(source, target, min_health_ratio)?;
|
||||||
*asset_token_index,
|
Ok(amount)
|
||||||
min_health_ratio,
|
|
||||||
)?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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 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
|
// 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")?;
|
.context("sending liq_token_with_token")?;
|
||||||
log::info!(
|
log::info!(
|
||||||
"Liquidated {}..., maint_health was {}, tx sig {:?}",
|
"Liquidated token with token for {}..., maint_health was {}, tx sig {:?}",
|
||||||
&pubkey.to_string()[..3],
|
&pubkey.to_string()[..3],
|
||||||
maint_health,
|
maint_health,
|
||||||
sig
|
sig
|
||||||
|
|
Loading…
Reference in New Issue