One rule
Assume every public or external function will be called by a stranger, a bot, or another contract. Write the function so it is still safe.
A safer contract checks first, updates its own state second, and talks to other contracts last. This is Checks-Effects-Interactions.
Public means public
Do not store secrets in a contract. Private variables are not secret. Local variables are not secret either. Anyone can inspect contract data on-chain.
Use Solidity 0.8.x arithmetic checks. Do not add unchecked blocks unless you can explain why wrapping is safe.
Bad authorisation
Never use tx.origin to decide who is allowed to do something. A phishing contract can trick the original wallet into calling through it.
Use msg.sender-style checks, a clear owner variable, or a reviewed library such as OpenZeppelin Ownable installed from the package. Do not copy-paste library source into your repo.
Safer withdrawal
This shape is better than pushing Ether to users inside a loop. Each user withdraws their own balance.
The important part is order: check amount, set balance to zero, then make the external call.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract PrizeVault {
mapping(address => uint256) public winnings;
error NothingToWithdraw();
error TransferFailed();
function claim() external {
uint256 amount = winnings[msg.sender];
if (amount == 0) revert NothingToWithdraw();
winnings[msg.sender] = 0;
(bool ok, ) = msg.sender.call{value: amount}("");
if (!ok) revert TransferFailed();
}
}Watch external calls
Any Ether transfer or call to another contract hands control away. That other contract may call you back before your first function finishes.
For simple projects, avoid complex cross-contract calls. If you must use them, keep the contract small, test the failure path, and consider ReentrancyGuard from OpenZeppelin Contracts 5.x.
Unbounded loops
A loop over a storage array can work in your test with 3 users and fail later with 3,000 users. If the loop needs more gas than a block allows, the function can become unusable.
Do not write one admin function that pays every participant, deletes every record, or recalculates every score. Prefer per-user actions, pagination, or fixed-size limits.
Security notes file
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done
Do this now
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done