最も正確な方法: 正確なトランザクションを分析することで最も高精度な優先手数料の推定が得られます。精度が最も重要なプロダクションアプリケーションに推奨されます。
概要
シリアライズトランザクションは、トランザクションで実行される正確なアカウントや操作をAPIが分析できるため、最も正確な手数料推定を提供します。シリアライズトランザクションを使用する理由
- 最高の精度 - 正確な操作を分析
- 詳細な分析 - 命令ごとのパターン
- 現実的な推定 - 実際のトランザクションを反映
- プロダクション対応 - 重要なアプリケーション向けに構築
最適な用途
- プロダクションアプリケーション
- 複雑なトランザクション
- 重要な操作
- 最大精度が必要な場合
アカウントキーに対する利点
- 精度の利点
- 実世界での利点
命令ごとの分析
APIは特定の操作とその歴史的な手数料パターンをアカウントアクティビティだけでなく分析できます。
トランザクションサイズの認識
トランザクションの実際のサイズと複雑さを考慮して、より正確な推定を行います。
読み取り専用アカウントの処理
トランザクションコンテキストでの書き込み可能および読み取り専用アカウントのより良い分析。
実装ガイド
1
トランザクションを構築
すべての命令(優先手数料を除く)でトランザクションを作成
2
トランザクションをシリアライズ
トランザクションをシリアライズ形式に変換
3
手数料推定を取得
シリアライズされたトランザクションでPriority Fee APIを呼び出す
4
優先手数料を適用
優先手数料の命令を追加してトランザクションを送信
クイックスタート例
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);
import requests
import json
from solana.transaction import Transaction
from solana.system_program import transfer, TransferParams
# Build and serialize transaction
def get_serialized_transaction():
# Build your transaction here
# Return base58 encoded serialized transaction
pass
# Get priority fee estimate
def get_priority_fee_estimate(serialized_tx, priority_level="Medium"):
response = requests.post(
"https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY",
json={
"jsonrpc": "2.0",
"id": "1",
"method": "getPriorityFeeEstimate",
"params": [{
"transaction": serialized_tx,
"options": {
"priorityLevel": priority_level,
"recommended": True
}
}]
}
)
return response.json()["result"]["priorityFeeEstimate"]
# Usage
serialized_tx = get_serialized_transaction()
fee = get_priority_fee_estimate(serialized_tx, "High")
print(f"Priority fee: {fee} micro-lamports")
コア実装機能
シリアライズされたトランザクションから優先手数料推定を取得するための再利用可能な関数です: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
完全な例を表示するには展開
完全な例を表示するには展開
const {
Connection,
PublicKey,
Transaction,
ComputeBudgetProgram,
sendAndConfirmTransaction,
Keypair
} = require("@solana/web3.js");
const {
createTransferInstruction,
getAssociatedTokenAddress,
TOKEN_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
} = require("@solana/spl-token");
const bs58 = require("bs58");
async function sendTokenWithPriorityFee(
connection,
senderKeypair,
recipientPublicKey,
mintAddress,
amount,
priorityLevel = "Medium"
) {
// 1. Get token account addresses
const senderTokenAccount = await getAssociatedTokenAddress(
mintAddress,
senderKeypair.publicKey
);
const recipientTokenAccount = await getAssociatedTokenAddress(
mintAddress,
recipientPublicKey
);
// 2. Create transaction with token transfer instruction
const transaction = new Transaction();
const transferIx = createTransferInstruction(
senderTokenAccount,
recipientTokenAccount,
senderKeypair.publicKey,
amount,
[],
TOKEN_PROGRAM_ID
);
transaction.add(transferIx);
// 3. Set required fields and serialize
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.feePayer = senderKeypair.publicKey;
const serializedTransaction = bs58.encode(transaction.serialize());
// 4. Get priority fee estimate
const priorityFee = await getPriorityFeeEstimate(connection, serializedTransaction, priorityLevel);
console.log(`Token transfer priority fee: ${priorityFee} micro-lamports`);
// 5. Reset and rebuild transaction with priority fee
transaction.instructions = [];
// Add priority fee instruction first
const priorityFeeIx = ComputeBudgetProgram.setComputeUnitPrice({
microLamports: priorityFee
});
transaction.add(priorityFeeIx);
// Re-add the transfer instruction
transaction.add(transferIx);
// 6. Update blockhash and send
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.sign(senderKeypair);
const signature = await sendAndConfirmTransaction(
connection,
transaction,
[senderKeypair],
{ maxRetries: 0 }
);
return signature;
}
完全な例を表示するには展開
完全な例を表示するには展開
async function complexTransactionWithPriorityFee(connection, keypair) {
// 1. Build complex transaction with multiple instructions
const transaction = new Transaction();
// Add multiple instructions
const createAccountIx = SystemProgram.createAccount({
fromPubkey: keypair.publicKey,
newAccountPubkey: newAccountKeypair.publicKey,
lamports: await connection.getMinimumBalanceForRentExemption(165),
space: 165,
programId: TOKEN_PROGRAM_ID,
});
const initializeAccountIx = createInitializeAccountInstruction(
newAccountKeypair.publicKey,
mintAddress,
keypair.publicKey,
TOKEN_PROGRAM_ID
);
const transferIx = SystemProgram.transfer({
fromPubkey: keypair.publicKey,
toPubkey: recipientPublicKey,
lamports: 1000000,
});
transaction.add(createAccountIx);
transaction.add(initializeAccountIx);
transaction.add(transferIx);
// 2. Set required fields and serialize
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.feePayer = keypair.publicKey;
const serializedTransaction = bs58.encode(transaction.serialize());
// 3. Get priority fee estimate for complex transaction
const priorityFee = await getPriorityFeeEstimate(connection, serializedTransaction, "High");
console.log(`Complex transaction priority fee: ${priorityFee} micro-lamports`);
// 4. Rebuild transaction with priority fee
transaction.instructions = [];
// Add priority fee instruction first
const priorityFeeIx = ComputeBudgetProgram.setComputeUnitPrice({
microLamports: priorityFee
});
transaction.add(priorityFeeIx);
// Optional: Set compute unit limit for complex transactions
const computeLimitIx = ComputeBudgetProgram.setComputeUnitLimit({
units: 400000 // Adjust based on your transaction complexity
});
transaction.add(computeLimitIx);
// Re-add all original instructions
transaction.add(createAccountIx);
transaction.add(initializeAccountIx);
transaction.add(transferIx);
// 5. Update blockhash and send
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.sign(keypair, newAccountKeypair);
const signature = await sendAndConfirmTransaction(
connection,
transaction,
[keypair, newAccountKeypair],
{ maxRetries: 0 }
);
return signature;
}
高度な設定オプション
すべての優先レベルを含む
すべての優先レベルを含む
すべての優先レベルの推定を一度に取得:
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");
async function safeGetPriorityFeeEstimate(connection, serializedTransaction, priorityLevel = "Medium") {
try {
return await getPriorityFeeEstimate(connection, serializedTransaction, priorityLevel);
} catch (error) {
console.warn(`Priority fee estimation failed: ${error.message}`);
// Extract account keys and fall back to account-based estimation
try {
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)];
return await getAccountBasedEstimate(connection, uniqueAccountKeys, priorityLevel);
} catch (fallbackError) {
console.warn(`Fallback estimation failed: ${fallbackError.message}`);
// Return reasonable fallback based on priority level
const fallbacks = {
"Low": 1000,
"Medium": 5000,
"High": 15000,
"VeryHigh": 50000
};
return fallbacks[priorityLevel] || 5000;
}
}
}
よくある問題と解決策
トランザクションシリアル化エラー
トランザクションシリアル化エラー
問題: 不完全なトランザクションのシリアル化エラー解決策: シリアル化前に常に必要なフィールドを設定:
// ✅ Always set these fields
transaction.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
transaction.feePayer = keypair.publicKey;
// Then serialize
const serialized = bs58.encode(transaction.serialize());
古いブロックハッシュの問題
古いブロックハッシュの問題
問題: 古いブロックハッシュの使用がトランザクションの失敗を引き起こす解決策: 最終送信前に常に新しいブロックハッシュを取得:
// 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());
アカウントキーと比較していつ使用するか
シリアライズトランザクションを使用
プロダクションアプリケーション
- 最大の精度が必要
- 複雑なマルチインストラクショントランザクション
- 重要な操作
- パフォーマンスに敏感なアプリケーション
- 最終統合試験
- パフォーマンス最適化
- プロダクション展開
アカウントキーを使用
開発とプロトタイピング
- 開発中のクイック推定
- 単純なトランザクション
- 取引計画前
- シリアル化を妨げるアーキテクチャ制約
- アカウントレベルの手数料パターン分析
- アカウントのバッチ分析
- クイックマーケットリサーチ
関連リソース
アカウントキーの方法
専門的なユースケース向けのアカウントキーを使用した高度な方法
APIリファレンス
完全なAPIドキュメントとパラメータ