Merge branch 'mc/liquidator-bot' into dev
This commit is contained in:
commit
383489ae34
|
@ -1,3 +1,4 @@
|
||||||
RPC_URL=
|
RPC_URL=
|
||||||
PAYER_KEYPAIR=
|
PAYER_KEYPAIR=
|
||||||
ADMIN_KEYPAIR=
|
ADMIN_KEYPAIR=
|
||||||
|
MANGO_ACCOUNT_NAME=
|
|
@ -34,6 +34,9 @@ struct Cli {
|
||||||
#[clap(short, long, env = "ADMIN_KEYPAIR")]
|
#[clap(short, long, env = "ADMIN_KEYPAIR")]
|
||||||
admin: Option<std::path::PathBuf>,
|
admin: Option<std::path::PathBuf>,
|
||||||
|
|
||||||
|
#[clap(short, long, env = "MANGO_ACCOUNT_NAME")]
|
||||||
|
mango_account_name: String,
|
||||||
|
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
command: Command,
|
command: Command,
|
||||||
}
|
}
|
||||||
|
@ -55,6 +58,7 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
payer,
|
payer,
|
||||||
admin,
|
admin,
|
||||||
command,
|
command,
|
||||||
|
mango_account_name,
|
||||||
} = Cli::parse();
|
} = Cli::parse();
|
||||||
|
|
||||||
let payer = match payer {
|
let payer = match payer {
|
||||||
|
@ -84,12 +88,13 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
Command::Taker { .. } => CommitmentConfig::confirmed(),
|
Command::Taker { .. } => CommitmentConfig::confirmed(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mango_client = Arc::new(MangoClient::new(cluster, commitment, payer, admin)?);
|
let mango_client = Arc::new(MangoClient::new(
|
||||||
|
cluster,
|
||||||
log::info!("Program Id {}", &mango_client.program().id());
|
commitment,
|
||||||
log::info!("Admin {}", &mango_client.admin.to_base58_string());
|
payer,
|
||||||
log::info!("Group {}", &mango_client.group());
|
admin,
|
||||||
log::info!("User {}", &mango_client.payer());
|
mango_account_name,
|
||||||
|
)?);
|
||||||
|
|
||||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||||
.enable_all()
|
.enable_all()
|
||||||
|
|
|
@ -13,14 +13,14 @@ use mango_v4::state::{Bank, MangoAccount, MintInfo, PerpMarket, Serum3Market, To
|
||||||
|
|
||||||
use solana_client::rpc_client::RpcClient;
|
use solana_client::rpc_client::RpcClient;
|
||||||
|
|
||||||
|
use crate::util::MyClone;
|
||||||
|
use anyhow::Context;
|
||||||
use solana_client::rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType};
|
use solana_client::rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType};
|
||||||
use solana_sdk::instruction::{AccountMeta, Instruction};
|
use solana_sdk::instruction::{AccountMeta, Instruction};
|
||||||
use solana_sdk::signature::{Keypair, Signature};
|
use solana_sdk::signature::{Keypair, Signature};
|
||||||
use solana_sdk::sysvar;
|
use solana_sdk::sysvar;
|
||||||
use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signer::Signer};
|
use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signer::Signer};
|
||||||
|
|
||||||
use crate::util::MyClone;
|
|
||||||
|
|
||||||
pub struct MangoClient {
|
pub struct MangoClient {
|
||||||
pub rpc: RpcClient,
|
pub rpc: RpcClient,
|
||||||
pub cluster: Cluster,
|
pub cluster: Cluster,
|
||||||
|
@ -51,6 +51,7 @@ impl MangoClient {
|
||||||
commitment: CommitmentConfig,
|
commitment: CommitmentConfig,
|
||||||
payer: Keypair,
|
payer: Keypair,
|
||||||
admin: Keypair,
|
admin: Keypair,
|
||||||
|
mango_account_name: String,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
let program =
|
let program =
|
||||||
Client::new_with_options(cluster.clone(), std::rc::Rc::new(payer.clone()), commitment)
|
Client::new_with_options(cluster.clone(), std::rc::Rc::new(payer.clone()), commitment)
|
||||||
|
@ -59,12 +60,22 @@ impl MangoClient {
|
||||||
let rpc = program.rpc();
|
let rpc = program.rpc();
|
||||||
|
|
||||||
let group = Pubkey::find_program_address(
|
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(),
|
&program.id(),
|
||||||
)
|
)
|
||||||
.0;
|
.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 {
|
RpcFilterType::Memcmp(Memcmp {
|
||||||
offset: 40,
|
offset: 40,
|
||||||
bytes: MemcmpEncodedBytes::Base58(group.to_string()),
|
bytes: MemcmpEncodedBytes::Base58(group.to_string()),
|
||||||
|
@ -76,8 +87,70 @@ impl MangoClient {
|
||||||
encoding: None,
|
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 = HashMap::new();
|
||||||
let mut banks_cache_by_token_index = HashMap::new();
|
let mut banks_cache_by_token_index = HashMap::new();
|
||||||
let bank_tuples = program.accounts::<Bank>(vec![RpcFilterType::Memcmp(Memcmp {
|
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));
|
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 = HashMap::new();
|
||||||
let mut mint_infos_cache_by_token_index = HashMap::new();
|
let mut mint_infos_cache_by_token_index = HashMap::new();
|
||||||
let mint_info_tuples =
|
let mint_info_tuples =
|
||||||
|
@ -111,6 +185,7 @@ impl MangoClient {
|
||||||
mint_infos_cache_by_token_index.insert(v.token_index, (k, v, mint));
|
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_markets_cache = HashMap::new();
|
||||||
let mut serum3_external_markets_cache = HashMap::new();
|
let mut serum3_external_markets_cache = HashMap::new();
|
||||||
let serum3_market_tuples =
|
let serum3_market_tuples =
|
||||||
|
@ -134,6 +209,7 @@ impl MangoClient {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// perp markets cache
|
||||||
let mut perp_markets_cache = HashMap::new();
|
let mut perp_markets_cache = HashMap::new();
|
||||||
let perp_market_tuples =
|
let perp_market_tuples =
|
||||||
program.accounts::<PerpMarket>(vec![RpcFilterType::Memcmp(Memcmp {
|
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 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 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 token_account_opt = mango_account.tokens.find(bank.token_index);
|
||||||
let native = token_account.native(bank);
|
|
||||||
|
|
||||||
let ui = token_account.ui(bank, mint);
|
let deposit_native = match token_account_opt {
|
||||||
log::info!("Current balance {} {}", ui, bank.name());
|
Some(token_account) => {
|
||||||
|
let native = token_account.native(bank);
|
||||||
|
|
||||||
let deposit_native = if native < I80F48::ZERO {
|
let ui = token_account.ui(bank, mint);
|
||||||
desired_balance - native
|
log::info!("Current balance {} {}", ui, bank.name());
|
||||||
} else {
|
|
||||||
desired_balance - native.min(desired_balance)
|
if native < I80F48::ZERO {
|
||||||
|
desired_balance - native
|
||||||
|
} else {
|
||||||
|
desired_balance - native.min(desired_balance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => desired_balance,
|
||||||
};
|
};
|
||||||
|
|
||||||
if deposit_native == I80F48::ZERO {
|
if deposit_native == I80F48::ZERO {
|
||||||
|
|
|
@ -728,7 +728,7 @@ impl std::fmt::Debug for MangoAccount {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MangoAccount {
|
impl MangoAccount {
|
||||||
fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
std::str::from_utf8(&self.name)
|
std::str::from_utf8(&self.name)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.trim_matches(char::from(0))
|
.trim_matches(char::from(0))
|
||||||
|
|
Loading…
Reference in New Issue