Prefer "group" argument to keeper/liquidator

The admin keypair doesn't need to be passed in. It's only convenient for
testing.
This commit is contained in:
Christian Kamm 2022-07-14 12:57:19 +02:00
parent 5231ee7f98
commit 4e87c07a9a
10 changed files with 67 additions and 49 deletions

10
Cargo.lock generated
View File

@ -2522,6 +2522,7 @@ dependencies = [
"mango-v4",
"pyth-sdk-solana",
"serum_dex",
"shellexpand",
"solana-client",
"solana-sdk",
"tokio",
@ -4506,6 +4507,15 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "shellexpand"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83bdb7831b2d85ddf4a7b148aa19d0587eddbe8671a436b7bd1182eaad0f2829"
dependencies = [
"dirs-next",
]
[[package]]
name = "shlex"
version = "1.1.0"

View File

@ -31,7 +31,6 @@ pub struct MangoClient {
pub cluster: Cluster,
pub commitment: CommitmentConfig,
pub payer: Keypair,
pub admin: Keypair,
pub mango_account_cache: (Pubkey, MangoAccount),
pub group: Pubkey,
pub group_cache: Group,
@ -53,11 +52,19 @@ pub struct MangoClient {
// 2/ pubkey, can be both owned, but also delegated accouns
impl MangoClient {
pub fn group_for_admin(admin: Pubkey, num: u32) -> Pubkey {
Pubkey::find_program_address(
&["Group".as_ref(), admin.as_ref(), num.to_le_bytes().as_ref()],
&mango_v4::ID,
)
.0
}
pub fn new(
cluster: Cluster,
commitment: CommitmentConfig,
payer: Keypair,
admin: Keypair,
group: Pubkey,
mango_account_name: &str,
) -> anyhow::Result<Self> {
let program =
@ -66,16 +73,6 @@ impl MangoClient {
let rpc = program.rpc();
let group = Pubkey::find_program_address(
&[
"Group".as_ref(),
admin.pubkey().as_ref(),
0u32.to_le_bytes().as_ref(),
],
&program.id(),
)
.0;
let group_data = program.account::<Group>(group)?;
// Mango Account
@ -237,7 +234,6 @@ impl MangoClient {
rpc,
cluster,
commitment,
admin,
payer,
mango_account_cache,
group,

View File

@ -1,4 +1,4 @@
RPC_URL=https://mango.devnet.rpcpool.com
PAYER_KEYPAIR=~/.config/solana/mango-devnet.json
ADMIN_KEYPAIR=~/.config/solana/admin.json
GROUP_FROM_ADMIN_KEYPAIR=~/.config/solana/admin.json
MANGO_ACCOUNT_NAME=Account

View File

@ -1,4 +1,4 @@
RPC_URL=
PAYER_KEYPAIR=
ADMIN_KEYPAIR=
GROUP=
MANGO_ACCOUNT_NAME=

View File

@ -1,4 +1,4 @@
RPC_URL=https://mango.rpcpool.com/
PAYER_KEYPAIR=~/.config/solana/mango-mainnet.json
ADMIN_KEYPAIR=~/.config/solana/mango-mainnet.json
GROUP=grouppubkey
MANGO_ACCOUNT_NAME=Account

View File

@ -11,16 +11,17 @@ anchor-lang = "0.24.2"
anchor-spl = "0.24.2"
anyhow = "1.0"
clap = { version = "3.1.8", features = ["derive", "env"] }
client = { path = "../client" }
client = { path = "../client" }
dotenv = "0.15.0"
env_logger = "0.8.4"
fixed = { version = "=1.11.0", features = ["serde", "borsh"] }
fixed-macro = "^1.1.1"
futures = "0.3.21"
log = "0.4.0"
mango-v4 = { path = "../programs/mango-v4" }
mango-v4 = { path = "../programs/mango-v4" }
pyth-sdk-solana = "0.1.0"
serum_dex = { version = "0.4.0", git = "https://github.com/blockworks-foundation/serum-dex.git", default-features=false, features = ["no-entrypoint", "program"] }
solana-client = "~1.9.13"
solana-sdk = "~1.9.13"
tokio = { version = "1.14.1", features = ["rt-multi-thread", "time", "macros", "sync"] }
tokio = { version = "1.14.1", features = ["rt-multi-thread", "time", "macros", "sync"] }
shellexpand = "2.1.0"

View File

@ -2,13 +2,19 @@ mod crank;
mod taker;
use std::env;
use std::str::FromStr;
use std::sync::Arc;
use anchor_client::Cluster;
use clap::{Parser, Subcommand};
use client::MangoClient;
use solana_sdk::{commitment_config::CommitmentConfig, signer::keypair};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::{
commitment_config::CommitmentConfig,
signature::Signer,
signer::{keypair, keypair::Keypair},
};
use tokio::time;
// TODO
@ -27,8 +33,14 @@ struct Cli {
#[clap(short, long, env = "PAYER_KEYPAIR")]
payer: Option<std::path::PathBuf>,
#[clap(short, long, env = "ADMIN_KEYPAIR")]
admin: Option<std::path::PathBuf>,
#[clap(short, long, env = "GROUP")]
group: Option<Pubkey>,
// These exist only as a shorthand to make testing easier. Normal users would provide the group.
#[clap(long, env = "GROUP_FROM_ADMIN_KEYPAIR")]
group_from_admin_keypair: Option<std::path::PathBuf>,
#[clap(long, env = "GROUP_FROM_ADMIN_NUM", default_value = "0")]
group_from_admin_num: u32,
#[clap(short, long, env = "MANGO_ACCOUNT_NAME")]
mango_account_name: String,
@ -37,6 +49,12 @@ struct Cli {
command: Command,
}
fn keypair_from_path(p: &std::path::PathBuf) -> Keypair {
let path = std::path::PathBuf::from_str(&*shellexpand::tilde(p.to_str().unwrap())).unwrap();
keypair::read_keypair_file(path)
.unwrap_or_else(|_| panic!("Failed to read keypair from {}", p.to_string_lossy()))
}
#[derive(Subcommand)]
enum Command {
Crank {},
@ -49,27 +67,14 @@ fn main() -> Result<(), anyhow::Error> {
dotenv::dotenv().ok();
let Cli {
rpc_url,
payer,
admin,
command,
mango_account_name,
} = Cli::parse();
let cli = Cli::parse();
let payer = match payer {
Some(p) => keypair::read_keypair_file(&p)
.unwrap_or_else(|_| panic!("Failed to read keypair from {}", p.to_string_lossy())),
let payer = match cli.payer {
Some(p) => keypair_from_path(&p),
None => panic!("Payer keypair not provided..."),
};
let admin = match admin {
Some(p) => keypair::read_keypair_file(&p)
.unwrap_or_else(|_| panic!("Failed to read keypair from {}", p.to_string_lossy())),
None => panic!("Admin keypair not provided..."),
};
let rpc_url = match rpc_url {
let rpc_url = match cli.rpc_url {
Some(rpc_url) => rpc_url,
None => match env::var("RPC_URL").ok() {
Some(rpc_url) => rpc_url,
@ -79,17 +84,26 @@ fn main() -> Result<(), anyhow::Error> {
let ws_url = rpc_url.replace("https", "wss");
let cluster = Cluster::Custom(rpc_url, ws_url);
let commitment = match command {
let commitment = match cli.command {
Command::Crank { .. } => CommitmentConfig::confirmed(),
Command::Taker { .. } => CommitmentConfig::confirmed(),
};
let group = if let Some(group) = cli.group {
group
} else if let Some(p) = cli.group_from_admin_keypair {
let admin = keypair_from_path(&p);
MangoClient::group_for_admin(admin.pubkey(), cli.group_from_admin_num)
} else {
panic!("Must provide either group or group_from_admin_keypair");
};
let mango_client = Arc::new(MangoClient::new(
cluster,
commitment,
payer,
admin,
&mango_account_name,
group,
&cli.mango_account_name,
)?);
let rt = tokio::runtime::Builder::new_multi_thread()
@ -111,7 +125,7 @@ fn main() -> Result<(), anyhow::Error> {
}
};
match command {
match cli.command {
Command::Crank { .. } => {
let client = mango_client.clone();
rt.block_on(crank::runner(client, debugging_handle))

View File

@ -9,5 +9,4 @@ snapshot_interval_secs = 240
parallel_rpc_requests = 10
get_multiple_accounts_count = 100
payer = "/root/.config/solana/mango-devnet.json"
admin = "/root/.config/solana/admin.json"
mango_account_name = "Taker"

View File

@ -27,5 +27,4 @@ get_multiple_accounts_count = 100
# FUTURE: separate into a separate conf file? we are mixing feed + mango client conf in one place here
# mango client specific
payer = "/root/.config/solana/id.json"
admin = "/root/.config/solana/admin.json"
mango_account_name = "Taker"

View File

@ -66,7 +66,6 @@ pub struct Config {
// FUTURE: split mango client and feed config
// mango client specific
pub payer: String,
pub admin: String,
pub mango_account_name: String,
}
@ -89,12 +88,13 @@ async fn main() -> anyhow::Result<()> {
toml::from_str(&contents).unwrap()
};
let mango_group_id = Pubkey::from_str(&config.mango_group_id)?;
//
// mango client setup
//
let mango_client = {
let payer = keypair::read_keypair_file(&config.payer).unwrap();
let admin = keypair::read_keypair_file(&config.admin).unwrap();
let rpc_url = config.rpc_http_url.to_owned();
let ws_url = rpc_url.replace("https", "wss");
@ -106,7 +106,7 @@ async fn main() -> anyhow::Result<()> {
cluster,
commitment,
payer,
admin,
mango_group_id,
&config.mango_account_name,
)?)
};
@ -123,7 +123,6 @@ async fn main() -> anyhow::Result<()> {
// FUTURE: decouple feed setup and liquidator business logic
// feed should send updates to a channel which liquidator can consume
let mango_program_id = Pubkey::from_str(&config.mango_program_id)?;
let mango_group_id = Pubkey::from_str(&config.mango_group_id)?;
solana_logger::setup_with_default("info");
info!("startup");