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
+107
View File
@@ -0,0 +1,107 @@
use solana_hash::Hash;
use solana_sdk::{pubkey::Pubkey, signature::Keypair};
use std::sync::Arc;
use crate::swqos::SwqosClient;
use crate::trading::{
core::params::{PumpSwapParams, BonkParams},
factory::Protocol,
BuyParams, TradeFactory,
};
use crate::{common::PriorityFee, SolanaRpcClient};
// Constants for compute budget
// Increased from 64KB to 256KB to handle larger transactions
const MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT: u32 = 256 * 1024;
// Buy tokens from a Pumpswap pool
pub async fn buy(
rpc: Arc<SolanaRpcClient>,
payer: Arc<Keypair>,
mint: Pubkey,
virtual_base: u128,
virtual_quote: u128,
real_base_before: u128,
real_quote_before: u128,
amount_sol: u64,
slippage_basis_points: Option<u64>,
priority_fee: PriorityFee,
lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
auto_handle_wsol: bool,
) -> Result<(), anyhow::Error> {
// 创建执行器
let executor = TradeFactory::create_executor(Protocol::Bonk);
// 创建协议特定参数
let protocol_params = Box::new(BonkParams {
auto_handle_wsol: auto_handle_wsol,
virtual_base: Some(virtual_base),
virtual_quote: Some(virtual_quote),
real_base_before: Some(real_base_before),
real_quote_before: Some(real_quote_before),
});
// 创建买入参数
let buy_params = BuyParams {
rpc: Some(rpc.clone()),
payer: payer,
mint: mint,
creator: Pubkey::default(),
amount_sol: amount_sol,
slippage_basis_points: slippage_basis_points,
priority_fee: priority_fee,
lookup_table_key: lookup_table_key,
recent_blockhash: recent_blockhash,
data_size_limit: MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT,
protocol_params,
};
// 执行买入
executor.buy(buy_params).await?;
Ok(())
}
// Buy tokens using a MEV service
pub async fn buy_with_tip(
rpc: Arc<SolanaRpcClient>,
swqos_clients: Vec<Arc<SwqosClient>>,
payer: Arc<Keypair>,
mint: Pubkey,
virtual_base: u128,
virtual_quote: u128,
real_base_before: u128,
real_quote_before: u128,
amount_sol: u64,
slippage_basis_points: Option<u64>,
priority_fee: PriorityFee,
lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
auto_handle_wsol: bool,
) -> Result<(), anyhow::Error> {
// 创建执行器
let executor = TradeFactory::create_executor(Protocol::Bonk);
// 创建协议特定参数
let protocol_params = Box::new(BonkParams {
auto_handle_wsol: auto_handle_wsol,
virtual_base: Some(virtual_base),
virtual_quote: Some(virtual_quote),
real_base_before: Some(real_base_before),
real_quote_before: Some(real_quote_before),
});
// 创建买入参数
let buy_params = BuyParams {
rpc: Some(rpc.clone()),
payer: payer,
mint: mint,
creator: Pubkey::default(),
amount_sol: amount_sol,
slippage_basis_points: slippage_basis_points,
priority_fee: priority_fee,
lookup_table_key: lookup_table_key,
recent_blockhash: recent_blockhash,
data_size_limit: MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT,
protocol_params,
};
let buy_with_tip_params = buy_params.with_tip(swqos_clients);
// 执行买入
executor.buy_with_tip(buy_with_tip_params).await?;
Ok(())
}
+75
View File
@@ -0,0 +1,75 @@
use anyhow::anyhow;
use solana_sdk::pubkey::Pubkey;
use spl_associated_token_account::get_associated_token_address;
use crate::{common::SolanaRpcClient, constants};
pub fn get_amount_out(
amount_in: u64,
protocol_fee_rate: u128,
platform_fee_rate: u128,
share_fee_rate: u128,
virtual_base: u128,
virtual_quote: u128,
real_base_before: u128,
real_quote_before: u128,
slippage_basis_points: u128,
) -> u64 {
let amount_in_u128 = amount_in as u128;
let protocol_fee = (amount_in_u128 * protocol_fee_rate / 10000) as u128;
let platform_fee = (amount_in_u128 * platform_fee_rate / 10000) as u128;
let share_fee = (amount_in_u128 * share_fee_rate / 10000) as u128;
let amount_in_net = amount_in_u128
.checked_sub(protocol_fee)
.unwrap()
.checked_sub(platform_fee)
.unwrap()
.checked_sub(share_fee)
.unwrap();
let input_reserve = virtual_quote.checked_add(real_quote_before).unwrap();
let output_reserve = virtual_base.checked_sub(real_base_before).unwrap();
let numerator = amount_in_net.checked_mul(output_reserve).unwrap();
let denominator = input_reserve.checked_add(amount_in_net).unwrap();
let mut amount_out = numerator.checked_div(denominator).unwrap();
amount_out = amount_out - (amount_out * slippage_basis_points) / 10000;
amount_out as u64
}
pub fn get_pool_pda(base_mint: &Pubkey, quote_mint: &Pubkey) -> Option<Pubkey> {
let seeds: &[&[u8]; 3] = &[
constants::bonk::seeds::POOL_SEED,
base_mint.as_ref(),
quote_mint.as_ref(),
];
let program_id: &Pubkey = &constants::bonk::accounts::BONK;
let pda: Option<(Pubkey, u8)> = Pubkey::try_find_program_address(seeds, program_id);
pda.map(|pubkey| pubkey.0)
}
pub fn get_vault_pda(pool_state: &Pubkey, mint: &Pubkey) -> Option<Pubkey> {
let seeds: &[&[u8]; 3] = &[
constants::bonk::seeds::POOL_VAULT_SEED,
pool_state.as_ref(),
mint.as_ref(),
];
let program_id: &Pubkey = &constants::bonk::accounts::BONK;
let pda: Option<(Pubkey, u8)> = Pubkey::try_find_program_address(seeds, program_id);
pda.map(|pubkey| pubkey.0)
}
pub async fn get_token_balance(
rpc: &SolanaRpcClient,
payer: &Pubkey,
mint: &Pubkey,
) -> Result<u64, anyhow::Error> {
println!("payer: {:?}", payer);
println!("mint: {:?}", mint);
let ata = get_associated_token_address(payer, mint);
let balance = rpc.get_token_account_balance(&ata).await?;
let balance_u64 = balance
.amount
.parse::<u64>()
.map_err(|_| anyhow!("Failed to parse token balance"))?;
Ok(balance_u64)
}
+4
View File
@@ -0,0 +1,4 @@
pub mod buy;
pub mod sell;
pub mod common;
pub mod pool;
+62
View File
@@ -0,0 +1,62 @@
use crate::{common::SolanaRpcClient, constants::bonk::accounts};
use anyhow::anyhow;
use borsh::BorshDeserialize;
use solana_sdk::pubkey::Pubkey;
#[derive(Debug, Clone, BorshDeserialize)]
pub struct VestingSchedule {
pub total_locked_amount: u64,
pub cliff_period: u64,
pub unlock_period: u64,
pub start_time: u64,
pub allocated_share_amount: u64,
}
#[derive(Debug, Clone, BorshDeserialize)]
pub struct Pool {
pub epoch: u64,
pub auth_bump: u8,
pub status: u8,
pub base_decimals: u8,
pub quote_decimals: u8,
pub migrate_type: u8,
pub supply: u64,
pub total_base_sell: u64,
pub virtual_base: u64,
pub virtual_quote: u64,
pub real_base: u64,
pub real_quote: u64,
pub total_quote_fund_raising: u64,
pub quote_protocol_fee: u64,
pub platform_fee: u64,
pub migrate_fee: u64,
pub vesting_schedule: VestingSchedule,
pub global_config: Pubkey,
pub platform_config: Pubkey,
pub base_mint: Pubkey,
pub quote_mint: Pubkey,
pub base_vault: Pubkey,
pub quote_vault: Pubkey,
pub creator: Pubkey,
pub padding: [u64; 8],
}
impl Pool {
pub fn from_bytes(data: &[u8]) -> Result<Self, anyhow::Error> {
let pool = Pool::try_from_slice(&data[8..])?;
Ok(pool)
}
pub async fn fetch(
rpc: &SolanaRpcClient,
pool_address: &Pubkey,
) -> Result<Self, anyhow::Error> {
let account = rpc.get_account(pool_address).await?;
if account.owner != accounts::BONK {
return Err(anyhow!("Account is not owned by Bonk program"));
}
Self::from_bytes(&account.data)
}
}
+240
View File
@@ -0,0 +1,240 @@
use anyhow::anyhow;
use solana_hash::Hash;
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::{
core::params::BonkParams, factory::Protocol, SellParams, TradeFactory,
};
// Sell tokens to a Pumpswap pool
pub async fn sell(
rpc: Arc<SolanaRpcClient>,
payer: Arc<Keypair>,
mint: Pubkey,
virtual_base: u128,
virtual_quote: u128,
real_base_before: u128,
real_quote_before: u128,
amount_token: Option<u64>,
slippage_basis_points: Option<u64>,
priority_fee: PriorityFee,
lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
) -> Result<(), anyhow::Error> {
let executor = TradeFactory::create_executor(Protocol::Bonk);
// 创建PumpFun协议参数
let protocol_params = Box::new(BonkParams {
virtual_base: Some(virtual_base),
virtual_quote: Some(virtual_quote),
real_base_before: Some(real_base_before),
real_quote_before: Some(real_quote_before),
auto_handle_wsol: true,
});
// 创建卖出参数
let sell_params = SellParams {
rpc: Some(rpc.clone()),
payer: payer.clone(),
mint,
creator: Pubkey::default(),
amount_token: amount_token,
slippage_basis_points: slippage_basis_points,
priority_fee: priority_fee.clone(),
lookup_table_key,
recent_blockhash,
protocol_params,
};
// 执行卖出交易
executor.sell(sell_params).await?;
Ok(())
}
// Sell tokens by percentage
pub async fn sell_by_percent(
rpc: Arc<SolanaRpcClient>,
payer: Arc<Keypair>,
mint: Pubkey,
virtual_base: u128,
virtual_quote: u128,
real_base_before: u128,
real_quote_before: u128,
percent: u64,
slippage_basis_points: Option<u64>,
priority_fee: PriorityFee,
lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
) -> Result<(), anyhow::Error> {
if percent == 0 || percent > 100 {
return Err(anyhow!("Percentage must be between 1 and 100"));
}
let (balance_u64, _) = get_token_balance(rpc.as_ref(), payer.as_ref(), &mint).await?;
let amount = balance_u64 * percent / 100;
sell(
rpc,
payer,
mint,
virtual_base,
virtual_quote,
real_base_before,
real_quote_before,
Some(amount),
slippage_basis_points,
priority_fee,
lookup_table_key,
recent_blockhash,
)
.await
}
/// Sell tokens by amount
pub async fn sell_by_amount(
rpc: Arc<SolanaRpcClient>,
payer: Arc<Keypair>,
mint: Pubkey,
virtual_base: u128,
virtual_quote: u128,
real_base_before: u128,
real_quote_before: u128,
amount: u64,
slippage_basis_points: Option<u64>,
priority_fee: PriorityFee,
lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
) -> Result<(), anyhow::Error> {
sell(
rpc,
payer,
mint,
virtual_base,
virtual_quote,
real_base_before,
real_quote_before,
Some(amount),
slippage_basis_points,
priority_fee,
lookup_table_key,
recent_blockhash,
)
.await
}
// Sell tokens using a MEV service
pub async fn sell_with_tip(
rpc: Arc<SolanaRpcClient>,
swqos_clients: Vec<Arc<SwqosClient>>,
payer: Arc<Keypair>,
mint: Pubkey,
virtual_base: u128,
virtual_quote: u128,
real_base_before: u128,
real_quote_before: u128,
amount_token: Option<u64>,
slippage_basis_points: Option<u64>,
priority_fee: PriorityFee,
lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
) -> Result<(), anyhow::Error> {
let executor = TradeFactory::create_executor(Protocol::Bonk);
// 创建PumpFun协议参数
let protocol_params = Box::new(BonkParams {
virtual_base: Some(virtual_base),
virtual_quote: Some(virtual_quote),
real_base_before: Some(real_base_before),
real_quote_before: Some(real_quote_before),
auto_handle_wsol: true,
});
// 创建卖出参数
let sell_params = SellParams {
rpc: Some(rpc.clone()),
payer: payer.clone(),
mint,
creator: Pubkey::default(),
amount_token: amount_token,
slippage_basis_points: slippage_basis_points,
priority_fee: priority_fee.clone(),
lookup_table_key,
recent_blockhash,
protocol_params,
};
let sell_with_tip_params = sell_params.with_tip(swqos_clients);
// 执行卖出交易
executor.sell_with_tip(sell_with_tip_params).await?;
Ok(())
}
// Sell tokens by percentage using a MEV service
pub async fn sell_by_percent_with_tip(
rpc: Arc<SolanaRpcClient>,
swqos_clients: Vec<Arc<SwqosClient>>,
payer: Arc<Keypair>,
mint: Pubkey,
virtual_base: u128,
virtual_quote: u128,
real_base_before: u128,
real_quote_before: u128,
percent: u64,
slippage_basis_points: Option<u64>,
priority_fee: PriorityFee,
lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
) -> Result<(), anyhow::Error> {
if percent == 0 || percent > 100 {
return Err(anyhow!("Percentage must be between 1 and 100"));
}
let (balance_u64, _) = get_token_balance(rpc.as_ref(), payer.as_ref(), &mint).await?;
let amount = balance_u64 * percent / 100;
sell_with_tip(
rpc,
swqos_clients,
payer,
mint,
virtual_base,
virtual_quote,
real_base_before,
real_quote_before,
Some(amount),
slippage_basis_points,
priority_fee,
lookup_table_key,
recent_blockhash,
)
.await
}
// Sell tokens by amount using a MEV service
pub async fn sell_by_amount_with_tip(
rpc: Arc<SolanaRpcClient>,
swqos_clients: Vec<Arc<SwqosClient>>,
payer: Arc<Keypair>,
mint: Pubkey,
virtual_base: u128,
virtual_quote: u128,
real_base_before: u128,
real_quote_before: u128,
amount: u64,
slippage_basis_points: Option<u64>,
priority_fee: PriorityFee,
lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
) -> Result<(), anyhow::Error> {
sell_with_tip(
rpc,
swqos_clients,
payer,
mint,
virtual_base,
virtual_quote,
real_base_before,
real_quote_before,
Some(amount),
slippage_basis_points,
priority_fee,
lookup_table_key,
recent_blockhash,
)
.await
}