> For the complete documentation index, see [llms.txt](https://blockchain-journal-hope-mabuza.gitbook.io/blockchain-journal-hope-mabuza-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blockchain-journal-hope-mabuza.gitbook.io/blockchain-journal-hope-mabuza-docs/smart-contracts/week-6-upgradable-smart-contracts-nft-minting.md).

# Week 6: Upgradable Smart Contracts – NFT Minting

#### Day 36 <a href="#day-36" id="day-36"></a>

**Building on Last Week and Looking Ahead**

* Last week I focused on mastering the architecture behind contract flexibility, specifically diving into UUPS and Transparent Proxy patterns. Understanding how to separate logic from state was a major milestone, but the real breakthrough was learning to navigate storage collisions. Gaining a solid handle on solutions like storage gaps has given me the confidence to ensure data integrity during contract evolution.
* I am now looking forward to applying these patterns in a more practical way. My primary focus this week will be on upgradable NFTs, with the goal of developing assets that can seamlessly integrate new features and functionality long after their initial deployment.

***

#### Day 37 <a href="#day-37" id="day-37"></a>

**Exercise 6.1, Building a Base Upgradable NFT**

* Today I worked on Exercise 6.1, where I had to build a base ERC-721 NFT contract using the UUPS proxy pattern. Just like with the ERC-20 I did earlier, I had to swap out the constructor for an `initialize()` function and make sure all the OpenZeppelin imports were the upgradeable versions.
* I ran into a small detail with the `mint()` function, I had to make sure it was access controlled so that not just anyone could trigger a mint. I used the `onlyOwner` modifier to keep it secure. I also made sure to include a `uint256[50] __gap;` in the state variables. Even though I don't need it right now, I know from last week that it's a best practice to reserve that space so I don't run into storage collisions when I upgrade to V2 later this week.
* After deploying the proxy and the implementation to Sepolia, it's becoming much clearer how the proxy holds the state while the implementation just holds the logic.

**Deployment addresses:**

* Proxy: `0x501Dea141D901A7efEC18990aB4949c998fc134E`
* Implementation: `0x2d296D060175fD2932Cba4D90b3af04b1f8C8C34`

***

#### Day 38 <a href="#day-38" id="day-38"></a>

**The Real Responsibility of Upgrading Live Contracts**

* Today I reflected on the safety measures that are actually necessary when you're upgrading live contracts. It's one thing to upgrade locally, but doing it with real user assets on the line is a whole different level of responsibility.
* The biggest technical priority is always avoiding storage collisions. I've learned that you have to be extremely careful with the storage layout, if you change the order of variables or accidentally overwrite a slot, you can easily brick the entire contract. Using storage gaps like `uint256[50] __gap;` is a must because it reserves space for future features without messing up the current state. I also rely on the OpenZeppelin Upgrades plugin to run automated checks before I even think about deploying an upgrade.
* Beyond the code, I realised that protecting the upgrade trigger is just as important. You can't just leave that power to a single private key. Using a Multi-Sig wallet and adding a Timelock are essential safety steps. It gives users time to see what's changing and ensures that no single point of failure can compromise the project. Safe upgrades aren't just about new code, they're about protecting the users' state and trust.

***

#### Day 39 <a href="#day-39" id="day-39"></a>

**Exercise 6.2, Adding Supply Caps, an Allowlist and Royalties**

* Today I worked on Exercise 6.2, which involved taking the base NFT contract and turning it into an Advanced Upgradable Minter. The goal was to add functional constraints like a maximum supply and an allowlist, while also handling a live upgrade to add royalty support.
* I refactored the logic to include a `MAX_SUPPLY` limit and a mapping for the `allowlist` to control who can mint. Just like with the previous exercise, it was important to keep the `uint256[50] __gap;` at the top of the state variables to make sure adding the new variables didn't cause any storage collisions when moving from V1 to V2.
* The upgrade to V2 added royalty support through EIP-2981. Royalties mean that every time an NFT is resold on a secondary market, a percentage automatically goes back to the original creator. It's built into the contract itself rather than depending on a marketplace to honour it, which makes it far more reliable. After deploying the new logic to Sepolia and pointing the proxy to the new address, everything worked with the original state fully intact.

**Deployment and Upgrade Details:**

* Proxy Address: `0x501Dea141D901A7efEC18990aB4949c998fc134E`
* V2 Implementation: `0xE8A363C67D04aE4fA718D1ee7dB50F0bE47c9554`
* Upgrade Tx Hash: `0x6028be1a0cc6593332785399dc527c41782657748a77fb92b92c32fc240b8e0f`

**Updated Functionality:**

* Max Supply: Capped at 10,000.
* Allowlist: Restricted minting access.
* Royalties: 5% fee support added via EIP-2981.

***

#### Day 40 <a href="#day-40" id="day-40"></a>

**Polishing, Testing and Wrapping Up the Project**

* Today I was polishing the previous exercise and making sure everything was ready for the repository submission. The main focus was writing comprehensive unit tests to cover the new features. It was important to test that the `MAX_SUPPLY` actually blocked minting once the limit was reached and that only addresses on the `allowlist` could access the mint function. I also wrote a test case for the upgrade itself, verifying that the royalty functions from V2 were accessible through the existing proxy address without losing any of the V1 state.
* The README was updated to document the full upgrade journey from the initial base ERC-721 to the final version with EIP-2981 support. Including the deployment addresses and the upgrade transaction hash was a key part of showing how the UUPS pattern handled the transition on Sepolia.
* Looking back at the week, this was the most complete project I have built so far. It had a real upgrade path, access control, supply constraints, royalties and proper test coverage. A few weeks ago I wouldn't have known where to start with any of that.

**Submission Details:**

* Testing: Coverage for Access Control, Supply Caps, and Royalties.
* Proxy Address: `0x501Dea141D901A7efEC18990aB4949c998fc134E`
* Final Implementation (V2): `0xE8A363C67D04aE4fA718D1ee7dB50F0bE47c9554`

***

#### Day 41 (ABC) <a href="#day-41-abc" id="day-41-abc"></a>

**Back to Basics With a Voting System**

* At ABC, the focus was on a revision of Solidity syntax by building a simple voting system contract. It was a good way to reinforce the basics like `structs`, `mappings`, and `arrays` after focusing so much on advanced proxy patterns earlier in the week.
* The contract was designed to handle a list of candidates and allow addresses to cast a single vote. The logic included a check to prevent double voting, which was handled using a `mapping(address => bool)`. A `struct` was also used to store each candidate's name and their current `voteCount`.
* It was a helpful exercise to get back to the core syntax and make sure the logic for iterating through candidates and updating state was gas-efficient. Even though it was a simpler project compared to the UUPS NFT, it was a solid reminder of how important clean, readable code is for basic smart contract functionality.

**Key Syntax Covered:**

* Structs: To define the Candidate objects.
* Mappings: To track voter status and prevent duplicates.
* Functions: Implementing `view` functions to check results without gas.

***
