1

I have an existing token mint created with the createMint() from "@solana/spl-token"

How can I add metadata to the fungible token?

The Metaplex docs cover creating a new fungible token from scratch but don't cover how to add metadata to an existing token.

Using the auto generated TS docs and manually trying to find a getCreateMetadataAccountV3Instruction() function doesn't have any function by that name, though there are other types related to CreateMetadataAccountV3.

My goal is to have a nice name and image instead of Unknown Token in Solana Explorer. enter image description here

0

1 Answer 1

1

Below is a script you can reference to create a metaplex metadata account, just replace wallet_1 with a funded keypair. Adapted from the solution from this stack exchange question.

   import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
    import {
      findMetadataPda,
      createMetadataAccountV3,
      MPL_TOKEN_METADATA_PROGRAM_ID,
    } from "@metaplex-foundation/mpl-token-metadata";
    import {
      fromWeb3JsPublicKey,
      toWeb3JsPublicKey,
    } from "@metaplex-foundation/umi-web3js-adapters";
    import {
      MINT_SIZE,
      TOKEN_PROGRAM_ID,
      createInitializeMint2Instruction,
      getMinimumBalanceForRentExemptMint,
    } from "@solana/spl-token";
    import {
      Connection,
      Keypair,
      PublicKey,
      SystemProgram,
      Transaction,
      TransactionInstruction,
      clusterApiUrl,
      sendAndConfirmTransaction,
    } from "@solana/web3.js";
    import { getOrCreateKeypair } from "./utils";
    import { createNoopSigner, signerIdentity } from "@metaplex-foundation/umi";
    
    // Use existing keypairs or generate new ones if they don't exist
    const wallet_1 = getOrCreateKeypair("wallet_1");
    const mySigner = createNoopSigner(fromWeb3JsPublicKey(wallet_1.publicKey));
    
    //Connection and Umi instance
    const endpoint = clusterApiUrl("devnet");
    const umi = createUmi(endpoint, "confirmed");
    umi.use(signerIdentity(mySigner));
    const connection = new Connection(endpoint, "confirmed");
    
    // Generate keypair to use as address of token account
    const mintKeypair = new Keypair();
    const mint = fromWeb3JsPublicKey(mintKeypair.publicKey);
    
    // Calculate minimum lamports for space required by mint account
    const lamports = await getMinimumBalanceForRentExemptMint(connection);
    
    // Instruction to create new account with space for new mint account
    const createAccountInstruction = SystemProgram.createAccount({
      fromPubkey: wallet_1.publicKey,
      newAccountPubkey: mintKeypair.publicKey,
      space: MINT_SIZE,
      lamports,
      programId: TOKEN_PROGRAM_ID,
    });
    
    // Instruction to initialize mint account
    const initializeMintInstruction = createInitializeMint2Instruction(
      mintKeypair.publicKey, // mint address
      2, // decimals
      wallet_1.publicKey, // mint authority
      wallet_1.publicKey // freeze authority
    );
    
    const metadataAccountAddress = await findMetadataPda(umi, {
      mint: mint,
    });
    
    // // Derive the Metadata account address
    // const [metadataAccountAddress] = PublicKey.findProgramAddressSync(
    //   [
    //     Buffer.from("metadata"), // hard-coded string "metadata"
    //     toWeb3JsPublicKey(MPL_TOKEN_METADATA_PROGRAM_ID).toBuffer(), // metadata program address
    //     mintKeypair.publicKey.toBuffer(), // mint address
    //   ],
    //   toWeb3JsPublicKey(MPL_TOKEN_METADATA_PROGRAM_ID)
    // );
    
    // Metadata for the 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",
    };
    
    // Create the Metadata account for the Mint
    const transactionBuilder = createMetadataAccountV3(umi, {
      metadata: metadataAccountAddress,
      mint: mint,
      mintAuthority: mySigner,
      payer: mySigner,
      updateAuthority: mySigner.publicKey,
      data: {
        creators: null,
        name: tokenMetadata.name,
        symbol: tokenMetadata.symbol,
        uri: tokenMetadata.uri,
        sellerFeeBasisPoints: 0,
        collection: null,
        uses: null,
      },
      collectionDetails: null,
      isMutable: true,
    });
    
    const ix: any = transactionBuilder.getInstructions()[0];
    
    ix.keys = ix.keys.map((key) => {
      const newKey = { ...key };
      newKey.pubkey = toWeb3JsPublicKey(key.pubkey);
      return newKey;
    });
    
    // Build transaction with instructions to create new account and initialize mint account
    const transaction = new Transaction().add(
      createAccountInstruction,
      initializeMintInstruction,
      ix
    );
    
    const transactionSignature = await sendAndConfirmTransaction(
      connection,
      transaction,
      [
        wallet_1, // payer
        mintKeypair, // mint address keypair
      ]
    );
    
    console.log(
      "Transaction Signature:",
      `https://explorer.solana.com/tx/${transactionSignature}?cluster=devnet`
    );
    
    console.log(
      "Mint Account:",
      `https://explorer.solana.com/address/${mintKeypair.publicKey.toString()}?cluster=devnet`
    );
1
  • is this the same answer as solana.stackexchange.com/questions/7909/… (you said it was 'adapted' but I wasn't sure what the changes are? If so I'll just mark this as a duplicate and people can read the other answer. General policy on StackExchange BTW is even if the questions are different, they should be marked dupe if they have the same answer.
    – mikemaccana
    Commented Mar 27 at 1:05

Not the answer you're looking for? Browse other questions tagged or ask your own question.