rebuild sdk dir
This commit is contained in:
@@ -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,
|
||||
},
|
||||
@@ -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,
|
||||
|
||||
Executable
+298
@@ -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(
|
||||
¶ms.payer.pubkey(),
|
||||
¶ms.payer.pubkey(),
|
||||
¶ms.mint,
|
||||
&constants::pumpfun::accounts::TOKEN_PROGRAM,
|
||||
));
|
||||
|
||||
// 创建买入指令
|
||||
instructions.push(buy(
|
||||
params.payer.as_ref(),
|
||||
¶ms.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(¶ms.creator).unwrap();
|
||||
let ata = get_associated_token_address(¶ms.payer.pubkey(), ¶ms.mint);
|
||||
|
||||
// 获取代币余额
|
||||
let balance_u64 = if let Some(rpc) = ¶ms.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(),
|
||||
¶ms.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,
|
||||
¶ms.payer.pubkey(),
|
||||
¶ms.payer.pubkey(),
|
||||
&[¶ms.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
@@ -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,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
@@ -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};
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
pub mod pumpfun;
|
||||
pub mod pumpswap;
|
||||
pub mod bonk;
|
||||
@@ -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(
|
||||
¶ms.payer.pubkey(),
|
||||
¶ms.payer.pubkey(),
|
||||
¶ms.mint,
|
||||
&constants::pumpfun::accounts::TOKEN_PROGRAM,
|
||||
));
|
||||
|
||||
// 创建买入指令
|
||||
instructions.push(instruction::buy(
|
||||
params.payer.as_ref(),
|
||||
¶ms.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(¶ms.creator).unwrap();
|
||||
let ata = get_associated_token_address(¶ms.payer.pubkey(), ¶ms.mint);
|
||||
|
||||
// 获取代币余额
|
||||
let balance_u64 = if let Some(rpc) = ¶ms.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(),
|
||||
¶ms.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,
|
||||
¶ms.payer.pubkey(),
|
||||
¶ms.payer.pubkey(),
|
||||
&[¶ms.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
|
||||
Reference in New Issue
Block a user