Skip to content

Commit

Permalink
rust client: ix cu limits based on health compute cost
Browse files Browse the repository at this point in the history
Many instructions now return PreparedInstructions instead of a direct
Instruction or Vec<Instruction>. That way they can keep track of the
expected cu cost of the instructions for the compute limit instruction
that gets added once all instructions are made.
  • Loading branch information
ckamm committed Nov 2, 2023
1 parent 2910fd1 commit edae113
Show file tree
Hide file tree
Showing 13 changed files with 936 additions and 352 deletions.
26 changes: 12 additions & 14 deletions bin/liquidator/src/liquidate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,6 @@ 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<Option<Signature>> {
let all_perp_base_positions: anyhow::Result<
Vec<Option<(PerpMarketIndex, i64, I80F48, I80F48)>>,
Expand Down Expand Up @@ -208,7 +202,7 @@ impl<'a> LiquidateHelper<'a> {
"computed transfer maximums"
);

let liq_ix = self
let mut liq_ixs = self
.client
.perp_liq_base_or_positive_pnl_instruction(
(self.pubkey, &self.liqee),
Expand All @@ -218,9 +212,10 @@ impl<'a> LiquidateHelper<'a> {
)
.await
.context("creating perp_liq_base_or_positive_pnl_instruction")?;
liq_ixs.cu = liq_ixs.cu.max(self.config.compute_limit_for_liq_ix);
let txsig = self
.client
.send_and_confirm_owner_tx(vec![self.liq_compute_limit_instruction(), liq_ix])
.send_and_confirm_owner_tx(liq_ixs.to_instructions())
.await
.context("sending perp_liq_base_or_positive_pnl_instruction")?;
info!(
Expand Down Expand Up @@ -253,7 +248,7 @@ impl<'a> LiquidateHelper<'a> {
}
let (perp_market_index, _) = perp_negative_pnl.first().unwrap();

let liq_ix = self
let mut liq_ixs = self
.client
.perp_liq_negative_pnl_or_bankruptcy_instruction(
(self.pubkey, &self.liqee),
Expand All @@ -263,9 +258,10 @@ impl<'a> LiquidateHelper<'a> {
)
.await
.context("creating perp_liq_negative_pnl_or_bankruptcy_instruction")?;
liq_ixs.cu = liq_ixs.cu.max(self.config.compute_limit_for_liq_ix);
let txsig = self
.client
.send_and_confirm_owner_tx(vec![self.liq_compute_limit_instruction(), liq_ix])
.send_and_confirm_owner_tx(liq_ixs.to_instructions())
.await
.context("sending perp_liq_negative_pnl_or_bankruptcy_instruction")?;
info!(
Expand Down Expand Up @@ -374,7 +370,7 @@ 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 liq_ix = self
let mut liq_ixs = self
.client
.token_liq_with_token_instruction(
(self.pubkey, &self.liqee),
Expand All @@ -384,9 +380,10 @@ impl<'a> LiquidateHelper<'a> {
)
.await
.context("creating liq_token_with_token ix")?;
liq_ixs.cu = liq_ixs.cu.max(self.config.compute_limit_for_liq_ix);
let txsig = self
.client
.send_and_confirm_owner_tx(vec![self.liq_compute_limit_instruction(), liq_ix])
.send_and_confirm_owner_tx(liq_ixs.to_instructions())
.await
.context("sending liq_token_with_token")?;
info!(
Expand Down Expand Up @@ -433,7 +430,7 @@ impl<'a> LiquidateHelper<'a> {
.max_token_liab_transfer(liab_token_index, quote_token_index)
.await?;

let liq_ix = self
let mut liq_ixs = self
.client
.token_liq_bankruptcy_instruction(
(self.pubkey, &self.liqee),
Expand All @@ -442,9 +439,10 @@ impl<'a> LiquidateHelper<'a> {
)
.await
.context("creating liq_token_bankruptcy")?;
liq_ixs.cu = liq_ixs.cu.max(self.config.compute_limit_for_liq_ix);
let txsig = self
.client
.send_and_confirm_owner_tx(vec![self.liq_compute_limit_instruction(), liq_ix])
.send_and_confirm_owner_tx(liq_ixs.to_instructions())
.await
.context("sending liq_token_with_token")?;
info!(
Expand Down
6 changes: 4 additions & 2 deletions bin/liquidator/src/trigger_tcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1122,7 +1122,7 @@ impl Context {
};

let liqee = self.account_fetcher.fetch_mango_account(&pending.pubkey)?;
let trigger_ix = self
let mut trigger_ixs = self
.mango_client
.token_conditional_swap_trigger_instruction(
(&pending.pubkey, &liqee),
Expand All @@ -1134,7 +1134,9 @@ impl Context {
&allowed_tokens,
)
.await?;
tx_builder.instructions.push(trigger_ix);
tx_builder
.instructions
.append(&mut trigger_ixs.instructions);

let txsig = tx_builder
.send_and_confirm(&self.mango_client.client)
Expand Down
24 changes: 14 additions & 10 deletions bin/settler/src/settle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ use mango_v4::accounts_zerocopy::KeyedAccountSharedData;
use mango_v4::health::HealthType;
use mango_v4::state::{PerpMarket, PerpMarketIndex};
use mango_v4_client::{
chain_data, health_cache, prettify_solana_client_error, MangoClient, TransactionBuilder,
chain_data, health_cache, prettify_solana_client_error, MangoClient, PreparedInstructions,
TransactionBuilder,
};
use solana_sdk::address_lookup_table_account::AddressLookupTableAccount;
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::instruction::Instruction;
use solana_sdk::signature::Signature;

use solana_sdk::signer::Signer;
Expand Down Expand Up @@ -180,7 +180,7 @@ impl SettlementState {
mango_client,
account_fetcher,
perp_market_index,
instructions: Vec::new(),
instructions: PreparedInstructions::new(),
max_batch_size: 8, // the 1.4M max CU limit if we assume settle ix can be up to around 150k
blockhash: mango_client
.client
Expand Down Expand Up @@ -242,7 +242,7 @@ struct SettleBatchProcessor<'a> {
mango_client: &'a MangoClient,
account_fetcher: &'a chain_data::AccountFetcher,
perp_market_index: PerpMarketIndex,
instructions: Vec<Instruction>,
instructions: PreparedInstructions,
max_batch_size: usize,
blockhash: solana_sdk::hash::Hash,
address_lookup_tables: &'a Vec<AddressLookupTableAccount>,
Expand All @@ -254,7 +254,7 @@ impl<'a> SettleBatchProcessor<'a> {
let fee_payer = client.fee_payer.clone();

TransactionBuilder {
instructions: self.instructions.clone(),
instructions: self.instructions.clone().to_instructions(),
address_lookup_tables: self.address_lookup_tables.clone(),
payer: fee_payer.pubkey(),
signers: vec![fee_payer],
Expand Down Expand Up @@ -296,15 +296,19 @@ impl<'a> SettleBatchProcessor<'a> {
) -> anyhow::Result<Option<Signature>> {
let a_value = self.account_fetcher.fetch_mango_account(&account_a)?;
let b_value = self.account_fetcher.fetch_mango_account(&account_b)?;
let ix = self.mango_client.perp_settle_pnl_instruction(
let new_ixs = self.mango_client.perp_settle_pnl_instruction(
self.perp_market_index,
(&account_a, &a_value),
(&account_b, &b_value),
)?;
self.instructions.push(ix);
let previous = self.instructions.clone();
self.instructions.append(new_ixs.clone());

// if we exceed the batch limit or tx size limit, send a batch without the new ix
let needs_send = if self.instructions.len() > self.max_batch_size {
let max_cu_per_tx = 1_400_000;
let needs_send = if self.instructions.len() > self.max_batch_size
|| self.instructions.cu >= max_cu_per_tx
{
true
} else {
let tx = self.transaction()?;
Expand All @@ -321,9 +325,9 @@ impl<'a> SettleBatchProcessor<'a> {
too_big
};
if needs_send {
let ix = self.instructions.pop().unwrap();
self.instructions = previous;
let txsig = self.send().await?;
self.instructions.push(ix);
self.instructions.append(new_ixs);
return Ok(txsig);
}

Expand Down
21 changes: 14 additions & 7 deletions bin/settler/src/tcs_start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
use itertools::Itertools;
use mango_v4::error::{IsAnchorErrorWithCode, MangoError};
use mango_v4::state::*;
use mango_v4_client::PreparedInstructions;
use mango_v4_client::{chain_data, error_tracking::ErrorTracking, MangoClient};
use solana_sdk::instruction::Instruction;

use tracing::*;
use {fixed::types::I80F48, solana_sdk::pubkey::Pubkey};
Expand Down Expand Up @@ -93,11 +93,11 @@ impl State {
}

for startable_chunk in startable.chunks(8) {
let mut instructions = vec![];
let mut instructions = PreparedInstructions::new();
let mut ix_targets = vec![];
let mut liqor_account = mango_client.mango_account().await?;
for (pubkey, tcs_id, incentive_token_index) in startable_chunk {
let ix = match self.make_start_ix(pubkey, *tcs_id).await {
let ixs = match self.make_start_ix(pubkey, *tcs_id).await {
Ok(v) => v,
Err(e) => {
self.errors.record_error(
Expand All @@ -108,23 +108,26 @@ impl State {
continue;
}
};
instructions.push(ix);
instructions.append(ixs);
ix_targets.push((*pubkey, *tcs_id));
liqor_account.ensure_token_position(*incentive_token_index)?;
}

// Clear newly created token positions, so the liqor account is mostly empty
for token_index in startable_chunk.iter().map(|(_, _, ti)| *ti).unique() {
let mint = mango_client.context.token(token_index).mint_info.mint;
instructions.append(&mut mango_client.token_withdraw_instructions(
instructions.append(mango_client.token_withdraw_instructions(
&liqor_account,
mint,
u64::MAX,
false,
)?);
}

let txsig = match mango_client.send_and_confirm_owner_tx(instructions).await {
let txsig = match mango_client
.send_and_confirm_owner_tx(instructions.to_instructions())
.await
{
Ok(v) => v,
Err(e) => {
warn!("error sending transaction: {e:?}");
Expand Down Expand Up @@ -154,7 +157,11 @@ impl State {
Ok(())
}

async fn make_start_ix(&self, pubkey: &Pubkey, tcs_id: u64) -> anyhow::Result<Instruction> {
async fn make_start_ix(
&self,
pubkey: &Pubkey,
tcs_id: u64,
) -> anyhow::Result<PreparedInstructions> {
let account = self.account_fetcher.fetch_mango_account(pubkey).unwrap();
self.mango_client
.token_conditional_swap_start_instruction((pubkey, &account), tcs_id)
Expand Down
Loading

0 comments on commit edae113

Please sign in to comment.