2023-02-10 05:22:07 -08:00
|
|
|
use mango_v4::accounts_zerocopy::*;
|
2023-07-03 05:09:11 -07:00
|
|
|
use mango_v4::state::{Bank, MangoAccountValue, MintInfo, PerpMarket, TokenIndex};
|
|
|
|
|
|
|
|
use anyhow::Context;
|
|
|
|
use fixed::types::I80F48;
|
2022-06-18 07:31:28 -07:00
|
|
|
|
2023-02-10 05:22:07 -08:00
|
|
|
use solana_sdk::account::AccountSharedData;
|
2022-06-18 07:31:28 -07:00
|
|
|
use solana_sdk::pubkey::Pubkey;
|
|
|
|
|
2023-02-20 05:08:38 -08:00
|
|
|
pub use mango_v4_client::snapshot_source::is_mango_account;
|
2023-08-24 07:45:01 -07:00
|
|
|
use mango_v4_client::{chain_data, MangoClient};
|
2022-06-18 07:31:28 -07:00
|
|
|
|
2023-02-10 05:22:07 -08:00
|
|
|
pub fn is_mango_bank<'a>(account: &'a AccountSharedData, group_id: &Pubkey) -> Option<&'a Bank> {
|
|
|
|
let bank = account.load::<Bank>().ok()?;
|
2022-06-18 07:31:28 -07:00
|
|
|
if bank.group != *group_id {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
Some(bank)
|
|
|
|
}
|
|
|
|
|
2023-02-10 05:22:07 -08:00
|
|
|
pub fn is_mint_info<'a>(account: &'a AccountSharedData, group_id: &Pubkey) -> Option<&'a MintInfo> {
|
|
|
|
let mint_info = account.load::<MintInfo>().ok()?;
|
2022-06-18 07:31:28 -07:00
|
|
|
if mint_info.group != *group_id {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
Some(mint_info)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_perp_market<'a>(
|
|
|
|
account: &'a AccountSharedData,
|
|
|
|
group_id: &Pubkey,
|
|
|
|
) -> Option<&'a PerpMarket> {
|
2023-02-10 05:22:07 -08:00
|
|
|
let perp_market = account.load::<PerpMarket>().ok()?;
|
2022-06-18 07:31:28 -07:00
|
|
|
if perp_market.group != *group_id {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
Some(perp_market)
|
|
|
|
}
|
2023-07-03 05:09:11 -07:00
|
|
|
|
|
|
|
/// Convenience wrapper for getting max swap amounts for a token pair
|
2023-08-11 03:08:34 -07:00
|
|
|
pub fn max_swap_source(
|
2023-07-03 05:09:11 -07:00
|
|
|
client: &MangoClient,
|
|
|
|
account_fetcher: &chain_data::AccountFetcher,
|
|
|
|
account: &MangoAccountValue,
|
|
|
|
source: TokenIndex,
|
|
|
|
target: TokenIndex,
|
|
|
|
price: I80F48,
|
|
|
|
min_health_ratio: I80F48,
|
|
|
|
) -> anyhow::Result<I80F48> {
|
|
|
|
let mut account = account.clone();
|
|
|
|
|
|
|
|
// Ensure the tokens are activated, so they appear in the health cache and
|
|
|
|
// max_swap_source() will work.
|
|
|
|
account.ensure_token_position(source)?;
|
|
|
|
account.ensure_token_position(target)?;
|
|
|
|
|
|
|
|
let health_cache =
|
2023-08-11 03:08:34 -07:00
|
|
|
mango_v4_client::health_cache::new_sync(&client.context, account_fetcher, &account)
|
2023-07-03 05:09:11 -07:00
|
|
|
.expect("always ok");
|
|
|
|
|
2023-08-11 03:08:34 -07:00
|
|
|
let source_bank: Bank =
|
|
|
|
account_fetcher.fetch(&client.context.mint_info(source).first_bank())?;
|
|
|
|
let target_bank: Bank =
|
|
|
|
account_fetcher.fetch(&client.context.mint_info(target).first_bank())?;
|
2023-07-03 05:09:11 -07:00
|
|
|
|
|
|
|
let source_price = health_cache.token_info(source).unwrap().prices.oracle;
|
|
|
|
|
|
|
|
let amount = health_cache
|
|
|
|
.max_swap_source_for_health_ratio(
|
|
|
|
&account,
|
|
|
|
&source_bank,
|
|
|
|
source_price,
|
|
|
|
&target_bank,
|
|
|
|
price,
|
|
|
|
min_health_ratio,
|
|
|
|
)
|
|
|
|
.context("getting max_swap_source")?;
|
|
|
|
Ok(amount)
|
|
|
|
}
|
2023-08-14 03:04:17 -07:00
|
|
|
|
|
|
|
/// Convenience wrapper for getting max swap amounts for a token pair
|
|
|
|
pub fn max_swap_source_ignore_net_borrows(
|
|
|
|
client: &MangoClient,
|
|
|
|
account_fetcher: &chain_data::AccountFetcher,
|
|
|
|
account: &MangoAccountValue,
|
|
|
|
source: TokenIndex,
|
|
|
|
target: TokenIndex,
|
|
|
|
price: I80F48,
|
|
|
|
min_health_ratio: I80F48,
|
|
|
|
) -> anyhow::Result<I80F48> {
|
|
|
|
let mut account = account.clone();
|
|
|
|
|
|
|
|
// Ensure the tokens are activated, so they appear in the health cache and
|
|
|
|
// max_swap_source() will work.
|
|
|
|
account.ensure_token_position(source)?;
|
|
|
|
account.ensure_token_position(target)?;
|
|
|
|
|
|
|
|
let health_cache =
|
|
|
|
mango_v4_client::health_cache::new_sync(&client.context, account_fetcher, &account)
|
|
|
|
.expect("always ok");
|
|
|
|
|
|
|
|
let mut source_bank: Bank =
|
|
|
|
account_fetcher.fetch(&client.context.mint_info(source).first_bank())?;
|
|
|
|
source_bank.net_borrow_limit_per_window_quote = -1;
|
|
|
|
let mut target_bank: Bank =
|
|
|
|
account_fetcher.fetch(&client.context.mint_info(target).first_bank())?;
|
|
|
|
target_bank.net_borrow_limit_per_window_quote = -1;
|
|
|
|
|
|
|
|
let source_price = health_cache.token_info(source).unwrap().prices.oracle;
|
|
|
|
|
|
|
|
let amount = health_cache
|
|
|
|
.max_swap_source_for_health_ratio(
|
|
|
|
&account,
|
|
|
|
&source_bank,
|
|
|
|
source_price,
|
|
|
|
&target_bank,
|
|
|
|
price,
|
|
|
|
min_health_ratio,
|
|
|
|
)
|
|
|
|
.context("getting max_swap_source")?;
|
|
|
|
Ok(amount)
|
|
|
|
}
|