指令处理
// 关键点: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
});