$ solidity lab

A public build log. I'm learning how smart contracts actually work by writing, testing, and deploying one small contract at a time, working up a seven-project ladder from a piggy bank to a toy stablecoin. Everything runs on testnets with fake money.

Neil Patel · started 2026-07-27 · built with Foundry on Base Sepolia · code on GitHub

The ladder

1. PiggyBankdeposits, withdrawals, ownership, events
2. ERC-20 tokenthe token standard, allowances, OpenZeppelin
3. Token faucetrate limits, pull vs push payments
4. Escrowstate machines, reentrancy, holding USDC
5. Payment splitterrevenue shares, pull-payment accounting
6. 2-of-3 multisigcontract wallets, low-level call
7. Toy stablecoinoracles, collateral, liquidations

Build log · newest first

2026-07-27 session 1 1. PiggyBank

Setup + first contract: PiggyBank

What we did

  • Installed Foundry 1.7.1 (forge, cast, anvil) via Homebrew
  • Scaffolded the repo with forge init
  • Wrote PiggyBank.sol: anyone deposits ETH, only the owner withdraws
  • Wrote 8 Foundry tests in Solidity, all passing, including a fuzz test that hit the contract with 256 random deposit amounts
  • Generated a fresh testnet-only wallet with cast wallet new
  • Spun up anvil (local chain, unlimited fake ETH) and deployed PiggyBank with forge create
  • Ran the full lifecycle from the terminal with cast: a stranger deposited 1 ETH, the stranger's withdrawal attempt reverted with NotOwner, the owner wallet withdrew everything

What I learned

  • msg.sender and msg.value: who is calling and how much ETH they attached
  • All amounts are in wei (1 ETH = 1e18 wei); there are no decimals on chain
  • payable, receive(), and why plain transfers revert without them
  • Modifiers as reusable access-control guards (onlyOwner)
  • Events are the contract's only output; indexers and dashboards live on them
  • Custom errors are cheaper than require strings and show up in traces
  • Send ETH with low-level call, not transfer (the 2300 gas stipend problem)
  • Fuzz testing: assert a property for all inputs, not one example
  • A deployed contract is forever; the rules at deploy time are the rules

Next up

  • Fund the testnet wallet from a Base Sepolia faucet
  • Deploy PiggyBank to Base Sepolia and verify it on a public explorer
  • Start project 2: write an ERC-20 token from scratch