Files
0xfnzero 4b451af5ff feat: Pump.fun mayhem_mode, Solana 3.1.12, TradeConfig builder alignment
- PumpFunParams::from_trade/from_dev_trade: add mayhem_mode Option; infer Mayhem
  via is_mayhem_fee_recipient when None (fixes fee recipient / NotAuthorized 6000
  when AMM protocol fee pubkey is used).
- Add is_mayhem_fee_recipient and is_amm_fee_recipient helpers in pumpfun utils.
- Bump solana-* crates to 3.1.12; align tonic/prost; use solana-message for
  AddressLookupTableAccount; add solana-system-interface 3.0.
- Update examples and latency script for new PumpFunParams signature.
- SWQoS and transaction builder adjustments for dependency changes.

Made-with: Cursor
2026-04-11 18:43:18 +08:00

308 lines
10 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# PumpFun 真实买入延迟测试
# 测试从调用buy到提交交易的完整流程
set -e
echo "================================"
echo " PumpFun 真实买入延迟测试"
echo "================================"
echo ""
# 检查 pkg-config
if ! command -v pkg-config &> /dev/null; then
echo "❌ 错误: 缺少 pkg-config"
echo ""
echo "请先安装 pkg-config:"
echo " brew install pkg-config"
echo ""
exit 1
fi
# 使用临时生成的私钥
if [ -z "$PAYER_KEYPAIR" ]; then
echo "📝 未设置PAYER_KEYPAIR,将在测试代码中生成临时密钥对"
PAYER_KEYPAIR="GENERATE_NEW" # 标记让测试代码生成新密钥对
else
echo "📝 使用用户提供的PAYER_KEYPAIR"
fi
# 使用真实的 PumpFun 代币
TEST_MINT=${TEST_MINT:-"Dna9Y9VwbFTfFzB4kN1hAbsMfPuwGHmrfD6LUQL2pump"}
echo "🪙 测试代币: $TEST_MINT"
RPC_URL=${RPC_URL:-"https://api.mainnet-beta.solana.com"}
echo "📡 RPC地址: $RPC_URL"
# SWQOS配置 - 4个并发发送节点
SWQOS_JITO=${SWQOS_JITO:-"https://mainnet.block-engine.jito.wtf/api/v1/transactions"}
SWQOS_BLOXROUTE=${SWQOS_BLOXROUTE:-"https://ny.solana.dex.blxrbdn.com"}
SWQOS_NEXTBLOCK=${SWQOS_NEXTBLOCK:-"https://api.nextblock.io/v1/solana"}
SWQOS_FLASHBLOCK=${SWQOS_FLASHBLOCK:-"https://api.flashblock.io/v1/solana"}
echo "🚀 SWQOS节点数: 4 (Jito, Bloxroute, NextBlock, FlashBlock)"
# 买入金额 (lamports, 默认0.001 SOL)
BUY_AMOUNT=${BUY_AMOUNT:-1000000}
echo "💰 买入金额: $BUY_AMOUNT lamports (0.001 SOL)"
# 滑点
SLIPPAGE=${SLIPPAGE:-1000}
echo "📊 滑点: $SLIPPAGE basis points (10%)"
# 设置日志级别
export RUST_LOG=${RUST_LOG:-"info,sol_trade_sdk=debug"}
echo "📊 日志级别: $RUST_LOG"
echo ""
echo "⚠️ 注意: 此测试使用临时生成的密钥对(无余额)"
echo " 测试目的: 验证交易构建和提交流程的延迟"
echo " 交易预期失败(余额不足),但会测量完整的性能数据"
echo ""
# 导出环境变量
export PAYER_KEYPAIR
export RPC_URL
export TEST_MINT
export BUY_AMOUNT
export SLIPPAGE
export SWQOS_JITO
export SWQOS_BLOXROUTE
export SWQOS_NEXTBLOCK
export SWQOS_FLASHBLOCK
# 清理可能存在的旧目录
rm -rf examples/pumpfun_buy_test
# 创建测试程序目录
mkdir -p examples/pumpfun_buy_test/src
# 创建测试程序
cat > examples/pumpfun_buy_test/src/main.rs << 'EOF'
use sol_trade_sdk::{
common::{TradeConfig, AnyResult},
constants::TOKEN_PROGRAM,
swqos::{SwqosConfig, SwqosRegion},
trading::{core::params::PumpFunParams, factory::DexType},
SolanaTrade, TradeTokenType, TradeBuyParams,
};
use solana_commitment_config::CommitmentConfig;
use solana_sdk::{signature::{Keypair, Signer}, pubkey::Pubkey};
use std::sync::Arc;
use std::env;
#[tokio::main]
async fn main() -> AnyResult<()> {
env_logger::init();
println!("\n🚀 初始化 PumpFun 交易客户端...\n");
// 生成临时测试密钥对
let payer_key = env::var("PAYER_KEYPAIR").unwrap_or_else(|_| "GENERATE_NEW".to_string());
let payer = if payer_key == "GENERATE_NEW" {
println!("📝 生成临时测试密钥对...");
Keypair::new()
} else {
Keypair::from_base58_string(&payer_key)
};
println!("📝 钱包地址: {}", payer.pubkey());
let rpc_url = env::var("RPC_URL").unwrap_or_else(|_| "https://api.mainnet-beta.solana.com".to_string());
let commitment = CommitmentConfig::confirmed();
// 配置4个SWQOS节点并发发送
let swqos_configs: Vec<SwqosConfig> = vec![
SwqosConfig::Jito(
String::new(), // uuid
SwqosRegion::Default,
Some(env::var("SWQOS_JITO").unwrap_or_else(|_| "https://mainnet.block-engine.jito.wtf/api/v1/transactions".to_string()))
),
SwqosConfig::Bloxroute(
String::new(), // api_token
SwqosRegion::Default,
Some(env::var("SWQOS_BLOXROUTE").unwrap_or_else(|_| "https://ny.solana.dex.blxrbdn.com".to_string()))
),
SwqosConfig::NextBlock(
String::new(), // api_token
SwqosRegion::Default,
Some(env::var("SWQOS_NEXTBLOCK").unwrap_or_else(|_| "https://api.nextblock.io/v1/solana".to_string()))
),
SwqosConfig::FlashBlock(
String::new(), // api_token
SwqosRegion::Default,
Some(env::var("SWQOS_FLASHBLOCK").unwrap_or_else(|_| "https://api.flashblock.io/v1/solana".to_string()))
),
];
println!("🚀 SWQOS配置: {} 个并发节点", swqos_configs.len());
let trade_config = TradeConfig::new(rpc_url, swqos_configs, commitment);
let client = SolanaTrade::new(Arc::new(payer), trade_config).await;
// 设置 PumpFun 的 gas 策略
sol_trade_sdk::common::GasFeeStrategy::set_global_fee_strategy(200000, 1000000, 0.005, 0.01);
println!("✅ 客户端初始化完成\n");
let mint_str = env::var("TEST_MINT").expect("TEST_MINT not set");
let mint = mint_str.parse().expect("Invalid mint address");
let buy_amount = env::var("BUY_AMOUNT")
.unwrap_or_else(|_| "1000000".to_string())
.parse::<u64>()
.expect("Invalid buy amount");
let slippage = env::var("SLIPPAGE")
.unwrap_or_else(|_| "1000".to_string())
.parse::<u64>()
.expect("Invalid slippage");
println!("🔍 获取最新区块哈希...");
let recent_blockhash = client.rpc.get_latest_blockhash().await?;
println!("✅ 区块哈希: {}\n", recent_blockhash);
println!("================================");
println!(" PumpFun 买入延迟测试");
println!("================================");
println!("🪙 代币: {}", mint);
println!("💰 金额: {} lamports", buy_amount);
println!("📊 滑点: {} basis points", slippage);
println!("================================\n");
// PumpFun买入参数 (占位;实际路径应使用 RPC 或事件填充)
let params = PumpFunParams::from_trade(
Pubkey::default(), // bonding_curve
Pubkey::default(), // associated_bonding_curve
mint, // mint
Pubkey::default(), // creator
Pubkey::default(), // creator_vault
0, // virtual_token_reserves
0, // virtual_sol_reserves
0, // real_token_reserves
0, // real_sol_reserves
None, // close_token_account_when_sell
Pubkey::default(), // fee_recipient
TOKEN_PROGRAM,
false, // is_cashback_coin
None, // mayhem_modeNone=按 fee_recipient 推断)
);
let buy_params = TradeBuyParams {
dex_type: DexType::PumpFun,
input_token_type: TradeTokenType::SOL,
mint,
input_token_amount: buy_amount,
slippage_basis_points: Some(slippage),
recent_blockhash: Some(recent_blockhash),
extension_params: Box::new(params),
address_lookup_table_account: None,
wait_transaction_confirmed: false, // 不等待确认,测试最快提交速度
create_input_token_ata: true,
close_input_token_ata: true,
create_mint_ata: true,
open_seed_optimize: false,
durable_nonce: None,
fixed_output_token_amount: None,
};
println!("⏱️ 开始执行买入流程...");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
match client.buy(buy_params).await {
Ok((success, signature)) => {
println!("\n================================");
println!(" ✅ 买入流程完成");
println!("================================");
println!("✅ 提交成功: {}", success);
println!("📝 签名: {}", signature);
println!("================================\n");
}
Err(e) => {
println!("\n================================");
println!(" ⚠️ 买入流程完成(交易失败)");
println!("================================");
println!("️ 错误: {:?}", e);
println!("\n💡 说明: 交易失败是预期的(测试账户无余额)");
println!(" 耗时统计见上方SDK日志输出");
println!("================================\n");
}
}
// 显示性能统计
println!("================================");
println!(" 性能优化模块状态");
println!("================================\n");
use sol_trade_sdk::swqos::serialization::get_serializer_stats;
let (available, capacity) = get_serializer_stats();
println!("📦 序列化器缓冲池:");
println!(" 容量: {}", capacity);
println!(" 可用: {}", available);
println!(" 使用: {}", capacity - available);
use sol_trade_sdk::trading::core::transaction_pool::get_pool_stats;
let (pool_available, pool_capacity) = get_pool_stats();
println!("\n🔧 交易构建器池:");
println!(" 容量: {}", pool_capacity);
println!(" 可用: {}", pool_available);
println!(" 使用: {}", pool_capacity - pool_available);
println!("\n================================");
println!("✅ 延迟测试完成!");
println!("================================\n");
println!("💡 提示: 查看上面的日志了解各环节详细耗时");
println!(" 日志中包含每个步骤的 step 和 total 时间\n");
Ok(())
}
EOF
# 创建 Cargo.toml
cat > examples/pumpfun_buy_test/Cargo.toml << 'EOF'
[package]
name = "pumpfun_buy_test"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "pumpfun_buy_test"
path = "src/main.rs"
[dependencies]
sol-trade-sdk = { path = "../.." }
solana-sdk = "3.0.0"
solana-commitment-config = "3.0.0"
tokio = { version = "1", features = ["full"] }
anyhow = "1.0"
env_logger = "0.11"
EOF
# 添加到workspace
if ! grep -q "examples/pumpfun_buy_test" Cargo.toml; then
sed -i.bak '/members = \[/a\
"examples/pumpfun_buy_test",
' Cargo.toml
rm -f Cargo.toml.bak
fi
echo "================================"
echo " 开始编译和运行测试..."
echo "================================"
echo ""
# 编译并运行
cargo run --release -p pumpfun_buy_test
# 从workspace中移除
sed -i.bak '/examples\/pumpfun_buy_test/d' Cargo.toml
rm -f Cargo.toml.bak
# 清理
echo ""
echo "清理测试文件..."
rm -rf examples/pumpfun_buy_test
echo ""
echo "================================"
echo " 测试完成"
echo "================================"