Skip to main content

Smart Contract Auditing

· 4 min read
Milad

Auditing smart contracts isn’t just about finding bugs; it’s about cultivating paranoia—the healthy kind. You learn to ask: What assumptions is this code making? What happens if they break? Who gains if something goes wrong?

Here’s a peek into how I approached a sample audit, step-by-step, and turned raw code into a structured security review.

🔍 The Setup

I picked a simple ERC20-based Solidity contract with added features like admin roles, fee extraction, and pause/resume control. My goal: audit it as if it were a production system holding real funds.


🛠️ My Process

1. High-level Threat Modeling

Before touching the code, I created a mental model:

  • Actors: owner, regular users, attacker, smart contract bots
  • Assets: user balances, contract funds, admin privileges
  • Goals: for each actor (e.g., attacker wants to drain funds or hijack control)

Then I asked:

If I were malicious, how would I break the game?

This mindset helped me focus on areas where incentives and permissions collide.


2. Manual Code Review

I reviewed the contract line by line with attention to:

  • Access Control: are modifiers (onlyOwner, etc.) applied correctly?
  • State Changes: can anyone trigger them? Can they be re-triggered?
  • ERC20 Conformance: does it implement the spec safely?
  • Gas Griefing: can a user cause another to revert unexpectedly?
  • Math Safety: overflows, underflows, division by zero (yes, even in 0.8.x)

I used no tools at this point. Just reading, annotating, and questioning.


3. Behavioral Edge Cases

I crafted test scenarios in my head and wrote them down:

  • What happens if I call pause() then transfer()?
  • What if transfer() emits but doesn’t update state?
  • What if _msgSender() is a contract?

In particular, I challenged:

  • Implicit trust in msg.sender
  • Assumptions about token decimals or balances
  • ERC20 event emission being “proof” of transfer

4. Write the Audit Report

A clear report matters more than a clever attack. I structured mine like this:

Overview

  • Summary of what the contract does and key design goals.

Findings

  • List of vulnerabilities (High / Medium / Low / Info)
  • Code references (line numbers, functions)
  • Impact + exploitation scenario
  • Suggested fix (code or logic)

Design Notes

  • Commentary on tradeoffs, gas usage, or unnecessary complexity.

This gave the developer something actionable; not just criticism, but clarity.


What I Learned

  • Auditing is not testing; it's reasoning under uncertainty.
  • Don’t trust the happy path; always ask: What if the world is hostile?
  • A clean report = one that improves the code and the developer.

Also, writing the report taught me something deeper: being useful as an auditor isn’t just about spotting edge cases; it’s about translating risk into human language.


Don't worry if the process feels overwhelming. Focus on understanding:

  • Why each function exists
  • Who can call it
  • What can go wrong if it’s misused

Start by reading well-audited contracts like OpenZeppelin’s and look for patterns.


Final Thought

Auditing is like cold reading a novel and finding plot holes before it hits the shelves. You’re not the author; you’re the guardian of trust. The work is never done, but each review makes the system a little safer.

Further Reading