Phantom Developer Docs
HomeDeveloper Forums
  • 👻Introduction
    • Introduction
  • 🟩Solana
    • Getting Started With Solana
    • Detecting the Provider
    • Establishing a Connection
    • Sending a Legacy Transaction
    • Sending a Versioned Transaction
    • Signing a Message
    • Error Messages and Codes
  • 🔷Ethereum, Monad Testnet, Base, & Polygon
    • Getting Started with EVM networks
    • Detecting the Provider
    • Establishing a Connection
    • Sending a Transaction
    • Signing a Message
    • Provider API Reference
      • Properties
        • isPhantom
        • chainId
        • networkVersion
        • selectedAddress
        • _events
        • _eventsCount
      • Events
        • Connect
        • Accounts Changed
        • Disconnect
        • Chain Changed
      • Methods
        • isConnected
        • request
      • Error Messages & Codes
  • 🌊Sui
    • Getting Started with Sui
    • Detecting the Provider
    • Establishing a Connection
    • Sending a Transaction
    • Signing a Message
  • 🟠Bitcoin
    • Getting Started With Bitcoin
    • Detecting the Provider
    • Establishing a Connection
    • Sending a Transaction
    • Signing a Message
    • Provider API Reference
  • ⛓️Phantom Deeplinks
    • Phantom Deeplinks
    • Provider Methods
      • Connect
      • Disconnect
      • SignAndSendTransaction
      • SignAllTransactions
      • SignTransaction
      • SignMessage
    • Other Methods
      • Browse
      • Fungible
      • Swap
    • Handling Sessions
    • Specifying Redirects
    • Encryption
    • Limitations
  • 🛠️Developer Powertools
    • Auto-Confirm
    • Domain and Transaction Warnings
    • Mobile Web Debugging
    • Phantom Blocklist
    • Shortcuts
    • Sign-In-With (SIW) Standards
    • Solana Actions & Blinks
    • Solana Priority Fees
    • Solana Token Extensions (Token22)
    • Solana Versioned Transactions
    • Testnet Mode
    • Token Pages
    • Wallet Standard
  • ✅Best Practices
    • Launching a Dapp
    • Displaying Apps within the Activity Tab
    • Displaying Apps within Dialogs
    • Displaying Tokens on Solana
      • Fungibles
      • NFTs & Semi-Fungibles
      • Supported Media Types
  • 🙋Resources
    • FAQ
    • Demo Applications
    • Community Guides & SDKs
    • Logos & Assets
Powered by GitBook
On this page
  • Building a Versioned Transaction
  • Signing and Sending a Versioned Transaction
  • Building an Address Lookup Table (LUT)
  • Extending an Address Lookup Table (LUT)
  • Signing and Sending a Versioned Transaction utilizing a LUT

Was this helpful?

  1. Solana

Sending a Versioned Transaction

PreviousSending a Legacy TransactionNextSigning a Message

Last updated 1 year ago

Was this helpful?

On October 10, 2022, Solana introduced the concept of . Currently, the Solana runtime supports two types of transactions: legacy (see ) and v0 (transactions that can include ).

The goal of v0 is to increase the maximum size of a transaction, and hence the number of accounts that can fit in a single atomic transaction. With LUTs, developers can now build transactions with a maximum of 256 accounts, as compared to the limit of 35 accounts in legacy transactions that do not utilize LUTs.

For a dive deep on Versioned Transactions, LUTs, and how the above changes affect the anatomy of a transaction, you can read .

On this page, we'll go over the following:

  1. Building a Versioned Transaction

  2. Signing and Sending a Versioned Transaction

  3. Building an Address Lookup Table (LUT)

  4. Extending an Address Lookup Table (LUT)

  5. Signing and Sending a Versioned Transaction utilising a LUT

Building a Versioned Transaction

Versioned transactions are built in a very similar fashion to . The only difference is that developers should use the VersionedTransaction class rather than the Transaction class.

The following example show how to build a simple transfer instruction. Once the transfer instruction is made, a MessageV0 formatted transaction message is constructed with the transfer instruction. Finally, a new VersionedTransaction is created, parsing in the v0 compatible message.

// create array of instructions
const instructions = [
  SystemProgram.transfer({
    fromPubkey: publicKey,
    toPubkey: publicKey,
    lamports: 10,
  }),
];

// create v0 compatible message
const messageV0 = new TransactionMessage({
  payerKey: publicKey,
  recentBlockhash: blockhash,
  instructions,
}).compileToV0Message();

// make a versioned transaction
const transactionV0 = new VersionedTransaction(messageV0);

Signing and Sending a Versioned Transaction

const provider = getProvider(); // see "Detecting the Provider"
const network = "<NETWORK_URL>";
const connection = new Connection(network);
const versionedTransaction = new VersionedTransaction();
const { signature } = await provider.signAndSendTransaction(versionedTransaction);
await connection.getSignatureStatus(signature);

Building an Address Lookup Table (LUT)

Address Lookup Tables (LUTs) can be used to load accounts into table-like data structures. These structures can then be referenced to significantly increase the number of accounts that can be loaded in a single transaction.

This lookup method effectively "compresses" a 32-byte address into a 1-byte index value. This "compression" enables storing up to 256 address in a single lookup table for use inside any given transaction.

Here's a code snippet that creates a Lookup Table.

// create an Address Lookup Table
const [lookupTableInst, lookupTableAddress] = AddressLookupTableProgram.createLookupTable({
  authority: publicKey,
  payer: publicKey,
  recentSlot: slot,
});

// To create the Address Lookup Table on chain:
// send the `lookupTableInst` instruction in a transaction
const lookupMessage = new TransactionMessage({
  payerKey: publicKey,
  recentBlockhash: blockhash,
  instructions: [lookupTableInst],
}).compileToV0Message();

const lookupTransaction = new VersionedTransaction(lookupMessage);
const lookupSignature = await signAndSendTransaction(provider, lookupTransaction);

Extending an Address Lookup Table (LUT)

// add addresses to the `lookupTableAddress` table via an `extend` instruction
const extendInstruction = AddressLookupTableProgram.extendLookupTable({
  payer: publicKey,
  authority: publicKey,
  lookupTable: lookupTableAddress,
  addresses: [
    publicKey,
    SystemProgram.programId,
    // more `publicKey` addresses can be listed here
  ],
});

// Send this `extendInstruction` in a transaction to the cluster
// to insert the listing of `addresses` into your lookup table with address `lookupTableAddress`
const extensionMessageV0 = new TransactionMessage({
  payerKey: publicKey,
  recentBlockhash: blockhash,
  instructions: [extendInstruction],
}).compileToV0Message();

const extensionTransactionV0 = new VersionedTransaction(extensionMessageV0);
const extensionSignature = await signAndSendTransaction(provider, extensionTransactionV0);

Signing and Sending a Versioned Transaction utilizing a LUT

Up until now, we have:

  1. Learned how to create a VersionedTransaction

  2. Created an Address Lookup Table

  3. Extended the Address Lookup Table

At this point, we are now ready to sign and send a VersionedTransaction utilizing an Address Lookup Table.

First, we need to fetch the account of the created Address Lookup Table.

// get the table from the cluster
const lookupTableAccount = await connection.getAddressLookupTable(lookupTableAddress).then((res) => res.value);
// `lookupTableAccount` will now be a `AddressLookupTableAccount` object
console.log('Table address from cluster:', lookupTableAccount.key.toBase58());

We can also parse and read all the addresses currently stores in the fetched Address Lookup Table.

// Loop through and parse all the address stored in the table
for (let i = 0; i < lookupTableAccount.state.addresses.length; i++) {
  const address = lookupTableAccount.state.addresses[i];
  console.log(i, address.toBase58());
}

We can now create the instructions array with an arbitrary transfer instruction, just the way we did while creating the VersionedTransaction earlier. This VersionedTransaction can then be sent using the signAndSendTransaction() provider function.

// create an array with your desired `instructions`
// in this case, just a transfer instruction
const instructions = [
  SystemProgram.transfer({
    fromPubkey: publicKey,
    toPubkey: publicKey,
    lamports: minRent,
  }),
];

// create v0 compatible message
const messageV0 = new TransactionMessage({
  payerKey: publicKey,
  recentBlockhash: blockhash,
  instructions,
}).compileToV0Message([lookupTableAccount]);

// make a versioned transaction
const transactionV0 = new VersionedTransaction(messageV0);
const signature = await signAndSendTransaction(provider, transactionV0);

Check out the function in our code sandbox for a live example of creating a versioned transaction.

Once a Versioned transaction is created, it can be signed and sent via Phantom using the signAndSendTransaction method on the provider. The call will return a for an object containing the signature. This is the same way a legacy transaction is sent via the Phantom provider.

You can also specify a SendOptions as a second argument into signAndSendTransaction() or as an options parameter when using request.

For a live demo of signing and sending a Versioned transaction, please refer to the section of our developer sandbox.

With the @solana/web3.js function, developers can construct the instruction needed to create a new lookup table, as well as determine its address. Once we have the lookup table instruction, we can construct a transaction, sign it, and send it to create a lookup table on-chain. Address lookup tables can be created with either a v0 transaction or a legacy transaction. However, the Solana runtime can only retrieve and handle the additional addresses within a lookup table while using v0 transactions.

Please refer to the in our code sandbox for a live demo of creating a lookup table.

Once an Address Lookup Table is created, it can then be extended (i.e. accounts can be appended to the table). Using the @solana/web3.js library, you can create a new extend instruction using the method. Once the extend instruction is created, it can be sent in a transaction.

Please refer to the in our code sandbox for a live demo of extending a lookup table.

Please refer to the in our code sandbox for a live demo of signing and sending a versioned transaction utilizing an Address Lookup Table.

🟩
Versioned Transactions
Sending a Legacy Transaction
Address Lookup Tables (LUTS)
this detailed guide
legacy transactions
createTransferTransactionV0()
Promise
object
handleSignAndSendTransactionV0()
createLookupTable
handleSignAndSendTransactionV0WithLookupTable()
extendLookupTable
handleSignAndSendTransactionV0WithLookupTable()
handleSignAndSendTransactionV0WithLookupTable()