Buy and sell according to the trading platform

This commit is contained in:
周威威
2025-06-10 19:39:06 +08:00
parent a3859edf86
commit 6f819be4e0
7 changed files with 227 additions and 90 deletions
+13
View File
@@ -1,2 +1,15 @@
pub mod pumpfun; pub mod pumpfun;
pub mod pumpswap; pub mod pumpswap;
pub mod trade_type {
pub const COPY_BUY: &'static str = "copy_buy";
pub const COPY_SELL: &'static str = "copy_sell";
pub const SNIPER_BUY: &'static str = "sniper_buy";
pub const SNIPER_SELL: &'static str = "sniper_sell";
}
pub mod trade_platform {
pub const PUMPFUN: &'static str = "pumpfun";
pub const PUMPFUN_SWAP: &'static str = "pumpswap";
pub const RAYDIUM: &'static str = "raydium";
}
-7
View File
@@ -173,10 +173,3 @@ impl Symbol {
pub const SOLANA: &'static str = "solana"; pub const SOLANA: &'static str = "solana";
} }
pub mod trade_type {
pub const COPY_BUY: &'static str = "copy_buy";
pub const COPY_SELL: &'static str = "copy_sell";
pub const SNIPER_BUY: &'static str = "sniper_buy";
pub const SNIPER_SELL: &'static str = "sniper_sell";
}
+166 -71
View File
@@ -7,6 +7,7 @@ pub mod common;
pub mod ipfs; pub mod ipfs;
pub mod swqos; pub mod swqos;
pub mod pumpfun; pub mod pumpfun;
pub mod pumpswap;
use std::sync::Arc; use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
@@ -24,7 +25,8 @@ use common::{pumpfun::logs_data::TradeInfo, pumpfun::logs_events::PumpfunEvent,
use common::pumpfun::logs_subscribe::SubscriptionHandle; use common::pumpfun::logs_subscribe::SubscriptionHandle;
use ipfs::TokenMetadataIPFS; use ipfs::TokenMetadataIPFS;
use constants::pumpfun::trade_type::{COPY_BUY, SNIPER_BUY}; use constants::trade_type::{COPY_BUY, SNIPER_BUY};
use constants::trade_platform::{PUMPFUN, PUMPFUN_SWAP, RAYDIUM};
pub struct PumpFun { pub struct PumpFun {
pub payer: Arc<Keypair>, pub payer: Arc<Keypair>,
@@ -228,21 +230,36 @@ impl PumpFun {
buy_sol_cost: u64, buy_sol_cost: u64,
slippage_basis_points: Option<u64>, slippage_basis_points: Option<u64>,
recent_blockhash: Hash, recent_blockhash: Hash,
trade_platform: String,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
pumpfun::buy::buy( if trade_platform == PUMPFUN {
self.rpc.clone(), pumpfun::buy::buy(
self.payer.clone(), self.rpc.clone(),
mint, self.payer.clone(),
creator, mint,
dev_buy_token, creator,
dev_sol_cost, dev_buy_token,
buy_sol_cost, dev_sol_cost,
slippage_basis_points, buy_sol_cost,
self.priority_fee.clone(), slippage_basis_points,
self.cluster.clone().lookup_table_key, self.priority_fee.clone(),
recent_blockhash, self.cluster.clone().lookup_table_key,
COPY_BUY.to_string(), recent_blockhash,
).await COPY_BUY.to_string(),
).await
} else if trade_platform == PUMPFUN_SWAP {
pumpswap::buy::buy(
self.rpc.clone(),
self.payer.clone(),
mint,
buy_sol_cost,
slippage_basis_points,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
).await
} else {
Err(anyhow::anyhow!("Unsupported trade platform: {}", trade_platform))
}
} }
/// Buy tokens using Jito /// Buy tokens using Jito
@@ -281,21 +298,37 @@ impl PumpFun {
buy_sol_cost: u64, buy_sol_cost: u64,
slippage_basis_points: Option<u64>, slippage_basis_points: Option<u64>,
recent_blockhash: Hash, recent_blockhash: Hash,
trade_platform: String,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
pumpfun::buy::buy_with_tip( if trade_platform == PUMPFUN {
self.fee_clients.clone(), pumpfun::buy::buy_with_tip(
self.payer.clone(), self.fee_clients.clone(),
mint, self.payer.clone(),
creator, mint,
dev_buy_token, creator,
dev_sol_cost, dev_buy_token,
buy_sol_cost, dev_sol_cost,
slippage_basis_points, buy_sol_cost,
self.priority_fee.clone(), slippage_basis_points,
self.cluster.clone().lookup_table_key, self.priority_fee.clone(),
recent_blockhash, self.cluster.clone().lookup_table_key,
COPY_BUY.to_string(), recent_blockhash,
).await COPY_BUY.to_string(),
).await
} else if trade_platform == PUMPFUN_SWAP {
pumpswap::buy::buy_with_tip(
self.rpc.clone(),
self.fee_clients.clone(),
self.payer.clone(),
mint,
buy_sol_cost,
slippage_basis_points,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
).await
} else {
Err(anyhow::anyhow!("Unsupported trade platform: {}", trade_platform))
}
} }
/// Sell tokens /// Sell tokens
@@ -326,18 +359,33 @@ impl PumpFun {
percent: u64, percent: u64,
amount_token: u64, amount_token: u64,
recent_blockhash: Hash, recent_blockhash: Hash,
trade_platform: String,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
pumpfun::sell::sell_by_percent( if trade_platform == PUMPFUN {
self.rpc.clone(), pumpfun::sell::sell_by_percent(
self.payer.clone(), self.rpc.clone(),
mint.clone(), self.payer.clone(),
creator, mint.clone(),
percent, creator,
amount_token, percent,
self.priority_fee.clone(), amount_token,
self.cluster.clone().lookup_table_key, self.priority_fee.clone(),
recent_blockhash, self.cluster.clone().lookup_table_key,
).await recent_blockhash,
).await
} else if trade_platform == PUMPFUN_SWAP {
pumpswap::sell::sell_by_percent(
self.rpc.clone(),
self.payer.clone(),
mint.clone(),
percent,
None,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
).await
} else {
Err(anyhow::anyhow!("Unsupported trade platform: {}", trade_platform))
}
} }
/// Sell tokens by amount /// Sell tokens by amount
@@ -347,17 +395,32 @@ impl PumpFun {
creator: Pubkey, creator: Pubkey,
amount: u64, amount: u64,
recent_blockhash: Hash, recent_blockhash: Hash,
trade_platform: String,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
pumpfun::sell::sell_by_amount( if trade_platform == PUMPFUN {
self.rpc.clone(), pumpfun::sell::sell_by_amount(
self.payer.clone(), self.rpc.clone(),
mint.clone(), self.payer.clone(),
creator, mint.clone(),
amount, creator,
self.priority_fee.clone(), amount,
self.cluster.clone().lookup_table_key, self.priority_fee.clone(),
recent_blockhash, self.cluster.clone().lookup_table_key,
).await recent_blockhash,
).await
} else if trade_platform == PUMPFUN_SWAP {
pumpswap::sell::sell_by_amount(
self.rpc.clone(),
self.payer.clone(),
mint.clone(),
amount,
None,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
).await
} else {
Err(anyhow::anyhow!("Unsupported trade platform: {}", trade_platform))
}
} }
pub async fn sell_by_percent_with_tip( pub async fn sell_by_percent_with_tip(
@@ -367,18 +430,34 @@ impl PumpFun {
percent: u64, percent: u64,
amount_token: u64, amount_token: u64,
recent_blockhash: Hash, recent_blockhash: Hash,
trade_platform: String,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
pumpfun::sell::sell_by_percent_with_tip( if trade_platform == PUMPFUN {
self.fee_clients.clone(), pumpfun::sell::sell_by_percent_with_tip(
self.payer.clone(), self.fee_clients.clone(),
mint, self.payer.clone(),
creator, mint,
percent, creator,
amount_token, percent,
self.priority_fee.clone(), amount_token,
self.cluster.clone().lookup_table_key, self.priority_fee.clone(),
recent_blockhash, self.cluster.clone().lookup_table_key,
).await recent_blockhash,
).await
} else if trade_platform == PUMPFUN_SWAP {
pumpswap::sell::sell_by_percent_with_tip(
self.rpc.clone(),
self.fee_clients.clone(),
self.payer.clone(),
mint,
percent,
None,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
).await
} else {
Err(anyhow::anyhow!("Unsupported trade platform: {}", trade_platform))
}
} }
pub async fn sell_by_amount_with_tip( pub async fn sell_by_amount_with_tip(
@@ -387,17 +466,33 @@ impl PumpFun {
creator: Pubkey, creator: Pubkey,
amount: u64, amount: u64,
recent_blockhash: Hash, recent_blockhash: Hash,
trade_platform: String,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
pumpfun::sell::sell_by_amount_with_tip( if trade_platform == PUMPFUN {
self.fee_clients.clone(), pumpfun::sell::sell_by_amount_with_tip(
self.payer.clone(), self.fee_clients.clone(),
mint, self.payer.clone(),
creator, mint,
amount, creator,
self.priority_fee.clone(), amount,
self.cluster.clone().lookup_table_key, self.priority_fee.clone(),
recent_blockhash, self.cluster.clone().lookup_table_key,
).await recent_blockhash,
).await
} else if trade_platform == PUMPFUN_SWAP {
pumpswap::sell::sell_by_amount_with_tip(
self.rpc.clone(),
self.fee_clients.clone(),
self.payer.clone(),
mint,
amount,
None,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
).await
} else {
Err(anyhow::anyhow!("Unsupported trade platform: {}", trade_platform))
}
} }
/// Sell tokens using Jito /// Sell tokens using Jito
+1 -1
View File
@@ -23,7 +23,7 @@ use crate::{
const MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT: u32 = 250000; const MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT: u32 = 250000;
use super::common::{calculate_with_slippage_buy, get_buy_token_amount_from_sol_amount, init_bonding_curve_account, get_bonding_curve_account_v2, get_bonding_curve_pda}; use super::common::{calculate_with_slippage_buy, get_buy_token_amount_from_sol_amount, init_bonding_curve_account, get_bonding_curve_account_v2, get_bonding_curve_pda};
use crate::constants::pumpfun::trade_type::{SNIPER_BUY}; use crate::constants::trade_type::{SNIPER_BUY};
use crate::PumpFun; use crate::PumpFun;
/// 添加nonce消费指令到指令集合中 /// 添加nonce消费指令到指令集合中
+6 -5
View File
@@ -11,12 +11,13 @@ use solana_sdk::{
signature::{Keypair, Signer}, signature::{Keypair, Signer},
system_instruction, system_instruction,
transaction::VersionedTransaction, transaction::VersionedTransaction,
native_token::sol_to_lamports,
}; };
use spl_associated_token_account::instruction::create_associated_token_account_idempotent; use spl_associated_token_account::instruction::create_associated_token_account_idempotent;
use crate::common::{address_lookup_cache::get_address_lookup_table_account, nonce_cache::{self, NonceCache}, PriorityFee, SolanaRpcClient}; use crate::common::{address_lookup_cache::get_address_lookup_table_account, nonce_cache::{self, NonceCache}, PriorityFee, SolanaRpcClient};
use crate::pumpswap::common::{calculate_with_slippage_buy, find_pool, get_buy_token_amount}; use crate::pumpswap::common::{calculate_with_slippage_buy, find_pool, get_buy_token_amount};
use crate::constants::{accounts, trade::DEFAULT_SLIPPAGE, BUY_DISCRIMINATOR}; use crate::constants::pumpswap::{accounts, trade::DEFAULT_SLIPPAGE, BUY_DISCRIMINATOR};
use crate::swqos::FeeClient; use crate::swqos::FeeClient;
// Constants for compute budget // Constants for compute budget
@@ -31,7 +32,7 @@ const MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT: u32 = 256 * 1024;
fn add_nonce_instruction(instructions: &mut Vec<Instruction>, payer: &Keypair) -> Result<(), anyhow::Error> { fn add_nonce_instruction(instructions: &mut Vec<Instruction>, payer: &Keypair) -> Result<(), anyhow::Error> {
let nonce_cache = NonceCache::get_instance(); let nonce_cache = NonceCache::get_instance();
let nonce_info = nonce_cache.get_nonce_info(); let nonce_info = nonce_cache.get_nonce_info();
if let (Some(nonce_pubkey), Some(program_id)) = (nonce_info.nonce_account, nonce_info.program_id) { if let Some(nonce_pubkey) = nonce_info.nonce_account {
let nonce_value = nonce_info.current_nonce; let nonce_value = nonce_info.current_nonce;
// 暂不加锁 // 暂不加锁
// if nonce_info.lock { // if nonce_info.lock {
@@ -47,7 +48,7 @@ fn add_nonce_instruction(instructions: &mut Vec<Instruction>, payer: &Keypair) -
// nonce_cache.lock(); // nonce_cache.lock();
// 创建自定义nonce消费指令 // 创建自定义nonce消费指令
let nonce_consume_ix = Instruction { let nonce_consume_ix = Instruction {
program_id, program_id: crate::constants::pumpswap::accounts::AMM_PROGRAM,
accounts: vec![ accounts: vec![
AccountMeta::new(nonce_pubkey, false), AccountMeta::new(nonce_pubkey, false),
AccountMeta::new_readonly(payer.pubkey(), true), AccountMeta::new_readonly(payer.pubkey(), true),
@@ -55,7 +56,7 @@ fn add_nonce_instruction(instructions: &mut Vec<Instruction>, payer: &Keypair) -
// INSTR_CONSUME = 1, 使用传入的nonce值 // INSTR_CONSUME = 1, 使用传入的nonce值
data: { data: {
let mut data = vec![1]; // INSTR_CONSUME = 1 let mut data = vec![1]; // INSTR_CONSUME = 1
data.extend_from_slice(&nonce_value.to_le_bytes()); // 添加nonce值 data.extend_from_slice(&nonce_value.to_bytes()); // 添加nonce值
data data
}, },
}; };
@@ -248,7 +249,7 @@ pub async fn build_buy_transaction_with_tip(
system_instruction::transfer( system_instruction::transfer(
&payer.pubkey(), &payer.pubkey(),
&tip_account, &tip_account,
priority_fee.buy_tip_fee, sol_to_lamports(priority_fee.buy_tip_fee),
), ),
]; ];
+2 -2
View File
@@ -1,7 +1,7 @@
use solana_sdk::pubkey::Pubkey; use solana_sdk::pubkey::Pubkey;
use anyhow::anyhow; use anyhow::anyhow;
use solana_account_decoder::UiAccountEncoding; use solana_account_decoder::UiAccountEncoding;
use crate::{common::SolanaRpcClient, constants::accounts}; use crate::{common::SolanaRpcClient, constants::pumpswap::accounts};
use std::str::FromStr; use std::str::FromStr;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -91,7 +91,7 @@ impl Pool {
sort_results: None, sort_results: None,
}; };
let program_id = crate::constants::accounts::AMM_PROGRAM; let program_id = crate::constants::pumpswap::accounts::AMM_PROGRAM;
println!("program_id: {:?}", program_id); println!("program_id: {:?}", program_id);
let accounts = rpc.get_program_accounts_with_config(&program_id, config).await?; let accounts = rpc.get_program_accounts_with_config(&program_id, config).await?;
+38 -3
View File
@@ -5,17 +5,17 @@ use anyhow::anyhow;
use solana_sdk::{ use solana_sdk::{
compute_budget::ComputeBudgetInstruction, compute_budget::ComputeBudgetInstruction,
instruction::Instruction, instruction::Instruction,
pubkey::Pubkey, pubkey::Pubkey,
signature::{Keypair, Signer}, signature::{Keypair, Signer},
system_instruction, system_instruction,
transaction::VersionedTransaction, transaction::VersionedTransaction,
native_token::sol_to_lamports,
}; };
use spl_associated_token_account::instruction::create_associated_token_account_idempotent; use spl_associated_token_account::instruction::create_associated_token_account_idempotent;
use crate::common::{address_lookup_cache::get_address_lookup_table_account, PriorityFee, SolanaRpcClient}; use crate::common::{address_lookup_cache::get_address_lookup_table_account, PriorityFee, SolanaRpcClient};
use crate::pumpswap::common::{calculate_with_slippage_sell, find_pool, get_sell_sol_amount, get_token_balance}; use crate::pumpswap::common::{calculate_with_slippage_sell, find_pool, get_sell_sol_amount, get_token_balance};
use crate::constants::{accounts, trade::DEFAULT_SLIPPAGE, SELL_DISCRIMINATOR}; use crate::constants::pumpswap::{accounts, trade::DEFAULT_SLIPPAGE, SELL_DISCRIMINATOR};
use crate::swqos::FeeClient; use crate::swqos::FeeClient;
// Constants for compute budget // Constants for compute budget
@@ -73,6 +73,23 @@ pub async fn sell_by_percent(
sell(rpc, payer, mint, Some(amount), slippage_basis_points, priority_fee, lookup_table_key).await sell(rpc, payer, mint, Some(amount), slippage_basis_points, priority_fee, lookup_table_key).await
} }
/// Sell tokens by amount
pub async fn sell_by_amount(
rpc: Arc<SolanaRpcClient>,
payer: Arc<Keypair>,
mint: Pubkey,
amount: u64,
slippage_basis_points: Option<u64>,
priority_fee: PriorityFee,
lookup_table_key: Option<Pubkey>
) -> Result<(), anyhow::Error> {
if amount == 0 {
return Err(anyhow!("Amount must be greater than 0"));
}
sell(rpc, payer, mint, Some(amount), slippage_basis_points, priority_fee, lookup_table_key).await
}
// Sell tokens using a MEV service // Sell tokens using a MEV service
pub async fn sell_with_tip( pub async fn sell_with_tip(
rpc: Arc<SolanaRpcClient>, rpc: Arc<SolanaRpcClient>,
@@ -144,6 +161,24 @@ pub async fn sell_by_percent_with_tip(
sell_with_tip(rpc, fee_clients, payer, mint, Some(amount), slippage_basis_points, priority_fee, lookup_table_key).await sell_with_tip(rpc, fee_clients, payer, mint, Some(amount), slippage_basis_points, priority_fee, lookup_table_key).await
} }
// Sell tokens by amount using a MEV service
pub async fn sell_by_amount_with_tip(
rpc: Arc<SolanaRpcClient>,
fee_clients: Vec<Arc<FeeClient>>,
payer: Arc<Keypair>,
mint: Pubkey,
amount: u64,
slippage_basis_points: Option<u64>,
priority_fee: PriorityFee,
lookup_table_key: Option<Pubkey>
) -> Result<(), anyhow::Error> {
if amount == 0 {
return Err(anyhow!("Amount must be greater than 0"));
}
sell_with_tip(rpc, fee_clients, payer, mint, Some(amount), slippage_basis_points, priority_fee, lookup_table_key).await
}
// Build a transaction for selling tokens // Build a transaction for selling tokens
pub async fn build_sell_transaction( pub async fn build_sell_transaction(
_rpc: Arc<SolanaRpcClient>, _rpc: Arc<SolanaRpcClient>,
@@ -206,7 +241,7 @@ pub async fn build_sell_transaction_with_tip(
system_instruction::transfer( system_instruction::transfer(
&payer.pubkey(), &payer.pubkey(),
&tip_account, &tip_account,
priority_fee.sell_tip_fee, sol_to_lamports(priority_fee.sell_tip_fee),
), ),
]; ];