Merge commit 'f20dbbd7936f301be8996b4dcf2a3c6a1c999cf6'
This commit is contained in:
@@ -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
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user