refactor: Major SDK architecture refactoring and API consolidation
- Consolidate separate buy/sell modules into unified trading interface - Remove protocol-specific buy/sell files (bonk, pumpfun, pumpswap) - Add new trading constants and utility functions - Simplify API with unified buy/sell methods supporting multiple protocols - Enhance documentation with comprehensive examples and usage guides - Add balance checking and token account management utilities - Improve code organization and maintainability
This commit is contained in:
@@ -1,15 +1,17 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use solana_sdk::{instruction::Instruction, pubkey::Pubkey, signer::Signer};
|
||||
use solana_sdk::{instruction::Instruction, signer::Signer};
|
||||
use spl_associated_token_account::instruction::create_associated_token_account_idempotent;
|
||||
|
||||
use crate::{
|
||||
constants::bonk::{
|
||||
accounts, trade::DEFAULT_SLIPPAGE, BUY_EXECT_IN_DISCRIMINATOR, SELL_EXECT_IN_DISCRIMINATOR,
|
||||
accounts, BUY_EXECT_IN_DISCRIMINATOR, SELL_EXECT_IN_DISCRIMINATOR,
|
||||
},
|
||||
constants::trade::trade::DEFAULT_SLIPPAGE,
|
||||
trading::bonk::{
|
||||
common::{get_amount_out, get_pool_pda, get_token_balance, get_vault_pda},
|
||||
common::{get_amount_out, get_pool_pda, get_vault_pda},
|
||||
pool::Pool,
|
||||
},
|
||||
trading::common::utils::get_token_balance,
|
||||
trading::core::{
|
||||
params::{BuyParams, BonkParams, SellParams},
|
||||
traits::InstructionBuilder,
|
||||
|
||||
+24
-27
@@ -1,34 +1,28 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use solana_sdk::{
|
||||
instruction::Instruction, native_token::sol_to_lamports,
|
||||
};
|
||||
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
|
||||
}
|
||||
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 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,
|
||||
},
|
||||
constants::pumpfun::global_constants::FEE_RECIPIENT,
|
||||
constants::trade::trade::DEFAULT_SLIPPAGE,
|
||||
trading::common::utils::calculate_with_slippage_buy,
|
||||
trading::core::{
|
||||
params::{BuyParams, PumpFunParams, SellParams},
|
||||
traits::InstructionBuilder,
|
||||
},
|
||||
trading::pumpfun::common::{get_buy_token_amount_from_sol_amount, get_creator_vault_pda},
|
||||
};
|
||||
|
||||
/// PumpFun协议的指令构建器
|
||||
@@ -56,9 +50,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder {
|
||||
|
||||
let max_sol_cost = calculate_with_slippage_buy(
|
||||
params.amount_sol,
|
||||
params
|
||||
.slippage_basis_points
|
||||
.unwrap_or(DEFAULT_SLIPPAGE),
|
||||
params.slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE),
|
||||
);
|
||||
let creator_vault_pda = bonding_curve.get_creator_vault_pda();
|
||||
|
||||
@@ -161,22 +153,24 @@ pub struct Create {
|
||||
|
||||
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);
|
||||
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 内容
|
||||
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 内容
|
||||
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._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());
|
||||
|
||||
@@ -233,7 +227,10 @@ pub fn create(payer: &Keypair, mint: &Keypair, args: Create) -> Instruction {
|
||||
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::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),
|
||||
|
||||
+63
-124
@@ -3,18 +3,19 @@ use solana_sdk::{instruction::Instruction, pubkey::Pubkey, signer::Signer};
|
||||
use spl_associated_token_account::instruction::create_associated_token_account_idempotent;
|
||||
|
||||
use crate::{
|
||||
constants::pumpswap::{
|
||||
accounts, trade::DEFAULT_SLIPPAGE, BUY_DISCRIMINATOR, SELL_DISCRIMINATOR,
|
||||
},
|
||||
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,
|
||||
constants::pumpswap::{accounts, BUY_DISCRIMINATOR, SELL_DISCRIMINATOR},
|
||||
constants::trade::trade::DEFAULT_SLIPPAGE,
|
||||
trading::common::utils::{
|
||||
calculate_with_slippage_buy, calculate_with_slippage_sell, get_token_balance,
|
||||
},
|
||||
trading::core::{
|
||||
params::{BuyParams, PumpSwapParams, SellParams},
|
||||
traits::InstructionBuilder,
|
||||
},
|
||||
trading::pumpswap::common::{
|
||||
coin_creator_vault_ata, coin_creator_vault_authority, find_pool, get_buy_token_amount,
|
||||
get_sell_sol_amount,
|
||||
},
|
||||
};
|
||||
|
||||
/// PumpSwap协议的指令构建器
|
||||
@@ -35,27 +36,11 @@ impl InstructionBuilder for PumpSwapInstructionBuilder {
|
||||
}
|
||||
|
||||
// 根据是否提供了账户信息来构建指令
|
||||
match (
|
||||
&protocol_params.pool,
|
||||
&protocol_params.pool_base_token_account,
|
||||
&protocol_params.pool_quote_token_account,
|
||||
&protocol_params.user_base_token_account,
|
||||
&protocol_params.user_quote_token_account,
|
||||
) {
|
||||
(
|
||||
Some(pool),
|
||||
Some(pool_base_token_account),
|
||||
Some(pool_quote_token_account),
|
||||
Some(user_base_token_account),
|
||||
Some(user_quote_token_account),
|
||||
) => {
|
||||
match (&protocol_params.pool,) {
|
||||
(Some(pool),) => {
|
||||
self.build_buy_instructions_with_accounts(
|
||||
params,
|
||||
*pool,
|
||||
*pool_base_token_account,
|
||||
*pool_quote_token_account,
|
||||
*user_base_token_account,
|
||||
*user_quote_token_account,
|
||||
protocol_params.auto_handle_wsol,
|
||||
)
|
||||
.await
|
||||
@@ -73,29 +58,10 @@ impl InstructionBuilder for PumpSwapInstructionBuilder {
|
||||
.ok_or_else(|| anyhow!("Invalid protocol params for PumpSwap"))?;
|
||||
|
||||
// 根据是否提供了账户信息来构建指令
|
||||
match (
|
||||
&protocol_params.pool,
|
||||
&protocol_params.pool_base_token_account,
|
||||
&protocol_params.pool_quote_token_account,
|
||||
&protocol_params.user_base_token_account,
|
||||
&protocol_params.user_quote_token_account,
|
||||
) {
|
||||
(
|
||||
Some(pool),
|
||||
Some(pool_base_token_account),
|
||||
Some(pool_quote_token_account),
|
||||
Some(user_base_token_account),
|
||||
Some(user_quote_token_account),
|
||||
) => {
|
||||
self.build_sell_instructions_with_accounts(
|
||||
params,
|
||||
*pool,
|
||||
*pool_base_token_account,
|
||||
*pool_quote_token_account,
|
||||
*user_base_token_account,
|
||||
*user_quote_token_account,
|
||||
)
|
||||
.await
|
||||
match (&protocol_params.pool,) {
|
||||
(Some(pool),) => {
|
||||
self.build_sell_instructions_with_accounts(params, *pool)
|
||||
.await
|
||||
}
|
||||
_ => self.build_sell_instructions_auto_discover(params).await,
|
||||
}
|
||||
@@ -115,41 +81,8 @@ impl PumpSwapInstructionBuilder {
|
||||
// 查找池
|
||||
let pool = find_pool(rpc.as_ref(), ¶ms.mint).await?;
|
||||
|
||||
// 创建用户代币账户
|
||||
let user_base_token_account = spl_associated_token_account::get_associated_token_address(
|
||||
¶ms.payer.pubkey(),
|
||||
¶ms.mint,
|
||||
);
|
||||
let user_quote_token_account = spl_associated_token_account::get_associated_token_address(
|
||||
¶ms.payer.pubkey(),
|
||||
&accounts::WSOL_TOKEN_ACCOUNT,
|
||||
);
|
||||
|
||||
// 获取池的代币账户
|
||||
let pool_base_token_account =
|
||||
spl_associated_token_account::get_associated_token_address_with_program_id(
|
||||
&pool,
|
||||
¶ms.mint,
|
||||
&accounts::TOKEN_PROGRAM,
|
||||
);
|
||||
|
||||
let pool_quote_token_account =
|
||||
spl_associated_token_account::get_associated_token_address_with_program_id(
|
||||
&pool,
|
||||
&accounts::WSOL_TOKEN_ACCOUNT,
|
||||
&accounts::TOKEN_PROGRAM,
|
||||
);
|
||||
|
||||
self.build_buy_instructions_with_accounts(
|
||||
params,
|
||||
pool,
|
||||
pool_base_token_account,
|
||||
pool_quote_token_account,
|
||||
user_base_token_account,
|
||||
user_quote_token_account,
|
||||
true,
|
||||
)
|
||||
.await
|
||||
self.build_buy_instructions_with_accounts(params, pool, true)
|
||||
.await
|
||||
}
|
||||
|
||||
/// 自动发现池和账户信息并构建卖出指令
|
||||
@@ -165,6 +98,30 @@ impl PumpSwapInstructionBuilder {
|
||||
// 查找池
|
||||
let pool = find_pool(rpc.as_ref(), ¶ms.mint).await?;
|
||||
|
||||
self.build_sell_instructions_with_accounts(params, pool)
|
||||
.await
|
||||
}
|
||||
|
||||
/// 使用提供的账户信息构建买入指令
|
||||
async fn build_buy_instructions_with_accounts(
|
||||
&self,
|
||||
params: &BuyParams,
|
||||
pool: Pubkey,
|
||||
auto_handle_wsol: bool,
|
||||
) -> Result<Vec<Instruction>> {
|
||||
if params.rpc.is_none() {
|
||||
return Err(anyhow!("RPC is not set"));
|
||||
}
|
||||
let rpc = params.rpc.as_ref().unwrap().clone();
|
||||
// 计算预期的代币数量
|
||||
let token_amount = get_buy_token_amount(rpc.as_ref(), &pool, params.amount_sol).await?;
|
||||
|
||||
// 计算滑点后的最大SOL数量
|
||||
let max_sol_amount = calculate_with_slippage_buy(
|
||||
params.amount_sol,
|
||||
params.slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE),
|
||||
);
|
||||
|
||||
// 创建用户代币账户
|
||||
let user_base_token_account = spl_associated_token_account::get_associated_token_address(
|
||||
¶ms.payer.pubkey(),
|
||||
@@ -190,41 +147,6 @@ impl PumpSwapInstructionBuilder {
|
||||
&accounts::TOKEN_PROGRAM,
|
||||
);
|
||||
|
||||
self.build_sell_instructions_with_accounts(
|
||||
params,
|
||||
pool,
|
||||
pool_base_token_account,
|
||||
pool_quote_token_account,
|
||||
user_base_token_account,
|
||||
user_quote_token_account,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// 使用提供的账户信息构建买入指令
|
||||
async fn build_buy_instructions_with_accounts(
|
||||
&self,
|
||||
params: &BuyParams,
|
||||
pool: Pubkey,
|
||||
pool_base_token_account: Pubkey,
|
||||
pool_quote_token_account: Pubkey,
|
||||
user_base_token_account: Pubkey,
|
||||
user_quote_token_account: Pubkey,
|
||||
auto_handle_wsol: bool,
|
||||
) -> Result<Vec<Instruction>> {
|
||||
if params.rpc.is_none() {
|
||||
return Err(anyhow!("RPC is not set"));
|
||||
}
|
||||
let rpc = params.rpc.as_ref().unwrap().clone();
|
||||
// 计算预期的代币数量
|
||||
let token_amount = get_buy_token_amount(rpc.as_ref(), &pool, params.amount_sol).await?;
|
||||
|
||||
// 计算滑点后的最大SOL数量
|
||||
let max_sol_amount = calculate_with_slippage_buy(
|
||||
params.amount_sol,
|
||||
params.slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE),
|
||||
);
|
||||
|
||||
let mut instructions = vec![];
|
||||
|
||||
if auto_handle_wsol {
|
||||
@@ -328,10 +250,6 @@ impl PumpSwapInstructionBuilder {
|
||||
&self,
|
||||
params: &SellParams,
|
||||
pool: Pubkey,
|
||||
pool_base_token_account: Pubkey,
|
||||
pool_quote_token_account: Pubkey,
|
||||
user_base_token_account: Pubkey,
|
||||
user_quote_token_account: Pubkey,
|
||||
) -> Result<Vec<Instruction>> {
|
||||
if params.rpc.is_none() {
|
||||
return Err(anyhow!("RPC is not set"));
|
||||
@@ -341,8 +259,8 @@ impl PumpSwapInstructionBuilder {
|
||||
// 获取代币余额
|
||||
let mut amount = params.amount_token;
|
||||
if params.amount_token.is_none() {
|
||||
let (balance_u64, _) =
|
||||
get_token_balance(rpc.as_ref(), params.payer.as_ref(), ¶ms.mint).await?;
|
||||
let balance_u64 =
|
||||
get_token_balance(rpc.as_ref(), ¶ms.payer.pubkey(), ¶ms.mint).await?;
|
||||
amount = Some(balance_u64);
|
||||
}
|
||||
let amount = amount.unwrap_or(0);
|
||||
@@ -363,6 +281,27 @@ impl PumpSwapInstructionBuilder {
|
||||
let coin_creator_vault_ata = coin_creator_vault_ata(params.creator);
|
||||
let coin_creator_vault_authority = coin_creator_vault_authority(params.creator);
|
||||
|
||||
let user_base_token_account = spl_associated_token_account::get_associated_token_address(
|
||||
¶ms.payer.pubkey(),
|
||||
¶ms.mint,
|
||||
);
|
||||
let user_quote_token_account = spl_associated_token_account::get_associated_token_address(
|
||||
¶ms.payer.pubkey(),
|
||||
&accounts::WSOL_TOKEN_ACCOUNT,
|
||||
);
|
||||
let pool_base_token_account =
|
||||
spl_associated_token_account::get_associated_token_address_with_program_id(
|
||||
&pool,
|
||||
¶ms.mint,
|
||||
&accounts::TOKEN_PROGRAM,
|
||||
);
|
||||
let pool_quote_token_account =
|
||||
spl_associated_token_account::get_associated_token_address_with_program_id(
|
||||
&pool,
|
||||
&accounts::WSOL_TOKEN_ACCOUNT,
|
||||
&accounts::TOKEN_PROGRAM,
|
||||
);
|
||||
|
||||
let mut instructions = vec![];
|
||||
|
||||
// 插入wsol
|
||||
|
||||
Reference in New Issue
Block a user