This tutorial demonstrates how to create a custom ERC721 NFT smart contract using Solidity and OpenZeppelin, covering the development cycle from writing the smart contract with functions for minting tokens, storing metadata (year, month, day, title, color), and implementing ownership verification, through testing with Truffle, deploying to Ganache, and finally connecting the NFT to OpenSea by implementing a backend service that generates token metadata JSON and animated SVG representations for each token.
ERC721 Token Implementation: Solidity Smart Contract and OpenSea Integration
Added:Welcome back to day two of my journey to develop my first-ever crypto collectible and smart contract for the Ethereum blockchain. If you haven't watched the first video I highly recommend it. Today we will write our first smart contract in solidity and figure out how we can connect our own NFT to marketplaces like OpenSea. If this sounds like a lot of work you're right it was a hell of a day.
So here is the idea: I want to develop a non-fungible token called Date Token, so you can mint your own token for every date in our calendar. From year one till now. Unless somebody else already owns that token. Every Date Token is unique. You could mint your birthday, or the date of the moon landing or the invention of the light bulb, whatever date you want to own. And I want to store all the needed information inside of the blockchain: year, month, and date. That sounds like a small and achievable goal for one day let's see how it goes.
Some of you might ask: What is an NFT? NFT stands for non-fungible token. A token is something you can have inside of your wallet. If you have one ether, that would be one token of ether inside of your wallet. But what does non-fungible mean? Fungible means replaceable by another identical item and non-fungible means basically the opposite. So if I give you a dollar and you give me one of your dollars we both end up again with one dollar. There is no value difference in your dollar to my dollar. Dollars are fungible.
But if we were to trade Pokemon cards. I give you one of my Pokemon cards and you give me another one of yours. We both have the same amount of pokemon cards after the exchange, but the value of the two cards is not necessarily the same. Pokemon cards are non-fungible.
The same goes for the Date Token. If I owned the date of the moon landing and you own some other random date, I certainly don't want to trade with you, because the intrinsic value of my date might be higher than yours.
I learned that there are different tokens on the Ethereum network and each token needs a certain smart contract to be implemented in order to work. If you want to create your own currency you would need to implement the ERC20 token and for NFTs you use ERC721. ERC20 and ERC2721 are basically interfaces you need to implement in your smart contract in order to be recognized as a currency or an NFT on the Ethereum network and so that other dApps can identify and use your tokens.
If you have looked into NFTs before, you certainly found the website OpenSea. OpenSea is a marketplace. On there you can buy and sell your NFTs. All of these are so-called ERC721 tokens.
You can also create your own NFTs here on OpenSea. You just need to upload whatever graphic, video, or audio file you want and OpenSea creates an OpenSea NFT for it. What OpenSea basically does, is creating an OpenSea token, which is connected to your media file using their own smart contract.
But doing that would be way too easy. We want to create our own smart contract. In order to create our own ERC721 smart contract, we could write implementations for all of these functions. Or we could use OpenZeppelin: A library for implementing different types of ERC tokens. OpenZeppelin can be installed using NPM and helps us by implementing almost all of the functionality we need for our ERC721 token. We just need to fill in the gaps.
So I installed OpenZeppelin using NPM and built my first ERC721 smart contract. This is what we got so far.
I created a file "date.sol". I added a little header. I imported the OpenZeppelin ERC721 contract and the contract date is ERC721. I call the constructor, define my own token name, and my own token symbol. I inherit all the functionality I need.
And, yeah, let's try to compile it. "truffle compile".
So the next step is to actually migrate our smart contract to our local ganache blockchain. As far as I know, I need to write "truffle migrate".
Okay, it went through. In ganache, there's a tab called "contracts". Going there I see a Migrations and I see a Date contract, but it is not deployed, which means we have to add our Date contract to our migration script.
For that to work, we need a new file in our migrations subfolder starting with a 2, so it's the second migration step. I call that "2_token_migration.js". In there i need to load my smart contract and deploy it to the blockchain.
So what's basically happening here is, that we import our "date.sol" file somehow and we export a function that calls the deployer to deploy our data. Let's try it out… And this time you see, that a second migration phase is executed: "2_token_migration.js", "Deploying Date" So if I open up ganache now I see that our contract Date is actually deployed and has the following address. That worked … After this first success, All I need to do is to implement the rest. I want to store the year month and day on the blockchain, I also want that the user can add a title to each date, and I have this idea of different materials to make minting more exciting, but more on that later.
The development cycle for smart contracts basically works like this: You implement a function. To make sure it works, you implement a Unit Test for it. truffle.js comes with a testing framework so you can make sure your smart contract works before you deploy it locally to a test net or finally to the main net.
It has been a couple of hours now and I think I have the Date token smart contract ready. So here's what I got so far … I want to store the year, the month, the day, a title for the date token, and the color on the blockchain. So what I did is to define this struct metadata. I added this mapping here, where I map the token-id to the metadata. This is basically how you store data inside of the blockchain.
The constructor is executed when you deploy your smart contract to the blockchain and because I want to have some Date tokens for myself, I call this mint function nine times to generate some interesting Date tokens for my wallet.
The mint function takes a year, month, day, and a color, as well as a title to create a new token. It's defined "internal" so only the contract itself can call it and nobody else can.
In order to create a token for yourself through the web app, I have a different endpoint defined which is "claim".
It has the same parameters, not the color because the color is randomly chosen, it's external so everybody else can call it, and it's payable so you have to pay a little fee in order to create your own Date token.
It costs 10 Finneys to create a Date token. So if that is not given you get a little error message. And then we check the incoming parameters for validity. If they are valid, I generate a different color based on some probabilities I have chosen. Put it into the mint function and transfer the 10 Finneys that you have to pay to my account because I am the owner of the smart contract.
I can "get" a Date token: So I want to read the metadata that is associated to a token-id. So that's the "get" function here.
I can get the title of the Date token. Either by token-id or by year, month, day.
I can change the title of the Date token. But only, If the token exists and, down here, if the owner of the Date token is calling this endpoint. If you don't own a Date token, you can't change the title. If you own it, you can.
One cool thing is that truffle.js comes bundled with a testing framework. The first thing we test is if, after deployment of the date token, the owner of the Date contract is correct. In the test environment, the first account in the ganache blockchain is deploying the contract. So we check if the deployed contract date has the correct owner. Like this.
We check if the name is correct, if the token symbol is correct, we check for the base URI or the token URI. Then we check if I as the owner get all the Date tokens that I have defined in the constructor. And then I check that minting a date actually works and that you have to pay the 10 Finneys to get the date token.
I know that I went over this code rather quickly, but remember the link to all the code is down in the description below if you want to have a closer look.
Now, let's try to run the tests, compile the contract, and migrate it to the ganache blockchain.
"truffle test" runs the test suite. All the tests went through successfully. Let's compile the contract: "truffle compile" "truffle migrate" to migrate the contract to the blockchain, but since we already have migrated the contract to the blockchain once, we need to add "--reset" to the command line parameters so we reset the blockchain and can redeploy our contract.
Bringing up ganache now, I see that the contract is deployed and that I paid a little bit of gas for the deployment.
Looking at MetaMask, we see that MetaMask is not showing the nine Date tokens, that we should have because of the deployment of our smart contract. But we can add the token… Go to "custom token" and paste the contract address here. It automatically reads the token symbol. We go "next" and see nine Date tokens. So now in our MetaMask wallet, we see the nine Date tokens, that we own. Amazing!
If you remember OpenSea and all the little images on it, you might ask yourself: "how does OpenSea know what to show for each token?"
Looking at the OpenSea developer documentation, you see that each ERC721 token has something called a "tokenUri". In there you can store any kind of URI and OpenSea reads this to get its needed information. It basically expects a JSON like the following. In here the title and description of the token is defined, as well as a link to an image, and some optional arbitrary attributes. So what we need to do is to implement a service which returns the JSON for each of our tokens.
After I found out about this, I spent the last couple of hours thinking about a nice representation for our Date tokens so they look good inside our collection on OpenSea. Here is what I came up with… The Date token should be represented by this futuristic-looking card. On there we have the date written out, as well as the token-id and a barcode encoding all the information of this token. The top half consists of three parts. We have five squares in the center which encode the day of the month. So it looks different for Elon Musk's birthday or the moon landing or the start of the Ethereum blockchain. It is a 5-bit encoding of the numbers 1-31. The triangles represent the month. So January looks different than June or December. 4 bits for 12 months. And the last part, the dots on the circle, represent the year. Which again is simply a binary encoding.
OpenSea supports animated SVGs. So, of course, I want it to be animated. And because I want to have some rarity factor for each minted date token, I also invented eight different colors: blue, green, red, black, silver, gold, neon, and pearl which get chosen randomly during the minting process.
Now, let's program a javascript express.js service, which generates those SVGs and the JSON needed for OpenSea.
So how did I do it: I implemented an express.js server app. I used web3.js to connect to our ganache blockchain like this. After that, I got all the contact information from our compiled JavaScript ABIs that truffle generates in order to interact with the contract and handing in the contract address from our migrated contract. This way I can actually call the functions inside of our smart contract. Then I have one endpoint for OpenSea to get the JSON, and another endpoint for OpenSea to get the SVG image.
Inside of the first endpoint, I call a contract method "get". You remember "get" is the contract method that returns the metadata that we store inside of the blockchain: year, month, day, color, and title. And I use this information to generate the JSON for OpenSea and to put in the URL to our SVG endpoint to get the right representation.
And down here we generate the SVG. All of the code generating the SVG is inside the "svg.js" file that I put into the repository as well. So if you want to look at it, there's a link in the description below.
And that's it for today good night.
Day two is a wrap. And what a day it was!
If you want to follow my journey consider subscribing. Thanks to my patrons for helping running this channel. I see you in one of my other videos if you want. And as always have a lot of fun coders!
Up Next

ERC-721 NFT Collection on Polygon: Smart Contract Deployment Guide
@AliSolanki
86.8K views•2021-11-05

Torrent File Format & Bencoding: A Technical Deep Dive
@AsliEngineering
12.5K views•2022-08-08

Operational Security Essentials: A Guide for Hacktivists (OPSEC)
@hitbsecconf
157.4K views•2012-11-26

Understanding Ethereum: A Comprehensive Beginner's Overview
@99Bitcoins
3.1M views•2018-06-26
Related Study Plans & Knowledge Roadmaps
Structured learning paths in Blockchain & Crypto























![Intro to Blockchain Programing [FULL COURSE 2023]](https://i.ytimg.com/vi_webp/cGQHXmCS94M/maxresdefault.webp)















