Mint an NFT using Solidity
You can host an NFT on sites like OpenSea or Rarible fairly quickly. Just connect your wallet, upload an NFT and boom, it’s listed. They even force the NFT buyer to pay the NFT poster’s gas! Really convenient, actually. But we’re not going to do that. We’ll pay our own gas fees, thank you very much! Minting NFTs with our bare hands builds character and we’ll have a lot more of it after this tutorial.
A poorly constructed analogy
If you wanted to set up a local HTTP server, would you whip out the mechanical keyboard, load up good ole RFC 2616, open your favorite C compiler, snort some G FUEL and get crackin’? No you wouldn’t. No sane person would. You would install Apache, let it do most of the legwork, and not waste weeks of your life. Solidity will be our Apache.
Solidity is a programming language written specifically to handle Ethereum smart contracts and comes with an ease of setup and a plethora of functionality. It also means we don’t have to spend I don’t know how much more time messing with any of the official reference implementations in C++, Golang, Java, or Python.
What is Rinkeby?
I’m assuming no one reading this is filthy rich and can afford to burn actual Ethereum every time they run their Solidity app in development so we’ll be using the Rinkeby Testnet. Rinkeby is a carbon copy of the actual Ethereum network except with what is essentially Monopoly money. Once everything is up and running, we can then choose to switch to the Ethereum Mainnet.
The Setup
Before getting into Solidity, we need three things.
- Alchemy deployment key
- MetaMask Rinkeby wallet private key
- Gas
Alchemy is a middleman that tells all the miners on the Ethereum network to add your transaction (your newly minted NFT) to the blockchain and recognize that it’s legitimate.
MetaMask is the wallet you’re going to be creating your NFT from.
Gas is Monopoly money Ethereum.
Let’s start with the Alchemy deployment key. Create an Alchemy account then create a new app. The settings must lineup:
Once created, keep the key on standby. We’ll use it soon.
Step 2, MetaMask. Download MetaMask on your browser and create an account. MetaMask does not enable Testnet wallets by default. This must be changed in order to create a Rinkeby wallet. Look for the circle at the top-right corner of the MetaMask browser extension interface.
Now you can create a new wallet on the Rinkeby Network. Once created, navigate to the wallet and grab the private key. Find the pseudo-snowman icon located right below the account circle icon at the top-right corner to access the wallet settings. Icon click > Account Details > Export Private Key > Enter Password. This key is highly sensitive. Do not share it with anyone, even your cat.
We’re almost done… with the setup!!! You should now have two super secret keys on standby, now you just need gas. There are many ways to get Ethereum on the Rinkeby network, here’s one. Do what they say. If you don’t like what they say, find another site. We’ll talk again once you have Ethereum in your wallet.
What is an NFT?
An NFT is just a glorified JSON file. It’s lame. But do you know what’s not lame? Base64 encoding. Let’s talk about that! Long story short, Base64 encoding converts binary data into an ASCII format. This allows you to send data (like SVG files) though channels that wouldn’t normally support such data (like JSON files). Interesting… Let’s look at an example.
The image we are going to mint into an NFT can be seen below. It’s in the form of an SVG, or Scalable Vector Graphics file. SVG files essentially store information that describes an image in ASCII formatting. This is useful for similar reasons to those mentioned above. Let’s see this usefulness in action using Base64 encoding.
You can find the source code of the SVG file in the gist. Copy it, visit this site, paste the code, and encode it.
That output looks pretty gnarly. Here’s where the magic happens. Open a new window and paste the output with the formatting below.
data:image/svg+xml;base64,<base64 output>
Our NFT image appears!
Notice, we aren’t hosting the image anywhere. There are no 3rd party sites like Imgur, Discord, etc. that we rely on in order to access this image. All of the data needed to generate our image is in that line of text in the URL. Once converted to an NFT, the only way that this image would not be accessible is if the entire Ethereum blockchain shuts down. If that happens, we may have bigger problems.
The NFT image is set, let’s create the actual NFT JSON file. We will need to abide by OpenSea’s strict standards on how NFT metadata needs to be structured so it doesn’t break when listed. Many NFTs will have more complex structures but we’re just interested in the essentials.
{
"name": "One Verticality",
"description": "Skyward at one.",
"image": "data:image/svg+xml;base64,<base64 output>"
}
Now we’re going to redo some of the same steps. Take the completed JSON, and re-encode it.
Now we have then entire JSON encoded! You will know it worked when the JSON gets returned after searching in the URL:
data:application/json;base64,<base64 JSON output>
Let’s call this line above the Base64 encoded JSON file for future reference. Test the image again to make sure it’s correct!
You’ve just technically created an NFT. The only difference between what we just created and an actual NFT is that the actual NFT is on the blockchain with a unique identifier. Let’s do that next.
Solidity
You’re ready. You have three things with you.
- Alchemy deployment key
- MetaMask Rinkeby wallet private key
- Base64 encoded JSON file
Let’s get started.
In a new directory, install npm, Hardhat, and OpenZeppelin. Hardhat is a local Solidity runtime environment. Without Hardhat, we can’t compile. We love Hardhat. OpenZeppelin will be crucial for creating NFT contracts.
npm init -y
npm install --save-dev hardhat
npm install @openzeppelin/contracts
npx hardhat
Hardhat will give you many project initialization options, just go with the basic one.
Once the project has been initialized, run Hardhat.
npx hardhat run scripts/sample-script.js
If the output looks like this, you’re in good shape:
We’re finally going to use those secret keys. Update module.exports in hardhat.config.js to add the Rinkeby network and include both the Alchemy and Rinkeby wallet keys.
module.exports = {
solidity: "0.8.4",
networks: {
rinkeby: {
url: "<Alchemy deployment key>",
accounts: [<Metamask Rinkeby wallet key>],
},
},
};
This lets Hardhat know to use the Rinkeby network, where the source wallet is, and to hit up Alchemy for blockchain communication.
To make the NFT we need to create an NFT contract. Create a new Solidity file in /contracts called NFT.sol
Not much is going on here. When initializing the contract, we let Solidity know we are specifically creating an NFT contract (ERC721 is the Ethereum NFT standard). One of the central features of any NFT is a unique id, initialized with a 256 bit integer. Then it sets the address of the NFT’s creator (your Rinkeby wallet) and mints it. The token URI holds the NFT’s JSON along with its unique id.
Now create a deploy.js file in /scripts. The purpose of this file seems self-explanatory. We’re creating a new NFT contract and deploying it to the Rinkeby network using the Solidity NFT contract initializer we just created.
Everything should be in order. Run deploy.js.
npx hardhat run scripts/deploy.js --network rinkeby
A successful output looks like this:
The last thing to do is to check OpenSea or Rarible to make sure that the NFT minted! Because we are using a Testnet and not the Mainnet, the NFTs can be found in the Testnet sites:
- testnets.opensea.io
- rinkeby.rarible.com
Go to either site and search for that provided address from the terminal output in order to find your NFT. Know that it may take a couple minutes for your NFT to show up on either site. In my experience, Rarible is faster than OpenSea.
Well, well, well… If it isn’t our NFT…
If you’re confident enough with a final product and have the gas, you have the knowledge to switch from the Rinkeby to Ethereum Mainnet and make these NFTs legit! Just switch to the new network on Alchemy, and in hardhat.config.js, change the network, wallet address, and the run command.
The project and code this article was based off of can be found here: