feat: upgrade to v0.2.12 and refactor system instructions

This commit is contained in:
ysq
2025-08-03 22:51:11 +08:00
parent 45140ae789
commit e976af6935
11 changed files with 62 additions and 126 deletions
+3 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "sol-trade-sdk" name = "sol-trade-sdk"
version = "0.2.11" version = "0.2.12"
edition = "2021" edition = "2021"
authors = ["William <byteblock6@gmail.com>", "sgxiang <sgxiang@gmail.com>", "wei <1415121722@qq.com>"] authors = ["William <byteblock6@gmail.com>", "sgxiang <sgxiang@gmail.com>", "wei <1415121722@qq.com>"]
repository = "https://github.com/0xfnzero/sol-trade-sdk" repository = "https://github.com/0xfnzero/sol-trade-sdk"
@@ -13,7 +13,7 @@ readme = "README.md"
crate-type = ["cdylib", "rlib"] crate-type = ["cdylib", "rlib"]
[dependencies] [dependencies]
solana-streamer-sdk = "0.1.8" solana-streamer-sdk = "0.1.9"
solana-sdk = "2.1.16" solana-sdk = "2.1.16"
solana-client = "2.1.16" solana-client = "2.1.16"
solana-program = "2.1.16" solana-program = "2.1.16"
@@ -68,3 +68,4 @@ arrayref = "0.3.6"
borsh-derive = "1.5.5" borsh-derive = "1.5.5"
indicatif = "0.17.11" indicatif = "0.17.11"
pumpfun_program = { version = "4.3.0", package = "pumpfun" } pumpfun_program = { version = "4.3.0", package = "pumpfun" }
solana-system-interface = "1.0.0"
+2 -2
View File
@@ -31,14 +31,14 @@ Add the dependency to your `Cargo.toml`:
```toml ```toml
# Add to your Cargo.toml # Add to your Cargo.toml
sol-trade-sdk = { path = "./sol-trade-sdk", version = "0.2.11" } sol-trade-sdk = { path = "./sol-trade-sdk", version = "0.2.12" }
``` ```
### Use crates.io ### Use crates.io
```toml ```toml
# Add to your Cargo.toml # Add to your Cargo.toml
sol-trade-sdk = "0.2.11" sol-trade-sdk = "0.2.12"
``` ```
## Usage Examples ## Usage Examples
+2 -2
View File
@@ -31,14 +31,14 @@ git clone https://github.com/0xfnzero/sol-trade-sdk
```toml ```toml
# 添加到您的 Cargo.toml # 添加到您的 Cargo.toml
sol-trade-sdk = { path = "./sol-trade-sdk", version = "0.2.11" } sol-trade-sdk = { path = "./sol-trade-sdk", version = "0.2.12" }
``` ```
### 使用 crates.io ### 使用 crates.io
```toml ```toml
# 添加到您的 Cargo.toml # 添加到您的 Cargo.toml
sol-trade-sdk = "0.2.11" sol-trade-sdk = "0.2.12"
``` ```
## 使用示例 ## 使用示例
+7
View File
@@ -0,0 +1,7 @@
max_width = 100
hard_tabs = false
tab_spaces = 4
edition = "2021"
use_small_heuristics = "Max"
newline_style = "Unix"
+4 -15
View File
@@ -1,5 +1,6 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use solana_sdk::{instruction::Instruction, signer::Signer}; use solana_sdk::{instruction::Instruction, signer::Signer};
use solana_system_interface::instruction::transfer;
use spl_associated_token_account::instruction::create_associated_token_account_idempotent; use spl_associated_token_account::instruction::create_associated_token_account_idempotent;
use spl_token::instruction::close_account; use spl_token::instruction::close_account;
@@ -105,11 +106,7 @@ impl BonkInstructionBuilder {
); );
instructions.push( instructions.push(
// 将SOL转入wSOL ATA账户 // 将SOL转入wSOL ATA账户
solana_sdk::system_instruction::transfer( transfer(&params.payer.pubkey(), &user_quote_token_account, amount_in),
&params.payer.pubkey(),
&user_quote_token_account,
amount_in,
),
); );
// 同步wSOL余额 // 同步wSOL余额
@@ -155,11 +152,7 @@ impl BonkInstructionBuilder {
data.extend_from_slice(&minimum_amount_out.to_le_bytes()); data.extend_from_slice(&minimum_amount_out.to_le_bytes());
data.extend_from_slice(&share_fee_rate.to_le_bytes()); data.extend_from_slice(&share_fee_rate.to_le_bytes());
instructions.push(Instruction { instructions.push(Instruction { program_id: accounts::BONK, accounts, data });
program_id: accounts::BONK,
accounts,
data,
});
if protocol_params.auto_handle_wsol { if protocol_params.auto_handle_wsol {
// 关闭wSOL ATA账户,回收租金 // 关闭wSOL ATA账户,回收租金
@@ -262,11 +255,7 @@ impl BonkInstructionBuilder {
data.extend_from_slice(&minimum_amount_out.to_le_bytes()); data.extend_from_slice(&minimum_amount_out.to_le_bytes());
data.extend_from_slice(&share_fee_rate.to_le_bytes()); data.extend_from_slice(&share_fee_rate.to_le_bytes());
instructions.push(Instruction { instructions.push(Instruction { program_id: accounts::BONK, accounts, data });
program_id: accounts::BONK,
accounts,
data,
});
let protocol_params = params let protocol_params = params
.protocol_params .protocol_params
+3 -3
View File
@@ -1,5 +1,5 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use solana_sdk::{instruction::Instruction, native_token::sol_to_lamports}; use solana_sdk::{instruction::Instruction, native_token::sol_str_to_lamports};
use spl_associated_token_account::{ use spl_associated_token_account::{
get_associated_token_address, instruction::create_associated_token_account, get_associated_token_address, instruction::create_associated_token_account,
}; };
@@ -8,7 +8,7 @@ use spl_token::instruction::close_account;
use crate::{ use crate::{
constants, constants,
trading::pumpfun::common::{ trading::pumpfun::common::{
get_bonding_curve_pda, get_global_pda, get_global_volume_accumulator_pda, get_metadata_pda, get_mint_authority_pda, get_user_volume_accumulator_pda get_bonding_curve_pda, get_global_volume_accumulator_pda, get_user_volume_accumulator_pda,
}, },
}; };
@@ -57,7 +57,7 @@ impl InstructionBuilder for PumpFunInstructionBuilder {
let mut buy_token_amount = let mut buy_token_amount =
get_buy_token_amount_from_sol_amount(&bonding_curve, params.sol_amount); get_buy_token_amount_from_sol_amount(&bonding_curve, params.sol_amount);
if buy_token_amount <= 100 * 1_000_000_u64 { if buy_token_amount <= 100 * 1_000_000_u64 {
buy_token_amount = if max_sol_cost > sol_to_lamports(0.01) { buy_token_amount = if max_sol_cost > sol_str_to_lamports("0.01").unwrap_or(0) {
25547619 * 1_000_000_u64 25547619 * 1_000_000_u64
} else { } else {
255476 * 1_000_000_u64 255476 * 1_000_000_u64
+9 -22
View File
@@ -1,5 +1,6 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use solana_sdk::{instruction::Instruction, pubkey::Pubkey, signer::Signer}; use solana_sdk::{instruction::Instruction, pubkey::Pubkey, signer::Signer};
use solana_system_interface::instruction::transfer;
use spl_associated_token_account::instruction::create_associated_token_account_idempotent; use spl_associated_token_account::instruction::create_associated_token_account_idempotent;
use spl_token::instruction::close_account; use spl_token::instruction::close_account;
@@ -19,7 +20,9 @@ use crate::{
pumpswap::{ pumpswap::{
self, self,
common::{ common::{
coin_creator_vault_ata, coin_creator_vault_authority, fee_recipient_ata, find_pool, get_global_volume_accumulator_pda, get_token_amount, get_user_volume_accumulator_pda, get_wsol_amount coin_creator_vault_ata, coin_creator_vault_authority, fee_recipient_ata, find_pool,
get_global_volume_accumulator_pda, get_token_amount,
get_user_volume_accumulator_pda, get_wsol_amount,
}, },
}, },
}, },
@@ -273,7 +276,7 @@ impl PumpSwapInstructionBuilder {
); );
instructions.push( instructions.push(
// Transfer SOL to wSOL ATA account // Transfer SOL to wSOL ATA account
solana_sdk::system_instruction::transfer( transfer(
&params.payer.pubkey(), &params.payer.pubkey(),
if quote_mint_is_wsol { if quote_mint_is_wsol {
&user_quote_token_account &user_quote_token_account
@@ -302,11 +305,7 @@ impl PumpSwapInstructionBuilder {
instructions.push(create_associated_token_account_idempotent( instructions.push(create_associated_token_account_idempotent(
&params.payer.pubkey(), &params.payer.pubkey(),
&params.payer.pubkey(), &params.payer.pubkey(),
if quote_mint_is_wsol { if quote_mint_is_wsol { &base_mint } else { &quote_mint },
&base_mint
} else {
&quote_mint
},
&accounts::TOKEN_PROGRAM, &accounts::TOKEN_PROGRAM,
)); ));
@@ -362,11 +361,7 @@ impl PumpSwapInstructionBuilder {
data.extend_from_slice(&token_amount.to_le_bytes()); data.extend_from_slice(&token_amount.to_le_bytes());
} }
instructions.push(Instruction { instructions.push(Instruction { program_id: accounts::AMM_PROGRAM, accounts, data });
program_id: accounts::AMM_PROGRAM,
accounts,
data,
});
if auto_handle_wsol { if auto_handle_wsol {
// Close wSOL ATA account, reclaim rent // Close wSOL ATA account, reclaim rent
instructions.push( instructions.push(
@@ -465,11 +460,7 @@ impl PumpSwapInstructionBuilder {
instructions.push(create_associated_token_account_idempotent( instructions.push(create_associated_token_account_idempotent(
&params.payer.pubkey(), &params.payer.pubkey(),
&params.payer.pubkey(), &params.payer.pubkey(),
if quote_mint_is_wsol { if quote_mint_is_wsol { &base_mint } else { &quote_mint },
&base_mint
} else {
&quote_mint
},
&accounts::TOKEN_PROGRAM, &accounts::TOKEN_PROGRAM,
)); ));
@@ -521,11 +512,7 @@ impl PumpSwapInstructionBuilder {
data.extend_from_slice(&token_amount.to_le_bytes()); data.extend_from_slice(&token_amount.to_le_bytes());
} }
instructions.push(Instruction { instructions.push(Instruction { program_id: accounts::AMM_PROGRAM, accounts, data });
program_id: accounts::AMM_PROGRAM,
accounts,
data,
});
if auto_handle_wsol { if auto_handle_wsol {
instructions.push( instructions.push(
+11 -30
View File
@@ -1,5 +1,6 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use solana_sdk::{instruction::Instruction, signer::Signer}; use solana_sdk::{instruction::Instruction, signer::Signer};
use solana_system_interface::instruction::transfer;
use spl_associated_token_account::instruction::create_associated_token_account_idempotent; use spl_associated_token_account::instruction::create_associated_token_account_idempotent;
use spl_token::instruction::close_account; use spl_token::instruction::close_account;
@@ -49,9 +50,8 @@ impl RaydiumCpmmInstructionBuilder {
let pool_state = if protocol_params.pool_state.is_some() { let pool_state = if protocol_params.pool_state.is_some() {
protocol_params.pool_state.unwrap() protocol_params.pool_state.unwrap()
} else { } else {
let mint_token_in_pool_state_index = protocol_params let mint_token_in_pool_state_index =
.mint_token_in_pool_state_index protocol_params.mint_token_in_pool_state_index.unwrap_or(1);
.unwrap_or(1);
get_pool_pda( get_pool_pda(
&accounts::AMM_CONFIG, &accounts::AMM_CONFIG,
if mint_token_in_pool_state_index == 1 { if mint_token_in_pool_state_index == 1 {
@@ -116,11 +116,7 @@ impl RaydiumCpmmInstructionBuilder {
); );
instructions.push( instructions.push(
// 将SOL转入wSOL ATA账户 // 将SOL转入wSOL ATA账户
solana_sdk::system_instruction::transfer( transfer(&params.payer.pubkey(), &wsol_token_account, amount_in),
&params.payer.pubkey(),
&wsol_token_account,
amount_in,
),
); );
// 同步wSOL余额 // 同步wSOL余额
@@ -135,9 +131,7 @@ impl RaydiumCpmmInstructionBuilder {
&params.payer.pubkey(), &params.payer.pubkey(),
&params.payer.pubkey(), &params.payer.pubkey(),
&params.mint, &params.mint,
&protocol_params &protocol_params.mint_token_program.unwrap_or(accounts::TOKEN_PROGRAM),
.mint_token_program
.unwrap_or(accounts::TOKEN_PROGRAM),
)); ));
// 创建买入指令 // 创建买入指令
@@ -152,9 +146,7 @@ impl RaydiumCpmmInstructionBuilder {
solana_sdk::instruction::AccountMeta::new(mint_vault_account, false), // Output Vault Account solana_sdk::instruction::AccountMeta::new(mint_vault_account, false), // Output Vault Account
solana_sdk::instruction::AccountMeta::new_readonly(accounts::TOKEN_PROGRAM, false), // Input Token Program (readonly) solana_sdk::instruction::AccountMeta::new_readonly(accounts::TOKEN_PROGRAM, false), // Input Token Program (readonly)
solana_sdk::instruction::AccountMeta::new_readonly( solana_sdk::instruction::AccountMeta::new_readonly(
protocol_params protocol_params.mint_token_program.unwrap_or(accounts::TOKEN_PROGRAM),
.mint_token_program
.unwrap_or(accounts::TOKEN_PROGRAM),
false, false,
), // Output Token Program (readonly) ), // Output Token Program (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::WSOL_TOKEN_ACCOUNT, false), // Input token mint (readonly) solana_sdk::instruction::AccountMeta::new_readonly(accounts::WSOL_TOKEN_ACCOUNT, false), // Input token mint (readonly)
@@ -167,11 +159,7 @@ impl RaydiumCpmmInstructionBuilder {
data.extend_from_slice(&amount_in.to_le_bytes()); data.extend_from_slice(&amount_in.to_le_bytes());
data.extend_from_slice(&minimum_amount_out.to_le_bytes()); data.extend_from_slice(&minimum_amount_out.to_le_bytes());
instructions.push(Instruction { instructions.push(Instruction { program_id: accounts::RAYDIUM_CPMM, accounts, data });
program_id: accounts::RAYDIUM_CPMM,
accounts,
data,
});
if protocol_params.auto_handle_wsol { if protocol_params.auto_handle_wsol {
// 关闭wSOL ATA账户,回收租金 // 关闭wSOL ATA账户,回收租金
@@ -239,9 +227,8 @@ impl RaydiumCpmmInstructionBuilder {
let pool_state = if protocol_params.pool_state.is_some() { let pool_state = if protocol_params.pool_state.is_some() {
protocol_params.pool_state.unwrap() protocol_params.pool_state.unwrap()
} else { } else {
let mint_token_in_pool_state_index = protocol_params let mint_token_in_pool_state_index =
.mint_token_in_pool_state_index protocol_params.mint_token_in_pool_state_index.unwrap_or(1);
.unwrap_or(1);
get_pool_pda( get_pool_pda(
&accounts::AMM_CONFIG, &accounts::AMM_CONFIG,
if mint_token_in_pool_state_index == 1 { if mint_token_in_pool_state_index == 1 {
@@ -297,9 +284,7 @@ impl RaydiumCpmmInstructionBuilder {
solana_sdk::instruction::AccountMeta::new(mint_vault_account, false), // Input Vault Account solana_sdk::instruction::AccountMeta::new(mint_vault_account, false), // Input Vault Account
solana_sdk::instruction::AccountMeta::new(wsol_vault_account, false), // Output Vault Account solana_sdk::instruction::AccountMeta::new(wsol_vault_account, false), // Output Vault Account
solana_sdk::instruction::AccountMeta::new_readonly( solana_sdk::instruction::AccountMeta::new_readonly(
protocol_params protocol_params.mint_token_program.unwrap_or(accounts::TOKEN_PROGRAM),
.mint_token_program
.unwrap_or(accounts::TOKEN_PROGRAM),
false, false,
), // Input Token Program (readonly) ), // Input Token Program (readonly)
solana_sdk::instruction::AccountMeta::new_readonly(accounts::TOKEN_PROGRAM, false), // Output Token Program (readonly) solana_sdk::instruction::AccountMeta::new_readonly(accounts::TOKEN_PROGRAM, false), // Output Token Program (readonly)
@@ -313,11 +298,7 @@ impl RaydiumCpmmInstructionBuilder {
data.extend_from_slice(&amount.to_le_bytes()); data.extend_from_slice(&amount.to_le_bytes());
data.extend_from_slice(&minimum_amount_out.to_le_bytes()); data.extend_from_slice(&minimum_amount_out.to_le_bytes());
instructions.push(Instruction { instructions.push(Instruction { program_id: accounts::RAYDIUM_CPMM, accounts, data });
program_id: accounts::RAYDIUM_CPMM,
accounts,
data,
});
if protocol_params.auto_handle_wsol { if protocol_params.auto_handle_wsol {
instructions.push( instructions.push(
+6 -13
View File
@@ -1,11 +1,7 @@
use anyhow::anyhow; use anyhow::anyhow;
use solana_sdk::{
instruction::Instruction,
signature::Keypair,
signer::Signer,
system_instruction,
};
use solana_hash::Hash; use solana_hash::Hash;
use solana_sdk::{instruction::Instruction, signature::Keypair, signer::Signer};
use solana_system_interface::instruction::advance_nonce_account;
use crate::common::nonce_cache::NonceCache; use crate::common::nonce_cache::NonceCache;
@@ -15,8 +11,8 @@ use crate::common::nonce_cache::NonceCache;
/// 如果nonce被锁定、已使用或未准备好,将返回错误 /// 如果nonce被锁定、已使用或未准备好,将返回错误
/// 成功时会锁定并标记nonce为已使用 /// 成功时会锁定并标记nonce为已使用
pub fn add_nonce_instruction( pub fn add_nonce_instruction(
instructions: &mut Vec<Instruction>, instructions: &mut Vec<Instruction>,
payer: &Keypair payer: &Keypair,
) -> Result<(), anyhow::Error> { ) -> 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();
@@ -40,10 +36,7 @@ pub fn add_nonce_instruction(
// nonce_cache.lock(); // nonce_cache.lock();
// 创建Solana系统nonce推进指令 - 使用系统程序ID // 创建Solana系统nonce推进指令 - 使用系统程序ID
let nonce_advance_ix = system_instruction::advance_nonce_account( let nonce_advance_ix = advance_nonce_account(&nonce_pubkey, &payer.pubkey());
&nonce_pubkey,
&payer.pubkey(),
);
instructions.push(nonce_advance_ix); instructions.push(nonce_advance_ix);
} }
@@ -69,4 +62,4 @@ pub fn is_using_nonce() -> bool {
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_info.nonce_account.is_some() nonce_info.nonce_account.is_some()
} }
+8 -20
View File
@@ -2,13 +2,13 @@ use solana_hash::Hash;
use solana_sdk::{ use solana_sdk::{
instruction::Instruction, instruction::Instruction,
message::{v0, VersionedMessage}, message::{v0, VersionedMessage},
native_token::sol_to_lamports, native_token::sol_str_to_lamports,
pubkey::Pubkey, pubkey::Pubkey,
signature::Keypair, signature::Keypair,
signer::Signer, signer::Signer,
system_instruction,
transaction::VersionedTransaction, transaction::VersionedTransaction,
}; };
use solana_system_interface::instruction::transfer;
use std::sync::Arc; use std::sync::Arc;
use super::{ use super::{
@@ -54,13 +54,7 @@ pub async fn build_rpc_transaction(
let address_lookup_table_accounts = get_address_lookup_table_accounts(lookup_table_key).await; let address_lookup_table_accounts = get_address_lookup_table_accounts(lookup_table_key).await;
// 构建交易 // 构建交易
build_versioned_transaction( build_versioned_transaction(payer, instructions, address_lookup_table_accounts, blockhash).await
payer,
instructions,
address_lookup_table_accounts,
blockhash,
)
.await
} }
/// 构建带小费的交易 /// 构建带小费的交易
@@ -88,10 +82,10 @@ pub async fn build_tip_transaction(
instructions.extend(business_instructions); instructions.extend(business_instructions);
// 添加小费转账指令 // 添加小费转账指令
instructions.push(system_instruction::transfer( instructions.push(transfer(
&payer.pubkey(), &payer.pubkey(),
tip_account, tip_account,
sol_to_lamports(tip_amount), sol_str_to_lamports(tip_amount.to_string().as_str()).unwrap_or(0),
)); ));
// 获取交易使用的blockhash // 获取交易使用的blockhash
@@ -101,13 +95,7 @@ pub async fn build_tip_transaction(
let address_lookup_table_accounts = get_address_lookup_table_accounts(lookup_table_key).await; let address_lookup_table_accounts = get_address_lookup_table_accounts(lookup_table_key).await;
// 构建交易 // 构建交易
build_versioned_transaction( build_versioned_transaction(payer, instructions, address_lookup_table_accounts, blockhash).await
payer,
instructions,
address_lookup_table_accounts,
blockhash,
)
.await
} }
/// 构建版本化交易的底层函数 /// 构建版本化交易的底层函数
@@ -200,10 +188,10 @@ pub async fn build_sell_tip_transaction(
instructions.extend(business_instructions); instructions.extend(business_instructions);
// 添加小费转账指令 // 添加小费转账指令
instructions.push(system_instruction::transfer( instructions.push(transfer(
&payer.pubkey(), &payer.pubkey(),
tip_account, tip_account,
sol_to_lamports(tip_amount), sol_str_to_lamports(tip_amount.to_string().as_str()).unwrap_or(0),
)); ));
// 获取地址查找表账户 // 获取地址查找表账户
+7 -17
View File
@@ -1,7 +1,5 @@
use solana_sdk::{ use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer, transaction::Transaction};
pubkey::Pubkey, signature::Keypair, signer::Signer, system_instruction, use solana_system_interface::instruction::transfer;
transaction::Transaction,
};
use spl_associated_token_account::get_associated_token_address; use spl_associated_token_account::get_associated_token_address;
use spl_token::instruction::close_account; use spl_token::instruction::close_account;
@@ -16,10 +14,8 @@ pub async fn get_token_balance(
) -> Result<u64, anyhow::Error> { ) -> Result<u64, anyhow::Error> {
let ata = get_associated_token_address(payer, mint); let ata = get_associated_token_address(payer, mint);
let balance = rpc.get_token_account_balance(&ata).await?; let balance = rpc.get_token_account_balance(&ata).await?;
let balance_u64 = balance let balance_u64 =
.amount balance.amount.parse::<u64>().map_err(|_| anyhow!("Failed to parse token balance"))?;
.parse::<u64>()
.map_err(|_| anyhow!("Failed to parse token balance"))?;
Ok(balance_u64) Ok(balance_u64)
} }
@@ -63,8 +59,7 @@ pub async fn transfer_sol(
return Err(anyhow!("Insufficient balance")); return Err(anyhow!("Insufficient balance"));
} }
let transfer_instruction = let transfer_instruction = transfer(&payer.pubkey(), receive_wallet, amount);
system_instruction::transfer(&payer.pubkey(), receive_wallet, amount);
let recent_blockhash = rpc.get_latest_blockhash().await?; let recent_blockhash = rpc.get_latest_blockhash().await?;
@@ -108,13 +103,8 @@ pub async fn close_token_account(
} }
// 构建关闭账户指令 // 构建关闭账户指令
let close_account_ix = close_account( let close_account_ix =
&spl_token::ID, close_account(&spl_token::ID, &ata, &payer.pubkey(), &payer.pubkey(), &[&payer.pubkey()])?;
&ata,
&payer.pubkey(),
&payer.pubkey(),
&[&payer.pubkey()],
)?;
// 构建交易 // 构建交易
let recent_blockhash = rpc.get_latest_blockhash().await?; let recent_blockhash = rpc.get_latest_blockhash().await?;