liquidator: better startup for tests

This commit is contained in:
Christian Kamm 2023-08-14 15:06:28 +02:00
parent f1e2b521f2
commit a04f5e0df0
2 changed files with 18 additions and 60 deletions

View File

@ -7,9 +7,8 @@ use anchor_client::Cluster;
use clap::Parser; use clap::Parser;
use mango_v4::state::{PerpMarketIndex, TokenIndex}; use mango_v4::state::{PerpMarketIndex, TokenIndex};
use mango_v4_client::{ use mango_v4_client::{
account_update_stream, chain_data, keypair_from_cli, snapshot_source, websocket_source, account_update_stream, chain_data, keypair_from_cli, snapshot_source, websocket_source, Client,
AsyncChannelSendUnlessFull, Client, MangoClient, MangoClientError, MangoGroupContext, MangoClient, MangoClientError, MangoGroupContext, TransactionBuilderConfig,
TransactionBuilderConfig,
}; };
use itertools::Itertools; use itertools::Itertools;
@ -25,7 +24,7 @@ pub mod token_swap_info;
pub mod trigger_tcs; pub mod trigger_tcs;
pub mod util; pub mod util;
use crate::util::{is_mango_account, is_mango_bank, is_mint_info, is_perp_market}; use crate::util::{is_mango_account, is_mint_info, is_perp_market};
// jemalloc seems to be better at keeping the memory footprint reasonable over // jemalloc seems to be better at keeping the memory footprint reasonable over
// longer periods of time // longer periods of time
@ -317,9 +316,6 @@ async fn main() -> anyhow::Result<()> {
last_persistent_error_report: Instant::now(), last_persistent_error_report: Instant::now(),
}); });
let (liquidation_trigger_sender, liquidation_trigger_receiver) =
async_channel::bounded::<()>(1);
info!("main loop"); info!("main loop");
// Job to update chain_data and notify the liquidation job when a new check is needed. // Job to update chain_data and notify the liquidation job when a new check is needed.
@ -359,29 +355,6 @@ async fn main() -> anyhow::Result<()> {
// Track all MangoAccounts: we need to iterate over them later // Track all MangoAccounts: we need to iterate over them later
state.mango_accounts.insert(account_write.pubkey); state.mango_accounts.insert(account_write.pubkey);
metric_mango_accounts.set(state.mango_accounts.len() as u64); metric_mango_accounts.set(state.mango_accounts.len() as u64);
if !state.health_check_all {
state.health_check_accounts.push(account_write.pubkey);
}
liquidation_trigger_sender.send_unless_full(()).unwrap();
} else {
let mut must_check_all = false;
if is_mango_bank(&account_write.account, &mango_group).is_some() {
debug!("change to bank {}", &account_write.pubkey);
must_check_all = true;
}
if is_perp_market(&account_write.account, &mango_group).is_some() {
debug!("change to perp market {}", &account_write.pubkey);
must_check_all = true;
}
if oracles.contains(&account_write.pubkey) {
debug!("change to oracle {}", &account_write.pubkey);
must_check_all = true;
}
if must_check_all {
state.health_check_all = true;
liquidation_trigger_sender.send_unless_full(()).unwrap();
}
} }
} }
Message::Snapshot(snapshot) => { Message::Snapshot(snapshot) => {
@ -404,9 +377,6 @@ async fn main() -> anyhow::Result<()> {
metric_mango_accounts.set(state.mango_accounts.len() as u64); metric_mango_accounts.set(state.mango_accounts.len() as u64);
state.one_snapshot_done = true; state.one_snapshot_done = true;
state.health_check_all = true;
liquidation_trigger_sender.send_unless_full(()).unwrap();
} }
_ => {} _ => {}
} }
@ -438,25 +408,20 @@ async fn main() -> anyhow::Result<()> {
}); });
let liquidation_job = tokio::spawn({ let liquidation_job = tokio::spawn({
// TODO: configurable interval
let mut interval = tokio::time::interval(Duration::from_secs(5));
let shared_state = shared_state.clone(); let shared_state = shared_state.clone();
async move { async move {
loop { loop {
liquidation_trigger_receiver.recv().await.unwrap(); interval.tick().await;
let account_addresses; let account_addresses = {
{ let state = shared_state.write().unwrap();
let mut state = shared_state.write().unwrap();
if !state.one_snapshot_done { if !state.one_snapshot_done {
continue; continue;
} }
account_addresses = if state.health_check_all { state.mango_accounts.iter().cloned().collect_vec()
state.mango_accounts.iter().cloned().collect() };
} else {
state.health_check_accounts.clone()
};
state.health_check_all = false;
state.health_check_accounts = vec![];
}
liquidation.log_persistent_errors(); liquidation.log_persistent_errors();
@ -482,10 +447,12 @@ async fn main() -> anyhow::Result<()> {
let shared_state = shared_state.clone(); let shared_state = shared_state.clone();
async move { async move {
loop { loop {
interval.tick().await; min_delay.tick().await;
if !shared_state.read().unwrap().one_snapshot_done { if !shared_state.read().unwrap().one_snapshot_done {
continue; continue;
} }
interval.tick().await;
let token_indexes = token_swap_info_updater let token_indexes = token_swap_info_updater
.mango_client() .mango_client()
.context .context
@ -499,8 +466,7 @@ async fn main() -> anyhow::Result<()> {
Ok(()) => {} Ok(()) => {}
Err(err) => { Err(err) => {
warn!( warn!(
"failed to update token swap info for token {token_index}: {:?}", "failed to update token swap info for token {token_index}: {err:?}",
err
); );
} }
} }
@ -540,12 +506,6 @@ struct SharedState {
/// Is the first snapshot done? Only start checking account health when it is. /// Is the first snapshot done? Only start checking account health when it is.
one_snapshot_done: bool, one_snapshot_done: bool,
/// Accounts whose health might have changed
health_check_accounts: Vec<Pubkey>,
/// Check all accounts?
health_check_all: bool,
} }
#[derive(Clone)] #[derive(Clone)]

View File

@ -41,11 +41,7 @@ fn tcs_is_in_price_range(
let buy_token_price = account_fetcher.fetch_bank_price(&buy_bank)?; let buy_token_price = account_fetcher.fetch_bank_price(&buy_bank)?;
let sell_token_price = account_fetcher.fetch_bank_price(&sell_bank)?; let sell_token_price = account_fetcher.fetch_bank_price(&sell_bank)?;
let base_price = (buy_token_price / sell_token_price).to_num(); let base_price = (buy_token_price / sell_token_price).to_num();
if !tcs.price_in_range(base_price) { Ok(tcs.price_in_range(base_price))
return Ok(false);
}
return Ok(true);
} }
fn tcs_has_plausible_premium( fn tcs_has_plausible_premium(
@ -440,7 +436,9 @@ fn tcs_max_liqee_execution(
// just assume it'll be fully margined here // just assume it'll be fully margined here
let max_buy = max_buy_ignoring_net_borrows.min(available_buy_borrows); let max_buy = max_buy_ignoring_net_borrows.min(available_buy_borrows);
let sell_borrows = (I80F48::from(max_sell_ignoring_net_borrows) - sell_position).clamp_to_u64(); let sell_borrows = (I80F48::from(max_sell_ignoring_net_borrows)
- sell_position.max(I80F48::ZERO))
.clamp_to_u64();
let max_sell = let max_sell =
max_sell_ignoring_net_borrows - sell_borrows + sell_borrows.min(available_sell_borrows); max_sell_ignoring_net_borrows - sell_borrows + sell_borrows.min(available_sell_borrows);