跳转至主要内容

How to Use Versioned Transactions on Solana

更新于
2025年11月26日

阅读时间 7 分钟

概述

On October 10, 2022 (Epoch 358), Solana added support for new transaction version types through a concept known as "Versioned Transactions". After this change, the Solana runtime now supports two types of transactions: "legacy" (older transactions) and "0" (transactions that include Address Lookup Tables). Versioned Transactions will allow you to utilize Address Lookup Tables today and could have additional functionality in the future.

In this guide, you will create and execute a Version 0 (V0) Transaction.

If you need help with ensuring your existing client-side apps can support Versioned Transactions, check out our Guide: How to Update Your Solana Client to Handle Versioned Transactions.

您需要准备的物品

设置您的项目

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

mkdir solana-versioned-tx
cd solana-versioned-tx

为您的应用程序创建一个文件,命名为app.ts

echo > app.ts

使用“yes”标志初始化项目,以便为新包采用默认值:

yarn init --yes
#or
npm init --yes

创建一个启用了 .json 导入功能的tsconfig.json文件:

tsc -init --resolveJsonModule true

安装 Solana Web3 依赖项

We will need to add the Solana Web3 library for this exercise. In your terminal, type:

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

让我们开始吧。

设置您的应用

导入必要的依赖项

Open app.ts, and paste the following imports on line 1 to get a few essential methods and classes from the Solana Web3 library:

import { Connection, Keypair, LAMPORTS_PER_SOL, SystemProgram, TransactionInstruction, TransactionMessage, VersionedTransaction } from '@solana/web3.js';

创建钱包并领取SOL空投

我们需要完成的第一项任务是创建一个钱包账户并为其充值。我们将使用下方的便捷工具自动生成一个新钱包,并向其中空投 1 SOL。(您也可以通过 Keypair.generate() 以及 requestAirdrop() (如果您更喜欢手动操作,也可以使用这些函数)。

🔑使用 Devnet SOL生成一个新钱包

注意:过频地发送空投请求可能会触发 429(请求过多)错误。

成功生成密钥对后,你会发现有两个新的常量: 秘密 以及 SIGNER_WALLET,一个密钥对。该 秘密 是一个 32 字节的数组,用于生成公钥和私钥。该 SIGNER_WALLET 这是一个用于签署交易的 Keypair 实例(我们已空投了一些开发网 SOL 用于支付 gas 费用)。如果您尚未添加,请务必将其添加到代码中,放在其他常量之后。

在导入语句下方,粘贴您的新密钥,并添加:

const secret = [0,...,0]; // 👈 Replace with your secret
const SIGNER_WALLET = Keypair.fromSecretKey(new Uint8Array(secret));
const DESTINATION_WALLET = Keypair.generate();

We have defined two wallets: SIGNER_WALLET will send SOL to our DESTINATION_WALLET. We have also added a constant, LOOKUP_TABLE_ADDRESS, which we will update later to reference our Lookup Table's on-chain account ID.

设置您的 Quicknode 端点

To build on Solana, you'll need an API endpoint to connect with the network. You're welcome to use public nodes or deploy and manage your own infrastructure; however, if you'd like 8x faster response times, you can leave the heavy lifting to us.


See why over 50% of projects on Solana choose Quicknode and sign up for an account here. We're going to use a Solana Devnet node.

复制 HTTP 提供程序的链接:

app.ts文件中,在 import 语句下方声明您的 RPC 并建立与 Solana的连接

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

Your environment should look like this:

Alright, let's BUILD!

Create a Version 0 Transaction

Version 0 Transactions require us to use a new class, VersionedTransaction, which requires us to pass a VersionedMessage as a parameter. A VersionedMessage accepts either a Message or MessageV0. Though very similar, MessageV0 allows the use of Address Lookup Tables!

Let's start by creating a new transfer TransactionInstruction that sends 0.1 SOL from our SIGNER_WALLET to our DESTINATION_WALLET. Since our transaction message is going to need an array of Transaction Instructions, go ahead and wrap the instruction in an array:

const instructions: TransactionInstruction[] = [
SystemProgram.transfer({
fromPubkey: SIGNER_WALLET.publicKey,
toPubkey: DESTINATION_WALLET.publicKey,
lamports: 0.01 * LAMPORTS_PER_SOL,
}),
];

Now let's build a new function, createAndSendV0Tx, that will accept our TransactionInstruction array:

async function createAndSendV0Tx(txInstructions: TransactionInstruction[]) {

}

Let's define a confirmTransaction function we will call in our createAndSendV0Tx function. Add the following code to your app.ts file:

async function confirmTransaction(
connection: Connection,
signature: TransactionSignature,
desiredConfirmationStatus: TransactionConfirmationStatus = 'confirmed',
timeout: number = 30000,
pollInterval: number = 1000,
searchTransactionHistory: boolean = false
): Promise<SignatureStatus> {
const start = Date.now();

while (Date.now() - start < timeout) {
const { value: statuses } = await connection.getSignatureStatuses([signature], { searchTransactionHistory });

if (!statuses || statuses.length === 0) {
throw new Error('Failed to get signature status');
}

const status = statuses[0];

if (status === null) {
// If status is null, the transaction is not yet known
await new Promise(resolve => setTimeout(resolve, pollInterval));
continue;
}

if (status.err) {
throw new Error(`Transaction failed: ${JSON.stringify(status.err)}`);
}

if (status.confirmationStatus && status.confirmationStatus === desiredConfirmationStatus) {
return status;
}

if (status.confirmationStatus === 'finalized') {
return status;
}

await new Promise(resolve => setTimeout(resolve, pollInterval));
}

throw new Error(`Transaction confirmation timeout after ${timeout}ms`);
}

This will simply poll the Solana network for the transaction status until it is either confirmed or the timeout is reached. We have included some default values for the timeout and poll interval, but you can adjust them as needed.

Let's assemble our function. Add these 5 steps to the body of your createAndSendV0Tx function.

Step 1: Fetch the latest blockhash from the network using getLatestBlockhash:

    // Step 1 - Fetch Latest Blockhash
let latestBlockhash = await SOLANA_CONNECTION.getLatestBlockhash('confirmed');
console.log(" ✅ - Fetched latest blockhash. Last Valid Height:", latestBlockhash.lastValidBlockHeight);

Note: We pass the parameter, 'confirmed,' to make it unlikely that the hash belongs to a dropped fork.

Step 2: Using our txInstructions parameter and the latestBlockhash, we can create a new MessageV0 by constructing a new Message and executing the .compileToV0Message() method:

    // Step 2 - Generate Transaction Message
const messageV0 = new TransactionMessage({
payerKey: SIGNER_WALLET.publicKey,
recentBlockhash: latestBlockhash.blockhash,
instructions: txInstructions
}).compileToV0Message();
console.log(" ✅ - Compiled Transaction Message");
const transaction = new VersionedTransaction(messageV0);

We then pass our message into a new instance of VersionedTransaction. Congrats! You have created a versioned transaction!

Step 3: Sign the transaction with an array of signers. In this case, it is just our SIGNER_WALLET.

    // Step 3 - Sign your transaction with the required `Signers`
transaction.sign([SIGNER_WALLET]);
console.log(" ✅ - Transaction Signed");

NOTE: When sending a VersionedTransaction to the cluster, it must be signed BEFORE calling the sendAndConfirmTransaction method. Source: edge.docs.solana.com.

Step 4: Send the transaction to the cluster using sendTransaction, which will return a transaction signature/id:

    // Step 4 - Send our v0 transaction to the cluster
const txid = await SOLANA_CONNECTION.sendTransaction(transaction, { maxRetries: 5 });
console.log(" ✅ - Transaction sent to network");

Note: We pass the parameter, 'maxRetries,' to allow the RPC to retry sending the transaction to the leader if necessary.

Step 5: Finally, wait for the cluster to confirm the transaction has succeeded:

    // Step 5 - Confirm Transaction 
const confirmation = await confirmTransaction(SOLANA_CONNECTION, txid);
if (confirmation.err) { throw new Error(" ❌ - Transaction not confirmed.") }
console.log('🎉 Transaction Succesfully Confirmed!', '\n', `https://explorer.solana.com/tx/${txid}?cluster=devnet`);

If it succeeds, we log the successful transaction's explorer URL.

Alright! We're ready to try it out!

Run Your Code

To execute our function, call createAndSendV0Tx at the bottom of the file, passing in instructions as the argument:

createAndSendV0Tx(instructions);

Our final code is available on GitHub, here.

And then, in your terminal, call:

ts-node app.ts

Do you see something like this?

Nice job! If you'd like to check your code against ours, we've provided it on GitHub, here.

下一步

Now that you can build and execute versioned transactions, it's time to see what V0 Transactions can do. Check out our Guide: How to Use Lookup Tables on Solana (coming soon) to learn more about Solana's new lookup table feature and how to use them.

If you're stuck, have questions, or just want to talk shop, drop us a line on Discord or Twitter!

我们 ❤️ 您的反馈!

If you have any feedback or questions on this guide, let us know. We’d love to hear from you.

分享本指南