网站Logo 北之屿

SOL交易构建

beiyu
6
2025-08-08

指令构建方式

使用 Anchor构建

// 使用 Anchor 构建交易
const buyTokenExactInArgs = {
    payAmount: new BN(100000000), // 0.01 SOL (10,000,000 lamports)
    minReceive: new BN(0),       // 最少接收1个代币
    donateRate: 0                // 捐赠率为0
};

const tx= await program.methods
    .buyTokenExactIn(buyTokenExactInArgs)  //交易参数
    .accounts(accounts) //指令账户
    .instruction(); //创建交易指令
  

原生构建

// 原生方式构建交易
const accounts = [
    { pubkey: account1, isSigner: true, isWritable: false },
    { pubkey: account2, isSigner: false, isWritable: true }
];

const tx= new TransactionInstruction({
    programId: programId,
    keys: accounts,
    data: instructionData
});

const transaction = new Transaction().add(instruction);

⚙️ 费用配置

计算单元限制,

const computeUnitLimit = 500000; // 根据指令复杂度调整
const computeLimitInstruction = ComputeBudgetProgram.setComputeUnitLimit({
    units: computeUnitLimit
});

Priority Fee 设置(优先费)

const priorityFeeInMicroLamports = 100000; // 网络拥堵情况调整
const priorityFeeInstruction = ComputeBudgetProgram.setComputeUnitPrice({
    microLamports: priorityFeeInMicroLamports
});

// 计算实际费用,计算单元 * PriorityFee / 1000000
const estimatedPriorityFee = (computeUnitLimit * priorityFeeInMicroLamports) / 1000000;

Jito Fee (可选)

const jitoTipAccounts = [
    "96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5",
    // ... 其他账户
];

const jitoTipAccount = new PublicKey(jitoTipAccounts[Math.floor(Math.random() * jitoTipAccounts.length)]);
const jitoFeeInLamports = 20000;

const jitoTipInstruction = SystemProgram.transfer({
    fromPubkey: playerKeyPair.publicKey,
    toPubkey: jitoTipAccount,
    lamports: jitoFeeInLamports
});

🔧 交易最终设置

基本设置

// 设置手续费的支付者
tx.feePayer = playerKeyPair.publicKey;

// 获取最新区块哈希
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
tx.recentBlockhash = blockhash;
tx.lastValidBlockHeight = lastValidBlockHeight;

添加费用指令(按顺序)

const finalTransaction = new Transaction();

// 指令顺序很重要!
finalTransaction.add(computeLimitInstruction);      // 1. 计算单元限制
finalTransaction.add(priorityFeeInstruction);       // 2. Priority Fee
finalTransaction.add(jitoTipInstruction);           // 3. Jito Fee (可选)
finalTransaction.add(mainInstruction);              // 4. 主要业务指令

// 设置交易属性
finalTransaction.feePayer = tx.feePayer;
finalTransaction.recentBlockhash = tx.recentBlockhash;
finalTransaction.lastValidBlockHeight = tx.lastValidBlockHeight;

⚠️ 关键计算和检查

账户余额检查

const balance = await connection.getBalance(playerKeyPair.publicKey);
const requiredBalance = maxPay + estimatedPriorityFee + jitoFeeInLamports + 5000; // 基础费用

if (balance < requiredBalance) {
    throw new Error(`余额不足: 需要 ${requiredBalance} lamports, 当前 ${balance} lamports`);
}

滑点保护

// ⚠️ 重要:不要设置 minReceive: 0,可能会遇到夹子
// 需要修改指令参数中的最小接收数量
// 计算合理的最小接收量
const slippageTolerance = 0.05; // 5% 滑点
const expectedTokens = await calculateExpectedOutput(maxPay); // 需要实现
const minReceive = Math.floor(expectedTokens * (1 - slippageTolerance));

交易大小检查

const serializedTransaction = finalTransaction.serialize();
console.log('交易大小:', serializedTransaction.length, 'bytes');

if (serializedTransaction.length > 1232) {
    throw new Error('交易过大,超过 1232 bytes 限制');
}

费用计算总结

const totalFees = {
    baseFee: 5000,                    // 系统自动收取
    priorityFee: estimatedPriorityFee, // 手动设置
    jitoFee: jitoFeeInLamports,       // 可选
    total: 5000 + estimatedPriorityFee + jitoFeeInLamports
};

console.log('费用明细:', totalFees);

📤 交易发送和确认

签名和发送

// 签名交易
finalTransaction.sign(playerKeyPair);

// 发送交易
const signature = await connection.sendRawTransaction(
    finalTransaction.serialize(),
    {
        skipPreflight: false,
        preflightCommitment: 'finalized',
        maxRetries: 5
    }
);

等待确认

// 等待交易确认
const confirmation = await connection.confirmTransaction({
    signature: signature,
    blockhash: blockhash,
    lastValidBlockHeight: lastValidBlockHeight
});

if (confirmation.value.err) {
    throw new Error(`交易失败: ${confirmation.value.err}`);
}

📊 完整示例总结

// 1. 环境准备 ✅
// 2. 账户计算 ✅  
// 3. 参数验证 ⚠️ (需要完善滑点保护)
// 4. 费用配置 ✅
// 5. 交易构建 ✅
// 6. 大小检查 ⚠️ (建议添加)
// 7. 余额检查 ⚠️ (建议添加)  
// 8. 签名发送 ✅
// 9. 确认等待 ⚠️ (建议添加)

🚨 常见风险和注意事项

高风险

  • minReceive: 0 → 可能遭受三明治攻击

  • 缺少余额检查 → 交易可能因余额不足失败

  • 区块哈希过期 → 交易可能被拒绝

中风险

  • 固定 Priority Fee → 网络拥堵时执行慢

  • 缺少重试机制 → 临时网络问题导致失败

  • 交易大小超限 → 交易被拒绝

动物装饰