From a7705a2a1b71593c721831bb00894013be69fb58 Mon Sep 17 00:00:00 2001 From: Christian Kamm Date: Wed, 9 Aug 2023 15:26:13 +0200 Subject: [PATCH] liquidator: Allow overriding compute limit for potentially costly ix (#669) --- bin/liquidator/README.md | 1 + bin/liquidator/src/liquidate.rs | 54 ++++++++++++++++++++++++++------- bin/liquidator/src/main.rs | 5 +++ lib/client/src/client.rs | 24 +++++++-------- 4 files changed, 61 insertions(+), 23 deletions(-) diff --git a/bin/liquidator/README.md b/bin/liquidator/README.md index 0cd1f689a..97d9629e2 100644 --- a/bin/liquidator/README.md +++ b/bin/liquidator/README.md @@ -47,6 +47,7 @@ more advanced parameters - `REBALANCE` - if rebalancing should happen (default true) - `REBALANCE_SLIPPAGE_BPS` - slippage liquidator should tolerate when offloading tokens (default 100) - `PRIORITIZATION_MICRO_LAMPORTS` - how much priority fee to pay (default 0) +- `COMPUTE_LIMIT_FOR_LIQUIDATION` - compute to request for liq instructions (default 250k) - `SNAPSHOT_INTERVAL_SECS` - how frequently to request a full on-chain snapshot (default 5min) - `PARALLEL_RPC_REQUESTS` - number of allowed parallel rpc calls (default 10) - `TELEMETRY` - report the liquidator's existence and pubkey occasionally (default true) diff --git a/bin/liquidator/src/liquidate.rs b/bin/liquidator/src/liquidate.rs index 50f24e7ad..b81227a07 100644 --- a/bin/liquidator/src/liquidate.rs +++ b/bin/liquidator/src/liquidate.rs @@ -14,10 +14,12 @@ use {anyhow::Context, fixed::types::I80F48, solana_sdk::pubkey::Pubkey}; use crate::util; +#[derive(Clone)] pub struct Config { pub min_health_ratio: f64, pub refresh_timeout: Duration, pub mock_jupiter: bool, + pub compute_limit_for_liq_ix: u32, } pub async fn jupiter_market_can_buy( @@ -88,6 +90,7 @@ struct LiquidateHelper<'a> { liqor_min_health_ratio: I80F48, allowed_asset_tokens: HashSet, allowed_liab_tokens: HashSet, + config: Config, } impl<'a> LiquidateHelper<'a> { @@ -160,6 +163,12 @@ impl<'a> LiquidateHelper<'a> { Ok(Some(txsig)) } + fn liq_compute_limit_instruction(&self) -> solana_sdk::instruction::Instruction { + solana_sdk::compute_budget::ComputeBudgetInstruction::set_compute_unit_limit( + self.config.compute_limit_for_liq_ix, + ) + } + async fn perp_liq_base_or_positive_pnl(&self) -> anyhow::Result> { let all_perp_base_positions: anyhow::Result< Vec>, @@ -258,15 +267,21 @@ impl<'a> LiquidateHelper<'a> { "computed transfer maximums" ); - let txsig = self + let liq_ix = self .client - .perp_liq_base_or_positive_pnl( + .perp_liq_base_or_positive_pnl_instruction( (self.pubkey, &self.liqee), *perp_market_index, side_signum * max_base_transfer_abs, max_pnl_transfer, ) - .await?; + .await + .context("creating perp_liq_base_or_positive_pnl_instruction")?; + let txsig = self + .client + .send_and_confirm_owner_tx(vec![self.liq_compute_limit_instruction(), liq_ix]) + .await + .context("sending perp_liq_base_or_positive_pnl_instruction")?; info!( perp_market_index, %txsig, @@ -297,15 +312,21 @@ impl<'a> LiquidateHelper<'a> { } let (perp_market_index, _) = perp_negative_pnl.first().unwrap(); - let txsig = self + let liq_ix = self .client - .perp_liq_negative_pnl_or_bankruptcy( + .perp_liq_negative_pnl_or_bankruptcy_instruction( (self.pubkey, &self.liqee), *perp_market_index, // Always use the max amount, since the health effect is >= 0 u64::MAX, ) - .await?; + .await + .context("creating perp_liq_negative_pnl_or_bankruptcy_instruction")?; + let txsig = self + .client + .send_and_confirm_owner_tx(vec![self.liq_compute_limit_instruction(), liq_ix]) + .await + .context("sending perp_liq_negative_pnl_or_bankruptcy_instruction")?; info!( perp_market_index, %txsig, @@ -413,15 +434,20 @@ impl<'a> LiquidateHelper<'a> { // 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 // - let txsig = self + let liq_ix = self .client - .token_liq_with_token( + .token_liq_with_token_instruction( (self.pubkey, &self.liqee), asset_token_index, liab_token_index, max_liab_transfer, ) .await + .context("creating liq_token_with_token ix")?; + let txsig = self + .client + .send_and_confirm_owner_tx(vec![self.liq_compute_limit_instruction(), liq_ix]) + .await .context("sending liq_token_with_token")?; info!( asset_token_index, @@ -467,15 +493,20 @@ impl<'a> LiquidateHelper<'a> { .max_token_liab_transfer(liab_token_index, quote_token_index) .await?; - let txsig = self + let liq_ix = self .client - .token_liq_bankruptcy( + .token_liq_bankruptcy_instruction( (self.pubkey, &self.liqee), liab_token_index, max_liab_transfer, ) .await - .context("sending liq_token_bankruptcy")?; + .context("creating liq_token_bankruptcy")?; + let txsig = self + .client + .send_and_confirm_owner_tx(vec![self.liq_compute_limit_instruction(), liq_ix]) + .await + .context("sending liq_token_with_token")?; info!( liab_token_index, %txsig, @@ -619,6 +650,7 @@ pub async fn maybe_liquidate_account( liqor_min_health_ratio, allowed_asset_tokens: all_token_mints.clone(), allowed_liab_tokens: all_token_mints, + config: config.clone(), } .send_liq_tx() .await?; diff --git a/bin/liquidator/src/main.rs b/bin/liquidator/src/main.rs index 261c4220d..9cf7b5925 100644 --- a/bin/liquidator/src/main.rs +++ b/bin/liquidator/src/main.rs @@ -91,6 +91,10 @@ struct Cli { #[clap(long, env, default_value = "0")] prioritization_micro_lamports: u64, + /// compute limit requested for liquidation instructions + #[clap(long, env, default_value = "250000")] + compute_limit_for_liquidation: u32, + /// use a jupiter mock instead of actual queries /// /// This is required for devnet testing. @@ -247,6 +251,7 @@ async fn main() -> anyhow::Result<()> { let liq_config = liquidate::Config { min_health_ratio: cli.min_health_ratio, mock_jupiter: cli.mock_jupiter == BoolArg::True, + compute_limit_for_liq_ix: cli.compute_limit_for_liquidation, // TODO: config refresh_timeout: Duration::from_secs(30), }; diff --git a/lib/client/src/client.rs b/lib/client/src/client.rs index 705cea7ad..ce00022bb 100644 --- a/lib/client/src/client.rs +++ b/lib/client/src/client.rs @@ -1052,13 +1052,13 @@ impl MangoClient { self.send_and_confirm_permissionless_tx(vec![ix]).await } - pub async fn perp_liq_base_or_positive_pnl( + pub async fn perp_liq_base_or_positive_pnl_instruction( &self, liqee: (&Pubkey, &MangoAccountValue), market_index: PerpMarketIndex, max_base_transfer: i64, max_pnl_transfer: u64, - ) -> anyhow::Result { + ) -> anyhow::Result { let perp = self.context.perp(market_index); let settle_token_info = self.context.token(perp.market.settle_token_index); @@ -1094,15 +1094,15 @@ impl MangoClient { }, ), }; - self.send_and_confirm_owner_tx(vec![ix]).await + Ok(ix) } - pub async fn perp_liq_negative_pnl_or_bankruptcy( + pub async fn perp_liq_negative_pnl_or_bankruptcy_instruction( &self, liqee: (&Pubkey, &MangoAccountValue), market_index: PerpMarketIndex, max_liab_transfer: u64, - ) -> anyhow::Result { + ) -> anyhow::Result { let group = account_fetcher_fetch_anchor_account::( &*self.account_fetcher, &self.context.group, @@ -1151,20 +1151,20 @@ impl MangoClient { &mango_v4::instruction::PerpLiqNegativePnlOrBankruptcyV2 { max_liab_transfer }, ), }; - self.send_and_confirm_owner_tx(vec![ix]).await + Ok(ix) } // // Liquidation // - pub async fn token_liq_with_token( + pub async fn token_liq_with_token_instruction( &self, liqee: (&Pubkey, &MangoAccountValue), asset_token_index: TokenIndex, liab_token_index: TokenIndex, max_liab_transfer: I80F48, - ) -> anyhow::Result { + ) -> anyhow::Result { let health_remaining_ams = self .derive_liquidation_health_check_remaining_account_metas( liqee.1, @@ -1195,15 +1195,15 @@ impl MangoClient { max_liab_transfer, }), }; - self.send_and_confirm_owner_tx(vec![ix]).await + Ok(ix) } - pub async fn token_liq_bankruptcy( + pub async fn token_liq_bankruptcy_instruction( &self, liqee: (&Pubkey, &MangoAccountValue), liab_token_index: TokenIndex, max_liab_transfer: I80F48, - ) -> anyhow::Result { + ) -> anyhow::Result { let quote_token_index = 0; let quote_info = self.context.token(quote_token_index); @@ -1255,7 +1255,7 @@ impl MangoClient { max_liab_transfer, }), }; - self.send_and_confirm_owner_tx(vec![ix]).await + Ok(ix) } pub async fn token_conditional_swap_trigger(