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);
Previous
Metaplex Umi Plugins