I worked through all 16 NEAR exercises. Here's what actually stuck.
I've been deep in DeFi infrastructure for a while now. And the thing I keep running into, whether it's smart contract bugs or bad architecture decisions is that most developers skip the fundamentals. They copy-paste, skim docs, and hope their contract doesn't get exploited.
I went through the full NEARbyExample track not to rush a checklist, but to actually understand how NEAR contracts behave reads vs writes, storage patterns, permission design, and upgrade strategies. 9 basics. 7 advanced. Every solution typed by hand.
This is what I found.
The 9 basics
The basics look simple on the surface. Don't be fooled. Each one introduces a concept that will bite you in production if you don't understand it properly.
Exercises 1–2: Greeting + Contract Structure
Your first real lesson: who called this function matters. predecessorAccountId() is how you gate writes. Owner-controlled functions aren't optional, they're the foundation of any secure contract. Deployment identity and caller identity are two different things. Know both.
Exercises 3–4: View vs Change Methods
Views don't cost gas for the caller. Changes do. This distinction shapes everything your UX, your architecture, how frequently your frontend polls state. Every product flow should batch work and avoid noisy updates.
Exercise 5: State Management
On-chain state outlives every single transaction. Design around explicit transitions. There's no garbage collection, no implicit reset. Whatever you store stays so be intentional about what you're storing and when.
Exercises 6–7: Input Validation + Error Handling
Arguments cross a trust boundary. Validate before they touch storage. Use recoverable returns when the caller can adjust; panic() only when continuing would corrupt state or funds. Fail loud, fail early.
Exercises 8–9: Vectors + Maps
On-chain collections aren't free arrays. They have storage prefixes, cost profiles, and iterator limits. swap_remove is not a casual splice. Maps are the default shape for account-keyed data like balances, settings, leaderboards.
The basics module is really one lesson: understand what you're paying for. Every read, write, and storage operation has a cost. Good contract design minimises unnecessary state and batches work intelligently.
The 7 advanced
This is where NEARbyExample stops being tutorial territory and starts being production prep. These patterns separate amateur contracts from deployed infrastructure.
Exercise 10: Map Leaderboard
Full sorts in a view are fine at small scale. In production, you plan for iterator cost and query frequency. Think before you sort on-chain.
Exercise 11: Events
Structured NEP-297 logs are how your contract communicates with UIs and indexers. The contract doesn't push to your frontend, your frontend listens. Critical for transaction tracking, notifications, and analytics. If you're not emitting events on state-changing methods, your frontend is flying blind.
Exercises 12–13: Owner + Role-Based Access
Single owner is the baseline. Layered roles — owners, admins — map directly to teams and DAOs. Access checks live next to entry points, not in some centralised validator. This is the pattern behind every serious multi-team protocol.
Exercise 14: Pausable Contract
A circuit breaker on writes limits damage during incidents while keeping reads available for monitoring. This is not optional for any contract holding real value. When something goes wrong on mainnet, you want this lever.
Exercise 15: Multi-Signature
Threshold approvals before execution. Single-key risk on treasury operations is unacceptable. Multisig is how you remove that single point of failure which is essential for DAOs, shared wallets, and any high-impact callable.
Exercise 16: Upgrade Pattern
Deployed bytecode is fixed. Migrations bridge one stored schema to the next. Rust and JavaScript diverge here Rust uses #[init(ignore_state)], JS uses explicit reset and wiring. Know which track you're on before you design your schema, because migration debt compounds fast.
Three things I actually took away
1. Permissions are the product
If your admin paths are wide open, nothing else you build matters. The permission layer isn't an afterthought, it's the first thing you design. Every contract I've seen fail in the wild failed because someone skipped this step.
2. Storage design determines everything downstream
How you store state : maps vs vectors, versioning strategy, collection prefixes drives your gas costs, your upgrade complexity, and what your frontend can query cheaply. This is architecture, not implementation detail. Get it wrong early and you'll pay for it at migration time.
3. Upgrades are doable but brittle
You can upgrade NEAR contracts. But Rust and JavaScript diverge exactly when you touch lifecycle hooks, and migrations that seem straightforward will break if your stored schema drifts. Plan your data model before you ship.
Go build
Start at near.peersurf.xyz. Type every solution yourself. Run the tests. The goal isn't to get through the exercises, it's to understand what you're actually paying for when a function runs on-chain.
The arc from exercise 1 to exercise 16 is really about learning how much careful design sits behind a small public API. That understanding is what separates builders who ship safe contracts from those who don't.
Find me at @zedonchain_
