{"content":{"title":"如何在 Solana 上使用优先级费用","body":"### 概述 \r\n\r\n你是否希望在 Solana 上尽快确认你的交易？本指南将向你展示如何使用优先费用，在领导者队列中出价以获得优先权，并更快确认你的交易。\r\n\r\nSolana 的费用优先系统允许你在交易的基础费用上设置额外费用，这将使你的交易在领导者队列中拥有更高的优先级。通过为优先状态出价更多，你的交易更有可能被网络快速确认。\r\n\r\n> 想观看视频教程吗？请跟随 Sahil 学习[关于 Solana 上的优先费用](https://www.youtube.com/watch?v=2p1Icrm2lFI)。 \r\n\r\n#### 你将要做的事情 \r\n\r\n在本指南中，我们将引导你如何使用 Solana Web3.js 库在你的 Solana 交易中使用优先费用。我们将向你展示如何创建基础交易，创建具有更高费用的优先交易，并将它们发送到网络。\r\n\r\n通过本指南结束时，你将很好地理解如何使用优先费用为你的 Solana 交易设置优先级，并在网络上更快确认它们。\r\n\r\n#### 你需要准备什么 \r\n\r\n要跟随本指南，你需要准备以下内容：\r\n\r\n- 有关 [使用 solanaWeb3.js 进行 Solana 交易的基本经验](https://learnblockchain.cn/article/11161)\r\n- 对 JavaScript/TypeScript 编程语言的基本知识\r\n- 已安装 [Nodejs](https://nodejs.org/en/)（版本 16.15 或更高）\r\n- 已安装 npm 或 yarn（我们将使用 yarn 初始化项目并安装必要的包。如果你更喜欢使用 npm，也可以选择 npm）\r\n- TypeScript 经验和已安装 [ts-node](https://www.npmjs.com/package/ts-node)\r\n- 拥有一份带有 Devnet SOL 的 Solana Paper 钱包 (.json) （ [示例脚本](https://github.com/quiknode-labs/qn-guide-examples/blob/main/solana/new-wallet-airdrop/wallet.ts)）。\r\n\r\n### 优先费用 \r\n\r\n在我们深入了解如何利用优先费用之前，让我们先了解一下 Solana 上的优先费用。 [优先费用](https://docs.solana.com/proposals/fee_transaction_priority) 最近由 Solana 引入，允许用户对其交易在队列中的顺序有更多控制。用户可以在其交易上设置额外费用，以在 Solana 的领导者队列中出价以获得更高的优先权。优先费用较高的交易更有可能被网络快速确认，因为它们在优先费用较低的交易之前被处理。这对于发送高价值或时间敏感交易的 dApp 特别有用。\r\n\r\n优先费用在实际应用中还有哪些使用方法？想象一下一个极其热门的 NFT 铸造活动。愿意支付额外费用以确保其交易被处理的用户可能会自愿支付优先费用，以增加他们成功完成交易并获得 NFT 的机会。\r\n\r\n### 设置你的项目 \r\n\r\n在终端中创建一个新的项目目录，使用以下命令：\r\n\r\n```\r\nmkdir solana-priority-fees\r\ncd solana-priority-fees\r\n\r\n```\r\n\r\n为你的应用创建一个文件，**app.ts**：\r\n\r\n```\r\necho > app.ts\r\n\r\n```\r\n\r\n使用 \"yes\" 标志初始化你的项目，以使用新包的默认值：\r\n\r\n```\r\nyarn init --yes\r\n# 或者\r\nnpm init --yes\r\n\r\n```\r\n\r\n创建一个启用 .json 导入的 **tsconfig.json**：\r\n\r\n```\r\ntsc -init --resolveJsonModule true --target es2020\r\n\r\n```\r\n\r\n将你的纸钱包（包含 devnet SOL）保存为 **guideSecret.json** 到项目目录。如果你需要一些 devnet SOL，你可以在这里申请：\r\n\r\n🪂申请 Devnet SOL\r\n\r\n空投 1 SOL (Devnet)\r\n\r\n#### 安装 Solana Web3 依赖 \r\n\r\n我们将需要为本练习添加 Solana Web3 库。在终端中输入：\r\n\r\n```\r\nyarn add @solana/web3.js@1\r\n# 或者\r\nnpm install @solana/web3.js@1\r\n\r\n```\r\n\r\n我们将需要从这些库和我们的私钥中导入几个组件。在 **app.ts** 第 1 行添加：\r\n\r\n```\r\nimport { ComputeBudgetProgram, Connection, Keypair, LAMPORTS_PER_SOL, sendAndConfirmTransaction, SystemProgram, Transaction } from \"@solana/web3.js\";\r\nimport secret from './guideSecret.json';\r\n\r\n```\r\n\r\n\r\n\r\n#### 使用你的 QuickNode 终端连接到 Solana 集群 \r\n\r\n要在 Solana 上构建，你需要一个 API 终端来连接网络。你可以使用公共节点，也可以部署和管理你自己的基础设施；不过，如果你希望享受 8 倍的更快响应时间，可以将繁重的工作交给我们来处理。\r\n\r\n看看为什么超过 50% 的 Solana 项目选择 QuickNode 并在 [这里](https://www.quicknode.com/signup?utm_source=internal&utm_campaign=guides&utm_content=how-to-use-priority-fees) 注册一个免费账户。\r\n我们将使用一个 Solana Devnet 节点。\r\n\r\n复制 HTTP Provider 链接：\r\n\r\n![New Node](https://img.learnblockchain.cn/2025/02/25/newNodeDevnet-c685bd4807744e357b9761c1822a904d.png)\r\n\r\n在 `app.ts` 的导入语句下方，声明你的 RPC 并建立与 Solana 的 _Connection_ 连接：\r\n\r\n```\r\nconst QUICKNODE_RPC = 'https://example.solana-devnet.quiknode.pro/0123456/';\r\nconst SOLANA_CONNECTION = new Connection(QUICKNODE_RPC);\r\n\r\n```\r\n\r\n你的环境应如下所示。\r\n\r\n![Ready to Build](https://img.learnblockchain.cn/2025/02/25/0-d68376f00213c3d42987f692bddec413.png)\r\n\r\n准备好了吗？让我们开始构建吧！\r\n\r\n### 创建基础交易 \r\n\r\n#### 设置 Keypairs \r\n\r\n要创建一个基础交易，我们首先需要设置一个“发送方”和一个“接收方”密钥对。\r\n\r\n将以下代码片段添加到 `app.ts`：\r\n\r\n```\r\nconst fromKeypair = Keypair.fromSecretKey(new Uint8Array(secret));\r\nconst toKeypair = Keypair.generate();\r\n\r\n```\r\n\r\n这段代码使用 `guideSecret.json` 文件中的私钥创建一个交易发送方的密钥对，并为交易的接收方生成一个新的随机密钥对。\r\n\r\n#### 添加常量 \r\n\r\n让我们定义一些将在代码中使用的重要常量。将以下代码片段添加到你的 `app.ts` 文件中：\r\n\r\n```\r\nconst PRIORITY_RATE = 100; // 微兰波特\r\nconst SEND_AMT = 0.01 * LAMPORTS_PER_SOL;\r\nconst PRIORITY_FEE_IX = ComputeBudgetProgram.setComputeUnitPrice({microLamports: PRIORITY_RATE});\r\n\r\n```\r\n\r\n- `PRIORITY_RATE` 常量用于以微兰波特的形式设置优先费用的费率；在这个例子中，它是 100 微兰波特（1 微兰波特 = 0.000001 兰波特）。\r\n- `SEND_AMT` 用于设置交易中发送的兰波特数量。在这个例子中，它是 0.01 SOL，相当于 1000 万兰波特（1 SOL = 1,000,000,000 兰波特）。\r\n- `PRIORITY_FEE_IX` 用于设置优先费用指令，该指令稍后将添加到交易中。`ComputeBudgetProgram.setComputeUnitPrice` 是 `@solana/web3.js` 库提供的方法，允许你为交易设置计算单元价格。这意味着你可以设置每个计算单位愿意支付多少微兰波特。在这种情况下，我们使用 `PRIORITY_RATE` 常量将计算单元价格设置为 100 微兰波特。\r\n\r\n#### 计算优先费用率（针对生产应用） \r\n\r\n对于生产应用，你可能希望根据当前费用市场动态计算优先费用率。跟踪本地费用市场以及了解在你的应用中使用的正确优先费用可能会很棘手。尽管 SolanaWeb3.js 提供了 [`getRecentPrioritizationFees()`](https://www.quicknode.com/docs/solana/getRecentPrioritizationFees) 方法来帮助你理解当前的费用市场，但它只返回整个网络的单一值。\r\n\r\n费用是由程序本地化的，交易成功率可能会根据当前市场状况有很大波动。监控费用市场并调整你的优先费用对确保交易成功至关重要。QuickNode 通过我们的 [Solana Priority Fees Add-on](https://marketplace.quicknode.com/add-on/solana-priority-fee) 使跟踪费用市场变得简单。该自定义方法接受程序账户 ID 和一系列最近的区块，并返回 5% 百分位的费用分布。\r\n\r\n要使用 `qn_estimatePriorityFees` 方法，你需要通过 [marketplace 页面](https://marketplace.quicknode.com/add-on/solana-priority-fee) 或在你的终端页面（例如，`https://dashboard.quicknode.com/endpoints/219123/add-ons`）将插件添加到你的 QuickNode 终端中。\r\n\r\n以下是如何将 `qn_estimatePriorityFees` 方法添加到你的应用的示例。首先，定义请求和响应有效负载的关键接口：\r\n\r\n```\r\ninterface RequestPayload {\r\n    method: string;\r\n    params: {\r\n        last_n_blocks: number;\r\n        account: string;\r\n        api_version: number;\r\n    };\r\n    id: number;\r\n    jsonrpc: string;\r\n}\r\n\r\ninterface FeeEstimates {\r\n    extreme: number;\r\n    high: number;\r\n    low: number;\r\n    medium: number;\r\n    percentiles: {\r\n        [key: string]: number;\r\n    };\r\n}\r\n\r\ninterface ResponseData {\r\n    jsonrpc: string;\r\n    result: {\r\n        context: {\r\n            slot: number;\r\n        };\r\n        per_compute_unit: FeeEstimates;\r\n        per_transaction: FeeEstimates;\r\n    };\r\n    id: number;\r\n}\r\n\r\ninterface EstimatePriorityFeesParams {\r\n    // 用于费用估算的区块数量\r\n    last_n_blocks?: number;\r\n    // 用于提取本地估算的程序账户（例如，Jupiter: JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4）\r\n    account?: string;\r\n    // 用于提取本地估算的 API 版本\r\n    api_version?: number;\r\n    // 你的附加端点（在你的 QuickNode 控制面板中找到 - https://dashboard.quicknode.com/endpoints）\r\n    endpoint: string;\r\n}\r\n\r\n```\r\n\r\n接下来，创建一个函数来提取优先费用：\r\n\r\n```\r\nasync function fetchEstimatePriorityFees({\r\n    last_n_blocks,\r\n    account,\r\n    api_version,\r\n    endpoint\r\n}: EstimatePriorityFeesParams): Promise<ResponseData> {\r\n    // 仅包含已定义的参数\r\n    const params: any = {};\r\n    if (last_n_blocks !== undefined) {\r\n        params.last_n_blocks = last_n_blocks;\r\n    }\r\n    if (account !== undefined) {\r\n        params.account = account;\r\n    }\r\n    if (api_version !== undefined) {\r\n        params.api_version = api_version;\r\n    }\r\n\r\n    const payload: RequestPayload = {\r\n        method: 'qn_estimatePriorityFees',\r\n        params,\r\n        id: 1,\r\n        jsonrpc: '2.0',\r\n    };\r\n\r\n    const response = await fetch(endpoint, {\r\n        method: 'POST',\r\n        headers: {\r\n            'Content-Type': 'application/json',\r\n        },\r\n        body: JSON.stringify(payload),\r\n    });\r\n\r\n    if (!response.ok) {\r\n        throw new Error(`HTTP error! status: ${response.status}`);\r\n    }\r\n\r\n    const data: ResponseData = await response.json();\r\n    return data;\r\n}\r\n\r\n```\r\n\r\n最后，你可以使用 `fetchEstimatePriorityFees` 函数获取特定程序的优先费用（用于你的优先费用指令中）：\r\n\r\n```\r\n\r\nconst params: EstimatePriorityFeesParams = {\r\n    last_n_blocks: 100,\r\n    account: 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',\r\n    endpoint: 'https://你的优先费用端点/'\r\n};\r\n\r\nasync function createDynamicPriorityFeeInstruction() {\r\n    const { result } = await fetchEstimatePriorityFees(params);\r\n    const priorityFee = result.per_compute_unit.high; // 👈 插入用于根据你的交易需求计算费用的业务逻辑（例如，低，中，高或特定百分位）\r\n    const priorityFeeInstruction = ComputeBudgetProgram.setComputeUnitPrice( { microLamports: priorityFee } );\r\n    return priorityFeeInstruction;\r\n}\r\n\r\n```\r\n\r\n让我们回到我们的示例。\r\n\r\n#### 创建基础交易示例 \r\n\r\n现在我们已经有了密钥对，我们可以创建基础交易。\r\n\r\n将以下代码片段添加到你的 app.ts 文件中：\r\n\r\n```\r\nfunction generateTxExample() {\r\n    return new Transaction().add(SystemProgram.transfer({\r\n        fromPubkey: fromKeypair.publicKey,\r\n        toPubkey: toKeypair.publicKey,\r\n        lamports: SEND_AMT\r\n    }));\r\n}\r\n\r\n```\r\n\r\n这个函数创建一个新交易并添加一个 `SystemProgram.transfer` 指令。该指令将 `SEND_AMT` 兰波特从 `fromKeypair` 转移到 `toKeypair`。\r\n\r\n完美。我们已经具备构建脚本所需的工具。\r\n\r\n### 创建并发送交易 \r\n\r\n让我们创建一个函数 `createAndSendTransactions()`，演示如何在 Solana 网络上使用优先费用。在 `app.ts` 中添加：\r\n\r\n```\r\nasync function createAndSendTransactions() {\r\n    // 第一步 - 生成基础和优先交易\r\n    const txBase = generateTxExample();\r\n    const txPriority = generateTxExample().add(PRIORITY_FEE_IX);\r\n    const { blockhash, lastValidBlockHeight } = await SOLANA_CONNECTION.getLatestBlockhash();\r\n    txBase.recentBlockhash = blockhash;\r\n    txPriority.recentBlockhash = blockhash;\r\n    txBase.lastValidBlockHeight = lastValidBlockHeight;\r\n    txPriority.lastValidBlockHeight = lastValidBlockHeight;\r\n\r\n    // 第二步 - 为每个交易生成 promises\r\n    const [txBaseRequest, txPriorityRequest] = [txBase, txPriority].map(tx => sendAndConfirmTransaction(SOLANA_CONNECTION, tx, [fromKeypair]));\r\n\r\n    try {\r\n        // 第三步 - 向集群发送交易\r\n        const [txBaseId, txPriorityId] = await Promise.all([txBaseRequest, txPriorityRequest]);\r\n\r\n        // 第四步 - 获取交易结果，并记录费用\r\n        const [txBaseResult, txPriorityResult] = await Promise.all([SOLANA_CONNECTION.getTransaction(txBaseId), SOLANA_CONNECTION.getTransaction(txPriorityId)]);\r\n        console.log(`txBase URL: https://explorer.solana.com/tx/${txBaseId}?cluster=devnet`);\r\n        console.log(`txBase Fee: ${txBaseResult?.meta?.fee} 兰波特`);\r\n        console.log(`txPriority URL: https://explorer.solana.com/tx/${txPriorityId}?cluster=devnet`);\r\n        console.log(`txPriority Fee: ${txPriorityResult?.meta?.fee} 兰波特`);\r\n    } catch (error) {\r\n        console.log(error);\r\n    }\r\n}\r\n\r\n```\r\n\r\n让我们来看看这些步骤：\r\n\r\n1. 生成基础和优先交易。基础交易通过调用 `generateTxExample()` 函数生成，而优先交易则通过添加先前定义的 `PRIORITY_FEE_IX` 指令生成，调用 `.add()`。然后，它将使用 `getLatestBlockhash()` 方法从 Solana 节点获取最近的区块哈希和最后有效区块高度。然后，我们在基础和优先交易中设置区块哈希和最后有效区块高度。最近的区块哈希和最后有效区块高度的目的是要在发送的交易中包含节点最新的状态信息；它确保发送的交易具有节点的最新状态。\r\n2. 为每个交易生成 promises。由 `@solana/web3.js` 库提供的 `sendAndConfirmTransaction()` 函数为基础和优先交易生成 promises。该函数将交易发送到 Solana 集群并等待确认。我们使用 JavaScript 解构来返回每个交易的一个 promise。\r\n3. 向 Solana 集群发送交易。`Promise.all()` 函数用于同时发送基础和优先交易到 Solana 集群。该函数返回每个交易的交易 ID，这些 ID 存储在 `txBaseId` 和 `txPriorityId` 变量中。\r\n4. 获取交易结果并记录费用。使用 `getTransaction()` 函数来获取基础交易和优先交易的结果。然后，我们在 Solana Explorer 上记录每个交易的 URL 以及与每个交易相关的费用。我们预期优先交易的费用会高于基础交易的费用。\r\n\r\n最后，你只需调用你的函数。在 `app.ts` 的底部调用你的函数：\r\n\r\n```\r\ncreateAndSendTransactions();\r\n\r\n```\r\n\r\n然后运行你的代码。在终端中运行以下命令：\r\n\r\n```\r\nts-node app\r\n\r\n```\r\n\r\n你应该会在终端中看到与两个交易相关的日志，以及与每个交易相关的总费用链接到 Solana Explorer：\r\n\r\n![Priority Transaction Results](https://img.learnblockchain.cn/2025/02/25/1-850f3aa287ad67335646e8bb6a07825d.png)\r\n\r\n干得好！\r\n\r\n### 总结 \r\n\r\n你现在已经了解了优先费用以及如何将其添加到你的交易中。优先费用仍然是新兴的，因此请随时关注随着生态系统的发展而发生的变化。我们想知道你如何使用优先费用 - 请在 [Discord](https://discord.gg/quicknode) 或 [Twitter](https://twitter.com/QuickNode) 上告诉我们，跟我们分享你正在做的事情！\r\n\r\n \r\n### 其他资源 \r\n\r\n- [Solana 优先费用附加功能](https://marketplace.quicknode.com/add-on/solana-priority-fee)\r\n- [优先费用附加功能文档](https://www.quicknode.com/docs/solana/qn_estimatePriorityFees)\r\n\r\n>- 原文链接： [quicknode.com/guides/sol...](https://www.quicknode.com/guides/solana-development/transactions/how-to-use-priority-fees)\r\n>- 登链社区 AI 助手，为大家转译优秀英文文章，如有翻译不通的地方，还请包涵～"},"author":{"user":"https://learnblockchain.cn/people/25306","address":null},"history":null,"timestamp":1740466610,"version":1}