rebuild sdk dir
This commit is contained in:
Executable
+107
@@ -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(())
|
||||
}
|
||||
Executable
+75
@@ -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)
|
||||
}
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
pub mod buy;
|
||||
pub mod sell;
|
||||
pub mod common;
|
||||
pub mod pool;
|
||||
Executable
+62
@@ -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)
|
||||
}
|
||||
}
|
||||
Executable
+240
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user