Merge commit 'f20dbbd7936f301be8996b4dcf2a3c6a1c999cf6'

This commit is contained in:
sgxiang
2025-06-16 21:08:56 +08:00
2 changed files with 79 additions and 127 deletions
+2
View File
@@ -257,6 +257,7 @@ impl PumpFun {
slippage_basis_points, slippage_basis_points,
self.priority_fee.clone(), self.priority_fee.clone(),
self.cluster.clone().lookup_table_key, self.cluster.clone().lookup_table_key,
recent_blockhash,
None, None,
None, None,
None, None,
@@ -332,6 +333,7 @@ impl PumpFun {
slippage_basis_points, slippage_basis_points,
self.priority_fee.clone(), self.priority_fee.clone(),
self.cluster.clone().lookup_table_key, self.cluster.clone().lookup_table_key,
recent_blockhash,
None, None,
None, None,
None, None,
+77 -127
View File
@@ -10,6 +10,7 @@ use solana_sdk::{
system_instruction, system_instruction,
transaction::VersionedTransaction, transaction::VersionedTransaction,
}; };
use solana_hash::Hash;
use spl_associated_token_account::instruction::create_associated_token_account_idempotent; use spl_associated_token_account::instruction::create_associated_token_account_idempotent;
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
@@ -33,17 +34,15 @@ const MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT: u32 = 256 * 1024;
/// 添加nonce消费指令到指令集合中 /// 添加nonce消费指令到指令集合中
/// ///
/// 只有当同时提供了nonce_pubkey和nonce_program_id时才使用nonce功能 /// 只有提供了nonce_pubkey时才使用nonce功能
/// 如果nonce被锁定、已使用或未准备好,将返回错误 /// 如果nonce被锁定、已使用或未准备好,将返回错误
/// 成功时会锁定并标记nonce为已使用 /// 成功时会锁定并标记nonce为已使用
fn add_nonce_instruction( fn add_nonce_instruction(instructions: &mut Vec<Instruction>, payer: &Keypair) -> Result<(), anyhow::Error> {
instructions: &mut Vec<Instruction>,
payer: &Keypair,
) -> Result<(), anyhow::Error> {
let nonce_cache = NonceCache::get_instance(); let nonce_cache = NonceCache::get_instance();
let nonce_info = nonce_cache.get_nonce_info(); let nonce_info = nonce_cache.get_nonce_info();
// 只检查nonce_account是否存在
if let Some(nonce_pubkey) = nonce_info.nonce_account { if let Some(nonce_pubkey) = nonce_info.nonce_account {
let nonce_value = nonce_info.current_nonce;
// 暂不加锁 // 暂不加锁
// if nonce_info.lock { // if nonce_info.lock {
// return Err(anyhow!("Nonce is locked")); // return Err(anyhow!("Nonce is locked"));
@@ -51,55 +50,28 @@ fn add_nonce_instruction(
if nonce_info.used { if nonce_info.used {
return Err(anyhow!("Nonce is used")); return Err(anyhow!("Nonce is used"));
} }
if nonce_info.next_buy_time == 0 if nonce_info.current_nonce == Hash::default() {
|| chrono::Utc::now().timestamp() < nonce_info.next_buy_time
{
return Err(anyhow!("Nonce is not ready")); return Err(anyhow!("Nonce is not ready"));
} }
// if nonce_info.next_buy_time == 0 || chrono::Utc::now().timestamp() < nonce_info.next_buy_time {
// return Err(anyhow!("Nonce is not ready"));
// }
// 加锁 - 暂不加锁 // 加锁 - 暂不加锁
// nonce_cache.lock(); // nonce_cache.lock();
// 创建自定义nonce消费指令
let nonce_consume_ix = Instruction { // 创建Solana系统nonce推进指令 - 使用系统程序ID
program_id: crate::constants::pumpswap::accounts::AMM_PROGRAM, let nonce_advance_ix = system_instruction::advance_nonce_account(
accounts: vec![ &nonce_pubkey,
AccountMeta::new(nonce_pubkey, false), &payer.pubkey(),
AccountMeta::new_readonly(payer.pubkey(), true), );
],
// INSTR_CONSUME = 1, 使用传入的nonce值
data: { instructions.push(nonce_advance_ix);
let mut data = vec![1]; // INSTR_CONSUME = 1
data.extend_from_slice(&nonce_value.to_bytes()); // 添加nonce值
data
},
};
instructions.push(nonce_consume_ix);
} }
Ok(()) Ok(())
} }
/// 验证地址表是否被成功用于编译后的消息中
fn verify_lookup_table_usage(
v0_message: &v0::Message,
address_lookup_table_accounts: &[AddressLookupTableAccount],
) {
if !address_lookup_table_accounts.is_empty() {
println!("消息已编译,使用了地址表引用");
// 如果地址表有地址,但没有被使用,给出警告
if v0_message.address_table_lookups.is_empty() {
println!("警告:编译后的消息没有使用地址表引用!");
} else {
for (i, lookup) in v0_message.address_table_lookups.iter().enumerate() {
println!(
"使用地址表 {}: 可写索引 {} 个, 只读索引 {}",
i,
lookup.writable_indexes.len(),
lookup.readonly_indexes.len()
);
}
}
}
}
// Buy tokens from a Pumpswap pool // Buy tokens from a Pumpswap pool
pub async fn buy( pub async fn buy(
@@ -111,6 +83,7 @@ pub async fn buy(
slippage_basis_points: Option<u64>, slippage_basis_points: Option<u64>,
priority_fee: PriorityFee, priority_fee: PriorityFee,
lookup_table_key: Option<Pubkey>, lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
// 可选(必须全部传) // 可选(必须全部传)
pool: Option<Pubkey>, pool: Option<Pubkey>,
pool_base_token_account: Option<Pubkey>, pool_base_token_account: Option<Pubkey>,
@@ -171,6 +144,7 @@ pub async fn buy(
priority_fee.clone(), priority_fee.clone(),
instructions, instructions,
lookup_table_key, lookup_table_key,
recent_blockhash,
) )
.await?; .await?;
println!(" Buy transaction signature: {:?}", start_time.elapsed()); println!(" Buy transaction signature: {:?}", start_time.elapsed());
@@ -193,6 +167,7 @@ pub async fn buy_with_tip(
slippage_basis_points: Option<u64>, slippage_basis_points: Option<u64>,
priority_fee: PriorityFee, priority_fee: PriorityFee,
lookup_table_key: Option<Pubkey>, lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
// 可选(必须全部传) // 可选(必须全部传)
pool: Option<Pubkey>, pool: Option<Pubkey>,
pool_base_token_account: Option<Pubkey>, pool_base_token_account: Option<Pubkey>,
@@ -260,6 +235,7 @@ pub async fn buy_with_tip(
priority_fee.clone(), priority_fee.clone(),
instructions.clone(), instructions.clone(),
lookup_table_key, lookup_table_key,
recent_blockhash,
) )
.await?; .await?;
@@ -298,57 +274,42 @@ pub async fn build_buy_transaction(
priority_fee: PriorityFee, priority_fee: PriorityFee,
build_instructions: Vec<Instruction>, build_instructions: Vec<Instruction>,
lookup_table_key: Option<Pubkey>, lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
) -> Result<VersionedTransaction, anyhow::Error> { ) -> Result<VersionedTransaction, anyhow::Error> {
let mut instructions = vec![ let mut instructions = vec![];
ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT,
),
ComputeBudgetInstruction::set_compute_unit_price(priority_fee.unit_price),
ComputeBudgetInstruction::set_compute_unit_limit(priority_fee.unit_limit),
];
// 添加nonce消费指令
if let Err(e) = add_nonce_instruction(&mut instructions, payer.as_ref()) { if let Err(e) = add_nonce_instruction(&mut instructions, payer.as_ref()) {
return Err(e); return Err(e);
} }
instructions.extend(build_instructions); // 添加计算预算指令
instructions.push(ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT));
instructions.push(ComputeBudgetInstruction::set_compute_unit_price( priority_fee.rpc_unit_price ));
instructions.push(ComputeBudgetInstruction::set_compute_unit_limit( priority_fee.rpc_unit_limit ));
instructions.extend(build_instructions);
let nonce_cache = NonceCache::get_instance();
let nonce_info = nonce_cache.get_nonce_info();
let blockhash = if nonce_info.nonce_account.is_some() && instructions.len() > 0 {
nonce_info.current_nonce
} else {
recent_blockhash
};
let blockhash = rpc.get_latest_blockhash().await?; let mut address_lookup_table_accounts = vec![];
if let Some(lookup_table_key) = lookup_table_key {
// 确保所有需要签名的账户都被正确标记 let account = get_address_lookup_table_account(&lookup_table_key).await;
for instruction in &instructions { address_lookup_table_accounts.push(account);
for account_meta in &instruction.accounts { }
if account_meta.is_signer && account_meta.pubkey != payer.pubkey() {
return Err(anyhow!( let v0_message: v0::Message =
"Transaction requires a signature from an account other than the payer: {}", v0::Message::try_compile(&payer.pubkey(), &instructions, &address_lookup_table_accounts, blockhash)?;
account_meta.pubkey let versioned_message: VersionedMessage = VersionedMessage::V0(v0_message.clone());
)); let transaction = VersionedTransaction::try_new(versioned_message, &[payer.as_ref()])?;
}
} // verify_lookup_table_usage(&v0_message, &address_lookup_table_accounts);
}
Ok(transaction)
let mut address_lookup_table_accounts = vec![];
if let Some(lookup_table_key) = lookup_table_key {
let account = get_address_lookup_table_account(&lookup_table_key).await;
address_lookup_table_accounts.push(account);
}
let v0_message = v0::Message::try_compile(
&payer.pubkey(),
&instructions,
&address_lookup_table_accounts,
blockhash,
)
.map_err(|e| anyhow!(e))?;
let versioned_message = VersionedMessage::V0(v0_message.clone());
let transaction = VersionedTransaction::try_new(versioned_message, &[&payer])?;
// 验证地址表使用情况
verify_lookup_table_usage(&v0_message, &address_lookup_table_accounts);
Ok(transaction)
} }
// Build a transaction with tip for buying tokens // Build a transaction with tip for buying tokens
@@ -359,40 +320,35 @@ pub async fn build_buy_transaction_with_tip(
priority_fee: PriorityFee, priority_fee: PriorityFee,
build_instructions: Vec<Instruction>, build_instructions: Vec<Instruction>,
lookup_table_key: Option<Pubkey>, lookup_table_key: Option<Pubkey>,
recent_blockhash: Hash,
) -> Result<VersionedTransaction, anyhow::Error> { ) -> Result<VersionedTransaction, anyhow::Error> {
let mut instructions = vec![ let mut instructions = vec![];
ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(
MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT,
),
ComputeBudgetInstruction::set_compute_unit_price(priority_fee.unit_price),
ComputeBudgetInstruction::set_compute_unit_limit(priority_fee.unit_limit),
system_instruction::transfer(
&payer.pubkey(),
&tip_account,
sol_to_lamports(priority_fee.buy_tip_fee),
),
];
// 添加nonce消费指令 // 添加nonce消费指令
if let Err(e) = add_nonce_instruction(&mut instructions, payer.as_ref()) { if let Err(e) = add_nonce_instruction(&mut instructions, payer.as_ref()) {
return Err(e); return Err(e);
} }
// 添加计算预算指令和小费转账指令
instructions.push(ComputeBudgetInstruction::set_loaded_accounts_data_size_limit(MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT));
instructions.push(ComputeBudgetInstruction::set_compute_unit_price(priority_fee.unit_price));
instructions.push(ComputeBudgetInstruction::set_compute_unit_limit(priority_fee.unit_limit));
instructions.extend(build_instructions); instructions.extend(build_instructions);
instructions.push(system_instruction::transfer(
&payer.pubkey(),
&tip_account,
sol_to_lamports(priority_fee.buy_tip_fee),
));
let blockhash = rpc.get_latest_blockhash().await?; let nonce_cache = NonceCache::get_instance();
let nonce_info = nonce_cache.get_nonce_info();
// 确保所有需要签名的账户都被正确标记 // 如果使用了nonce账户,则使用nonce账户中的blockhash
for instruction in &instructions { let blockhash_to_use = if nonce_info.nonce_account.is_some() && instructions.len() > 0 {
for account_meta in &instruction.accounts { nonce_info.current_nonce
if account_meta.is_signer && account_meta.pubkey != payer.pubkey() { } else {
return Err(anyhow!( recent_blockhash
"Transaction requires a signature from an account other than the payer: {}", };
account_meta.pubkey
));
}
}
}
let mut address_lookup_table_accounts = vec![]; let mut address_lookup_table_accounts = vec![];
if let Some(lookup_table_key) = lookup_table_key { if let Some(lookup_table_key) = lookup_table_key {
@@ -400,19 +356,13 @@ pub async fn build_buy_transaction_with_tip(
address_lookup_table_accounts.push(account); address_lookup_table_accounts.push(account);
} }
let v0_message = v0::Message::try_compile( let v0_message: v0::Message =
&payer.pubkey(), v0::Message::try_compile(&payer.pubkey(), &instructions, &address_lookup_table_accounts, blockhash_to_use)?;
&instructions, let versioned_message: VersionedMessage = VersionedMessage::V0(v0_message.clone());
&address_lookup_table_accounts, let transaction = VersionedTransaction::try_new(versioned_message, &[payer.as_ref()])?;
blockhash,
)
.map_err(|e| anyhow!(e))?;
let versioned_message = VersionedMessage::V0(v0_message.clone()); // nonce_cache.mark_used();
let transaction = VersionedTransaction::try_new(versioned_message, &[&payer])?; // verify_lookup_table_usage(&v0_message, &address_lookup_table_accounts);
// 验证地址表使用情况
verify_lookup_table_usage(&v0_message, &address_lookup_table_accounts);
Ok(transaction) Ok(transaction)
} }