8

I am following the Metaplex JS documentation to mint an NFT with Metaplex. I have solana-test-validator running locally, and my Connection object is working fine with @solana/web3.js and @solana/spl-token. However trying to create an NFT using:

  // Start metaplex
  const metaplex = Metaplex.make(connection)
    .use(keypairIdentity(tokenCreator))
    .use(mockStorage());

  const uploadResponse = await metaplex
    .nfts()
    .uploadMetadata({
      name: "First NFT",
    })
    .run();

  console.log(uploadResponse.uri);

  // Create an NFT
  const createOutput = await metaplex
    .nfts()
    .create({
      uri: uploadResponse.uri,
      name: "My NFT",
      sellerFeeBasisPoints: 500,
    })
    .run();

...fails with:

MetaplexError: Failed to Send Transaction
    >> Source: RPC
    >> Problem: The transaction could not be sent successfully to the network.
    >> Solution: Check the error below for more information.

    Caused By: Error: failed to send transaction: Transaction simulation failed: Attempt to load a program that does not exist

I understand there's a program that makes NFTs and it doesn't seem to exist on localhost - however when I started metaplex I didn't get the option to specify a program address - it looks like metaplex picks the program address for me.

How can I create an NFT using metaplex/js?

2 Answers 2

6

Answering my own question to help others.

I'm not completely sure (because the Metaplex docs don't tell me, and other programs like SPL work on localhost) but Metaplex isn't available on localhost by default.

Saving the Token Metadata program for use on localhost

Find the address of the Token Metadata Program using https://explorer.solana.com/

enter image description here

Then in your shell:

# Token Metadata program
export METAPLEX_PROGRAM_ADDRESS="metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"
solana program dump -u m ${METAPLEX_PROGRAM_ADDRESS} metaplex_token_metadata_program.so

Then run:

solana program dump -u m ${METAPLEX_PROGRAM_ADDRESS} metaplex_token_metadata_program.so

Using a different network (that likely already has the Token Metadata Program loaded).

Modifying the Connection above from:

const connection = new Connection("http://127.0.0.1:8899", "confirmed");

to:

const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

Either method will now create an NFT:

{
  response: {
    signature: '4LtQJVaUbEFdj1hxfPtWsauzVmongHqi2ogLFoHNiMaC56EQjBoaAA8sFqxpadKFTRj8XE8DAkwpwvcaajLjPAbX',
    confirmResponse: { context: [Object], value: [Object] }
  },
  mintAddress: PublicKey {
    _bn: <BN: 5050e6a65c08671fa01e90c7ea6bb2deae4e0c6acbb2c4e42075c5cd16586dec>
  },
  metadataAddress: Pda {
    _bn: <BN: 1fe9d690897e239152627074adc0c48dba4ce3d6b7e851bb5d6eccebf90033a9>,
    bump: 251
  },
  masterEditionAddress: Pda {
    _bn: <BN: f9ab790b1919e47e17b325515f57f5d6f6077e641cd4f2e69d648060db2931ae>,
    bump: 255
  },
  tokenAddress: Pda {
    _bn: <BN: 83bb07d2b1fb7041fcca1eedcc285c991eb40b5593dcc3ac948fa949d7b37a5f>,
    bump: 255
  },
  nft: {
    model: 'nft',
    updateAuthorityAddress: PublicKey {
      _bn: <BN: de3762527abedd0a802891770ee0a7306c04dba7c79620de328b03ff7902b90c>
    },
    json: { name: 'First NFT' },
    jsonLoaded: true,
    name: 'My NFT',
    symbol: '',
    uri: 'https://mockstorage.example.com/bV5x6x2y3dvQ5f29MTgV',
    isMutable: true,
    primarySaleHappened: false,
    sellerFeeBasisPoints: 500,
    editionNonce: 255,
    creators: [ [Object] ],
    tokenStandard: 0,
    collection: null,
    collectionDetails: null,
    uses: null,
    address: PublicKey {
      _bn: <BN: 5050e6a65c08671fa01e90c7ea6bb2deae4e0c6acbb2c4e42075c5cd16586dec>
    },
    metadataAddress: Pda {
      _bn: <BN: 1fe9d690897e239152627074adc0c48dba4ce3d6b7e851bb5d6eccebf90033a9>,
      bump: 251
    },
    mint: {
      model: 'mint',
      address: [PublicKey],
      mintAuthorityAddress: [PublicKey],
      freezeAuthorityAddress: [PublicKey],
      decimals: 0,
      supply: [Object],
      isWrappedSol: false,
      currency: [Object]
    },
    token: {
      model: 'token',
      address: [Pda],
      isAssociatedToken: true,
      mintAddress: [PublicKey],
      ownerAddress: [PublicKey],
      amount: [Object],
      closeAuthorityAddress: null,
      delegateAddress: null,
      delegateAmount: [Object],
      state: 1
    },
    edition: {
      model: 'nftEdition',
      isOriginal: true,
      address: [Pda],
      supply: <BN: 0>,
      maxSupply: <BN: 0>
    }
  }
}
6

If you want to use localnet, you will need to load any already-existing programs, other than the Solana "native" programs (native programs include the token program, associated token program, compute budget program and others).

There are different ways to load a program to localnet, take a look at the solana cookbook and anchor docs (if you're using anchor).

## An example from the cookbook that downloads and loads the Serum Dex program
solana program dump -u m 9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin serum_dex_v3.so
solana-test-validator --bpf-program 9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin serum_dex_v3.so --reset

Another anchor-specific thing: the 'anchor-localnet-nfts' app can generate the anchor.toml file that loads NFT both the required programs and mint addresses) in your wallet. E.g. it would look like this:

### Generated by anchor-localnet-nfts

## Necessary for test validator
[test.validator]
url = "https://api.devnet.solana.com"
[test]
startup_wait = 20000

## Cloning main programs
# Token program
[[test.validator.clone]]
address = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
# Associated Token program
[[test.validator.clone]]
address = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
# Token Metadata program
[[test.validator.clone]]
address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"

### Cloning NFT-related Accounts from address 5xsj5... on devnet

## NFT #0 (Random NFT)
# Mint address
[[test.validator.clone]]
address = "FigzseRcPZ26xE7ZRPUUQvtxuT7sQ1scqCYpRvasABBZ"
# Associated Token Account address
[[test.validator.clone]]
address = "BETsRRYAhQRhuSDzRSh4F5kD52JdhsEfYwihduNJzHjB"
# Metadata Program Derived address
[[test.validator.clone]]
address = "Dr2iXV9r8vJEu2eCCqsCuAZkzr1sq6uVRBLpncMZA9xz"
6
  • 1
    Thanks @pepelKO! How would I get the program address for Metaplex? How did you know "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" was Metaplex token metadata?
    – mikemaccana
    Commented Aug 11, 2022 at 14:33
  • I've updated my own answer to add instructions for those not using anchor. I'll mark yours as correct though since you helped me!
    – mikemaccana
    Commented Aug 11, 2022 at 15:20
  • 1
    Good question, I think it should be possible to find it somewhere in the docs: docs.metaplex.com. I knew about it, so I just entered "Token" on explorer.solana.com and let the autocomplete find it for me.
    – pepeIKO
    Commented Aug 11, 2022 at 15:49
  • @pepelKO How do I know if a program is a native program or a BPF program? For example, ComputeBudget? You might be able to help with solana.stackexchange.com/questions/5600/…
    – mikemaccana
    Commented Feb 14, 2023 at 13:31
  • 1
    @mikemaccana I'm not sure but I would do the same thing as above: try to find it in the explorer (explorer.solana.com/address/…) and then check if it has a field where the "Assigned Program Id" or something similar is equal to "Native Loader" or "BPF Loader/BPF Loader 2". If it has, it's a native program.
    – pepeIKO
    Commented Feb 15, 2023 at 14:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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