← BlogSmart Contracts

Smart Contract Security Checklist: 15 Checks Before You Deploy to Mainnet

Deployed contracts are hard to fix and easy to drain. A practical checklist covering access control, reentrancy, testing, upgrades and launch-day operations.

EA

Emmanuel Oluwaseun Akinloye

Founder, EmmaForYou

Oct 13, 2026·📖 10 min read

The problem: bugs on a blockchain are permanent and public

A bug in a normal app is embarrassing. A bug in a smart contract can be catastrophic. Contracts often hold real value, the code is public for attackers to study, and once deployed it usually can't be patched like a website.

Most exploits aren't exotic. They come from a short list of well-known mistakes. Work through this checklist before mainnet.

Design and access

1. Write the specification first

List every function, who may call it, and what must always be true (for example, "total supply never exceeds X"). Bugs hide in the gap between what you meant and what you wrote.

2. Lock down admin functions

Minting, pausing, upgrading, withdrawing treasury funds and changing owners must be restricted with access control, such as OpenZeppelin's Ownable or AccessControl. Test that other accounts are rejected.

3. Put admin keys behind a multisig

A single private key controlling a contract is a single point of failure. Use a multisig wallet and, where possible, a timelock on sensitive changes.

4. Use battle-tested libraries

Don't write your own token or access-control logic. OpenZeppelin's contracts have been reviewed and used far more widely than anything written from scratch.

Common vulnerabilities

5. Reentrancy

If your contract sends ETH or calls another contract before updating its own state, an attacker can call back in and repeat the action. Update state first (checks-effects-interactions) and add a reentrancy guard.

6. Authorisation with tx.origin

Use msg.sender for authorisation, never tx.origin.

7. Unchecked external calls

Low-level calls return a success flag. Check it, and assume any external contract can behave maliciously.

8. On-chain randomness

Block timestamps and hashes can be predicted or influenced. Use a verifiable randomness source such as Chainlink VRF for anything that needs to be fair.

9. Price oracles

Prices taken from a single liquidity pool can be manipulated within one transaction. Use robust oracles and sanity checks.

10. Arithmetic and rounding

Solidity 0.8+ checks overflow, but rounding in division can still leak value over many transactions. Test the edge cases.

Testing and review

11. Unit, fuzz and invariant tests

Unit tests check what you expect. Fuzz and invariant tests (Foundry makes them easy) throw thousands of random inputs at your contract to find what you didn't expect.

12. Static analysis

Tools such as Slither catch many common issues automatically. Run them and read every warning.

13. An independent review

The person who wrote the code is the worst person to review it. Get a second developer to read it line by line and, for contracts holding significant value, an independent audit firm.

Launch

14. Rehearse on a testnet

Deploy the exact build, run every function, and simulate admin operations before mainnet.

15. Verify, monitor and plan for incidents

Verify source code on the block explorer, set up monitoring and alerts, and write down what you'll do if something goes wrong, including who can pause the contract.

How EmmaForYou helps

Our smart contracts and Solidity service covers specification, implementation with OpenZeppelin, unit, fuzz and invariant testing, static analysis, manual review and deployment with multisig ownership. If you're heading for a formal audit, we'll prepare you for it and fix the findings.

Free tool

Free smart contract check

Paste Solidity code and get findings ranked by severity, each with a fix.

Try it free →

Want us to do this for you?

We help businesses across 3 continents implement everything you just read — and a lot more.