Merge commit 'f20dbbd7936f301be8996b4dcf2a3c6a1c999cf6'
This commit is contained in:
@@ -257,6 +257,7 @@ impl PumpFun {
|
||||
slippage_basis_points,
|
||||
self.priority_fee.clone(),
|
||||
self.cluster.clone().lookup_table_key,
|
||||
recent_blockhash,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
@@ -332,6 +333,7 @@ impl PumpFun {
|
||||
slippage_basis_points,
|
||||
self.priority_fee.clone(),
|
||||
self.cluster.clone().lookup_table_key,
|
||||
recent_blockhash,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
|
||||
+77
-127
@@ -10,6 +10,7 @@ use solana_sdk::{
|
||||
system_instruction,
|
||||
transaction::VersionedTransaction,
|
||||
};
|
||||
use solana_hash::Hash;
|
||||
use spl_associated_token_account::instruction::create_associated_token_account_idempotent;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
@@ -33,17 +34,15 @@ const MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT: u32 = 256 * 1024;
|
||||
|
||||
/// 添加nonce消费指令到指令集合中
|
||||
///
|
||||
/// 只有当同时提供了nonce_pubkey和nonce_program_id时才使用nonce功能
|
||||
/// 只有提供了nonce_pubkey时才使用nonce功能
|
||||
/// 如果nonce被锁定、已使用或未准备好,将返回错误
|
||||
/// 成功时会锁定并标记nonce为已使用
|
||||
fn add_nonce_instruction(
|
||||
instructions: &mut Vec<Instruction>,
|
||||
payer: &Keypair,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
fn add_nonce_instruction(instructions: &mut Vec<Instruction>, payer: &Keypair) -> Result<(), anyhow::Error> {
|
||||
let nonce_cache = NonceCache::get_instance();
|
||||
let nonce_info = nonce_cache.get_nonce_info();
|
||||
|
||||
// 只检查nonce_account是否存在
|
||||
if let Some(nonce_pubkey) = nonce_info.nonce_account {
|
||||
let nonce_value = nonce_info.current_nonce;
|
||||
// 暂不加锁
|
||||
// if nonce_info.lock {
|
||||
// return Err(anyhow!("Nonce is locked"));
|
||||
@@ -51,55 +50,28 @@ fn add_nonce_instruction(
|
||||
if nonce_info.used {
|
||||
return Err(anyhow!("Nonce is used"));
|
||||
}
|
||||
if nonce_info.next_buy_time == 0
|
||||
|| chrono::Utc::now().timestamp() < nonce_info.next_buy_time
|
||||
{
|
||||
if nonce_info.current_nonce == Hash::default() {
|
||||
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消费指令
|
||||
let nonce_consume_ix = Instruction {
|
||||
program_id: crate::constants::pumpswap::accounts::AMM_PROGRAM,
|
||||
accounts: vec![
|
||||
AccountMeta::new(nonce_pubkey, false),
|
||||
AccountMeta::new_readonly(payer.pubkey(), true),
|
||||
],
|
||||
// INSTR_CONSUME = 1, 使用传入的nonce值
|
||||
data: {
|
||||
let mut data = vec![1]; // INSTR_CONSUME = 1
|
||||
data.extend_from_slice(&nonce_value.to_bytes()); // 添加nonce值
|
||||
data
|
||||
},
|
||||
};
|
||||
instructions.push(nonce_consume_ix);
|
||||
|
||||
// 创建Solana系统nonce推进指令 - 使用系统程序ID
|
||||
let nonce_advance_ix = system_instruction::advance_nonce_account(
|
||||
&nonce_pubkey,
|
||||
&payer.pubkey(),
|
||||
);
|
||||
|
||||
|
||||
instructions.push(nonce_advance_ix);
|
||||
}
|
||||
|
||||
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
|
||||
pub async fn buy(
|
||||
@@ -111,6 +83,7 @@ pub async fn buy(
|
||||
slippage_basis_points: Option<u64>,
|
||||
priority_fee: PriorityFee,
|
||||
lookup_table_key: Option<Pubkey>,
|
||||
recent_blockhash: Hash,
|
||||
// 可选(必须全部传)
|
||||
pool: Option<Pubkey>,
|
||||
pool_base_token_account: Option<Pubkey>,
|
||||
@@ -171,6 +144,7 @@ pub async fn buy(
|
||||
priority_fee.clone(),
|
||||
instructions,
|
||||
lookup_table_key,
|
||||
recent_blockhash,
|
||||
)
|
||||
.await?;
|
||||
println!(" Buy transaction signature: {:?}", start_time.elapsed());
|
||||
@@ -193,6 +167,7 @@ pub async fn buy_with_tip(
|
||||
slippage_basis_points: Option<u64>,
|
||||
priority_fee: PriorityFee,
|
||||
lookup_table_key: Option<Pubkey>,
|
||||
recent_blockhash: Hash,
|
||||
// 可选(必须全部传)
|
||||
pool: Option<Pubkey>,
|
||||
pool_base_token_account: Option<Pubkey>,
|
||||
@@ -260,6 +235,7 @@ pub async fn buy_with_tip(
|
||||
priority_fee.clone(),
|
||||
instructions.clone(),
|
||||
lookup_table_key,
|
||||
recent_blockhash,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -298,57 +274,42 @@ pub async fn build_buy_transaction(
|
||||
priority_fee: PriorityFee,
|
||||
build_instructions: Vec<Instruction>,
|
||||
lookup_table_key: Option<Pubkey>,
|
||||
recent_blockhash: Hash,
|
||||
) -> Result<VersionedTransaction, anyhow::Error> {
|
||||
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消费指令
|
||||
let mut instructions = vec![];
|
||||
if let Err(e) = add_nonce_instruction(&mut instructions, payer.as_ref()) {
|
||||
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?;
|
||||
|
||||
// 确保所有需要签名的账户都被正确标记
|
||||
for instruction in &instructions {
|
||||
for account_meta in &instruction.accounts {
|
||||
if account_meta.is_signer && account_meta.pubkey != payer.pubkey() {
|
||||
return Err(anyhow!(
|
||||
"Transaction requires a signature from an account other than the payer: {}",
|
||||
account_meta.pubkey
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
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 =
|
||||
v0::Message::try_compile(&payer.pubkey(), &instructions, &address_lookup_table_accounts, blockhash)?;
|
||||
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)
|
||||
}
|
||||
|
||||
// Build a transaction with tip for buying tokens
|
||||
@@ -359,40 +320,35 @@ pub async fn build_buy_transaction_with_tip(
|
||||
priority_fee: PriorityFee,
|
||||
build_instructions: Vec<Instruction>,
|
||||
lookup_table_key: Option<Pubkey>,
|
||||
recent_blockhash: Hash,
|
||||
) -> Result<VersionedTransaction, anyhow::Error> {
|
||||
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),
|
||||
),
|
||||
];
|
||||
let mut instructions = vec![];
|
||||
|
||||
// 添加nonce消费指令
|
||||
if let Err(e) = add_nonce_instruction(&mut instructions, payer.as_ref()) {
|
||||
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.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();
|
||||
|
||||
// 确保所有需要签名的账户都被正确标记
|
||||
for instruction in &instructions {
|
||||
for account_meta in &instruction.accounts {
|
||||
if account_meta.is_signer && account_meta.pubkey != payer.pubkey() {
|
||||
return Err(anyhow!(
|
||||
"Transaction requires a signature from an account other than the payer: {}",
|
||||
account_meta.pubkey
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 如果使用了nonce账户,则使用nonce账户中的blockhash
|
||||
let blockhash_to_use = if nonce_info.nonce_account.is_some() && instructions.len() > 0 {
|
||||
nonce_info.current_nonce
|
||||
} else {
|
||||
recent_blockhash
|
||||
};
|
||||
|
||||
let mut address_lookup_table_accounts = vec![];
|
||||
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);
|
||||
}
|
||||
|
||||
let v0_message = v0::Message::try_compile(
|
||||
&payer.pubkey(),
|
||||
&instructions,
|
||||
&address_lookup_table_accounts,
|
||||
blockhash,
|
||||
)
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
let v0_message: v0::Message =
|
||||
v0::Message::try_compile(&payer.pubkey(), &instructions, &address_lookup_table_accounts, blockhash_to_use)?;
|
||||
let versioned_message: VersionedMessage = VersionedMessage::V0(v0_message.clone());
|
||||
let transaction = VersionedTransaction::try_new(versioned_message, &[payer.as_ref()])?;
|
||||
|
||||
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);
|
||||
// nonce_cache.mark_used();
|
||||
// verify_lookup_table_usage(&v0_message, &address_lookup_table_accounts);
|
||||
|
||||
Ok(transaction)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user