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
+14 -1
View File
@@ -1,2 +1,15 @@
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 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 swqos;
pub mod pumpfun;
pub mod pumpswap;
use std::sync::Arc;
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 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 payer: Arc<Keypair>,
@@ -228,21 +230,36 @@ impl PumpFun {
buy_sol_cost: u64,
slippage_basis_points: Option<u64>,
recent_blockhash: Hash,
trade_platform: String,
) -> Result<(), anyhow::Error> {
pumpfun::buy::buy(
self.rpc.clone(),
self.payer.clone(),
mint,
creator,
dev_buy_token,
dev_sol_cost,
buy_sol_cost,
slippage_basis_points,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
recent_blockhash,
COPY_BUY.to_string(),
).await
if trade_platform == PUMPFUN {
pumpfun::buy::buy(
self.rpc.clone(),
self.payer.clone(),
mint,
creator,
dev_buy_token,
dev_sol_cost,
buy_sol_cost,
slippage_basis_points,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
recent_blockhash,
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
@@ -281,21 +298,37 @@ impl PumpFun {
buy_sol_cost: u64,
slippage_basis_points: Option<u64>,
recent_blockhash: Hash,
trade_platform: String,
) -> Result<(), anyhow::Error> {
pumpfun::buy::buy_with_tip(
self.fee_clients.clone(),
self.payer.clone(),
mint,
creator,
dev_buy_token,
dev_sol_cost,
buy_sol_cost,
slippage_basis_points,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
recent_blockhash,
COPY_BUY.to_string(),
).await
if trade_platform == PUMPFUN {
pumpfun::buy::buy_with_tip(
self.fee_clients.clone(),
self.payer.clone(),
mint,
creator,
dev_buy_token,
dev_sol_cost,
buy_sol_cost,
slippage_basis_points,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
recent_blockhash,
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
@@ -326,18 +359,33 @@ impl PumpFun {
percent: u64,
amount_token: u64,
recent_blockhash: Hash,
trade_platform: String,
) -> Result<(), anyhow::Error> {
pumpfun::sell::sell_by_percent(
self.rpc.clone(),
self.payer.clone(),
mint.clone(),
creator,
percent,
amount_token,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
recent_blockhash,
).await
if trade_platform == PUMPFUN {
pumpfun::sell::sell_by_percent(
self.rpc.clone(),
self.payer.clone(),
mint.clone(),
creator,
percent,
amount_token,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
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
@@ -347,17 +395,32 @@ impl PumpFun {
creator: Pubkey,
amount: u64,
recent_blockhash: Hash,
trade_platform: String,
) -> Result<(), anyhow::Error> {
pumpfun::sell::sell_by_amount(
self.rpc.clone(),
self.payer.clone(),
mint.clone(),
creator,
amount,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
recent_blockhash,
).await
if trade_platform == PUMPFUN {
pumpfun::sell::sell_by_amount(
self.rpc.clone(),
self.payer.clone(),
mint.clone(),
creator,
amount,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
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(
@@ -367,18 +430,34 @@ impl PumpFun {
percent: u64,
amount_token: u64,
recent_blockhash: Hash,
trade_platform: String,
) -> Result<(), anyhow::Error> {
pumpfun::sell::sell_by_percent_with_tip(
self.fee_clients.clone(),
self.payer.clone(),
mint,
creator,
percent,
amount_token,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
recent_blockhash,
).await
if trade_platform == PUMPFUN {
pumpfun::sell::sell_by_percent_with_tip(
self.fee_clients.clone(),
self.payer.clone(),
mint,
creator,
percent,
amount_token,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
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(
@@ -387,17 +466,33 @@ impl PumpFun {
creator: Pubkey,
amount: u64,
recent_blockhash: Hash,
trade_platform: String,
) -> Result<(), anyhow::Error> {
pumpfun::sell::sell_by_amount_with_tip(
self.fee_clients.clone(),
self.payer.clone(),
mint,
creator,
amount,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
recent_blockhash,
).await
if trade_platform == PUMPFUN {
pumpfun::sell::sell_by_amount_with_tip(
self.fee_clients.clone(),
self.payer.clone(),
mint,
creator,
amount,
self.priority_fee.clone(),
self.cluster.clone().lookup_table_key,
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
+1 -1
View File
@@ -23,7 +23,7 @@ use crate::{
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 crate::constants::pumpfun::trade_type::{SNIPER_BUY};
use crate::constants::trade_type::{SNIPER_BUY};
use crate::PumpFun;
/// 添加nonce消费指令到指令集合中
+6 -5
View File
@@ -11,12 +11,13 @@ use solana_sdk::{
signature::{Keypair, Signer},
system_instruction,
transaction::VersionedTransaction,
native_token::sol_to_lamports,
};
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::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;
// 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> {
let nonce_cache = NonceCache::get_instance();
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;
// 暂不加锁
// if nonce_info.lock {
@@ -47,7 +48,7 @@ fn add_nonce_instruction(instructions: &mut Vec<Instruction>, payer: &Keypair) -
// nonce_cache.lock();
// 创建自定义nonce消费指令
let nonce_consume_ix = Instruction {
program_id,
program_id: crate::constants::pumpswap::accounts::AMM_PROGRAM,
accounts: vec![
AccountMeta::new(nonce_pubkey, false),
AccountMeta::new_readonly(payer.pubkey(), true),
@@ -55,7 +56,7 @@ fn add_nonce_instruction(instructions: &mut Vec<Instruction>, payer: &Keypair) -
// INSTR_CONSUME = 1, 使用传入的nonce值
data: {
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
},
};
@@ -248,7 +249,7 @@ pub async fn build_buy_transaction_with_tip(
system_instruction::transfer(
&payer.pubkey(),
&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 anyhow::anyhow;
use solana_account_decoder::UiAccountEncoding;
use crate::{common::SolanaRpcClient, constants::accounts};
use crate::{common::SolanaRpcClient, constants::pumpswap::accounts};
use std::str::FromStr;
#[derive(Debug, Clone)]
@@ -91,7 +91,7 @@ impl Pool {
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);
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::{
compute_budget::ComputeBudgetInstruction,
instruction::Instruction,
pubkey::Pubkey,
signature::{Keypair, Signer},
system_instruction,
transaction::VersionedTransaction,
native_token::sol_to_lamports,
};
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::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;
// 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 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
pub async fn sell_with_tip(
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 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
pub async fn build_sell_transaction(
_rpc: Arc<SolanaRpcClient>,
@@ -206,7 +241,7 @@ pub async fn build_sell_transaction_with_tip(
system_instruction::transfer(
&payer.pubkey(),
&tip_account,
priority_fee.sell_tip_fee,
sol_to_lamports(priority_fee.sell_tip_fee),
),
];