Rollback
This commit is contained in:
@@ -15,6 +15,8 @@ pub struct NonceInfo {
|
||||
pub nonce_account: Option<Pubkey>,
|
||||
/// Current nonce value
|
||||
pub current_nonce: Hash,
|
||||
/// Next available time (Unix timestamp in seconds)
|
||||
pub next_buy_time: i64,
|
||||
/// Whether it has been used
|
||||
pub used: bool,
|
||||
}
|
||||
@@ -37,6 +39,7 @@ impl NonceCache {
|
||||
nonce_info: Mutex::new(NonceInfo {
|
||||
nonce_account: None,
|
||||
current_nonce: Hash::default(),
|
||||
next_buy_time: 0,
|
||||
used: false,
|
||||
}),
|
||||
})
|
||||
@@ -47,7 +50,7 @@ impl NonceCache {
|
||||
/// Initialize nonce information
|
||||
pub fn init(&self, nonce_account_str: Option<String>) {
|
||||
let nonce_account = nonce_account_str.and_then(|s| Pubkey::from_str(&s).ok());
|
||||
self.update_nonce_info_partial(nonce_account, None, Some(false));
|
||||
self.update_nonce_info_partial(nonce_account, None, None, Some(false));
|
||||
}
|
||||
|
||||
/// Get a copy of NonceInfo
|
||||
@@ -56,6 +59,7 @@ impl NonceCache {
|
||||
NonceInfo {
|
||||
nonce_account: nonce_info.nonce_account,
|
||||
current_nonce: nonce_info.current_nonce,
|
||||
next_buy_time: nonce_info.next_buy_time,
|
||||
used: nonce_info.used,
|
||||
}
|
||||
}
|
||||
@@ -65,6 +69,7 @@ impl NonceCache {
|
||||
&self,
|
||||
nonce_account: Option<Pubkey>,
|
||||
current_nonce: Option<Hash>,
|
||||
next_buy_time: Option<i64>,
|
||||
used: Option<bool>,
|
||||
) {
|
||||
let mut current = self.nonce_info.lock();
|
||||
@@ -78,6 +83,10 @@ impl NonceCache {
|
||||
current.current_nonce = nonce;
|
||||
}
|
||||
|
||||
if let Some(time) = next_buy_time {
|
||||
current.next_buy_time = time;
|
||||
}
|
||||
|
||||
if let Some(u) = used {
|
||||
current.used = u;
|
||||
}
|
||||
@@ -85,7 +94,7 @@ impl NonceCache {
|
||||
|
||||
/// Mark nonce as used
|
||||
pub fn mark_used(&self) {
|
||||
self.update_nonce_info_partial(None, None, Some(true));
|
||||
self.update_nonce_info_partial(None, None, None, Some(true));
|
||||
}
|
||||
|
||||
/// Fetch nonce information using RPC
|
||||
@@ -100,7 +109,12 @@ impl NonceCache {
|
||||
let blockhash = data.durable_nonce.as_hash();
|
||||
let old_nonce_info = self.get_nonce_info();
|
||||
if old_nonce_info.current_nonce != *blockhash {
|
||||
self.update_nonce_info_partial(None, Some(*blockhash), Some(false));
|
||||
self.update_nonce_info_partial(
|
||||
None,
|
||||
Some(*blockhash),
|
||||
None,
|
||||
Some(false),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,80 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
constants::trade::trade::{
|
||||
DEFAULT_BUY_TIP_FEE, DEFAULT_RPC_UNIT_LIMIT, DEFAULT_RPC_UNIT_PRICE, DEFAULT_SELL_TIP_FEE,
|
||||
DEFAULT_TIP_UNIT_LIMIT, DEFAULT_TIP_UNIT_PRICE,
|
||||
},
|
||||
swqos::{SwqosClient, SwqosConfig},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TradeConfig {
|
||||
pub rpc_url: String,
|
||||
pub swqos_configs: Vec<SwqosConfig>,
|
||||
pub priority_fee: PriorityFee,
|
||||
pub commitment: CommitmentConfig,
|
||||
}
|
||||
|
||||
impl TradeConfig {
|
||||
pub fn new(
|
||||
rpc_url: String,
|
||||
swqos_configs: Vec<SwqosConfig>,
|
||||
priority_fee: PriorityFee,
|
||||
commitment: CommitmentConfig,
|
||||
) -> Self {
|
||||
Self { rpc_url, swqos_configs, priority_fee, commitment }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, PartialEq)]
|
||||
pub struct PriorityFee {
|
||||
pub tip_unit_limit: u32,
|
||||
pub tip_unit_price: u64,
|
||||
pub rpc_unit_limit: u32,
|
||||
pub rpc_unit_price: u64,
|
||||
// Matches the order of swqos
|
||||
pub buy_tip_fees: Vec<f64>,
|
||||
// Matches the order of swqos
|
||||
pub sell_tip_fees: Vec<f64>,
|
||||
}
|
||||
|
||||
impl Default for PriorityFee {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
tip_unit_limit: DEFAULT_TIP_UNIT_LIMIT,
|
||||
tip_unit_price: DEFAULT_TIP_UNIT_PRICE,
|
||||
rpc_unit_limit: DEFAULT_RPC_UNIT_LIMIT,
|
||||
rpc_unit_price: DEFAULT_RPC_UNIT_PRICE,
|
||||
// Matches the order of swqos
|
||||
buy_tip_fees: vec![DEFAULT_BUY_TIP_FEE],
|
||||
// Matches the order of swqos
|
||||
sell_tip_fees: vec![DEFAULT_SELL_TIP_FEE],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type SolanaRpcClient = solana_client::nonblocking::rpc_client::RpcClient;
|
||||
|
||||
pub struct MethodArgs {
|
||||
pub payer: Arc<Keypair>,
|
||||
pub rpc: Arc<RpcClient>,
|
||||
pub nonblocking_rpc: Arc<SolanaRpcClient>,
|
||||
pub jito_client: Arc<SwqosClient>,
|
||||
}
|
||||
|
||||
impl MethodArgs {
|
||||
pub fn new(
|
||||
payer: Arc<Keypair>,
|
||||
rpc: Arc<RpcClient>,
|
||||
nonblocking_rpc: Arc<SolanaRpcClient>,
|
||||
jito_client: Arc<SwqosClient>,
|
||||
) -> Self {
|
||||
Self { payer, rpc, nonblocking_rpc, jito_client }
|
||||
}
|
||||
}
|
||||
|
||||
pub type AnyResult<T> = anyhow::Result<T>;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
pub mod trade {
|
||||
pub const DEFAULT_CU_LIMIT: u32 = 150000;
|
||||
pub const DEFAULT_CU_PRICE: u64 = 500000;
|
||||
pub const DEFAULT_SLIPPAGE: u64 = 1000; // 10%
|
||||
pub const DEFAULT_TIP_UNIT_LIMIT: u32 = 78000;
|
||||
pub const DEFAULT_TIP_UNIT_PRICE: u64 = 500000;
|
||||
pub const DEFAULT_BUY_TIP_FEE: f64 = 0.0006;
|
||||
pub const DEFAULT_SELL_TIP_FEE: f64 = 0.0001;
|
||||
pub const DEFAULT_SELL_TIP_FEE: f64 = 0.0001;
|
||||
pub const DEFAULT_RPC_UNIT_LIMIT: u32 = 78000;
|
||||
pub const DEFAULT_RPC_UNIT_PRICE: u64 = 500000;
|
||||
}
|
||||
@@ -7,7 +7,7 @@ use crate::{
|
||||
trading::{
|
||||
common::utils::get_token_balance,
|
||||
core::{
|
||||
params::{BonkParams, InternalBuyParams, InternalSellParams},
|
||||
params::{BonkParams, BuyParams, SellParams},
|
||||
traits::InstructionBuilder,
|
||||
},
|
||||
},
|
||||
@@ -27,7 +27,7 @@ pub struct BonkInstructionBuilder;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl InstructionBuilder for BonkInstructionBuilder {
|
||||
async fn build_buy_instructions(&self, params: &InternalBuyParams) -> Result<Vec<Instruction>> {
|
||||
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>> {
|
||||
// ========================================
|
||||
// Parameter validation and basic data preparation
|
||||
// ========================================
|
||||
@@ -144,7 +144,7 @@ impl InstructionBuilder for BonkInstructionBuilder {
|
||||
Ok(instructions)
|
||||
}
|
||||
|
||||
async fn build_sell_instructions(&self, params: &InternalSellParams) -> Result<Vec<Instruction>> {
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
|
||||
// ========================================
|
||||
// Parameter validation and basic data preparation
|
||||
// ========================================
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
constants::trade::trade::DEFAULT_SLIPPAGE,
|
||||
trading::core::{
|
||||
params::{InternalBuyParams, PumpFunParams, InternalSellParams},
|
||||
params::{BuyParams, PumpFunParams, SellParams},
|
||||
traits::InstructionBuilder,
|
||||
},
|
||||
};
|
||||
@@ -25,7 +25,7 @@ pub struct PumpFunInstructionBuilder;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl InstructionBuilder for PumpFunInstructionBuilder {
|
||||
async fn build_buy_instructions(&self, params: &InternalBuyParams) -> Result<Vec<Instruction>> {
|
||||
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>> {
|
||||
// ========================================
|
||||
// Parameter validation and basic data preparation
|
||||
// ========================================
|
||||
@@ -138,7 +138,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder {
|
||||
Ok(instructions)
|
||||
}
|
||||
|
||||
async fn build_sell_instructions(&self, params: &InternalSellParams) -> Result<Vec<Instruction>> {
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
|
||||
// ========================================
|
||||
// Parameter validation and basic data preparation
|
||||
// ========================================
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::{
|
||||
trading::{
|
||||
common::wsol_manager,
|
||||
core::{
|
||||
params::{InternalBuyParams, PumpSwapParams, InternalSellParams},
|
||||
params::{BuyParams, PumpSwapParams, SellParams},
|
||||
traits::InstructionBuilder,
|
||||
},
|
||||
},
|
||||
@@ -25,7 +25,7 @@ pub struct PumpSwapInstructionBuilder;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl InstructionBuilder for PumpSwapInstructionBuilder {
|
||||
async fn build_buy_instructions(&self, params: &InternalBuyParams) -> Result<Vec<Instruction>> {
|
||||
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>> {
|
||||
// ========================================
|
||||
// Parameter validation and basic data preparation
|
||||
// ========================================
|
||||
@@ -197,7 +197,7 @@ impl InstructionBuilder for PumpSwapInstructionBuilder {
|
||||
Ok(instructions)
|
||||
}
|
||||
|
||||
async fn build_sell_instructions(&self, params: &InternalSellParams) -> Result<Vec<Instruction>> {
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
|
||||
// ========================================
|
||||
// Parameter validation and basic data preparation
|
||||
// ========================================
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::{
|
||||
constants::trade::trade::DEFAULT_SLIPPAGE,
|
||||
instruction::utils::raydium_amm_v4::{accounts, SWAP_BASE_IN_DISCRIMINATOR},
|
||||
trading::core::{
|
||||
params::{InternalBuyParams, RaydiumAmmV4Params, InternalSellParams},
|
||||
params::{BuyParams, RaydiumAmmV4Params, SellParams},
|
||||
traits::InstructionBuilder,
|
||||
},
|
||||
utils::calc::raydium_amm_v4::compute_swap_amount,
|
||||
@@ -18,7 +18,7 @@ pub struct RaydiumAmmV4InstructionBuilder;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl InstructionBuilder for RaydiumAmmV4InstructionBuilder {
|
||||
async fn build_buy_instructions(&self, params: &InternalBuyParams) -> Result<Vec<Instruction>> {
|
||||
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>> {
|
||||
// ========================================
|
||||
// Parameter validation and basic data preparation
|
||||
// ========================================
|
||||
@@ -122,7 +122,7 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder {
|
||||
Ok(instructions)
|
||||
}
|
||||
|
||||
async fn build_sell_instructions(&self, params: &InternalSellParams) -> Result<Vec<Instruction>> {
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
|
||||
// ========================================
|
||||
// Parameter validation and basic data preparation
|
||||
// ========================================
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::{
|
||||
SWAP_BASE_IN_DISCRIMINATOR,
|
||||
},
|
||||
trading::core::{
|
||||
params::{InternalBuyParams, RaydiumCpmmParams, InternalSellParams},
|
||||
params::{BuyParams, RaydiumCpmmParams, SellParams},
|
||||
traits::InstructionBuilder,
|
||||
},
|
||||
utils::calc::raydium_cpmm::compute_swap_amount,
|
||||
@@ -23,7 +23,7 @@ pub struct RaydiumCpmmInstructionBuilder;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl InstructionBuilder for RaydiumCpmmInstructionBuilder {
|
||||
async fn build_buy_instructions(&self, params: &InternalBuyParams) -> Result<Vec<Instruction>> {
|
||||
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>> {
|
||||
// ========================================
|
||||
// Parameter validation and basic data preparation
|
||||
// ========================================
|
||||
@@ -153,7 +153,7 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder {
|
||||
Ok(instructions)
|
||||
}
|
||||
|
||||
async fn build_sell_instructions(&self, params: &InternalSellParams) -> Result<Vec<Instruction>> {
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
|
||||
// ========================================
|
||||
// Parameter validation and basic data preparation
|
||||
// ========================================
|
||||
|
||||
+191
-223
@@ -5,8 +5,11 @@ pub mod protos;
|
||||
pub mod swqos;
|
||||
pub mod trading;
|
||||
pub mod utils;
|
||||
use solana_sdk::signer::Signer;
|
||||
pub use solana_streamer_sdk;
|
||||
|
||||
use crate::constants::trade::trade::DEFAULT_SLIPPAGE;
|
||||
use crate::swqos::settings::SwqosSettings;
|
||||
use crate::swqos::SwqosConfig;
|
||||
use crate::trading::core::params::BonkParams;
|
||||
use crate::trading::core::params::PumpFunParams;
|
||||
use crate::trading::core::params::PumpSwapParams;
|
||||
@@ -14,33 +17,24 @@ use crate::trading::core::params::RaydiumAmmV4Params;
|
||||
use crate::trading::core::params::RaydiumCpmmParams;
|
||||
use crate::trading::core::traits::ProtocolParams;
|
||||
use crate::trading::factory::DexType;
|
||||
use crate::trading::InternalBuyParams;
|
||||
use crate::trading::InternalSellParams;
|
||||
use crate::trading::BuyParams;
|
||||
use crate::trading::MiddlewareManager;
|
||||
use crate::trading::SellParams;
|
||||
use crate::trading::TradeFactory;
|
||||
use common::SolanaRpcClient;
|
||||
use common::{PriorityFee, SolanaRpcClient, TradeConfig};
|
||||
use parking_lot::Mutex;
|
||||
use rustls::crypto::{ring::default_provider, CryptoProvider};
|
||||
use solana_sdk::commitment_config::CommitmentConfig;
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::signer::Signer;
|
||||
use solana_sdk::{pubkey::Pubkey, signature::Keypair, signature::Signature};
|
||||
pub use solana_streamer_sdk;
|
||||
use std::sync::Arc;
|
||||
use swqos::SwqosClient;
|
||||
|
||||
/// Main trading client for Solana DeFi protocols
|
||||
///
|
||||
/// `SolanaTrade` provides a unified interface for trading across multiple Solana DEXs
|
||||
/// including PumpFun, PumpSwap, Bonk, Raydium AMM V4, and Raydium CPMM.
|
||||
/// It manages RPC connections, transaction signing, and SWQOS (Solana Web Quality of Service) settings.
|
||||
pub struct SolanaTrade {
|
||||
/// The keypair used for signing all transactions
|
||||
pub payer: Arc<Keypair>,
|
||||
/// RPC client for blockchain interactions
|
||||
pub rpc: Arc<SolanaRpcClient>,
|
||||
/// SWQOS settings for transaction priority and routing
|
||||
pub swqos_settings: Vec<Arc<SwqosSettings>>,
|
||||
/// Optional middleware manager for custom transaction processing
|
||||
pub rpc_client: Vec<Arc<SwqosClient>>,
|
||||
pub swqos_clients: Vec<Arc<SwqosClient>>,
|
||||
pub priority_fee: Arc<PriorityFee>,
|
||||
pub middleware_manager: Option<Arc<MiddlewareManager>>,
|
||||
}
|
||||
|
||||
@@ -51,105 +45,17 @@ impl Clone for SolanaTrade {
|
||||
Self {
|
||||
payer: self.payer.clone(),
|
||||
rpc: self.rpc.clone(),
|
||||
swqos_settings: self.swqos_settings.clone(),
|
||||
rpc_client: self.rpc_client.clone(),
|
||||
swqos_clients: self.swqos_clients.clone(),
|
||||
priority_fee: self.priority_fee.clone(),
|
||||
middleware_manager: self.middleware_manager.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parameters for executing buy orders across different DEX protocols
|
||||
///
|
||||
/// Contains all necessary configuration for purchasing tokens, including
|
||||
/// protocol-specific settings, account management options, and transaction preferences.
|
||||
#[derive(Clone)]
|
||||
pub struct TradeBuyParams {
|
||||
// Trading configuration
|
||||
/// The DEX protocol to use for the trade
|
||||
pub dex_type: DexType,
|
||||
/// Public key of the token to purchase
|
||||
pub mint: Pubkey,
|
||||
/// Amount of SOL to spend (in lamports)
|
||||
pub sol_amount: u64,
|
||||
/// Optional slippage tolerance in basis points (e.g., 100 = 1%)
|
||||
pub slippage_basis_points: Option<u64>,
|
||||
/// Recent blockhash for transaction validity
|
||||
pub recent_blockhash: Hash,
|
||||
/// Protocol-specific parameters (PumpFun, Raydium, etc.)
|
||||
pub extension_params: Box<dyn ProtocolParams>,
|
||||
// Extended configuration
|
||||
/// Optional custom compute unit limit for the transaction
|
||||
pub custom_cu_limit: Option<u32>,
|
||||
/// Optional address lookup table for transaction size optimization
|
||||
pub lookup_table_key: Option<Pubkey>,
|
||||
/// Whether to wait for transaction confirmation before returning
|
||||
pub wait_transaction_confirmed: bool,
|
||||
/// Whether to create wrapped SOL associated token account
|
||||
pub create_wsol_ata: bool,
|
||||
/// Whether to close wrapped SOL associated token account after trade
|
||||
pub close_wsol_ata: bool,
|
||||
/// Whether to create token mint associated token account
|
||||
pub create_mint_ata: bool,
|
||||
/// Whether to enable seed-based optimization for account creation
|
||||
pub open_seed_optimize: bool,
|
||||
}
|
||||
|
||||
/// Parameters for executing sell orders across different DEX protocols
|
||||
///
|
||||
/// Contains all necessary configuration for selling tokens, including
|
||||
/// protocol-specific settings, tip preferences, account management options, and transaction preferences.
|
||||
#[derive(Clone)]
|
||||
pub struct TradeSellParams {
|
||||
// Trading configuration
|
||||
/// The DEX protocol to use for the trade
|
||||
pub dex_type: DexType,
|
||||
/// Public key of the token to sell
|
||||
pub mint: Pubkey,
|
||||
/// Amount of tokens to sell (in smallest token units)
|
||||
pub token_amount: u64,
|
||||
/// Optional slippage tolerance in basis points (e.g., 100 = 1%)
|
||||
pub slippage_basis_points: Option<u64>,
|
||||
/// Recent blockhash for transaction validity
|
||||
pub recent_blockhash: Hash,
|
||||
/// Whether to include tip for transaction priority
|
||||
pub with_tip: bool,
|
||||
/// Protocol-specific parameters (PumpFun, Raydium, etc.)
|
||||
pub extension_params: Box<dyn ProtocolParams>,
|
||||
// Extended configuration
|
||||
/// Optional custom compute unit limit for the transaction
|
||||
pub custom_cu_limit: Option<u32>,
|
||||
/// Optional address lookup table for transaction size optimization
|
||||
pub lookup_table_key: Option<Pubkey>,
|
||||
/// Whether to wait for transaction confirmation before returning
|
||||
pub wait_transaction_confirmed: bool,
|
||||
/// Whether to create wrapped SOL associated token account
|
||||
pub create_wsol_ata: bool,
|
||||
/// Whether to close wrapped SOL associated token account after trade
|
||||
pub close_wsol_ata: bool,
|
||||
/// Whether to enable seed-based optimization for account creation
|
||||
pub open_seed_optimize: bool,
|
||||
}
|
||||
|
||||
impl SolanaTrade {
|
||||
/// Creates a new SolanaTrade instance with the specified configuration
|
||||
///
|
||||
/// This function initializes the trading system with RPC connection, SWQOS settings,
|
||||
/// and sets up necessary components for trading operations.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `payer` - The keypair used for signing transactions
|
||||
/// * `rpc_url` - Solana RPC endpoint URL
|
||||
/// * `commitment` - Transaction commitment level for RPC calls
|
||||
/// * `swqos_settings` - List of SWQOS (Solana Web Quality of Service) configurations
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a configured `SolanaTrade` instance ready for trading operations
|
||||
#[inline]
|
||||
pub async fn new(
|
||||
payer: Arc<Keypair>,
|
||||
rpc_url: String,
|
||||
commitment: CommitmentConfig,
|
||||
mut swqos_settings: Vec<SwqosSettings>,
|
||||
) -> Self {
|
||||
pub async fn new(payer: Arc<Keypair>, trade_config: TradeConfig) -> Self {
|
||||
crate::common::fast_fn::fast_init(&payer.try_pubkey().unwrap());
|
||||
|
||||
if CryptoProvider::get_default().is_none() {
|
||||
@@ -158,22 +64,34 @@ impl SolanaTrade {
|
||||
.map_err(|e| anyhow::anyhow!("Failed to install crypto provider: {:?}", e));
|
||||
}
|
||||
|
||||
let rpc_url = rpc_url.clone();
|
||||
let commitment = commitment.clone();
|
||||
let rpc_url = trade_config.rpc_url.clone();
|
||||
let swqos_configs = trade_config.swqos_configs.clone();
|
||||
let priority_fee = Arc::new(trade_config.priority_fee.clone());
|
||||
let commitment = trade_config.commitment.clone();
|
||||
let mut swqos_clients: Vec<Arc<SwqosClient>> = vec![];
|
||||
|
||||
for swqos in &mut swqos_settings {
|
||||
swqos.setup_swqos_client(rpc_url.clone(), commitment.clone());
|
||||
for swqos in swqos_configs {
|
||||
let swqos_client =
|
||||
SwqosConfig::get_swqos_client(rpc_url.clone(), commitment.clone(), swqos.clone());
|
||||
swqos_clients.push(swqos_client);
|
||||
}
|
||||
|
||||
let rpc =
|
||||
Arc::new(SolanaRpcClient::new_with_commitment(rpc_url.clone(), commitment.clone()));
|
||||
let rpc = Arc::new(SolanaRpcClient::new_with_commitment(rpc_url.clone(), commitment));
|
||||
common::seed::update_rents(&rpc).await.unwrap();
|
||||
common::seed::start_rent_updater(rpc.clone());
|
||||
|
||||
let rpc_client = SwqosConfig::get_swqos_client(
|
||||
rpc_url.clone(),
|
||||
commitment,
|
||||
SwqosConfig::Default(rpc_url),
|
||||
);
|
||||
|
||||
let instance = Self {
|
||||
payer,
|
||||
rpc,
|
||||
swqos_settings: swqos_settings.into_iter().map(|s| Arc::new(s)).collect(),
|
||||
rpc_client: vec![rpc_client],
|
||||
swqos_clients,
|
||||
priority_fee,
|
||||
middleware_manager: None,
|
||||
};
|
||||
|
||||
@@ -183,47 +101,22 @@ impl SolanaTrade {
|
||||
instance
|
||||
}
|
||||
|
||||
/// Adds a middleware manager to the SolanaTrade instance
|
||||
///
|
||||
/// Middleware managers can be used to implement custom logic that runs before or after trading operations,
|
||||
/// such as logging, monitoring, or custom validation.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `middleware_manager` - The middleware manager to attach
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns the modified SolanaTrade instance with middleware manager attached
|
||||
pub fn with_middleware_manager(mut self, middleware_manager: MiddlewareManager) -> Self {
|
||||
self.middleware_manager = Some(Arc::new(middleware_manager));
|
||||
self
|
||||
}
|
||||
|
||||
/// Gets the RPC client instance for direct Solana blockchain interactions
|
||||
///
|
||||
/// This provides access to the underlying Solana RPC client that can be used
|
||||
/// for custom blockchain operations outside of the trading framework.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns a reference to the Arc-wrapped SolanaRpcClient instance
|
||||
/// Get the RPC client instance
|
||||
pub fn get_rpc(&self) -> &Arc<SolanaRpcClient> {
|
||||
&self.rpc
|
||||
}
|
||||
|
||||
/// Gets the current globally shared SolanaTrade instance
|
||||
///
|
||||
/// This provides access to the singleton instance that was created with `new()`.
|
||||
/// Useful for accessing the trading instance from different parts of the application.
|
||||
///
|
||||
/// # Returns
|
||||
/// Returns the Arc-wrapped SolanaTrade instance
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if no instance has been initialized yet. Make sure to call `new()` first.
|
||||
/// Get the current instance
|
||||
pub fn get_instance() -> Arc<Self> {
|
||||
let instance = INSTANCE.lock();
|
||||
instance
|
||||
.as_ref()
|
||||
.expect("SolanaTrade instance not initialized. Please call new() first.")
|
||||
.expect("PumpFun instance not initialized. Please call new() first.")
|
||||
.clone()
|
||||
}
|
||||
|
||||
@@ -231,53 +124,80 @@ impl SolanaTrade {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `params` - Buy trade parameters containing all necessary trading configuration
|
||||
/// * `dex_type` - The trading protocol to use (PumpFun, PumpSwap, or Bonk)
|
||||
/// * `mint` - The public key of the token mint to buy
|
||||
/// * `sol_amount` - Amount of SOL to spend on the purchase (in lamports)
|
||||
/// * `slippage_basis_points` - Optional slippage tolerance in basis points (e.g., 100 = 1%)
|
||||
/// * `recent_blockhash` - Recent blockhash for transaction validity
|
||||
/// * `custom_priority_fee` - Optional custom priority fee for priority processing
|
||||
/// * `extension_params` - Optional protocol-specific parameters (uses defaults if None)
|
||||
/// * `lookup_table_key` - Optional address lookup table key for transaction optimization
|
||||
/// * `wait_transaction_confirmed` - Whether to wait for the transaction to be confirmed
|
||||
/// * `create_wsol_ata` - Whether to create wSOL ATA account
|
||||
/// * `close_wsol_ata` - Whether to close wSOL ATA account
|
||||
/// * `open_seed_optimize` - Whether to open seed optimize
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns `Ok(Signature)` with the transaction signature if the buy order is successfully executed,
|
||||
/// or an error if the transaction fails.
|
||||
/// Returns `Ok(())` if the buy order is successfully executed, or an error if the transaction fails.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if:
|
||||
/// - Invalid protocol parameters are provided for the specified DEX type
|
||||
/// - Invalid protocol parameters are provided
|
||||
/// - The transaction fails to execute
|
||||
/// - Network or RPC errors occur
|
||||
/// - Insufficient SOL balance for the purchase
|
||||
/// - Required accounts cannot be created or accessed
|
||||
pub async fn buy(&self, params: TradeBuyParams) -> Result<Signature, anyhow::Error> {
|
||||
if params.slippage_basis_points.is_none() {
|
||||
pub async fn buy(
|
||||
&self,
|
||||
dex_type: DexType,
|
||||
mint: Pubkey,
|
||||
sol_amount: u64,
|
||||
slippage_basis_points: Option<u64>,
|
||||
recent_blockhash: Hash,
|
||||
custom_priority_fee: Option<PriorityFee>,
|
||||
extension_params: Box<dyn ProtocolParams>,
|
||||
lookup_table_key: Option<Pubkey>,
|
||||
wait_transaction_confirmed: bool,
|
||||
create_wsol_ata: bool,
|
||||
close_wsol_ata: bool,
|
||||
create_mint_ata: bool,
|
||||
open_seed_optimize: bool,
|
||||
) -> Result<Signature, anyhow::Error> {
|
||||
if slippage_basis_points.is_none() {
|
||||
println!(
|
||||
"slippage_basis_points is none, use default slippage basis points: {}",
|
||||
DEFAULT_SLIPPAGE
|
||||
);
|
||||
}
|
||||
let executor = TradeFactory::create_executor(params.dex_type.clone());
|
||||
let protocol_params = params.extension_params;
|
||||
let executor = TradeFactory::create_executor(dex_type.clone());
|
||||
let protocol_params = extension_params;
|
||||
|
||||
let buy_params = InternalBuyParams {
|
||||
let mut buy_params = BuyParams {
|
||||
rpc: Some(self.rpc.clone()),
|
||||
payer: self.payer.clone(),
|
||||
mint: params.mint,
|
||||
sol_amount: params.sol_amount,
|
||||
slippage_basis_points: params.slippage_basis_points,
|
||||
lookup_table_key: params.lookup_table_key,
|
||||
recent_blockhash: params.recent_blockhash,
|
||||
mint: mint,
|
||||
sol_amount: sol_amount,
|
||||
slippage_basis_points: slippage_basis_points,
|
||||
priority_fee: self.priority_fee.clone(),
|
||||
lookup_table_key,
|
||||
recent_blockhash,
|
||||
data_size_limit: 256 * 1024,
|
||||
wait_transaction_confirmed: params.wait_transaction_confirmed,
|
||||
wait_transaction_confirmed: wait_transaction_confirmed,
|
||||
protocol_params: protocol_params.clone(),
|
||||
open_seed_optimize: params.open_seed_optimize,
|
||||
create_wsol_ata: params.create_wsol_ata,
|
||||
close_wsol_ata: params.close_wsol_ata,
|
||||
create_mint_ata: params.create_mint_ata,
|
||||
swqos_settings: self.swqos_settings.clone(),
|
||||
open_seed_optimize,
|
||||
create_wsol_ata,
|
||||
close_wsol_ata,
|
||||
create_mint_ata,
|
||||
swqos_clients: self.swqos_clients.clone(),
|
||||
middleware_manager: self.middleware_manager.clone(),
|
||||
custom_cu_limit: params.custom_cu_limit,
|
||||
};
|
||||
if custom_priority_fee.is_some() {
|
||||
buy_params.priority_fee = Arc::new(custom_priority_fee.unwrap());
|
||||
}
|
||||
|
||||
// Validate protocol params
|
||||
let is_valid_params = match params.dex_type {
|
||||
let is_valid_params = match dex_type {
|
||||
DexType::PumpFun => protocol_params.as_any().downcast_ref::<PumpFunParams>().is_some(),
|
||||
DexType::PumpSwap => {
|
||||
protocol_params.as_any().downcast_ref::<PumpSwapParams>().is_some()
|
||||
@@ -302,53 +222,86 @@ impl SolanaTrade {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `params` - Sell trade parameters containing all necessary trading configuration
|
||||
/// * `dex_type` - The trading protocol to use (PumpFun, PumpSwap, or Bonk)
|
||||
/// * `mint` - The public key of the token mint to sell
|
||||
/// * `token_amount` - Amount of tokens to sell (in smallest token units)
|
||||
/// * `slippage_basis_points` - Optional slippage tolerance in basis points (e.g., 100 = 1%)
|
||||
/// * `recent_blockhash` - Recent blockhash for transaction validity
|
||||
/// * `custom_priority_fee` - Optional custom priority fee for priority processing
|
||||
/// * `with_tip` - Optional boolean to indicate if the transaction should be sent with tip
|
||||
/// * `extension_params` - Optional protocol-specific parameters (uses defaults if None)
|
||||
/// * `lookup_table_key` - Optional address lookup table key for transaction optimization
|
||||
/// * `wait_transaction_confirmed` - Whether to wait for the transaction to be confirmed
|
||||
/// * `create_wsol_ata` - Whether to create wSOL ATA account
|
||||
/// * `close_wsol_ata` - Whether to close wSOL ATA account
|
||||
/// * `open_seed_optimize` - Whether to open seed optimize
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns `Ok(Signature)` with the transaction signature if the sell order is successfully executed,
|
||||
/// or an error if the transaction fails.
|
||||
/// Returns `Ok(())` if the sell order is successfully executed, or an error if the transaction fails.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if:
|
||||
/// - Invalid protocol parameters are provided for the specified DEX type
|
||||
/// - Invalid protocol parameters are provided
|
||||
/// - The transaction fails to execute
|
||||
/// - Network or RPC errors occur
|
||||
/// - Insufficient token balance for the sale
|
||||
/// - Token account doesn't exist or is not properly initialized
|
||||
/// - Required accounts cannot be created or accessed
|
||||
pub async fn sell(&self, params: TradeSellParams) -> Result<Signature, anyhow::Error> {
|
||||
if params.slippage_basis_points.is_none() {
|
||||
pub async fn sell(
|
||||
&self,
|
||||
dex_type: DexType,
|
||||
mint: Pubkey,
|
||||
token_amount: u64,
|
||||
slippage_basis_points: Option<u64>,
|
||||
recent_blockhash: Hash,
|
||||
custom_priority_fee: Option<PriorityFee>,
|
||||
with_tip: bool,
|
||||
extension_params: Box<dyn ProtocolParams>,
|
||||
lookup_table_key: Option<Pubkey>,
|
||||
wait_transaction_confirmed: bool,
|
||||
create_wsol_ata: bool,
|
||||
close_wsol_ata: bool,
|
||||
open_seed_optimize: bool,
|
||||
) -> Result<Signature, anyhow::Error> {
|
||||
if slippage_basis_points.is_none() {
|
||||
println!(
|
||||
"slippage_basis_points is none, use default slippage basis points: {}",
|
||||
DEFAULT_SLIPPAGE
|
||||
);
|
||||
}
|
||||
let executor = TradeFactory::create_executor(params.dex_type.clone());
|
||||
let protocol_params = params.extension_params;
|
||||
let executor = TradeFactory::create_executor(dex_type.clone());
|
||||
let protocol_params = extension_params;
|
||||
|
||||
let sell_params = InternalSellParams {
|
||||
let mut sell_params = SellParams {
|
||||
rpc: Some(self.rpc.clone()),
|
||||
payer: self.payer.clone(),
|
||||
mint: params.mint,
|
||||
token_amount: Some(params.token_amount),
|
||||
slippage_basis_points: params.slippage_basis_points,
|
||||
lookup_table_key: params.lookup_table_key,
|
||||
recent_blockhash: params.recent_blockhash,
|
||||
wait_transaction_confirmed: params.wait_transaction_confirmed,
|
||||
mint: mint,
|
||||
token_amount: Some(token_amount),
|
||||
slippage_basis_points: slippage_basis_points,
|
||||
priority_fee: self.priority_fee.clone(),
|
||||
lookup_table_key,
|
||||
recent_blockhash,
|
||||
wait_transaction_confirmed: wait_transaction_confirmed,
|
||||
protocol_params: protocol_params.clone(),
|
||||
with_tip: params.with_tip,
|
||||
open_seed_optimize: params.open_seed_optimize,
|
||||
swqos_settings: self.swqos_settings.clone(),
|
||||
with_tip: with_tip,
|
||||
open_seed_optimize,
|
||||
swqos_clients: if !with_tip {
|
||||
self.rpc_client.clone()
|
||||
} else {
|
||||
self.swqos_clients.clone()
|
||||
},
|
||||
middleware_manager: self.middleware_manager.clone(),
|
||||
create_wsol_ata: params.create_wsol_ata,
|
||||
close_wsol_ata: params.close_wsol_ata,
|
||||
custom_cu_limit: params.custom_cu_limit,
|
||||
create_wsol_ata,
|
||||
close_wsol_ata,
|
||||
};
|
||||
|
||||
if custom_priority_fee.is_some() {
|
||||
sell_params.priority_fee = Arc::new(custom_priority_fee.unwrap());
|
||||
}
|
||||
|
||||
// Validate protocol params
|
||||
let is_valid_params = match params.dex_type {
|
||||
let is_valid_params = match dex_type {
|
||||
DexType::PumpFun => protocol_params.as_any().downcast_ref::<PumpFunParams>().is_some(),
|
||||
DexType::PumpSwap => {
|
||||
protocol_params.as_any().downcast_ref::<PumpSwapParams>().is_some()
|
||||
@@ -377,59 +330,82 @@ impl SolanaTrade {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `params` - Sell trade parameters (will be modified with calculated token amount)
|
||||
/// * `dex_type` - The trading protocol to use (PumpFun, PumpSwap, or Bonk)
|
||||
/// * `mint` - The public key of the token mint to sell
|
||||
/// * `amount_token` - Total amount of tokens available (in smallest token units)
|
||||
/// * `percent` - Percentage of tokens to sell (1-100, where 100 = 100%)
|
||||
/// * `slippage_basis_points` - Optional slippage tolerance in basis points (e.g., 100 = 1%)
|
||||
/// * `recent_blockhash` - Recent blockhash for transaction validity
|
||||
/// * `custom_priority_fee` - Optional custom priority fee for priority processing
|
||||
/// * `with_tip` - Whether to use tip for priority processing
|
||||
/// * `extension_params` - Optional protocol-specific parameters (uses defaults if None)
|
||||
/// * `lookup_table_key` - Optional lookup table key for address lookup optimization
|
||||
/// * `wait_transaction_confirmed` - Whether to wait for the transaction to be confirmed
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns `Ok(Signature)` with the transaction signature if the sell order is successfully executed,
|
||||
/// or an error if the transaction fails.
|
||||
/// Returns `Ok(())` if the sell order is successfully executed, or an error if the transaction fails.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if:
|
||||
/// - `percent` is 0 or greater than 100
|
||||
/// - Invalid protocol parameters are provided for the specified DEX type
|
||||
/// - Invalid protocol parameters are provided
|
||||
/// - The transaction fails to execute
|
||||
/// - Network or RPC errors occur
|
||||
/// - Insufficient token balance for the calculated sale amount
|
||||
/// - Token account doesn't exist or is not properly initialized
|
||||
/// - Required accounts cannot be created or accessed
|
||||
pub async fn sell_by_percent(
|
||||
&self,
|
||||
mut params: TradeSellParams,
|
||||
dex_type: DexType,
|
||||
mint: Pubkey,
|
||||
amount_token: u64,
|
||||
percent: u64,
|
||||
slippage_basis_points: Option<u64>,
|
||||
recent_blockhash: Hash,
|
||||
custom_priority_fee: Option<PriorityFee>,
|
||||
with_tip: bool,
|
||||
extension_params: Box<dyn ProtocolParams>,
|
||||
lookup_table_key: Option<Pubkey>,
|
||||
wait_transaction_confirmed: bool,
|
||||
create_wsol_ata: bool,
|
||||
close_wsol_ata: bool,
|
||||
open_seed_optimize: bool,
|
||||
) -> Result<Signature, anyhow::Error> {
|
||||
if percent == 0 || percent > 100 {
|
||||
return Err(anyhow::anyhow!("Percentage must be between 1 and 100"));
|
||||
}
|
||||
let amount = amount_token * percent / 100;
|
||||
params.token_amount = amount;
|
||||
self.sell(params).await
|
||||
self.sell(
|
||||
dex_type,
|
||||
mint,
|
||||
amount,
|
||||
slippage_basis_points,
|
||||
recent_blockhash,
|
||||
custom_priority_fee,
|
||||
with_tip,
|
||||
extension_params,
|
||||
lookup_table_key,
|
||||
wait_transaction_confirmed,
|
||||
create_wsol_ata,
|
||||
close_wsol_ata,
|
||||
open_seed_optimize,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Wraps native SOL into wSOL (Wrapped SOL) for use in SPL token operations
|
||||
/// Wraps SOL into wSOL (Wrapped SOL)
|
||||
///
|
||||
/// This function creates a wSOL associated token account (if it doesn't exist),
|
||||
/// transfers the specified amount of SOL to that account, and then syncs the native
|
||||
/// token balance to make SOL usable as an SPL token in trading operations.
|
||||
/// token balance to make SOL usable as an SPL token.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `amount` - The amount of SOL to wrap (in lamports)
|
||||
/// - `amount`: The amount of SOL to wrap (in lamports)
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(String)` - Transaction signature if successful
|
||||
/// * `Err(anyhow::Error)` - If the transaction fails to execute
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if:
|
||||
/// - Insufficient SOL balance for the wrap operation
|
||||
/// - wSOL associated token account creation fails
|
||||
/// - Transaction fails to execute or confirm
|
||||
/// - Network or RPC errors occur
|
||||
/// - `Ok(String)`: Transaction signature
|
||||
/// - `Err(anyhow::Error)`: If the transaction fails
|
||||
pub async fn wrap_sol_to_wsol(&self, amount: u64) -> Result<String, anyhow::Error> {
|
||||
use crate::trading::common::wsol_manager::handle_wsol;
|
||||
use solana_sdk::transaction::Transaction;
|
||||
@@ -441,23 +417,15 @@ impl SolanaTrade {
|
||||
let signature = self.rpc.send_and_confirm_transaction(&transaction).await?;
|
||||
Ok(signature.to_string())
|
||||
}
|
||||
/// Closes the wSOL associated token account and unwraps remaining balance to native SOL
|
||||
/// Closes the wSOL account and unwraps SOL back to native SOL
|
||||
///
|
||||
/// This function closes the wSOL associated token account, which automatically
|
||||
/// transfers any remaining wSOL balance back to the account owner as native SOL.
|
||||
/// This is useful for cleaning up wSOL accounts and recovering wrapped SOL after trading operations.
|
||||
/// This is useful for cleaning up wSOL accounts and recovering wrapped SOL.
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(String)` - Transaction signature if successful
|
||||
/// * `Err(anyhow::Error)` - If the transaction fails to execute
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if:
|
||||
/// - wSOL associated token account doesn't exist
|
||||
/// - Account closure fails due to insufficient permissions
|
||||
/// - Transaction fails to execute or confirm
|
||||
/// - Network or RPC errors occur
|
||||
/// - `Ok(String)`: Transaction signature
|
||||
/// - `Err(anyhow::Error)`: If the transaction fails
|
||||
pub async fn close_wsol(&self) -> Result<String, anyhow::Error> {
|
||||
use crate::trading::common::wsol_manager::close_wsol;
|
||||
use solana_sdk::transaction::Transaction;
|
||||
|
||||
@@ -9,7 +9,6 @@ pub mod node1;
|
||||
pub mod flashblock;
|
||||
pub mod blockrazor;
|
||||
pub mod astralane;
|
||||
pub mod settings;
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -108,23 +107,14 @@ pub enum SwqosRegion {
|
||||
#[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)
|
||||
Astralane(String, SwqosRegion, Option<String>),
|
||||
}
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
use crate::swqos::{SwqosClient, SwqosConfig};
|
||||
use solana_sdk::commitment_config::CommitmentConfig;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct SwqosSettings {
|
||||
pub swqos_config: SwqosConfig,
|
||||
pub swqos_client: Option<Arc<SwqosClient>>,
|
||||
pub unit_limit: u32,
|
||||
pub unit_price: u64,
|
||||
pub buy_tip_fee: f64,
|
||||
pub sell_tip_fee: f64,
|
||||
}
|
||||
|
||||
impl SwqosSettings {
|
||||
/// Create a new SwqosSettings
|
||||
/// swqos_config: SwqosConfig,
|
||||
/// unit_limit: u32,
|
||||
/// unit_price: u64,
|
||||
/// buy_tip_fee: f64,
|
||||
/// sell_tip_fee: f64,
|
||||
pub fn new(
|
||||
swqos_config: SwqosConfig,
|
||||
unit_limit: u32,
|
||||
unit_price: u64,
|
||||
buy_tip_fee: f64,
|
||||
sell_tip_fee: f64,
|
||||
) -> Self {
|
||||
Self { swqos_config, swqos_client: None, unit_limit, unit_price, buy_tip_fee, sell_tip_fee }
|
||||
}
|
||||
|
||||
pub fn setup_swqos_client(&mut self, rpc_url: String, commitment: CommitmentConfig) {
|
||||
let swqos_client =
|
||||
SwqosConfig::get_swqos_client(rpc_url, commitment, self.swqos_config.clone());
|
||||
self.swqos_client = Some(swqos_client);
|
||||
}
|
||||
|
||||
pub fn clone(&self) -> Self {
|
||||
Self {
|
||||
swqos_config: self.swqos_config.clone(),
|
||||
swqos_client: self.swqos_client.clone(),
|
||||
unit_limit: self.unit_limit,
|
||||
unit_price: self.unit_price,
|
||||
buy_tip_fee: self.buy_tip_fee,
|
||||
sell_tip_fee: self.sell_tip_fee,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::common::PriorityFee;
|
||||
use dashmap::DashMap;
|
||||
use once_cell::sync::Lazy;
|
||||
use smallvec::SmallVec;
|
||||
@@ -19,19 +20,20 @@ static COMPUTE_BUDGET_CACHE: Lazy<DashMap<ComputeBudgetCacheKey, SmallVec<[Instr
|
||||
|
||||
#[inline(always)]
|
||||
pub fn compute_budget_instructions(
|
||||
unit_price: u64,
|
||||
unit_limit: u32,
|
||||
priority_fee: &PriorityFee,
|
||||
data_size_limit: u32,
|
||||
is_rpc: bool,
|
||||
is_buy: bool,
|
||||
) -> SmallVec<[Instruction; 3]> {
|
||||
// Create cache key
|
||||
let cache_key = ComputeBudgetCacheKey {
|
||||
data_size_limit,
|
||||
unit_price: unit_price,
|
||||
unit_limit: unit_limit,
|
||||
is_buy,
|
||||
let (unit_price, unit_limit) = if is_rpc {
|
||||
(priority_fee.rpc_unit_price, priority_fee.rpc_unit_limit)
|
||||
} else {
|
||||
(priority_fee.tip_unit_price, priority_fee.tip_unit_limit)
|
||||
};
|
||||
|
||||
// Create cache key
|
||||
let cache_key = ComputeBudgetCacheKey { data_size_limit, unit_price, unit_limit, is_buy };
|
||||
|
||||
// Try to get from cache first
|
||||
if let Some(cached_insts) = COMPUTE_BUDGET_CACHE.get(&cache_key) {
|
||||
return cached_insts.clone();
|
||||
|
||||
@@ -16,13 +16,12 @@ use super::{
|
||||
compute_budget_manager::compute_budget_instructions,
|
||||
nonce_manager::{add_nonce_instruction, get_transaction_blockhash},
|
||||
};
|
||||
use crate::trading::MiddlewareManager;
|
||||
use crate::{common::PriorityFee, trading::MiddlewareManager};
|
||||
|
||||
/// Build standard RPC transaction
|
||||
pub async fn build_transaction(
|
||||
payer: Arc<Keypair>,
|
||||
unit_limit: u32,
|
||||
unit_price: u64,
|
||||
priority_fee: &PriorityFee,
|
||||
business_instructions: Vec<Instruction>,
|
||||
lookup_table_key: Option<Pubkey>,
|
||||
recent_blockhash: Hash,
|
||||
@@ -37,8 +36,10 @@ pub async fn build_transaction(
|
||||
let mut instructions = Vec::with_capacity(business_instructions.len() + 5);
|
||||
|
||||
// Add nonce instruction
|
||||
if let Err(e) = add_nonce_instruction(&mut instructions, payer.as_ref()) {
|
||||
return Err(e);
|
||||
if is_buy {
|
||||
if let Err(e) = add_nonce_instruction(&mut instructions, payer.as_ref()) {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Add tip transfer instruction
|
||||
@@ -52,9 +53,9 @@ pub async fn build_transaction(
|
||||
|
||||
// Add compute budget instructions
|
||||
instructions.extend(compute_budget_instructions(
|
||||
unit_price,
|
||||
unit_limit,
|
||||
priority_fee,
|
||||
data_size_limit,
|
||||
!with_tip,
|
||||
is_buy,
|
||||
));
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::{sync::Arc, time::Instant};
|
||||
use crate::trading::core::parallel::{buy_parallel_execute, sell_parallel_execute};
|
||||
|
||||
use super::{
|
||||
params::{InternalBuyParams, InternalSellParams},
|
||||
params::{BuyParams, SellParams},
|
||||
traits::{InstructionBuilder, TradeExecutor},
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ impl GenericTradeExecutor {
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl TradeExecutor for GenericTradeExecutor {
|
||||
async fn buy_with_tip(&self, params: InternalBuyParams) -> Result<Signature> {
|
||||
async fn buy_with_tip(&self, params: BuyParams) -> Result<Signature> {
|
||||
let start = Instant::now();
|
||||
|
||||
// Build instructions directly from params to avoid unnecessary cloning
|
||||
@@ -47,7 +47,7 @@ impl TradeExecutor for GenericTradeExecutor {
|
||||
buy_parallel_execute(params, final_instructions, self.protocol_name).await
|
||||
}
|
||||
|
||||
async fn sell_with_tip(&self, params: InternalSellParams) -> Result<Signature> {
|
||||
async fn sell_with_tip(&self, params: SellParams) -> Result<Signature> {
|
||||
let start = Instant::now();
|
||||
|
||||
// Build instructions directly from params to avoid unnecessary cloning
|
||||
|
||||
@@ -8,21 +8,21 @@ use tokio::sync::mpsc;
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
use crate::{
|
||||
swqos::{settings::SwqosSettings, SwqosType, TradeType},
|
||||
trading::{
|
||||
common::build_transaction, InternalBuyParams, InternalSellParams, MiddlewareManager,
|
||||
},
|
||||
common::PriorityFee,
|
||||
swqos::{SwqosClient, SwqosType, TradeType},
|
||||
trading::{common::build_transaction, BuyParams, MiddlewareManager, SellParams},
|
||||
};
|
||||
|
||||
pub async fn buy_parallel_execute(
|
||||
params: InternalBuyParams,
|
||||
params: BuyParams,
|
||||
instructions: Vec<Instruction>,
|
||||
protocol_name: &'static str,
|
||||
) -> Result<Signature> {
|
||||
parallel_execute(
|
||||
params.swqos_settings,
|
||||
params.swqos_clients,
|
||||
params.payer,
|
||||
instructions,
|
||||
params.priority_fee,
|
||||
params.lookup_table_key,
|
||||
params.recent_blockhash,
|
||||
params.data_size_limit,
|
||||
@@ -31,20 +31,20 @@ pub async fn buy_parallel_execute(
|
||||
true,
|
||||
params.wait_transaction_confirmed,
|
||||
true,
|
||||
params.custom_cu_limit,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn sell_parallel_execute(
|
||||
params: InternalSellParams,
|
||||
params: SellParams,
|
||||
instructions: Vec<Instruction>,
|
||||
protocol_name: &'static str,
|
||||
) -> Result<Signature> {
|
||||
parallel_execute(
|
||||
params.swqos_settings,
|
||||
params.swqos_clients,
|
||||
params.payer,
|
||||
instructions,
|
||||
params.priority_fee,
|
||||
params.lookup_table_key,
|
||||
params.recent_blockhash,
|
||||
0,
|
||||
@@ -53,16 +53,16 @@ pub async fn sell_parallel_execute(
|
||||
false,
|
||||
params.wait_transaction_confirmed,
|
||||
params.with_tip,
|
||||
params.custom_cu_limit,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Generic function for parallel transaction execution
|
||||
async fn parallel_execute(
|
||||
swqos_settings: Vec<Arc<SwqosSettings>>,
|
||||
swqos_clients: Vec<Arc<SwqosClient>>,
|
||||
payer: Arc<Keypair>,
|
||||
instructions: Vec<Instruction>,
|
||||
priority_fee: Arc<PriorityFee>,
|
||||
lookup_table_key: Option<Pubkey>,
|
||||
recent_blockhash: Hash,
|
||||
data_size_limit: u32,
|
||||
@@ -71,115 +71,114 @@ async fn parallel_execute(
|
||||
is_buy: bool,
|
||||
wait_transaction_confirmed: bool,
|
||||
with_tip: bool,
|
||||
custom_cu_limit: Option<u32>,
|
||||
) -> Result<Signature> {
|
||||
if swqos_settings.is_empty() {
|
||||
return Err(anyhow!("swqos_settings is empty"));
|
||||
}
|
||||
if !with_tip
|
||||
&& swqos_settings
|
||||
.iter()
|
||||
.find(|swqos| {
|
||||
matches!(swqos.swqos_client.as_ref().unwrap().get_swqos_type(), SwqosType::Default)
|
||||
})
|
||||
.is_none()
|
||||
{
|
||||
return Err(anyhow!("No Rpc Default Swqos configured"));
|
||||
}
|
||||
let cores = core_affinity::get_core_ids().unwrap();
|
||||
let mut handles: Vec<JoinHandle<Result<Signature>>> = Vec::with_capacity(swqos_settings.len());
|
||||
let mut handles: Vec<JoinHandle<Result<Signature>>> = Vec::with_capacity(swqos_clients.len());
|
||||
|
||||
if is_buy && with_tip && priority_fee.buy_tip_fees.is_empty() {
|
||||
return Err(anyhow!("buy_tip_fees is empty"));
|
||||
}
|
||||
if !is_buy && with_tip && priority_fee.sell_tip_fees.is_empty() {
|
||||
return Err(anyhow!("sell_tip_fees is empty"));
|
||||
}
|
||||
|
||||
let instructions = Arc::new(instructions);
|
||||
|
||||
for i in 0..swqos_settings.len() {
|
||||
if let Some(swqos_client) = swqos_settings[i].swqos_client.as_ref() {
|
||||
if !with_tip && !matches!(swqos_client.get_swqos_type(), SwqosType::Default) {
|
||||
continue;
|
||||
}
|
||||
let payer = payer.clone();
|
||||
let instructions = instructions.clone();
|
||||
let core_id = cores[i % cores.len()];
|
||||
for i in 0..swqos_clients.len() {
|
||||
let swqos_client = swqos_clients[i].clone();
|
||||
if !with_tip && !matches!(swqos_client.get_swqos_type(), SwqosType::Default) {
|
||||
continue;
|
||||
}
|
||||
let payer = payer.clone();
|
||||
let instructions = instructions.clone();
|
||||
let priority_fee = priority_fee.clone();
|
||||
let core_id = cores[i % cores.len()];
|
||||
|
||||
let middleware_manager = middleware_manager.clone();
|
||||
let swqos_client = swqos_client.clone();
|
||||
let buy_tip_fee = swqos_settings[i].buy_tip_fee;
|
||||
let sell_tip_fee = swqos_settings[i].sell_tip_fee;
|
||||
let mut unit_limit = swqos_settings[i].unit_limit;
|
||||
let unit_price = swqos_settings[i].unit_price;
|
||||
let middleware_manager = middleware_manager.clone();
|
||||
|
||||
if let Some(custom_cu_limit) = custom_cu_limit {
|
||||
unit_limit = custom_cu_limit;
|
||||
}
|
||||
let handle = tokio::spawn(async move {
|
||||
core_affinity::set_for_current(core_id);
|
||||
|
||||
let handle = tokio::spawn(async move {
|
||||
core_affinity::set_for_current(core_id);
|
||||
let swqos_type = swqos_client.get_swqos_type();
|
||||
let mut start = Instant::now();
|
||||
|
||||
let swqos_type = swqos_client.get_swqos_type();
|
||||
let mut start = Instant::now();
|
||||
let tip_account_str = swqos_client.get_tip_account()?;
|
||||
let tip_account = Arc::new(Pubkey::from_str(&tip_account_str).unwrap_or_default());
|
||||
|
||||
let tip_account_str = swqos_client.get_tip_account()?;
|
||||
let tip_account = Arc::new(Pubkey::from_str(&tip_account_str).unwrap_or_default());
|
||||
|
||||
let tip_amount = if with_tip {
|
||||
if is_buy {
|
||||
buy_tip_fee
|
||||
let tip_amount = if with_tip {
|
||||
if is_buy {
|
||||
if priority_fee.buy_tip_fees.len() > i {
|
||||
priority_fee.buy_tip_fees[i]
|
||||
} else {
|
||||
sell_tip_fee
|
||||
println!(
|
||||
"❗️❗️❗️[{:?}] - Using buy_tip_fees[0]: {:?}",
|
||||
swqos_type, priority_fee.buy_tip_fees[0]
|
||||
);
|
||||
priority_fee.buy_tip_fees[0]
|
||||
}
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
if priority_fee.sell_tip_fees.len() > i {
|
||||
priority_fee.sell_tip_fees[i]
|
||||
} else {
|
||||
println!(
|
||||
"❗️❗️❗️[{:?}] - Using sell_tip_fees[0]: {:?}",
|
||||
swqos_type, priority_fee.sell_tip_fees[0]
|
||||
);
|
||||
priority_fee.sell_tip_fees[0]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
let transaction = build_transaction(
|
||||
payer,
|
||||
unit_limit,
|
||||
unit_price,
|
||||
instructions.as_ref().clone(),
|
||||
lookup_table_key,
|
||||
recent_blockhash,
|
||||
data_size_limit,
|
||||
middleware_manager,
|
||||
protocol_name,
|
||||
is_buy,
|
||||
swqos_type != SwqosType::Default,
|
||||
&tip_account,
|
||||
tip_amount,
|
||||
let transaction = build_transaction(
|
||||
payer,
|
||||
&priority_fee,
|
||||
instructions.as_ref().clone(),
|
||||
lookup_table_key,
|
||||
recent_blockhash,
|
||||
data_size_limit,
|
||||
middleware_manager,
|
||||
protocol_name,
|
||||
is_buy,
|
||||
swqos_type != SwqosType::Default,
|
||||
&tip_account,
|
||||
tip_amount,
|
||||
)
|
||||
.await?;
|
||||
|
||||
println!(
|
||||
"[{:?}] - Building transaction instructions: {:?}",
|
||||
swqos_type,
|
||||
start.elapsed()
|
||||
);
|
||||
|
||||
start = Instant::now();
|
||||
|
||||
swqos_client
|
||||
.send_transaction(
|
||||
if is_buy { TradeType::Buy } else { TradeType::Sell },
|
||||
&transaction,
|
||||
)
|
||||
.await?;
|
||||
|
||||
println!(
|
||||
"[{:?}] - Building transaction instructions: {:?}",
|
||||
swqos_type,
|
||||
start.elapsed()
|
||||
);
|
||||
println!(
|
||||
"[{:?}] - Submitting transaction instructions: {:?}",
|
||||
swqos_type,
|
||||
start.elapsed()
|
||||
);
|
||||
|
||||
start = Instant::now();
|
||||
transaction
|
||||
.signatures
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("Transaction has no signatures"))
|
||||
.cloned()
|
||||
});
|
||||
|
||||
swqos_client
|
||||
.send_transaction(
|
||||
if is_buy { TradeType::Buy } else { TradeType::Sell },
|
||||
&transaction,
|
||||
)
|
||||
.await?;
|
||||
|
||||
println!(
|
||||
"[{:?}] - Submitting transaction instructions: {:?}",
|
||||
swqos_type,
|
||||
start.elapsed()
|
||||
);
|
||||
|
||||
transaction
|
||||
.signatures
|
||||
.first()
|
||||
.ok_or_else(|| anyhow!("Transaction has no signatures"))
|
||||
.cloned()
|
||||
});
|
||||
|
||||
handles.push(handle);
|
||||
}
|
||||
handles.push(handle);
|
||||
}
|
||||
// Return as soon as any one succeeds
|
||||
let (tx, mut rx) = mpsc::channel(handles.len());
|
||||
let (tx, mut rx) = mpsc::channel(swqos_clients.len());
|
||||
|
||||
// Start monitoring tasks
|
||||
for handle in handles {
|
||||
|
||||
+12
-12
@@ -1,9 +1,9 @@
|
||||
use super::traits::ProtocolParams;
|
||||
use crate::common::bonding_curve::BondingCurveAccount;
|
||||
use crate::common::SolanaRpcClient;
|
||||
use crate::common::{PriorityFee, SolanaRpcClient};
|
||||
use crate::solana_streamer_sdk::streaming::event_parser::common::EventType;
|
||||
use crate::solana_streamer_sdk::streaming::event_parser::protocols::bonk::BonkTradeEvent;
|
||||
use crate::swqos::settings::SwqosSettings;
|
||||
use crate::swqos::SwqosClient;
|
||||
use crate::trading::common::get_multi_token_balances;
|
||||
use crate::trading::MiddlewareManager;
|
||||
use solana_hash::Hash;
|
||||
@@ -18,56 +18,56 @@ use spl_associated_token_account::get_associated_token_address;
|
||||
use std::sync::Arc;
|
||||
/// Buy parameters
|
||||
#[derive(Clone)]
|
||||
pub struct InternalBuyParams {
|
||||
pub struct BuyParams {
|
||||
pub rpc: Option<Arc<SolanaRpcClient>>,
|
||||
pub payer: Arc<Keypair>,
|
||||
pub mint: Pubkey,
|
||||
pub sol_amount: u64,
|
||||
pub slippage_basis_points: Option<u64>,
|
||||
pub priority_fee: Arc<PriorityFee>,
|
||||
pub lookup_table_key: Option<Pubkey>,
|
||||
pub recent_blockhash: Hash,
|
||||
pub data_size_limit: u32,
|
||||
pub wait_transaction_confirmed: bool,
|
||||
pub protocol_params: Box<dyn ProtocolParams>,
|
||||
pub open_seed_optimize: bool,
|
||||
pub swqos_settings: Vec<Arc<SwqosSettings>>,
|
||||
pub swqos_clients: Vec<Arc<SwqosClient>>,
|
||||
pub middleware_manager: Option<Arc<MiddlewareManager>>,
|
||||
pub create_wsol_ata: bool,
|
||||
pub close_wsol_ata: bool,
|
||||
pub create_mint_ata: bool,
|
||||
pub custom_cu_limit: Option<u32>,
|
||||
}
|
||||
|
||||
/// Sell parameters
|
||||
#[derive(Clone)]
|
||||
pub struct InternalSellParams {
|
||||
pub struct SellParams {
|
||||
pub rpc: Option<Arc<SolanaRpcClient>>,
|
||||
pub payer: Arc<Keypair>,
|
||||
pub mint: Pubkey,
|
||||
pub token_amount: Option<u64>,
|
||||
pub slippage_basis_points: Option<u64>,
|
||||
pub priority_fee: Arc<PriorityFee>,
|
||||
pub lookup_table_key: Option<Pubkey>,
|
||||
pub recent_blockhash: Hash,
|
||||
pub wait_transaction_confirmed: bool,
|
||||
pub with_tip: bool,
|
||||
pub protocol_params: Box<dyn ProtocolParams>,
|
||||
pub open_seed_optimize: bool,
|
||||
pub swqos_settings: Vec<Arc<SwqosSettings>>,
|
||||
pub swqos_clients: Vec<Arc<SwqosClient>>,
|
||||
pub middleware_manager: Option<Arc<MiddlewareManager>>,
|
||||
pub create_wsol_ata: bool,
|
||||
pub close_wsol_ata: bool,
|
||||
pub custom_cu_limit: Option<u32>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for InternalBuyParams {
|
||||
impl std::fmt::Debug for BuyParams {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "InternalBuyParams: {:?}", self)
|
||||
write!(f, "BuyParams: {:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for InternalSellParams {
|
||||
impl std::fmt::Debug for SellParams {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "InternalSellParams: {:?}", self)
|
||||
write!(f, "SellParams: {:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::params::{InternalBuyParams, InternalSellParams};
|
||||
use super::params::{BuyParams, SellParams};
|
||||
use anyhow::Result;
|
||||
use solana_sdk::{instruction::Instruction, signature::Signature};
|
||||
|
||||
@@ -6,9 +6,9 @@ use solana_sdk::{instruction::Instruction, signature::Signature};
|
||||
#[async_trait::async_trait]
|
||||
pub trait TradeExecutor: Send + Sync {
|
||||
/// 使用MEV服务执行买入交易
|
||||
async fn buy_with_tip(&self, params: InternalBuyParams) -> Result<Signature>;
|
||||
async fn buy_with_tip(&self, params: BuyParams) -> Result<Signature>;
|
||||
/// 使用MEV服务执行卖出交易
|
||||
async fn sell_with_tip(&self, params: InternalSellParams) -> Result<Signature>;
|
||||
async fn sell_with_tip(&self, params: SellParams) -> Result<Signature>;
|
||||
/// 获取协议名称
|
||||
fn protocol_name(&self) -> &'static str;
|
||||
}
|
||||
@@ -17,10 +17,10 @@ pub trait TradeExecutor: Send + Sync {
|
||||
#[async_trait::async_trait]
|
||||
pub trait InstructionBuilder: Send + Sync {
|
||||
/// 构建买入指令
|
||||
async fn build_buy_instructions(&self, params: &InternalBuyParams) -> Result<Vec<Instruction>>;
|
||||
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>>;
|
||||
|
||||
/// 构建卖出指令
|
||||
async fn build_sell_instructions(&self, params: &InternalSellParams) -> Result<Vec<Instruction>>;
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>>;
|
||||
}
|
||||
|
||||
/// 协议特定参数trait - 允许每个协议定义自己的参数
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ pub mod core;
|
||||
pub mod factory;
|
||||
pub mod middleware;
|
||||
|
||||
pub use core::params::{InternalBuyParams, InternalSellParams};
|
||||
pub use core::params::{BuyParams, SellParams};
|
||||
pub use core::traits::{InstructionBuilder, TradeExecutor};
|
||||
pub use factory::TradeFactory;
|
||||
pub use middleware::{InstructionMiddleware, MiddlewareManager};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
pub mod calc;
|
||||
pub mod price;
|
||||
|
||||
use crate::solana_streamer_sdk::streaming::event_parser::protocols::pumpfun::PumpFunTradeEvent;
|
||||
use crate::trading;
|
||||
use crate::SolanaTrade;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
@@ -55,4 +57,107 @@ impl SolanaTrade {
|
||||
pub async fn close_token_account(&self, mint: &Pubkey) -> Result<(), anyhow::Error> {
|
||||
trading::common::utils::close_token_account(&self.rpc, self.payer.as_ref(), mint).await
|
||||
}
|
||||
|
||||
// -------------------------------- PumpFun --------------------------------
|
||||
|
||||
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
|
||||
#[inline]
|
||||
pub fn get_pumpfun_token_buy_price(&self, amount: u64, trade_info: &PumpFunTradeEvent) -> u64 {
|
||||
crate::instruction::utils::pumpfun::get_buy_price(amount, trade_info)
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
|
||||
#[inline]
|
||||
pub async fn get_pumpfun_token_current_price(
|
||||
&self,
|
||||
mint: &Pubkey,
|
||||
) -> Result<f64, anyhow::Error> {
|
||||
let (bonding_curve, _) =
|
||||
crate::instruction::utils::pumpfun::fetch_bonding_curve_account(&self.rpc, mint)
|
||||
.await?;
|
||||
|
||||
let virtual_sol_reserves = bonding_curve.virtual_sol_reserves;
|
||||
let virtual_token_reserves = bonding_curve.virtual_token_reserves;
|
||||
|
||||
Ok(price::pumpfun::price_token_in_sol(virtual_sol_reserves, virtual_token_reserves))
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
|
||||
#[inline]
|
||||
pub async fn get_pumpfun_token_real_sol_reserves(
|
||||
&self,
|
||||
mint: &Pubkey,
|
||||
) -> Result<u64, anyhow::Error> {
|
||||
let (bonding_curve, _) =
|
||||
crate::instruction::utils::pumpfun::fetch_bonding_curve_account(&self.rpc, mint)
|
||||
.await?;
|
||||
|
||||
let actual_sol_reserves = bonding_curve.real_sol_reserves;
|
||||
|
||||
Ok(actual_sol_reserves)
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
|
||||
#[inline]
|
||||
pub async fn get_pumpfun_token_creator(&self, mint: &Pubkey) -> Result<Pubkey, anyhow::Error> {
|
||||
let (bonding_curve, _) =
|
||||
crate::instruction::utils::pumpfun::fetch_bonding_curve_account(&self.rpc, mint)
|
||||
.await?;
|
||||
|
||||
let creator = bonding_curve.creator;
|
||||
|
||||
Ok(creator)
|
||||
}
|
||||
|
||||
// -------------------------------- PumpSwap --------------------------------
|
||||
|
||||
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
|
||||
#[inline]
|
||||
pub async fn get_pumpswap_token_current_price(
|
||||
&self,
|
||||
pool_address: &Pubkey,
|
||||
) -> Result<f64, anyhow::Error> {
|
||||
let pool = crate::instruction::utils::pumpswap::fetch_pool(&self.rpc, pool_address).await?;
|
||||
|
||||
let (base_amount, quote_amount) =
|
||||
crate::instruction::utils::pumpswap::get_token_balances(&pool, &self.rpc).await?;
|
||||
|
||||
// Calculate price using constant product formula (x * y = k)
|
||||
// Price = quote_amount / base_amount
|
||||
if base_amount == 0 {
|
||||
return Err(anyhow::anyhow!("Base amount is zero, cannot calculate price"));
|
||||
}
|
||||
|
||||
let price = quote_amount as f64 / base_amount as f64;
|
||||
|
||||
Ok(price)
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
|
||||
#[inline]
|
||||
pub async fn get_pumpswap_token_real_sol_reserves(
|
||||
&self,
|
||||
pool_address: &Pubkey,
|
||||
) -> Result<u64, anyhow::Error> {
|
||||
let pool = crate::instruction::utils::pumpswap::fetch_pool(&self.rpc, pool_address).await?;
|
||||
|
||||
let (_, quote_amount) =
|
||||
crate::instruction::utils::pumpswap::get_token_balances(&pool, &self.rpc).await?;
|
||||
|
||||
Ok(quote_amount)
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.6.7", note = "This function is deprecated and will be removed in a future version")]
|
||||
#[inline]
|
||||
pub async fn get_pumpswap_payer_token_balance(
|
||||
&self,
|
||||
pool_address: &Pubkey,
|
||||
) -> Result<u64, anyhow::Error> {
|
||||
let pool = crate::instruction::utils::pumpswap::fetch_pool(&self.rpc, pool_address).await?;
|
||||
|
||||
let (base_amount, _) =
|
||||
crate::instruction::utils::pumpswap::get_token_balances(&pool, &self.rpc).await?;
|
||||
|
||||
Ok(base_amount)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user