Merge commit 'b3338114837482c5d17b53d347b283959c0f5e45' into feat/pumpswap
This commit is contained in:
@@ -87,6 +87,8 @@ tokio-tungstenite = { version = "0.26.1", features = ["native-tls"] }
|
|||||||
indicatif = "0.17.11"
|
indicatif = "0.17.11"
|
||||||
toml = "0.8.20"
|
toml = "0.8.20"
|
||||||
|
|
||||||
|
pumpfun_program = { version = "4.2.0", package = "pumpfun" }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -172,3 +172,11 @@ pub struct Symbol;
|
|||||||
impl Symbol {
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+137
-4
@@ -9,6 +9,7 @@ pub mod swqos;
|
|||||||
pub mod pumpfun;
|
pub mod pumpfun;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use swqos::{FeeClient, JitoClient, NextBlockClient, NozomiClient, SolRpcClient, ZeroSlotClient};
|
use swqos::{FeeClient, JitoClient, NextBlockClient, NozomiClient, SolRpcClient, ZeroSlotClient};
|
||||||
use rustls::crypto::{ring::default_provider, CryptoProvider};
|
use rustls::crypto::{ring::default_provider, CryptoProvider};
|
||||||
@@ -23,6 +24,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};
|
||||||
|
|
||||||
pub struct PumpFun {
|
pub struct PumpFun {
|
||||||
pub payer: Arc<Keypair>,
|
pub payer: Arc<Keypair>,
|
||||||
pub rpc: Arc<SolanaRpcClient>,
|
pub rpc: Arc<SolanaRpcClient>,
|
||||||
@@ -31,6 +34,8 @@ pub struct PumpFun {
|
|||||||
pub cluster: Cluster,
|
pub cluster: Cluster,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static INSTANCE: Mutex<Option<Arc<PumpFun>>> = Mutex::new(None);
|
||||||
|
|
||||||
impl Clone for PumpFun {
|
impl Clone for PumpFun {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -105,13 +110,29 @@ impl PumpFun {
|
|||||||
fee_clients.push(Arc::new(rpc_client));
|
fee_clients.push(Arc::new(rpc_client));
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
let instance = Self {
|
||||||
payer,
|
payer,
|
||||||
rpc,
|
rpc,
|
||||||
fee_clients,
|
fee_clients,
|
||||||
priority_fee: cluster.clone().priority_fee,
|
priority_fee: cluster.clone().priority_fee,
|
||||||
cluster: cluster.clone(),
|
cluster: cluster.clone(),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
let mut current = INSTANCE.lock().unwrap();
|
||||||
|
*current = Some(Arc::new(instance.clone()));
|
||||||
|
|
||||||
|
instance
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the RPC client instance
|
||||||
|
pub fn get_rpc(&self) -> &Arc<SolanaRpcClient> {
|
||||||
|
&self.rpc
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the current instance
|
||||||
|
pub fn get_instance() -> Arc<Self> {
|
||||||
|
let instance = INSTANCE.lock().unwrap();
|
||||||
|
instance.as_ref().expect("PumpFun instance not initialized. Please call new() first.").clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new token
|
/// Create a new token
|
||||||
@@ -172,7 +193,7 @@ impl PumpFun {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Buy tokens
|
/// Buy tokens
|
||||||
pub async fn buy(
|
pub async fn sniper_buy(
|
||||||
&self,
|
&self,
|
||||||
mint: Pubkey,
|
mint: Pubkey,
|
||||||
creator: Pubkey,
|
creator: Pubkey,
|
||||||
@@ -194,11 +215,38 @@ impl PumpFun {
|
|||||||
self.priority_fee.clone(),
|
self.priority_fee.clone(),
|
||||||
self.cluster.clone().lookup_table_key,
|
self.cluster.clone().lookup_table_key,
|
||||||
recent_blockhash,
|
recent_blockhash,
|
||||||
|
SNIPER_BUY.to_string(),
|
||||||
|
).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn copy_buy(
|
||||||
|
&self,
|
||||||
|
mint: Pubkey,
|
||||||
|
creator: Pubkey,
|
||||||
|
dev_buy_token: u64,
|
||||||
|
dev_sol_cost: u64,
|
||||||
|
buy_sol_cost: u64,
|
||||||
|
slippage_basis_points: Option<u64>,
|
||||||
|
recent_blockhash: Hash,
|
||||||
|
) -> 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
|
).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Buy tokens using Jito
|
/// Buy tokens using Jito
|
||||||
pub async fn buy_with_tip(
|
pub async fn sniper_buy_with_tip(
|
||||||
&self,
|
&self,
|
||||||
mint: Pubkey,
|
mint: Pubkey,
|
||||||
creator: Pubkey,
|
creator: Pubkey,
|
||||||
@@ -220,6 +268,33 @@ impl PumpFun {
|
|||||||
self.priority_fee.clone(),
|
self.priority_fee.clone(),
|
||||||
self.cluster.clone().lookup_table_key,
|
self.cluster.clone().lookup_table_key,
|
||||||
recent_blockhash,
|
recent_blockhash,
|
||||||
|
SNIPER_BUY.to_string(),
|
||||||
|
).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn copy_buy_with_tip(
|
||||||
|
&self,
|
||||||
|
mint: Pubkey,
|
||||||
|
creator: Pubkey,
|
||||||
|
dev_buy_token: u64,
|
||||||
|
dev_sol_cost: u64,
|
||||||
|
buy_sol_cost: u64,
|
||||||
|
slippage_basis_points: Option<u64>,
|
||||||
|
recent_blockhash: Hash,
|
||||||
|
) -> 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
|
).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,6 +340,26 @@ impl PumpFun {
|
|||||||
).await
|
).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sell tokens by amount
|
||||||
|
pub async fn sell_by_amount(
|
||||||
|
&self,
|
||||||
|
mint: Pubkey,
|
||||||
|
creator: Pubkey,
|
||||||
|
amount: u64,
|
||||||
|
recent_blockhash: Hash,
|
||||||
|
) -> 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
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn sell_by_percent_with_tip(
|
pub async fn sell_by_percent_with_tip(
|
||||||
&self,
|
&self,
|
||||||
mint: Pubkey,
|
mint: Pubkey,
|
||||||
@@ -286,6 +381,25 @@ impl PumpFun {
|
|||||||
).await
|
).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn sell_by_amount_with_tip(
|
||||||
|
&self,
|
||||||
|
mint: Pubkey,
|
||||||
|
creator: Pubkey,
|
||||||
|
amount: u64,
|
||||||
|
recent_blockhash: Hash,
|
||||||
|
) -> 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
|
||||||
|
}
|
||||||
|
|
||||||
/// Sell tokens using Jito
|
/// Sell tokens using Jito
|
||||||
pub async fn sell_with_tip(
|
pub async fn sell_with_tip(
|
||||||
&self,
|
&self,
|
||||||
@@ -375,4 +489,23 @@ impl PumpFun {
|
|||||||
pub async fn close_token_account(&self, mint: &Pubkey) -> Result<(), anyhow::Error> {
|
pub async fn close_token_account(&self, mint: &Pubkey) -> Result<(), anyhow::Error> {
|
||||||
pumpfun::common::close_token_account(&self.rpc, self.payer.as_ref(), mint).await
|
pumpfun::common::close_token_account(&self.rpc, self.payer.as_ref(), mint).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub async fn get_current_price(&self, mint: &Pubkey) -> Result<f64, anyhow::Error> {
|
||||||
|
let (bonding_curve, _) = pumpfun::common::get_bonding_curve_account_v2(&self.rpc, mint).await?;
|
||||||
|
|
||||||
|
let virtual_sol_reserves = bonding_curve.virtual_sol_reserves;
|
||||||
|
let virtual_token_reserves = bonding_curve.virtual_token_reserves;
|
||||||
|
|
||||||
|
Ok(pumpfun::common::get_token_price(virtual_sol_reserves, virtual_token_reserves))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub async fn get_real_sol_reserves(&self, mint: &Pubkey) -> Result<u64, anyhow::Error> {
|
||||||
|
let (bonding_curve, _) = pumpfun::common::get_bonding_curve_account_v2(&self.rpc, mint).await?;
|
||||||
|
|
||||||
|
let actual_sol_reserves = bonding_curve.real_sol_reserves;
|
||||||
|
|
||||||
|
Ok(actual_sol_reserves)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+91
-8
@@ -5,14 +5,16 @@ use solana_sdk::{commitment_config::CommitmentConfig, transaction::VersionedTran
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
// test_pumpfun().await?;
|
// test_pumpfun_with_shreds().await?;
|
||||||
test_pumpswap().await?;
|
// test_pumpfun_with_grpc().await?;
|
||||||
|
// test_pumpswap_with_shreds().await?;
|
||||||
|
test_pumpswap_with_grpc().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn test_pumpfun() -> Result<(), Box<dyn std::error::Error>> {
|
async fn test_pumpfun_with_shreds() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let grpc = ShredStreamGrpc::new(
|
let grpc = ShredStreamGrpc::new(
|
||||||
"http://127.0.0.1:10800".to_string(),
|
"http://127.0.0.1:10000".to_string(),
|
||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
let callback = |event: PumpfunEvent| {
|
let callback = |event: PumpfunEvent| {
|
||||||
@@ -52,12 +54,44 @@ async fn test_pumpfun() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn test_pumpswap() -> Result<(), Box<dyn std::error::Error>> {
|
async fn test_pumpfun_with_grpc() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
// 使用 GRPC 客户端订阅 PumpSwap 事件
|
let grpc = YellowstoneGrpc::new(
|
||||||
println!("正在订阅 PumpSwap GRPC 事件...");
|
"https://solana-yellowstone-grpc.publicnode.com:443".to_string(),
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let callback = |event: PumpfunEvent| {
|
||||||
|
|
||||||
|
match event {
|
||||||
|
PumpfunEvent::NewDevTrade(trade_info) => {
|
||||||
|
println!("Received new dev trade event: {:?}", trade_info);
|
||||||
|
},
|
||||||
|
PumpfunEvent::NewToken(token_info) => {
|
||||||
|
println!("Received new token event: {:?}", token_info);
|
||||||
|
},
|
||||||
|
PumpfunEvent::NewUserTrade(trade_info) => {
|
||||||
|
println!("Received new trade event: {:?}", trade_info);
|
||||||
|
},
|
||||||
|
PumpfunEvent::NewBotTrade(trade_info) => {
|
||||||
|
println!("Received new bot trade event: {:?}", trade_info);
|
||||||
|
},
|
||||||
|
PumpfunEvent::Error(err) => {
|
||||||
|
println!("Received error: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
grpc.subscribe_pumpfun(callback, None).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn test_pumpswap_with_shreds() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// 使用 ShredStream 客户端订阅 PumpSwap 事件
|
||||||
|
println!("正在订阅 PumpSwap ShredStream 事件...");
|
||||||
|
|
||||||
let grpc_client = ShredStreamGrpc::new(
|
let grpc_client = ShredStreamGrpc::new(
|
||||||
"http://127.0.0.1:10800".to_string(),
|
"http://127.0.0.1:10000".to_string(),
|
||||||
).await?;
|
).await?;
|
||||||
|
|
||||||
// 定义回调函数处理 PumpSwap 事件
|
// 定义回调函数处理 PumpSwap 事件
|
||||||
@@ -100,6 +134,55 @@ async fn test_pumpswap() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn test_pumpswap_with_grpc() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
// 使用 GRPC 客户端订阅 PumpSwap 事件
|
||||||
|
println!("正在订阅 PumpSwap GRPC 事件...");
|
||||||
|
|
||||||
|
let grpc = YellowstoneGrpc::new(
|
||||||
|
"https://solana-yellowstone-grpc.publicnode.com:443".to_string(),
|
||||||
|
None
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// 定义回调函数处理 PumpSwap 事件
|
||||||
|
let callback = |event: PumpSwapEvent| {
|
||||||
|
match event {
|
||||||
|
PumpSwapEvent::Buy(buy_event) => {
|
||||||
|
println!("buy_event: {:?}", buy_event);
|
||||||
|
},
|
||||||
|
PumpSwapEvent::Sell(sell_event) => {
|
||||||
|
println!("sell_event: {:?}", sell_event);
|
||||||
|
},
|
||||||
|
PumpSwapEvent::CreatePool(create_event) => {
|
||||||
|
println!("create_event: {:?}", create_event);
|
||||||
|
},
|
||||||
|
PumpSwapEvent::Deposit(deposit_event) => {
|
||||||
|
println!("deposit_event: {:?}", deposit_event);
|
||||||
|
},
|
||||||
|
PumpSwapEvent::Withdraw(withdraw_event) => {
|
||||||
|
println!("withdraw_event: {:?}", withdraw_event);
|
||||||
|
},
|
||||||
|
PumpSwapEvent::Disable(disable_event) => {
|
||||||
|
println!("disable_event: {:?}", disable_event);
|
||||||
|
},
|
||||||
|
PumpSwapEvent::UpdateAdmin(update_admin_event) => {
|
||||||
|
println!("update_admin_event: {:?}", update_admin_event);
|
||||||
|
},
|
||||||
|
PumpSwapEvent::UpdateFeeConfig(update_fee_event) => {
|
||||||
|
println!("update_fee_event: {:?}", update_fee_event);
|
||||||
|
},
|
||||||
|
PumpSwapEvent::Error(err) => {
|
||||||
|
println!("error: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 订阅 PumpSwap 事件
|
||||||
|
println!("开始监听 PumpSwap 事件,按 Ctrl+C 停止...");
|
||||||
|
|
||||||
|
grpc.subscribe_pumpswap(callback).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn test_wss() -> AnyResult<()> {
|
async fn test_wss() -> AnyResult<()> {
|
||||||
println!("Starting token subscription\n");
|
println!("Starting token subscription\n");
|
||||||
|
|||||||
+25
-5
@@ -22,7 +22,9 @@ 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};
|
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::PumpFun;
|
||||||
|
|
||||||
/// 添加nonce消费指令到指令集合中
|
/// 添加nonce消费指令到指令集合中
|
||||||
///
|
///
|
||||||
@@ -76,10 +78,11 @@ pub async fn buy(
|
|||||||
priority_fee: PriorityFee,
|
priority_fee: PriorityFee,
|
||||||
lookup_table_key: Option<Pubkey>,
|
lookup_table_key: Option<Pubkey>,
|
||||||
recent_blockhash: Hash,
|
recent_blockhash: Hash,
|
||||||
|
trade_type: String,
|
||||||
) -> Result<(), anyhow::Error> {
|
) -> Result<(), anyhow::Error> {
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
let mint = Arc::new(mint.clone());
|
let mint = Arc::new(mint.clone());
|
||||||
let instructions = build_buy_instructions(payer.clone(), mint.clone(), creator, dev_buy_token, dev_sol_cost, buy_sol_cost, slippage_basis_points).await?;
|
let instructions = build_buy_instructions(payer.clone(), mint.clone(), creator, dev_buy_token, dev_sol_cost, buy_sol_cost, slippage_basis_points, trade_type).await?;
|
||||||
println!(" 买入交易指令: {:?}", start_time.elapsed());
|
println!(" 买入交易指令: {:?}", start_time.elapsed());
|
||||||
|
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
@@ -191,10 +194,11 @@ pub async fn buy_with_tip(
|
|||||||
priority_fee: PriorityFee,
|
priority_fee: PriorityFee,
|
||||||
lookup_table_key: Option<Pubkey>,
|
lookup_table_key: Option<Pubkey>,
|
||||||
recent_blockhash: Hash,
|
recent_blockhash: Hash,
|
||||||
|
trade_type: String,
|
||||||
) -> Result<(), anyhow::Error> {
|
) -> Result<(), anyhow::Error> {
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
let mint = Arc::new(mint.clone());
|
let mint = Arc::new(mint.clone());
|
||||||
let instructions = build_buy_instructions(payer.clone(), mint.clone(), creator, dev_buy_token, dev_sol_cost, buy_sol_cost, slippage_basis_points).await?;
|
let instructions = build_buy_instructions(payer.clone(), mint.clone(), creator, dev_buy_token, dev_sol_cost, buy_sol_cost, slippage_basis_points, trade_type).await?;
|
||||||
println!(" 买入交易指令: {:?}", start_time.elapsed());
|
println!(" 买入交易指令: {:?}", start_time.elapsed());
|
||||||
|
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
@@ -356,7 +360,6 @@ pub async fn build_buy_transaction_with_tip(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn build_buy_instructions(
|
pub async fn build_buy_instructions(
|
||||||
// rpc: Arc<SolanaRpcClient>,
|
|
||||||
payer: Arc<Keypair>,
|
payer: Arc<Keypair>,
|
||||||
mint: Arc<Pubkey>,
|
mint: Arc<Pubkey>,
|
||||||
creator: Pubkey,
|
creator: Pubkey,
|
||||||
@@ -364,12 +367,29 @@ pub async fn build_buy_instructions(
|
|||||||
dev_sol_cost: u64,
|
dev_sol_cost: u64,
|
||||||
buy_sol_cost: u64,
|
buy_sol_cost: u64,
|
||||||
slippage_basis_points: Option<u64>,
|
slippage_basis_points: Option<u64>,
|
||||||
|
trade_type: String,
|
||||||
) -> Result<Vec<Instruction>, anyhow::Error> {
|
) -> Result<Vec<Instruction>, anyhow::Error> {
|
||||||
if buy_sol_cost == 0 {
|
if buy_sol_cost == 0 {
|
||||||
return Err(anyhow!("Amount cannot be zero"));
|
return Err(anyhow!("Amount cannot be zero"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let bonding_curve = init_bonding_curve_account(&mint, dev_buy_token, dev_sol_cost, creator).await?;
|
let bonding_curve = if trade_type == SNIPER_BUY {
|
||||||
|
init_bonding_curve_account(&mint, dev_buy_token, dev_sol_cost, creator).await?
|
||||||
|
} else {
|
||||||
|
let (bonding_curve, _) = get_bonding_curve_account_v2(&PumpFun::get_instance().get_rpc(), &mint).await?;
|
||||||
|
Arc::new(crate::accounts::BondingCurveAccount {
|
||||||
|
discriminator: bonding_curve.discriminator,
|
||||||
|
account: get_bonding_curve_pda(&mint).unwrap(),
|
||||||
|
virtual_token_reserves: bonding_curve.virtual_token_reserves,
|
||||||
|
virtual_sol_reserves: bonding_curve.virtual_sol_reserves,
|
||||||
|
real_token_reserves: bonding_curve.real_token_reserves,
|
||||||
|
real_sol_reserves: bonding_curve.real_sol_reserves,
|
||||||
|
token_total_supply: bonding_curve.token_total_supply,
|
||||||
|
complete: bonding_curve.complete,
|
||||||
|
creator: creator,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
let max_sol_cost = calculate_with_slippage_buy(buy_sol_cost, slippage_basis_points.unwrap_or(100));
|
let max_sol_cost = calculate_with_slippage_buy(buy_sol_cost, slippage_basis_points.unwrap_or(100));
|
||||||
let creator_vault_pda = bonding_curve.get_creator_vault_pda();
|
let creator_vault_pda = bonding_curve.get_creator_vault_pda();
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use solana_sdk::{
|
|||||||
compute_budget::ComputeBudgetInstruction, instruction::Instruction, pubkey::Pubkey, signature::Keypair, signer::Signer, system_instruction, transaction::Transaction
|
compute_budget::ComputeBudgetInstruction, instruction::Instruction, pubkey::Pubkey, signature::Keypair, signer::Signer, system_instruction, transaction::Transaction
|
||||||
};
|
};
|
||||||
use spl_associated_token_account::get_associated_token_address;
|
use spl_associated_token_account::get_associated_token_address;
|
||||||
|
use pumpfun_program::accounts::BondingCurveAccount as PumpfunBondingCurveAccount;
|
||||||
use crate::{accounts::{self, BondingCurveAccount}, common::{pumpfun::logs_data::TradeInfo, PriorityFee, SolanaRpcClient}, constants::{self, pumpfun::{self, global_constants::{CREATOR_FEE, FEE_BASIS_POINTS}, trade::DEFAULT_SLIPPAGE}}};
|
use crate::{accounts::{self, BondingCurveAccount}, common::{pumpfun::logs_data::TradeInfo, PriorityFee, SolanaRpcClient}, constants::{self, pumpfun::{self, global_constants::{CREATOR_FEE, FEE_BASIS_POINTS}, trade::DEFAULT_SLIPPAGE}}};
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
@@ -224,6 +225,25 @@ pub async fn get_bonding_curve_account(
|
|||||||
Ok((bonding_curve, bonding_curve_pda))
|
Ok((bonding_curve, bonding_curve_pda))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub async fn get_bonding_curve_account_v2(
|
||||||
|
rpc: &SolanaRpcClient,
|
||||||
|
mint: &Pubkey,
|
||||||
|
) -> Result<(Arc<PumpfunBondingCurveAccount>, Pubkey), anyhow::Error> {
|
||||||
|
let bonding_curve_pda = get_bonding_curve_pda(mint)
|
||||||
|
.ok_or(anyhow!("Bonding curve not found"))?;
|
||||||
|
|
||||||
|
let account = rpc.get_account(&bonding_curve_pda).await?;
|
||||||
|
if account.data.is_empty() {
|
||||||
|
return Err(anyhow!("Bonding curve not found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let bonding_curve = solana_sdk::borsh1::try_from_slice_unchecked::<PumpfunBondingCurveAccount>(&account.data)
|
||||||
|
.map_err(|e| anyhow::anyhow!("Failed to deserialize bonding curve account: {}", e))?;
|
||||||
|
|
||||||
|
Ok((Arc::new(bonding_curve), bonding_curve_pda))
|
||||||
|
}
|
||||||
|
|
||||||
// #[inline]
|
// #[inline]
|
||||||
// pub fn get_buy_token_amount(
|
// pub fn get_buy_token_amount(
|
||||||
// mint: &Pubkey,
|
// mint: &Pubkey,
|
||||||
|
|||||||
@@ -56,6 +56,24 @@ pub async fn sell_by_percent(
|
|||||||
sell(rpc, payer, mint, creator, amount, priority_fee, lookup_table_key, recent_blockhash).await
|
sell(rpc, payer, mint, creator, amount, priority_fee, lookup_table_key, recent_blockhash).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sell tokens by amount
|
||||||
|
pub async fn sell_by_amount(
|
||||||
|
rpc: Arc<SolanaRpcClient>,
|
||||||
|
payer: Arc<Keypair>,
|
||||||
|
mint: Pubkey,
|
||||||
|
creator: Pubkey,
|
||||||
|
amount: u64,
|
||||||
|
priority_fee: PriorityFee,
|
||||||
|
lookup_table_key: Option<Pubkey>,
|
||||||
|
recent_blockhash: Hash,
|
||||||
|
) -> Result<(), anyhow::Error> {
|
||||||
|
if amount == 0 {
|
||||||
|
return Err(anyhow!("Amount must be greater than 0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
sell(rpc, payer, mint, creator, amount, priority_fee, lookup_table_key, recent_blockhash).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn sell_by_percent_with_tip(
|
pub async fn sell_by_percent_with_tip(
|
||||||
fee_clients: Vec<Arc<FeeClient>>,
|
fee_clients: Vec<Arc<FeeClient>>,
|
||||||
payer: Arc<Keypair>,
|
payer: Arc<Keypair>,
|
||||||
@@ -75,6 +93,23 @@ pub async fn sell_by_percent_with_tip(
|
|||||||
sell_with_tip(fee_clients, payer, mint, creator, amount, priority_fee, lookup_table_key, recent_blockhash).await
|
sell_with_tip(fee_clients, payer, mint, creator, amount, priority_fee, lookup_table_key, recent_blockhash).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn sell_by_amount_with_tip(
|
||||||
|
fee_clients: Vec<Arc<FeeClient>>,
|
||||||
|
payer: Arc<Keypair>,
|
||||||
|
mint: Pubkey,
|
||||||
|
creator: Pubkey,
|
||||||
|
amount: u64,
|
||||||
|
priority_fee: PriorityFee,
|
||||||
|
lookup_table_key: Option<Pubkey>,
|
||||||
|
recent_blockhash: Hash,
|
||||||
|
) -> Result<(), anyhow::Error> {
|
||||||
|
if amount == 0 {
|
||||||
|
return Err(anyhow!("Amount must be greater than 0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
sell_with_tip(fee_clients, payer, mint, creator, amount, priority_fee, lookup_table_key, recent_blockhash).await
|
||||||
|
}
|
||||||
|
|
||||||
/// Sell tokens using Jito
|
/// Sell tokens using Jito
|
||||||
pub async fn sell_with_tip(
|
pub async fn sell_with_tip(
|
||||||
fee_clients: Vec<Arc<FeeClient>>,
|
fee_clients: Vec<Arc<FeeClient>>,
|
||||||
|
|||||||
Reference in New Issue
Block a user