Javascript

How to Add Metadata to a Solana Token

This guide will take you through adding metadata to an already initialized Solana Token (SPL Token) using the Metaplex Token Metadata protocol.

It is recommended to use the available create helper functions to create and initialize your token instead of doing so separately. If you are looking on how to do this, check out this guide instead How to create a Solana Token.

Prerequisite

  • Code Editor of your choice (recommended Visual Studio Code)
  • Node 18.x.x or above.

Initial Setup

This guide assumes that you already have an SPL token initialized for which you'd like to add metadata to. You might need to modify and move functions around to suite your needs.

Initializing

Start by initializing a new empty project using a JS/TS package manager (npm, yarn, pnpm, bun, deno) of your choice.

npm init -y

Required Packages

Install the required packages for this guide.

npm i @metaplex-foundation/umi
npm i @metaplex-foundation/umi-bundle-defaults
npm i @metaplex-foundation/mpl-token-metadata

Imports and Wrapper Function

We will list the necessary imports and our wrapper function,

  1. addMetadata
import {
	createV1,
	findMetadataPda,
	mplTokenMetadata,
} from "@metaplex-foundation/mpl-token-metadata";
import { generateSigner, signerIdentity, sol } from "@metaplex-foundation/umi";
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
import { base58 } from "@metaplex-foundation/umi/serializers";

/// 
/// instantiate umi 
///


// Add metadata to an existing SPL token wrapper function
async function addMetadata() {
	///
	///
	///  code will go in here
	///
	///
}

// run the function
addMetadata();

Setting up Umi

This example is going to run through setting up Umi with a generatedSigner(). If you wish to set up a wallet or signer differently you can check out the Connecting to Umi guide.

You can place the Umi instantiation code inside or outside the code blocks, but to reduce code duplication, we will keep it outside.

Generating a New Wallet

const umi = createUmi("https://api.devnet.solana.com")
	.use(mplTokenMetadata())
	.use(mplToolbox());

// Generate a new keypair signer.
const signer = generateSigner(umi);

// Tell umi to use the new signer.
umi.use(signerIdentity(signer));

// Airdrop 2 SOL to the identity
// if you end up with a 429 too many requests error, you may have to use
// the a different rpc other than the free default one supplied.
await umi.rpc.airdrop(umi.identity.publicKey, sol(2));

Use an Existing Wallet Stored Locally

const umi = createUmi("https://api.devnet.solana.com")
	.use(mplTokenMetadata())
	.use(mplToolbox());

// You will need to us fs and navigate the filesystem to
// load the wallet you wish to use via relative pathing.
const walletFile = const imageFile = fs.readFileSync('./keypair.json')

// Convert your walletFile onto a keypair.
let keypair = umi.eddsa.createKeypairFromSecretKey(new Uint8Array(walletFile));

// Load the keypair into umi.
umi.use(keypairIdentity(umiSigner));

Adding Metadata

Adding metadata is also as simple as creating an SPL token. We will utilize the createV1 helper method from the mpl-token-metadata library.

Also note that this guide assumes that you already had your off-chain token metadata prepared beforehand. We will need the name, off-chain uri address and symbol

name: "Solana Gold",
symbol: "GOLDSOL",
uri: "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json",
// Sample Metadata for our Token
const tokenMetadata = {
	name: "Solana Gold",
	symbol: "GOLDSOL",
	uri: "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json",
};

// Add metadata to an existing SPL token wrapper function
async function addMetadata() {
    const mint = publicKey("YOUR_TOKEN_MINT_ADDRESS");

    // derive the metadata account that will store our metadata data onchain
	const metadataAccountAddress = await findMetadataPda(umi, {
		mint: mint,
	});

   // add metadata to our already initialized token using `createV1` helper 
	const tx = await createV1(umi, {
		mint,
		authority: umi.identity,
		payer: umi.identity,
		updateAuthority: umi.identity,
		name: tokenMetadata.name,
		symbol: tokenMetadata.symbol,
		uri: tokenMetadata.uri,
		sellerFeeBasisPoints: percentAmount(5.5), // 5.5%
		tokenStandard: TokenStandard.Fungible,
	}).sendAndConfirm(umi);

	let txSig = base58.deserialize(tx.signature);
	console.log(`https://explorer.solana.com/tx/${txSig}?cluster=devnet`);
}

Nullable fields like creators have been left out as they might not be as necessary for SPL tokens compared to Non Fungibles.

Take note of the mint address, If you will call the functions at different instances, make sure to set the address of the mint field in the findMetadataPda function as generateSigner will return a new keypair upon each call.

Full Code Example

import {
	createV1,
	findMetadataPda,
	mplTokenMetadata,
} from "@metaplex-foundation/mpl-token-metadata";
import { createMint, mplToolbox } from "@metaplex-foundation/mpl-toolbox";
import { generateSigner, signerIdentity, sol } from "@metaplex-foundation/umi";
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
import { base58 } from "@metaplex-foundation/umi/serializers";

const umi = createUmi("https://api.devnet.solana.com")
	.use(mplTokenMetadata())
	.use(mplToolbox());

// Generate a new keypair signer.
const signer = generateSigner(umi);

// Tell umi to use the new signer.
umi.use(signerIdentity(signer));

// Airdrop 2 SOL to the identity
// if you end up with a 429 too many requests error, you may have to use
// the a different rpc other than the free default one supplied.
await umi.rpc.airdrop(umi.identity.publicKey, sol(2));

// your SPL Token mint address
const mint = publicKey("YOUR_TOKEN_MINT_ADDRESS");
 

// Sample Metadata for our Token
const tokenMetadata = {
	name: "Solana Gold",
	symbol: "GOLDSOL",
	uri: "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json",
};

// Add metadata to an existing SPL token wrapper function
async function addMetadata() {
    // derive the metadata account that will store our metadata data onchain
	const metadataAccountAddress = await findMetadataPda(umi, {
		mint: mint,
	});

	const tx = await createV1(umi, {
		mint,
		authority: umi.identity,
		payer: umi.identity,
		updateAuthority: umi.identity,
		name: tokenMetadata.name,
		symbol: tokenMetadata.symbol,
		uri: tokenMetadata.uri,
		sellerFeeBasisPoints: percentAmount(5.5), // 5.5%
		tokenStandard: TokenStandard.Fungible,
	}).sendAndConfirm(umi);

	let txSig = base58.deserialize(tx.signature);
	console.log(`https://explorer.solana.com/tx/${txSig}?cluster=devnet`);
}

// run the function
addMetadata();

What's Next?

This guide helped you to add metadata to a Solana Token, from here you can head over to the Token Metadata Program and check out helper functions that initialize and add metadata to your token in one step, working with non-fungibles and other various ways to interact with the Token Metadata program.

Previous
How to Create a Solana Token