rebuild sdk dir

This commit is contained in:
wood
2025-07-10 02:38:06 +08:00
parent 1540fb6469
commit 8f79c3bfd9
24 changed files with 348 additions and 195 deletions
+1 -1
View File
@@ -28,7 +28,7 @@
use serde::{Serialize, Deserialize};
use solana_sdk::pubkey::Pubkey;
use crate::{constants::pumpfun::global_constants::{INITIAL_REAL_TOKEN_RESERVES, INITIAL_VIRTUAL_SOL_RESERVES, INITIAL_VIRTUAL_TOKEN_RESERVES, TOKEN_TOTAL_SUPPLY}, pumpfun::common::{get_bonding_curve_pda, get_creator_vault_pda}};
use crate::{constants::pumpfun::global_constants::{INITIAL_REAL_TOKEN_RESERVES, INITIAL_VIRTUAL_SOL_RESERVES, INITIAL_VIRTUAL_TOKEN_RESERVES, TOKEN_TOTAL_SUPPLY}, trading::pumpfun::common::{get_bonding_curve_pda, get_creator_vault_pda}};
/// Represents the global configuration account for token pricing and fees
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -6,7 +6,7 @@ use crate::{
constants::bonk::{
accounts, trade::DEFAULT_SLIPPAGE, BUY_EXECT_IN_DISCRIMINATOR, SELL_EXECT_IN_DISCRIMINATOR,
},
bonk::{
trading::bonk::{
common::{get_amount_out, get_pool_pda, get_token_balance, get_vault_pda},
pool::Pool,
},
+5 -1
View File
@@ -11,7 +11,7 @@
//! - `sell`: Instruction to sell tokens back to the bonding curve in exchange for SOL.
use crate::{
constants,
pumpfun::common::{
trading::pumpfun::common::{
get_bonding_curve_pda, get_global_pda, get_metadata_pda, get_mint_authority_pda
},
};
@@ -24,6 +24,10 @@ use solana_sdk::{
signer::Signer,
};
pub mod pumpfun;
pub mod pumpswap;
pub mod bonk;
pub struct Create {
pub _name: String,
pub _symbol: String,
+298
View File
@@ -0,0 +1,298 @@
use anyhow::{anyhow, Result};
use solana_sdk::{
instruction::Instruction, native_token::sol_to_lamports,
};
use spl_associated_token_account::{
get_associated_token_address, instruction::create_associated_token_account,
};
use spl_token::instruction::close_account;
use crate::{
constants, trading::pumpfun::common::{
get_bonding_curve_pda, get_global_pda, get_metadata_pda, get_mint_authority_pda
}
};
use solana_sdk::{
instruction::AccountMeta,
pubkey::Pubkey,
signature::Keypair,
signer::Signer,
};
use crate::{
constants::pumpfun::{global_constants::FEE_RECIPIENT, trade::DEFAULT_SLIPPAGE},
trading::pumpfun::common::{
calculate_with_slippage_buy, get_buy_token_amount_from_sol_amount, get_creator_vault_pda,
},
trading::core::{
params::{BuyParams, PumpFunParams, SellParams},
traits::InstructionBuilder,
},
};
/// PumpFun协议的指令构建器
pub struct PumpFunInstructionBuilder;
#[async_trait::async_trait]
impl InstructionBuilder for PumpFunInstructionBuilder {
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>> {
// 获取PumpFun特定参数
let protocol_params = params
.protocol_params
.as_any()
.downcast_ref::<PumpFunParams>()
.ok_or_else(|| anyhow!("Invalid protocol params for PumpFun"))?;
if params.amount_sol == 0 {
return Err(anyhow!("Amount cannot be zero"));
}
let bonding_curve = if protocol_params.bonding_curve.is_some() {
protocol_params.bonding_curve.clone().unwrap()
} else {
return Err(anyhow!("Bonding curve not found"));
};
let max_sol_cost = calculate_with_slippage_buy(
params.amount_sol,
params
.slippage_basis_points
.unwrap_or(DEFAULT_SLIPPAGE),
);
let creator_vault_pda = bonding_curve.get_creator_vault_pda();
let mut buy_token_amount =
get_buy_token_amount_from_sol_amount(&bonding_curve, params.amount_sol);
if buy_token_amount <= 100 * 1_000_000_u64 {
buy_token_amount = if max_sol_cost > sol_to_lamports(0.01) {
25547619 * 1_000_000_u64
} else {
255476 * 1_000_000_u64
};
}
let mut instructions = vec![];
// 创建关联代币账户
instructions.push(create_associated_token_account(
&params.payer.pubkey(),
&params.payer.pubkey(),
&params.mint,
&constants::pumpfun::accounts::TOKEN_PROGRAM,
));
// 创建买入指令
instructions.push(buy(
params.payer.as_ref(),
&params.mint,
&bonding_curve.account,
&creator_vault_pda,
&FEE_RECIPIENT,
Buy {
_amount: buy_token_amount,
_max_sol_cost: max_sol_cost,
},
));
Ok(instructions)
}
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
let amount_token = if let Some(amount) = params.amount_token {
if amount == 0 {
return Err(anyhow!("Amount cannot be zero"));
}
amount
} else {
return Err(anyhow!("Amount token is required"));
};
let creator_vault_pda = get_creator_vault_pda(&params.creator).unwrap();
let ata = get_associated_token_address(&params.payer.pubkey(), &params.mint);
// 获取代币余额
let balance_u64 = if let Some(rpc) = &params.rpc {
let balance = rpc.get_token_account_balance(&ata).await?;
balance
.amount
.parse::<u64>()
.map_err(|_| anyhow!("Failed to parse token balance"))?
} else {
return Err(anyhow!("RPC client is required to get token balance"));
};
let mut amount_token = amount_token;
if amount_token > balance_u64 {
amount_token = balance_u64;
}
let mut instructions = vec![sell(
params.payer.as_ref(),
&params.mint,
&creator_vault_pda,
&FEE_RECIPIENT,
Sell {
_amount: amount_token,
_min_sol_output: 1,
},
)];
// 如果卖出全部代币,关闭账户
if amount_token >= balance_u64 {
instructions.push(close_account(
&spl_token::ID,
&ata,
&params.payer.pubkey(),
&params.payer.pubkey(),
&[&params.payer.pubkey()],
)?);
}
Ok(instructions)
}
}
pub struct Create {
pub _name: String,
pub _symbol: String,
pub _uri: String,
pub _creator: Pubkey,
}
impl Create {
pub fn data(&self) -> Vec<u8> {
let mut data = Vec::with_capacity(8 + 4 + self._name.len() + 4 + self._symbol.len() + 4 + self._uri.len() + 32);
// 追加 discriminator
data.extend_from_slice(&[24, 30, 200, 40, 5, 28, 7, 119]); // discriminator
// 添加 name 字符串长度和内容
data.extend_from_slice(&(self._name.len() as u32).to_le_bytes()); // 添加 name 长度
data.extend_from_slice(self._name.as_bytes()); // 添加 name 内容
// 添加 symbol 字符串长度和内容
data.extend_from_slice(&(self._symbol.len() as u32).to_le_bytes()); // 添加 symbol 长度
data.extend_from_slice(self._symbol.as_bytes()); // 添加 symbol 内容
// 添加 uri 字符串长度和内容
data.extend_from_slice(&(self._uri.len() as u32).to_le_bytes()); // 添加 uri 长度
data.extend_from_slice(self._uri.as_bytes()); // 添加 uri 内容
data.extend_from_slice(&self._creator.to_bytes());
data
}
}
pub struct Buy {
pub _amount: u64,
pub _max_sol_cost: u64,
}
impl Buy {
pub fn data(&self) -> Vec<u8> {
let mut data = Vec::with_capacity(8 + 8 + 8);
data.extend_from_slice(&[102, 6, 61, 18, 1, 218, 235, 234]); // discriminator
data.extend_from_slice(&self._amount.to_le_bytes());
data.extend_from_slice(&self._max_sol_cost.to_le_bytes());
data
}
}
pub struct Sell {
pub _amount: u64,
pub _min_sol_output: u64,
}
impl Sell {
pub fn data(&self) -> Vec<u8> {
let mut data = Vec::with_capacity(8 + 8 + 8);
data.extend_from_slice(&[51, 230, 133, 164, 1, 127, 131, 173]); // discriminator
data.extend_from_slice(&self._amount.to_le_bytes());
data.extend_from_slice(&self._min_sol_output.to_le_bytes());
data
}
}
pub fn create(payer: &Keypair, mint: &Keypair, args: Create) -> Instruction {
let bonding_curve: Pubkey = get_bonding_curve_pda(&mint.pubkey()).unwrap();
Instruction::new_with_bytes(
constants::pumpfun::accounts::PUMPFUN,
&args.data(),
vec![
AccountMeta::new(mint.pubkey(), true),
AccountMeta::new(get_mint_authority_pda(), false),
AccountMeta::new(bonding_curve, false),
AccountMeta::new(
get_associated_token_address(&bonding_curve, &mint.pubkey()),
false,
),
AccountMeta::new_readonly(get_global_pda(), false),
AccountMeta::new_readonly(constants::pumpfun::accounts::MPL_TOKEN_METADATA, false),
AccountMeta::new(get_metadata_pda(&mint.pubkey()), false),
AccountMeta::new(payer.pubkey(), true),
AccountMeta::new_readonly(constants::pumpfun::accounts::SYSTEM_PROGRAM, false),
AccountMeta::new_readonly(constants::pumpfun::accounts::TOKEN_PROGRAM, false),
AccountMeta::new_readonly(constants::pumpfun::accounts::ASSOCIATED_TOKEN_PROGRAM, false),
AccountMeta::new_readonly(constants::pumpfun::accounts::RENT, false),
AccountMeta::new_readonly(constants::pumpfun::accounts::EVENT_AUTHORITY, false),
AccountMeta::new_readonly(constants::pumpfun::accounts::PUMPFUN, false),
],
)
}
pub fn buy(
payer: &Keypair,
mint: &Pubkey,
bonding_curve_pda: &Pubkey,
creator_vault_pda: &Pubkey,
fee_recipient: &Pubkey,
args: Buy,
) -> Instruction {
Instruction::new_with_bytes(
constants::pumpfun::accounts::PUMPFUN,
&args.data(),
vec![
AccountMeta::new_readonly(constants::pumpfun::global_constants::GLOBAL_ACCOUNT, false),
AccountMeta::new(*fee_recipient, false),
AccountMeta::new_readonly(*mint, false),
AccountMeta::new(*bonding_curve_pda, false),
AccountMeta::new(get_associated_token_address(bonding_curve_pda, mint), false),
AccountMeta::new(get_associated_token_address(&payer.pubkey(), mint), false),
AccountMeta::new(payer.pubkey(), true),
AccountMeta::new_readonly(constants::pumpfun::accounts::SYSTEM_PROGRAM, false),
AccountMeta::new_readonly(constants::pumpfun::accounts::TOKEN_PROGRAM, false),
AccountMeta::new(*creator_vault_pda, false),
AccountMeta::new_readonly(constants::pumpfun::accounts::EVENT_AUTHORITY, false),
AccountMeta::new_readonly(constants::pumpfun::accounts::PUMPFUN, false),
],
)
}
pub fn sell(
payer: &Keypair,
mint: &Pubkey,
creator_vault_pda: &Pubkey,
fee_recipient: &Pubkey,
args: Sell,
) -> Instruction {
let bonding_curve: Pubkey = get_bonding_curve_pda(mint).unwrap();
Instruction::new_with_bytes(
constants::pumpfun::accounts::PUMPFUN,
&args.data(),
vec![
AccountMeta::new_readonly(constants::pumpfun::global_constants::GLOBAL_ACCOUNT, false),
AccountMeta::new(*fee_recipient, false),
AccountMeta::new_readonly(*mint, false),
AccountMeta::new(bonding_curve, false),
AccountMeta::new(get_associated_token_address(&bonding_curve, mint), false),
AccountMeta::new(get_associated_token_address(&payer.pubkey(), mint), false),
AccountMeta::new(payer.pubkey(), true),
AccountMeta::new_readonly(constants::pumpfun::accounts::SYSTEM_PROGRAM, false),
AccountMeta::new(*creator_vault_pda, false),
AccountMeta::new_readonly(constants::pumpfun::accounts::TOKEN_PROGRAM, false),
AccountMeta::new_readonly(constants::pumpfun::accounts::EVENT_AUTHORITY, false),
AccountMeta::new_readonly(constants::pumpfun::accounts::PUMPFUN, false),
],
)
}
@@ -1,13 +1,12 @@
use anyhow::{anyhow, Result};
use solana_sdk::{instruction::Instruction, pubkey::Pubkey, signer::Signer};
use spl_associated_token_account::instruction::create_associated_token_account_idempotent;
use std::sync::Arc;
use crate::{
constants::pumpswap::{
accounts, trade::DEFAULT_SLIPPAGE, BUY_DISCRIMINATOR, SELL_DISCRIMINATOR,
},
pumpswap::common::{
trading::pumpswap::common::{
calculate_with_slippage_buy, calculate_with_slippage_sell, coin_creator_vault_ata,
coin_creator_vault_authority, find_pool, get_buy_token_amount, get_sell_sol_amount,
get_token_balance,
+33 -36
View File
@@ -6,9 +6,6 @@ pub mod event_parser;
pub mod grpc;
pub mod instruction;
pub mod protos;
pub mod pumpfun;
pub mod pumpswap;
pub mod bonk;
pub mod swqos;
pub mod trading;
@@ -141,7 +138,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<PumpFunParams>()
{
pumpfun::buy::buy(
trading::pumpfun::buy::buy(
self.rpc.clone(),
self.payer.clone(),
mint,
@@ -160,7 +157,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<PumpSwapParams>()
{
pumpswap::buy::buy(
trading::pumpswap::buy::buy(
self.rpc.clone(),
self.payer.clone(),
mint,
@@ -183,7 +180,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<BonkParams>()
{
bonk::buy::buy(
trading::bonk::buy::buy(
self.rpc.clone(),
self.payer.clone(),
mint,
@@ -229,7 +226,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<PumpFunParams>()
{
pumpfun::buy::buy_with_tip(
trading::pumpfun::buy::buy_with_tip(
self.swqos_clients.clone(),
self.payer.clone(),
mint,
@@ -248,7 +245,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<PumpSwapParams>()
{
pumpswap::buy::buy_with_tip(
trading::pumpswap::buy::buy_with_tip(
self.rpc.clone(),
self.swqos_clients.clone(),
self.payer.clone(),
@@ -272,7 +269,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<BonkParams>()
{
bonk::buy::buy(
trading::bonk::buy::buy(
self.rpc.clone(),
self.payer.clone(),
mint,
@@ -308,7 +305,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<PumpFunSellParams>()
{
pumpfun::sell::sell_by_percent(
trading::pumpfun::sell::sell_by_percent(
self.rpc.clone(),
self.payer.clone(),
mint.clone(),
@@ -325,7 +322,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<PumpSwapParams>()
{
pumpswap::sell::sell_by_percent(
trading::pumpswap::sell::sell_by_percent(
self.rpc.clone(),
self.payer.clone(),
mint.clone(),
@@ -347,7 +344,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<BonkParams>()
{
bonk::sell::sell_by_percent(
trading::bonk::sell::sell_by_percent(
self.rpc.clone(),
self.payer.clone(),
mint.clone(),
@@ -381,7 +378,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<PumpFunSellParams>()
{
pumpfun::sell::sell_by_amount(
trading::pumpfun::sell::sell_by_amount(
self.rpc.clone(),
self.payer.clone(),
mint.clone(),
@@ -397,7 +394,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<PumpSwapParams>()
{
pumpswap::sell::sell_by_amount(
trading::pumpswap::sell::sell_by_amount(
self.rpc.clone(),
self.payer.clone(),
mint.clone(),
@@ -419,7 +416,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<BonkParams>()
{
bonk::sell::sell_by_amount(
trading::bonk::sell::sell_by_amount(
self.rpc.clone(),
self.payer.clone(),
mint.clone(),
@@ -453,7 +450,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<PumpFunSellParams>()
{
pumpfun::sell::sell_by_percent_with_tip(
trading::pumpfun::sell::sell_by_percent_with_tip(
self.rpc.clone(),
self.swqos_clients.clone(),
self.payer.clone(),
@@ -471,7 +468,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<PumpSwapParams>()
{
pumpswap::sell::sell_by_percent_with_tip(
trading::pumpswap::sell::sell_by_percent_with_tip(
self.rpc.clone(),
self.swqos_clients.clone(),
self.payer.clone(),
@@ -494,7 +491,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<BonkParams>()
{
bonk::sell::sell_by_percent_with_tip(
trading::bonk::sell::sell_by_percent_with_tip(
self.rpc.clone(),
self.swqos_clients.clone(),
self.payer.clone(),
@@ -528,7 +525,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<PumpFunSellParams>()
{
pumpfun::sell::sell_by_amount_with_tip(
trading::pumpfun::sell::sell_by_amount_with_tip(
self.rpc.clone(),
self.swqos_clients.clone(),
self.payer.clone(),
@@ -545,7 +542,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<PumpSwapParams>()
{
pumpswap::sell::sell_by_amount_with_tip(
trading::pumpswap::sell::sell_by_amount_with_tip(
self.rpc.clone(),
self.swqos_clients.clone(),
self.payer.clone(),
@@ -568,7 +565,7 @@ impl SolanaTrade {
.as_any()
.downcast_ref::<BonkParams>()
{
bonk::sell::sell_by_amount_with_tip(
trading::bonk::sell::sell_by_amount_with_tip(
self.rpc.clone(),
self.swqos_clients.clone(),
self.payer.clone(),
@@ -591,12 +588,12 @@ impl SolanaTrade {
#[inline]
pub async fn get_sol_balance(&self, payer: &Pubkey) -> Result<u64, anyhow::Error> {
pumpfun::common::get_sol_balance(&self.rpc, payer).await
trading::pumpfun::common::get_sol_balance(&self.rpc, payer).await
}
#[inline]
pub async fn get_payer_sol_balance(&self) -> Result<u64, anyhow::Error> {
pumpfun::common::get_sol_balance(&self.rpc, &self.payer.pubkey()).await
trading::pumpfun::common::get_sol_balance(&self.rpc, &self.payer.pubkey()).await
}
#[inline]
@@ -609,12 +606,12 @@ impl SolanaTrade {
"get_token_balance payer: {}, mint: {}, rpc_url: {}",
payer, mint, self.trade_config.rpc_url
);
pumpfun::common::get_token_balance(&self.rpc, payer, mint).await
trading::pumpfun::common::get_token_balance(&self.rpc, payer, mint).await
}
#[inline]
pub async fn get_payer_token_balance(&self, mint: &Pubkey) -> Result<u64, anyhow::Error> {
pumpfun::common::get_token_balance(&self.rpc, &self.payer.pubkey(), mint).await
trading::pumpfun::common::get_token_balance(&self.rpc, &self.payer.pubkey(), mint).await
}
#[inline]
@@ -629,12 +626,12 @@ impl SolanaTrade {
#[inline]
pub fn get_token_price(&self, virtual_sol_reserves: u64, virtual_token_reserves: u64) -> f64 {
pumpfun::common::get_token_price(virtual_sol_reserves, virtual_token_reserves)
trading::pumpfun::common::get_token_price(virtual_sol_reserves, virtual_token_reserves)
}
#[inline]
pub fn get_buy_price(&self, amount: u64, trade_info: &PumpFunTradeEvent) -> u64 {
pumpfun::common::get_buy_price(amount, trade_info)
trading::pumpfun::common::get_buy_price(amount, trade_info)
}
#[inline]
@@ -644,23 +641,23 @@ impl SolanaTrade {
receive_wallet: &Pubkey,
amount: u64,
) -> Result<(), anyhow::Error> {
pumpfun::common::transfer_sol(&self.rpc, payer, receive_wallet, amount).await
trading::pumpfun::common::transfer_sol(&self.rpc, payer, receive_wallet, amount).await
}
#[inline]
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
trading::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?;
trading::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(
Ok(trading::pumpfun::common::get_token_price(
virtual_sol_reserves,
virtual_token_reserves,
))
@@ -669,7 +666,7 @@ impl SolanaTrade {
#[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?;
trading::pumpfun::common::get_bonding_curve_account_v2(&self.rpc, mint).await?;
let actual_sol_reserves = bonding_curve.real_sol_reserves;
@@ -679,7 +676,7 @@ impl SolanaTrade {
#[inline]
pub async fn get_creator(&self, mint: &Pubkey) -> Result<Pubkey, anyhow::Error> {
let (bonding_curve, _) =
pumpfun::common::get_bonding_curve_account_v2(&self.rpc, mint).await?;
trading::pumpfun::common::get_bonding_curve_account_v2(&self.rpc, mint).await?;
let creator = bonding_curve.creator;
@@ -691,7 +688,7 @@ impl SolanaTrade {
&self,
pool_address: &Pubkey,
) -> Result<f64, anyhow::Error> {
let pool = pumpswap::pool::Pool::fetch(&self.rpc, pool_address).await?;
let pool = trading::pumpswap::pool::Pool::fetch(&self.rpc, pool_address).await?;
let (base_amount, quote_amount) = pool.get_token_balances(&self.rpc).await?;
@@ -713,7 +710,7 @@ impl SolanaTrade {
&self,
pool_address: &Pubkey,
) -> Result<u64, anyhow::Error> {
let pool = pumpswap::pool::Pool::fetch(&self.rpc, pool_address).await?;
let pool = trading::pumpswap::pool::Pool::fetch(&self.rpc, pool_address).await?;
let (_, quote_amount) = pool.get_token_balances(&self.rpc).await?;
@@ -725,7 +722,7 @@ impl SolanaTrade {
&self,
pool_address: &Pubkey,
) -> Result<u64, anyhow::Error> {
let pool = pumpswap::pool::Pool::fetch(&self.rpc, pool_address).await?;
let pool = trading::pumpswap::pool::Pool::fetch(&self.rpc, pool_address).await?;
let (base_amount, _) = pool.get_token_balances(&self.rpc).await?;
+1 -2
View File
@@ -1,11 +1,10 @@
use anyhow::{anyhow, Result};
use std::sync::Arc;
use crate::trading::protocols::bonk::BonkInstructionBuilder;
use crate::instruction::{bonk::BonkInstructionBuilder, pumpfun::PumpFunInstructionBuilder, pumpswap::PumpSwapInstructionBuilder};
use super::{
core::{executor::GenericTradeExecutor, traits::TradeExecutor},
protocols::{pumpfun::PumpFunInstructionBuilder, pumpswap::PumpSwapInstructionBuilder},
};
/// 支持的交易协议
+3 -1
View File
@@ -1,7 +1,9 @@
pub mod common;
pub mod core;
pub mod factory;
pub mod protocols;
pub mod bonk;
pub mod pumpfun;
pub mod pumpswap;
pub use core::params::{BuyParams, BuyWithTipParams, SellParams, SellWithTipParams};
pub use core::traits::{InstructionBuilder, TradeExecutor};
-3
View File
@@ -1,3 +0,0 @@
pub mod pumpfun;
pub mod pumpswap;
pub mod bonk;
-144
View File
@@ -1,144 +0,0 @@
use anyhow::{anyhow, Result};
use solana_sdk::{
instruction::Instruction, native_token::sol_to_lamports, pubkey::Pubkey, signer::Signer,
};
use spl_associated_token_account::{
get_associated_token_address, instruction::create_associated_token_account,
};
use spl_token::instruction::close_account;
use std::sync::Arc;
use crate::{
accounts::BondingCurveAccount,
constants::{self, pumpfun::{global_constants::FEE_RECIPIENT, trade::DEFAULT_SLIPPAGE}, trade_type::SNIPER_BUY},
instruction,
pumpfun::common::{
calculate_with_slippage_buy, get_bonding_curve_account_v2, get_bonding_curve_pda,
get_buy_token_amount_from_sol_amount, get_creator_vault_pda, init_bonding_curve_account,
},
trading::core::{
params::{BuyParams, PumpFunParams, SellParams},
traits::InstructionBuilder,
},
};
/// PumpFun协议的指令构建器
pub struct PumpFunInstructionBuilder;
#[async_trait::async_trait]
impl InstructionBuilder for PumpFunInstructionBuilder {
async fn build_buy_instructions(&self, params: &BuyParams) -> Result<Vec<Instruction>> {
// 获取PumpFun特定参数
let protocol_params = params
.protocol_params
.as_any()
.downcast_ref::<PumpFunParams>()
.ok_or_else(|| anyhow!("Invalid protocol params for PumpFun"))?;
if params.amount_sol == 0 {
return Err(anyhow!("Amount cannot be zero"));
}
let bonding_curve = if protocol_params.bonding_curve.is_some() {
protocol_params.bonding_curve.clone().unwrap()
} else {
return Err(anyhow!("Bonding curve not found"));
};
let max_sol_cost = calculate_with_slippage_buy(
params.amount_sol,
params
.slippage_basis_points
.unwrap_or(DEFAULT_SLIPPAGE),
);
let creator_vault_pda = bonding_curve.get_creator_vault_pda();
let mut buy_token_amount =
get_buy_token_amount_from_sol_amount(&bonding_curve, params.amount_sol);
if buy_token_amount <= 100 * 1_000_000_u64 {
buy_token_amount = if max_sol_cost > sol_to_lamports(0.01) {
25547619 * 1_000_000_u64
} else {
255476 * 1_000_000_u64
};
}
let mut instructions = vec![];
// 创建关联代币账户
instructions.push(create_associated_token_account(
&params.payer.pubkey(),
&params.payer.pubkey(),
&params.mint,
&constants::pumpfun::accounts::TOKEN_PROGRAM,
));
// 创建买入指令
instructions.push(instruction::buy(
params.payer.as_ref(),
&params.mint,
&bonding_curve.account,
&creator_vault_pda,
&FEE_RECIPIENT,
instruction::Buy {
_amount: buy_token_amount,
_max_sol_cost: max_sol_cost,
},
));
Ok(instructions)
}
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
let amount_token = if let Some(amount) = params.amount_token {
if amount == 0 {
return Err(anyhow!("Amount cannot be zero"));
}
amount
} else {
return Err(anyhow!("Amount token is required"));
};
let creator_vault_pda = get_creator_vault_pda(&params.creator).unwrap();
let ata = get_associated_token_address(&params.payer.pubkey(), &params.mint);
// 获取代币余额
let balance_u64 = if let Some(rpc) = &params.rpc {
let balance = rpc.get_token_account_balance(&ata).await?;
balance
.amount
.parse::<u64>()
.map_err(|_| anyhow!("Failed to parse token balance"))?
} else {
return Err(anyhow!("RPC client is required to get token balance"));
};
let mut amount_token = amount_token;
if amount_token > balance_u64 {
amount_token = balance_u64;
}
let mut instructions = vec![instruction::sell(
params.payer.as_ref(),
&params.mint,
&creator_vault_pda,
&FEE_RECIPIENT,
instruction::Sell {
_amount: amount_token,
_min_sol_output: 1,
},
)];
// 如果卖出全部代币,关闭账户
if amount_token >= balance_u64 {
instructions.push(close_account(
&spl_token::ID,
&ata,
&params.payer.pubkey(),
&params.payer.pubkey(),
&[&params.payer.pubkey()],
)?);
}
Ok(instructions)
}
}
@@ -4,6 +4,7 @@ use solana_sdk::{
signature::{Keypair, Signer},
};
use crate::common::SolanaRpcClient;
use crate::trading::pumpswap;
// Calculate slippage for buy operations
pub fn calculate_with_slippage_buy(amount: u64, basis_points: u64) -> u64 {
@@ -41,7 +42,7 @@ pub async fn find_pool(
rpc: &SolanaRpcClient,
mint: &Pubkey,
) -> Result<Pubkey, anyhow::Error> {
let (pool_address, _) = crate::pumpswap::pool::Pool::find_by_mint(rpc, mint).await?;
let (pool_address, _) = pumpswap::pool::Pool::find_by_mint(rpc, mint).await?;
Ok(pool_address)
}
@@ -51,7 +52,7 @@ pub async fn get_buy_token_amount(
pool: &Pubkey,
sol_amount: u64,
) -> Result<u64, anyhow::Error> {
let pool_data = crate::pumpswap::pool::Pool::fetch(rpc, pool).await?;
let pool_data = pumpswap::pool::Pool::fetch(rpc, pool).await?;
pool_data.calculate_buy_amount(rpc, sol_amount).await
}
@@ -61,7 +62,7 @@ pub async fn get_sell_sol_amount(
pool: &Pubkey,
token_amount: u64,
) -> Result<u64, anyhow::Error> {
let pool_data = crate::pumpswap::pool::Pool::fetch(rpc, pool).await?;
let pool_data = pumpswap::pool::Pool::fetch(rpc, pool).await?;
pool_data.calculate_sell_amount(rpc, token_amount).await
}
@@ -4,8 +4,8 @@ use solana_sdk::{pubkey::Pubkey, signature::Keypair};
use std::sync::Arc;
use crate::common::{PriorityFee, SolanaRpcClient};
use crate::pumpswap::common::get_token_balance;
use crate::swqos::SwqosClient;
use crate::trading::pumpswap::common::get_token_balance;
use crate::trading::{core::params::PumpSwapParams, factory::Protocol, SellParams, TradeFactory};
// Sell tokens to a Pumpswap pool