Introduction
Web3.js Differences and Adapters
The @solana/web3.js
library is currently widely used in the Solana ecosystem and defines its own types for Publickeys
, Transactions
, Instructions
, etc.
When creating Umi
, we wanted to move away from the class-based types defined in @solana/web3.js
. This unfortunately means that, although having the same or similar import names, not all types from @solana/web3.js
are compatible with the ones provided by Umi
and vice versa.
To help with this issue, Umi
provides a set of adapters that allows to parse types to and from their Web3.js
counterparts and they can be found in the @metaplex-foundation/umi-web3js-adapters
package.
Required Package and Imports
The umi-web3js-adapters
package includes all the helper methods needed to convert between Umi and Web3.js types.
While it's already included when you install the @metaplex-foundation/umi
package, you can also install it separately using the following command:
npm i @metaplex-foundation/umi-web3js-adapters
Here are the imports you’ll have access to:
import {
// Keypairs
fromWeb3JsKeypair, toWeb3JsKeypair,
// Publickey
fromWeb3JsPublicKey, toWeb3JsPublicKey,
// Instructions
fromWeb3JsInstruction, toWeb3JsInstruction,
// Legacy Transactions
fromWeb3JsLegacyTransaction, toWeb3JsLegacyTransaction,
// Versioned Transactions
fromWeb3JsTransaction, toWeb3JsTransaction,
// Messages
fromWeb3JsMessage, toWeb3JsMessage, toWeb3JsMessageFromInput
} from '@metaplex-foundation/umi-web3js-adapters';
Publickeys
Generating publickeys might seem similar at first sight, but there are some subtle differences between the packages. Web3Js uses a capital P
and requires new
, while the Umi version uses a lowercase p
.
Umi
import { publicKey } from '@metaplex-foundation/umi';
// Generate a new Umi Publickey
const umiPublicKey = publicKey("11111111111111111111111111111111");
Web3Js
import { PublicKey } from '@solana/web3.js';
// Generate a new Web3Js Publickey
const web3jsPublickey = new PublicKey("1111111111111111111111111111111111111111");
Next, let's look into how to use the adapters.
From Web3Js to Umi
import { PublicKey } from '@solana/web3.js';
import { fromWeb3JsPublicKey } from '@metaplex-foundation/umi-web3js-adapters';
// Generate a new Publickey
const web3jsPublickey = new PublicKey("1111111111111111111111111111111111111111");
// Convert it using the UmiWeb3jsAdapters Package
const umiPublicKey = fromWeb3JsPublicKey(web3jsPublickey);
From Umi to Web3Js
import { publicKey } from '@metaplex-foundation/umi';
import { toWeb3JsPublicKey } from '@metaplex-foundation/umi-web3js-adapters';
// Generate a new Publickey
const umiPublicKey = publicKey("11111111111111111111111111111111");
// Convert it using the UmiWeb3jsAdapters Package
const web3jsPublickey = toWeb3JsPublicKey(umiPublicKey);
Keypairs
Generating keypairs is where the difference from Web3Js and Umi increase. With Web3Js, you can simply use Keypair.generate()
, however, in Umi, you first need to create an Umi instance, which you'll use for most Umi and Metaplex-related operations.
Umi
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { generateSigner, createSignerFromKeypair } from '@metaplex-foundation/umi'
// Generate a new Umi instance
const umi = createUmi('https://api.devnet.solana.com')
// Generate a new Umi keypair
const umiKeypair = generateSigner(umi)
// Or use an existing one
const umiKeypair = umi.eddsa.createKeypairFromSecretKey(new Uint8Array(walletFile));
Web3Js
import { Keypair } from '@solana/web3.js';
// Generate a new Web3Js keypair
const web3jsKeypair = Keypair.generate();
// Or use an existing one
const web3jsKeypair = Keypair.fromSecretKey(new Uint8Array(walletFile));
Next, let's look into how to use the adapters.
From Umi to Web3Js
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { generateSigner } from '@metaplex-foundation/umi'
import { toWeb3JsKeypair } from '@metaplex-foundation/umi-web3js-adapters';
// Generate a new Umi instance
const umi = createUmi('https://api.devnet.solana.com')
// Generate a new keypair
const umiKeypair = generateSigner(umi)
// Convert it using the UmiWeb3jsAdapters Package
const web3jsKeypair = toWeb3JsKeypair(umiKeypair);
From Web3Js to Umi
import { Keypair } from '@solana/web3.js';
import { fromWeb3JsKeypair } from '@metaplex-foundation/umi-web3js-adapters';
// Generate a new keypair
const web3jsKeypair = Keypair.generate();
// Convert it using the UmiWeb3jsAdapters Package
const umiKeypair = fromWeb3JsKeypair(web3jsKeypair);
Instructions
When creating instructions, the key difference with Umi is that you must first create an Umi instance (as with Keypairs
). Additionally, getInstructions()
returns an array of instructions instead of a single one.
For most use cases, handling individual instructions isn't necessary anyway, as this can be simplified using other helpers and transaction builders.
Umi
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { transferSol } from '@metaplex-foundation/mpl-toolbox';
// Generate a new Umi instance
const umi = createUmi('https://api.devnet.solana.com').use(mplCore())
// Create a new instruction (like a core nft transfer)
// get instructions will give you an Array of instructions
const umiInstructions = transferSol(umi, {...TransferParams}).getInstructions();
Web3Js
import { SystemProgram } from '@solana/web3.js';
// Create a new instruction (like a lamport transfer)
const web3jsInstruction = SystemProgram.transfer({...TransferParams})
Next, let's look into how to use the adapters.
From Umi to Web3Js
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { transferSol } from '@metaplex-foundation/mpl-toolbox';
import { toWeb3JsInstruction } from '@metaplex-foundation/umi-web3js-adapters';
// Generate a new Umi instance
const umi = createUmi('https://api.devnet.solana.com').use(mplCore())
// Create a new instruction (like a core nft transfer)
const umiInstruction = transferSol(umi, {...TransferParams}).getInstructions();
// Convert it using the UmiWeb3jsAdapters Package
const web3jsInstruction = umiInstruction.map(toWeb3JsInstruction);
From Web3Js to Umi
import { SystemProgram } from '@solana/web3.js';
import { fromWeb3JsInstruction } from '@metaplex-foundation/umi-web3js-adapters';
// Generate a new Umi instance
const umi = createUmi('https://api.devnet.solana.com')
// Create a new instruction (like a lamport transfer)
const web3jsInstruction = SystemProgram.transfer({...TransferParams})
// Convert it using the UmiWeb3jsAdapters Package
const umiInstruction = fromWeb3JsInstruction(web3jsInstruction);
Transactions
The Solana runtime supports two transaction versions:
- Legacy Transaction: Older transaction format with no additional benefit
- 0 / Versioned Transaction: Added support for Address Lookup Tables
Note: if you're not familiar with the concept of Versioned Transactions, read more about it here
For umi
and umi-web3js-adapters
we added support for both transaction types!
Umi
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { transferSol } from '@metaplex-foundation/mpl-toolbox';
// Generate a new Umi instance
const umi = createUmi('https://api.devnet.solana.com').use(mplCore())
// Create a new Umi Legacy Transaction
const umiTransaction = transferSol(umi, {...TransferParams}).useLegacyVersion();
// Create a new Umi Versioned Transaction
const umiVersionedTransaction = transferSol(umi, {...TransferParams}).useV0().build(umi)
Web3Js
import { Transaction, VersionedTransaction, TransactionMessage, Connection, clusterApiUrl, SystemProgram } from '@solana/web3.js';
// Create a new Web3Js Legacy Transaction
const web3jsTransaction = new Transaction().add(SystemProgram.transfer({...TransferParams}));
// Create a new Web3Js Versioned Transaction
const instructions = [SystemProgram.transfer({...TransferParams})];
const connection = new Connection(clusterApiUrl("devnet"));
const blockhash = await connection.getLatestBlockhash().then(res => res.blockhash);
const messageV0 = new TransactionMessage({
payerKey: payer.publicKey,
recentBlockhash: blockhash,
instructions,
}).compileToV0Message();
const web3jsVersionedTransaction = new VersionedTransaction(messageV0);
Next, let's look into how to use the adapters.
From Umi to Web3Js
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { transferSol } from '@metaplex-foundation/mpl-toolbox';
import { toWeb3JsLegacyTransaction, toWeb3JsTransaction } from '@metaplex-foundation/umi-web3js-adapters';
// Generate a new Umi instance
const umi = createUmi('https://api.devnet.solana.com').use(mplCore())
// Create a new Legacy Transaction
const umiTransaction = transferSol(umi, {...TransferParams}).useLegacyVersion();
// Convert it using the UmiWeb3jsAdapters Package
const web3jsTransaction = toWeb3JsTransaction(umiTransaction);
/// Versioned Transactions ///
// Create a new Versioned Transaction
const umiVersionedTransaction = transferSol(umi, {...TransferParams}).useV0().build(umi)
// Convert it using the UmiWeb3jsAdapters Package
const web3jsVersionedTransaction = toWeb3JsTransaction(umiVersionedTransaction);
From Web3Js to Umi
import { Transaction, VersionedTransaction, TransactionMessage, Connection, clusterApiUrl, SystemProgram } from '@solana/web3.js';
import { fromWeb3JsLegacyTransaction, fromWeb3JsTransaction } from '@metaplex-foundation/umi-web3js-adapters';
// Create a new Legacy Transaction
const web3jsTransaction = new Transaction().add(SystemProgram.transfer({...TransferParams}));
// Convert it using the UmiWeb3jsAdapters Package
const umiTransaction = fromWeb3JsLegacyTransaction(web3jsTransaction);
/// Versioned Transactions ///
// Create a new Versioned Transaction
const web3jsVersionedTransaction = new VersionedTransaction(...messageV0Params);
// Convert it using the UmiWeb3jsAdapters Package
const umiVersionedTransaction = fromWeb3JsTransaction(web3jsVersionedTransaction);
Messages
We've already covered creating messages during versioned transaction creation. Let's review it again.
Umi
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { transfer, mplCore } from '@metaplex-foundation/mpl-core'
// Generate a new Umi instance
const umi = createUmi('https://api.devnet.solana.com').use(mplCore())
// Create a new Umi Message
const blockhash = await umi.rpc.getLatestBlockhash()
const instructions = transfer(umi, {...TransferParams}).getInstructions()
const umiVersionedTransaction = umi.transactions.create({
version: 0,
payer: frontEndSigner.publicKey,
instructions,
blockhash: blockhash.blockhash,
});
const umiMessage = umiVersionedTransaction.message
Web3Js
import { TransactionMessage, Connection, clusterApiUrl, SystemProgram } from '@solana/web3.js';
// Create a new Web3Js Message
const connection = new Connection(clusterApiUrl("devnet"));
const minRent = await connection.getMinimumBalanceForRentExemption(0);
const blockhash = await connection.getLatestBlockhash().then(res => res.blockhash);
const instructions = [SystemProgram.transfer({...TransferParams})];
const Web3JsMessage = new TransactionMessage({
payerKey: payer.publicKey,
recentBlockhash: blockhash,
instructions,
}).compileToV0Message();
Next, let's look into how to use the adapters.
From Umi to Web3Js
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults'
import { toWeb3JMessage } from '@metaplex-foundation/umi-web3js-adapters';
// Generate a new Umi instance
const umi = createUmi('https://api.devnet.solana.com').use(mplCore())
// Create a new Versioned Transaction
const umiMessage = umi.transactions.create({...createParams}).message;
// Convert it using the UmiWeb3jsAdapters Package
const web3jsMessage = toWeb3JMessage(umiMessage);
From Web3Js to Umi
import { TransactionMessage } from '@solana/web3.js';
import { fromWeb3JMessage } from '@metaplex-foundation/umi-web3js-adapters';
// Create a new Versioned Transaction
const Web3JsMessage = new TransactionMessage({...createMessageParams}).compileToV0Message();
// Convert it using the UmiWeb3jsAdapters Package
const umiMessage = fromWeb3JMessage(Web3JsMessage);