什么是 Jito Bundles 以及如何使用它们?

  • QuickNode
  • 发布于 2024-06-16 21:18
  • 阅读 23

本文详细介绍了如何在 Solana 区块链上使用 Jito Bundles 功能,通过捆绑多个交易确保它们在同一区块中顺序执行。文章还提供了具体的代码示例,展示了如何使用 TypeScript 和 Solana Web3.js 2.0 创建和发送交易捆绑包。

概述

JM!随着对 Solana 区块空间需求的增加,也出现了确保你的交易包含在区块中的需求。此外,许多应用程序需要以原子且顺序的方式执行多个交易。Jito Labs 是一个为 Solana 构建高性能 MEV 基础设施的团队,运营着一个 Solana 验证器客户端,该客户端启用了一个名为 Bundles 的独特功能,使得这一切成为可能。在本指南中,我们将讨论 Jito Bundles 的定义及如何使用 Lil' JIT 市场附加组件将交易打包并发送到 Jito 验证器客户端。

让我们开始吧!

喜欢视频讲解吗?跟随 Sahil 学习关于 Jito Bundles 以及如何发送一个的内容。 什么是 Jito Bundles 及如何使用?

你将要做的事情

  • 安装 Lil' JIT 市场附加组件
  • 使用 TypeScript 和 Solana Web3.js 2.0 编写脚本
  • 创建一个包含 5 个交易的 Bundle
  • 将 Bundle 发送到 Jito 验证器客户端
  • 验证交易是否包含在区块中并按照正确的顺序处理

你将需要的东西

什么是 Jito Bundles?

Jito Bundles 是 Jito Labs 提供的一个功能,允许在 Solana 区块链上顺序且原子地执行多个交易。这个功能对于复杂的操作、高效的 MEV(Miner Extractable Value)捕获和某些 DeFi 应用程序尤其有用。为了理解它们的重要性,我们首先回顾一些关键概念:

  • 单个 Solana 交易是原子的:一个交易内的所有 指令 要么成功执行,要么一起失败。
  • 然而,单独发送的多个交易不是原子的:某些交易可能成功,而其他交易失败。这对许多应用程序来说是有问题的;例如,你可能只希望一个交易在另一个影响用户状态的交易成功后执行。
  • 一些复杂的交易在 Solana 上不可执行,因为它们包含超过运行时计算预算的多个计算密集型指令(当前每个交易 1.4M 计算单位
  • 偶尔,网络拥堵可能导致交易失败,而未能落入指定区块中(参考:指南:如何优化 Solana 交易)。

Jito Bundles 解决了所有这些问题,允许将多个交易打包在一起,并确保 Bundle 中的所有交易作为一个单元成功或失败。Jito Bundle 是最多包含五个 Solana 交易的组合,这些交易由 Jito 验证者在同一块内顺序和原子地执行,确保 Bundle 中的所有交易要么成功,要么都未被处理。Bundles 根据用户定义的小费金额进行优先处理,激励验证者优先处理 Bundles 而非其他交易。

Jito Bundles 的主要特征

特征 描述
顺序执行 Bundle 中的交易保证按列出的顺序执行
原子执行 所有交易在相同的槽内执行
所有或无结果 如果 Bundle 中的任何交易失败,则所有交易均未提交到链上
Bundle 大小 每个 Bundle 最大 5 个交易(允许复杂操作超出每个交易 1.4M 计算单位限制)

Jito Bundles 是如何工作的

  1. 用户创建并签署交易
  2. 用户将交易打包,并在最后一个交易中包含小费指令
  3. 用户将 Bundles 发送到 Jito 的区块引擎
  4. 区块引擎将 Bundles 转发给运行 Jito 的验证者
  5. Jito-Solana 特殊的 BundleStage 用于执行 Bundles
  6. 仅当 Jito-Solana 领导者生成区块时,Bundles 才会被处理

Jito Bundles 的应用场景

  • MEV 套利:通过将用户交易与套利交易打包,执行原子套利
  • 清算:将预言机更新交易与清算交易打包
  • 批量复杂操作:通过跨多个交易批量操作,克服交易大小限制或计算预算限制

关于小费的重要说明

Bundles 根据用户定义的小费金额进行优先处理,这激励验证者优先处理 Bundles。使用小费时的一些关键考虑:

  • 小费激励验证者优先处理 Bundles
  • 小费仅仅是在链上小费地址之一的 SOL 转账指令
  • 小费指令必须在你的 Bundle 的最后一个交易中
  • 最小小费要求:1,000 lamports
  • 小费金额会根据需求和竞争账户变化
  • 小费账户不应包含在地址查找表中
  • 小费支付程序:T1pyyaTNZsKv2WcRAB8oVnk93mLJw2XzjtVYqCsaHqt
  • 可以通过 getTipAccounts RPC 方法访问小费账户(稍后我们会讨论)或者通过 Jito 文档

区块引擎 Bundle 选择过程

  1. 基本完整性检查:验证交易并确保 Bundle 包含五个或更少的交易
  2. 模拟检查:验证所有交易将成功并与其他 Bundle 提交进行比较
  3. 拍卖检查:根据状态锁分组 Bundles,进行模拟并选择前 N 个小费最高的 Bundles

限制

  • Jito Bundles 仅在 Jito-Solana 领导者生成区块时进行处理(Anza 验证器客户端不处理它们)。在撰写本文时(2024 年 10 月),Jito 验证器客户端占据了 Solana 区块链大约 85% 的质押率( 来源:Jito Labs)。
  • 每个 Bundle 最大 5 个交易

通过利用 Jito Bundles,开发者可以确保复杂的多交易操作以原子方式并顺序执行,为 DeFi 应用程序、交易策略和 Solana 上的其他高级用例开启新的可能性。

欲获取更详细的信息,请参考 Jito 官方文档

让我们测试一下!

创建一个新项目

首先,打开你选择的代码编辑器并创建一个新项目文件夹:

mkdir lil-jit-demo && cd lil-jit-demo

然后,使用以下命令初始化一个新项目:

npm init -y

接下来,安装以下依赖:

npm install --save @solana/web3.js@2 @solana-program/memo @solana-program/system

注意:你可能需要使用 --legacy-peer-deps 标记安装 @solana-program/system@solana-program/memo 包。

确保你安装了 Node 类型:

npm i --save-dev @types/node

并初始化一个支持 JSON 模块的新 TypeScript 配置文件:

tsc --init --resolveJsonModule

并在项目根目录创建一个名为 index.ts 的新文件:

echo > index.ts

你将需要一个包含 ~0.01 SOL 的纸钱包来测试该演示(并覆盖 Bundle 小费的费用)。如果你没有,可以使用以下命令创建一个:

solana-keygen new -o secret.json -s --no-bip39-passphrase

你可以通过运行以下命令获取新钱包的地址:

solana address -k secret.json

确保在继续之前将 ~0.01 SOL 发送到该钱包。在终端运行以下命令可以验证你的主网余额:

solana balance -um -k secret.json

很好。让我们编写我们的脚本!

编写脚本

在我们开始编码之前,让我们概述一下我们希望脚本执行的步骤:

  1. 通过从 secret.json 文件中导入 Solana 密钥对并建立与 Lil' Jit 启用的 Solana 端点的连接来设置脚本
  2. 获取一个 Jito Tip 账户,以便用来发送我们的提示
  3. 获取最近的区块哈希
  4. 创建要打包的一组交易。对于这个示例,我们将创建 5 个 Memo 交易,每个交易包含一个唯一的顺序消息(例如,“lil jit demo transaction # ${index}”)
  5. 模拟我们的 Bundle 以确保它能成功
  6. 发送我们的 Bundle
  7. 验证它是否包含在一个区块中

让我们开始构建!

导入依赖

首先,打开你的 index.ts 文件并添加以下导入:

import {
    Rpc,
    createDefaultRpcTransport,
    createRpc,
    createJsonRpcApi,
    Address,
    mainnet,
    Base58EncodedBytes,
    createSolanaRpc,
    createKeyPairSignerFromBytes,
    createTransactionMessage,
    setTransactionMessageFeePayerSigner,
    pipe,
    setTransactionMessageLifetimeUsingBlockhash,
    appendTransactionMessageInstruction,
    TransactionPartialSigner,
    signTransactionMessageWithSigners,
    getBase64EncodedWireTransaction,
    Base64EncodedWireTransaction,
    getTransactionEncoder,
    getBase58Decoder,
} from "@solana/web3.js";
import { getAddMemoInstruction } from "@solana-program/memo";
import { getTransferSolInstruction } from "@solana-program/system";
import secret from "./secret.json";

我们将使用 @solana/web3.js 库中的多个接口和功能。我们还将使用 @solana-program/memo@solana-program/system 库来创建我们的交易。

定义常量

让我们定义一些将在脚本中使用的常量。将以下常量添加到导入下面:

const MINIMUM_JITO_TIP = 1_000; // lamports
const NUMBER_TRANSACTIONS = 5;
const SIMULATE_ONLY = true;
const ENDPOINT = 'https://example.solana-mainnet.quiknode.pro/123456/'; // 👈 替换为你的端点
const POLL_INTERVAL_MS = 3000;
const POLL_TIMEOUT_MS = 30000;
const DEFAULT_WAIT_BEFORE_POLL_MS = 5000;

确保将 ENDPOINT 常量替换为你自己的 Lil' JIT 启用的端点。如果你尚未拥有端点,可以在 QuickNode.com 创建一个。如果你已经有端点并需要添加 Lil' JIT Marketplace Add-on,你可以通过访问你的端点页面并点击Add-on来按照步骤添加该附加组件。

定义 Lil JIT 类型

为了最佳使用最新的 Solana Web3.js 库,我们将为我们的 Lil' JIT 端点定义一个自定义类型。在你的常量下方添加以下类型定义:

type JitoBundleSimulationResponse = {
    context: {
        apiVersion: string;
        slot: number;
    };
    value: {
        summary: 'succeeded' | {
            failed: {
                error: {
                    TransactionFailure: [number[], string];
                };
                tx_signature: string;
            };
        };
        transactionResults: Array<{
            err: null | unknown;
            logs: string[];
            postExecutionAccounts: null | unknown;
            preExecutionAccounts: null | unknown;
            returnData: null | unknown;
            unitsConsumed: number;
        }>;
    };
};

type LilJitAddon = {
    getRegions(): string[];
    getTipAccounts(): Address[];
    getBundleStatuses(bundleIds: string[]): {
        context: { slot: number };
        value: {
            bundleId: string;
            transactions: Base58EncodedBytes[];
            slot: number;
            confirmationStatus: string;
            err: any;
        }[]
    };
    getInflightBundleStatuses(bundleIds: string[]): {
        context: { slot: number };
        value: {
            bundle_id: string;
            status: "Invalid" | "Pending" | "Landed" | "Failed";
            landed_slot: number | null;
        }[];
    };
    sendTransaction(transactions: Base64EncodedWireTransaction[]): string;
    simulateBundle(transactions: [Base64EncodedWireTransaction[]]): JitoBundleSimulationResponse;
    sendBundle(transactions: Base58EncodedBytes[]): string;
}

这里我们定义了 LilJitAddon 类型,该类型指定了与 Lil' JIT Marketplace 附加组件交互的方法、参数和返回类型。我们还将 JitoBundleSimulationResponse 类型单独定义。

创建助手函数

让我们创建一些助手函数来让脚本更易读。

创建 Jito Bundles RPC 客户端

首先,让我们创建一个 createJitoBundlesRpc 函数,创建一个与我们的 Lil' JIT 端点交互的新 RPC 客户端。在导入下面添加以下函数:

function createJitoBundlesRpc({ endpoint }: { endpoint: string }): Rpc<LilJitAddon> {
    const api = createJsonRpcApi<LilJitAddon>({
        responseTransformer: (response: any) => response.result,
    });
    const transport = createDefaultRpcTransport({
        url: mainnet(endpoint),
    });
    return createRpc({ api, transport });
}

我们简单地使用 @solana/web3.js 库中的 createRpc 函数为我们的端点创建一个新的 RPC 客户端。我们还使用 createJsonRpcApicreateDefaultRpcTransport 函数来为我们的 RPC 客户端创建必要的 API 和传输对象。有几点注意:

  • 确保将 LilJitAddon 指定为你的 api 对象的类型
  • 注意,我们使用 responseTransformer 仅返回响应的 result 属性

创建模拟检查器

接下来,创建一个 validateSimulation 函数,检查模拟结果以确保 Bundle 成功。将以下函数添加到导入下面:

function isFailedSummary(summary: JitoBundleSimulationResponse['value']['summary']): summary is { failed: any } {
    return typeof summary === 'object' && summary !== null && 'failed' in summary;
}

function validateSimulation(simulation: JitoBundleSimulationResponse) {
    if (simulation.value.summary !== 'succeeded' && isFailedSummary(simulation.value.summary)) {
        throw new Error(`模拟失败:${simulation.value.summary.failed.error.TransactionFailure[1]}`);
    }
}

在这里,我们添加两个函数来帮助我们检查接收到的模拟的响应。isFailedSummary 函数检查模拟摘要是否为带有 failed 属性的对象。validateSimulation 函数检查模拟摘要是否具有 succeeded,如果没有则抛出错误。

创建交易生成器

我们将需要为演示目的创建五个不同的交易。让我们创建一个 createTransaction 函数,为每个五个交易生成一个新交易。我们希望能够指定一个可以传入备忘录消息的 index,以确保每个交易是唯一的,并希望在我们的交易中包含小费指令的选项(这将是 Bundle 中的最后一个交易)。将以下函数添加到导入下面:

async function createTransaction(
    index: number,
    latestBlockhash: Parameters<
        typeof setTransactionMessageLifetimeUsingBlockhash
    >[0],
    payerSigner: TransactionPartialSigner,
    includeTip?: Address
) {
    const transactionMessage = pipe(
        createTransactionMessage({ version: 0 }),
        (tx) => setTransactionMessageFeePayerSigner(payerSigner, tx),
        (tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
        (tx) =>
            appendTransactionMessageInstruction(
                getAddMemoInstruction({
                    memo: `lil jit demo transaction # ${index}`,
                }),
                tx
            ),
        (tx) =>
            includeTip
                ? appendTransactionMessageInstruction(
                    getTransferSolInstruction({
                        source: payerSigner,
                        destination: includeTip,
                        amount: MINIMUM_JITO_TIP,
                    }),
                    tx
                )
                : tx
    );
    return await signTransactionMessageWithSigners(transactionMessage);
}

在这里,我们使用 @solana/web3.jspipe 函数创建一个新的交易消息:

  • 我们使用 setTransactionMessageFeePayerSigner 设置费用付款人
  • 我们使用 setTransactionMessageLifetimeUsingBlockhash 函数设置交易的生命周期
  • 我们还使用 appendTransactionMessageInstruction 函数为交易添加备忘录指令(每个备忘录将根据 index 参数分配一个唯一消息——我们将用来验证交易序列是否正确执行)
  • 如果includeTip 参数被传入,我们还使用 appendTransactionMessageInstruction 为交易添加小费指令

获取小费账户

Lil' JIT 附加组件包括获取小费账户列表的方法。我们将使用此方法获取所有小费账户,然后随机选择一个从列表中包含在我们的交易中。将以下函数添加到导入下面:

async function getTipAccount(rpc: Rpc<LilJitAddon>): Promise<Address> {
    try {
        const tipAccounts = await rpc.getTipAccounts().send();
        const jitoTipAddress = tipAccounts[Math.floor(Math.random() * tipAccounts.length)];
        if (!jitoTipAddress) {
            throw new Error("未找到 JITO 小费账户");
        }
        return jitoTipAddress;
    } catch {
        throw new Error("获取小费账户失败");
    }
}

在这里,我们简单地使用 getTipAccounts 方法来检索小费账户列表。然后从列表中随机选择一个小费账户并返回。

轮询 Bundle 状态

我们将使用 getInflightBundleStatuses 方法轮询我们的 Bundle 状态,直到它落地、失败或超时。添加以下函数到你的导入下面:

async function pollBundleStatus(
    rpc: Rpc<LilJitAddon>,
    bundleId: string,
    timeoutMs = 30000,
    pollIntervalMs = 3000,
    waitBeforePollMs = DEFAULT_WAIT_BEFORE_POLL_MS
) {
    await new Promise(resolve => setTimeout(resolve, waitBeforePollMs));

    const startTime = Date.now();
    let lastStatus = '';
    while (Date.now() - startTime < timeoutMs) {
        try {
            const bundleStatus = await rpc.getInflightBundleStatuses([bundleId]).send();
            const status = bundleStatus.value[0]?.status ?? '未知';

            if (status !== lastStatus) {
                lastStatus = status;
            }

            if (status === 'Landed') {
                return true;
            }

            if (status === 'Failed') {
                console.log(`Bundle ${status.toLowerCase()}. 退出...`);
                throw new Error(`Bundle 失败,状态: ${status}`);
            }

            await new Promise(resolve => setTimeout(resolve, pollIntervalMs));
        } catch {
            console.error('❌ - 轮询 Bundle 状态时出错。');
        }
    }
    throw new Error("轮询超时,无确认");
}

这里没有很多内容;我们只是定义了一个轮询频率和超时,并调用 getInflightBundleStatuses 来检查我们 Bundle 的状态。如果 Bundle 已经落地,我们返回 true,中断循环。如果 Bundle 失败或轮询超时,我们记录错误并抛出错误。

考虑事项 getInflightBundleStatuses

请注意,我们在轮询前添加了一个简短的延迟,以确保 Bundle 有时间被处理——否则可能会出现轮询错误。此外,getInflightBundleStatuses 方法仅会查找过去五分钟内处理的 Bundles。如果你在处理超过五分钟之前的 Bundle 时使用此方法,将会出现 500 错误。

创建主函数

现在,基于上述步骤,让我们开始构建 main 函数。将以下函数添加到代码的其余部分下面:

async function main() {
    // 第 1 步 - 设置

    // 第 2 步 - 获取一个 Jitotip 账户

    // 第 3 步 - 获取最近的区块哈希

    // 第 4 步 - 创建交易

    // 第 5 步 - 模拟 Bundle

    // 第 6 步 - 发送 Bundle

    // 第 7 步 - 验证 Bundle 是否落地

}

main().catch((error) => {
    console.error(`❌ - 错误: ${error}`);
    process.exit(1);
});

太好了。现在让我们填充这些步骤。

第 1 步 - 设置

首先,让我们导入我们的密钥对,并定义我们的 Solana RPC 和 Lil' JIT RPC。将以下内容添加到你的 main 函数:

    // 第 1 步 - 设置
    const signer = await createKeyPairSignerFromBytes(new Uint8Array(secret));
    console.log(`初始化 Jito Bundles 演示。发送 ${NUMBER_TRANSACTIONS} 个交易来自 ${signer.address}。`);

    const solanaRpc = createSolanaRpc(ENDPOINT);
    const lilJitRpc = createJitoBundlesRpc({ endpoint: ENDPOINT });
    console.log(`✅ - 已与 QuickNode 建立连接。`);

现在我们可以使用本地 Solana RPC 方法(使用 solanaRpc)和我们的 Jito Bundles RPC 方法(使用 lilJitRpc)与 Jito 验证器客户端进行交互。

第 2 步 - 获取一个 Jitotip 账户

由于我们已经定义了 getTipAccount 函数,我们所需要做的就是调用它并将其响应存储在一个变量 jitoTipAddress 中。将以下内容添加到你的 main 函数:

    // 第 2 步 - 获取一个 Jitotip 账户
    const jitoTipAddress = await getTipAccount(lilJitRpc);
    console.log(`✅ - 使用以下 Jito Tip 账户:${jitoTipAddress}`);

第 3 步 - 获取最近的区块哈希

就像 Solana 上的任何交易一样,我们必须传递一个最近的区块哈希以确保交易能够及时处理。如果你发送一个带有过时区块哈希的 Bundle,交易/Bundle 将会失败。

将以下内容添加到你的 main 函数:

    // 第 3 步 - 获取最近的区块哈希
    const { value: latestBlockhash } = await solanaRpc
        .getLatestBlockhash({ commitment: "confirmed" })
        .send();
    console.log(`✅ - 最新的区块哈希:${latestBlockhash.blockhash}`);

第 4 步 - 创建交易

现在,我们将创建五个备忘录交易,每个交易都有一个独特的顺序消息。将以下内容添加到你的 main 函数:

    // 第 4 步 - 创建交易
    const signedTransactions = await Promise.all(
        Array.from({ length: NUMBER_TRANSACTIONS }, (_, i) => {
            const isLastTransaction = i === NUMBER_TRANSACTIONS - 1;
            return createTransaction(
                i + 1,
                latestBlockhash,
                signer,
                isLastTransaction ? jitoTipAddress : undefined
            );
        })
    );

    const base64EncodedTransactions = signedTransactions.map((transaction) => {
        const base64EncodedTransaction = getBase64EncodedWireTransaction(transaction);
        return base64EncodedTransaction;
    }) as Base64EncodedWireTransaction[];

    const transactionEncoder = getTransactionEncoder();
    const base58Decoder = getBase58Decoder();

    const base58EncodedTransactions = signedTransactions.map((transaction) => {
        const transactionBytes = transactionEncoder.encode(transaction);
        return base58Decoder.decode(transactionBytes) as Base58EncodedBytes;
    });
    console.log(`✅ - 交易组装并编码完毕。`);

让我们走一遍我们所做的事情:

  • 我们使用 createTransaction 函数创建 5 个 Memo 交易。
  • 在数组中的最后一个交易中,我们包括 jitoTipAddress 作为小费账户,使得交易中包括小费指令。
  • 然后我们分别使用 Base64 和 Base58 编码交易(模拟和发送 Bundles 时所需)。

第 5 步 - 模拟 Bundle

接下来,我们将使用 Lil' JIT simulateBundle 方法测试我们的 Bundle。我们可以使用之前写的 validateSimulation 函数来确保模拟成功。最后,我们创建一个条件,如果我们的配置设置为 仅模拟 模式,则结束脚本。将以下内容添加到你的 main 函数:

    // 第 5 步 - 模拟 Bundle
    const simulation = await lilJitRpc
        .simulateBundle([base64EncodedTransactions])
        .send();

    validateSimulation(simulation);
    console.log(`✅ - 模拟成功。`);

    if (SIMULATE_ONLY) {
        console.log("🏁 - 仅模拟模式 - 退出脚本。");
        return;
    }

第 6 步 - 发送 Bundle

现在,我们将使用 sendBundle 方法将我们的 Bundle 发送到 Jito 验证器客户端。将以下内容添加到你的 main 函数:

    // 第 6 步 - 发送 Bundle
    let bundleId: string;
    try {
        bundleId = await lilJitRpc
            .sendBundle(base58EncodedTransactions)
            .send();
        console.log(`✅ - Bundle 已发送:${bundleId}`);
    } catch (error) {
        console.error("❌ - 发送 Bundle 时出错:", error);
        throw error;
    }

第 7 步 - 验证 Bundle 是否落地

最后,让我们调用我们的 pollBundleStatus 函数来验证 Bundle 是否落地。将以下内容添加到你的 main 函数:

    // 第 7 步 - 验证 Bundle 是否落地
    await pollBundleStatus(lilJitRpc, bundleId, POLL_TIMEOUT_MS, POLL_INTERVAL_MS);
    console.log(`✅ - Bundle 已落地:${bundleId}`);
    console.log(`     https://explorer.jito.wtf/bundle/${bundleId}`);
    console.log(`     (注意:该 URL 可能需要几分钟才能变得可用。)`);

干得很好。我们现在应该有一个完整的脚本,用于将 5 个 Memo 交易发送到 Jito 验证器客户端并验证它们是否成功。让我们运行它!

运行你的代码

在运行代码之前,请检查你的 SIMULATE_ONLYMINIMUM_JITO_TIP 变量。如果你将 SIMULATE_ONLY 设置为 true,脚本将仅模拟 Bundle 并退出。否则,它将把 Bundle 发送到验证者客户端——如果交易在主网上落地,你的交易将包含在一个区块中,意味着你的小费将被支付。这是不可逆的。

当你准备好后,请在终端运行以下命令:

ts-node index.ts

如果将 SIMULATE_ONLY 设置为 false,你应该会看到类似以下的输出:

初始化 Jito Bundles 演示。发送 5 个交易来自 FUA7zS5PXVtW2VCmFGtfv5q6AdusbpVGy8HTjVjBAAzR。
✅ - 使用以下 Jito Tip 账户:HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe
✅ - 最新的区块哈希:CghMwVqLLdKrdgdCKDbTtRgdRhj9BfCBZxL8n87QNB9C
✅ - 交易组装并编码完毕。
✅ - 模拟成功。
✅ - Bundle 已发送:c4fb0940406d3fead71e29b9f87d2273ab6a743f3da1bf4aeeb73db3521685b0
✅ - Bundle 已落地:c4fb0940406d3fead71e29b9f87d2273ab6a743f3da1bf4aeeb73db3521685b0
     https://explorer.jito.wtf/bundle/c4fb0940406d3fead71e29b9f87d2273ab6a743f3da1bf4aeeb73db3521685b0
     (注意:该 URL 可能需要几分钟才能变得可用。)

LFJitoooo!干得好!你的第一个 Bundle 已经落地在 Solana 上。正如你在终端输出中所注意到的,Jito bundle explorer 可能需要一分钟来更新你的 Bundle,请稍等一分钟,然后单击链接。你应该会看到如下内容:

已确认的 Jito Bundle - Jito Explorer

该 Bundle 应显示五个按顺序排列的交易。第五个交易应包含小费指令和 SOL 余额转移。你可以在上面的示例中看到这一点。你还可以通过点击交易右上角的 ⎘ 图标单独打开每个交易(或者通过在 Solana Explorer 中浏览你的钱包地址)。你应该会看到所有五个交易具有相同的时间戳和区块:

所有 Bundle 的交易 - Solana Explorer

你应该能够导航到五个交易中的第一个,并在交易详情中看到“lil jit demo transaction # 1”:

第一个交易 - Solana Explorer

你还应该能够导航到第五个交易,并在交易详情中看到“lil jit demo transaction # 5”及我们的转小费:

第五个交易 - Solana Explorer

这表明:

  • 所有交易都包含在同一个区块中
  • 所有交易都按照发送的顺序执行
  • 所有交易都是成功的
  • 最终交易包含转向小费账户的转账

非常酷,对吧?干得不错! 🎉

这就是 Bundle!

Jito Bundles 是提升你 Solana 开发体验的强大工具。通过利用 Lil' JIT 市场附加组件,你可以打包交易,并确保它们在同一块中并按指定顺序执行。这是优化交易并最大化你应用性能的好方法。

我们期待看到你与 Lil' JIT 附加组件的成果。如果你有任何问题或想告诉我们你的进展,请与我们联系!你可以在 DiscordTwitter 上与我们联系。

我们 ❤️ 反馈!

让我们知道如果你有任何反馈或新的主题请求。我们很乐意听取你的声音。

资源

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

0 条评论

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