metaplex-foundation / mpl-token-metadata

Program to attach additional data to Fungible or Non-Fungible tokens on Solana.
https://developers.metaplex.com/token-metadata
Other
98 stars 41 forks source link

Incorrect account owner during minting on asset created with mpl-core #119

Open pietromosca1994 opened 4 weeks ago

pietromosca1994 commented 4 weeks ago

I am trying to mint a NFT by combining the create functionality from mpl-core, which allows to add plugins, and the minting functionality from mpl-token-metadata. When I try to mint the token I get the following error:

'Program log: IX: Mint',
'Program log: Incorrect account owner',

Here the program that I am running for replication

// https://developers.metaplex.com/core/create-asset
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
import { generateSigner, createSignerFromKeypair, signerIdentity, percentAmount, PublicKey, createGenericFile } from '@metaplex-foundation/umi'
import { createV2, transferV1, mplCore, addPluginV1, createPluginV2, pluginAuthority} from '@metaplex-foundation/mpl-core'
import { irysUploader} from "@metaplex-foundation/umi-uploader-irys";
import {createAndMint, TokenStandard, mintV1, createNft, createFungibleAsset, mplTokenMetadata} from "@metaplex-foundation/mpl-token-metadata"
import { readFile } from "fs/promises";

const wallet = require('../solana_client/wallet.json');

const umi = createUmi("https://api.devnet.solana.com", "finalized").use(mplCore())
let keypair = umi.eddsa.createKeypairFromSecretKey(new Uint8Array(wallet));
const myKeypairSigner = createSignerFromKeypair(umi, keypair);
umi.use(signerIdentity(myKeypairSigner));
umi.use(mplTokenMetadata())
umi.use(irysUploader());

export interface BatteryInfo {
  token_id: string,
  battery_cathegory: string,
  battery_weight: string;
  rated_capacity: string,
  nominal_voltage: string
}

export async function createBatteryNFT(batteryInfo: BatteryInfo){

  // create metadata
  const image = await readFile('./battery_pack.jpeg');
  const imageFile = createGenericFile(image, "battery_pack")

  const imageUri = await umi.uploader.upload([imageFile], {
      onProgress: (percent) => {
          console.log(`${percent * 100}% uploaded...`);
      },
  })

  // https://developers.metaplex.com/core/what-is-an-asset
  const uri = await umi.uploader.uploadJson({
  name: `Battery Pack ID ${batteryInfo.token_id}`,
  description: `Battery Pack ID ${batteryInfo.token_id}`,
  image: imageUri[0],
  // animation_url
  // external_url
  // attributes
  "attributes": [
    {
      "trait_type": "Token ID",
      "value": batteryInfo.token_id
    },
    {
      "trait_type": "Battery Cathegory",
      "value": batteryInfo.battery_cathegory
    },
    {
      "trait_type": "Battery Weight",
      "value": batteryInfo.battery_weight
    },
    {
      "trait_type": "Rated Capacity",
      "value": batteryInfo.rated_capacity
    },
    {
      "trait_type": "Nominal Voltage",
      "value": batteryInfo.nominal_voltage
    },
  ]
  // properties
  })

  // create mint address
  const mint = generateSigner(umi);
  console.log(`Mint address: ${mint.publicKey}`)

  await createV2(umi, {
    asset: mint,
    name: `Battery Pack ID ${batteryInfo.token_id}`,
    uri: uri,
    updateAuthority: umi.identity.publicKey,
    payer: umi.identity,
    owner: umi.identity.publicKey,
    authority: umi.identity,
    plugins: [
      {
        plugin: createPluginV2({
          type: 'Attributes',
          attributeList: [{ key: 'key1', value: 'value1' },
                          { key: 'key2', value: 'value2' }
          ],
        }),
        authority: pluginAuthority('UpdateAuthority'),
      },
    ]
  }).sendAndConfirm(umi)

  await mintV1(umi, {
    mint: mint.publicKey,
    authority: umi.identity,
    amount: 1,
    tokenOwner: umi.identity.publicKey,
    tokenStandard: TokenStandard.NonFungible,
  }).sendAndConfirm(umi)

  console.log(`Solana Explorer:   https://explorer.solana.com/address/${mint.publicKey}`)
  console.log(`Solscan:           https://solscan.io/token/${mint.publicKey}`)
}

(async () => {
  const batteryInfo: BatteryInfo = {
    token_id: "123",
    battery_cathegory: "test_battery_cathegory",
    battery_weight: "test_battery_weight",
    rated_capacity: "test_rated_capacity",
    nominal_voltage: "test_nominal_voltage"
  }

  createBatteryNFT(batteryInfo);

})()

Here the versions of the packages that I am using (latest on 04/06/2024)

  "dependencies": {
    "@metaplex-foundation/mpl-core": "^1.0.0",
    "@metaplex-foundation/mpl-token-metadata": "^3.2.1",
    "@metaplex-foundation/umi": "^0.9.1",
    "@metaplex-foundation/umi-bundle-defaults": "^0.9.1",
    "@metaplex-foundation/umi-uploader-irys": "^0.9.1",
    "@metaplex/js": "^4.12.0",
    "@solana/web3.js": "^1.91.8",
    "bs58": "^5.0.0",
    "dotenv": "^16.4.5",
    "ts-node": "^10.9.2",
    "typescript": "^5.4.5",
    "web3": "^4.9.0"
  }

Thank you very much in advance for your help!

MarkSackerberg commented 4 weeks ago

Hey, you can not use the same mint address for a token metadata NFT and a core asset. What are you trying to achieve here? Maybe there is a different solution. It's important to understand that core and TM are completely indpendent programs.

pietromosca1994 commented 4 weeks ago

Hi Mark! Thank you very much for your reply :) I would like to mint an NFT that has attributes that the update authority can change on-chain. I was able to create an NFT with the following method from mpl-token-metadata

  await createAndMint(umi, {
    mint,
    name: 'name',
    symbol: "symbol",
    uri: 'uri',
    sellerFeeBasisPoints: percentAmount(0),
    amount: 1,
    tokenOwner: umi.identity.publicKey,
    tokenStandard: TokenStandard.NonFungible
  }).sendAndConfirm(umi)

and I was able to mint an NFT with the solana token program

let tx = new Transaction().add(
  createUpdateFieldInstruction({
    metadata: mint.publicKey,
    updateAuthority: payer.publicKey,
    programId: TOKEN_2022_PROGRAM_ID,
    field: 'myfield',
    value: 'old-value',
  }),
);

Is there a way to achieve a combination of the two in Metaplex and have an NFT with both traits (off-chain) and fields on chain that I can update with transactions? Thank you very much for the reply!