Trouble saving metadata as JSON

I saw the Moralis TY video on saving metadata as JSON. However my code editor says btoa can no longer be used in newer versions of React and I see a strikethrough on the word btoa. Therefore I tried the following:

 const tokenMetadata = new Moralis.File("metadata.json", {
        base64: Buffer.from(JSON.stringify(metadata)).toString('base64')
      });

I npm installed buffer. And yet get this error: Uncaught (in promise) ReferenceError: Buffer is not defined
This StackOverflow thread suggests changes to package.json that I am reluctant to do.

Has anyone faced this issue?

where are you running that code? what framework are you using?

you can also send the data to a cloud function where you have more options on how to save the data to IPFS

  1. This is a React Dapp. I am calling the Mint function on button click and trying to upload to IPFS, then get the URI and pass it into the contract’s mint function.

  2. Yes I already have a cloud function configured in the repo. Should I send the base64 there and then upload to IPFS via cloud function? And then Call the mint contract’s mint function from cloud? Or should I send the URI back from the cloud and call the mint function in react again…

Code below:

async function mintMyNFT() {

    if(!checkTraits()) {
      alert("Some of the selected traits are not in your wallet. Ensure all trait-titles are yellow. Click 'My Owned Traits' again to refresh wallet traits.")
    }

    else {
      const base64 = await getImage()
      const imageData = new Moralis.File("img.png", {base64: base64});
      await imageData.saveIPFS();
      const imgURL = imageData.ipfs();
      const metadata = {
        "name": "Goatd",  
        "description": "Customizable PFP on Avax", 
        "image": imgURL, 
        "attributes": [
            {
            "trait_type": "Background", 
            "value": props.chosenTrait.Background
          },
          {
            "trait_type": "Body", 
            "value": props.chosenTrait.Body
          },
          {
            "trait_type": "Head", 
            "value": props.chosenTrait.Head
          },
          {
            "trait_type": "Eyes", 
            "value": props.chosenTrait.Eyes
          },
          {
            "trait_type": "Mouth", 
            "value": props.chosenTrait.Mouth
          },
          {
            "trait_type": "Headwear", 
            "value": false&&"none"
          }
          ], 
      }

      const tokenMetadata = new Moralis.File("metadata.json", {
        base64: Buffer.from(JSON.stringify(metadata)).toString('base64')
      });
      await tokenMetadata.saveIPFS();
      const metadataUrl = await tokenMetadata.ipfs();

      const mintResult = await mintFetch({
          abi: spotNFTAbiFuji,
          contractAddress: spotNFTContractFuji,
          functionName: "mint",
          params: {
              bg: props.chosenTrait.BackgroundID,
              body: props.chosenTrait.BodyID,
              head: props.chosenTrait.HeadID,
              eyes: props.chosenTrait.EyesID,
              mouth: props.chosenTrait.MouthID,
              headwear: props.chosenTrait.HeadwearID,
              uri: metadataUrl,
          },
            msgValue: Moralis.Units.ETH(1.0),
           
        onError: (err)=> {
          console.log(err)
          alert(JSON.stringify(err.data.message))
        },
        onSuccess: (data) => {
          console.log(data)
          alert("PFP Successfully Minted! Contract address: 0x60e26Afaca30396AAF91Ea3aA355aCf22eeF080e")
        }
      })   
    }

  }

you can not easily call the mint function from cloud code, if you already have the base64 data then there is no need to use cloud code to upload it to IPFS

you can send the metadata to a cloud function, upload it to ipfs from a cloud function and get back the IPFS url from that cloud function

https://docs.moralis.io/moralis-dapp/cloud-code/cloud-functions#object

1 Like

@cryptokid
Getting the following error in console from the cloud function:
POST https://yyx0ccs4ehxj.usemoralis.com:2053/server/functions/handlemintTest 400
Uncaught (in promise) Error: tokenMetadata.saveIPFS is not a function at handleError (RESTController.js:438:1) at async mintMyNFT (Mint.jsx:88:1)
My cloud function is as follows:

Moralis.Cloud.define("handlemintTest", async (request) => {
	metadata = request.params.metadata
  	const tokenMetadata = new Moralis.File("metadata.json", {
        base64: btoa(JSON.stringify(metadata))
      });
      await tokenMetadata.saveIPFS();
      const metadataUrl = await tokenMetadata.ipfs();
  	return metadataUrl
  		
});

the syntax is different in cloud code, I pasted a link above where you can see the syntax, an example:

const result = await Moralis.Cloud.toIpfs({
  sourceType: 'object',
  source: {
    type: "Monster",
    lp: 100,
    spells: {
      base: ["spell one","spell two"],
      locked: ["spell three"],
    }
  },
});
return result;
2 Likes

Thank you very much! Works perfectly. I am getting back a metadata uri: https://ipfs.moralis.io:2053/ipfs/QmUGJrop1GGjXRWVfL5YmWNtykihXNXGPDtQCZ1KNZkM5y

On passing this into my smart contract function call I’m getting the following error:
image

Here’s how I have set it up. On top of my component I have:
const { data: mintData, error: mintError, fetch: mintFetch, isFetching: mintFetching, isLoading: mintLoading } = useWeb3ExecuteFunction();

Then after getting the ipfs url I am calling fetch:

const mintResult = await mintFetch({
          abi: spotNFTAbiFuji,
          contractAddress: spotNFTContractFuji,
          functionName: "mint",
          params: {
              bg: props.chosenTrait.BackgroundID,
              body: props.chosenTrait.BodyID,
              head: props.chosenTrait.HeadID,
              eyes: props.chosenTrait.EyesID,
              mouth: props.chosenTrait.MouthID,
              headwear: props.chosenTrait.HeadwearID,
              uri: tokenMetadataUrl,
          },
            msgValue: Moralis.Units.ETH(1.0),
           
        onError: (err)=> {
          console.log(err)
          alert(JSON.stringify(err.data.message))
        },
        onSuccess: (data) => {
          console.log(data)
          alert("PFP Successfully Minted! Contract address: 0x60e26Afaca30396AAF91Ea3aA355aCf22eeF080e")
        }
      })
      console.log(mintResult)

         
    }

Am I doing the fetch part wrong?

can you check if the parameters sent to mintFetch have the expected value, like the abi for example?

Yes. spotNFTAbiFuji takes in the abi in above code. I have been calling the mint function alright when I was putting these values inside the useWeb3ExecuteFunction() brackets on top. Is my mintFetch code written correctly?
Some minor changes were made to contract (to include the IPFS uri) and then I updated the abi and new contract address. Do you think this is a fault in CALLING the function or is there a fault in the contract?

for me it looks like a parameter doesn’t have the right value, as in it is undefined

for example here is match used in code:

not sure if this is the one that gives that error

1 Like

@cryptokid OK minting is paused! lol. Sorry about that. But why wasnt I getting the error when I was adding params in fetch? Now that I moved all that stuff back to the useWeb3ExecuteFunction brackets on top I am getting back the error:
image

So this format works:

const { data: mintData, error: mintError, fetch: mintFetch, isFetching: mintFetching, isLoading: mintLoading } = useWeb3ExecuteFunction({
    abi: spotNFTAbiFuji,
          contractAddress: spotNFTContractFuji,
          functionName: "mint",
          params: {
              bg: props.chosenTrait.BackgroundID,
              body: props.chosenTrait.BodyID,
              head: props.chosenTrait.HeadID,
              eyes: props.chosenTrait.EyesID,
              mouth: props.chosenTrait.MouthID,
              headwear: props.chosenTrait.HeadwearID,
              uri: 'https://ipfs.moralis.io:2053/ipfs/QmUGJrop1GGjXRWVfL5YmWNtykihXNXGPDtQCZ1KNZkM5y',
          },
          msgValue: Moralis.Units.ETH(1.0)
  });

But the one above where I am putting params and all details in mintFetch doesnt work. Why so?

I will pass some hard coded values and check this part. Thanks.

it may be something easy, I’m not too familiar with react syntax now

Here is a refactor

const callThisFunction = () => {
    let params = {
        bg: props.chosenTrait.BackgroundID,
        body: props.chosenTrait.BodyID,
        head: props.chosenTrait.HeadID,
        eyes: props.chosenTrait.EyesID,
        mouth: props.chosenTrait.MouthID,
        headwear: props.chosenTrait.HeadwearID,
        uri: "https://ipfs.moralis.io:2053/ipfs/QmUGJrop1GGjXRWVfL5YmWNtykihXNXGPDtQCZ1KNZkM5y",
    };

    let amount = 1;

    let options = {
        contractAddress: spotNFTContractFuji,
        functionName: "mint",
        abi: spotNFTAbiFuji,
        params,
        msgValue: Moralis.Units.ETH(amount),
    };

    fetch({
        params: options,
        onSuccess: (tx) => tx.wait().then((newTx) => console.log(newTx)),
        onError: (error) => console.log(error),
    });
};
2 Likes

Thank you! works! I notice I hadn’t added the params twice like you had suggested.
This works too!