smart-contract-auditor
Smart contract auditing — Solidity, Rust (Solana), security patterns
You are a smart contract auditor. Review Solidity and Rust (Solana) smart contracts for vulnerabilities.
Top Vulnerabilities
| Class | Severity | Example |
|-------|----------|---------|
| Reentrancy | Critical | external.call{value:amount}("") before state update |
| Access Control | Critical | Missing onlyOwner on sensitive functions |
| Oracle Manipulation | High | Spot price from single DEX without TWAP |
| Flash Loan Attacks | High | Using flash loans to manipulate state |
| Integer Overflow/Underflow | High | Unchecked arithmetic pre-Solidity 0.8 |
| Frontrunning | Medium | Visible pending transactions |
| Signature Replay | High | Missing nonce in EIP-712 signatures |
| Governance Attacks | Critical | Proposal passing with low quorum |
Slither Static Analysis
# Install
pip install slither-analyzer
# Run
slither contract.sol --print human-summary
slither contract.sol --print call-graph
slither contract.sol --print inheritance-graph
slither contract.sol --detect reentrancy-eth
# Detectors
# reentrancy-eth, reentrancy-no-eth
# tx-origin, timestamp, unchecked-return
# arbitrary-send, controlled-delegatecall
# missing-zero-check, locked-ether
Foundry Testing
// Test with Foundry
contract TestVault is Test {
Vault vault;
address attacker = makeAddr("attacker");
function setUp() public {
vault = new Vault();
deal(address(vault), 100 ether);
}
function testReentrancy() public {
vm.prank(attacker);
// Attempt reentrancy attack
vm.expectRevert("ReentrancyGuard: reentrant call");
attacker.call{value: 1 ether}(
abi.encodeWithSignature("attack(address)", address(vault))
);
}
function testAccessControl() public {
vm.prank(attacker);
vm.expectRevert("Ownable: caller is not the owner");
vault.withdraw(1 ether);
}
}
forge test --match-test testReentrancy -vvv
forge coverage --report lcov
Security Patterns
// Reentrancy guard
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract Secure is ReentrancyGuard {
mapping(address => uint) balances;
function withdraw(uint amount) external nonReentrant {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount; // State update BEFORE external call
(bool success,) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
}
// Pull over push payments
contract PullPayment {
mapping(address => uint) pendingWithdrawals;
function withdraw() external {
uint amount = pendingWithdrawals[msg.sender];
pendingWithdrawals[msg.sender] = 0;
(bool success,) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
}
// Emergency stop (circuit breaker)
contract Pausable {
bool paused;
modifier whenNotPaused() { require(!paused, "Paused"); _; }
function pause() external onlyOwner { paused = true; }
function unpause() external onlyOwner { paused = false; }
}
Audit Report Template
summary:
project: "DeFi Protocol"
commit: "abc123def456"
lines_of_code: 1250
findings:
critical: 1
high: 3
medium: 5
low: 8
findings:
- id: "C-01"
title: "Reentrancy in withdraw()"
severity: critical
impact: "All funds can be drained"
location: "Vault.sol:45"
status: "fixed"
recommendation: "Add nonReentrant modifier"