feat: add wrap_wsol_to_sol function with seed account optimization

This commit is contained in:
ysq
2025-11-20 11:21:27 +08:00
parent f06d6b4eee
commit c0e026a88a
7 changed files with 161 additions and 12 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "sol-trade-sdk"
version = "3.3.2"
version = "3.3.3"
edition = "2021"
authors = [
"William <byteblock6@gmail.com>",
+2 -2
View File
@@ -87,14 +87,14 @@ Add the dependency to your `Cargo.toml`:
```toml
# Add to your Cargo.toml
sol-trade-sdk = { path = "./sol-trade-sdk", version = "3.3.2" }
sol-trade-sdk = { path = "./sol-trade-sdk", version = "3.3.3" }
```
### Use crates.io
```toml
# Add to your Cargo.toml
sol-trade-sdk = "3.3.2"
sol-trade-sdk = "3.3.3"
```
## 🛠️ Usage Examples
+2 -2
View File
@@ -87,14 +87,14 @@ git clone https://github.com/0xfnzero/sol-trade-sdk
```toml
# 添加到您的 Cargo.toml
sol-trade-sdk = { path = "./sol-trade-sdk", version = "3.3.2" }
sol-trade-sdk = { path = "./sol-trade-sdk", version = "3.3.3" }
```
### 使用 crates.io
```toml
# 添加到您的 Cargo.toml
sol-trade-sdk = "3.3.2"
sol-trade-sdk = "3.3.3"
```
## 🛠️ 使用示例
+30 -6
View File
@@ -6,7 +6,10 @@ use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🔄 WSOL Wrapper Example");
println!("This example demonstrates how to wrap SOL to WSOL and unwrap WSOL back to SOL");
println!("This example demonstrates:");
println!("1. Wrapping SOL to WSOL");
println!("2. Partial unwrapping WSOL back to SOL using seed account");
println!("3. Closing WSOL account and unwrapping remaining balance");
// Initialize SolanaTrade client
let solana_trade = create_solana_trade_client().await?;
@@ -24,15 +27,36 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
Err(e) => {
println!("❌ Failed to wrap SOL to WSOL: {}", e);
return Ok(());
}
}
// Wait a moment before unwrapping
println!("\n⏳ Waiting 3 seconds before unwrapping...");
// Wait a moment before partial unwrapping
println!("\n⏳ Waiting 3 seconds before partial unwrapping...");
tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
// Example 2: Close WSOL account and unwrap all remaining balance
println!("\n🔒 Example 2: Closing WSOL account and unwrapping remaining balance");
// Example 2: Unwrap half of the WSOL back to SOL using seed account
println!("\n🔄 Example 2: Unwrapping half of WSOL back to SOL using seed account");
let unwrap_amount = wrap_amount / 2; // Half of the wrapped amount
println!("Unwrapping {} lamports (0.0005 SOL) back to SOL using seed account...", unwrap_amount);
match solana_trade.wrap_wsol_to_sol(unwrap_amount).await {
Ok(signature) => {
println!("✅ Successfully unwrapped half of WSOL back to SOL using seed account!");
println!("Transaction signature: {}", signature);
println!("Explorer: https://solscan.io/tx/{}", signature);
}
Err(e) => {
println!("❌ Failed to unwrap WSOL to SOL: {}", e);
}
}
// Wait a moment before final unwrapping
println!("\n⏳ Waiting 3 seconds before final unwrapping...");
tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
// Example 3: Close WSOL account and unwrap all remaining balance
println!("\n🔒 Example 3: Closing WSOL account and unwrapping remaining balance");
println!("Closing WSOL account and unwrapping all remaining balance to SOL...");
match solana_trade.close_wsol().await {
@@ -53,7 +77,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// Create and initialize SolanaTrade client
async fn create_solana_trade_client() -> Result<SolanaTrade, Box<dyn std::error::Error>> {
println!("🚀 Initializing SolanaTrade client...");
let payer = Keypair::from_base58_string("use_your_payer_keypair_here");
let payer = Keypair::from_base58_string("R26eUYq691PC7AFh6yNyC285qr5tZfu43SAYhKGNZrpRVmrwDhR254bSS7Z1e87LWCmPNmiPvYkz9kA9hXyQD2m");
let rpc_url = "https://api.mainnet-beta.solana.com".to_string();
let commitment = CommitmentConfig::confirmed();
let swqos_configs: Vec<SwqosConfig> = vec![SwqosConfig::Default(rpc_url.clone())];
+29
View File
@@ -30,6 +30,35 @@ pub fn close_account(
Ok(Instruction { program_id: *token_program_id, accounts, data })
}
pub fn transfer(
token_program_id: &Pubkey,
source_pubkey: &Pubkey,
destination_pubkey: &Pubkey,
owner_pubkey: &Pubkey,
amount: u64,
signers: &[&Pubkey],
) -> Result<Instruction, ProgramError> {
// Transfer
let mut data = Vec::with_capacity(9);
data.push(3); // Instruction discriminator for Transfer
data.extend_from_slice(&amount.to_le_bytes());
let mut accounts = Vec::with_capacity(3 + signers.len());
accounts.push(AccountMeta::new(*source_pubkey, false));
accounts.push(AccountMeta::new(*destination_pubkey, false));
accounts.push(AccountMeta::new_readonly(*owner_pubkey, signers.is_empty()));
for signer in signers.iter() {
accounts.push(AccountMeta::new_readonly(**signer, true));
}
Ok(Instruction {
program_id: *token_program_id,
accounts,
data,
})
}
pub fn initialize_account3(
token_program_id: &Pubkey,
account_pubkey: &Pubkey,
+36
View File
@@ -663,4 +663,40 @@ impl SolanaTrade {
let signature = self.rpc.send_and_confirm_transaction(&transaction).await?;
Ok(signature.to_string())
}
/// 将 WSOL 转换为 SOL,使用 seed 账户
///
/// 这个函数实现以下步骤:
/// 1. 使用 super::seed::create_associated_token_account_use_seed 创建 WSOL seed 账号
/// 2. 使用 get_associated_token_address_with_program_id_use_seed 获取该账号的 ATA 地址
/// 3. 添加从用户 WSOL ATA 转账到该 seed ATA 账号的指令
/// 4. 添加关闭 WSOL seed 账号的指令
///
/// # Arguments
/// * `amount` - 要转换的 WSOL 数量(以 lamports 为单位)
///
/// # Returns
/// * `Ok(String)` - 交易签名
/// * `Err(anyhow::Error)` - 如果交易执行失败
///
/// # Errors
///
/// 此函数在以下情况下会返回错误:
/// - 用户 WSOL ATA 中余额不足
/// - seed 账户创建失败
/// - 转账指令执行失败
/// - 交易执行或确认失败
/// - 网络或 RPC 错误
pub async fn wrap_wsol_to_sol(&self, amount: u64) -> Result<String, anyhow::Error> {
use crate::trading::common::wsol_manager::wrap_wsol_to_sol as wrap_wsol_to_sol_internal;
use solana_sdk::transaction::Transaction;
let recent_blockhash = self.rpc.get_latest_blockhash().await?;
let instructions = wrap_wsol_to_sol_internal(&self.payer.pubkey(), amount)?;
let mut transaction = Transaction::new_with_payer(&instructions, Some(&self.payer.pubkey()));
transaction.sign(&[&*self.payer], recent_blockhash);
let signature = self.rpc.send_and_confirm_transaction(&transaction).await?;
Ok(signature.to_string())
}
}
+61 -1
View File
@@ -1,5 +1,7 @@
use crate::common::{
fast_fn::create_associated_token_account_idempotent_fast, spl_token::close_account,
fast_fn::create_associated_token_account_idempotent_fast,
spl_token::close_account,
seed::{create_associated_token_account_use_seed, get_associated_token_address_with_program_id_use_seed},
};
use smallvec::SmallVec;
use solana_sdk::{instruction::Instruction, message::AccountMeta, pubkey::Pubkey};
@@ -92,3 +94,61 @@ pub fn wrap_sol_only(payer: &Pubkey, amount_in: u64) -> SmallVec<[Instruction; 2
insts
}
/// 将 WSOL 转换为 SOL,使用 seed 账户
/// 1. 使用 super::seed::create_associated_token_account_use_seed 创建 WSOL seed 账号
/// 2. 使用 get_associated_token_address_with_program_id_use_seed 获取该账号的 ATA 地址
/// 3. 添加从用户 WSOL ATA 转账到该 seed ATA 账号的指令
/// 4. 添加关闭 WSOL seed 账号的指令
pub fn wrap_wsol_to_sol(
payer: &Pubkey,
amount: u64,
) -> Result<Vec<Instruction>, anyhow::Error> {
let mut instructions = Vec::new();
// 1. 创建 WSOL seed 账户
let seed_account_instructions = create_associated_token_account_use_seed(
payer,
payer,
&crate::constants::WSOL_TOKEN_ACCOUNT,
&crate::constants::TOKEN_PROGRAM,
)?;
instructions.extend(seed_account_instructions);
// 2. 获取 seed 账户的 ATA 地址
let seed_ata_address = get_associated_token_address_with_program_id_use_seed(
payer,
&crate::constants::WSOL_TOKEN_ACCOUNT,
&crate::constants::TOKEN_PROGRAM,
)?;
// 3. 获取用户的 WSOL ATA 地址
let user_wsol_ata = crate::common::fast_fn::get_associated_token_address_with_program_id_fast(
payer,
&crate::constants::WSOL_TOKEN_ACCOUNT,
&crate::constants::TOKEN_PROGRAM,
);
// 4. 添加从用户 WSOL ATA 转账到 seed ATA 的指令
let transfer_instruction = crate::common::spl_token::transfer(
&crate::constants::TOKEN_PROGRAM,
&user_wsol_ata,
&seed_ata_address,
payer,
amount,
&[],
)?;
instructions.push(transfer_instruction);
// 5. 添加关闭 WSOL seed 账户的指令
let close_instruction = close_account(
&crate::constants::TOKEN_PROGRAM,
&seed_ata_address,
payer,
payer,
&[],
)?;
instructions.push(close_instruction);
Ok(instructions)
}