From bfd6809855a37a55b852fee18b507640a955bb0d Mon Sep 17 00:00:00 2001 From: ysq Date: Tue, 24 Jun 2025 20:56:15 +0800 Subject: [PATCH] refactor: rename PumpFun to SolanaTrade and improve API consistency - Rename PumpFun class to SolanaTrade to better reflect its expanded functionality - Rename copy_buy methods to buy for better API clarity - Update ShredStream and Yellowstone gRPC subscription examples - Add bonding_curve parameter to trading methods - Improve documentation with updated code examples - Update README files with new features and API changes --- README.md | 266 +++++++++++++++++-------------- README_CN.md | 266 +++++++++++++++++-------------- src/lib.rs | 75 ++++++++- src/main.rs | 190 +++++++++++++++------- src/trading/protocols/pumpfun.rs | 1 - 5 files changed, 496 insertions(+), 302 deletions(-) diff --git a/README.md b/README.md index 1a3db9d..a1e0787 100755 --- a/README.md +++ b/README.md @@ -6,12 +6,14 @@ A comprehensive Rust SDK for seamless interaction with Solana DEX trading progra 1. **PumpFun Trading**: Support for `create`, `buy`, `sell` operations 2. **PumpSwap Trading**: Support for PumpSwap pool trading operations -3. **Logs Subscription**: Subscribe to PumpFun program transaction logs -4. **Yellowstone gRPC**: Subscribe to program logs using gRPC -5. **Multiple MEV Protection**: Support for Jito, Nextblock, 0slot, Nozomi services -6. **Concurrent Transactions**: Submit transactions using multiple MEV services simultaneously; the fastest succeeds while others fail -7. **IPFS Integration**: Support for token metadata IPFS uploads -8. **Real-time Pricing**: Get real-time token prices and liquidity information +3. **Raydium Trading**: Support for Raydium DEX trading operations +4. **Logs Subscription**: Subscribe to PumpFun, PumpSwap, and Raydium program transaction logs +5. **Yellowstone gRPC**: Subscribe to program logs using Yellowstone gRPC +6. **ShredStream Support**: Subscribe to program logs using ShredStream +7. **Multiple MEV Protection**: Support for Jito, Nextblock, 0slot, Nozomi services +8. **Concurrent Transactions**: Submit transactions using multiple MEV services simultaneously; the fastest succeeds while others fail +9. **IPFS Integration**: Support for token metadata IPFS uploads +10. **Real-time Pricing**: Get real-time token prices and liquidity information ## Installation @@ -37,41 +39,38 @@ sol-trade-sdk = { path = "./sol-trade-sdk", version = "0.1.0" } use sol_trade_sdk::{common::pumpfun::logs_events::PumpfunEvent, grpc::YellowstoneGrpc}; use solana_sdk::signature::Keypair; -// Create gRPC client -let grpc_url = "http://127.0.0.1:10000"; +// Create gRPC client with Yellowstone +let grpc_url = "https://solana-yellowstone-grpc.publicnode.com:443"; let x_token = None; // Optional auth token let client = YellowstoneGrpc::new(grpc_url.to_string(), x_token)?; // Define callback function -let callback = |event: PumpfunEvent| { - match event { - PumpfunEvent::NewToken(token_info) => { - println!("Received new token event: {:?}", token_info); - }, - PumpfunEvent::NewDevTrade(trade_info) => { - println!("Received dev trade event: {:?}", trade_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); - } +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); } }; -let payer_keypair = Keypair::from_base58_string("your_private_key"); -client.subscribe_pumpfun(callback, Some(payer_keypair.pubkey())).await?; +client.subscribe_pumpfun(callback, None).await?; ``` -### 2. Initialize PumpFun Instance +### 2. Initialize SolanaTrade Instance ```rust use std::sync::Arc; -use sol_trade_sdk::{common::{Cluster, PriorityFee}, PumpFun}; +use sol_trade_sdk::{common::{Cluster, PriorityFee}, SolanaTrade}; use solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair}; // Configure priority fees @@ -105,15 +104,15 @@ let cluster = Cluster { lookup_table_key: None, // Optional lookup table }; -// Create PumpFun instance +// Create SolanaTrade instance let payer = Keypair::from_base58_string("your_private_key"); -let pumpfun = PumpFun::new(Arc::new(payer), &cluster).await; +let solana_trade_client = SolanaTrade::new(Arc::new(payer), &cluster).await; ``` ### 3. Create Token ```rust -use sol_trade_sdk::{PumpFun, ipfs::CreateTokenMetadata, ipfs::create_token_metadata}; +use sol_trade_sdk::{ipfs::CreateTokenMetadata, ipfs::create_token_metadata}; use solana_sdk::signature::Keypair; // Create token keypair @@ -136,14 +135,14 @@ let api_token = "your_pinata_api_token"; let ipfs_response = create_token_metadata(metadata, api_token).await?; // Create token -pumpfun.create(mint_keypair, ipfs_response).await?; +solana_trade_client.create(mint_keypair, ipfs_response).await?; ``` ### 3.1. Create and Buy Token (with MEV protection) ```rust // Create token and buy simultaneously with MEV protection -pumpfun.create_and_buy_with_tip( +solana_trade_client.create_and_buy_with_tip( payer.clone(), // payer keypair mint_keypair, // mint keypair ipfs_response, // IPFS response @@ -157,32 +156,39 @@ pumpfun.create_and_buy_with_tip( ```rust use solana_sdk::{pubkey::Pubkey, hash::Hash}; +use std::sync::Arc; +use sol_trade_sdk::accounts::BondingCurveAccount; let mint_pubkey = Pubkey::from_str("token_address")?; let creator = Pubkey::from_str("creator_address")?; let recent_blockhash = Hash::default(); // Get latest blockhash +let buy_sol_cost = 50000; // 0.00005 SOL +let slippage_basis_points = Some(100); // 1% // Sniper buy (fast purchase when new token launches) -pumpfun.sniper_buy_with_tip( +let dev_buy_token = 100_000; // test value +let dev_cost_sol = 10_000; // test value +let bonding_curve = BondingCurveAccount::new(&mint_pubkey, dev_buy_token, dev_cost_sol, creator); + +solana_trade_client.sniper_buy( mint_pubkey, creator, - 1000000, // dev_buy_token - 10000, // dev_sol_cost - 50000, // buy_sol_cost (lamports) - Some(100), // slippage (1%) + buy_sol_cost, + slippage_basis_points, recent_blockhash, + Some(Arc::new(bonding_curve)), ).await?; -// Copy buy (follow other traders) -pumpfun.copy_buy_with_tip( +// Buy with tip for MEV protection +solana_trade_client.buy_with_tip( mint_pubkey, creator, - 1000000, // dev_buy_token - 10000, // dev_sol_cost - 50000, // buy_sol_cost (lamports) - Some(100), // slippage (1%) + buy_sol_cost, + slippage_basis_points, recent_blockhash, + Some(Arc::new(bonding_curve)), "pumpfun".to_string(), // trading platform + None, // custom tip fee ).await?; ``` @@ -190,22 +196,22 @@ pumpfun.copy_buy_with_tip( ```rust // Sell by amount -pumpfun.sell_by_amount_with_tip( +solana_trade_client.sell_by_amount_with_tip( mint_pubkey, creator, 1000000, // token amount recent_blockhash, - "pumpfun".to_string(), + "pumpfun".to_string(), // trading platform ).await?; // Sell by percentage -pumpfun.sell_by_percent_with_tip( +solana_trade_client.sell_by_percent_with_tip( mint_pubkey, creator, 50, // percentage (50%) 2000000, // total token amount recent_blockhash, - "pumpfun".to_string(), + "pumpfun".to_string(), // trading platform ).await?; ``` @@ -213,19 +219,19 @@ pumpfun.sell_by_percent_with_tip( ```rust // Get current token price -let price = pumpfun.get_current_price(&mint_pubkey).await?; +let price = solana_trade_client.get_current_price(&mint_pubkey).await?; println!("Current price: {}", price); // Get SOL balance -let sol_balance = pumpfun.get_payer_sol_balance().await?; +let sol_balance = solana_trade_client.get_payer_sol_balance().await?; println!("SOL balance: {} lamports", sol_balance); // Get token balance -let token_balance = pumpfun.get_payer_token_balance(&mint_pubkey).await?; +let token_balance = solana_trade_client.get_payer_token_balance(&mint_pubkey).await?; println!("Token balance: {}", token_balance); // Get liquidity information -let sol_reserves = pumpfun.get_real_sol_reserves(&mint_pubkey).await?; +let sol_reserves = solana_trade_client.get_real_sol_reserves(&mint_pubkey).await?; println!("SOL reserves: {} lamports", sol_reserves); ``` @@ -234,87 +240,109 @@ println!("SOL reserves: {} lamports", sol_reserves); ```rust use sol_trade_sdk::{common::pumpswap::logs_events::PumpSwapEvent, grpc::YellowstoneGrpc}; -// Create gRPC client (same as above) -let grpc_url = "http://127.0.0.1:10000"; +// Create gRPC client with Yellowstone +let grpc_url = "https://solana-yellowstone-grpc.publicnode.com:443"; let x_token = None; let client = YellowstoneGrpc::new(grpc_url.to_string(), x_token)?; // Define callback function for PumpSwap events -let callback = |event: PumpSwapEvent| { - match event { - PumpSwapEvent::Buy(buy_event) => { - println!("PumpSwap Buy Event: {:?}", buy_event); - }, - PumpSwapEvent::Sell(sell_event) => { - println!("PumpSwap Sell Event: {:?}", sell_event); - }, - PumpSwapEvent::CreatePool(pool_event) => { - println!("PumpSwap Pool Created: {:?}", pool_event); - }, - PumpSwapEvent::Deposit(deposit_event) => { - println!("PumpSwap Deposit: {:?}", deposit_event); - }, - PumpSwapEvent::Withdraw(withdraw_event) => { - println!("PumpSwap Withdraw: {:?}", withdraw_event); - }, - PumpSwapEvent::Disable(disable_event) => { - println!("PumpSwap Pool Disabled: {:?}", disable_event); - }, - PumpSwapEvent::UpdateAdmin(admin_event) => { - println!("PumpSwap Admin Updated: {:?}", admin_event); - }, - PumpSwapEvent::UpdateFeeConfig(fee_event) => { - println!("PumpSwap Fee Config Updated: {:?}", fee_event); - }, - PumpSwapEvent::Error(err) => { - println!("PumpSwap Error: {}", err); - } +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); } }; // Subscribe to PumpSwap events +println!("Monitoring PumpSwap events, press Ctrl+C to stop..."); client.subscribe_pumpswap(callback).await?; ``` ### 8. PumpSwap Trading Operations ```rust -use solana_sdk::{pubkey::Pubkey, hash::Hash}; +use std::sync::Arc; +use solana_sdk::{pubkey::Pubkey, hash::Hash, signature::Keypair}; +use solana_client::rpc_client::RpcClient; +use sol_trade_sdk::{common::{Cluster, PriorityFee}, SolanaTrade}; -let mint_pubkey = Pubkey::from_str("token_address")?; -let creator = Pubkey::from_str("creator_address")?; -let recent_blockhash = Hash::default(); +let payer = Keypair::new(); +// Define cluster configuration +let cluster = Cluster { + rpc_url: "https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY".to_string(), + commitment: CommitmentConfig::confirmed(), + priority_fee: PriorityFee::default(), + use_jito: false, + use_zeroslot: false, + use_nozomi: false, + use_nextblock: false, + block_engine_url: "".to_string(), + zeroslot_url: "".to_string(), + zeroslot_auth_token: "".to_string(), + nozomi_url: "".to_string(), + nozomi_auth_token: "".to_string(), + nextblock_url: "".to_string(), + nextblock_auth_token: "".to_string(), + lookup_table_key: None, + use_rpc: true, +}; -// Buy tokens on PumpSwap -pumpfun.copy_buy_with_tip( - mint_pubkey, - creator, - 1000000, // dev_buy_token - 10000, // dev_sol_cost - 50000, // buy_sol_cost (lamports) - Some(100), // slippage (1%) - recent_blockhash, - "pumpswap".to_string(), // Use PumpSwap platform -).await?; +let solana_trade_client = SolanaTrade::new(Arc::new(payer), &cluster).await; +let creator = Pubkey::from_str("11111111111111111111111111111111")?; // dev account +let buy_sol_cost = 500_000; // 0.0005 SOL +let slippage_basis_points = Some(100); +let rpc = RpcClient::new(cluster.rpc_url); +let recent_blockhash = rpc.get_latest_blockhash().unwrap(); +let trade_platform = "pumpswap".to_string(); +let mint_pubkey = Pubkey::from_str("YOUR_TOKEN_MINT")?; // token mint -// Sell tokens on PumpSwap by amount -pumpfun.sell_by_amount_with_tip( - mint_pubkey, - creator, - 1000000, // token amount - recent_blockhash, - "pumpswap".to_string(), // Use PumpSwap platform -).await?; +println!("Buying tokens from PumpSwap..."); +solana_trade_client + .buy( + mint_pubkey, + creator, + buy_sol_cost, + slippage_basis_points, + recent_blockhash, + None, + trade_platform.clone(), + ) + .await?; -// Sell tokens on PumpSwap by percentage -pumpfun.sell_by_percent_with_tip( - mint_pubkey, - creator, - 50, // percentage (50%) - 2000000, // total token amount - recent_blockhash, - "pumpswap".to_string(), // Use PumpSwap platform -).await?; +// Sell 30% * amount_token quantity +solana_trade_client + .sell_by_percent( + mint_pubkey, + creator, + 30, // percentage (30%) + 100, // total token amount + recent_blockhash, + trade_platform.clone(), + ) + .await?; ``` ### 9. PumpSwap Pool Information @@ -325,15 +353,15 @@ use solana_sdk::pubkey::Pubkey; let pool_address = Pubkey::from_str("pool_address")?; // Get current price from PumpSwap pool -let price = pumpfun.get_current_price_with_pumpswap(&pool_address).await?; +let price = solana_trade_client.get_current_price_with_pumpswap(&pool_address).await?; println!("PumpSwap pool price: {}", price); // Get SOL reserves in PumpSwap pool -let sol_reserves = pumpfun.get_real_sol_reserves_with_pumpswap(&pool_address).await?; +let sol_reserves = solana_trade_client.get_real_sol_reserves_with_pumpswap(&pool_address).await?; println!("PumpSwap SOL reserves: {} lamports", sol_reserves); // Get token balance in PumpSwap pool -let token_balance = pumpfun.get_payer_token_balance_with_pumpswap(&pool_address).await?; +let token_balance = solana_trade_client.get_payer_token_balance_with_pumpswap(&pool_address).await?; println!("PumpSwap token balance: {}", token_balance); ``` diff --git a/README_CN.md b/README_CN.md index 42e0c87..09dc84a 100755 --- a/README_CN.md +++ b/README_CN.md @@ -6,12 +6,14 @@ 1. **PumpFun交易**: 支持`创建代币`、`购买`、`卖出`功能 2. **PumpSwap交易**: 支持PumpSwap池的交易操作 -3. **日志订阅**: 订阅PumpFun程序的交易日志 -4. **Yellowstone gRPC**: 使用gRPC订阅程序日志 -5. **多种MEV保护**: 支持Jito、Nextblock、0slot、Nozomi等服务 -6. **并发交易**: 同时使用多个MEV服务发送交易,最快的成功,其他失败 -7. **IPFS集成**: 支持代币元数据的IPFS上传 -8. **实时价格**: 获取代币实时价格和流动性信息 +3. **Raydium交易**: 支持Raydium DEX的交易操作 +4. **日志订阅**: 订阅PumpFun、PumpSwap和Raydium程序的交易日志 +5. **Yellowstone gRPC**: 使用Yellowstone gRPC订阅程序日志 +6. **ShredStream支持**: 使用ShredStream订阅程序日志 +7. **多种MEV保护**: 支持Jito、Nextblock、0slot、Nozomi等服务 +8. **并发交易**: 同时使用多个MEV服务发送交易,最快的成功,其他失败 +9. **IPFS集成**: 支持代币元数据的IPFS上传 +10. **实时价格**: 获取代币实时价格和流动性信息 ## 安装 @@ -37,41 +39,38 @@ sol-trade-sdk = { path = "./sol-trade-sdk", version = "0.1.0" } use sol_trade_sdk::{common::pumpfun::logs_events::PumpfunEvent, grpc::YellowstoneGrpc}; use solana_sdk::signature::Keypair; -// 创建gRPC客户端 -let grpc_url = "http://127.0.0.1:10000"; +// 创建Yellowstone gRPC客户端 +let grpc_url = "https://solana-yellowstone-grpc.publicnode.com:443"; let x_token = None; // 可选的认证令牌 let client = YellowstoneGrpc::new(grpc_url.to_string(), x_token)?; // 定义回调函数 -let callback = |event: PumpfunEvent| { - match event { - PumpfunEvent::NewToken(token_info) => { - println!("收到新代币事件: {:?}", token_info); - }, - PumpfunEvent::NewDevTrade(trade_info) => { - println!("收到开发者交易事件: {:?}", trade_info); - }, - PumpfunEvent::NewUserTrade(trade_info) => { - println!("收到用户交易事件: {:?}", trade_info); - }, - PumpfunEvent::NewBotTrade(trade_info) => { - println!("收到机器人交易事件: {:?}", trade_info); - } - PumpfunEvent::Error(err) => { - println!("收到错误: {}", err); - } +let callback = |event: PumpfunEvent| match event { + PumpfunEvent::NewDevTrade(trade_info) => { + println!("收到开发者交易事件: {:?}", trade_info); + } + PumpfunEvent::NewToken(token_info) => { + println!("收到新代币事件: {:?}", token_info); + } + PumpfunEvent::NewUserTrade(trade_info) => { + println!("收到用户交易事件: {:?}", trade_info); + } + PumpfunEvent::NewBotTrade(trade_info) => { + println!("收到机器人交易事件: {:?}", trade_info); + } + PumpfunEvent::Error(err) => { + println!("收到错误: {}", err); } }; -let payer_keypair = Keypair::from_base58_string("your_private_key"); -client.subscribe_pumpfun(callback, Some(payer_keypair.pubkey())).await?; +client.subscribe_pumpfun(callback, None).await?; ``` -### 2. 初始化PumpFun实例 +### 2. 初始化SolanaTrade实例 ```rust use std::sync::Arc; -use sol_trade_sdk::{common::{Cluster, PriorityFee}, PumpFun}; +use sol_trade_sdk::{common::{Cluster, PriorityFee}, SolanaTrade}; use solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair}; // 配置优先费用 @@ -105,15 +104,15 @@ let cluster = Cluster { lookup_table_key: None, // 可选的查找表 }; -// 创建PumpFun实例 +// 创建SolanaTrade实例 let payer = Keypair::from_base58_string("your_private_key"); -let pumpfun = PumpFun::new(Arc::new(payer), &cluster).await; +let solana_trade_client = SolanaTrade::new(Arc::new(payer), &cluster).await; ``` ### 3. 创建代币 ```rust -use sol_trade_sdk::{PumpFun, ipfs::CreateTokenMetadata, ipfs::create_token_metadata}; +use sol_trade_sdk::{ipfs::CreateTokenMetadata, ipfs::create_token_metadata}; use solana_sdk::signature::Keypair; // 创建代币密钥对 @@ -136,14 +135,14 @@ let api_token = "your_pinata_api_token"; let ipfs_response = create_token_metadata(metadata, api_token).await?; // 创建代币 -pumpfun.create(mint_keypair, ipfs_response).await?; +solana_trade_client.create(mint_keypair, ipfs_response).await?; ``` ### 3.1. 创建并购买代币(带小费) ```rust // 创建代币的同时购买,并使用MEV保护 -pumpfun.create_and_buy_with_tip( +solana_trade_client.create_and_buy_with_tip( payer.clone(), // payer keypair mint_keypair, // mint keypair ipfs_response, // IPFS响应 @@ -157,32 +156,39 @@ pumpfun.create_and_buy_with_tip( ```rust use solana_sdk::{pubkey::Pubkey, hash::Hash}; +use std::sync::Arc; +use sol_trade_sdk::accounts::BondingCurveAccount; let mint_pubkey = Pubkey::from_str("代币地址")?; let creator = Pubkey::from_str("创建者地址")?; let recent_blockhash = Hash::default(); // 获取最新区块哈希 +let buy_sol_cost = 50000; // 0.00005 SOL +let slippage_basis_points = Some(100); // 1% // 狙击购买(新代币上线时快速购买) -pumpfun.sniper_buy_with_tip( +let dev_buy_token = 100_000; // 测试值 +let dev_cost_sol = 10_000; // 测试值 +let bonding_curve = BondingCurveAccount::new(&mint_pubkey, dev_buy_token, dev_cost_sol, creator); + +solana_trade_client.sniper_buy( mint_pubkey, creator, - 1000000, // dev_buy_token - 10000, // dev_sol_cost - 50000, // buy_sol_cost (lamports) - Some(100), // slippage (1%) + buy_sol_cost, + slippage_basis_points, recent_blockhash, + Some(Arc::new(bonding_curve)), ).await?; -// 复制购买(跟随其他交易者) -pumpfun.copy_buy_with_tip( +// 使用小费进行MEV保护的购买 +solana_trade_client.buy_with_tip( mint_pubkey, creator, - 1000000, // dev_buy_token - 10000, // dev_sol_cost - 50000, // buy_sol_cost (lamports) - Some(100), // slippage (1%) + buy_sol_cost, + slippage_basis_points, recent_blockhash, + Some(Arc::new(bonding_curve)), "pumpfun".to_string(), // 交易平台 + None, // 自定义小费 ).await?; ``` @@ -190,22 +196,22 @@ pumpfun.copy_buy_with_tip( ```rust // 按数量卖出 -pumpfun.sell_by_amount_with_tip( +solana_trade_client.sell_by_amount_with_tip( mint_pubkey, creator, 1000000, // 代币数量 recent_blockhash, - "pumpfun".to_string(), + "pumpfun".to_string(), // 交易平台 ).await?; // 按百分比卖出 -pumpfun.sell_by_percent_with_tip( +solana_trade_client.sell_by_percent_with_tip( mint_pubkey, creator, 50, // 百分比 (50%) 2000000, // 总代币数量 recent_blockhash, - "pumpfun".to_string(), + "pumpfun".to_string(), // 交易平台 ).await?; ``` @@ -213,19 +219,19 @@ pumpfun.sell_by_percent_with_tip( ```rust // 获取代币当前价格 -let price = pumpfun.get_current_price(&mint_pubkey).await?; +let price = solana_trade_client.get_current_price(&mint_pubkey).await?; println!("当前价格: {}", price); // 获取SOL余额 -let sol_balance = pumpfun.get_payer_sol_balance().await?; +let sol_balance = solana_trade_client.get_payer_sol_balance().await?; println!("SOL余额: {} lamports", sol_balance); // 获取代币余额 -let token_balance = pumpfun.get_payer_token_balance(&mint_pubkey).await?; +let token_balance = solana_trade_client.get_payer_token_balance(&mint_pubkey).await?; println!("代币余额: {}", token_balance); // 获取流动性信息 -let sol_reserves = pumpfun.get_real_sol_reserves(&mint_pubkey).await?; +let sol_reserves = solana_trade_client.get_real_sol_reserves(&mint_pubkey).await?; println!("SOL储备: {} lamports", sol_reserves); ``` @@ -234,87 +240,109 @@ println!("SOL储备: {} lamports", sol_reserves); ```rust use sol_trade_sdk::{common::pumpswap::logs_events::PumpSwapEvent, grpc::YellowstoneGrpc}; -// 创建gRPC客户端(与上面相同) -let grpc_url = "http://127.0.0.1:10000"; +// 创建Yellowstone gRPC客户端 +let grpc_url = "https://solana-yellowstone-grpc.publicnode.com:443"; let x_token = None; let client = YellowstoneGrpc::new(grpc_url.to_string(), x_token)?; // 定义PumpSwap事件的回调函数 -let callback = |event: PumpSwapEvent| { - match event { - PumpSwapEvent::Buy(buy_event) => { - println!("PumpSwap购买事件: {:?}", buy_event); - }, - PumpSwapEvent::Sell(sell_event) => { - println!("PumpSwap卖出事件: {:?}", sell_event); - }, - PumpSwapEvent::CreatePool(pool_event) => { - println!("PumpSwap池创建: {:?}", pool_event); - }, - PumpSwapEvent::Deposit(deposit_event) => { - println!("PumpSwap存款: {:?}", deposit_event); - }, - PumpSwapEvent::Withdraw(withdraw_event) => { - println!("PumpSwap提款: {:?}", withdraw_event); - }, - PumpSwapEvent::Disable(disable_event) => { - println!("PumpSwap池禁用: {:?}", disable_event); - }, - PumpSwapEvent::UpdateAdmin(admin_event) => { - println!("PumpSwap管理员更新: {:?}", admin_event); - }, - PumpSwapEvent::UpdateFeeConfig(fee_event) => { - println!("PumpSwap费用配置更新: {:?}", fee_event); - }, - PumpSwapEvent::Error(err) => { - println!("PumpSwap错误: {}", err); - } +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停止..."); client.subscribe_pumpswap(callback).await?; ``` ### 8. PumpSwap交易操作 ```rust -use solana_sdk::{pubkey::Pubkey, hash::Hash}; +use std::sync::Arc; +use solana_sdk::{pubkey::Pubkey, hash::Hash, signature::Keypair}; +use solana_client::rpc_client::RpcClient; +use sol_trade_sdk::{common::{Cluster, PriorityFee}, SolanaTrade}; -let mint_pubkey = Pubkey::from_str("代币地址")?; -let creator = Pubkey::from_str("创建者地址")?; -let recent_blockhash = Hash::default(); +let payer = Keypair::new(); +// 配置集群 +let cluster = Cluster { + rpc_url: "https://mainnet.helius-rpc.com/?api-key=您的API密钥".to_string(), + commitment: CommitmentConfig::confirmed(), + priority_fee: PriorityFee::default(), + use_jito: false, + use_zeroslot: false, + use_nozomi: false, + use_nextblock: false, + block_engine_url: "".to_string(), + zeroslot_url: "".to_string(), + zeroslot_auth_token: "".to_string(), + nozomi_url: "".to_string(), + nozomi_auth_token: "".to_string(), + nextblock_url: "".to_string(), + nextblock_auth_token: "".to_string(), + lookup_table_key: None, + use_rpc: true, +}; -// 在PumpSwap上购买代币 -pumpfun.copy_buy_with_tip( - mint_pubkey, - creator, - 1000000, // dev_buy_token - 10000, // dev_sol_cost - 50000, // buy_sol_cost (lamports) - Some(100), // slippage (1%) - recent_blockhash, - "pumpswap".to_string(), // 使用PumpSwap平台 -).await?; +let solana_trade_client = SolanaTrade::new(Arc::new(payer), &cluster).await; +let creator = Pubkey::from_str("11111111111111111111111111111111")?; // 开发者账户 +let buy_sol_cost = 500_000; // 0.0005 SOL +let slippage_basis_points = Some(100); +let rpc = RpcClient::new(cluster.rpc_url); +let recent_blockhash = rpc.get_latest_blockhash().unwrap(); +let trade_platform = "pumpswap".to_string(); +let mint_pubkey = Pubkey::from_str("您的代币铸造地址")?; // 代币铸造地址 -// 在PumpSwap上按数量卖出代币 -pumpfun.sell_by_amount_with_tip( - mint_pubkey, - creator, - 1000000, // 代币数量 - recent_blockhash, - "pumpswap".to_string(), // 使用PumpSwap平台 -).await?; +println!("从PumpSwap购买代币..."); +solana_trade_client + .buy( + mint_pubkey, + creator, + buy_sol_cost, + slippage_basis_points, + recent_blockhash, + None, + trade_platform.clone(), + ) + .await?; -// 在PumpSwap上按百分比卖出代币 -pumpfun.sell_by_percent_with_tip( - mint_pubkey, - creator, - 50, // 百分比 (50%) - 2000000, // 总代币数量 - recent_blockhash, - "pumpswap".to_string(), // 使用PumpSwap平台 -).await?; +// 卖出30%的代币数量 +solana_trade_client + .sell_by_percent( + mint_pubkey, + creator, + 30, // 百分比 (30%) + 100, // 总代币数量 + recent_blockhash, + trade_platform.clone(), + ) + .await?; ``` ### 9. PumpSwap池信息 @@ -325,15 +353,15 @@ use solana_sdk::pubkey::Pubkey; let pool_address = Pubkey::from_str("池地址")?; // 从PumpSwap池获取当前价格 -let price = pumpfun.get_current_price_with_pumpswap(&pool_address).await?; +let price = solana_trade_client.get_current_price_with_pumpswap(&pool_address).await?; println!("PumpSwap池价格: {}", price); // 获取PumpSwap池中的SOL储备 -let sol_reserves = pumpfun.get_real_sol_reserves_with_pumpswap(&pool_address).await?; +let sol_reserves = solana_trade_client.get_real_sol_reserves_with_pumpswap(&pool_address).await?; println!("PumpSwap SOL储备: {} lamports", sol_reserves); // 获取PumpSwap池中的代币余额 -let token_balance = pumpfun.get_payer_token_balance_with_pumpswap(&pool_address).await?; +let token_balance = solana_trade_client.get_payer_token_balance_with_pumpswap(&pool_address).await?; println!("PumpSwap代币余额: {}", token_balance); ``` diff --git a/src/lib.rs b/src/lib.rs index c278323..8830ef8 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,7 @@ use crate::trading::BuyWithTipParams; use crate::trading::SellParams; use crate::trading::SellWithTipParams; -pub struct PumpFun { +pub struct SolanaTrade { pub payer: Arc, pub rpc: Arc, pub fee_clients: Vec>, @@ -45,9 +45,9 @@ pub struct PumpFun { pub cluster: Cluster, } -static INSTANCE: Mutex>> = Mutex::new(None); +static INSTANCE: Mutex>> = Mutex::new(None); -impl Clone for PumpFun { +impl Clone for SolanaTrade { fn clone(&self) -> Self { Self { payer: self.payer.clone(), @@ -59,7 +59,7 @@ impl Clone for PumpFun { } } -impl PumpFun { +impl SolanaTrade { #[inline] pub async fn new( payer: Arc, @@ -211,6 +211,7 @@ impl PumpFun { buy_sol_cost: u64, slippage_basis_points: Option, recent_blockhash: Hash, + bonding_curve: Option>, ) -> Result<(), anyhow::Error> { pumpfun::buy::buy( self.rpc.clone(), @@ -222,12 +223,12 @@ impl PumpFun { self.priority_fee.clone(), self.cluster.clone().lookup_table_key, recent_blockhash, - None, + bonding_curve, SNIPER_BUY.to_string(), ).await } - pub async fn copy_buy( + pub async fn buy( &self, mint: Pubkey, creator: Pubkey, @@ -274,6 +275,64 @@ impl PumpFun { } } + pub async fn buy_use_buy_params( + &self, + buy_params: BuyWithTipParams, + custom_buy_tip_fee: Option, + ) -> Result<(), anyhow::Error> { + let mut priority_fee = buy_params.priority_fee.clone(); + if custom_buy_tip_fee.is_some() { + priority_fee.buy_tip_fee = custom_buy_tip_fee.unwrap(); + priority_fee.buy_tip_fees = vec![custom_buy_tip_fee.unwrap()]; + } + let mint = buy_params.mint; + let creator = buy_params.creator; + let buy_sol_cost = buy_params.amount_sol; + let slippage_basis_points = buy_params.slippage_basis_points; + let recent_blockhash = buy_params.recent_blockhash; + if let Some(protocol_params) = buy_params + .protocol_params + .as_any() + .downcast_ref::() { + pumpfun::buy::buy( + self.rpc.clone(), + self.payer.clone(), + mint, + creator, + buy_sol_cost, + slippage_basis_points, + self.priority_fee.clone(), + self.cluster.clone().lookup_table_key, + recent_blockhash, + protocol_params.bonding_curve.clone(), + COPY_BUY.to_string(), + ).await + } else if let Some(protocol_params) = buy_params + .protocol_params + .as_any() + .downcast_ref::() { + pumpswap::buy::buy( + self.rpc.clone(), + self.payer.clone(), + mint, + creator, + buy_sol_cost, + slippage_basis_points, + self.priority_fee.clone(), + self.cluster.clone().lookup_table_key, + recent_blockhash, + protocol_params.pool.clone(), + protocol_params.pool_base_token_account.clone(), + protocol_params.pool_quote_token_account.clone(), + protocol_params.user_base_token_account.clone(), + protocol_params.user_quote_token_account.clone(), + protocol_params.auto_handle_wsol, + ).await + } else { + return Err(anyhow::anyhow!("Invalid protocol params for PumpFun")); + } + } + /// Buy tokens using Jito pub async fn sniper_buy_with_tip( &self, @@ -299,7 +358,7 @@ impl PumpFun { ).await } - pub async fn copy_buy_with_tip_use_buy_params( + pub async fn buy_with_tip_use_buy_params( &self, buy_params: BuyWithTipParams, custom_buy_tip_fee: Option, @@ -358,7 +417,7 @@ impl PumpFun { } } - pub async fn copy_buy_with_tip( + pub async fn buy_with_tip( &self, mint: Pubkey, creator: Pubkey, diff --git a/src/main.rs b/src/main.rs index 9c183ab..58f2a15 100755 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,16 @@ use std::{str::FromStr, sync::Arc}; use sol_trade_sdk::{ - common::{ + accounts::BondingCurveAccount, common::{ pumpfun::{ self, logs_events::PumpfunEvent, - logs_subscribe::{stop_subscription, tokens_subscription}, + logs_subscribe::{stop_subscription, tokens_subscription}, TradeInfo, }, pumpswap::{self, PumpSwapEvent}, raydium::{self, RaydiumEvent}, AnyResult, Cluster, PriorityFee, - }, - grpc::{ShredStreamGrpc, YellowstoneGrpc}, - PumpFun, + }, constants::pumpfun::global_constants::TOKEN_TOTAL_SUPPLY, grpc::{ShredStreamGrpc, YellowstoneGrpc}, pumpfun::common::get_bonding_curve_pda, SolanaTrade }; use solana_client::rpc_client::RpcClient; use solana_hash::Hash; @@ -29,7 +27,9 @@ async fn main() -> Result<(), Box> { // test_pumpswap_with_grpc().await?; // test_raydium_with_shreds().await?; // test_raydium_with_grpc().await?; - test_sell().await?; + // test_pumpfun_sniper().await?; + // test_pumpfun().await?; + test_pumpswap().await?; Ok(()) } @@ -257,7 +257,7 @@ async fn test_raydium_with_grpc() -> Result<(), Box> { Ok(()) } -async fn test_sell() -> AnyResult<()> { +async fn test_pumpfun_sniper() -> AnyResult<()> { let payer = Keypair::new(); // Define cluster configuration let cluster = Cluster { @@ -279,17 +279,137 @@ async fn test_sell() -> AnyResult<()> { lookup_table_key: None, use_rpc: true, }; - let pumpfun_client = PumpFun::new(Arc::new(payer), &cluster).await; - let creator = Pubkey::from_str("43tFsRkZyhE1JXGivxWthApHPqWCnDqs7E1ZNdy7gkNz")?; + let solana_trade_client = SolanaTrade::new(Arc::new(payer), &cluster).await; + let creator = Pubkey::from_str("xxx")?; // dev account + let buy_sol_cost = 500_000; // 0.0005 SOL + let slippage_basis_points = Some(100); + let rpc = RpcClient::new(cluster.rpc_url); + let recent_blockhash = rpc.get_latest_blockhash().unwrap(); + let mint_pubkey = Pubkey::from_str("xxx")?; // token mint + println!("Sniping buy tokens from PumpFun..."); + // get bonding curve + let dev_buy_token = 100_000; // test value + let dev_cost_sol = 100_000; // test value + let bonding_curve = BondingCurveAccount::new(&mint_pubkey, dev_buy_token, dev_cost_sol, creator); + solana_trade_client + .sniper_buy( + mint_pubkey, + creator, + buy_sol_cost, + slippage_basis_points, + recent_blockhash, + Some(Arc::new(bonding_curve)), + ) + .await?; + Ok(()) +} + +async fn test_pumpfun() -> AnyResult<()> { + let payer = Keypair::new(); + // Define cluster configuration + let cluster = Cluster { + rpc_url: "https://mainnet.helius-rpc.com/?api-key=f2f194bb-6bd6-4f20-9a94-7fe0799ade0b" + .to_string(), + commitment: CommitmentConfig::confirmed(), + priority_fee: PriorityFee::default(), + use_jito: false, + use_zeroslot: false, + use_nozomi: false, + use_nextblock: false, + block_engine_url: "".to_string(), + zeroslot_url: "".to_string(), + zeroslot_auth_token: "".to_string(), + nozomi_url: "".to_string(), + nozomi_auth_token: "".to_string(), + nextblock_url: "".to_string(), + nextblock_auth_token: "".to_string(), + lookup_table_key: None, + use_rpc: true, + }; + let solana_trade_client = SolanaTrade::new(Arc::new(payer), &cluster).await; + let creator = Pubkey::from_str("xxx")?; // dev account + let buy_sol_cost = 500_000; // 0.0005 SOL + let slippage_basis_points = Some(100); + let rpc = RpcClient::new(cluster.rpc_url); + let recent_blockhash = rpc.get_latest_blockhash().unwrap(); + let trade_platform = "pumpfun".to_string(); + let mint_pubkey = Pubkey::from_str("xxx")?; // token mint + println!("Buying tokens from PumpFun..."); + // get bonding curve + // Relevant on-chain information can be obtained from rpc/grpc + let virtual_token_reserves = 0; + let virtual_sol_reserves = 0; + let real_token_reserves = 0; + let real_sol_reserves = 0; + let bonding_curve = BondingCurveAccount { + discriminator: 0, + account: get_bonding_curve_pda(&mint_pubkey).unwrap(), + virtual_token_reserves: virtual_token_reserves, + virtual_sol_reserves: virtual_sol_reserves, + real_token_reserves: real_token_reserves, + real_sol_reserves: real_sol_reserves, + token_total_supply: TOKEN_TOTAL_SUPPLY, + complete: false, + creator: creator, + }; + solana_trade_client + .buy( + mint_pubkey, + creator, + buy_sol_cost, + slippage_basis_points, + recent_blockhash, + Some(Arc::new(bonding_curve)), + trade_platform.clone(), + ) + .await?; + // Sell 30% * amount_token quantity + // solana_trade_client + // .sell_by_percent( + // mint_pubkey, + // creator, + // 30, + // 100, + // recent_blockhash, + // trade_platform.clone(), + // ) + // .await?; + Ok(()) +} + +async fn test_pumpswap() -> AnyResult<()> { + let payer = Keypair::new(); + // Define cluster configuration + let cluster = Cluster { + rpc_url: "https://mainnet.helius-rpc.com/?api-key=f2f194bb-6bd6-4f20-9a94-7fe0799ade0b" + .to_string(), + commitment: CommitmentConfig::confirmed(), + priority_fee: PriorityFee::default(), + use_jito: false, + use_zeroslot: false, + use_nozomi: false, + use_nextblock: false, + block_engine_url: "".to_string(), + zeroslot_url: "".to_string(), + zeroslot_auth_token: "".to_string(), + nozomi_url: "".to_string(), + nozomi_auth_token: "".to_string(), + nextblock_url: "".to_string(), + nextblock_auth_token: "".to_string(), + lookup_table_key: None, + use_rpc: true, + }; + let solana_trade_client = SolanaTrade::new(Arc::new(payer), &cluster).await; + let creator = Pubkey::from_str("11111111111111111111111111111111")?; // dev account let buy_sol_cost = 500_000; // 0.0005 SOL let slippage_basis_points = Some(100); let rpc = RpcClient::new(cluster.rpc_url); let recent_blockhash = rpc.get_latest_blockhash().unwrap(); let trade_platform = "pumpswap".to_string(); - let mint_pubkey = Pubkey::from_str("FMnWxuES8X7n33SJryf9MKbZNH57tPREtjWqCTMupump")?; + let mint_pubkey = Pubkey::from_str("2zMMhcVQEXDtdE6vsFS7S7D5oUodfJHE8vd1gnBouauv")?; // token mint println!("Buying tokens from PumpSwap..."); - pumpfun_client - .copy_buy( + solana_trade_client + .buy( mint_pubkey, creator, buy_sol_cost, @@ -299,56 +419,16 @@ async fn test_sell() -> AnyResult<()> { trade_platform.clone(), ) .await?; - // pumpfun_client + // Sell 30% * amount_token quantity + // solana_trade_client // .sell_by_percent( // mint_pubkey, // creator, + // 30, // 100, - // 0, // recent_blockhash, // trade_platform.clone(), // ) // .await?; Ok(()) } - -async fn test_wss() -> AnyResult<()> { - println!("Starting token subscription\n"); - - let ws_url = "wss://api.mainnet-beta.solana.com"; - - // Set commitment - let commitment = CommitmentConfig::confirmed(); - - // Define callback function - 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); - } - }; - - // Start subscription - let subscription = tokens_subscription(ws_url, commitment, callback, None) - .await - .unwrap(); - - // Wait for a while to receive events - tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; - - // Stop subscription - stop_subscription(subscription).await; - - Ok(()) -} diff --git a/src/trading/protocols/pumpfun.rs b/src/trading/protocols/pumpfun.rs index 4941547..27555bb 100755 --- a/src/trading/protocols/pumpfun.rs +++ b/src/trading/protocols/pumpfun.rs @@ -21,7 +21,6 @@ use crate::{ params::{BuyParams, PumpFunParams, SellParams}, traits::InstructionBuilder, }, - PumpFun, }; /// PumpFun协议的指令构建器