client: construct from account pubkeys
This commit is contained in:
parent
16290e07f4
commit
b0dae7ec22
|
@ -1,7 +1,9 @@
|
||||||
|
use std::rc::Rc;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use anchor_client::{Client, ClientError, Cluster, Program};
|
use anchor_client::{ClientError, Cluster, Program};
|
||||||
|
|
||||||
use anchor_lang::__private::bytemuck;
|
use anchor_lang::__private::bytemuck;
|
||||||
use anchor_lang::prelude::System;
|
use anchor_lang::prelude::System;
|
||||||
|
@ -28,17 +30,45 @@ 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};
|
||||||
|
|
||||||
|
// very close to anchor_client::Client, which unfortunately has no accessors or Clone
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Client {
|
||||||
|
pub cluster: Cluster,
|
||||||
|
pub fee_payer: Arc<Keypair>,
|
||||||
|
pub commitment: CommitmentConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Client {
|
||||||
|
pub fn new(cluster: Cluster, commitment: CommitmentConfig, fee_payer: &Keypair) -> Self {
|
||||||
|
Self {
|
||||||
|
cluster,
|
||||||
|
fee_payer: Arc::new(fee_payer.clone()),
|
||||||
|
commitment,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn anchor_client(&self) -> anchor_client::Client {
|
||||||
|
anchor_client::Client::new_with_options(
|
||||||
|
self.cluster.clone(),
|
||||||
|
Rc::new((*self.fee_payer).clone()),
|
||||||
|
self.commitment,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rpc_with_timeout(&self, timeout: Duration) -> RpcClient {
|
||||||
|
RpcClient::new_with_timeout_and_commitment(self.cluster.clone(), timeout, self.commitment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// todo: might want to integrate geyser, websockets, or simple http polling for keeping data fresh
|
// todo: might want to integrate geyser, websockets, or simple http polling for keeping data fresh
|
||||||
pub struct MangoClient {
|
pub struct MangoClient {
|
||||||
pub rpc: RpcClient,
|
pub client: Client,
|
||||||
pub cluster: Cluster,
|
|
||||||
pub commitment: CommitmentConfig,
|
|
||||||
|
|
||||||
// todo: possibly this object should have cache-functions, so there can be one getMultipleAccounts
|
// todo: possibly this object should have cache-functions, so there can be one getMultipleAccounts
|
||||||
// call to refresh banks etc -- if it's backed by websockets, these could just do nothing
|
// call to refresh banks etc -- if it's backed by websockets, these could just do nothing
|
||||||
pub account_fetcher: Arc<dyn AccountFetcher>,
|
pub account_fetcher: Arc<dyn AccountFetcher>,
|
||||||
|
|
||||||
pub payer: Keypair,
|
pub owner: Keypair,
|
||||||
pub mango_account_address: Pubkey,
|
pub mango_account_address: Pubkey,
|
||||||
|
|
||||||
pub context: MangoGroupContext,
|
pub context: MangoGroupContext,
|
||||||
|
@ -58,48 +88,17 @@ impl MangoClient {
|
||||||
.0
|
.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Conveniently creates a RPC based client
|
pub fn find_or_create_account(
|
||||||
pub fn new(
|
client: &Client,
|
||||||
cluster: Cluster,
|
|
||||||
commitment: CommitmentConfig,
|
|
||||||
group: Pubkey,
|
group: Pubkey,
|
||||||
payer: Keypair,
|
owner: Keypair,
|
||||||
|
payer: Keypair, // pays the SOL for the new account
|
||||||
mango_account_name: &str,
|
mango_account_name: &str,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Pubkey> {
|
||||||
let group_context = MangoGroupContext::new_from_rpc(group, cluster.clone(), commitment)?;
|
let program = client.anchor_client().program(mango_v4::ID);
|
||||||
|
|
||||||
let rpc = RpcClient::new_with_commitment(cluster.url().to_string(), commitment);
|
|
||||||
let account_fetcher = Arc::new(CachedAccountFetcher::new(RpcAccountFetcher { rpc }));
|
|
||||||
|
|
||||||
Self::new_detail(
|
|
||||||
cluster,
|
|
||||||
commitment,
|
|
||||||
payer,
|
|
||||||
mango_account_name,
|
|
||||||
group_context,
|
|
||||||
account_fetcher,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Allows control of AccountFetcher and externally created MangoGroupContext
|
|
||||||
pub fn new_detail(
|
|
||||||
cluster: Cluster,
|
|
||||||
commitment: CommitmentConfig,
|
|
||||||
payer: Keypair,
|
|
||||||
mango_account_name: &str,
|
|
||||||
// future: maybe pass Arc<MangoGroupContext>, so it can be extenally updated?
|
|
||||||
group_context: MangoGroupContext,
|
|
||||||
account_fetcher: Arc<dyn AccountFetcher>,
|
|
||||||
) -> anyhow::Result<Self> {
|
|
||||||
let program =
|
|
||||||
Client::new_with_options(cluster.clone(), std::rc::Rc::new(payer.clone()), commitment)
|
|
||||||
.program(mango_v4::ID);
|
|
||||||
|
|
||||||
let rpc = program.rpc();
|
|
||||||
let group = group_context.group;
|
|
||||||
|
|
||||||
// Mango Account
|
// Mango Account
|
||||||
let mut mango_account_tuples = fetch_mango_accounts(&program, group, payer.pubkey())?;
|
let mut mango_account_tuples = fetch_mango_accounts(&program, group, owner.pubkey())?;
|
||||||
let mango_account_opt = mango_account_tuples
|
let mango_account_opt = mango_account_tuples
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(_, account)| account.fixed.name() == mango_account_name);
|
.find(|(_, account)| account.fixed.name() == mango_account_name);
|
||||||
|
@ -121,13 +120,13 @@ impl MangoClient {
|
||||||
accounts: anchor_lang::ToAccountMetas::to_account_metas(
|
accounts: anchor_lang::ToAccountMetas::to_account_metas(
|
||||||
&mango_v4::accounts::AccountCreate {
|
&mango_v4::accounts::AccountCreate {
|
||||||
group,
|
group,
|
||||||
owner: payer.pubkey(),
|
owner: owner.pubkey(),
|
||||||
account: {
|
account: {
|
||||||
Pubkey::find_program_address(
|
Pubkey::find_program_address(
|
||||||
&[
|
&[
|
||||||
group.as_ref(),
|
group.as_ref(),
|
||||||
b"MangoAccount".as_ref(),
|
b"MangoAccount".as_ref(),
|
||||||
payer.pubkey().as_ref(),
|
owner.pubkey().as_ref(),
|
||||||
&account_num.to_le_bytes(),
|
&account_num.to_le_bytes(),
|
||||||
],
|
],
|
||||||
&mango_v4::id(),
|
&mango_v4::id(),
|
||||||
|
@ -147,42 +146,72 @@ impl MangoClient {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
.signer(&owner)
|
||||||
|
.signer(&payer)
|
||||||
.send()
|
.send()
|
||||||
.map_err(prettify_client_error)
|
.map_err(prettify_client_error)
|
||||||
.context("Failed to create account...")?;
|
.context("Failed to create account...")?;
|
||||||
}
|
}
|
||||||
let mango_account_tuples = fetch_mango_accounts(&program, group, payer.pubkey())?;
|
let mango_account_tuples = fetch_mango_accounts(&program, group, owner.pubkey())?;
|
||||||
let index = mango_account_tuples
|
let index = mango_account_tuples
|
||||||
.iter()
|
.iter()
|
||||||
.position(|tuple| tuple.1.fixed.name() == mango_account_name)
|
.position(|tuple| tuple.1.fixed.name() == mango_account_name)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mango_account_cache = &mango_account_tuples[index];
|
Ok(mango_account_tuples[index].0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Conveniently creates a RPC based client
|
||||||
|
pub fn new_for_existing_account(
|
||||||
|
client: Client,
|
||||||
|
account: Pubkey,
|
||||||
|
owner: Keypair,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
let rpc = client.rpc_with_timeout(Duration::from_secs(60));
|
||||||
|
let account_fetcher = Arc::new(CachedAccountFetcher::new(RpcAccountFetcher { rpc }));
|
||||||
|
let mango_account = account_fetcher_fetch_mango_account(&*account_fetcher, account)?;
|
||||||
|
let group = mango_account.fixed.group;
|
||||||
|
if mango_account.fixed.owner != owner.pubkey() {
|
||||||
|
anyhow::bail!(
|
||||||
|
"bad owner for account: expected {} got {}",
|
||||||
|
mango_account.fixed.owner,
|
||||||
|
owner.pubkey()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let group_context =
|
||||||
|
MangoGroupContext::new_from_rpc(group, client.cluster.clone(), client.commitment)?;
|
||||||
|
|
||||||
|
Self::new_detail(client, account, owner, group_context, account_fetcher)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows control of AccountFetcher and externally created MangoGroupContext
|
||||||
|
pub fn new_detail(
|
||||||
|
client: Client,
|
||||||
|
account: Pubkey,
|
||||||
|
owner: Keypair,
|
||||||
|
// future: maybe pass Arc<MangoGroupContext>, so it can be extenally updated?
|
||||||
|
group_context: MangoGroupContext,
|
||||||
|
account_fetcher: Arc<dyn AccountFetcher>,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
rpc,
|
client,
|
||||||
cluster,
|
|
||||||
commitment,
|
|
||||||
account_fetcher,
|
account_fetcher,
|
||||||
payer,
|
owner,
|
||||||
mango_account_address: mango_account_cache.0,
|
mango_account_address: account,
|
||||||
context: group_context,
|
context: group_context,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn client(&self) -> Client {
|
pub fn anchor_client(&self) -> anchor_client::Client {
|
||||||
Client::new_with_options(
|
self.client.anchor_client()
|
||||||
self.cluster.clone(),
|
|
||||||
std::rc::Rc::new(self.payer.clone()),
|
|
||||||
self.commitment,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn program(&self) -> Program {
|
pub fn program(&self) -> Program {
|
||||||
self.client().program(mango_v4::ID)
|
self.anchor_client().program(mango_v4::ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn payer(&self) -> Pubkey {
|
pub fn owner(&self) -> Pubkey {
|
||||||
self.payer.pubkey()
|
self.owner.pubkey()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn group(&self) -> Pubkey {
|
pub fn group(&self) -> Pubkey {
|
||||||
|
@ -282,10 +311,10 @@ impl MangoClient {
|
||||||
bank: mint_info.first_bank(),
|
bank: mint_info.first_bank(),
|
||||||
vault: mint_info.first_vault(),
|
vault: mint_info.first_vault(),
|
||||||
token_account: get_associated_token_address(
|
token_account: get_associated_token_address(
|
||||||
&self.payer(),
|
&self.owner(),
|
||||||
&mint_info.mint,
|
&mint_info.mint,
|
||||||
),
|
),
|
||||||
token_authority: self.payer(),
|
token_authority: self.owner(),
|
||||||
token_program: Token::id(),
|
token_program: Token::id(),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
|
@ -297,6 +326,7 @@ impl MangoClient {
|
||||||
amount,
|
amount,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
.signer(&self.owner)
|
||||||
.send()
|
.send()
|
||||||
.map_err(prettify_client_error)
|
.map_err(prettify_client_error)
|
||||||
}
|
}
|
||||||
|
@ -348,8 +378,8 @@ impl MangoClient {
|
||||||
serum_program: serum3_info.market.serum_program,
|
serum_program: serum3_info.market.serum_program,
|
||||||
serum_market_external: serum3_info.market.serum_market_external,
|
serum_market_external: serum3_info.market.serum_market_external,
|
||||||
open_orders,
|
open_orders,
|
||||||
owner: self.payer(),
|
owner: self.owner(),
|
||||||
payer: self.payer(),
|
payer: self.owner(),
|
||||||
system_program: System::id(),
|
system_program: System::id(),
|
||||||
rent: sysvar::rent::id(),
|
rent: sysvar::rent::id(),
|
||||||
},
|
},
|
||||||
|
@ -359,6 +389,7 @@ impl MangoClient {
|
||||||
&mango_v4::instruction::Serum3CreateOpenOrders {},
|
&mango_v4::instruction::Serum3CreateOpenOrders {},
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
.signer(&self.owner)
|
||||||
.send()
|
.send()
|
||||||
.map_err(prettify_client_error)
|
.map_err(prettify_client_error)
|
||||||
}
|
}
|
||||||
|
@ -482,7 +513,7 @@ impl MangoClient {
|
||||||
market_base_vault: s3.market.coin_vault,
|
market_base_vault: s3.market.coin_vault,
|
||||||
market_quote_vault: s3.market.pc_vault,
|
market_quote_vault: s3.market.pc_vault,
|
||||||
market_vault_signer: s3.market.vault_signer,
|
market_vault_signer: s3.market.vault_signer,
|
||||||
owner: self.payer(),
|
owner: self.owner(),
|
||||||
token_program: Token::id(),
|
token_program: Token::id(),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
|
@ -503,6 +534,7 @@ impl MangoClient {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
.signer(&self.owner)
|
||||||
.send()
|
.send()
|
||||||
.map_err(prettify_client_error)
|
.map_err(prettify_client_error)
|
||||||
}
|
}
|
||||||
|
@ -532,7 +564,7 @@ impl MangoClient {
|
||||||
market_base_vault: s3.market.coin_vault,
|
market_base_vault: s3.market.coin_vault,
|
||||||
market_quote_vault: s3.market.pc_vault,
|
market_quote_vault: s3.market.pc_vault,
|
||||||
market_vault_signer: s3.market.vault_signer,
|
market_vault_signer: s3.market.vault_signer,
|
||||||
owner: self.payer(),
|
owner: self.owner(),
|
||||||
token_program: Token::id(),
|
token_program: Token::id(),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
|
@ -541,6 +573,7 @@ impl MangoClient {
|
||||||
&mango_v4::instruction::Serum3SettleFunds {},
|
&mango_v4::instruction::Serum3SettleFunds {},
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
.signer(&self.owner)
|
||||||
.send()
|
.send()
|
||||||
.map_err(prettify_client_error)
|
.map_err(prettify_client_error)
|
||||||
}
|
}
|
||||||
|
@ -602,7 +635,7 @@ impl MangoClient {
|
||||||
market_bids: s3.market.bids,
|
market_bids: s3.market.bids,
|
||||||
market_asks: s3.market.asks,
|
market_asks: s3.market.asks,
|
||||||
market_event_queue: s3.market.event_q,
|
market_event_queue: s3.market.event_q,
|
||||||
owner: self.payer(),
|
owner: self.owner(),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
@ -611,6 +644,7 @@ impl MangoClient {
|
||||||
&mango_v4::instruction::Serum3CancelOrder { side, order_id },
|
&mango_v4::instruction::Serum3CancelOrder { side, order_id },
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
.signer(&self.owner)
|
||||||
.send()
|
.send()
|
||||||
.map_err(prettify_client_error)?;
|
.map_err(prettify_client_error)?;
|
||||||
|
|
||||||
|
@ -650,7 +684,7 @@ impl MangoClient {
|
||||||
group: self.group(),
|
group: self.group(),
|
||||||
liqee: *liqee.0,
|
liqee: *liqee.0,
|
||||||
liqor: self.mango_account_address,
|
liqor: self.mango_account_address,
|
||||||
liqor_owner: self.payer.pubkey(),
|
liqor_owner: self.owner(),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
@ -665,6 +699,7 @@ impl MangoClient {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
.signer(&self.owner)
|
||||||
.send()
|
.send()
|
||||||
.map_err(prettify_client_error)
|
.map_err(prettify_client_error)
|
||||||
}
|
}
|
||||||
|
@ -714,7 +749,7 @@ impl MangoClient {
|
||||||
group: self.group(),
|
group: self.group(),
|
||||||
liqee: *liqee.0,
|
liqee: *liqee.0,
|
||||||
liqor: self.mango_account_address,
|
liqor: self.mango_account_address,
|
||||||
liqor_owner: self.payer.pubkey(),
|
liqor_owner: self.owner(),
|
||||||
liab_mint_info: liab_info.mint_info_address,
|
liab_mint_info: liab_info.mint_info_address,
|
||||||
quote_vault: quote_info.mint_info.first_vault(),
|
quote_vault: quote_info.mint_info.first_vault(),
|
||||||
insurance_vault: group.insurance_vault,
|
insurance_vault: group.insurance_vault,
|
||||||
|
@ -733,6 +768,7 @@ impl MangoClient {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
.signer(&self.owner)
|
||||||
.send()
|
.send()
|
||||||
.map_err(prettify_client_error)
|
.map_err(prettify_client_error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
RPC_URL=
|
RPC_URL=
|
||||||
PAYER_KEYPAIR=
|
MANGO_ACCOUNT=
|
||||||
GROUP=
|
OWNER=
|
||||||
MANGO_ACCOUNT_NAME=
|
|
||||||
|
|
|
@ -6,9 +6,9 @@ use std::sync::Arc;
|
||||||
use anchor_client::Cluster;
|
use anchor_client::Cluster;
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use client::{keypair_from_cli, MangoClient};
|
use client::{keypair_from_cli, Client, MangoClient};
|
||||||
|
use solana_sdk::commitment_config::CommitmentConfig;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::{commitment_config::CommitmentConfig, signature::Signer};
|
|
||||||
use tokio::time;
|
use tokio::time;
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -34,21 +34,11 @@ struct Cli {
|
||||||
#[clap(short, long, env)]
|
#[clap(short, long, env)]
|
||||||
rpc_url: String,
|
rpc_url: String,
|
||||||
|
|
||||||
#[clap(short, long, env = "PAYER_KEYPAIR")]
|
#[clap(short, long, env)]
|
||||||
payer: String,
|
mango_account: Pubkey,
|
||||||
|
|
||||||
#[clap(short, long, env)]
|
#[clap(short, long, env)]
|
||||||
group: Option<Pubkey>,
|
owner: String,
|
||||||
|
|
||||||
// These exist only as a shorthand to make testing easier. Normal users would provide the group.
|
|
||||||
#[clap(long, env)]
|
|
||||||
group_from_admin_keypair: Option<String>,
|
|
||||||
|
|
||||||
#[clap(long, env, default_value = "0")]
|
|
||||||
group_from_admin_num: u32,
|
|
||||||
|
|
||||||
#[clap(short, long, env)]
|
|
||||||
mango_account_name: String,
|
|
||||||
|
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
command: Command,
|
command: Command,
|
||||||
|
@ -73,7 +63,7 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
};
|
};
|
||||||
let cli = Cli::parse_from(args);
|
let cli = Cli::parse_from(args);
|
||||||
|
|
||||||
let payer = keypair_from_cli(&cli.payer);
|
let owner = keypair_from_cli(&cli.owner);
|
||||||
|
|
||||||
let rpc_url = cli.rpc_url;
|
let rpc_url = cli.rpc_url;
|
||||||
let ws_url = rpc_url.replace("https", "wss");
|
let ws_url = rpc_url.replace("https", "wss");
|
||||||
|
@ -84,21 +74,10 @@ fn main() -> Result<(), anyhow::Error> {
|
||||||
Command::Taker { .. } => CommitmentConfig::confirmed(),
|
Command::Taker { .. } => CommitmentConfig::confirmed(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let group = if let Some(group) = cli.group {
|
let mango_client = Arc::new(MangoClient::new_for_existing_account(
|
||||||
group
|
Client::new(cluster, commitment, &owner),
|
||||||
} else if let Some(p) = cli.group_from_admin_keypair {
|
cli.mango_account,
|
||||||
let admin = keypair_from_cli(&p);
|
owner,
|
||||||
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,
|
|
||||||
group,
|
|
||||||
payer,
|
|
||||||
&cli.mango_account_name,
|
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
let rt = tokio::runtime::Builder::new_multi_thread()
|
let rt = tokio::runtime::Builder::new_multi_thread()
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
RPC_URL=https://mango.devnet.rpcpool.com
|
RPC_URL=https://mango.devnet.rpcpool.com
|
||||||
GROUP=9njq91AuvDD6MXxr1uPiHY1B5ACHv6r6z5ZrCpz7sqtQ
|
|
||||||
PYTH_PROGRAM=gSbePebfvPy7tRqimPoVecS2UsBvYv46ynrzWocc92s
|
|
||||||
SERUM_PROGRAM=DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY
|
SERUM_PROGRAM=DESVgJVGajEgKGXhb6XmqDHGz3VjdgP7rEVESBgxmroY
|
||||||
|
LIQOR_MANGO_ACCOUNT=
|
||||||
LIQOR_OWNER=~/.config/solana/user.json
|
LIQOR_OWNER=~/.config/solana/user.json
|
||||||
LIQOR_MANGO_ACCOUNT_NAME=my_mango_account
|
|
||||||
|
|
|
@ -4,14 +4,12 @@ use std::time::Duration;
|
||||||
|
|
||||||
use anchor_client::Cluster;
|
use anchor_client::Cluster;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use client::{chain_data, keypair_from_cli, MangoClient, MangoGroupContext};
|
use client::{chain_data, keypair_from_cli, Client, MangoClient, MangoGroupContext};
|
||||||
use log::*;
|
use log::*;
|
||||||
use mango_v4::state::{PerpMarketIndex, TokenIndex};
|
use mango_v4::state::{PerpMarketIndex, TokenIndex};
|
||||||
|
|
||||||
use solana_client::rpc_client::RpcClient;
|
|
||||||
use solana_sdk::commitment_config::CommitmentConfig;
|
use solana_sdk::commitment_config::CommitmentConfig;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::signer::Signer;
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
pub mod account_shared_data;
|
pub mod account_shared_data;
|
||||||
|
@ -56,29 +54,15 @@ struct Cli {
|
||||||
#[clap(short, long, env)]
|
#[clap(short, long, env)]
|
||||||
rpc_url: String,
|
rpc_url: String,
|
||||||
|
|
||||||
#[clap(long, env)]
|
|
||||||
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: Option<String>,
|
|
||||||
|
|
||||||
#[clap(long, env, default_value = "0")]
|
|
||||||
group_from_admin_num: u32,
|
|
||||||
|
|
||||||
// TODO: maybe store this in the group, so it's easy to start without providing it?
|
|
||||||
#[clap(long, env)]
|
|
||||||
pyth_program: Pubkey,
|
|
||||||
|
|
||||||
// TODO: different serum markets could use different serum programs, should come from registered markets
|
// TODO: different serum markets could use different serum programs, should come from registered markets
|
||||||
#[clap(long, env)]
|
#[clap(long, env)]
|
||||||
serum_program: Pubkey,
|
serum_program: Pubkey,
|
||||||
|
|
||||||
#[clap(long, env)]
|
#[clap(long, env)]
|
||||||
liqor_owner: String,
|
liqor_mango_account: Pubkey,
|
||||||
|
|
||||||
#[clap(long, env)]
|
#[clap(long, env)]
|
||||||
liqor_mango_account_name: String,
|
liqor_owner: String,
|
||||||
|
|
||||||
#[clap(long, env, default_value = "300")]
|
#[clap(long, env, default_value = "300")]
|
||||||
snapshot_interval_secs: u64,
|
snapshot_interval_secs: u64,
|
||||||
|
@ -109,21 +93,25 @@ async fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
let liqor_owner = keypair_from_cli(&cli.liqor_owner);
|
let liqor_owner = keypair_from_cli(&cli.liqor_owner);
|
||||||
|
|
||||||
let mango_group = if let Some(group) = cli.group {
|
|
||||||
group
|
|
||||||
} else if let Some(p) = cli.group_from_admin_keypair {
|
|
||||||
let admin = keypair_from_cli(&p);
|
|
||||||
MangoClient::group_for_admin(admin.pubkey(), cli.group_from_admin_num)
|
|
||||||
} else {
|
|
||||||
panic!("Must provide either group or group_from_admin_keypair");
|
|
||||||
};
|
|
||||||
|
|
||||||
let rpc_url = cli.rpc_url;
|
let rpc_url = cli.rpc_url;
|
||||||
let ws_url = rpc_url.replace("https", "wss");
|
let ws_url = rpc_url.replace("https", "wss");
|
||||||
|
|
||||||
let rpc_timeout = Duration::from_secs(1);
|
let rpc_timeout = Duration::from_secs(1);
|
||||||
let cluster = Cluster::Custom(rpc_url.clone(), ws_url.clone());
|
let cluster = Cluster::Custom(rpc_url.clone(), ws_url.clone());
|
||||||
let commitment = CommitmentConfig::processed();
|
let commitment = CommitmentConfig::processed();
|
||||||
|
let client = Client::new(cluster.clone(), commitment, &liqor_owner);
|
||||||
|
|
||||||
|
// The representation of current on-chain account data
|
||||||
|
let chain_data = Arc::new(RwLock::new(chain_data::ChainData::new()));
|
||||||
|
// Reading accounts from chain_data
|
||||||
|
let account_fetcher = Arc::new(chain_data::AccountFetcher {
|
||||||
|
chain_data: chain_data.clone(),
|
||||||
|
rpc: client.rpc_with_timeout(rpc_timeout),
|
||||||
|
});
|
||||||
|
|
||||||
|
let mango_account = account_fetcher.fetch_fresh_mango_account(&cli.liqor_mango_account)?;
|
||||||
|
let mango_group = mango_account.fixed.group;
|
||||||
|
|
||||||
let group_context = MangoGroupContext::new_from_rpc(mango_group, cluster.clone(), commitment)?;
|
let group_context = MangoGroupContext::new_from_rpc(mango_group, cluster.clone(), commitment)?;
|
||||||
|
|
||||||
// TODO: this is all oracles, not just pyth!
|
// TODO: this is all oracles, not just pyth!
|
||||||
|
@ -185,18 +173,6 @@ async fn main() -> anyhow::Result<()> {
|
||||||
snapshot_sender,
|
snapshot_sender,
|
||||||
);
|
);
|
||||||
|
|
||||||
// The representation of current on-chain account data
|
|
||||||
let chain_data = Arc::new(RwLock::new(chain_data::ChainData::new()));
|
|
||||||
// Reading accounts from chain_data
|
|
||||||
let account_fetcher = Arc::new(chain_data::AccountFetcher {
|
|
||||||
chain_data: chain_data.clone(),
|
|
||||||
rpc: RpcClient::new_with_timeout_and_commitment(
|
|
||||||
cluster.url().to_string(),
|
|
||||||
rpc_timeout,
|
|
||||||
commitment,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
start_chain_data_metrics(chain_data.clone(), &metrics);
|
start_chain_data_metrics(chain_data.clone(), &metrics);
|
||||||
|
|
||||||
// Addresses of the MangoAccounts belonging to the mango program.
|
// Addresses of the MangoAccounts belonging to the mango program.
|
||||||
|
@ -227,10 +203,9 @@ async fn main() -> anyhow::Result<()> {
|
||||||
//
|
//
|
||||||
let mango_client = {
|
let mango_client = {
|
||||||
Arc::new(MangoClient::new_detail(
|
Arc::new(MangoClient::new_detail(
|
||||||
cluster,
|
client,
|
||||||
commitment,
|
cli.liqor_mango_account,
|
||||||
liqor_owner,
|
liqor_owner,
|
||||||
&cli.liqor_mango_account_name,
|
|
||||||
group_context,
|
group_context,
|
||||||
account_fetcher.clone(),
|
account_fetcher.clone(),
|
||||||
)?)
|
)?)
|
||||||
|
|
Loading…
Reference in New Issue