All Things Web3 Logo

Initializing...

Back to Resources
SecurityFebruary 1, 202519 min readBy Lozz

Smart Contract Audit Checklist: What We Actually Look For After Securing $5M+ in Assets

TL;DR

  • Testing matters more than auditing. Write tests for everything. That's the expensive part.
  • External audits miss things. We've paid $15K for audits that missed critical bugs.
  • Basic tokens don't need audits. Save your money.
  • Upgradeability has saved projects millions. Don't dismiss it.
  • Most audit companies are scams. They outsource to AI or offshore devs.
  • The real cost: Proper testing and review costs $5K-30K depending on complexity.

After securing over $5M in assets across 100+ smart contracts, from simple tokens to complex DeFi protocols, we've learned one thing: the audit isn't what saves you. The testing is.

Most guides tell you to hire an auditor and call it done. That's terrible advice.

Here's what actually matters in smart contract security, including the things auditors won't tell you.


The Hard Truth About Audits

Let's start with something most devs won't admit: we've paid external auditors $15K+ who missed critical exploits that we later caught ourselves.

Example: We paid a well-known audit company to review a staking contract. They gave us the all-clear. Clean report. No critical issues.

One month after launch, we discovered the rewards calculation could be exploited. An attacker could've drained the entire rewards pool. The auditor completely missed it.

We caught it during our own post-launch monitoring, patched via upgrade (thank god for upgradeability), and migrated users before any funds were lost.

The lesson: External audits give you an extra set of eyeballs, but they're not a silver bullet. Your own testing matters more.


When You Actually Need an Audit

Skip the audit for:

  • Basic ERC-20 tokens with no custom logic
  • Copied code from verified, battle-tested contracts
  • Low-value experiments (under $50K TVL expected)
  • Launchpad tokens using standard templates

Why? You're paying $8K-15K to audit code that's already been audited thousands of times. Waste of money.

Get an audit for:

  • Custom tokenomics (tax logic, reflection, rebasing)
  • DeFi protocols (staking, yield, LP management)
  • Anything holding user funds over $100K
  • Upgradeability logic (proxy patterns, admin functions)
  • Complex integrations with other protocols

The rule: The more complexity, the more you need external review. Simple token? Skip it. Multi-contract DeFi system? Get multiple audits.


What We Actually Check (The Real Checklist)

This is our internal audit process before launching any contract. If you follow this, you'll catch 90% of issues before paying an auditor.

Phase 1: Test-Driven Development (The Foundation)

This is the most important and most overlooked part.

Amateur developers write code first, then write tests. That's backwards.

Our process:

  1. Write the test for the feature first
  2. Watch it fail
  3. Write the code to make it pass
  4. Refactor and optimize
  5. Repeat

Why this matters: You can't skip testing to save time. You end up paying 10x more fixing exploits later.

Real example: A project we inherited had zero tests. Just deployed code that "seemed to work." We found 7 critical vulnerabilities in the first hour of review. Cost them $20K to fix and redeploy everything.

Time investment: Testing takes 40-60% of development time. It's the expensive part. But it's also what keeps your project alive.

Phase 2: Edge Case Testing (Where AI Helps Now)

With AI, this has gotten 3-5x faster.

We use AI (Claude, GPT-4) to generate edge case scenarios we might not think of:

"What happens if..."

  • User tries to stake 0 tokens?
  • Contract receives ETH it doesn't expect?
  • Same user calls function twice in same block?
  • Someone sends tokens directly to contract address?
  • Gas price spikes to 500 gwei mid-transaction?
  • User approves max uint256 then revokes?

The goal: Break your own contract before someone else does.

We write tests for every edge case. Yes, every single one. This is what takes time and costs money.

Phase 3: Third-Party Dependencies (The Hidden Danger)

This is where even careful devs get burned.

We lost $20K once because of a bug in Uniswap V2 contracts that we didn't know about. Our code was perfect. Our tests passed. The exploit was in the LP contract we integrated with.

The vulnerability: Uniswap V2 pairs can be manipulated to cause LP imbalances under specific conditions. The exploiter knew about it. We didn't. They drained our liquidity.

Lesson learned: Test your integrations as thoroughly as your own code.

What we check now:

  • Is the third-party contract verified and audited?
  • Has it been exploited before?
  • Are there known issues in their GitHub?
  • Do we understand every function we're calling?
  • What happens if their contract is compromised?
  • Can we pause our integration if needed?

Common risky dependencies:

  • Uniswap / Sushiswap LP contracts
  • Oracle integrations (Chainlink, etc.)
  • Wrapped tokens (WETH, etc.)
  • Proxy/implementation patterns from other projects

Don't trust, verify. Even battle-tested code has edge cases.

Phase 4: Access Control & Ownership

This is where 30% of hacks happen.

Critical checks:

  1. Who can call admin functions?
  2. Is ownership renounced too early? (Can't fix bugs)
  3. Is ownership renounced too late? (Rug risk)
  4. Are there hidden backdoors in "safe" functions?
  5. Can ownership be transferred accidentally?

Our recommendation: Use a Safe (Gnosis Safe) instead of EOA ownership.

Why?

  • EOA gets compromised → Hacker owns your contract
  • Safe gets compromised → Need 2-3 signatures, much harder
  • Safe has transaction queueing (you can see malicious txns before execution)
  • Safe can have multiple owners (distribute risk)

Real example: A project we consulted for had their deployer wallet compromised. Hacker immediately called transferOwnership() and bricked the contract. Game over.

If they'd used a Safe with 2-of-3 multisig? Hacker would've needed to compromise 2 wallets. Way harder.

Cost difference: Zero. Deploying through a Safe costs the same as EOA. No excuse not to do this.

Phase 5: Reentrancy & State Management

The classic vulnerability that still gets people.

What is reentrancy?
Contract A calls Contract B → Contract B calls back to Contract A before first call finishes → Contract A's state is outdated → Exploit.

Famous example: The DAO hack (2016) that stole $50M+ and led to Ethereum hard fork.

How we prevent it:

  1. Checks-Effects-Interactions pattern (always)
  2. ReentrancyGuard from OpenZeppelin (for external calls)
  3. State updates BEFORE external calls
  4. Never trust external contracts

Test every external call:

// Bad (vulnerable)
function withdraw() external {
    uint256 amount = balances[msg.sender];
    (bool success,) = msg.sender.call{value: amount}("");
    require(success);
    balances[msg.sender] = 0; // State update AFTER external call
}

// Good (safe)
function withdraw() external nonReentrant {
    uint256 amount = balances[msg.sender];
    balances[msg.sender] = 0; // State update FIRST
    (bool success,) = msg.sender.call{value: amount}("");
    require(success);
}

Write tests that attempt reentrancy. If they succeed, you have a bug.

Phase 6: Integer Overflow/Underflow

Less of an issue in Solidity 0.8+ (has built-in overflow checks), but still worth understanding.

What to check:

  • Are you using older Solidity? (Upgrade to 0.8.x)
  • Do you have unchecked blocks? (Review them carefully)
  • Are math operations safe in all edge cases?
  • Can user input cause unexpected overflow?

Common mistake:

uint256 reward = (amount * rewardRate) / 1000;

If amount * rewardRate overflows before division, you get wrong result. Even with 0.8.x checks, this fails silently in unchecked blocks.

Better:

uint256 reward = (amount / 1000) * rewardRate;

Order of operations matters.

Phase 7: Front-Running & MEV

If your contract has economic incentives, it WILL be front-run.

Common targets:

  • Liquidation functions
  • Arbitrage opportunities
  • Mint/claim functions with profit
  • Governance votes (yes, these get front-run)

How we mitigate:

  1. Commit-reveal schemes (for sensitive operations)
  2. Batch processing (harder to front-run)
  3. Time delays (reduce profitability)
  4. Off-chain signatures (verify off-chain, execute on-chain)

Real example from token launches: We implemented commit-reveal for fair launch claims. Users commit their claim first (hash only), then reveal after block confirmation. Result: Zero front-running, fair distribution.

Without this? Bots would've claimed 40-60% of supply in first block.

Phase 8: Gas Optimization (The Overlooked $$$)

Gas savings add up to tens or hundreds of thousands of dollars over a contract's lifetime.

We use Solady by Vectorized (the most gas-optimized Solidity library) for common patterns.

Quick wins:

  • Use uint256 instead of smaller types (costs more to pack/unpack)
  • Cache storage variables in memory
  • Use calldata instead of memory for function params
  • Batch operations when possible
  • Use events instead of storage for historical data

Real example: We optimized a staking contract's claim() function from 180K gas to 95K gas. With 10K claims per month at 50 gwei, that's $4,200 saved monthly. $50K+ saved per year.

Users notice. Lower gas = more usage = more revenue.

Good audits include gas optimization review. If your auditor doesn't mention gas, they're not thorough.

Phase 9: Logic Errors (The Hardest to Catch)

These are bugs where the code does exactly what you told it to... but you told it the wrong thing.

Example from our own experience: We built a vesting contract. Code was perfect. Tests passed. Audit was clean.

Launch day: We realized vesting cliff was 90 days, not 60 days like we intended. The math was right for 90 days. We just coded the wrong requirement.

Not an exploit, but embarrassing and required migration.

How to prevent:

  1. Write requirements in plain English first
  2. Have non-technical person review requirements
  3. Check math on paper before coding
  4. Compare expected vs actual outputs in tests
  5. Do a walkthrough with someone else

The best test: Explain your contract to a 10-year-old. If you can't, your logic is too complex and probably has bugs.

Phase 10: Upgradeability (The Controversial Safety Net)

Hot take: Upgradeability has saved projects we've worked on from millions in losses.

The debate:

  • Anti-upgrade crowd: "Immutable contracts are trustless!"
  • Pro-upgrade crowd: "I'd rather fix bugs than lose user funds!"

Our stance: Use upgradeable contracts, but with strong governance.

Why upgradeability matters:

  1. You WILL find bugs post-launch
  2. Requirements change
  3. Gas optimizations get discovered
  4. External dependencies get updated
  5. Regulations change (unfortunately)

Real examples where upgradeability saved us:

  • Caught staking rewards bug 1 month after launch → Patched in 24 hours
  • Discovered gas optimization that saved users 40% → Upgraded
  • Third-party oracle deprecated → Switched to new one without user migration

Without upgradeability? Each of these would've cost $50K-200K in migration costs, plus loss of TVL from users not migrating.

How to do it safely:

  • Use transparent proxy pattern (OpenZeppelin)
  • Governance multisig controls upgrades (not EOA)
  • Time-lock on upgrades (24-48 hour delay)
  • Announce upgrades publicly before execution
  • Keep upgrade functions minimal and audited

The tradeoff: Users trust the governance process. If that's compromised, game over. But same risk exists with non-upgradeable contracts that have admin functions anyway.

Bottom line: For anything holding user funds over $100K, upgradeability is worth the centralization risk. Just make the upgrade process transparent and governed properly.


On-Chain vs Off-Chain: Choose Wisely

Not everything needs to happen on-chain.

Keep On-Chain:

  • Token balances
  • Ownership records
  • Critical state changes
  • Anything that affects user funds

Move Off-Chain:

  • Message signing/verification
  • Metadata storage (use IPFS)
  • Historical logs (use events)
  • Complex calculations (verify on-chain, compute off-chain)

Example: Whitelist verification

Bad (expensive on-chain):

mapping(address => bool) public whitelist; // Costs gas to update

Good (cheap with signatures):

// Off-chain: Generate signature for each whitelisted address
// On-chain: Verify signature in mint function
function mint(bytes signature) external {
    require(verify(signature, msg.sender), "Not whitelisted");
    // mint logic
}

Gas savings: 20K gas per whitelist add → 1K gas per mint verification. 95% cheaper.

Alternative: Merkle trees

Even cheaper for large whitelists. Store root on-chain, users provide proofs off-chain. We use this for 10K+ whitelist mints.


Unverified Contracts = False Security

Thinking unverified code hides exploits from attackers?

Wrong. Smart attackers use reverse engineering tools to decompile your bytecode in minutes.

Tools they use:

  • Etherscan decompiler
  • Panoramix decompiler
  • Manual bytecode analysis

They can reconstruct your logic even without source code. Unverified contracts only keep out amateurs. The people you actually need to worry about? They'll find your bugs regardless.

Our advice: Always verify contracts. Transparency builds trust and doesn't meaningfully reduce security.


The Audit Company Scam

Here's what most audit companies do:

  1. Take your $15K
  2. Feed your code into GPT-4 or Claude
  3. Generate a report from AI output
  4. Charge you extra for "critical" findings
  5. Miss actual bugs because AI missed them

Or worse:

  • Outsource to offshore devs at $20/hour
  • Copy-paste findings from similar contracts
  • Use automated tools (Slither, Mythril) and repackage results
  • Charge $15K for 2 hours of actual work

How we know: We've seen audit reports that were clearly AI-generated (wrong contract names, generic findings, no context-specific analysis).

Red flags for scam auditors:

  • Charge per critical finding (incentivizes fake findings)
  • Fast turnaround (24-48 hours for complex contract)
  • Template report with your contract name swapped in
  • No questions asked during audit (real auditors ask tons)
  • Guarantee "zero exploits" (impossible to guarantee)

Good auditors:

  • Charge by line of code or time (aligned incentives)
  • Ask detailed questions about your business logic
  • Provide context-specific recommendations
  • Admit when they're uncertain about something
  • Suggest gas optimizations (shows they read your code)

Reality check: Most "audited" contracts haven't been carefully reviewed by a human. The badge means almost nothing.


Real Audit Costs (2025)

With AI assistance, audits are getting cheaper. But quality still varies wildly.

DIY Audit (Free - $5K)

What you do:

  • Write comprehensive tests yourself
  • Use automated tools (Slither, Mythril, Aderyn)
  • Have senior dev review code
  • Run test coverage (aim for 100%)

Time: 40-80 hours
Best for: Standard tokens, low-complexity contracts
Risk: You might miss something

Basic External Audit ($5K - $15K)

What you get:

  • 1-2 auditors review code
  • Automated tool scans
  • Standard security checklist
  • Generic report

Time: 3-7 days
Best for: Medium complexity (staking, vesting, etc.)
Risk: May miss logic bugs

Comprehensive Audit ($15K - $50K+)

What you get:

  • 3-5 senior auditors
  • Manual deep review of all logic
  • Economic exploit analysis
  • Gas optimization recommendations
  • Multiple review rounds
  • Post-audit verification

Time: 2-4 weeks
Best for: DeFi protocols, high-value contracts
Risk: Still not perfect (see our staking bug example)

Continuous Auditing ($5K - $20K/month)

What you get:

  • Ongoing monitoring of deployed contracts
  • Alert system for suspicious transactions
  • Review of any upgrades
  • Emergency response team

Best for: Protocols with $10M+ TVL
Why: One exploit costs more than years of monitoring

The pricing reality: Most audits now charge $100-300 per line of code. A 500-line contract = $50K-150K at high-end firms.

With AI assistance, expect this to drop 30-50% over next year as automated analysis improves.


Our Internal Checklist (Steal This)

Before we ship any contract, we go through this checklist. Follow this and you'll catch most bugs yourself.

Pre-Deployment:

  • All tests written and passing
  • Test coverage above 95%
  • Edge cases tested with fuzzing
  • Third-party integrations reviewed
  • Access control verified (who can call what)
  • Owner is Safe multisig, not EOA
  • Reentrancy guards on external calls
  • State updates before external calls
  • Integer math checked (no overflow possible)
  • Gas optimizations applied
  • Events emitted for all state changes
  • Code commented for future maintainers
  • External audit completed (if complex)
  • Audit findings addressed
  • Testnet deployment successful
  • Contract verified on Etherscan
  • Emergency pause function exists (if holding funds)
  • Upgradeability implemented correctly (if used)
  • Time-locks on critical functions
  • Docs written for users and devs

Post-Deployment:

  • Monitoring alerts set up
  • Transaction analysis dashboard live
  • Response plan for exploits ready
  • Multisig signers identified and available
  • Insurance considered (Nexus Mutual, etc.)
  • Bug bounty program launched
  • Community notified of security measures
  • Regular security reviews scheduled

This checklist has caught dozens of bugs before launch. Use it.


When Audits Fail (And They Do)

Even paid audits miss things. Here are scenarios we've seen:

Case 1: The Staking Exploit We Mentioned

  • Cost: $15K audit
  • Result: Clean report
  • Reality: Rewards calculation could be manipulated
  • Outcome: We caught it ourselves, patched via upgrade
  • Lesson: Trust but verify. Review audit findings yourself.

Case 2: The Uniswap LP Bug

  • Cost: $20K lost despite thorough testing
  • Issue: Third-party contract (Uniswap V2) had edge case
  • Reality: Our code was perfect, integration wasn't
  • Outcome: Exploiter drained LP balance
  • Lesson: Test integrations as thoroughly as your own code

Case 3: The Logic Error No One Caught

  • Cost: $50K in migration costs
  • Issue: Vesting formula was coded correctly for wrong requirement
  • Reality: Code did exactly what we wrote, we wrote the wrong thing
  • Outcome: Had to migrate to new contract after launch
  • Lesson: Requirements review matters as much as code review

The pattern: Even with testing, audits, and care, bugs happen.
The solution: Build in upgradeability and response plans. You can't prevent all bugs, but you can minimize damage.


What Actually Keeps Contracts Safe

After 100+ contract deployments and $5M+ secured, here's what we've learned:

Security isn't about the audit. It's about the process.

  1. Test-driven development (40-60% of dev time)
  2. Edge case analysis (AI-assisted now)
  3. Third-party review (internal + external)
  4. Upgradeability (controversial but effective)
  5. Monitoring (catch exploits early)
  6. Response plans (move fast when something breaks)

The audit is just one piece. It's the extra set of eyeballs. But if you haven't done steps 1-3 thoroughly, the audit won't save you.

Inversely: If you have excellent testing and review processes, you might not need an expensive audit for simple contracts.


Common Mistakes That Cost Projects

1. Skipping Tests to Launch Faster

Cost: 10x more expensive to fix exploits than write tests
Fix: Budget 50% of dev time for testing

2. Trusting Audit Badge Blindly

Cost: False sense of security, users still get exploited
Fix: Review audit findings yourself, understand what was checked

3. Using EOA for Contract Ownership

Cost: Single point of failure, one compromised key = game over
Fix: Use Safe multisig, costs same as EOA

4. No Upgrade Path for Critical Contracts

Cost: $50K-200K per migration, loss of users who don't migrate
Fix: Implement upgradeability with strong governance

5. Ignoring Gas Optimization

Cost: $50K-500K+ in unnecessary user fees over contract lifetime
Fix: Use Solady, optimize hot paths, get gas review

6. Not Testing Third-Party Integrations

Cost: Exploits in code you don't control but depend on
Fix: Treat integrations as untrusted, test thoroughly

7. Deploying Without Monitoring

Cost: Exploits run for hours/days before anyone notices
Fix: Set up alerts on contract interactions, dashboard


Resources Worth Using

Automated Tools (Free):

  • Slither: Static analysis, catches common bugs
  • Mythril: Symbolic execution, finds edge cases
  • Aderyn: Rust-based auditor, fast and thorough
  • Foundry: Testing framework, fuzzing built-in

Learning Resources:

  • Solidity by Example: Code patterns with security notes
  • OpenZeppelin Contracts: Battle-tested, secure implementations
  • Secureum: Security-focused Solidity bootcamp
  • Damn Vulnerable DeFi: Practice exploiting contracts

Gas Optimization:

  • Solady by Vectorized: Most gas-efficient library
  • Gas Snapshots: Track gas costs over time

AI Assistants:

  • Claude/GPT-4: Generate edge case tests
  • GitHub Copilot: Write boilerplate tests faster
  • Cursor: AI-powered debugging

The Bottom Line

Your testing matters more than the audit.

We've seen projects spend $20K on audits but $0 on comprehensive testing. They still got exploited.

We've also seen projects with excellent testing and no external audit. Zero exploits.

The formula:

  • 50-60% of budget on thorough testing
  • 20-30% on internal review
  • 10-20% on external audit (if complex)
  • 10% on monitoring and response

For simple tokens: Skip external audit. Focus on testing.

For complex DeFi: Get multiple audits, but don't rely on them. Your own testing still matters most.

For anything holding $1M+: Ongoing monitoring + insurance + bug bounties.


What We Recommend

Based on contract complexity:

Simple ERC-20 Token:

  • Comprehensive tests (100% coverage)
  • Internal review by senior dev
  • Automated tool scan (Slither)
  • Skip external audit
  • Cost: $2K-5K (testing time)

Medium Complexity (Staking, Vesting):

  • Test-driven development
  • Edge case fuzzing
  • Internal review
  • Basic external audit ($8K-15K)
  • Total cost: $12K-25K

Complex DeFi Protocol:

  • Full test suite with fuzzing
  • Internal security team review
  • Multiple external audits
  • Gas optimization review
  • Ongoing monitoring
  • Bug bounty program
  • Total cost: $50K-150K

The real cost is always higher than you expect. Budget accordingly.


Final Thoughts

After $5M+ secured and 100+ contracts launched, here's what keeps us up at night:

It's not the exploits we know about. It's the ones we don't.

Every contract can have bugs. Even audited ones. Even ours.

The difference between a successful project and a catastrophic failure is:

  1. How thoroughly you test
  2. How quickly you catch issues
  3. How fast you can respond

Audits don't make contracts safe. Processes do.

Build the process right, and the audit becomes a formality. Build it wrong, and even $50K audits won't save you.

FREE CALCULATOR

PRICE YOUR
WEB3 PROJECT.

Get instant pricing and timeline estimates based on 100+ projects and $72M+ in delivered value. No guessing. No sales calls.

  • Results in under 2 minutes
  • Pricing for DeFi, tokens, NFTs & GameFi
  • Custom tech stack recommendations
  • Compare with similar successful projects

START YOUR ESTIMATE

Find out what your project costs, how long it takes, and what tech stack you'll need.

GET INSTANT ESTIMATE

Join 500+ founders who've used our calculator.

Let's Build
Together

From experimental memecoins to institutional-grade DeFi infrastructure—we build the technology that powers the next bull run.

Direct Line to the Founder