Skip to content

Commit

Permalink
J/cli better bankruptcy handling (#135)
Browse files Browse the repository at this point in the history
* fix: better bankruptcy handling cli

* fix: bankruptcy obvs accounts

* fix: handle multiple accounts at once

* fix: remove commented out code
  • Loading branch information
jkbpvsc authored Nov 23, 2023
1 parent 279c1b8 commit 0f1597a
Show file tree
Hide file tree
Showing 2 changed files with 221 additions and 10 deletions.
12 changes: 4 additions & 8 deletions clients/rust/marginfi-cli/src/entrypoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,7 @@ pub enum GroupCommand {
},
#[cfg(feature = "admin")]
HandleBankruptcy {
#[clap(long)]
bank: Pubkey,
#[clap(long)]
marginfi_account: Pubkey,
accounts: Vec<Pubkey>,
},
}

Expand Down Expand Up @@ -502,10 +499,9 @@ fn group(subcmd: GroupCommand, global_options: &GlobalOptions) -> Result<()> {
risk_tier,
),
#[cfg(feature = "admin")]
GroupCommand::HandleBankruptcy {
bank,
marginfi_account,
} => processor::group_handle_bankruptcy(&config, profile, bank, marginfi_account),
GroupCommand::HandleBankruptcy { accounts } => {
processor::handle_bankruptcy_for_accounts(&config, &profile, accounts)
}
}
}

Expand Down
219 changes: 217 additions & 2 deletions clients/rust/marginfi-cli/src/processor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ use {

#[cfg(feature = "dev")]
use marginfi::state::price::{OraclePriceFeedAdapter, PriceAdapter};
use marginfi::{
constants::ZERO_AMOUNT_THRESHOLD, state::marginfi_account::RiskEngine,
utils::NumTraitsWithTolerance,
};
use solana_client::rpc_client::RpcClient;

#[cfg(feature = "admin")]
use {
Expand Down Expand Up @@ -457,10 +462,85 @@ pub fn group_handle_bankruptcy(
config,
Some(profile.marginfi_group.unwrap()),
)?);

let marginfi_account = config
.mfi_program
.account::<MarginfiAccount>(marginfi_account_pk)?;

handle_bankruptcy_for_an_account(
config,
&profile,
&rpc_client,
&banks,
marginfi_account_pk,
&marginfi_account,
bank_pk,
)?;

Ok(())
}

pub fn group_auto_handle_bankruptcy_for_an_account(
config: &Config,
profile: Profile,
marginfi_account_pk: Pubkey,
) -> Result<()> {
let rpc_client = config.mfi_program.rpc();

if profile.marginfi_group.is_none() {
bail!("Marginfi group not specified in profile [{}]", profile.name);
}

let banks = HashMap::from_iter(load_all_banks(
config,
Some(profile.marginfi_group.unwrap()),
)?);
let marginfi_account = config
.mfi_program
.account::<MarginfiAccount>(marginfi_account_pk)?;

marginfi_account
.lending_account
.balances
.iter()
.filter(|b| {
b.active
&& banks
.get(&b.bank_pk)
.unwrap()
.get_liability_amount(b.liability_shares.into())
.unwrap()
.is_positive_with_tolerance(ZERO_AMOUNT_THRESHOLD)
})
.map(|b| b.bank_pk)
.collect::<Vec<Pubkey>>()
.iter()
.for_each(|bank_pk| {
handle_bankruptcy_for_an_account(
config,
&profile,
&rpc_client,
&banks,
marginfi_account_pk,
&marginfi_account,
*bank_pk,
)
.unwrap();
});

Ok(())
}

fn handle_bankruptcy_for_an_account(
config: &Config,
profile: &Profile,
rpc_client: &RpcClient,
banks: &HashMap<Pubkey, Bank>,
marginfi_account_pk: Pubkey,
marginfi_account: &MarginfiAccount,
bank_pk: Pubkey,
) -> Result<()> {
println!("Handling bankruptcy for bank {}", bank_pk);
let mut handle_bankruptcy_ix = Instruction {
program_id: config.program_id,
accounts: marginfi::accounts::LendingPoolHandleBankruptcy {
Expand Down Expand Up @@ -519,6 +599,141 @@ pub fn group_handle_bankruptcy(
Ok(())
}

#[cfg(feature = "admin")]
const BANKRUPTCY_CHUNKS: usize = 4;

#[cfg(feature = "admin")]
pub fn handle_bankruptcy_for_accounts(
config: &Config,
profile: &Profile,
accounts: Vec<Pubkey>,
) -> Result<()> {
let mut instructions = vec![];
let rpc_client = config.mfi_program.rpc();

let banks = HashMap::from_iter(load_all_banks(
config,
Some(profile.marginfi_group.unwrap()),
)?);

for account in accounts {
let marginfi_account = config
.mfi_program
.account::<MarginfiAccount>(account)
.unwrap();

marginfi_account
.lending_account
.balances
.iter()
.filter(|b| {
b.active
&& banks
.get(&b.bank_pk)
.unwrap()
.get_liability_amount(b.liability_shares.into())
.unwrap()
.is_positive_with_tolerance(ZERO_AMOUNT_THRESHOLD)
})
.map(|b| b.bank_pk)
.collect::<Vec<Pubkey>>()
.iter()
.for_each(|bank_pk| {
instructions.push(
make_bankruptcy_ix(
config,
profile,
&banks,
account,
&marginfi_account,
*bank_pk,
)
.unwrap(),
);
});
}

println!("Handling {} bankruptcies", instructions.len());

let chunks = instructions.chunks(BANKRUPTCY_CHUNKS);

for chunk in chunks {
let recent_blockhash = rpc_client.get_latest_blockhash().unwrap();
let signing_keypairs = if let CliSigner::Keypair(keypair) = &config.signer {
vec![keypair]
} else {
vec![]
};

let mut ixs = vec![ComputeBudgetInstruction::set_compute_unit_limit(1_400_000)];
ixs.extend_from_slice(chunk);

let message = Message::new(&ixs, Some(&config.signer.pubkey()));

let mut transaction = Transaction::new_unsigned(message);
transaction.partial_sign(&signing_keypairs, recent_blockhash);

match process_transaction(&transaction, &rpc_client, config.dry_run, &config.signer) {
Ok(sig) => println!("Bankruptcy handled (sig: {})", sig),
Err(err) => println!("Error during bankruptcy handling:\n{:#?}", err),
};
}

Ok(())
}
#[cfg(feature = "admin")]
fn make_bankruptcy_ix(
config: &Config,
profile: &Profile,
banks: &HashMap<Pubkey, Bank>,
marginfi_account_pk: Pubkey,
marginfi_account: &MarginfiAccount,
bank_pk: Pubkey,
) -> Result<Instruction> {
println!("Handling bankruptcy for bank {}", bank_pk);
let mut handle_bankruptcy_ix = Instruction {
program_id: config.program_id,
accounts: marginfi::accounts::LendingPoolHandleBankruptcy {
marginfi_group: profile.marginfi_group.unwrap(),
admin: config.signer.pubkey(),
bank: bank_pk,
marginfi_account: marginfi_account_pk,
liquidity_vault: find_bank_vault_pda(
&bank_pk,
BankVaultType::Liquidity,
&config.program_id,
)
.0,
insurance_vault: find_bank_vault_pda(
&bank_pk,
BankVaultType::Insurance,
&config.program_id,
)
.0,
insurance_vault_authority: find_bank_vault_authority_pda(
&bank_pk,
BankVaultType::Insurance,
&config.program_id,
)
.0,
token_program: token::ID,
}
.to_account_metas(Some(true)),
data: marginfi::instruction::LendingPoolHandleBankruptcy {}.data(),
};

handle_bankruptcy_ix
.accounts
.extend(load_observation_account_metas(
&marginfi_account,
&banks,
vec![bank_pk],
vec![],
));

Ok(handle_bankruptcy_ix)
}

// --------------------------------------------------------------------------------------------------------------------
// bank
// --------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -719,7 +934,7 @@ pub fn bank_setup_emissions(

match process_transaction(&transaction, &rpc_client, config.dry_run, &config.signer) {
Ok(sig) => println!("Tx succeded (sig: {})", sig),
Err(err) => println!("Error during bankruptcy handling:\n{:#?}", err),
Err(err) => println!("Error :\n{:#?}", err),
};

Ok(())
Expand Down Expand Up @@ -835,7 +1050,7 @@ pub fn bank_update_emissions(

match process_transaction(&transaction, &rpc_client, config.dry_run, &config.signer) {
Ok(sig) => println!("Tx succeded (sig: {})", sig),
Err(err) => println!("Error during bankruptcy handling:\n{:#?}", err),
Err(err) => println!("Error:\n{:#?}", err),
};

Ok(())
Expand Down

0 comments on commit 0f1597a

Please sign in to comment.