# Week 14 at Blockfuse Labs: My Journey with Foundry, Building a School Management System and an NFT Marketplace
When I first heard about **Foundry**, I thought, *“Here w**Blockfuse Labs** changed that. Instead of feeling overwhelmed, I discovered how powerful Foundry is — not just for writing smart contracts, but for testing, debugging, and deploying them faster than I imagined.
This week, I built two projects that pushed me out of my comfort zone:
1. A **School Management System** smart contract.
2. An **NFT Marketplace** where people could mint, buy, and sell NFTs.
It was one of the most exciting weeks so far.
## Discovering Foundry
Foundry is like having a turbo engine for smart contract development. It comes with two main tools:
* **Forge** → for building, testing, and deploying contracts.
* **Cast** → for sending transactions and reading data from contracts.
Here are the basic commands I learned:
### Foundry Setup Commands
```bash
forge init myProject # Create a new project
forge build # Compile contracts
forge test # Run all tests
forge test -vvv # Run tests with detailed logs
forge clean # Clear build cache
forge install OpenZeppelin/openzeppelin-contracts # Install dependencies
forge update # Update dependencies
```
### Cast Commands
```bash
cast call <address> "<functionSignature>" <args> # Call a contract function
cast send <address> "<functionSignature>" <args> # Send a transaction
cast block-number # Get current block number
cast balance <address> # Get ETH balance
```
## Project 1: School Management System
I revisited the **School Management System** idea from earlier weeks but rebuilt it in Foundry.
### Features I implemented:
* **Admin** can register students.
* **Admin** can assign grades.
* Students’ data (name + grade) is stored on-chain.
### Smart Contract Example
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract School {
address public admin;
struct Student {
string name;
uint grade;
}
mapping(address => Student) public students;
constructor() {
admin = msg.sender;
}
function registerStudent(address student, string memory name) external {
require(msg.sender == admin, "Only admin can register");
students[student] = Student(name, 0);
}
function assignGrade(address student, uint grade) external {
require(msg.sender == admin, "Only admin can assign grades");
students[student].grade = grade;
}
}
```
## Writing Tests in Foundry
The beauty of Foundry is that you write tests directly in Solidity.
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "forge-std/Test.sol";
import "../src/School.sol";
contract SchoolTest is Test {
School school;
address admin = address(this);
address student = address(0xBEEF);
function setUp() public {
school = new School();
}
function testRegisterStudent() public {
school.registerStudent(student, "Alice");
(string memory name, uint grade) = school.students(student);
assertEq(name, "Alice");
assertEq(grade, 0);
}
function testOnlyAdminCanRegister() public {
vm.prank(address(0xCAFE)); // impersonate another account
vm.expectRevert();
school.registerStudent(student, "Bob");
}
}
```
### Useful Foundry Cheatcodes (via `vm`)
* `vm.prank(addr)` → impersonates another account.
* `vm.expectRevert()` → expect a function to fail.
* `vm.warp(timestamp)` → fast-forward time.
* `vm.deal(addr, amount)` → give ETH to an account.
* `vm.roll(blockNumber)` → set block number.
* `vm.snapshot()` / `vm.revert(snapshotId)` → save and restore blockchain state.
---
## Project 2: NFT Marketplace
After the school system, I built an **NFT Marketplace**.
### Features:
* Users can mint NFTs.
* Owners can list NFTs for sale.
* Buyers can purchase NFTs.
### Contract Example
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract NFTMarket is ERC721 {
uint public nextTokenId;
address public admin;
struct Listing {
uint tokenId;
uint price;
address seller;
}
mapping(uint => Listing) public listings;
constructor() ERC721("MyNFT", "MNFT") {
admin = msg.sender;
}
function mint(address to) external {
_safeMint(to, nextTokenId);
nextTokenId++;
}
function list(uint tokenId, uint price) external {
require(ownerOf(tokenId) == msg.sender, "Not owner");
listings[tokenId] = Listing(tokenId, price, msg.sender);
}
function buy(uint tokenId) external payable {
Listing memory listing = listings[tokenId];
require(msg.value == listing.price, "Incorrect price");
_transfer(listing.seller, msg.sender, tokenId);
payable(listing.seller).transfer(msg.value);
delete listings[tokenId];
}
}
```
## Testing the Marketplace in Foundry
```solidity
pragma solidity ^0.8.17;
import "forge-std/Test.sol";
import "../src/NFTMarket.sol";
contract NFTMarketTest is Test {
NFTMarket market;
address alice = address(0xABCD);
address bob = address(0x1234);
function setUp() public {
market = new NFTMarket();
}
function testMintAndListNFT() public {
vm.prank(alice);
market.mint(alice);
vm.prank(alice);
market.list(0, 1 ether);
(uint tokenId, uint price, address seller) = market.listings(0);
assertEq(tokenId, 0);
assertEq(price, 1 ether);
assertEq(seller, alice);
}
function testBuyNFT() public {
vm.deal(alice, 1 ether);
vm.deal(bob, 2 ether);
vm.prank(alice);
market.mint(alice);
vm.prank(alice);
market.list(0, 1 ether);
vm.prank(bob);
market.buy{value: 1 ether}(0);
assertEq(market.ownerOf(0), bob);
}
}
```
---
## Foundry Commands I Used for This Project
Here’s the cheat sheet of commands that carried me through Week 14:
### Compilation & Testing
```bash
forge build # Compile contracts
forge test # Run tests
forge test -vvv # Run tests with detailed logs
forge test --match-test testBuyNFT # Run a single test
```
### Gas Reporting
```bash
forge test --gas-report # Run tests and show gas usage
```
### Coverage
```bash
forge coverage # Check test coverage
```
### Deployments
```bash
forge script script/Deploy.s.sol --rpc-url <RPC_URL> --private-key <KEY> --broadcast
```
### Cast Utilities
```bash
cast balance <address> # Get ETH balance
cast call <address> "ownerOf(uint256)" 0 # Read NFT owner
cast send <address> "mint(address)" <to> --private-key <KEY> --rpc-url <RPC_URL>
```
---
## Summary Of Week 14
By the end of the week, I realized:
1. **Foundry is lightning-fast** — no waiting for TypeScript, just Solidity tests running instantly.
2. **Cheatcodes give control** — I could impersonate accounts, fast-forward time, or fund wallets.
3. **Testing = confidence** — I could simulate real-world scenarios (students registering, NFTs being bought) safely.
4. **Commands matter** — Foundry’s simplicity comes from its CLI. Once you memorize `forge build`, `forge test`, and `cast call`, you feel unstoppable.
---
## Looking Ahead
Week 14 made me feel like I unlocked a new level of blockchain development. With Foundry, I don’t just write contracts — I **test them deeply**, **analyze gas usage**, and **interact with them live** using Cast.
Next, I want to try:
* **Property-based testing** (`forge fuzz`) to check random inputs.
* **Mainnet forking** (`--fork-url`) to simulate real Ethereum conditions.
For now, I’m just happy that I built a **school on-chain** and a **marketplace for NFTs** — and proved they worked, line by line, with Foundry.