网站Logo 北之屿

SOL原生交易的构建

beiyu
6
2025-08-08

指令处理

// 关键点:Buffer 大小根据实际指令长度确定,通常对齐到 32 字节
const hexData = "ea8dbeecdd59098f00e1f50500000000000000000000000000000000";
const actualLength = hexData.length / 2; // 28 字节
const bufferSize = Math.max(actualLength, 32); // 确保至少 32 字节对齐

const dataBuffer = Buffer.alloc(bufferSize);
dataBuffer.write(hexData, "hex");
const instructionData = new Uint8Array(dataBuffer);

计算要点

  • 十六进制字符串长度 ÷ 2 = 实际字节数

  • Buffer 大小建议 32 字节对齐(程序要求 + 内存优化)

  • 前 8 字节:Anchor 程序指令标识符

  • 第 9-16 字节:参数数据(具体含义看程序设计)

这里获取到的指令可以直接在链上查看

Buffer.alloc(32) 位数是根据指令长度来设置的

构建 Solana 交易指令

// 交易构建
const mainInstruction = new TransactionInstruction({
    programId: PROGRAM_ID,
    keys: [
        {pubkey: new PublicKey("GRAwZQybSEocRMhm27tsfRa3kC5EUwzs9cBUpJBHvVrM"), isSigner: false, isWritable: false}, // config
        {pubkey: new PublicKey("HRT51LkhmTS5Y56SE1F2tQbccrHtzgrfVnvNK6o5nVrC"), isSigner: false, isWritable: true}, // market #
		 // ...
    ],
    data: data
});

计算单元估算

// 固定计算单元值
const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({ 
    units: 300000 
});

// 动态计算所需计算单元
const baseComputeUnits = 5000;           // 基础开销
const accountReadCost = accounts.length * 200;   // 每个账户读取成本
const programInvokeCost = 10000;         // 程序调用成本
const estimated = baseComputeUnits + accountReadCost + programInvokeCost;
// 安全边际
const computeLimit = Math.min(estimated * 1.5, 1400000); // 150% 缓冲,不超过上限

计算要素

  • 账户数量:每个账户约 200 CU

  • 程序复杂度:DeFi 操作通常 50K-300K CU

  • 安全边际:建议 150% 缓冲

  • 上限限制:单次交易最多 1.4M CU

优先费计算

// 固定优先费
const addPriorityFee = ComputeBudgetProgram.setComputeUnitPrice({ 
    microLamports: 1000 
});

// 动态计算优先费
const networkCongestion = await getNetworkCongestion(); // 获取网络拥堵状态
const baseFee = 1000; // 基础费用(微 lamports)
const priorityFee = baseFee * (1 + networkCongestion); // 动态调整

const addPriorityFee = ComputeBudgetProgram.setComputeUnitPrice({
    microLamports: Math.min(priorityFee, 10000) // 设置上限
});

费用策略

  • 低拥堵:1000-2000 micro-lamports

  • 中等拥堵:3000-5000 micro-lamports

  • 高拥堵:5000-10000 micro-lamports

交易指令组装顺序

const instructions = [
    modifyComputeUnits,    // 1. 计算单元限制
    addPriorityFee,        // 2. 优先费设置  
    mainInstruction        // 3. 主要业务指令
];

交易消息构建

// 获取最新的区块哈希
const latestBlockhash = await connection.getLatestBlockhash();

// 交易消息构建
const messageV0 = new TransactionMessage({
    payerKey: walletKeyPair.publicKey,
    recentBlockhash: latestBlockhash.blockhash,
    instructions: [modifyComputeUnits, addPriorityFee, mainInstruction]
}).compileToV0Message();
// 创建版本化交易对象
const transaction = new VersionedTransaction(messageV0);
//签名交易
transaction.sign([walletKeyPair]);

关键配置

  • payerKey:交易费用支付者

  • recentBlockhash:防重放攻击,有时效性(约 150 个 slot)

  • instructions 顺序:预算指令 → 业务指令

  • V0 格式:支持地址查找表,节省交易大小

提交交易到网络

// 发送交易
const signature = await connection.sendTransaction(transaction, {
    skipPreflight: false,  / 预检查开启
    preflightCommitment: "confirmed",
    maxRetries: 3
});
console.log("交易已发送,签名:", signature);

// 等待确认
await connection.confirmTransaction({
    signature,
    blockhash: latestBlockhash.blockhash,
    lastValidBlockHeight: latestBlockhash.lastValidBlockHeight
});

动物装饰