client: configurable jupiter urls (#800)

This commit is contained in:
Christian Kamm 2023-12-05 13:23:11 +01:00 committed by GitHub
parent ce16d79b13
commit 71f0e5cc13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 169 additions and 41 deletions

75
Cargo.lock generated
View File

@ -1508,14 +1508,38 @@ dependencies = [
"zeroize",
]
[[package]]
name = "darling"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
dependencies = [
"darling_core 0.14.4",
"darling_macro 0.14.4",
]
[[package]]
name = "darling"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
dependencies = [
"darling_core",
"darling_macro",
"darling_core 0.20.3",
"darling_macro 0.20.3",
]
[[package]]
name = "darling_core"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
dependencies = [
"fnv",
"ident_case",
"proc-macro2 1.0.67",
"quote 1.0.33",
"strsim 0.10.0",
"syn 1.0.109",
]
[[package]]
@ -1532,13 +1556,24 @@ dependencies = [
"syn 2.0.37",
]
[[package]]
name = "darling_macro"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
dependencies = [
"darling_core 0.14.4",
"quote 1.0.33",
"syn 1.0.109",
]
[[package]]
name = "darling_macro"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [
"darling_core",
"darling_core 0.20.3",
"quote 1.0.33",
"syn 2.0.37",
]
@ -1617,6 +1652,37 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "derive_builder"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8"
dependencies = [
"derive_builder_macro",
]
[[package]]
name = "derive_builder_core"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f"
dependencies = [
"darling 0.14.4",
"proc-macro2 1.0.67",
"quote 1.0.33",
"syn 1.0.109",
]
[[package]]
name = "derive_builder_macro"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"
dependencies = [
"derive_builder_core",
"syn 1.0.109",
]
[[package]]
name = "derive_more"
version = "0.99.17"
@ -3379,6 +3445,7 @@ dependencies = [
"atty",
"base64 0.13.1",
"bincode",
"derive_builder",
"fixed 1.11.0 (git+https://github.com/blockworks-foundation/fixed.git?branch=v1.11.0-borsh0_10-mango)",
"futures 0.3.28",
"itertools",
@ -5779,7 +5846,7 @@ version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f"
dependencies = [
"darling",
"darling 0.20.3",
"proc-macro2 1.0.67",
"quote 1.0.33",
"syn 2.0.37",

View File

@ -158,6 +158,14 @@ struct Cli {
#[clap(long, env, value_enum, default_value = "v6")]
jupiter_version: JupiterVersionArg,
/// override the url to jupiter v4
#[clap(long, env, default_value = "https://quote-api.jup.ag/v4")]
jupiter_v4_url: String,
/// override the url to jupiter v6
#[clap(long, env, default_value = "https://quote-api.jup.ag/v6")]
jupiter_v6_url: String,
/// report liquidator's existence and pubkey
#[clap(long, env, value_enum, default_value = "true")]
telemetry: BoolArg,
@ -188,18 +196,21 @@ async fn main() -> anyhow::Result<()> {
let rpc_timeout = Duration::from_secs(10);
let cluster = Cluster::Custom(rpc_url.clone(), ws_url.clone());
let commitment = CommitmentConfig::processed();
let client = Client::new(
cluster.clone(),
commitment,
liqor_owner.clone(),
Some(rpc_timeout),
TransactionBuilderConfig {
let client = Client::builder()
.cluster(cluster.clone())
.commitment(commitment)
.fee_payer(Some(liqor_owner.clone()))
.timeout(Some(rpc_timeout))
.jupiter_v4_url(cli.jupiter_v4_url)
.jupiter_v6_url(cli.jupiter_v6_url)
.transaction_builder_config(TransactionBuilderConfig {
prioritization_micro_lamports: (cli.prioritization_micro_lamports > 0)
.then_some(cli.prioritization_micro_lamports),
// Liquidation and tcs triggers set their own budgets, this is a default for other tx
compute_budget_per_instruction: Some(250_000),
},
);
})
.build()
.unwrap();
// The representation of current on-chain account data
let chain_data = Arc::new(RwLock::new(chain_data::ChainData::new()));

View File

@ -1105,14 +1105,12 @@ impl Context {
solana_sdk::compute_budget::ComputeBudgetInstruction::set_compute_unit_limit(
self.config.compute_limit_for_trigger,
);
let fee_payer = self.mango_client.client.fee_payer();
TransactionBuilder {
instructions: vec![compute_ix],
address_lookup_tables: vec![],
payer: self.mango_client.client.fee_payer.pubkey(),
signers: vec![
self.mango_client.owner.clone(),
self.mango_client.client.fee_payer.clone(),
],
payer: fee_payer.pubkey(),
signers: vec![self.mango_client.owner.clone(), fee_payer],
config: self.mango_client.client.transaction_builder_config,
}
};

View File

@ -267,7 +267,7 @@ struct SettleBatchProcessor<'a> {
impl<'a> SettleBatchProcessor<'a> {
fn transaction(&self) -> anyhow::Result<VersionedTransaction> {
let client = &self.mango_client.client;
let fee_payer = client.fee_payer.clone();
let fee_payer = client.fee_payer();
TransactionBuilder {
instructions: self.instructions.clone().to_instructions(),

View File

@ -15,6 +15,7 @@ async-channel = "1.6"
async-once-cell = { version = "0.4.2", features = ["unpin"] }
async-trait = "0.1.52"
atty = "0.2"
derive_builder = "0.12.0"
fixed = { workspace = true, features = ["serde", "borsh"] }
futures = "0.3.25"
itertools = "0.10.3"

View File

@ -49,17 +49,55 @@ use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signer::Si
pub const MAX_ACCOUNTS_PER_TRANSACTION: usize = 64;
// very close to anchor_client::Client, which unfortunately has no accessors or Clone
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Builder)]
pub struct Client {
/// RPC url
///
/// Defaults to Cluster::Mainnet, using the public crowded mainnet-beta rpc endpoint.
/// Should usually be overridden with a custom rpc endpoint.
#[builder(default = "Cluster::Mainnet")]
pub cluster: Cluster,
pub fee_payer: Arc<Keypair>,
/// Transaction fee payer. Needs to be set to send transactions.
pub fee_payer: Option<Arc<Keypair>>,
/// Commitment for interacting with the chain. Defaults to processed.
#[builder(default = "CommitmentConfig::processed()")]
pub commitment: CommitmentConfig,
/// Timeout, defaults to 60s
#[builder(default = "Some(Duration::from_secs(60))")]
pub timeout: Option<Duration>,
#[builder(default)]
pub transaction_builder_config: TransactionBuilderConfig,
/// Defaults to a preflight check at processed commitment
#[builder(default = "ClientBuilder::default_rpc_send_transaction_config()")]
pub rpc_send_transaction_config: RpcSendTransactionConfig,
#[builder(default = "\"https://quote-api.jup.ag/v4\".into()")]
pub jupiter_v4_url: String,
#[builder(default = "\"https://quote-api.jup.ag/v6\".into()")]
pub jupiter_v6_url: String,
}
impl ClientBuilder {
pub fn default_rpc_send_transaction_config() -> RpcSendTransactionConfig {
RpcSendTransactionConfig {
preflight_commitment: Some(CommitmentLevel::Processed),
..Default::default()
}
}
}
impl Client {
pub fn builder() -> ClientBuilder {
ClientBuilder::default()
}
/// Prefer using the builder()
pub fn new(
cluster: Cluster,
commitment: CommitmentConfig,
@ -67,17 +105,14 @@ impl Client {
timeout: Option<Duration>,
transaction_builder_config: TransactionBuilderConfig,
) -> Self {
Self {
cluster,
fee_payer,
commitment,
timeout,
transaction_builder_config,
rpc_send_transaction_config: RpcSendTransactionConfig {
preflight_commitment: Some(CommitmentLevel::Processed),
..Default::default()
},
}
Self::builder()
.cluster(cluster)
.commitment(commitment)
.fee_payer(Some(fee_payer))
.timeout(timeout)
.transaction_builder_config(transaction_builder_config)
.build()
.unwrap()
}
pub fn rpc_async(&self) -> RpcClientAsync {
@ -96,6 +131,13 @@ impl Client {
) -> anyhow::Result<T> {
fetch_anchor_account(&self.rpc_async(), address).await
}
pub fn fee_payer(&self) -> Arc<Keypair> {
self.fee_payer
.as_ref()
.expect("fee payer must be set")
.clone()
}
}
// todo: might want to integrate geyser, websockets, or simple http polling for keeping data fresh
@ -1617,11 +1659,12 @@ impl MangoClient {
&self,
instructions: Vec<Instruction>,
) -> anyhow::Result<Signature> {
let fee_payer = self.client.fee_payer();
TransactionBuilder {
instructions,
address_lookup_tables: self.mango_address_lookup_tables().await?,
payer: self.client.fee_payer.pubkey(),
signers: vec![self.owner.clone(), self.client.fee_payer.clone()],
payer: fee_payer.pubkey(),
signers: vec![self.owner.clone(), fee_payer],
config: self.client.transaction_builder_config,
}
.send_and_confirm(&self.client)
@ -1632,11 +1675,12 @@ impl MangoClient {
&self,
instructions: Vec<Instruction>,
) -> anyhow::Result<Signature> {
let fee_payer = self.client.fee_payer();
TransactionBuilder {
instructions,
address_lookup_tables: self.mango_address_lookup_tables().await?,
payer: self.client.fee_payer.pubkey(),
signers: vec![self.client.fee_payer.clone()],
payer: fee_payer.pubkey(),
signers: vec![fee_payer],
config: self.client.transaction_builder_config,
}
.send_and_confirm(&self.client)
@ -1647,11 +1691,12 @@ impl MangoClient {
&self,
instructions: Vec<Instruction>,
) -> anyhow::Result<SimulateTransactionResponse> {
let fee_payer = self.client.fee_payer();
TransactionBuilder {
instructions,
address_lookup_tables: vec![],
payer: self.client.fee_payer.pubkey(),
signers: vec![self.client.fee_payer.clone()],
payer: fee_payer.pubkey(),
signers: vec![fee_payer],
config: self.client.transaction_builder_config,
}
.simulate(&self.client)

View File

@ -107,7 +107,7 @@ impl<'a> JupiterV4<'a> {
let response = self
.mango_client
.http_client
.get("https://quote-api.jup.ag/v4/quote")
.get(format!("{}/quote", self.mango_client.client.jupiter_v4_url))
.query(&[
("inputMint", input_mint.to_string()),
("outputMint", output_mint.to_string()),
@ -158,7 +158,7 @@ impl<'a> JupiterV4<'a> {
let swap_response = self
.mango_client
.http_client
.post("https://quote-api.jup.ag/v4/swap")
.post(format!("{}/swap", self.mango_client.client.jupiter_v4_url))
.json(&SwapRequest {
route: route.clone(),
user_public_key: self.mango_client.owner.pubkey().to_string(),

View File

@ -183,7 +183,7 @@ impl<'a> JupiterV6<'a> {
let response = self
.mango_client
.http_client
.get("https://quote-api.jup.ag/v6/quote")
.get(format!("{}/quote", self.mango_client.client.jupiter_v6_url))
.query(&[
("inputMint", input_mint.to_string()),
("outputMint", output_mint.to_string()),
@ -263,7 +263,10 @@ impl<'a> JupiterV6<'a> {
let swap_response = self
.mango_client
.http_client
.post("https://quote-api.jup.ag/v6/swap-instructions")
.post(format!(
"{}/swap-instructions",
self.mango_client.client.jupiter_v6_url
))
.json(&SwapRequest {
user_public_key: owner.to_string(),
wrap_and_unwrap_sol: false,

View File

@ -17,3 +17,6 @@ pub mod perp_pnl;
pub mod snapshot_source;
mod util;
pub mod websocket_source;
#[macro_use]
extern crate derive_builder;