Merge branch 'mc/liquidator-bot' into dev
This commit is contained in:
commit
383489ae34
|
@ -1,3 +1,4 @@
|
|||
RPC_URL=
|
||||
PAYER_KEYPAIR=
|
||||
ADMIN_KEYPAIR=
|
||||
MANGO_ACCOUNT_NAME=
|
|
@ -34,6 +34,9 @@ struct Cli {
|
|||
#[clap(short, long, env = "ADMIN_KEYPAIR")]
|
||||
admin: Option<std::path::PathBuf>,
|
||||
|
||||
#[clap(short, long, env = "MANGO_ACCOUNT_NAME")]
|
||||
mango_account_name: String,
|
||||
|
||||
#[clap(subcommand)]
|
||||
command: Command,
|
||||
}
|
||||
|
@ -55,6 +58,7 @@ fn main() -> Result<(), anyhow::Error> {
|
|||
payer,
|
||||
admin,
|
||||
command,
|
||||
mango_account_name,
|
||||
} = Cli::parse();
|
||||
|
||||
let payer = match payer {
|
||||
|
@ -84,12 +88,13 @@ fn main() -> Result<(), anyhow::Error> {
|
|||
Command::Taker { .. } => CommitmentConfig::confirmed(),
|
||||
};
|
||||
|
||||
let mango_client = Arc::new(MangoClient::new(cluster, commitment, payer, admin)?);
|
||||
|
||||
log::info!("Program Id {}", &mango_client.program().id());
|
||||
log::info!("Admin {}", &mango_client.admin.to_base58_string());
|
||||
log::info!("Group {}", &mango_client.group());
|
||||
log::info!("User {}", &mango_client.payer());
|
||||
let mango_client = Arc::new(MangoClient::new(
|
||||
cluster,
|
||||
commitment,
|
||||
payer,
|
||||
admin,
|
||||
mango_account_name,
|
||||
)?);
|
||||
|
||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
|
|
|
@ -13,14 +13,14 @@ use mango_v4::state::{Bank, MangoAccount, MintInfo, PerpMarket, Serum3Market, To
|
|||
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
|
||||
use crate::util::MyClone;
|
||||
use anyhow::Context;
|
||||
use solana_client::rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType};
|
||||
use solana_sdk::instruction::{AccountMeta, Instruction};
|
||||
use solana_sdk::signature::{Keypair, Signature};
|
||||
use solana_sdk::sysvar;
|
||||
use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signer::Signer};
|
||||
|
||||
use crate::util::MyClone;
|
||||
|
||||
pub struct MangoClient {
|
||||
pub rpc: RpcClient,
|
||||
pub cluster: Cluster,
|
||||
|
@ -51,6 +51,7 @@ impl MangoClient {
|
|||
commitment: CommitmentConfig,
|
||||
payer: Keypair,
|
||||
admin: Keypair,
|
||||
mango_account_name: String,
|
||||
) -> anyhow::Result<Self> {
|
||||
let program =
|
||||
Client::new_with_options(cluster.clone(), std::rc::Rc::new(payer.clone()), commitment)
|
||||
|
@ -59,12 +60,22 @@ impl MangoClient {
|
|||
let rpc = program.rpc();
|
||||
|
||||
let group = Pubkey::find_program_address(
|
||||
&["Group".as_ref(), admin.pubkey().as_ref()],
|
||||
&[
|
||||
"Group".as_ref(),
|
||||
admin.pubkey().as_ref(),
|
||||
0u32.to_le_bytes().as_ref(),
|
||||
],
|
||||
&program.id(),
|
||||
)
|
||||
.0;
|
||||
|
||||
let mango_accounts = program.accounts::<MangoAccount>(vec![
|
||||
log::info!("Program Id {}", program.id());
|
||||
log::info!("Admin {}", admin.pubkey());
|
||||
log::info!("Group {}", group);
|
||||
log::info!("User {}", payer.pubkey());
|
||||
|
||||
// Mango Account
|
||||
let mut mango_account_tuples = program.accounts::<MangoAccount>(vec![
|
||||
RpcFilterType::Memcmp(Memcmp {
|
||||
offset: 40,
|
||||
bytes: MemcmpEncodedBytes::Base58(group.to_string()),
|
||||
|
@ -76,8 +87,70 @@ impl MangoClient {
|
|||
encoding: None,
|
||||
}),
|
||||
])?;
|
||||
let mango_account_cache = mango_accounts[0];
|
||||
let mango_account_opt = mango_account_tuples
|
||||
.iter()
|
||||
.find(|tuple| tuple.1.name() == mango_account_name);
|
||||
if mango_account_opt.is_none() {
|
||||
mango_account_tuples
|
||||
.sort_by(|a, b| a.1.account_num.partial_cmp(&b.1.account_num).unwrap());
|
||||
let account_num = match mango_account_tuples.last() {
|
||||
Some(tuple) => tuple.1.account_num + 1,
|
||||
None => 0u8,
|
||||
};
|
||||
program
|
||||
.request()
|
||||
.instruction(Instruction {
|
||||
program_id: mango_v4::id(),
|
||||
accounts: anchor_lang::ToAccountMetas::to_account_metas(
|
||||
&mango_v4::accounts::CreateAccount {
|
||||
group,
|
||||
owner: payer.pubkey(),
|
||||
account: {
|
||||
Pubkey::find_program_address(
|
||||
&[
|
||||
group.as_ref(),
|
||||
b"MangoAccount".as_ref(),
|
||||
payer.pubkey().as_ref(),
|
||||
&account_num.to_le_bytes(),
|
||||
],
|
||||
&mango_v4::id(),
|
||||
)
|
||||
.0
|
||||
},
|
||||
payer: payer.pubkey(),
|
||||
system_program: System::id(),
|
||||
},
|
||||
None,
|
||||
),
|
||||
data: anchor_lang::InstructionData::data(
|
||||
&mango_v4::instruction::CreateAccount {
|
||||
account_num,
|
||||
name: mango_account_name.to_owned(),
|
||||
},
|
||||
),
|
||||
})
|
||||
.send()
|
||||
.context("Failed to create account...")?;
|
||||
}
|
||||
let mango_account_tuples = program.accounts::<MangoAccount>(vec![
|
||||
RpcFilterType::Memcmp(Memcmp {
|
||||
offset: 40,
|
||||
bytes: MemcmpEncodedBytes::Base58(group.to_string()),
|
||||
encoding: None,
|
||||
}),
|
||||
RpcFilterType::Memcmp(Memcmp {
|
||||
offset: 72,
|
||||
bytes: MemcmpEncodedBytes::Base58(payer.pubkey().to_string()),
|
||||
encoding: None,
|
||||
}),
|
||||
])?;
|
||||
let index = mango_account_tuples
|
||||
.iter()
|
||||
.position(|tuple| tuple.1.name() == &mango_account_name)
|
||||
.unwrap();
|
||||
let mango_account_cache = mango_account_tuples[index];
|
||||
|
||||
// banks cache
|
||||
let mut banks_cache = HashMap::new();
|
||||
let mut banks_cache_by_token_index = HashMap::new();
|
||||
let bank_tuples = program.accounts::<Bank>(vec![RpcFilterType::Memcmp(Memcmp {
|
||||
|
@ -90,6 +163,7 @@ impl MangoClient {
|
|||
banks_cache_by_token_index.insert(v.token_index, (k, v));
|
||||
}
|
||||
|
||||
// mintinfo cache
|
||||
let mut mint_infos_cache = HashMap::new();
|
||||
let mut mint_infos_cache_by_token_index = HashMap::new();
|
||||
let mint_info_tuples =
|
||||
|
@ -111,6 +185,7 @@ impl MangoClient {
|
|||
mint_infos_cache_by_token_index.insert(v.token_index, (k, v, mint));
|
||||
}
|
||||
|
||||
// serum3 markets cache
|
||||
let mut serum3_markets_cache = HashMap::new();
|
||||
let mut serum3_external_markets_cache = HashMap::new();
|
||||
let serum3_market_tuples =
|
||||
|
@ -134,6 +209,7 @@ impl MangoClient {
|
|||
);
|
||||
}
|
||||
|
||||
// perp markets cache
|
||||
let mut perp_markets_cache = HashMap::new();
|
||||
let perp_market_tuples =
|
||||
program.accounts::<PerpMarket>(vec![RpcFilterType::Memcmp(Memcmp {
|
||||
|
|
|
@ -90,16 +90,22 @@ fn ensure_deposit(mango_client: &Arc<MangoClient>) -> Result<(), anyhow::Error>
|
|||
let mint = &mango_client.mint_infos_cache.get(&bank.mint).unwrap().2;
|
||||
let desired_balance = I80F48::from_num(10_000 * 10u64.pow(mint.decimals as u32));
|
||||
|
||||
let token_account = mango_account.tokens.find(bank.token_index).unwrap();
|
||||
let native = token_account.native(bank);
|
||||
let token_account_opt = mango_account.tokens.find(bank.token_index);
|
||||
|
||||
let ui = token_account.ui(bank, mint);
|
||||
log::info!("Current balance {} {}", ui, bank.name());
|
||||
let deposit_native = match token_account_opt {
|
||||
Some(token_account) => {
|
||||
let native = token_account.native(bank);
|
||||
|
||||
let deposit_native = if native < I80F48::ZERO {
|
||||
desired_balance - native
|
||||
} else {
|
||||
desired_balance - native.min(desired_balance)
|
||||
let ui = token_account.ui(bank, mint);
|
||||
log::info!("Current balance {} {}", ui, bank.name());
|
||||
|
||||
if native < I80F48::ZERO {
|
||||
desired_balance - native
|
||||
} else {
|
||||
desired_balance - native.min(desired_balance)
|
||||
}
|
||||
}
|
||||
None => desired_balance,
|
||||
};
|
||||
|
||||
if deposit_native == I80F48::ZERO {
|
||||
|
|
|
@ -728,7 +728,7 @@ impl std::fmt::Debug for MangoAccount {
|
|||
}
|
||||
|
||||
impl MangoAccount {
|
||||
fn name(&self) -> &str {
|
||||
pub fn name(&self) -> &str {
|
||||
std::str::from_utf8(&self.name)
|
||||
.unwrap()
|
||||
.trim_matches(char::from(0))
|
||||
|
|
Loading…
Reference in New Issue