Road to Web3 — Develop NFT contract — Reflection

5 min readNov 25, 2022


To continue my learning journey, I have decided to join Alchemy University. The first course I selected is titled Road to Web 3. My goal is to understand more about how to develop web3 applications, and more specifically to gain more understanding about developing various types of Ethereum contracts.

For the first week we were challenged to create and deploy an NFT contract.

The platforms we used to accomplish this were;

Using OpenZeppelin, I was able to generate base-level code for an ERC721 contract in a wizard type interface. Within the wizard I was able toggle On/Off different features of the contract including to allow minting, burning, URI storage, and to auto increment ID’s. Toggling these features would add code in the form of functions or objects to the contract.

The Mintable toggle added a function titled safeMint, and auto-increment added a _tokenIDCounter object. There were other functions created but we focused mostly on this section in the next step.

// Auto increment
using Counters for Counters.Counter;

Counters.Counter private _tokenIdCounter;

// Mintable
function safeMint(address to, string memory uri) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);

The next step was to take the auto-generated code from the wizard and transfer it to an IDE where we would modify it slightly and finally deploy it on-chain. The transfer between OpenZeppelin and Remix IDE was seamless using an Open in Remix button located in the OpenZeppelin wizard.

After relocating the contract to Remix, we made some minor modifications to the code. The modifications included removing onlyOwner from the safeMint function so that any address could call the function, and including a MAX_SUPPLY variable that limited the amount of tokens that could be minted.

using Counters for Counters.Counter;

Counters.Counter private _tokenIdCounter;
// Add MAX_SUPPLY to limit qty
uint256 MAX_SUPPLY = 100000;

constructor() ERC721("Titus", "TTS") {}

// function safeMint(address to, string memory uri) public onlyOwner {
// remove onlyOwner to allow different addresses to mint
function safeMint(address to, string memory uri) public {
// Check if the counter is less than max supply
require(_tokenIdCounter.current() <= MAX_SUPPLY, "I'm sorry we reached the cap");
uint256 tokenId = _tokenIdCounter.current();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);

Once, the changes to the code were complete the next step was to compile and deploy the contract.

The Remix IDE has a built in compiler and the process of compiling was as simple as selecting the Compile button. I did not have any errors during compiling, but this is the step where any errors related to the modifications above would have appeared.

To deploy the contract, we first had to point Metamask to the Goerli testnet and then get some GoerliETH added to our wallet. To point Metamask at the Goerli network we had to add the chain using details from our Alchemy account RPC URL and chainID = 5. To get GoerliETH, Alchemy provided a URL to a faucet where we simply had to enter our wallet address and the GoerliETH was automatically sent.

To deploy the contract there is a Deploy & Run section of Remix. When you enter this section, the compiled contract from the previous step is automatically visible in a drop down with a Deploy button directly below it. There are a few settings available to adjust but the only one we were required to change was switching the environment to Injected provider — Metamask. Hitting the Deploy button initiated a Metamask transaction which once approved and processed deployed the contract to the chain.

After the contract was deployed, we shifted to learning about how NFT metadata works. The metadata for an NFT contains all of the information about the NFT including the name, description, attributes, and most importantly the URL of the related image. The metadata is stored in JSON format.

"description": "This NFT proves I've created and deployed my first ERC20 smart contract on Goerli with Alchemy Road to Web3",
"external_url": "",
"image": "",
"name": "A cool NFT",
"attributes": [
"trait_type": "Base",
"value": "Starfish"

In order for the metadata and resulting image to be available to any downstream application we had to publish the information on IPFS using Filebase. With Filebase, we first uploaded the image we wanted our NFT to represent. Once uploaded this image was assigned a unique URL, which we copied to the metadata.json file following “image”. After adding the image URL to the metadata file, we also uploaded metadata.json to IPFS. After uploaded, just like the image file, the metadata file was assigned a unique CID which we converted to URL format like ipfs:\\<CID>.

Now that our image and metadata were available it was now time to mint an NFT. To perform the mint, we headed back to Remix and again to the Deploy and Transact section.

After the contract was deployed, it was present in the Deployed Contracts section of Remix. Below the contract all of the functions were listed with input boxes where you could enter the arguments needed for the function and a Transact button.

Expanding the safeMint function unveiled two inputs, Address and URI. For the address, I entered my wallet address, and for the URI box I input the ipfs:\\<CID> URL for the metadata.json file. After inputting the data, I selected Transact. My transaction was then pushed to Metamask where I had to sign it and then wait for processing.

After the transaction had processed we were directed to the test Opensea application where viewing our profile confirmed that we had successfully minted the NFT. The details and image matched both the metadata and image that we had uploaded to IPFS. 🎉

Key lessons learned;

  • Base level contracts are already available on OpenZeppelin. You do not need to start from scratch.
  • Remix is an IDE where you can write, deploy, and interact with contracts.
  • NFT data can be stored on IPFS, and Filebase is an easy portal to upload this information.

Some questions I had;

  • How do I pull an already deployed contract into Remix? Once my session refreshed my previous work was lost and nothing showed up under Deployed Contracts.
  • Is it possible to change the metadata or image AFTER the mint process has completed? I assume the image can change, but the metadata can not. Is this how projects do “reveal” functionality where the images appear weeks AFTER the mint has passed.
  • If you had 500 NFT’s would each NFT need it’s own metadata file?