Write real Solidity and watch it compile as you type. Storage slots appear beside your variables, and you can drag through a run backwards to see exactly what changed.
You can write a contract that keeps a balance per address, groups related facts into records, refuses the callers it should refuse, holds real AVAX and lets it back out, calls other contracts through an interface, and costs two storage slots instead of three.
Declare one variable and watch a storage slot appear beside you. That slot is the whole idea.
Storage is where things stand. Events are how anyone finds out they changed.
A rejected transaction leaves no trace on state. Watch a whole call undo itself.
A single total cannot say who owns what. A mapping can, and it is the first thing that stops looking like a normal variable.
Every public function is callable by anyone on earth until you say otherwise. Here is how you say otherwise, and how to stop repeating yourself.
A revert string is stored in your contract forever and charged for at deploy. A custom error says the same thing, carries more, and costs less.
Until now your contract has only counted. This one holds real AVAX, and getting it back out is the part people get wrong.
A mapping gives every address a number. Sooner or later you need two, and adding a second mapping is how contracts drift out of sync.
A mapping cannot be counted or listed. An array can be both, and that convenience is the one that later costs you the most gas.
You have now written the same owner check twice. The third time is when you move it somewhere both contracts can reach it.
Three numbers can cost three storage slots or two, and the only difference is the width and the order you wrote them in. The grid counts them for you.
Almost nothing on Avalanche is one contract. An interface is how yours calls something already deployed, without holding a copy of its code.