Files
sol-trade-sdk/src/swqos/mod.rs
T

344 lines
12 KiB
Rust
Raw Normal View History

2025-04-02 13:39:59 +08:00
pub mod common;
2025-10-06 23:40:27 +08:00
pub mod serialization;
2025-07-06 22:06:44 +08:00
pub mod solana_rpc;
pub mod jito;
pub mod nextblock;
pub mod zeroslot;
2025-07-06 23:36:18 +08:00
pub mod temporal;
2025-07-07 02:06:52 +08:00
pub mod bloxroute;
2025-08-20 20:50:56 +08:00
pub mod node1;
2025-08-21 21:04:19 +08:00
pub mod flashblock;
2025-09-06 21:24:38 +08:00
pub mod blockrazor;
2025-09-07 15:22:06 +08:00
pub mod astralane;
pub mod stellium;
pub mod lightspeed;
2025-12-19 17:48:09 +08:00
pub mod soyas;
2025-07-06 22:06:44 +08:00
2025-07-07 03:28:02 +08:00
use std::sync::Arc;
use solana_commitment_config::CommitmentConfig;
use solana_sdk::transaction::VersionedTransaction;
2025-07-06 22:06:44 +08:00
use tokio::sync::RwLock;
use anyhow::Result;
2025-02-13 20:44:20 +08:00
2025-08-21 21:04:19 +08:00
use crate::{
common::SolanaRpcClient,
2025-08-21 21:04:19 +08:00
constants::swqos::{
SWQOS_ENDPOINTS_BLOX,
SWQOS_ENDPOINTS_JITO,
SWQOS_ENDPOINTS_NEXTBLOCK,
SWQOS_ENDPOINTS_TEMPORAL,
SWQOS_ENDPOINTS_ZERO_SLOT,
SWQOS_ENDPOINTS_NODE1,
2025-09-06 21:24:38 +08:00
SWQOS_ENDPOINTS_FLASHBLOCK,
2025-09-07 15:22:06 +08:00
SWQOS_ENDPOINTS_BLOCKRAZOR,
SWQOS_ENDPOINTS_ASTRALANE,
2025-12-19 17:48:09 +08:00
SWQOS_ENDPOINTS_STELLIUM,
SWQOS_ENDPOINTS_SOYAS
},
2025-08-21 21:04:19 +08:00
swqos::{
bloxroute::BloxrouteClient,
jito::JitoClient,
nextblock::NextBlockClient,
solana_rpc::SolRpcClient,
temporal::TemporalClient,
zeroslot::ZeroSlotClient,
node1::Node1Client,
2025-09-06 21:24:38 +08:00
flashblock::FlashBlockClient,
2025-09-07 15:22:06 +08:00
blockrazor::BlockRazorClient,
astralane::AstralaneClient,
stellium::StelliumClient,
2025-12-19 17:48:09 +08:00
lightspeed::LightspeedClient,
soyas::SoyasClient
2025-08-21 21:04:19 +08:00
}
};
2025-07-06 23:36:18 +08:00
2025-04-02 13:39:59 +08:00
lazy_static::lazy_static! {
static ref TIP_ACCOUNT_CACHE: RwLock<Vec<String>> = RwLock::new(Vec::new());
2025-01-14 19:18:48 +08:00
}
/// SWQOS provider blacklist configuration
/// Providers added here will be disabled even if configured by user
/// To enable a provider, remove it from this list
pub const SWQOS_BLACKLIST: &[SwqosType] = &[
SwqosType::NextBlock, // NextBlock is disabled by default
];
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TradeType {
Create,
CreateAndBuy,
Buy,
Sell,
}
impl std::fmt::Display for TradeType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
2025-08-27 14:27:26 +08:00
TradeType::Create => "Create",
TradeType::CreateAndBuy => "Create and Buy",
TradeType::Buy => "Buy",
TradeType::Sell => "Sell",
};
write!(f, "{}", s)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2025-07-06 23:36:18 +08:00
pub enum SwqosType {
2025-04-02 13:39:59 +08:00
Jito,
NextBlock,
ZeroSlot,
2025-07-06 23:36:18 +08:00
Temporal,
2025-07-07 02:06:52 +08:00
Bloxroute,
2025-08-20 20:50:56 +08:00
Node1,
2025-08-21 21:04:19 +08:00
FlashBlock,
2025-09-06 21:24:38 +08:00
BlockRazor,
2025-09-07 15:22:06 +08:00
Astralane,
Stellium,
Lightspeed,
2025-12-19 17:48:09 +08:00
Soyas,
2025-07-07 03:28:02 +08:00
Default,
2025-04-02 13:39:59 +08:00
}
impl SwqosType {
pub fn values() -> Vec<Self> {
vec![
Self::Jito,
Self::NextBlock,
Self::ZeroSlot,
Self::Temporal,
Self::Bloxroute,
Self::Node1,
Self::FlashBlock,
Self::BlockRazor,
Self::Astralane,
Self::Stellium,
Self::Lightspeed,
2025-12-19 17:48:09 +08:00
Self::Soyas,
Self::Default,
]
}
}
2025-07-06 22:06:44 +08:00
pub type SwqosClient = dyn SwqosClientTrait + Send + Sync + 'static;
2025-04-02 13:39:59 +08:00
#[async_trait::async_trait]
2025-07-06 22:06:44 +08:00
pub trait SwqosClientTrait {
async fn send_transaction(&self, trade_type: TradeType, transaction: &VersionedTransaction, wait_confirmation: bool) -> Result<()>;
async fn send_transactions(&self, trade_type: TradeType, transactions: &Vec<VersionedTransaction>, wait_confirmation: bool) -> Result<()>;
fn get_tip_account(&self) -> Result<String>;
2025-07-06 23:36:18 +08:00
fn get_swqos_type(&self) -> SwqosType;
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SwqosRegion {
NewYork,
Frankfurt,
2025-07-07 01:19:12 +08:00
Amsterdam,
SLC,
Tokyo,
London,
LosAngeles,
Default,
2025-07-06 23:36:18 +08:00
}
2025-07-07 03:28:02 +08:00
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SwqosConfig {
Default(String),
/// Jito(uuid, region, custom_url)
Jito(String, SwqosRegion, Option<String>),
/// NextBlock(api_token, region, custom_url)
NextBlock(String, SwqosRegion, Option<String>),
/// Bloxroute(api_token, region, custom_url)
Bloxroute(String, SwqosRegion, Option<String>),
/// Temporal(api_token, region, custom_url)
Temporal(String, SwqosRegion, Option<String>),
/// ZeroSlot(api_token, region, custom_url)
ZeroSlot(String, SwqosRegion, Option<String>),
/// Node1(api_token, region, custom_url)
Node1(String, SwqosRegion, Option<String>),
/// FlashBlock(api_token, region, custom_url)
FlashBlock(String, SwqosRegion, Option<String>),
/// BlockRazor(api_token, region, custom_url)
BlockRazor(String, SwqosRegion, Option<String>),
/// Astralane(api_token, region, custom_url)
2025-09-07 15:22:06 +08:00
Astralane(String, SwqosRegion, Option<String>),
/// Stellium(api_token, region, custom_url)
Stellium(String, SwqosRegion, Option<String>),
/// Lightspeed(api_key, region, custom_url) - Solana Vibe Station
/// Endpoint format: https://<tier>.rpc.solanavibestation.com/lightspeed?api_key=<key>
/// Minimum tip: 0.001 SOL
Lightspeed(String, SwqosRegion, Option<String>),
2025-12-19 17:48:09 +08:00
/// Soyas(api_token, region, custom_url)
Soyas(String, SwqosRegion, Option<String>),
2025-07-06 23:36:18 +08:00
}
impl SwqosConfig {
2025-12-19 17:48:09 +08:00
pub fn swqos_type(&self) -> SwqosType{
match self {
SwqosConfig::Default(_) => SwqosType::Default,
SwqosConfig::Jito(_, _, _) => SwqosType::Jito,
SwqosConfig::NextBlock(_, _, _) => SwqosType::NextBlock,
SwqosConfig::Bloxroute(_, _, _) => SwqosType::Bloxroute,
SwqosConfig::Temporal(_, _, _) => SwqosType::Temporal,
SwqosConfig::ZeroSlot(_, _, _) => SwqosType::ZeroSlot,
SwqosConfig::Node1(_, _, _) => SwqosType::Node1,
SwqosConfig::FlashBlock(_, _, _) => SwqosType::FlashBlock,
SwqosConfig::BlockRazor(_, _, _) => SwqosType::BlockRazor,
SwqosConfig::Astralane(_, _, _) => SwqosType::Astralane,
SwqosConfig::Stellium(_, _, _) => SwqosType::Stellium,
SwqosConfig::Lightspeed(_, _, _) => SwqosType::Lightspeed,
SwqosConfig::Soyas(_, _, _) => SwqosType::Soyas,
}
}
/// Check if current config is in the blacklist
pub fn is_blacklisted(&self) -> bool {
SWQOS_BLACKLIST.contains(&self.swqos_type())
}
pub fn get_endpoint(swqos_type: SwqosType, region: SwqosRegion, url: Option<String>) -> String {
if let Some(custom_url) = url {
return custom_url;
}
2025-07-07 03:28:02 +08:00
match swqos_type {
2025-07-06 23:36:18 +08:00
SwqosType::Jito => SWQOS_ENDPOINTS_JITO[region as usize].to_string(),
SwqosType::NextBlock => SWQOS_ENDPOINTS_NEXTBLOCK[region as usize].to_string(),
SwqosType::ZeroSlot => SWQOS_ENDPOINTS_ZERO_SLOT[region as usize].to_string(),
SwqosType::Temporal => SWQOS_ENDPOINTS_TEMPORAL[region as usize].to_string(),
2025-07-07 02:06:52 +08:00
SwqosType::Bloxroute => SWQOS_ENDPOINTS_BLOX[region as usize].to_string(),
2025-08-20 20:50:56 +08:00
SwqosType::Node1 => SWQOS_ENDPOINTS_NODE1[region as usize].to_string(),
2025-08-21 21:04:19 +08:00
SwqosType::FlashBlock => SWQOS_ENDPOINTS_FLASHBLOCK[region as usize].to_string(),
2025-09-06 21:24:38 +08:00
SwqosType::BlockRazor => SWQOS_ENDPOINTS_BLOCKRAZOR[region as usize].to_string(),
2025-09-07 15:22:06 +08:00
SwqosType::Astralane => SWQOS_ENDPOINTS_ASTRALANE[region as usize].to_string(),
SwqosType::Stellium => SWQOS_ENDPOINTS_STELLIUM[region as usize].to_string(),
SwqosType::Lightspeed => "".to_string(), // Lightspeed requires custom URL with api_key
2025-12-19 17:48:09 +08:00
SwqosType::Soyas => SWQOS_ENDPOINTS_SOYAS[region as usize].to_string(),
2025-07-07 03:28:02 +08:00
SwqosType::Default => "".to_string(),
}
}
2025-07-06 23:36:18 +08:00
2025-12-19 17:48:09 +08:00
pub async fn get_swqos_client(rpc_url: String, commitment: CommitmentConfig, swqos_config: SwqosConfig) -> Result<Arc<SwqosClient>> {
2025-07-07 03:28:02 +08:00
match swqos_config {
SwqosConfig::Jito(auth_token, region, url) => {
let endpoint = SwqosConfig::get_endpoint(SwqosType::Jito, region, url);
2025-07-07 03:28:02 +08:00
let jito_client = JitoClient::new(
rpc_url.clone(),
endpoint,
auth_token
2025-07-07 03:28:02 +08:00
);
2025-12-19 17:48:09 +08:00
Ok(Arc::new(jito_client))
2025-07-07 03:28:02 +08:00
}
SwqosConfig::NextBlock(auth_token, region, url) => {
let endpoint = SwqosConfig::get_endpoint(SwqosType::NextBlock, region, url);
2025-07-07 03:28:02 +08:00
let nextblock_client = NextBlockClient::new(
rpc_url.clone(),
endpoint.to_string(),
auth_token
);
2025-12-19 17:48:09 +08:00
Ok(Arc::new(nextblock_client))
2025-07-07 03:28:02 +08:00
},
SwqosConfig::ZeroSlot(auth_token, region, url) => {
let endpoint = SwqosConfig::get_endpoint(SwqosType::ZeroSlot, region, url);
2025-07-07 03:28:02 +08:00
let zeroslot_client = ZeroSlotClient::new(
rpc_url.clone(),
endpoint.to_string(),
auth_token
);
2025-12-19 17:48:09 +08:00
Ok(Arc::new(zeroslot_client))
2025-07-07 03:28:02 +08:00
},
SwqosConfig::Temporal(auth_token, region, url) => {
let endpoint = SwqosConfig::get_endpoint(SwqosType::Temporal, region, url);
2025-07-07 03:28:02 +08:00
let temporal_client = TemporalClient::new(
rpc_url.clone(),
endpoint.to_string(),
auth_token
);
2025-12-19 17:48:09 +08:00
Ok(Arc::new(temporal_client))
2025-07-07 03:28:02 +08:00
},
SwqosConfig::Bloxroute(auth_token, region, url) => {
let endpoint = SwqosConfig::get_endpoint(SwqosType::Bloxroute, region, url);
2025-07-07 03:28:02 +08:00
let bloxroute_client = BloxrouteClient::new(
rpc_url.clone(),
endpoint.to_string(),
auth_token
);
2025-12-19 17:48:09 +08:00
Ok(Arc::new(bloxroute_client))
2025-07-07 03:28:02 +08:00
},
SwqosConfig::Node1(auth_token, region, url) => {
let endpoint = SwqosConfig::get_endpoint(SwqosType::Node1, region, url);
2025-08-20 20:50:56 +08:00
let node1_client = Node1Client::new(
rpc_url.clone(),
endpoint.to_string(),
auth_token
);
2025-12-19 17:48:09 +08:00
Ok(Arc::new(node1_client))
2025-08-20 20:50:56 +08:00
},
SwqosConfig::FlashBlock(auth_token, region, url) => {
let endpoint = SwqosConfig::get_endpoint(SwqosType::FlashBlock, region, url);
2025-08-21 21:04:19 +08:00
let flashblock_client = FlashBlockClient::new(
rpc_url.clone(),
endpoint.to_string(),
auth_token
);
2025-12-19 17:48:09 +08:00
Ok(Arc::new(flashblock_client))
2025-08-21 21:04:19 +08:00
},
SwqosConfig::BlockRazor(auth_token, region, url) => {
let endpoint = SwqosConfig::get_endpoint(SwqosType::BlockRazor, region, url);
2025-09-06 21:24:38 +08:00
let blockrazor_client = BlockRazorClient::new(
rpc_url.clone(),
endpoint.to_string(),
auth_token
);
2025-12-19 17:48:09 +08:00
Ok(Arc::new(blockrazor_client))
2025-09-06 21:24:38 +08:00
},
2025-09-07 15:22:06 +08:00
SwqosConfig::Astralane(auth_token, region, url) => {
let endpoint = SwqosConfig::get_endpoint(SwqosType::Astralane, region, url);
let astralane_client = AstralaneClient::new(
rpc_url.clone(),
endpoint.to_string(),
auth_token
);
2025-12-19 17:48:09 +08:00
Ok(Arc::new(astralane_client))
2025-09-07 15:22:06 +08:00
},
SwqosConfig::Stellium(auth_token, region, url) => {
let endpoint = SwqosConfig::get_endpoint(SwqosType::Stellium, region, url);
let stellium_client = StelliumClient::new(
rpc_url.clone(),
endpoint.to_string(),
auth_token
);
2025-12-19 17:48:09 +08:00
Ok(Arc::new(stellium_client))
},
SwqosConfig::Lightspeed(auth_token, region, url) => {
let endpoint = SwqosConfig::get_endpoint(SwqosType::Lightspeed, region, url);
let lightspeed_client = LightspeedClient::new(
rpc_url.clone(),
endpoint.to_string(),
auth_token
);
2025-12-19 17:48:09 +08:00
Ok(Arc::new(lightspeed_client))
},
SwqosConfig::Soyas(auth_token, region, url) => {
let endpoint = SwqosConfig::get_endpoint(SwqosType::Soyas, region, url);
let soyas_client = SoyasClient::new(
rpc_url.clone(),
endpoint.to_string(),
auth_token
).await?;
Ok(Arc::new(soyas_client))
},
2025-07-07 03:28:02 +08:00
SwqosConfig::Default(endpoint) => {
let rpc = SolanaRpcClient::new_with_commitment(
endpoint,
commitment
);
2025-07-07 03:28:02 +08:00
let rpc_client = SolRpcClient::new(Arc::new(rpc));
2025-12-19 17:48:09 +08:00
Ok(Arc::new(rpc_client))
2025-07-07 03:28:02 +08:00
}
}
2025-07-06 23:36:18 +08:00
}
2025-04-02 13:39:59 +08:00
}