- HTTP binary mode: POST /send-bin with bincode body, x-api-key header, keepalive ping - QUIC mode: port 16888 via lunar-lander-quic-client crate, fire-and-forget uni streams - Dual transport: SwqosConfig::LunarLander(key, region, url, transport) like Astralane - 10 moon-prefix tip accounts, 0.001 SOL minimum tip - Regional endpoints: NYC, Frankfurt, Amsterdam, Ashburn, Tokyo
508 lines
22 KiB
Rust
Executable File
508 lines
22 KiB
Rust
Executable File
pub mod astralane;
|
||
pub mod astralane_quic;
|
||
pub mod blockrazor;
|
||
pub mod bloxroute;
|
||
pub mod common;
|
||
pub mod flashblock;
|
||
pub mod helius;
|
||
pub mod jito;
|
||
pub mod lightspeed;
|
||
pub mod lunarlander;
|
||
pub mod nextblock;
|
||
pub mod node1;
|
||
pub mod node1_quic;
|
||
pub mod serialization;
|
||
pub mod solana_rpc;
|
||
pub mod soyas;
|
||
pub mod speedlanding;
|
||
pub mod stellium;
|
||
pub mod temporal;
|
||
pub mod zeroslot;
|
||
|
||
use std::sync::Arc;
|
||
|
||
use solana_commitment_config::CommitmentConfig;
|
||
use solana_sdk::transaction::VersionedTransaction;
|
||
use tokio::sync::RwLock;
|
||
|
||
use anyhow::Result;
|
||
|
||
use crate::{
|
||
common::SolanaRpcClient,
|
||
constants::swqos::{
|
||
SWQOS_ENDPOINTS_ASTRALANE, SWQOS_ENDPOINTS_ASTRALANE_QUIC, SWQOS_ENDPOINTS_BLOCKRAZOR,
|
||
SWQOS_ENDPOINTS_BLOCKRAZOR_GRPC, SWQOS_ENDPOINTS_BLOX, SWQOS_ENDPOINTS_FLASHBLOCK,
|
||
SWQOS_ENDPOINTS_HELIUS, SWQOS_ENDPOINTS_JITO, SWQOS_ENDPOINTS_LUNARLANDER,
|
||
SWQOS_ENDPOINTS_LUNARLANDER_QUIC, SWQOS_ENDPOINTS_NEXTBLOCK, SWQOS_ENDPOINTS_NODE1,
|
||
SWQOS_ENDPOINTS_NODE1_QUIC, SWQOS_ENDPOINTS_SOYAS, SWQOS_ENDPOINTS_SPEEDLANDING,
|
||
SWQOS_ENDPOINTS_STELLIUM, SWQOS_ENDPOINTS_TEMPORAL, SWQOS_ENDPOINTS_ZERO_SLOT,
|
||
SWQOS_MIN_TIP_ASTRALANE, SWQOS_MIN_TIP_BLOCKRAZOR, SWQOS_MIN_TIP_BLOXROUTE,
|
||
SWQOS_MIN_TIP_DEFAULT, SWQOS_MIN_TIP_FLASHBLOCK, SWQOS_MIN_TIP_HELIUS,
|
||
SWQOS_MIN_TIP_JITO, SWQOS_MIN_TIP_LIGHTSPEED, SWQOS_MIN_TIP_LUNARLANDER,
|
||
SWQOS_MIN_TIP_NEXTBLOCK, SWQOS_MIN_TIP_NODE1, SWQOS_MIN_TIP_SOYAS,
|
||
SWQOS_MIN_TIP_SPEEDLANDING, SWQOS_MIN_TIP_STELLIUM, SWQOS_MIN_TIP_TEMPORAL,
|
||
SWQOS_MIN_TIP_ZERO_SLOT,
|
||
},
|
||
swqos::{
|
||
astralane::AstralaneClient, blockrazor::BlockRazorClient, bloxroute::BloxrouteClient,
|
||
flashblock::FlashBlockClient, helius::HeliusClient, jito::JitoClient,
|
||
lightspeed::LightspeedClient, lunarlander::LunarLanderClient,
|
||
nextblock::NextBlockClient, node1::Node1Client, node1_quic::Node1QuicClient,
|
||
solana_rpc::SolRpcClient, soyas::SoyasClient, speedlanding::SpeedlandingClient,
|
||
stellium::StelliumClient, temporal::TemporalClient, zeroslot::ZeroSlotClient,
|
||
},
|
||
};
|
||
|
||
lazy_static::lazy_static! {
|
||
/// Reserved for future per-SWQOS tip account caching (currently unused).
|
||
#[allow(dead_code)]
|
||
static ref TIP_ACCOUNT_CACHE: RwLock<Vec<String>> = RwLock::new(Vec::new());
|
||
}
|
||
|
||
/// 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
|
||
];
|
||
|
||
/// SWQOS 提交通道:HTTP、gRPC 或 QUIC(低延迟)。
|
||
/// BlockRazor 支持 gRPC 和 HTTP。
|
||
/// Astralane 和 Node1 支持 QUIC。
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
|
||
pub enum SwqosTransport {
|
||
#[default]
|
||
Http,
|
||
Grpc,
|
||
Quic,
|
||
}
|
||
|
||
#[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 {
|
||
TradeType::Create => "Create",
|
||
TradeType::CreateAndBuy => "Create and Buy",
|
||
TradeType::Buy => "Buy",
|
||
TradeType::Sell => "Sell",
|
||
};
|
||
write!(f, "{}", s)
|
||
}
|
||
}
|
||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||
pub enum SwqosType {
|
||
Jito,
|
||
NextBlock,
|
||
ZeroSlot,
|
||
Temporal,
|
||
Bloxroute,
|
||
Node1,
|
||
FlashBlock,
|
||
BlockRazor,
|
||
Astralane,
|
||
Stellium,
|
||
Lightspeed,
|
||
Soyas,
|
||
Speedlanding,
|
||
Helius,
|
||
LunarLander,
|
||
Default,
|
||
}
|
||
|
||
impl SwqosType {
|
||
/// Label for log alignment; same as Debug output (e.g. "Soyas", "Speedlanding").
|
||
#[inline]
|
||
pub fn as_str(self) -> &'static str {
|
||
match self {
|
||
Self::Jito => "Jito",
|
||
Self::NextBlock => "NextBlock",
|
||
Self::ZeroSlot => "ZeroSlot",
|
||
Self::Temporal => "Temporal",
|
||
Self::Bloxroute => "Bloxroute",
|
||
Self::Node1 => "Node1",
|
||
Self::FlashBlock => "FlashBlock",
|
||
Self::BlockRazor => "BlockRazor",
|
||
Self::Astralane => "Astralane",
|
||
Self::Stellium => "Stellium",
|
||
Self::Lightspeed => "Lightspeed",
|
||
Self::Soyas => "Soyas",
|
||
Self::Speedlanding => "Speedlanding",
|
||
Self::Helius => "Helius",
|
||
Self::LunarLander => "LunarLander",
|
||
Self::Default => "Default",
|
||
}
|
||
}
|
||
|
||
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,
|
||
Self::Soyas,
|
||
Self::Speedlanding,
|
||
Self::Helius,
|
||
Self::LunarLander,
|
||
Self::Default,
|
||
]
|
||
}
|
||
}
|
||
|
||
pub type SwqosClient = dyn SwqosClientTrait + Send + Sync + 'static;
|
||
|
||
#[async_trait::async_trait]
|
||
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>;
|
||
fn get_swqos_type(&self) -> SwqosType;
|
||
/// Minimum tip in SOL required by this provider. Helius returns lower value when swqos_only is true.
|
||
#[inline]
|
||
fn min_tip_sol(&self) -> f64 {
|
||
match self.get_swqos_type() {
|
||
SwqosType::Jito => SWQOS_MIN_TIP_JITO,
|
||
SwqosType::NextBlock => SWQOS_MIN_TIP_NEXTBLOCK,
|
||
SwqosType::ZeroSlot => SWQOS_MIN_TIP_ZERO_SLOT,
|
||
SwqosType::Temporal => SWQOS_MIN_TIP_TEMPORAL,
|
||
SwqosType::Bloxroute => SWQOS_MIN_TIP_BLOXROUTE,
|
||
SwqosType::Node1 => SWQOS_MIN_TIP_NODE1,
|
||
SwqosType::FlashBlock => SWQOS_MIN_TIP_FLASHBLOCK,
|
||
SwqosType::BlockRazor => SWQOS_MIN_TIP_BLOCKRAZOR,
|
||
SwqosType::Astralane => SWQOS_MIN_TIP_ASTRALANE,
|
||
SwqosType::Stellium => SWQOS_MIN_TIP_STELLIUM,
|
||
SwqosType::Lightspeed => SWQOS_MIN_TIP_LIGHTSPEED,
|
||
SwqosType::Soyas => SWQOS_MIN_TIP_SOYAS,
|
||
SwqosType::Speedlanding => SWQOS_MIN_TIP_SPEEDLANDING,
|
||
SwqosType::Helius => SWQOS_MIN_TIP_HELIUS,
|
||
SwqosType::LunarLander => SWQOS_MIN_TIP_LUNARLANDER,
|
||
SwqosType::Default => SWQOS_MIN_TIP_DEFAULT,
|
||
}
|
||
}
|
||
}
|
||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||
pub enum SwqosRegion {
|
||
NewYork,
|
||
Frankfurt,
|
||
Amsterdam,
|
||
SLC,
|
||
Tokyo,
|
||
London,
|
||
LosAngeles,
|
||
Default,
|
||
}
|
||
|
||
#[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, transport). transport=None => HTTP; Some(Quic) => QUIC (port 16666, UUID auth).
|
||
Node1(String, SwqosRegion, Option<String>, Option<SwqosTransport>),
|
||
/// FlashBlock(api_token, region, custom_url)
|
||
FlashBlock(String, SwqosRegion, Option<String>),
|
||
/// BlockRazor(api_token, region, custom_url, transport). transport=None 或 Grpc => gRPC; Some(Http) => HTTP.
|
||
BlockRazor(String, SwqosRegion, Option<String>, Option<SwqosTransport>),
|
||
/// Astralane(api_token, region, custom_url, transport). transport=None 表示 Http。
|
||
Astralane(String, SwqosRegion, Option<String>, Option<SwqosTransport>),
|
||
/// 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>),
|
||
/// Soyas(api_token, region, custom_url)
|
||
Soyas(String, SwqosRegion, Option<String>),
|
||
/// To apply for an API key, please contact -> https://t.me/speedlanding_bot?start=0xzero
|
||
/// Minimum tip: 0.001 SOL
|
||
Speedlanding(String, SwqosRegion, Option<String>),
|
||
/// Helius Sender: dual routing to validators and Jito. API key optional (custom TPS only).
|
||
/// (api_key, region, custom_url, swqos_only). swqos_only: None => false (min tip 0.0002 SOL); Some(true) => SWQOS-only (min tip 0.000005 SOL, much lower).
|
||
Helius(String, SwqosRegion, Option<String>, Option<bool>),
|
||
/// Lunar Lander (HelloMoon): binary tx via HTTP POST /send-bin or QUIC (port 16888).
|
||
/// (api_key, region, custom_url, transport). transport=None => HTTP; Some(Quic) => QUIC.
|
||
/// Minimum tip: 0.001 SOL. Apply for API key: https://docs.hellomoon.io/reference/lunar-lander
|
||
LunarLander(String, SwqosRegion, Option<String>, Option<SwqosTransport>),
|
||
}
|
||
|
||
impl SwqosConfig {
|
||
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,
|
||
SwqosConfig::Speedlanding(_, _, _) => SwqosType::Speedlanding,
|
||
SwqosConfig::Helius(_, _, _, _) => SwqosType::Helius,
|
||
SwqosConfig::LunarLander(_, _, _, _) => SwqosType::LunarLander,
|
||
}
|
||
}
|
||
|
||
/// 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;
|
||
}
|
||
|
||
match swqos_type {
|
||
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(),
|
||
SwqosType::Bloxroute => SWQOS_ENDPOINTS_BLOX[region as usize].to_string(),
|
||
SwqosType::Node1 => SWQOS_ENDPOINTS_NODE1[region as usize].to_string(),
|
||
SwqosType::FlashBlock => SWQOS_ENDPOINTS_FLASHBLOCK[region as usize].to_string(),
|
||
SwqosType::BlockRazor => SWQOS_ENDPOINTS_BLOCKRAZOR[region as usize].to_string(),
|
||
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
|
||
SwqosType::Soyas => SWQOS_ENDPOINTS_SOYAS[region as usize].to_string(),
|
||
SwqosType::Speedlanding => SWQOS_ENDPOINTS_SPEEDLANDING[region as usize].to_string(),
|
||
SwqosType::Helius => SWQOS_ENDPOINTS_HELIUS[region as usize].to_string(),
|
||
SwqosType::LunarLander => SWQOS_ENDPOINTS_LUNARLANDER[region as usize].to_string(),
|
||
SwqosType::Default => "".to_string(),
|
||
}
|
||
}
|
||
|
||
pub fn get_endpoint_with_transport(
|
||
swqos_type: SwqosType,
|
||
region: SwqosRegion,
|
||
url: Option<String>,
|
||
transport: Option<SwqosTransport>,
|
||
) -> String {
|
||
if let Some(custom_url) = url {
|
||
return custom_url;
|
||
}
|
||
|
||
match swqos_type {
|
||
SwqosType::BlockRazor => {
|
||
// transport=None 或 transport=Grpc => gRPC; transport=Http => HTTP
|
||
let use_http = transport.map_or(false, |t| t == SwqosTransport::Http);
|
||
if use_http {
|
||
SWQOS_ENDPOINTS_BLOCKRAZOR[region as usize].to_string()
|
||
} else {
|
||
SWQOS_ENDPOINTS_BLOCKRAZOR_GRPC[region as usize].to_string()
|
||
}
|
||
}
|
||
SwqosType::Node1 => {
|
||
let use_quic = transport.map_or(false, |t| t == SwqosTransport::Quic);
|
||
if use_quic {
|
||
SWQOS_ENDPOINTS_NODE1_QUIC[region as usize].to_string()
|
||
} else {
|
||
SWQOS_ENDPOINTS_NODE1[region as usize].to_string()
|
||
}
|
||
}
|
||
SwqosType::Astralane => {
|
||
let use_quic = transport.map_or(false, |t| t == SwqosTransport::Quic);
|
||
if use_quic {
|
||
SWQOS_ENDPOINTS_ASTRALANE_QUIC[region as usize].to_string()
|
||
} else {
|
||
SWQOS_ENDPOINTS_ASTRALANE[region as usize].to_string()
|
||
}
|
||
}
|
||
SwqosType::LunarLander => {
|
||
let use_quic = transport.map_or(false, |t| t == SwqosTransport::Quic);
|
||
if use_quic {
|
||
SWQOS_ENDPOINTS_LUNARLANDER_QUIC[region as usize].to_string()
|
||
} else {
|
||
SWQOS_ENDPOINTS_LUNARLANDER[region as usize].to_string()
|
||
}
|
||
}
|
||
_ => Self::get_endpoint(swqos_type, region, url),
|
||
}
|
||
}
|
||
|
||
pub async fn get_swqos_client(
|
||
rpc_url: String,
|
||
commitment: CommitmentConfig,
|
||
swqos_config: SwqosConfig,
|
||
) -> Result<Arc<SwqosClient>> {
|
||
match swqos_config {
|
||
SwqosConfig::Jito(auth_token, region, url) => {
|
||
let endpoint = SwqosConfig::get_endpoint(SwqosType::Jito, region, url);
|
||
let jito_client = JitoClient::new(rpc_url.clone(), endpoint, auth_token);
|
||
Ok(Arc::new(jito_client))
|
||
}
|
||
SwqosConfig::NextBlock(auth_token, region, url) => {
|
||
let endpoint = SwqosConfig::get_endpoint(SwqosType::NextBlock, region, url);
|
||
let nextblock_client =
|
||
NextBlockClient::new(rpc_url.clone(), endpoint.to_string(), auth_token);
|
||
Ok(Arc::new(nextblock_client))
|
||
}
|
||
SwqosConfig::ZeroSlot(auth_token, region, url) => {
|
||
let endpoint = SwqosConfig::get_endpoint(SwqosType::ZeroSlot, region, url);
|
||
let zeroslot_client =
|
||
ZeroSlotClient::new(rpc_url.clone(), endpoint.to_string(), auth_token);
|
||
Ok(Arc::new(zeroslot_client))
|
||
}
|
||
SwqosConfig::Temporal(auth_token, region, url) => {
|
||
let endpoint = SwqosConfig::get_endpoint(SwqosType::Temporal, region, url);
|
||
let temporal_client =
|
||
TemporalClient::new(rpc_url.clone(), endpoint.to_string(), auth_token);
|
||
Ok(Arc::new(temporal_client))
|
||
}
|
||
SwqosConfig::Bloxroute(auth_token, region, url) => {
|
||
let endpoint = SwqosConfig::get_endpoint(SwqosType::Bloxroute, region, url);
|
||
let bloxroute_client =
|
||
BloxrouteClient::new(rpc_url.clone(), endpoint.to_string(), auth_token);
|
||
Ok(Arc::new(bloxroute_client))
|
||
}
|
||
SwqosConfig::Node1(auth_token, region, url, transport) => {
|
||
let use_quic = transport.map_or(false, |t| t == SwqosTransport::Quic);
|
||
if use_quic {
|
||
let quic_endpoint = url
|
||
.unwrap_or_else(|| SWQOS_ENDPOINTS_NODE1_QUIC[region as usize].to_string());
|
||
let node1_quic =
|
||
Node1QuicClient::connect(&quic_endpoint, &auth_token, rpc_url.clone())
|
||
.await?;
|
||
Ok(Arc::new(node1_quic))
|
||
} else {
|
||
let endpoint = SwqosConfig::get_endpoint(SwqosType::Node1, region, url);
|
||
let node1_client =
|
||
Node1Client::new(rpc_url.clone(), endpoint.to_string(), auth_token);
|
||
Ok(Arc::new(node1_client))
|
||
}
|
||
}
|
||
SwqosConfig::FlashBlock(auth_token, region, url) => {
|
||
let endpoint = SwqosConfig::get_endpoint(SwqosType::FlashBlock, region, url);
|
||
let flashblock_client =
|
||
FlashBlockClient::new(rpc_url.clone(), endpoint.to_string(), auth_token);
|
||
Ok(Arc::new(flashblock_client))
|
||
}
|
||
SwqosConfig::BlockRazor(auth_token, region, url, transport) => {
|
||
// BlockRazor: transport=None 或 transport=Grpc 时使用 gRPC,transport=Http 时使用 HTTP
|
||
let use_http = transport.map_or(false, |t| t == SwqosTransport::Http);
|
||
let endpoint = SwqosConfig::get_endpoint_with_transport(SwqosType::BlockRazor, region, url, transport);
|
||
if use_http {
|
||
let blockrazor_client =
|
||
BlockRazorClient::new_http(rpc_url.clone(), endpoint.to_string(), auth_token);
|
||
Ok(Arc::new(blockrazor_client))
|
||
} else {
|
||
// 使用 gRPC 模式(默认或用户明确指定了 gRPC)
|
||
let blockrazor_client =
|
||
BlockRazorClient::new_grpc(rpc_url.clone(), endpoint.to_string(), auth_token).await?;
|
||
Ok(Arc::new(blockrazor_client))
|
||
}
|
||
}
|
||
SwqosConfig::Astralane(auth_token, region, url, transport) => {
|
||
let use_quic = transport.map_or(false, |t| t == SwqosTransport::Quic);
|
||
if use_quic {
|
||
let quic_endpoint = url.unwrap_or_else(|| {
|
||
SWQOS_ENDPOINTS_ASTRALANE_QUIC[region as usize].to_string()
|
||
});
|
||
let astralane_client =
|
||
AstralaneClient::new_quic(rpc_url.clone(), &quic_endpoint, auth_token)
|
||
.await?;
|
||
Ok(Arc::new(astralane_client))
|
||
} else {
|
||
let endpoint = SwqosConfig::get_endpoint(SwqosType::Astralane, region, url);
|
||
let astralane_client =
|
||
AstralaneClient::new(rpc_url.clone(), endpoint.to_string(), auth_token);
|
||
Ok(Arc::new(astralane_client))
|
||
}
|
||
}
|
||
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);
|
||
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);
|
||
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))
|
||
}
|
||
SwqosConfig::Speedlanding(auth_token, region, url) => {
|
||
let endpoint = SwqosConfig::get_endpoint(SwqosType::Speedlanding, region, url);
|
||
let speedlanding_client =
|
||
SpeedlandingClient::new(rpc_url.clone(), endpoint.to_string(), auth_token)
|
||
.await?;
|
||
Ok(Arc::new(speedlanding_client))
|
||
}
|
||
SwqosConfig::Helius(api_key, region, url, swqos_only) => {
|
||
let swqos_only = swqos_only.unwrap_or(false);
|
||
let endpoint = SwqosConfig::get_endpoint(SwqosType::Helius, region, url.clone());
|
||
let api_key_opt = if api_key.is_empty() { None } else { Some(api_key.clone()) };
|
||
let helius_client =
|
||
HeliusClient::new(rpc_url.clone(), endpoint, api_key_opt, swqos_only);
|
||
Ok(Arc::new(helius_client))
|
||
}
|
||
SwqosConfig::LunarLander(api_key, region, url, transport) => {
|
||
let use_quic = transport.map_or(false, |t| t == SwqosTransport::Quic);
|
||
if use_quic {
|
||
let quic_endpoint = url.unwrap_or_else(|| {
|
||
SWQOS_ENDPOINTS_LUNARLANDER_QUIC[region as usize].to_string()
|
||
});
|
||
let lunarlander_client =
|
||
LunarLanderClient::new_quic(rpc_url.clone(), &quic_endpoint, api_key)
|
||
.await?;
|
||
Ok(Arc::new(lunarlander_client))
|
||
} else {
|
||
let endpoint = SwqosConfig::get_endpoint(SwqosType::LunarLander, region, url);
|
||
let lunarlander_client =
|
||
LunarLanderClient::new(rpc_url.clone(), endpoint, api_key);
|
||
Ok(Arc::new(lunarlander_client))
|
||
}
|
||
}
|
||
SwqosConfig::Default(endpoint) => {
|
||
let rpc = SolanaRpcClient::new_with_commitment(endpoint, commitment);
|
||
let rpc_client = SolRpcClient::new(Arc::new(rpc));
|
||
Ok(Arc::new(rpc_client))
|
||
}
|
||
}
|
||
}
|
||
}
|