9f79e865ab
P0: - blockhash/nonce: get_transaction_blockhash returns Result; buy/sell entry validation - Bonk sell: remove RPC get_token_balance from build path; require caller to pass input_amount - Hot path: drop redundant dex_type/protocol_params clone; tip via sol_f64_to_lamports (no String) - compute_budget cache uses Arc; extend_compute_budget_instructions avoids SmallVec clone P1: - middleware protocol_name takes &str; executor destructures result once to avoid signatures/submit_timings clone - Error messages include dex context; params use Copy for Pubkey; pumpswap utils clone only Pool for pools[0] P2: - transaction_pool capacity constants; TIP_ACCOUNT_CACHE marked allow(dead_code) - Fix error copy in raydium_amm_v4 / meteora_damm_v2 to correct protocol names Made-with: Cursor
116 lines
3.3 KiB
Rust
116 lines
3.3 KiB
Rust
use anyhow::Result;
|
|
use solana_sdk::instruction::Instruction;
|
|
|
|
/// Instruction middleware trait
|
|
///
|
|
/// Used to modify, add or remove protocol_instructions before transaction execution
|
|
pub trait InstructionMiddleware: Send + Sync {
|
|
/// Middleware name
|
|
fn name(&self) -> &'static str;
|
|
|
|
/// Core method for processing protocol_instructions
|
|
///
|
|
/// # Arguments
|
|
/// * `protocol_instructions` - Current instruction list
|
|
/// * `protocol_name` - Protocol name
|
|
/// * `is_buy` - Whether the transaction is a buy transaction
|
|
///
|
|
/// # Returns
|
|
/// Returns modified instruction list
|
|
fn process_protocol_instructions(
|
|
&self,
|
|
protocol_instructions: Vec<Instruction>,
|
|
protocol_name: &str,
|
|
is_buy: bool,
|
|
) -> Result<Vec<Instruction>>;
|
|
|
|
/// Core method for processing full_instructions
|
|
///
|
|
/// # Arguments
|
|
/// * `full_instructions` - Current instruction list
|
|
/// * `protocol_name` - Protocol name
|
|
/// * `is_buy` - Whether the transaction is a buy transaction
|
|
///
|
|
/// # Returns
|
|
/// Returns modified instruction list
|
|
fn process_full_instructions(
|
|
&self,
|
|
full_instructions: Vec<Instruction>,
|
|
protocol_name: &str,
|
|
is_buy: bool,
|
|
) -> Result<Vec<Instruction>>;
|
|
|
|
/// Clone middleware
|
|
fn clone_box(&self) -> Box<dyn InstructionMiddleware>;
|
|
}
|
|
|
|
/// Middleware manager
|
|
pub struct MiddlewareManager {
|
|
middlewares: Vec<Box<dyn InstructionMiddleware>>,
|
|
}
|
|
|
|
impl Clone for MiddlewareManager {
|
|
fn clone(&self) -> Self {
|
|
Self {
|
|
middlewares: self.middlewares.iter().map(|middleware| middleware.clone_box()).collect(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl MiddlewareManager {
|
|
/// Create new middleware manager
|
|
pub fn new() -> Self {
|
|
Self { middlewares: Vec::new() }
|
|
}
|
|
|
|
/// Add middleware
|
|
pub fn add_middleware(mut self, middleware: Box<dyn InstructionMiddleware>) -> Self {
|
|
self.middlewares.push(middleware);
|
|
self
|
|
}
|
|
|
|
pub fn apply_middlewares_process_full_instructions(
|
|
&self,
|
|
mut full_instructions: Vec<Instruction>,
|
|
protocol_name: &str,
|
|
is_buy: bool,
|
|
) -> Result<Vec<Instruction>> {
|
|
for middleware in &self.middlewares {
|
|
full_instructions = middleware.process_full_instructions(
|
|
full_instructions,
|
|
protocol_name,
|
|
is_buy,
|
|
)?;
|
|
if full_instructions.is_empty() {
|
|
break;
|
|
}
|
|
}
|
|
Ok(full_instructions)
|
|
}
|
|
|
|
/// Apply all middlewares to process protocol_instructions
|
|
pub fn apply_middlewares_process_protocol_instructions(
|
|
&self,
|
|
mut protocol_instructions: Vec<Instruction>,
|
|
protocol_name: &str,
|
|
is_buy: bool,
|
|
) -> Result<Vec<Instruction>> {
|
|
for middleware in &self.middlewares {
|
|
protocol_instructions = middleware.process_protocol_instructions(
|
|
protocol_instructions,
|
|
protocol_name,
|
|
is_buy,
|
|
)?;
|
|
if protocol_instructions.is_empty() {
|
|
break;
|
|
}
|
|
}
|
|
Ok(protocol_instructions)
|
|
}
|
|
|
|
/// Create manager with common middlewares
|
|
pub fn with_common_middlewares() -> Self {
|
|
Self::new().add_middleware(Box::new(crate::trading::middleware::builtin::LoggingMiddleware))
|
|
}
|
|
}
|