Shred Delivery and Sender are now live! Get earliest access to raw Solana data and optimized transaction sending. Learn about Shred Delivery | Learn about Sender
Shred Delivery and Sender are now live! Get earliest access to raw Solana data and optimized transaction sending. Learn about Shred Delivery | Learn about Sender
使用 Helius 优先费用 API,通过序列化交易获取最准确的 Solana 优先费用估算。非常适合生产应用。
构建您的交易
序列化交易
获取费用估算
应用优先费用
import {
Connection,
PublicKey,
Transaction,
SystemProgram,
ComputeBudgetProgram
} from "@solana/web3.js";
import bs58 from "bs58";
const connection = new Connection("https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY");
// 1. Build your transaction (without priority fee)
const transaction = new Transaction();
const transferIx = SystemProgram.transfer({
fromPubkey: senderKeypair.publicKey,
toPubkey: recipientPublicKey,
lamports: 1000000, // 0.001 SOL
});
transaction.add(transferIx);
// 2. Set required fields and serialize
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.feePayer = senderKeypair.publicKey;
const serializedTx = bs58.encode(transaction.serialize());
// 3. Get priority fee estimate
const priorityFee = await getPriorityFeeEstimate(connection, serializedTx, "Medium");
// 4. Add priority fee and send
transaction.instructions = []; // Reset
transaction.add(ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priorityFee }));
transaction.add(transferIx);
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.sign(senderKeypair);
async function getPriorityFeeEstimate(connection, serializedTransaction, priorityLevel = "Medium") {
const response = await fetch(connection.rpcEndpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "getPriorityFeeEstimate",
params: [{
transaction: serializedTransaction,
options: {
priorityLevel: priorityLevel,
recommended: true
}
}]
})
});
const result = await response.json();
if (result.error) {
throw new Error(`Fee estimation failed: ${JSON.stringify(result.error)}`);
}
return result.result.priorityFeeEstimate;
}
展开查看完整示例
const {
Connection,
PublicKey,
Transaction,
SystemProgram,
ComputeBudgetProgram,
sendAndConfirmTransaction,
Keypair
} = require("@solana/web3.js");
const bs58 = require("bs58");
// Initialize connection and accounts
const connection = new Connection("https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY");
const senderKeypair = Keypair.fromSecretKey(bs58.decode("YOUR_PRIVATE_KEY"));
const receiverPublicKey = new PublicKey("RECIPIENT_PUBLIC_KEY");
async function sendTransactionWithPriorityFee(amount, priorityLevel = "Medium") {
// 1. Create transaction with transfer instruction
const transaction = new Transaction();
const transferIx = SystemProgram.transfer({
fromPubkey: senderKeypair.publicKey,
toPubkey: receiverPublicKey,
lamports: amount,
});
transaction.add(transferIx);
// 2. Set required fields for serialization
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.feePayer = senderKeypair.publicKey;
// 3. Serialize the transaction
const serializedTransaction = bs58.encode(transaction.serialize());
// 4. Get priority fee estimate
const priorityFee = await getPriorityFeeEstimate(connection, serializedTransaction, priorityLevel);
console.log(`Estimated ${priorityLevel} priority fee: ${priorityFee} micro-lamports`);
// 5. Reset transaction and add priority fee instruction first
transaction.instructions = [];
// Add priority fee instruction
const priorityFeeIx = ComputeBudgetProgram.setComputeUnitPrice({
microLamports: priorityFee
});
transaction.add(priorityFeeIx);
// Re-add the original transfer instruction
transaction.add(transferIx);
// 6. Update blockhash and sign
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.sign(senderKeypair);
// 7. Send the transaction
try {
const signature = await sendAndConfirmTransaction(
connection,
transaction,
[senderKeypair],
{ maxRetries: 0 } // Set to 0 for staked connection usage
);
console.log(`Transaction successful with signature: ${signature}`);
return signature;
} catch (error) {
console.error("Error sending transaction:", error);
throw error;
}
}
// Usage
sendTransactionWithPriorityFee(1000000, "High"); // Send 0.001 SOL with high priority
包含所有优先级别
async function getAllPriorityLevels(connection, serializedTransaction) {
const response = await fetch(connection.rpcEndpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "getPriorityFeeEstimate",
params: [{
transaction: serializedTransaction,
options: {
includeAllPriorityFeeLevels: true
}
}]
})
});
const result = await response.json();
return result.result.priorityFeeLevels;
}
// Usage
const allLevels = await getAllPriorityLevels(connection, serializedTransaction);
console.log("All priority levels:", allLevels);
/*
Output:
{
"min": 0,
"low": 1000,
"medium": 5000,
"high": 15000,
"veryHigh": 50000,
"unsafeMax": 100000
}
*/
包含详细分析
async function getDetailedFeeAnalysis(connection, serializedTransaction) {
const response = await fetch(connection.rpcEndpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "getPriorityFeeEstimate",
params: [{
transaction: serializedTransaction,
options: {
includeDetails: true,
priorityLevel: "Medium"
}
}]
})
});
const result = await response.json();
console.log("Detailed analysis:", result.result);
return result.result;
}
自定义回溯期
async function getCustomLookbackEstimate(connection, serializedTransaction, lookbackSlots = 50) {
const response = await fetch(connection.rpcEndpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "getPriorityFeeEstimate",
params: [{
transaction: serializedTransaction,
options: {
priorityLevel: "Medium",
lookbackSlots: lookbackSlots // 1-150, default is 150
}
}]
})
});
const result = await response.json();
return result.result.priorityFeeEstimate;
}
// Compare different lookback periods
const recentEstimate = await getCustomLookbackEstimate(connection, serializedTx, 30);
const longerEstimate = await getCustomLookbackEstimate(connection, serializedTx, 100);
console.log(`Recent (30 slots): ${recentEstimate} micro-lamports`);
console.log(`Longer (100 slots): ${longerEstimate} micro-lamports`);
// ✅ Good - serialize actual transaction
const transaction = new Transaction();
transaction.add(actualInstruction1);
transaction.add(actualInstruction2);
const serialized = bs58.encode(transaction.serialize());
// ✅ Good - all business logic included
transaction.add(createAccountIx);
transaction.add(initializeIx);
transaction.add(transferIx);
// ❌ Don't include priority fee in estimation
class SerializedTransactionFeeEstimator {
constructor(connection) {
this.connection = connection;
this.fallbackFee = 10000; // 10k micro-lamports
}
async getEstimate(serializedTransaction, priorityLevel = "Medium") {
try {
// Primary attempt with serialized transaction
return await this.getPrimaryEstimate(serializedTransaction, priorityLevel);
} catch (error) {
console.warn("Serialized transaction estimate failed:", error.message);
// Fallback to account-based estimation
try {
return await this.getFallbackEstimate(serializedTransaction, priorityLevel);
} catch (fallbackError) {
console.warn("Fallback estimate failed:", fallbackError.message);
return this.getFallbackFee(priorityLevel);
}
}
}
async getPrimaryEstimate(serializedTransaction, priorityLevel) {
const response = await fetch(this.connection.rpcEndpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "getPriorityFeeEstimate",
params: [{
transaction: serializedTransaction,
options: {
priorityLevel: priorityLevel,
recommended: true
}
}]
})
});
const result = await response.json();
if (result.error) {
throw new Error(result.error.message);
}
return result.result.priorityFeeEstimate;
}
async getFallbackEstimate(serializedTransaction, priorityLevel) {
// Extract account keys from transaction and use account-based estimation
const transaction = Transaction.from(bs58.decode(serializedTransaction));
const accountKeys = transaction.instructions
.flatMap(ix => [ix.programId, ...ix.keys.map(k => k.pubkey)])
.map(key => key.toString());
const uniqueAccountKeys = [...new Set(accountKeys)];
// Use account-based estimation as fallback
const response = await fetch(this.connection.rpcEndpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: "1",
method: "getPriorityFeeEstimate",
params: [{
accountKeys: uniqueAccountKeys,
options: {
priorityLevel: priorityLevel,
recommended: true
}
}]
})
});
const result = await response.json();
if (result.error) {
throw new Error(result.error.message);
}
return result.result.priorityFeeEstimate;
}
getFallbackFee(priorityLevel) {
const fallbacks = {
"Low": 1000,
"Medium": 5000,
"High": 15000,
"VeryHigh": 50000
};
return fallbacks[priorityLevel] || 5000;
}
}
// Usage
const estimator = new SerializedTransactionFeeEstimator(connection);
const fee = await estimator.getEstimate(serializedTransaction, "High");
交易序列化错误
// ✅ Always set these fields
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.feePayer = keypair.publicKey;
// Then serialize
const serialized = bs58.encode(transaction.serialize());
过期的Blockhash问题
// Get estimate with temporary blockhash
const tempBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.recentBlockhash = tempBlockhash;
const serialized = bs58.encode(transaction.serialize());
const priorityFee = await getPriorityFeeEstimate(connection, serialized, "Medium");
// Reset and rebuild with fresh blockhash
transaction.instructions = [];
transaction.add(ComputeBudgetProgram.setComputeUnitPrice({ microLamports: priorityFee }));
transaction.add(originalInstruction);
// Get FRESH blockhash before sending
const freshBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.recentBlockhash = freshBlockhash;
大型交易错误
import { VersionedTransaction, TransactionMessage } from "@solana/web3.js";
// For large transactions, use versioned transactions
const messageV0 = new TransactionMessage({
payerKey: keypair.publicKey,
recentBlockhash: (await connection.getLatestBlockhash()).blockhash,
instructions: [instruction1, instruction2, instruction3] // Many instructions
}).compileToV0Message();
const versionedTransaction = new VersionedTransaction(messageV0);
const serialized = bs58.encode(versionedTransaction.serialize());