Add an Image to an NFT with Token Metadata

Ryan Harris
InstructorRyan Harris

Share this video with your friends

Send Tweet
Published a year ago
Updated a year ago

Let’s add an image to our SVG. We’ll start by creating a base 64 encoded SVG using Base64 and OpenZeppelin.

Then, in order to actually associate an image to our token, we’ll have to apply it to our token’s metadata. We’ll create a base64 JSON object that includes our image, save it as a string variable that lives in memory, then call the _setTokenURI method with our NFT’s ID and our metadata string.

Instructor: [0:00] Let's add an image to our NFT's metadata. First, we'll scroll down to our mint function. Right below the require statement, we're going to create an array of strings that lives in memory and call it SVG.

[0:15] To start, we're going to set the array's length to three. The first index in the array is going to be the start to our SVG string. We'll say SVG =, and I'm going to copy and paste this string. It's an SVG with a viewBox of 100 by 100 and text in the middle of the y-axis.

[0:35] The next index in the array, SVG , will be the value displayed inside our SVG's text tag. In this case, we want to use our currentId counter's value. We'll say currentId.current. This value needs to be a string. Let's go to the top of our contract because we need to import another utility from OpenZeppelin. Then we can come back down to our mint function and wrap our current ID value in strings.tostring.

[1:08] Finally, the last index in the array SVG is going to be the closing SVG in text tags. We'll say, close text, close SVG. We need to concatenate the strings in this array into a single SVG string. We'll create a new string variable that lives in memory and call it image.

[1:31] We'll set this to abi.encodePacked and pass it all three indices of our SVG array. SVG , SVG, SVG. Then we need to wrap this value in a string. If we want to persist this image on the blockchain, we need to encode it in base64.

[1:54] I'm going to go to the top of the smart contract and I'm going to import a base64 utility that I created. You can find more about this in the lesson notes. Import base64.sol.

[2:07] If we go back down to our mint function, we can create a new string variable that lives in memory called encoded image and we'll set that to base64.encodeBytesImage. Let's log out the new encoded image string, console.log encoded image.

[2:30] We can come to our terminal and deploy this to our local blockchain. In order to see this log, we'll need to mint to token. Let's hop over to the browser. Here we are back in the scaffold ETH UI. We have 10 tickets available.

[2:46] Let's scroll down to the mint function right here. Click Send. We've successfully minted in NFT using our updated smart contract. Let's hop back to VS Code. Back in VS Code, let's look through our hardhat logs and see if we can find the console.log encoded image. Here it is.

[3:08] Let's copy and paste this, and hop back to our browser. Open a new tab and paste the value. Before you hit Enter, we need to tell the browser what type of data we're dealing with. We need to prepend the string with data:image/SVG+XML;base64, Enter.

[3:29] You can see here that our current token ID of one has successfully been interpolated into the base64 encoded SVG image. Let's go back to VS Code. While we have the SVG image working, we need to apply this all to our NFT's metadata. We need to do a bit more work.

[3:47] First, we need to come down below our encoded image and create a new variable. This will be a string that lives in memory and we'll call it JSON. We'll set its value to base64.encode. Inside of that, we'll have bytes string and abi.encodePacked.

[4:07] In here, we need to create a JSON string that represents our NFT's metadata. Instead of typing this out, I'm going to copy and paste it. What we have here is an NFT with the name NFTix.

[4:21] Again, we're interpolating the string value of our current ID counter, so that each token has a unique ID number. Each token in the collection shares the same description, a NFT powered ticketing system. We also have a set of traits here based on the OpenSea metadata model.

[4:37] Once again, we need to take all of this and create a new string variable that lives in memory. We'll call it string memory token URI and we'll set it to string abi.encodePackedData:application/JSON;base64, and our JSON string.

[5:02] Token URI is a base64 encoded JSON object that represents the metadata of our NFT. The last thing we need to do here is right below where we mint, call another method we've inherited from OpenZeppelin. Set token URI, which will set the metadata of an NFT.

[5:21] Then we pass it a token ID. In this case, the current value of our currentId counter. We'll say, currentId.current, and then the metadata itself, so token URI.

[5:34] For testing purposes, we can also log out this token URI string, console.log token URI. We can redeploy the smart contract to our local blockchain, yarn deploy, and go back to our browser where we can mint another NFT.

[5:53] Let's find the token URI we logged out in our Hardhat logs. There it is. We'll copy and paste this. We'll go back to our browser. Open a new tab, paste it into the address bar, and hit Enter. You should see all of the metadata associated with this NFT, including the image.

[6:20] In summary, we updated our smart contract to create a base64 encoded JSON object, that represents the metadata of our NFT, and applied it to the token.

~ a year ago

Hi Ryan! For [1:54] I can't find any info on how to get the Base64.sol implementation in the lesson notes. Am I missing something?

Panagiotis Thomoglou
Panagiotis Thomoglou
~ a year ago

Hi, I couldn't find it either. You could use another working library here https://gist.github.com/hellopath/6f7cd754fbcd45653946095e857f7c7e

Ryan Harris
Ryan Harrisinstructor
~ a year ago

Hey, y'all! So sorry I forgot to include that info. Here are some links:

  • UI starter repo: https://github.com/ryancharris/nftix-demo-ui
  • Base64: https://gist.github.com/ryancharris/ed5c4f161f2ab049adf41a7f3eed2229
  • Final smart contract: https://gist.github.com/ryancharris/b1be47faf3f141f21fbd5b42c80da2e3
~ a year ago

what extension do you have to for reading json?

~ a year ago

Running into issues with _setTokenURI probably because of this:

https://forum.openzeppelin.com/t/function-settokenuri-in-erc721-is-gone-with-pragma-0-8-0/5978/2

Am I the only one?

~ 9 months ago

i got a error : string memory encodedImage = Base64.encode(bytes(image));

Invalid type for argument in function call. Invalid implicit conversion from bytes memory to string memory requested.

Lucas
Lucas
~ 4 months ago

Hey. Here is a forum post about implicit conversion from string memory to bytes memory requested. Hopefully, this should answer your error: https://ethereum.stackexchange.com/questions/69055/solidity-invalid-implicit-conversion-from-string-memory-to-bytes-memory-requeste.