2022-05-06 05:19:49 -07:00
mod consume_events ;
mod crank ;
2022-05-06 01:13:33 -07:00
mod update_index ;
use std ::env ;
2022-05-06 07:45:04 -07:00
use std ::sync ::Arc ;
2022-04-09 12:18:07 -07:00
2022-04-13 07:41:15 -07:00
use anchor_client ::{ Client , Cluster , Program } ;
2022-05-06 01:13:33 -07:00
2022-04-13 07:41:15 -07:00
use clap ::{ Parser , Subcommand } ;
2022-05-06 01:13:33 -07:00
2022-04-13 07:41:15 -07:00
use solana_client ::rpc_client ::RpcClient ;
2022-05-06 01:13:33 -07:00
2022-04-13 07:41:15 -07:00
use solana_sdk ::signature ::Keypair ;
use solana_sdk ::{
commitment_config ::CommitmentConfig ,
pubkey ::Pubkey ,
signer ::{ keypair , Signer } ,
} ;
2022-05-06 07:45:04 -07:00
use tokio ::time ;
2022-04-09 12:18:07 -07:00
2022-04-14 03:42:13 -07:00
// TODO
// - may be nice to have one-shot cranking as well as the interval cranking
// - doing a gPA for all banks call every 10millis may be too often,
// might make sense that we maintain a service when users should query group for changes
// - I'm really annoyed about Keypair not being clonable. Seems everyone works around that manually. Should make a PR to solana to newtype it and provide that function.
// keypair_from_arg_or_env could be a function
2022-04-13 07:41:15 -07:00
/// Wrapper around anchor client with some mango specific useful things
pub struct MangoClient {
pub rpc : RpcClient ,
pub cluster : Cluster ,
pub commitment : CommitmentConfig ,
pub payer : Keypair ,
pub admin : Keypair ,
}
impl MangoClient {
pub fn new (
cluster : Cluster ,
commitment : CommitmentConfig ,
payer : Keypair ,
admin : Keypair ,
) -> Self {
let program = Client ::new_with_options (
cluster . clone ( ) ,
std ::rc ::Rc ::new ( Keypair ::from_bytes ( & payer . to_bytes ( ) ) . unwrap ( ) ) ,
commitment ,
)
. program ( mango_v4 ::ID ) ;
let rpc = program . rpc ( ) ;
Self {
rpc ,
cluster ,
commitment ,
admin ,
payer ,
}
}
2022-05-06 01:13:33 -07:00
pub fn client ( & self ) -> Client {
Client ::new_with_options (
self . cluster . clone ( ) ,
std ::rc ::Rc ::new ( Keypair ::from_bytes ( & self . payer . to_bytes ( ) ) . unwrap ( ) ) ,
self . commitment ,
)
}
pub fn program ( & self ) -> Program {
self . client ( ) . program ( mango_v4 ::ID )
}
2022-04-13 07:41:15 -07:00
pub fn payer ( & self ) -> Pubkey {
self . payer . pubkey ( )
}
pub fn admin ( & self ) -> Pubkey {
self . payer . pubkey ( )
}
}
#[ derive(Parser) ]
#[ clap() ]
struct Cli {
#[ clap(short, long, env = " RPC_URL " ) ]
rpc_url : Option < String > ,
#[ clap(short, long, env = " PAYER_KEYPAIR " ) ]
payer : Option < std ::path ::PathBuf > ,
#[ clap(short, long, env = " ADMIN_KEYPAIR " ) ]
admin : Option < std ::path ::PathBuf > ,
#[ clap(subcommand) ]
command : Command ,
}
#[ derive(Subcommand) ]
enum Command {
Crank { } ,
2022-05-06 01:13:33 -07:00
Liquidator { } ,
2022-04-13 07:41:15 -07:00
}
2022-05-06 01:13:33 -07:00
fn main ( ) -> Result < ( ) , anyhow ::Error > {
2022-04-13 07:41:15 -07:00
env_logger ::init_from_env (
env_logger ::Env ::default ( ) . filter_or ( env_logger ::DEFAULT_FILTER_ENV , " info " ) ,
) ;
dotenv ::dotenv ( ) . ok ( ) ;
let Cli {
rpc_url ,
payer ,
admin ,
command ,
} = 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 ( ) ) ) ,
None = > match env ::var ( " PAYER_KEYPAIR " ) . ok ( ) {
Some ( k ) = > {
keypair ::read_keypair ( & mut k . as_bytes ( ) ) . expect ( " Failed to parse $PAYER_KEYPAIR " )
}
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 = > match env ::var ( " ADMIN_KEYPAIR " ) . ok ( ) {
Some ( k ) = > {
keypair ::read_keypair ( & mut k . as_bytes ( ) ) . expect ( " Failed to parse $ADMIN_KEYPAIR " )
}
None = > panic! ( " Admin keypair not provided... " ) ,
} ,
} ;
let rpc_url = match rpc_url {
Some ( rpc_url ) = > rpc_url ,
None = > match env ::var ( " RPC_URL " ) . ok ( ) {
Some ( rpc_url ) = > rpc_url ,
None = > panic! ( " Rpc URL not provided... " ) ,
} ,
} ;
let ws_url = rpc_url . replace ( " https " , " wss " ) ;
let cluster = Cluster ::Custom ( rpc_url , ws_url ) ;
let commitment = match command {
2022-05-06 01:13:33 -07:00
Command ::Crank { .. } = > CommitmentConfig ::confirmed ( ) ,
2022-05-06 05:19:49 -07:00
Command ::Liquidator { } = > todo! ( ) ,
2022-04-13 07:41:15 -07:00
} ;
2022-05-06 07:45:04 -07:00
let mango_client = Arc ::new ( MangoClient ::new ( cluster , commitment , payer , admin ) ) ;
2022-04-13 07:41:15 -07:00
2022-05-11 04:33:01 -07:00
log ::info! ( " Program Id {} " , & mango_client . program ( ) . id ( ) ) ;
log ::info! ( " Admin {} " , & mango_client . admin . to_base58_string ( ) ) ;
2022-04-09 12:18:07 -07:00
let rt = tokio ::runtime ::Builder ::new_multi_thread ( )
. enable_all ( )
. build ( )
. unwrap ( ) ;
2022-05-09 04:24:33 -07:00
// TODO: future: remove, just for learning purposes
2022-05-06 07:45:04 -07:00
let debugging_handle = async {
let mut interval = time ::interval ( time ::Duration ::from_secs ( 5 ) ) ;
loop {
interval . tick ( ) . await ;
let client = mango_client . clone ( ) ;
tokio ::task ::spawn_blocking ( move | | {
log ::info! (
" std::sync::Arc<MangoClient>::strong_count() {} " ,
Arc ::< MangoClient > ::strong_count ( & client )
)
} ) ;
}
} ;
2022-05-06 01:13:33 -07:00
match command {
Command ::Crank { .. } = > {
2022-05-06 07:45:04 -07:00
let client = mango_client . clone ( ) ;
let x : Result < ( ) , anyhow ::Error > = rt . block_on ( crank ::runner ( client , debugging_handle ) ) ;
2022-05-06 01:13:33 -07:00
x . expect ( " Something went wrong here... " ) ;
2022-04-13 10:47:31 -07:00
}
2022-05-06 05:19:49 -07:00
Command ::Liquidator { .. } = > {
todo! ( )
}
2022-04-13 07:41:15 -07:00
}
2022-04-09 12:18:07 -07:00
2022-04-13 07:41:15 -07:00
Ok ( ( ) )
2022-04-09 12:18:07 -07:00
}