feat: add examples and enhance MEV protection services

This commit adds comprehensive examples for various trading operations including:
- PumpFun copy and sniper trading
- Bonk copy and sniper trading
- PumpSwap trading
- Raydium CPMM and AMM V4 trading
- Middleware system demonstration
- Event subscription

Enhanced MEV protection services with FlashBlock and Node1 integration.
Updated instruction modules for bonk, pumpswap, and raydium_cpmm.
Improved SWQOS modules for better transaction handling.
This commit is contained in:
ysq
2025-08-25 00:21:15 +08:00
parent 90ea46ea3f
commit c10406915c
36 changed files with 2049 additions and 1562 deletions
+31 -11
View File
@@ -117,7 +117,7 @@ impl BonkInstructionBuilder {
&params.payer.pubkey(),
&params.payer.pubkey(),
&params.mint,
&accounts::TOKEN_PROGRAM,
&protocol_params.mint_token_program,
));
// Create buy instruction
@@ -125,7 +125,10 @@ impl BonkInstructionBuilder {
solana_sdk::instruction::AccountMeta::new(params.payer.pubkey(), true), // Payer (signer)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::AUTHORITY, false), // Authority (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::GLOBAL_CONFIG, false), // Global Config (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(protocol_params.platform_onfig, false), // Platform Config (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(
protocol_params.platform_onfig,
false,
), // Platform Config (readonly)
solana_sdk::instruction::AccountMeta::new(pool_state, false), // Pool State
solana_sdk::instruction::AccountMeta::new(user_base_token_account, false), // User Base Token
solana_sdk::instruction::AccountMeta::new(user_quote_token_account, false), // User Quote Token
@@ -141,8 +144,14 @@ impl BonkInstructionBuilder {
solana_sdk::instruction::AccountMeta::new_readonly(accounts::EVENT_AUTHORITY, false), // Event Authority (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::BONK, false), // Program (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::SYSTEM_PROGRAM, false), // System Program (readonly)
solana_sdk::instruction::AccountMeta::new(protocol_params.platform_associated_account, false), // Platform Associated Account
solana_sdk::instruction::AccountMeta::new(protocol_params.creator_associated_account, false), // Creator Associated Account
solana_sdk::instruction::AccountMeta::new(
protocol_params.platform_associated_account,
false,
), // Platform Associated Account
solana_sdk::instruction::AccountMeta::new(
protocol_params.creator_associated_account,
false,
), // Creator Associated Account
];
// Create instruction data
let mut data = vec![];
@@ -218,10 +227,12 @@ impl BonkInstructionBuilder {
);
// Create user token accounts
let user_base_token_account = spl_associated_token_account::get_associated_token_address(
&params.payer.pubkey(),
&params.mint,
);
let user_base_token_account =
spl_associated_token_account::get_associated_token_address_with_program_id(
&params.payer.pubkey(),
&params.mint,
&protocol_params.mint_token_program,
);
let user_quote_token_account = spl_associated_token_account::get_associated_token_address(
&params.payer.pubkey(),
&accounts::WSOL_TOKEN_ACCOUNT,
@@ -252,7 +263,10 @@ impl BonkInstructionBuilder {
solana_sdk::instruction::AccountMeta::new(params.payer.pubkey(), true), // Payer (signer)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::AUTHORITY, false), // Authority (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::GLOBAL_CONFIG, false), // Global Config (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(protocol_params.platform_onfig, false), // Platform Config (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(
protocol_params.platform_onfig,
false,
), // Platform Config (readonly)
solana_sdk::instruction::AccountMeta::new(pool_state, false), // Pool State
solana_sdk::instruction::AccountMeta::new(user_base_token_account, false), // User Base Token
solana_sdk::instruction::AccountMeta::new(user_quote_token_account, false), // User Quote Token
@@ -268,8 +282,14 @@ impl BonkInstructionBuilder {
solana_sdk::instruction::AccountMeta::new_readonly(accounts::EVENT_AUTHORITY, false), // Event Authority (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::BONK, false), // Program (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::SYSTEM_PROGRAM, false), // System Program (readonly)
solana_sdk::instruction::AccountMeta::new(protocol_params.platform_associated_account, false), // Platform Associated Account
solana_sdk::instruction::AccountMeta::new(protocol_params.creator_associated_account, false), // Creator Associated Account
solana_sdk::instruction::AccountMeta::new(
protocol_params.platform_associated_account,
false,
), // Platform Associated Account
solana_sdk::instruction::AccountMeta::new(
protocol_params.creator_associated_account,
false,
), // Creator Associated Account
];
// Create instruction data
+48 -26
View File
@@ -57,6 +57,8 @@ impl InstructionBuilder for PumpSwapInstructionBuilder {
coin_creator_vault_ata,
coin_creator_vault_authority,
protocol_params.auto_handle_wsol,
protocol_params.base_token_program,
protocol_params.quote_token_program,
)
.await
}
@@ -86,6 +88,8 @@ impl InstructionBuilder for PumpSwapInstructionBuilder {
coin_creator_vault_ata,
coin_creator_vault_authority,
protocol_params.auto_handle_wsol,
protocol_params.base_token_program,
protocol_params.quote_token_program,
)
.await
}
@@ -104,7 +108,12 @@ impl PumpSwapInstructionBuilder {
params_coin_creator_vault_ata: Pubkey,
params_coin_creator_vault_authority: Pubkey,
auto_handle_wsol: bool,
base_token_program: Pubkey,
quote_token_program: Pubkey,
) -> Result<Vec<Instruction>> {
if base_mint != accounts::WSOL_TOKEN_ACCOUNT && quote_mint != accounts::WSOL_TOKEN_ACCOUNT {
return Err(anyhow!("Invalid base mint and quote mint"));
}
if params.rpc.is_none() {
return Err(anyhow!("RPC is not set"));
}
@@ -147,28 +156,32 @@ impl PumpSwapInstructionBuilder {
}
// Create user token accounts
let user_base_token_account = spl_associated_token_account::get_associated_token_address(
&params.payer.pubkey(),
&base_mint,
);
let user_quote_token_account = spl_associated_token_account::get_associated_token_address(
&params.payer.pubkey(),
&quote_mint,
);
let user_base_token_account =
spl_associated_token_account::get_associated_token_address_with_program_id(
&params.payer.pubkey(),
&base_mint,
&base_token_program,
);
let user_quote_token_account =
spl_associated_token_account::get_associated_token_address_with_program_id(
&params.payer.pubkey(),
&quote_mint,
&quote_token_program,
);
// Get pool token accounts
let pool_base_token_account =
spl_associated_token_account::get_associated_token_address_with_program_id(
&pool,
&base_mint,
&accounts::TOKEN_PROGRAM,
&base_token_program,
);
let pool_quote_token_account =
spl_associated_token_account::get_associated_token_address_with_program_id(
&pool,
&quote_mint,
&accounts::TOKEN_PROGRAM,
&quote_token_program,
);
let mut instructions = vec![];
@@ -216,7 +229,7 @@ impl PumpSwapInstructionBuilder {
&params.payer.pubkey(),
&params.payer.pubkey(),
if quote_mint_is_wsol { &base_mint } else { &quote_mint },
&accounts::TOKEN_PROGRAM,
if quote_mint_is_wsol { &base_token_program } else { &quote_token_program },
));
let fee_recipient_ata = fee_recipient_ata(accounts::FEE_RECIPIENT, quote_mint);
@@ -234,8 +247,8 @@ impl PumpSwapInstructionBuilder {
solana_sdk::instruction::AccountMeta::new(pool_quote_token_account, false), // pool_quote_token_account
solana_sdk::instruction::AccountMeta::new_readonly(accounts::FEE_RECIPIENT, false), // fee_recipient (readonly)
solana_sdk::instruction::AccountMeta::new(fee_recipient_ata, false), // fee_recipient_ata
solana_sdk::instruction::AccountMeta::new_readonly(accounts::TOKEN_PROGRAM, false), // TOKEN_PROGRAM_ID (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::TOKEN_PROGRAM, false), // TOKEN_PROGRAM_ID (readonly, duplicated as in JS)
solana_sdk::instruction::AccountMeta::new_readonly(base_token_program, false), // TOKEN_PROGRAM_ID (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(quote_token_program, false), // TOKEN_PROGRAM_ID (readonly, duplicated as in JS)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::SYSTEM_PROGRAM, false), // System Program (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(
accounts::ASSOCIATED_TOKEN_PROGRAM,
@@ -309,7 +322,12 @@ impl PumpSwapInstructionBuilder {
params_coin_creator_vault_ata: Pubkey,
params_coin_creator_vault_authority: Pubkey,
auto_handle_wsol: bool,
base_token_program: Pubkey,
quote_token_program: Pubkey,
) -> Result<Vec<Instruction>> {
if base_mint != accounts::WSOL_TOKEN_ACCOUNT && quote_mint != accounts::WSOL_TOKEN_ACCOUNT {
return Err(anyhow!("Invalid base mint and quote mint"));
}
if params.rpc.is_none() {
return Err(anyhow!("RPC is not set"));
}
@@ -358,25 +376,29 @@ impl PumpSwapInstructionBuilder {
let fee_recipient_ata = fee_recipient_ata(accounts::FEE_RECIPIENT, quote_mint);
let user_base_token_account = spl_associated_token_account::get_associated_token_address(
&params.payer.pubkey(),
&base_mint,
);
let user_quote_token_account = spl_associated_token_account::get_associated_token_address(
&params.payer.pubkey(),
&quote_mint,
);
let user_base_token_account =
spl_associated_token_account::get_associated_token_address_with_program_id(
&params.payer.pubkey(),
&base_mint,
&base_token_program,
);
let user_quote_token_account =
spl_associated_token_account::get_associated_token_address_with_program_id(
&params.payer.pubkey(),
&quote_mint,
&quote_token_program,
);
let pool_base_token_account =
spl_associated_token_account::get_associated_token_address_with_program_id(
&pool,
&base_mint,
&accounts::TOKEN_PROGRAM,
&base_token_program,
);
let pool_quote_token_account =
spl_associated_token_account::get_associated_token_address_with_program_id(
&pool,
&quote_mint,
&accounts::TOKEN_PROGRAM,
&quote_token_program,
);
let mut instructions = vec![];
@@ -397,7 +419,7 @@ impl PumpSwapInstructionBuilder {
&params.payer.pubkey(),
&params.payer.pubkey(),
if quote_mint_is_wsol { &base_mint } else { &quote_mint },
&accounts::TOKEN_PROGRAM,
if quote_mint_is_wsol { &base_token_program } else { &quote_token_program },
));
// Create sell instruction
@@ -413,8 +435,8 @@ impl PumpSwapInstructionBuilder {
solana_sdk::instruction::AccountMeta::new(pool_quote_token_account, false), // pool_quote_token_account
solana_sdk::instruction::AccountMeta::new_readonly(accounts::FEE_RECIPIENT, false), // fee_recipient (readonly)
solana_sdk::instruction::AccountMeta::new(fee_recipient_ata, false), // fee_recipient_ata
solana_sdk::instruction::AccountMeta::new_readonly(accounts::TOKEN_PROGRAM, false), // TOKEN_PROGRAM_ID (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::TOKEN_PROGRAM, false), // TOKEN_PROGRAM_ID (readonly, duplicated as in JS)
solana_sdk::instruction::AccountMeta::new_readonly(base_token_program, false), // TOKEN_PROGRAM_ID (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(quote_token_program, false), // TOKEN_PROGRAM_ID (readonly, duplicated as in JS)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::SYSTEM_PROGRAM, false), // System Program (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(
accounts::ASSOCIATED_TOKEN_PROGRAM,
+24 -21
View File
@@ -55,21 +55,29 @@ impl RaydiumCpmmInstructionBuilder {
)
.unwrap();
let is_base_in = protocol_params.base_mint == accounts::WSOL_TOKEN_ACCOUNT;
let mint_token_program = if is_base_in {
protocol_params.quote_token_program
} else {
protocol_params.base_token_program
};
let wsol_token_account = spl_associated_token_account::get_associated_token_address(
&params.payer.pubkey(),
&accounts::WSOL_TOKEN_ACCOUNT,
);
let mint_token_account = spl_associated_token_account::get_associated_token_address(
&params.payer.pubkey(),
&params.mint,
);
let mint_token_account =
spl_associated_token_account::get_associated_token_address_with_program_id(
&params.payer.pubkey(),
&params.mint,
&mint_token_program,
);
// Get pool token accounts
let wsol_vault_account = get_vault_pda(&pool_state, &accounts::WSOL_TOKEN_ACCOUNT).unwrap();
let mint_vault_account = get_vault_pda(&pool_state, &params.mint).unwrap();
let observation_state_account = get_observation_state_pda(&pool_state).unwrap();
let is_base_in = protocol_params.base_mint == accounts::WSOL_TOKEN_ACCOUNT;
let amount_in: u64 = params.sol_amount;
let result = compute_swap_amount(
@@ -106,12 +114,6 @@ impl RaydiumCpmmInstructionBuilder {
);
}
let mint_token_program = if is_base_in {
protocol_params.quote_token_program
} else {
protocol_params.base_token_program
};
instructions.push(create_associated_token_account_idempotent(
&params.payer.pubkey(),
&params.payer.pubkey(),
@@ -176,6 +178,11 @@ impl RaydiumCpmmInstructionBuilder {
}
let is_base_in = protocol_params.base_mint == params.mint;
let mint_token_program = if is_base_in {
protocol_params.base_token_program
} else {
protocol_params.quote_token_program
};
let minimum_amount_out: u64 = compute_swap_amount(
protocol_params.base_reserve,
@@ -197,10 +204,12 @@ impl RaydiumCpmmInstructionBuilder {
&params.payer.pubkey(),
&accounts::WSOL_TOKEN_ACCOUNT,
);
let mint_token_account = spl_associated_token_account::get_associated_token_address(
&params.payer.pubkey(),
&params.mint,
);
let mint_token_account =
spl_associated_token_account::get_associated_token_address_with_program_id(
&params.payer.pubkey(),
&params.mint,
&mint_token_program,
);
// Get pool token accounts
let wsol_vault_account = get_vault_pda(&pool_state, &accounts::WSOL_TOKEN_ACCOUNT).unwrap();
@@ -221,12 +230,6 @@ impl RaydiumCpmmInstructionBuilder {
),
);
let mint_token_program = if is_base_in {
protocol_params.base_token_program
} else {
protocol_params.quote_token_program
};
// Create sell instruction
let accounts = vec![
solana_sdk::instruction::AccountMeta::new(params.payer.pubkey(), true), // Payer (signer)
+4 -1
View File
@@ -92,7 +92,10 @@ impl BloxrouteClient {
let start_time: Instant = Instant::now();
match poll_transaction_confirmation(&self.rpc_client, signature).await {
Ok(_) => (),
Err(_) => (),
Err(e) => {
println!(" bloxroute{}确认失败: {:?}", trade_type, start_time.elapsed());
return Err(e);
},
}
println!(" bloxroute{}确认: {:?}", trade_type, start_time.elapsed());
+4 -1
View File
@@ -92,7 +92,10 @@ impl FlashBlockClient {
let start_time: Instant = Instant::now();
match poll_transaction_confirmation(&self.rpc_client, signature).await {
Ok(_) => (),
Err(_) => (),
Err(e) => {
println!(" FlashBlock{}确认失败: {:?}", trade_type, start_time.elapsed());
return Err(e);
},
}
println!(" FlashBlock{}确认: {:?}", trade_type, start_time.elapsed());
+4 -1
View File
@@ -108,7 +108,10 @@ impl JitoClient {
let start_time: Instant = Instant::now();
match poll_transaction_confirmation(&self.rpc_client, signature).await {
Ok(_) => (),
Err(_) => (),
Err(e) => {
println!(" jito{}确认失败: {:?}", trade_type, start_time.elapsed());
return Err(e);
},
}
println!(" jito{}确认: {:?}", trade_type, start_time.elapsed());
+4 -1
View File
@@ -89,7 +89,10 @@ impl NextBlockClient {
let start_time: Instant = Instant::now();
match poll_transaction_confirmation(&self.rpc_client, signature).await {
Ok(_) => (),
Err(_) => (),
Err(e) => {
println!(" nextblock{}确认失败: {:?}", trade_type, start_time.elapsed());
return Err(e);
},
}
println!(" nextblock{}确认: {:?}", trade_type, start_time.elapsed());
+4 -1
View File
@@ -177,7 +177,10 @@ impl Node1Client {
let start_time: Instant = Instant::now();
match poll_transaction_confirmation(&self.rpc_client, signature).await {
Ok(_) => (),
Err(_) => (),
Err(e) => {
println!(" node1{}确认失败: {:?}", trade_type, start_time.elapsed());
return Err(e);
},
}
println!(" node1{}确认: {:?}", trade_type, start_time.elapsed());
+4 -1
View File
@@ -30,7 +30,10 @@ impl SwqosClientTrait for SolRpcClient {
let start_time = Instant::now();
match poll_transaction_confirmation(&self.rpc_client, signature).await {
Ok(_) => (),
Err(_) => (),
Err(e) => {
println!(" rpc{}确认失败: {:?}", trade_type, start_time.elapsed());
return Err(e);
},
}
println!(" signature: {:?}", signature);
println!(" rpc{}确认: {:?}", trade_type, start_time.elapsed());
+4 -1
View File
@@ -98,7 +98,10 @@ impl TemporalClient {
let start_time: Instant = Instant::now();
match poll_transaction_confirmation(&self.rpc_client, signature).await {
Ok(_) => (),
Err(_) => (),
Err(e) => {
println!(" nozomi{}确认失败: {:?}", trade_type, start_time.elapsed());
return Err(e);
},
}
println!(" nozomi{}确认: {:?}", trade_type, start_time.elapsed());
+4 -1
View File
@@ -99,7 +99,10 @@ impl ZeroSlotClient {
let start_time: Instant = Instant::now();
match poll_transaction_confirmation(&self.rpc_client, signature).await {
Ok(_) => (),
Err(_) => (),
Err(e) => {
println!(" 0slot{}确认失败: {:?}", trade_type, start_time.elapsed());
return Err(e);
},
}
println!(" 0slot{}确认: {:?}", trade_type, start_time.elapsed());
+32
View File
@@ -179,6 +179,10 @@ pub struct PumpSwapParams {
pub coin_creator_vault_ata: Pubkey,
/// Coin creator vault authority
pub coin_creator_vault_authority: Pubkey,
/// Token program ID
pub base_token_program: Pubkey,
/// Quote token program ID
pub quote_token_program: Pubkey,
/// Automatically handle WSOL wrapping
/// When true, automatically handles wrapping and unwrapping operations between SOL and WSOL
pub auto_handle_wsol: bool,
@@ -194,6 +198,8 @@ impl PumpSwapParams {
pool_quote_token_reserves: event.pool_quote_token_reserves,
coin_creator_vault_ata: event.coin_creator_vault_ata,
coin_creator_vault_authority: event.coin_creator_vault_authority,
base_token_program: event.base_token_program,
quote_token_program: event.quote_token_program,
auto_handle_wsol: true,
}
}
@@ -207,6 +213,8 @@ impl PumpSwapParams {
pool_quote_token_reserves: event.pool_quote_token_reserves,
coin_creator_vault_ata: event.coin_creator_vault_ata,
coin_creator_vault_authority: event.coin_creator_vault_authority,
base_token_program: event.base_token_program,
quote_token_program: event.quote_token_program,
auto_handle_wsol: true,
}
}
@@ -221,6 +229,20 @@ impl PumpSwapParams {
let creator = pool_data.creator;
let coin_creator_vault_ata = coin_creator_vault_ata(creator, pool_data.quote_mint);
let coin_creator_vault_authority = coin_creator_vault_authority(creator);
let base_token_program_ata =
spl_associated_token_account::get_associated_token_address_with_program_id(
&pool_address,
&pool_data.base_mint,
&accounts::TOKEN_PROGRAM,
);
let quote_token_program_ata =
spl_associated_token_account::get_associated_token_address_with_program_id(
&pool_address,
&pool_data.quote_mint,
&accounts::TOKEN_PROGRAM,
);
Ok(Self {
pool: pool_address.clone(),
base_mint: pool_data.base_mint,
@@ -229,6 +251,16 @@ impl PumpSwapParams {
pool_quote_token_reserves: pool_quote_token_reserves,
coin_creator_vault_ata: coin_creator_vault_ata,
coin_creator_vault_authority: coin_creator_vault_authority,
base_token_program: if pool_data.pool_base_token_account == base_token_program_ata {
accounts::TOKEN_PROGRAM
} else {
spl_token_2022::ID
},
quote_token_program: if pool_data.pool_quote_token_account == quote_token_program_ata {
accounts::TOKEN_PROGRAM
} else {
spl_token_2022::ID
},
auto_handle_wsol: true,
})
}