Track 4 · Solidity foundations · lesson 15
Milestone: the piggy bank
25 min
No new concepts. Everything below is something you have already done — this time all at once, with no worked example in front of you.
The brief
A contract that holds ETH for people:
- Anyone can deposit, and their balance is tracked.
- Only the owner can withdraw, and only what they put in.
- Both actions emit an event.
- A stranger's withdrawal reverts with
NotOwner. - Withdrawing more than you have reverts with
InsufficientBalance.
Twelve tests. The state variables, events and errors are already declared — you are writing two function bodies.
Nudge
Show me the approach
Show me the code
Explain the solution
One thing worth getting right
The order of operations inside withdraw matters more than anything else on
this page.
Checks, effects, interactions.
- Check the caller is allowed and the balance is sufficient.
- Update the balance.
- Send the ETH.
Sending before subtracting leaves a window where the recipient can call
withdraw again while their balance still reads full. That is reentrancy, and
it took $60 million out of The DAO.
Track 7 opens with a vault that gets this backwards, and asks you to empty it.
Check
Why send the ETH last rather than first?
What you have actually learnedOptional
This contract is a small version of something real. Strip the owner check and you have the deposit half of a lending protocol. Add interest and you have a vault. Swap ETH for a token and you have a staking contract.
The patterns are the same at every scale:
- a mapping of address to amount
- events so the outside world can follow along
- custom errors for cheap, specific failures
- checks-effects-interactions around anything that leaves the contract
Track 5 takes the same shape and turns it into a token that anyone can hold.
Worth remembering
- State, events and errors are declared at contract level; logic goes in the functions.
- Guard first, mutate second, call out last — checks-effects-interactions.
- `payable(addr).call{value: x}("")` is the way to send ETH, and its result must be checked.
- Custom errors give callers a specific reason for far less gas than a string.
- This contract's shape underlies vaults, staking and lending protocols.