如何在 Solana 上使用优先级费用

  • QuickNode
  • 发布于 2024-02-26 11:18
  • 阅读 19

本文介绍了如何在Solana网络中使用优先级费用来加速交易确认。通过Solana Web3.js库,用户可以设置额外的优先级费用以在领导者的队列中提高交易的优先级。

概述

你是否希望在 Solana 上尽快确认你的交易?本指南将向你展示如何使用优先费用,在领导者队列中出价以获得优先权,并更快确认你的交易。

Solana 的费用优先系统允许你在交易的基础费用上设置额外费用,这将使你的交易在领导者队列中拥有更高的优先级。通过为优先状态出价更多,你的交易更有可能被网络快速确认。

想观看视频教程吗?请跟随 Sahil 学习关于 Solana 上的优先费用

你将要做的事情

在本指南中,我们将引导你如何使用 Solana Web3.js 库在你的 Solana 交易中使用优先费用。我们将向你展示如何创建基础交易,创建具有更高费用的优先交易,并将它们发送到网络。

通过本指南结束时,你将很好地理解如何使用优先费用为你的 Solana 交易设置优先级,并在网络上更快确认它们。

你需要准备什么

要跟随本指南,你需要准备以下内容:

  • 有关 使用 solanaWeb3.js 进行 Solana 交易的基本经验
  • 对 JavaScript/TypeScript 编程语言的基本知识
  • 已安装 Nodejs(版本 16.15 或更高)
  • 已安装 npm 或 yarn(我们将使用 yarn 初始化项目并安装必要的包。如果你更喜欢使用 npm,也可以选择 npm)
  • TypeScript 经验和已安装 ts-node
  • 拥有一份带有 Devnet SOL 的 Solana Paper 钱包 (.json) ( 示例脚本)。

优先费用

在我们深入了解如何利用优先费用之前,让我们先了解一下 Solana 上的优先费用。 优先费用 最近由 Solana 引入,允许用户对其交易在队列中的顺序有更多控制。用户可以在其交易上设置额外费用,以在 Solana 的领导者队列中出价以获得更高的优先权。优先费用较高的交易更有可能被网络快速确认,因为它们在优先费用较低的交易之前被处理。这对于发送高价值或时间敏感交易的 dApp 特别有用。

优先费用在实际应用中还有哪些使用方法?想象一下一个极其热门的 NFT 铸造活动。愿意支付额外费用以确保其交易被处理的用户可能会自愿支付优先费用,以增加他们成功完成交易并获得 NFT 的机会。

设置你的项目

在终端中创建一个新的项目目录,使用以下命令:

mkdir solana-priority-fees
cd solana-priority-fees

为你的应用创建一个文件,app.ts

echo > app.ts

使用 "yes" 标志初始化你的项目,以使用新包的默认值:

yarn init --yes
# 或者
npm init --yes

创建一个启用 .json 导入的 tsconfig.json

tsc -init --resolveJsonModule true --target es2020

将你的纸钱包(包含 devnet SOL)保存为 guideSecret.json 到项目目录。如果你需要一些 devnet SOL,你可以在这里申请:

🪂申请 Devnet SOL

空投 1 SOL (Devnet)

安装 Solana Web3 依赖

我们将需要为本练习添加 Solana Web3 库。在终端中输入:

yarn add @solana/web3.js@1
# 或者
npm install @solana/web3.js@1

我们将需要从这些库和我们的私钥中导入几个组件。在 app.ts 第 1 行添加:

import { ComputeBudgetProgram, Connection, Keypair, LAMPORTS_PER_SOL, sendAndConfirmTransaction, SystemProgram, Transaction } from "@solana/web3.js";
import secret from './guideSecret.json';

使用你的 QuickNode 终端连接到 Solana 集群

要在 Solana 上构建,你需要一个 API 终端来连接网络。你可以使用公共节点,也可以部署和管理你自己的基础设施;不过,如果你希望享受 8 倍的更快响应时间,可以将繁重的工作交给我们来处理。

看看为什么超过 50% 的 Solana 项目选择 QuickNode 并在 这里 注册一个免费账户。 我们将使用一个 Solana Devnet 节点。

复制 HTTP Provider 链接:

New Node

app.ts 的导入语句下方,声明你的 RPC 并建立与 Solana 的 Connection 连接:

const QUICKNODE_RPC = 'https://example.solana-devnet.quiknode.pro/0123456/';
const SOLANA_CONNECTION = new Connection(QUICKNODE_RPC);

你的环境应如下所示。

Ready to Build

准备好了吗?让我们开始构建吧!

创建基础交易

设置 Keypairs

要创建一个基础交易,我们首先需要设置一个“发送方”和一个“接收方”密钥对。

将以下代码片段添加到 app.ts

const fromKeypair = Keypair.fromSecretKey(new Uint8Array(secret));
const toKeypair = Keypair.generate();

这段代码使用 guideSecret.json 文件中的私钥创建一个交易发送方的密钥对,并为交易的接收方生成一个新的随机密钥对。

添加常量

让我们定义一些将在代码中使用的重要常量。将以下代码片段添加到你的 app.ts 文件中:

const PRIORITY_RATE = 100; // 微兰波特
const SEND_AMT = 0.01 * LAMPORTS_PER_SOL;
const PRIORITY_FEE_IX = ComputeBudgetProgram.setComputeUnitPrice({microLamports: PRIORITY_RATE});
  • PRIORITY_RATE 常量用于以微兰波特的形式设置优先费用的费率;在这个例子中,它是 100 微兰波特(1 微兰波特 = 0.000001 兰波特)。
  • SEND_AMT 用于设置交易中发送的兰波特数量。在这个例子中,它是 0.01 SOL,相当于 1000 万兰波特(1 SOL = 1,000,000,000 兰波特)。
  • PRIORITY_FEE_IX 用于设置优先费用指令,该指令稍后将添加到交易中。ComputeBudgetProgram.setComputeUnitPrice@solana/web3.js 库提供的方法,允许你为交易设置计算单元价格。这意味着你可以设置每个计算单位愿意支付多少微兰波特。在这种情况下,我们使用 PRIORITY_RATE 常量将计算单元价格设置为 100 微兰波特。

计算优先费用率(针对生产应用)

对于生产应用,你可能希望根据当前费用市场动态计算优先费用率。跟踪本地费用市场以及了解在你的应用中使用的正确优先费用可能会很棘手。尽管 SolanaWeb3.js 提供了 getRecentPrioritizationFees() 方法来帮助你理解当前的费用市场,但它只返回整个网络的单一值。

费用是由程序本地化的,交易成功率可能会根据当前市场状况有很大波动。监控费用市场并调整你的优先费用对确保交易成功至关重要。QuickNode 通过我们的 Solana Priority Fees Add-on 使跟踪费用市场变得简单。该自定义方法接受程序账户 ID 和一系列最近的区块,并返回 5% 百分位的费用分布。

要使用 qn_estimatePriorityFees 方法,你需要通过 marketplace 页面 或在你的终端页面(例如,https://dashboard.quicknode.com/endpoints/219123/add-ons)将插件添加到你的 QuickNode 终端中。

以下是如何将 qn_estimatePriorityFees 方法添加到你的应用的示例。首先,定义请求和响应有效负载的关键接口:

interface RequestPayload {
    method: string;
    params: {
        last_n_blocks: number;
        account: string;
        api_version: number;
    };
    id: number;
    jsonrpc: string;
}

interface FeeEstimates {
    extreme: number;
    high: number;
    low: number;
    medium: number;
    percentiles: {
        [key: string]: number;
    };
}

interface ResponseData {
    jsonrpc: string;
    result: {
        context: {
            slot: number;
        };
        per_compute_unit: FeeEstimates;
        per_transaction: FeeEstimates;
    };
    id: number;
}

interface EstimatePriorityFeesParams {
    // 用于费用估算的区块数量
    last_n_blocks?: number;
    // 用于提取本地估算的程序账户(例如,Jupiter: JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4)
    account?: string;
    // 用于提取本地估算的 API 版本
    api_version?: number;
    // 你的附加端点(在你的 QuickNode 控制面板中找到 - https://dashboard.quicknode.com/endpoints)
    endpoint: string;
}

接下来,创建一个函数来提取优先费用:

async function fetchEstimatePriorityFees({
    last_n_blocks,
    account,
    api_version,
    endpoint
}: EstimatePriorityFeesParams): Promise<ResponseData> {
    // 仅包含已定义的参数
    const params: any = {};
    if (last_n_blocks !== undefined) {
        params.last_n_blocks = last_n_blocks;
    }
    if (account !== undefined) {
        params.account = account;
    }
    if (api_version !== undefined) {
        params.api_version = api_version;
    }

    const payload: RequestPayload = {
        method: 'qn_estimatePriorityFees',
        params,
        id: 1,
        jsonrpc: '2.0',
    };

    const response = await fetch(endpoint, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(payload),
    });

    if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data: ResponseData = await response.json();
    return data;
}

最后,你可以使用 fetchEstimatePriorityFees 函数获取特定程序的优先费用(用于你的优先费用指令中):


const params: EstimatePriorityFeesParams = {
    last_n_blocks: 100,
    account: 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',
    endpoint: 'https://你的优先费用端点/'
};

async function createDynamicPriorityFeeInstruction() {
    const { result } = await fetchEstimatePriorityFees(params);
    const priorityFee = result.per_compute_unit.high; // 👈 插入用于根据你的交易需求计算费用的业务逻辑(例如,低,中,高或特定百分位)
    const priorityFeeInstruction = ComputeBudgetProgram.setComputeUnitPrice( { microLamports: priorityFee } );
    return priorityFeeInstruction;
}

让我们回到我们的示例。

创建基础交易示例

现在我们已经有了密钥对,我们可以创建基础交易。

将以下代码片段添加到你的 app.ts 文件中:

function generateTxExample() {
    return new Transaction().add(SystemProgram.transfer({
        fromPubkey: fromKeypair.publicKey,
        toPubkey: toKeypair.publicKey,
        lamports: SEND_AMT
    }));
}

这个函数创建一个新交易并添加一个 SystemProgram.transfer 指令。该指令将 SEND_AMT 兰波特从 fromKeypair 转移到 toKeypair

完美。我们已经具备构建脚本所需的工具。

创建并发送交易

让我们创建一个函数 createAndSendTransactions(),演示如何在 Solana 网络上使用优先费用。在 app.ts 中添加:

async function createAndSendTransactions() {
    // 第一步 - 生成基础和优先交易
    const txBase = generateTxExample();
    const txPriority = generateTxExample().add(PRIORITY_FEE_IX);
    const { blockhash, lastValidBlockHeight } = await SOLANA_CONNECTION.getLatestBlockhash();
    txBase.recentBlockhash = blockhash;
    txPriority.recentBlockhash = blockhash;
    txBase.lastValidBlockHeight = lastValidBlockHeight;
    txPriority.lastValidBlockHeight = lastValidBlockHeight;

    // 第二步 - 为每个交易生成 promises
    const [txBaseRequest, txPriorityRequest] = [txBase, txPriority].map(tx => sendAndConfirmTransaction(SOLANA_CONNECTION, tx, [fromKeypair]));

    try {
        // 第三步 - 向集群发送交易
        const [txBaseId, txPriorityId] = await Promise.all([txBaseRequest, txPriorityRequest]);

        // 第四步 - 获取交易结果,并记录费用
        const [txBaseResult, txPriorityResult] = await Promise.all([SOLANA_CONNECTION.getTransaction(txBaseId), SOLANA_CONNECTION.getTransaction(txPriorityId)]);
        console.log(`txBase URL: https://explorer.solana.com/tx/${txBaseId}?cluster=devnet`);
        console.log(`txBase Fee: ${txBaseResult?.meta?.fee} 兰波特`);
        console.log(`txPriority URL: https://explorer.solana.com/tx/${txPriorityId}?cluster=devnet`);
        console.log(`txPriority Fee: ${txPriorityResult?.meta?.fee} 兰波特`);
    } catch (error) {
        console.log(error);
    }
}

让我们来看看这些步骤:

  1. 生成基础和优先交易。基础交易通过调用 generateTxExample() 函数生成,而优先交易则通过添加先前定义的 PRIORITY_FEE_IX 指令生成,调用 .add()。然后,它将使用 getLatestBlockhash() 方法从 Solana 节点获取最近的区块哈希和最后有效区块高度。然后,我们在基础和优先交易中设置区块哈希和最后有效区块高度。最近的区块哈希和最后有效区块高度的目的是要在发送的交易中包含节点最新的状态信息;它确保发送的交易具有节点的最新状态。
  2. 为每个交易生成 promises。由 @solana/web3.js 库提供的 sendAndConfirmTransaction() 函数为基础和优先交易生成 promises。该函数将交易发送到 Solana 集群并等待确认。我们使用 JavaScript 解构来返回每个交易的一个 promise。
  3. 向 Solana 集群发送交易。Promise.all() 函数用于同时发送基础和优先交易到 Solana 集群。该函数返回每个交易的交易 ID,这些 ID 存储在 txBaseIdtxPriorityId 变量中。
  4. 获取交易结果并记录费用。使用 getTransaction() 函数来获取基础交易和优先交易的结果。然后,我们在 Solana Explorer 上记录每个交易的 URL 以及与每个交易相关的费用。我们预期优先交易的费用会高于基础交易的费用。

最后,你只需调用你的函数。在 app.ts 的底部调用你的函数:

createAndSendTransactions();

然后运行你的代码。在终端中运行以下命令:

ts-node app

你应该会在终端中看到与两个交易相关的日志,以及与每个交易相关的总费用链接到 Solana Explorer:

Priority Transaction Results

干得好!

总结

你现在已经了解了优先费用以及如何将其添加到你的交易中。优先费用仍然是新兴的,因此请随时关注随着生态系统的发展而发生的变化。我们想知道你如何使用优先费用 - 请在 DiscordTwitter 上告诉我们,跟我们分享你正在做的事情!

其他资源

  • 原文链接: quicknode.com/guides/sol...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。