Security is not a one-time gate. It's a continuous process that starts at the first line of code and continues long after mainnet deployment. This checklist distills the lessons from hundreds of DeFi exploits into a practical, actionable format that protocol teams can use at every stage of development.

We've organized the checklist into three phases: development (checks during coding), pre-deployment (checks before going live), and post-deployment (ongoing monitoring). Most items should be verified during development, but some only become relevant at deployment time.

How to use this checklist: Work through each category systematically. For each item, verify it applies to your protocol and mark it as checked, not applicable, or needs-fix. Items marked as needs-fix should be resolved and re-verified before deployment. Use our free scanner to automatically check many of these items.

1

Reentrancy & State Management

All external calls follow the Checks-Effects-Interactions pattern — state updates happen before any external calls
Functions that transfer ETH or tokens use ReentrancyGuard (or equivalent nonReentrant modifier)
Cross-function reentrancy is considered — no function reads state that could be stale during reentrancy from another function
Read-only reentrancy is considered — view functions called by external protocols return correct values during reentrancy
State is consistent before and after every external call — no partial state updates visible to re-entrant callers
Callback hooks (ERC-721 onERC721Received, ERC-1155 hooks, ERC-777 hooks) are handled safely with reentrancy protection
Multi-contract systems consider reentrancy across contract boundaries, not just within a single contract
2

Access Control & Authorization

Every external and public function has been reviewed for correct access control (onlyOwner, onlyRole, etc.)
Critical functions (mint, burn, pause, upgrade, withdraw, setFee) are restricted to appropriate roles
tx.origin is never used for authorization — only msg.sender
Multi-sig or timelock is required for admin operations that affect user funds
Role-based access control uses least privilege — each role has only the permissions it needs
Ownership transfer uses a two-step process (propose + accept) to prevent accidental transfers
Initialize functions can only be called once and are protected on implementation contracts
No functions have unprotected selfdestruct or delegatecall to arbitrary addresses
3

Arithmetic & Data Handling

All unchecked blocks have been individually verified to be safe from overflow/underflow
Division before multiplication patterns have been eliminated — multiply first, divide last
Division by zero is impossible in all arithmetic operations (denominators validated or guaranteed non-zero)
Token decimal differences are handled correctly when comparing or converting between tokens with different decimals
Rounding direction is explicitly chosen and favors the protocol (round down for user withdrawals, round up for user deposits)
Calculations involving large numbers have been tested at boundary values (type(uint256).max, 0, 1, etc.)
Casting between types (uint256 to uint128, int256 to uint256) is safe and validated
4

Oracle & Price Feed Security

Price feeds use TWAP or Chainlink — never single-block spot prices from AMM pools
Oracle staleness is checked — stale prices (e.g., Chainlink heartbeat exceeded) trigger a revert or fallback
Oracle manipulation resistance has been evaluated — cost to manipulate the oracle exceeds potential profit
Multiple oracle sources are used for critical price data, with deviation checks between them
L2/sidechain sequencer uptime is verified when using Chainlink on L2s (sequencer uptime feed)
Price bounds are enforced — prices outside reasonable ranges are rejected
The protocol gracefully handles oracle failure rather than bricking all operations
5

Token Handling Safety

SafeERC20 is used for all token transfers (handles non-standard return values)
Fee-on-transfer tokens are handled correctly — actual received amount is checked, not assumed
Rebasing tokens are either explicitly supported or explicitly documented as unsupported
ERC-777 callback reentrancy is protected against (tokensReceived hook)
The protocol handles tokens with different decimals (6, 8, 18) correctly
Token approval race conditions are handled (use increaseAllowance/decreaseAllowance or approve-to-zero first)
The protocol documents which token types are supported and which are not
6

Economic & Flash Loan Resistance

The protocol's security model does not assume attackers need capital (flash loans provide unlimited single-tx capital)
First depositor attack is prevented (vault share price cannot be manipulated by the first depositor with dust amounts)
Donation attacks are considered — direct token transfers to the contract cannot manipulate internal accounting
Pool ratio manipulation within a single transaction is accounted for
Liquidation mechanisms are resistant to price manipulation attacks
Fee extraction paths have been reviewed — no way to avoid fees through clever transaction ordering
The protocol's invariants (total supply == sum of balances, etc.) are documented and tested
7

Front-Running & MEV Protection

All swaps include slippage parameters (minAmountOut) that users can set
Transaction deadlines are enforced to prevent stale transactions from executing at unfavorable prices
Sensitive operations use commit-reveal schemes where appropriate (auctions, governance votes)
The protocol considers sandwich attack resistance for large operations
Block.timestamp is not used for critical randomness (miners can manipulate within limits)
8

Upgrade & Proxy Security

Storage layout between proxy and implementation is verified — no slot collisions
Implementation contracts have initializers disabled (cannot be initialized directly)
Upgrade function is protected with timelock and multi-sig
Storage layout tests verify that new implementation is compatible with existing storage
Standard proxy patterns are used (ERC-1967 storage slots, OpenZeppelin TransparentProxy or UUPS)
Gap variables are used in base contracts to allow future storage additions
If using UUPS, the _authorizeUpgrade function has proper access control
9

Gas Optimization & DoS Prevention

No unbounded loops over arrays that can grow with user input
Pull-over-push pattern is used for distributions (users withdraw rather than contract pushes)
External call failures do not block the entire function (handle failures gracefully)
Gas costs for critical user operations are reasonable and predictable
Functions that iterate over data structures have upper bounds on iteration count
Batch operations have limits to prevent single-transaction gas exhaustion
10

Testing & Coverage

Line and branch coverage exceeds 95% for all critical contracts
Edge cases are tested: zero amounts, max values, empty arrays, single-element arrays
Fuzz testing (Foundry fuzz, Echidna, or Medusa) has been run on critical functions
Invariant testing verifies protocol invariants hold across random operation sequences
Fork testing against mainnet state validates real-world token and protocol interactions
Integration tests cover multi-contract interactions and cross-contract flows
Tests include attack scenarios: reentrancy attempts, flash loan attacks, sandwich attacks
Formal verification has been considered for the most critical invariants (Certora, Halmos)
11

Deployment & Operations

Deployment scripts are version controlled and tested — not manual
Constructor arguments and initialization parameters are verified before deployment
Source code is verified on block explorers (Etherscan, etc.) immediately after deployment
Admin keys are stored in hardware wallets or multi-sig, never in hot wallets or plain text
Emergency pause functionality exists and has been tested
Protocol parameters (fees, limits, addresses) are documented and their valid ranges are enforced on-chain
Testnet deployment has been live for at least 2 weeks before mainnet
12

Incident Response & Monitoring

Real-time monitoring and alerting is configured for unusual activity (large withdrawals, governance changes)
An incident response plan exists with clear roles, communication channels, and procedures
War gaming has been conducted — the team has practiced responding to simulated exploits
A bug bounty program is live on a reputable platform (Immunefi, HackenProof, Code4rena)
Circuit breakers exist for rate-limiting large operations (e.g., max withdrawal per block)
Team members can be reached within 15 minutes during an incident via on-call rotation

Audit Workflow: When to Check What

During Development

Run automated scans on every commit. Categories 1-5 should be checked continuously. Use our free scanner to catch pattern-level issues early. Write tests that cover attack scenarios from categories 6-7. This is the cheapest time to find and fix bugs.

Pre-Deployment

All 12 categories should be fully checked. Run the complete checklist at least once. Commission a professional audit for protocols handling significant value. Categories 10-11 become critical. Allow 2-4 weeks for audit turnaround and another 1-2 weeks for fixes.

Post-Deployment

Category 12 is ongoing. Monitor continuously. Maintain your bug bounty. Re-audit after any code changes. Track emerging vulnerability classes and verify your protocol is not affected. The security landscape evolves — your monitoring must evolve with it.

Automated vs. Manual: Getting the Best of Both

This checklist contains over 80 items. Checking them all manually is time-consuming and error-prone. The most effective approach is layering automated and manual review:

Workflow
Development Phase:
  1. Automated scanner on every commit      // Catches ~40% of items
  2. Unit + fuzz + invariant tests           // Catches ~25% of items
  3. Internal code review                   // Catches ~15% of items

Pre-Deployment Phase:
  4. AI deep analysis ($99-$199)             // Catches cross-contract issues
  5. Professional manual audit               // Catches business logic flaws
  6. Full checklist walkthrough              // Catches remaining ~20%

Ongoing:
  7. Monitoring + bug bounty                // Catches novel attacks

No single approach catches everything. Automated tools are fast and consistent but miss business logic. Manual auditors are thorough but expensive and slow. The combination is what gives you real confidence.

Start Scanning Now

The best time to start scanning is before you've written all the code. The Solari free scanner checks for reentrancy, access control, oracle manipulation, arithmetic issues, and many more vulnerability patterns from this checklist. Paste your Solidity code and get results in seconds.

For a comprehensive pre-deployment review that covers cross-contract interactions, economic attack modeling, and detailed remediation guidance, explore our paid scanning tiers starting at $99.