refactor: simplify instruction builders and optimize transaction construction
- Remove redundant helper methods in instruction builders (bonk, pumpfun, pumpswap, raydium) - Inline buy/sell instruction construction for better performance - Remove unnecessary Buy/Sell structs and helper functions in pumpfun - Consolidate instruction building logic to reduce code duplication - Fix pointer dereference issue in parallel execution - Improve code maintainability and reduce complexity
This commit is contained in:
+1
-19
@@ -31,20 +31,6 @@ impl InstructionBuilder for BonkInstructionBuilder {
|
||||
if params.sol_amount == 0 {
|
||||
return Err(anyhow!("Amount cannot be zero"));
|
||||
}
|
||||
self.build_buy_instructions_with_accounts(params).await
|
||||
}
|
||||
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
|
||||
self.build_sell_instructions_with_accounts(params).await
|
||||
}
|
||||
}
|
||||
|
||||
impl BonkInstructionBuilder {
|
||||
/// Build buy instructions with provided account information
|
||||
async fn build_buy_instructions_with_accounts(
|
||||
&self,
|
||||
params: &BuyParams,
|
||||
) -> Result<Vec<Instruction>> {
|
||||
let protocol_params = params
|
||||
.protocol_params
|
||||
.as_any()
|
||||
@@ -179,11 +165,7 @@ impl BonkInstructionBuilder {
|
||||
Ok(instructions)
|
||||
}
|
||||
|
||||
/// Build sell instructions with provided account information
|
||||
async fn build_sell_instructions_with_accounts(
|
||||
&self,
|
||||
params: &SellParams,
|
||||
) -> Result<Vec<Instruction>> {
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
|
||||
if params.rpc.is_none() {
|
||||
return Err(anyhow!("RPC is not set"));
|
||||
}
|
||||
|
||||
+69
-107
@@ -1,5 +1,5 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use solana_sdk::instruction::Instruction;
|
||||
use solana_sdk::{instruction::Instruction, signer::Signer};
|
||||
use spl_associated_token_account::{
|
||||
get_associated_token_address, instruction::create_associated_token_account,
|
||||
};
|
||||
@@ -17,7 +17,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
use solana_sdk::{instruction::AccountMeta, pubkey::Pubkey, signature::Keypair, signer::Signer};
|
||||
use solana_sdk::{instruction::AccountMeta, pubkey::Pubkey};
|
||||
|
||||
use crate::{
|
||||
constants::trade::trade::DEFAULT_SLIPPAGE,
|
||||
@@ -85,14 +85,43 @@ impl InstructionBuilder for PumpFunInstructionBuilder {
|
||||
&accounts::TOKEN_PROGRAM,
|
||||
));
|
||||
|
||||
// Create buy instruction data
|
||||
let mut buy_data = Vec::with_capacity(8 + 8 + 8);
|
||||
buy_data.extend_from_slice(&[102, 6, 61, 18, 1, 218, 235, 234]); // discriminator
|
||||
buy_data.extend_from_slice(&buy_token_amount.to_le_bytes());
|
||||
buy_data.extend_from_slice(&max_sol_cost.to_le_bytes());
|
||||
|
||||
// Create buy instruction
|
||||
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 },
|
||||
instructions.push(Instruction::new_with_bytes(
|
||||
accounts::PUMPFUN,
|
||||
&buy_data,
|
||||
vec![
|
||||
AccountMeta::new_readonly(global_constants::GLOBAL_ACCOUNT, false),
|
||||
AccountMeta::new(FEE_RECIPIENT, false),
|
||||
AccountMeta::new_readonly(params.mint, false),
|
||||
AccountMeta::new(bonding_curve.account, false),
|
||||
AccountMeta::new(
|
||||
get_associated_token_address(&bonding_curve.account, ¶ms.mint),
|
||||
false,
|
||||
),
|
||||
AccountMeta::new(
|
||||
get_associated_token_address(¶ms.payer.pubkey(), ¶ms.mint),
|
||||
false,
|
||||
),
|
||||
AccountMeta::new(params.payer.pubkey(), true),
|
||||
AccountMeta::new_readonly(accounts::SYSTEM_PROGRAM, false),
|
||||
AccountMeta::new_readonly(accounts::TOKEN_PROGRAM, false),
|
||||
AccountMeta::new(creator_vault_pda, false),
|
||||
AccountMeta::new_readonly(accounts::EVENT_AUTHORITY, false),
|
||||
AccountMeta::new_readonly(accounts::PUMPFUN, false),
|
||||
AccountMeta::new(get_global_volume_accumulator_pda().unwrap(), false),
|
||||
AccountMeta::new(
|
||||
get_user_volume_accumulator_pda(¶ms.payer.pubkey()).unwrap(),
|
||||
false,
|
||||
),
|
||||
AccountMeta::new_readonly(get_fee_config_pda().unwrap(), false),
|
||||
AccountMeta::new_readonly(accounts::FEE_PROGRAM, false),
|
||||
],
|
||||
));
|
||||
|
||||
Ok(instructions)
|
||||
@@ -137,12 +166,37 @@ impl InstructionBuilder for PumpFunInstructionBuilder {
|
||||
params.slippage_basis_points.unwrap_or(DEFAULT_SLIPPAGE),
|
||||
);
|
||||
|
||||
let mut instructions = vec![sell(
|
||||
params.payer.as_ref(),
|
||||
¶ms.mint,
|
||||
&creator_vault_pda,
|
||||
&FEE_RECIPIENT,
|
||||
Sell { _amount: token_amount, _min_sol_output: min_sol_output },
|
||||
// Create sell instruction data
|
||||
let mut sell_data = Vec::with_capacity(8 + 8 + 8);
|
||||
sell_data.extend_from_slice(&[51, 230, 133, 164, 1, 127, 131, 173]); // discriminator
|
||||
sell_data.extend_from_slice(&token_amount.to_le_bytes());
|
||||
sell_data.extend_from_slice(&min_sol_output.to_le_bytes());
|
||||
|
||||
let bonding_curve = get_bonding_curve_pda(¶ms.mint).unwrap();
|
||||
|
||||
// Create sell instruction
|
||||
let mut instructions = vec![Instruction::new_with_bytes(
|
||||
accounts::PUMPFUN,
|
||||
&sell_data,
|
||||
vec![
|
||||
AccountMeta::new_readonly(global_constants::GLOBAL_ACCOUNT, false),
|
||||
AccountMeta::new(FEE_RECIPIENT, false),
|
||||
AccountMeta::new_readonly(params.mint, false),
|
||||
AccountMeta::new(bonding_curve, false),
|
||||
AccountMeta::new(get_associated_token_address(&bonding_curve, ¶ms.mint), false),
|
||||
AccountMeta::new(
|
||||
get_associated_token_address(¶ms.payer.pubkey(), ¶ms.mint),
|
||||
false,
|
||||
),
|
||||
AccountMeta::new(params.payer.pubkey(), true),
|
||||
AccountMeta::new_readonly(accounts::SYSTEM_PROGRAM, false),
|
||||
AccountMeta::new(creator_vault_pda, false),
|
||||
AccountMeta::new_readonly(accounts::TOKEN_PROGRAM, false),
|
||||
AccountMeta::new_readonly(accounts::EVENT_AUTHORITY, false),
|
||||
AccountMeta::new_readonly(accounts::PUMPFUN, false),
|
||||
AccountMeta::new_readonly(get_fee_config_pda().unwrap(), false),
|
||||
AccountMeta::new_readonly(accounts::FEE_PROGRAM, false),
|
||||
],
|
||||
)];
|
||||
|
||||
// If selling all tokens, close the account
|
||||
@@ -159,95 +213,3 @@ impl InstructionBuilder for PumpFunInstructionBuilder {
|
||||
Ok(instructions)
|
||||
}
|
||||
}
|
||||
|
||||
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 buy(
|
||||
payer: &Keypair,
|
||||
mint: &Pubkey,
|
||||
bonding_curve_pda: &Pubkey,
|
||||
creator_vault_pda: &Pubkey,
|
||||
fee_recipient: &Pubkey,
|
||||
args: Buy,
|
||||
) -> Instruction {
|
||||
Instruction::new_with_bytes(
|
||||
accounts::PUMPFUN,
|
||||
&args.data(),
|
||||
vec![
|
||||
AccountMeta::new_readonly(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(accounts::SYSTEM_PROGRAM, false),
|
||||
AccountMeta::new_readonly(accounts::TOKEN_PROGRAM, false),
|
||||
AccountMeta::new(*creator_vault_pda, false),
|
||||
AccountMeta::new_readonly(accounts::EVENT_AUTHORITY, false),
|
||||
AccountMeta::new_readonly(accounts::PUMPFUN, false),
|
||||
AccountMeta::new(get_global_volume_accumulator_pda().unwrap(), false),
|
||||
AccountMeta::new(get_user_volume_accumulator_pda(&payer.pubkey()).unwrap(), false),
|
||||
AccountMeta::new_readonly(get_fee_config_pda().unwrap(), false),
|
||||
AccountMeta::new_readonly(accounts::FEE_PROGRAM, 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(
|
||||
accounts::PUMPFUN,
|
||||
&args.data(),
|
||||
vec![
|
||||
AccountMeta::new_readonly(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(accounts::SYSTEM_PROGRAM, false),
|
||||
AccountMeta::new(*creator_vault_pda, false),
|
||||
AccountMeta::new_readonly(accounts::TOKEN_PROGRAM, false),
|
||||
AccountMeta::new_readonly(accounts::EVENT_AUTHORITY, false),
|
||||
AccountMeta::new_readonly(accounts::PUMPFUN, false),
|
||||
AccountMeta::new_readonly(get_fee_config_pda().unwrap(), false),
|
||||
AccountMeta::new_readonly(accounts::FEE_PROGRAM, false),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
+28
-82
@@ -35,78 +35,18 @@ impl InstructionBuilder for PumpSwapInstructionBuilder {
|
||||
return Err(anyhow!("Amount cannot be zero"));
|
||||
}
|
||||
|
||||
// Build instructions based on whether account information is provided
|
||||
// Build instructions based on account information
|
||||
let pool = protocol_params.pool;
|
||||
let base_mint = protocol_params.base_mint;
|
||||
let quote_mint = protocol_params.quote_mint;
|
||||
let pool_base_token_reserves = protocol_params.pool_base_token_reserves;
|
||||
let pool_quote_token_reserves = protocol_params.pool_quote_token_reserves;
|
||||
let coin_creator_vault_ata = protocol_params.coin_creator_vault_ata;
|
||||
let coin_creator_vault_authority = protocol_params.coin_creator_vault_authority;
|
||||
let params_coin_creator_vault_ata = protocol_params.coin_creator_vault_ata;
|
||||
let params_coin_creator_vault_authority = protocol_params.coin_creator_vault_authority;
|
||||
let auto_handle_wsol = protocol_params.auto_handle_wsol;
|
||||
let base_token_program = protocol_params.base_token_program;
|
||||
let quote_token_program = protocol_params.quote_token_program;
|
||||
|
||||
self.build_buy_instructions_with_accounts(
|
||||
params,
|
||||
protocol_params.pool,
|
||||
base_mint,
|
||||
quote_mint,
|
||||
pool_base_token_reserves,
|
||||
pool_quote_token_reserves,
|
||||
coin_creator_vault_ata,
|
||||
coin_creator_vault_authority,
|
||||
protocol_params.auto_handle_wsol,
|
||||
protocol_params.base_token_program,
|
||||
protocol_params.quote_token_program,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
|
||||
// Get PumpSwap specific parameters
|
||||
let protocol_params = params
|
||||
.protocol_params
|
||||
.as_any()
|
||||
.downcast_ref::<PumpSwapParams>()
|
||||
.ok_or_else(|| anyhow!("Invalid protocol params for PumpSwap"))?;
|
||||
// Build instructions based on whether account information is provided
|
||||
let base_mint = protocol_params.base_mint;
|
||||
let quote_mint = protocol_params.quote_mint;
|
||||
let pool_base_token_reserves = protocol_params.pool_base_token_reserves;
|
||||
let pool_quote_token_reserves = protocol_params.pool_quote_token_reserves;
|
||||
let coin_creator_vault_ata = protocol_params.coin_creator_vault_ata;
|
||||
let coin_creator_vault_authority = protocol_params.coin_creator_vault_authority;
|
||||
|
||||
self.build_sell_instructions_with_accounts(
|
||||
params,
|
||||
protocol_params.pool,
|
||||
base_mint,
|
||||
quote_mint,
|
||||
pool_base_token_reserves,
|
||||
pool_quote_token_reserves,
|
||||
coin_creator_vault_ata,
|
||||
coin_creator_vault_authority,
|
||||
protocol_params.auto_handle_wsol,
|
||||
protocol_params.base_token_program,
|
||||
protocol_params.quote_token_program,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl PumpSwapInstructionBuilder {
|
||||
/// Build buy instructions with provided account information
|
||||
async fn build_buy_instructions_with_accounts(
|
||||
&self,
|
||||
params: &BuyParams,
|
||||
pool: Pubkey,
|
||||
base_mint: Pubkey,
|
||||
quote_mint: Pubkey,
|
||||
pool_base_token_reserves: u64,
|
||||
pool_quote_token_reserves: u64,
|
||||
params_coin_creator_vault_ata: Pubkey,
|
||||
params_coin_creator_vault_authority: Pubkey,
|
||||
auto_handle_wsol: bool,
|
||||
base_token_program: Pubkey,
|
||||
quote_token_program: Pubkey,
|
||||
) -> Result<Vec<Instruction>> {
|
||||
if base_mint != accounts::WSOL_TOKEN_ACCOUNT && quote_mint != accounts::WSOL_TOKEN_ACCOUNT {
|
||||
return Err(anyhow!("Invalid base mint and quote mint"));
|
||||
}
|
||||
@@ -310,21 +250,26 @@ impl PumpSwapInstructionBuilder {
|
||||
Ok(instructions)
|
||||
}
|
||||
|
||||
/// Build sell instructions with provided account information
|
||||
async fn build_sell_instructions_with_accounts(
|
||||
&self,
|
||||
params: &SellParams,
|
||||
pool: Pubkey,
|
||||
base_mint: Pubkey,
|
||||
quote_mint: Pubkey,
|
||||
pool_base_token_reserves: u64,
|
||||
pool_quote_token_reserves: u64,
|
||||
params_coin_creator_vault_ata: Pubkey,
|
||||
params_coin_creator_vault_authority: Pubkey,
|
||||
auto_handle_wsol: bool,
|
||||
base_token_program: Pubkey,
|
||||
quote_token_program: Pubkey,
|
||||
) -> Result<Vec<Instruction>> {
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
|
||||
// Get PumpSwap specific parameters
|
||||
let protocol_params = params
|
||||
.protocol_params
|
||||
.as_any()
|
||||
.downcast_ref::<PumpSwapParams>()
|
||||
.ok_or_else(|| anyhow!("Invalid protocol params for PumpSwap"))?;
|
||||
|
||||
// Build instructions based on account information
|
||||
let pool = protocol_params.pool;
|
||||
let base_mint = protocol_params.base_mint;
|
||||
let quote_mint = protocol_params.quote_mint;
|
||||
let pool_base_token_reserves = protocol_params.pool_base_token_reserves;
|
||||
let pool_quote_token_reserves = protocol_params.pool_quote_token_reserves;
|
||||
let params_coin_creator_vault_ata = protocol_params.coin_creator_vault_ata;
|
||||
let params_coin_creator_vault_authority = protocol_params.coin_creator_vault_authority;
|
||||
let auto_handle_wsol = protocol_params.auto_handle_wsol;
|
||||
let base_token_program = protocol_params.base_token_program;
|
||||
let quote_token_program = protocol_params.quote_token_program;
|
||||
|
||||
if base_mint != accounts::WSOL_TOKEN_ACCOUNT && quote_mint != accounts::WSOL_TOKEN_ACCOUNT {
|
||||
return Err(anyhow!("Invalid base mint and quote mint"));
|
||||
}
|
||||
@@ -503,3 +448,4 @@ impl PumpSwapInstructionBuilder {
|
||||
Ok(instructions)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,20 +23,6 @@ impl InstructionBuilder for RaydiumAmmV4InstructionBuilder {
|
||||
if params.sol_amount == 0 {
|
||||
return Err(anyhow!("Amount cannot be zero"));
|
||||
}
|
||||
self.build_buy_instructions_with_accounts(params).await
|
||||
}
|
||||
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
|
||||
self.build_sell_instructions_with_accounts(params).await
|
||||
}
|
||||
}
|
||||
|
||||
impl RaydiumAmmV4InstructionBuilder {
|
||||
/// Build buy instructions with provided account information
|
||||
async fn build_buy_instructions_with_accounts(
|
||||
&self,
|
||||
params: &BuyParams,
|
||||
) -> Result<Vec<Instruction>> {
|
||||
let protocol_params = params
|
||||
.protocol_params
|
||||
.as_any()
|
||||
@@ -147,11 +133,7 @@ impl RaydiumAmmV4InstructionBuilder {
|
||||
Ok(instructions)
|
||||
}
|
||||
|
||||
/// Build sell instructions with provided account information
|
||||
async fn build_sell_instructions_with_accounts(
|
||||
&self,
|
||||
params: &SellParams,
|
||||
) -> Result<Vec<Instruction>> {
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
|
||||
let protocol_params = params
|
||||
.protocol_params
|
||||
.as_any()
|
||||
|
||||
@@ -26,20 +26,6 @@ impl InstructionBuilder for RaydiumCpmmInstructionBuilder {
|
||||
if params.sol_amount == 0 {
|
||||
return Err(anyhow!("Amount cannot be zero"));
|
||||
}
|
||||
self.build_buy_instructions_with_accounts(params).await
|
||||
}
|
||||
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
|
||||
self.build_sell_instructions_with_accounts(params).await
|
||||
}
|
||||
}
|
||||
|
||||
impl RaydiumCpmmInstructionBuilder {
|
||||
/// Build buy instructions with provided account information
|
||||
async fn build_buy_instructions_with_accounts(
|
||||
&self,
|
||||
params: &BuyParams,
|
||||
) -> Result<Vec<Instruction>> {
|
||||
let protocol_params = params
|
||||
.protocol_params
|
||||
.as_any()
|
||||
@@ -160,11 +146,7 @@ impl RaydiumCpmmInstructionBuilder {
|
||||
Ok(instructions)
|
||||
}
|
||||
|
||||
/// Build sell instructions with provided account information
|
||||
async fn build_sell_instructions_with_accounts(
|
||||
&self,
|
||||
params: &SellParams,
|
||||
) -> Result<Vec<Instruction>> {
|
||||
async fn build_sell_instructions(&self, params: &SellParams) -> Result<Vec<Instruction>> {
|
||||
let protocol_params = params
|
||||
.protocol_params
|
||||
.as_any()
|
||||
|
||||
@@ -69,7 +69,7 @@ pub async fn parallel_execute_with_tips(
|
||||
let transaction = build_transaction(
|
||||
payer,
|
||||
&priority_fee,
|
||||
(*instructions).clone(),
|
||||
instructions.as_ref().clone(),
|
||||
lookup_table_key,
|
||||
recent_blockhash,
|
||||
data_size_limit,
|
||||
|
||||
Reference in New Issue
Block a user