# Smart Contract Fuzz Tester

> Dynamic testing framework that generates random inputs to discover vulnerabilities and invariant violations in smart contracts

- Skill: `xspoonai/smart-contract-fuzz-tester` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add xspoonai/smart-contract-fuzz-tester`
- Raw SKILL.md: https://api.skillmd.com/api/skills/xspoonai/smart-contract-fuzz-tester/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: XSpoonAi (https://skillmd.com/u/xspoonai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/xspoonai/smart-contract-fuzz-tester

---


# Smart Contract Fuzz Tester

## Overview

Comprehensive fuzzing framework for smart contract testing that implements dynamic analysis through random input generation, property-based testing, and vulnerability detection. Discovers edge cases, invariant violations, and security issues that might be missed by traditional testing.

**Testing Type**: Dynamic Analysis (Runtime)  
**Approach**: Property-Based Testing + Mutation Fuzzing  
**Target**: Solidity Smart Contracts (EVM)  
**Status**: Production Ready  

## Key Capabilities

### 1. **Input Generation** (input_generator.py)
- ✅ All Solidity primitive types (uint, int, address, bool, bytes, string)
- ✅ Complex types (arrays, fixed arrays, dynamic arrays)
- ✅ Edge case generation (zero, max, overflow boundary values)
- ✅ Random value generation with seed support
- ✅ Mutation-based fuzzing from seed corpus
- ✅ Type-aware intelligent generation

### 2. **Invariant Checking** (invariant_checker.py)
- ✅ Balance invariants (min/max balance constraints)
- ✅ Supply invariants (totalSupply validation)
- ✅ Ownership invariants (access control verification)
- ✅ Arithmetic invariants (overflow/underflow detection)
- ✅ State transition invariants (valid state changes)
- ✅ Custom invariant support

### 3. **Vulnerability Detection** (vulnerability_detector.py)
- ✅ Reentrancy (state changes after external calls)
- ✅ Integer overflow/underflow
- ✅ Access control bypass
- ✅ Unchecked external calls
- ✅ Dangerous delegatecall
- ✅ tx.origin authentication
- ✅ Timestamp dependence
- ✅ Gas limit DoS
- ✅ Front-running vulnerabilities

### 4. **Fuzz Engine** (fuzz_engine.py)
- ✅ Coverage-guided fuzzing (prioritize unexplored paths)
- ✅ Function coverage tracking
- ✅ Crash deduplication
- ✅ Gas analysis and optimization
- ✅ Detailed execution reporting
- ✅ Configurable test campaigns

## Components

### input_generator.py (580 lines)
**Purpose**: Generate random and edge-case inputs for smart contract functions

**Classes**:
- `InputGenerator` - Main input generation engine
- `FuzzInput` - Generated input with metadata

**Methods**:
```python
generate_uint(bits, edge_case)           # Generate unsigned integer
generate_int(bits, edge_case)            # Generate signed integer
generate_address(edge_case)              # Generate Ethereum address
generate_bool()                          # Generate boolean
generate_bytes(size, edge_case)          # Generate bytes value
generate_string(edge_case)               # Generate string
generate_array(base_type, length, edge_case)  # Generate array
generate_for_type(type_str, edge_case)   # Generate for any Solidity type
generate_function_inputs(param_types, edge_case_probability)  # Complete function inputs
mutate_input(original)                   # Mutation-based fuzzing
```

### invariant_checker.py (420 lines)
**Purpose**: Verify contract properties and detect violations

**Classes**:
- `InvariantChecker` - Main invariant verification engine
- `Invariant` - Invariant definition
- `InvariantViolation` - Detected violation

**Methods**:
```python
add_invariant(name, inv_type, check_function, description, critical)
check_all_invariants()
create_balance_invariant(address, min_balance, max_balance)
create_supply_invariant()
create_ownership_invariant(expected_owner)
create_arithmetic_invariant(function_name, args, expected_min, expected_max)
create_no_overflow_invariant(a, b, operation)
create_state_transition_invariant(state_function, valid_states)
create_access_control_invariant(function_name, allowed_caller)
get_violations_summary()
```

### vulnerability_detector.py (490 lines)
**Purpose**: Detect common smart contract vulnerabilities

**Classes**:
- `VulnerabilityDetector` - Pattern-based vulnerability detection
- `Vulnerability` - Detected vulnerability with severity
- `VulnerabilityType` - Enum of vulnerability types
- `Severity` - Severity classification

**Methods**:
```python
detect_reentrancy(contract_address, function_name, trace)
detect_integer_overflow(function_name, a, b, operation)
detect_integer_underflow(function_name, a, b)
detect_access_control_bypass(function_name, caller, expected_caller, execution_succeeded)
detect_unchecked_call(function_name, call_result, call_checked)
detect_dangerous_delegatecall(function_name, target_address, caller_is_arbitrary)
detect_tx_origin_auth(source_code, function_name)
detect_timestamp_dependence(source_code, function_name)
detect_gas_limit_dos(function_name, loop_iterations, gas_per_iteration)
detect_front_running(function_name, involves_price, state_dependent)
analyze_transaction(tx_receipt, function_name)
get_summary()
```

### fuzz_engine.py (520 lines)
**Purpose**: Orchestrate fuzzing campaigns

**Classes**:
- `FuzzEngine` - Main fuzzing orchestrator
- `FuzzConfig` - Configuration parameters
- `FuzzResult` - Single iteration result
- `FuzzSummary` - Campaign summary

**Methods**:
```python
add_invariant(name, inv_type, check_function, description, critical)
get_fuzzable_functions()
fuzz_function(function_abi, iteration, caller_account)
run_campaign()
print_summary(summary)
```

## Usage Examples

### Example 1: Basic ERC20 Token Fuzzing

```python
from web3 import Web3
from fuzz_engine import FuzzEngine, FuzzConfig
from invariant_checker import InvariantType

# Connect to Ethereum
w3 = Web3(Web3.HTTPProvider("https://eth.llamarpc.com"))

# ERC20 ABI (simplified)
erc20_abi = [
    {"name": "transfer", "inputs": [{"name": "to", "type": "address"}, {"name": "amount", "type": "uint256"}], "outputs": [{"type": "bool"}], "stateMutability": "nonpayable", "type": "function"},
    {"name": "approve", "inputs": [{"name": "spender", "type": "address"}, {"name": "amount", "type": "uint256"}], "outputs": [{"type": "bool"}], "stateMutability": "nonpayable", "type": "function"},
    {"name": "totalSupply", "outputs": [{"type": "uint256"}], "stateMutability": "view", "type": "function"},
    {"name": "balanceOf", "inputs": [{"name": "account", "type": "address"}], "outputs": [{"type": "uint256"}], "stateMutability": "view", "type": "function"},
]

# Configure fuzzing
config = FuzzConfig(
    max_iterations=500,
    edge_case_probability=0.4,
    timeout_seconds=120,
    verbose=True
)

# Initialize and run
engine = FuzzEngine(w3, "0xTokenAddress", erc20_abi, config)

# Add ERC20 invariants
engine.add_invariant(
    name="supply_positive",
    inv_type=InvariantType.SUPPLY,
    check_function=engine.invariant_checker.create_supply_invariant(),
    description="Total supply must be positive",
    critical=True
)

summary = engine.run_campaign()
```

**Expected Output**:
```
======================================================================
SMART CONTRACT FUZZ ENGINE
======================================================================
✅ Target: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
   Max iterations: 500
   Edge case prob: 0.4
   Gas limit: 3,000,000
======================================================================
STARTING FUZZ CAMPAIGN
======================================================================
Found 2 fuzzable functions:
  • transfer(address, uint256)
  • approve(address, uint256)

[0] Fuzzing transfer(address, uint256)
  Param 0: 0x0000000000000000000000000000000000000000 (edge case address)
  Param 1: 0 (zero)
  ❌ Reverted: execution reverted: ERC20: transfer to the zero address

[1] Fuzzing approve(address, uint256)
  Param 0: 0xF3d0c63a8eB2F2f1d8e5f9e3a5Cb8dF1234567890 (random address)
  Param 1: 1000000000000000000 (random)
  ✅ Success (estimated gas: 46,109)

📊 Progress: 100/500 (12.5 iter/sec)
📊 Progress: 200/500 (13.1 iter/sec)
📊 Progress: 300/500 (12.8 iter/sec)
📊 Progress: 400/500 (13.0 iter/sec)
📊 Progress: 500/500 (12.9 iter/sec)

======================================================================
FUZZ CAMPAIGN SUMMARY
======================================================================

📊 Execution Statistics:
   Total iterations: 500
   Successful: 387 (77.4%)
   Failed: 113 (22.6%)
   Execution time: 38.76s
   Rate: 12.9 iter/sec

⛽ Gas Analysis:
   Total gas: 17,854,321
   Average: 35,709 per call

🎯 Coverage:
   Function coverage: 100.0%
   Functions tested: 2
      approve: 261 iterations
      transfer: 239 iterations

🐛 Issues Found:
   Invariant violations: 0
   Vulnerabilities: 3
   Unique crashes: 8

   Top crashes:
      transfer:execution reverted: ERC20: transfer to the zero address (45x)
      transfer:execution reverted: ERC20: transfer amount exceeds balance (32x)
      approve:execution reverted: ERC20: approve from the zero address (18x)

   Vulnerabilities by severity:
      high: 2
      medium: 1
```

### Example 2: Test with Custom Invariants

```python
from invariant_checker import InvariantChecker, InvariantType

checker = InvariantChecker(w3, contract_address, contract_abi)

# Custom balance invariant
def check_user_balance():
    user_address = "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
    balance = checker.contract.functions.balanceOf(user_address).call()
    total_supply = checker.contract.functions.totalSupply().call()
    
    if balance > total_supply:
        return False, balance, f"<= totalSupply ({total_supply})"
    
    return True

checker.add_invariant(
    name="balance_not_exceed_supply",
    inv_type=InvariantType.BALANCE,
    check_function=check_user_balance,
    description="User balance cannot exceed total supply",
    critical=True
)

violations = checker.check_all_invariants()

if violations:
    print(f"❌ Found {len(violations)} invariant violations")
    for v in violations:
        print(f"   {v.invariant_name}: {v.description}")
```

**Actual Test Output** (Run on Ethereum Mainnet):
```
Connected to: https://eth.llamarpc.com
Block: 24489808

======================================================================
SMART CONTRACT INVARIANT CHECKER
======================================================================
✅ Checking contract: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48

======================================================================
EXAMPLE: Adding Invariants
======================================================================
✅ Added invariant: total_supply_positive
✅ Added invariant: zero_address_no_balance

======================================================================
EXAMPLE: Checking Invariants
======================================================================

🔍 Checking 2 invariants...
  ✅ All invariants hold

======================================================================
EXAMPLE: Violation Summary
======================================================================
Total violations: 0
Critical: 0
Warnings: 0
By type: {}
```

### Example 3: Generate Edge Case Inputs

```python
from input_generator import InputGenerator

generator = InputGenerator(seed=123)

# Generate edge cases for different types
print("Edge Case Examples:")

# Unsigned integers
for _ in range(5):
    uint = generator.generate_uint(256, edge_case=True)
    print(f"\nuint256 ({uint.description}):")
    print(f"  Value: {uint.value}")

# Addresses
for _ in range(3):
    addr = generator.generate_address(edge_case=True)
    print(f"\naddress ({addr.description}):")
    print(f"  Value: {addr.value}")

# Bytes
for _ in range(3):
    b = generator.generate_bytes(32, edge_case=True)
    print(f"\nbytes32 ({b.description}):")
    print(f"  Value: {b.value.hex()}")
```

**Expected Edge Case Values** (Deterministic based on type logic):
```
uint256 edge cases:
  - 0 (zero)
  - 1 (one)
  - 115792089237316195423570985008687907853269984665640564039457584007913129639935 (maximum 2^256-1)
  - 115792089237316195423570985008687907853269984665640564039457584007913129639934 (maximum - 1)
  - 57896044618658097711785492504343953926634992332820282019728792003956564819968 (half maximum 2^255)

address edge cases:
  - 0x0000000000000000000000000000000000000000 (zero address)
  - 0x000000000000000000000000000000000000dEaD (burn address)
  - 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF (max address)

bytes32 edge cases:
  - 0x0000...0000 (all zeros)
  - 0xFFFF...FFFF (all ones)
```

### Example 4: Detect Vulnerabilities

```python
from vulnerability_detector import VulnerabilityDetector

detector = VulnerabilityDetector(w3)

# Test for integer overflow
print("Testing for integer overflow...")
overflow_vuln = detector.detect_integer_overflow(
    function_name="add",
    a=2**256 - 100,
    b=200,
    operation="add"
)

if overflow_vuln:
    print(f"❌ {overflow_vuln.vuln_type.value.upper()}")
    print(f"   Severity: {overflow_vuln.severity.value}")
    print(f"   Location: {overflow_vuln.location}")
    print(f"   Evidence: {overflow_vuln.evidence}")
    print(f"   Recommendation: {overflow_vuln.recommendation}")

# Test for integer underflow
print("\nTesting for integer underflow...")
underflow_vuln = detector.detect_integer_underflow(
    function_name="subtract",
    a=50,
    b=100
)

if underflow_vuln:
    print(f"❌ {underflow_vuln.vuln_type.value.upper()}")
    print(f"   Evidence: {underflow_vuln.evidence}")

# Test for access control bypass
print("\nTesting for access control bypass...")
access_vuln = detector.detect_access_control_bypass(
    function_name="mint",
    caller="0x1234567890123456789012345678901234567890",
    expected_caller="0xOwnerAddress...",
    execution_succeeded=True
)

if access_vuln:
    print(f"❌ {access_vuln.vuln_type.value.upper()}")
    print(f"   Severity: {access_vuln.severity.value}")
    print(f"   Recommendation: {access_vuln.recommendation}")

# Summary
summary = detector.get_summary()
print(f"\n📊 Total vulnerabilities: {summary['total']}")
print(f"   By severity: {summary['by_severity']}")
```

**Actual Test Output**:
```
======================================================================
SMART CONTRACT VULNERABILITY DETECTOR
======================================================================
✅ Pattern-based vulnerability detection enabled

======================================================================
EXAMPLE: Detecting Vulnerabilities
======================================================================

❌ INTEGER_OVERFLOW
   Severity: high
   Location: add
   Evidence: 115792089237316195423570985008687907853269984665640564039457584007913129639926 + 20 = 115792089237316195423570985008687907853269984665640564039457584007913129639946 > 2^256-1
   Fix: Use SafeMath library or Solidity 0.8+ built-in overflow checks

❌ INTEGER_UNDERFLOW
   Severity: high
   Evidence: 5 - 10 would underflow (a < b)

❌ ACCESS_CONTROL
   Severity: critical
   Evidence: Caller 0x1234567890123456789012345678901234567890 (expected 0x0000000000000000000000000000000000000001) executed successfully

======================================================================
VULNERABILITY SUMMARY
======================================================================
Total vulnerabilities: 3

By severity:
  critical: 1
  high: 2

By type:
  integer_overflow: 1
  integer_underflow: 1
  access_control: 1
```

### Example 5: Mutation-Based Fuzzing

```python
from input_generator import InputGenerator

generator = InputGenerator()

# Start with seed input
seed_input = generator.generate_uint(256, edge_case=False)
print(f"Original: {seed_input.value}")

# Generate mutations
print("\nMutations:")
for i in range(10):
    mutated = generator.mutate_input(seed_input)
    print(f"  {i+1}. {mutated.value} ({mutated.description})")
```

**Note**: Mutation output is non-deterministic and varies by random seed. Example mutations include:
- Bit flips (XOR with random mask)
- Arithmetic operations (+, -, *, ^ with random values)
- Negation (for signed integers)
- Byte manipulation (insert, delete, modify)

## Testing

### Prerequisites

1. **Install dependencies**:
   ```bash
   pip install web3 eth-abi eth-utils eth-account
   ```

2. **Set RPC URL**:
   ```bash
   export RPC_URL="https://eth.llamarpc.com"
   ```

### Run Individual Modules

```bash
# Test input generator
python input_generator.py

# Test invariant checker
python invariant_checker.py

# Test vulnerability detector
python vulnerability_detector.py

# Test fuzz engine
python fuzz_engine.py
```

### Run Full Fuzzing Campaign

```python
python fuzz_engine.py
```

Expected: Fuzzes USDC contract for 50 iterations, reports summary with coverage and issues found.

## Common Issues & Solutions

### Issue 1: "No fuzzable functions found"
**Cause**: Contract only has view/pure (read-only) functions  
**Solution**: Fuzz testing requires state-changing functions. Add write functions to contract.

### Issue 2: High rate of reverts
**Cause**: Edge cases intentionally trigger require() statements  
**Solution**: This is expected behavior. Review revert reasons to ensure they're legitimate.

### Issue 3: Low function coverage
**Cause**: Not enough iterations to explore all functions  
**Solution**: Increase `max_iterations` in FuzzConfig.

### Issue 4: Memory issues with large campaigns
**Cause**: Storing all results in memory  
**Solution**: Reduce verbose logging or implement result streaming to disk.

### Issue 5: RPC rate limiting
**Cause**: Too many requests to public RPC  
**Solution**: Use local node or rate-limit requests with delays.

## Production Deployment

### Testing Checklist

- [ ] Define comprehensive invariants for your contract
- [ ] Test with both random and edge-case inputs
- [ ] Run sufficient iterations (1000+ recommended)
- [ ] Review all detected vulnerabilities
- [ ] Fix critical and high-severity issues
- [ ] Re-run fuzzing after fixes
- [ ] Achieve >90% function coverage
- [ ] Document known limitations and edge cases

### Best Practices

1. **Start with known invariants**: Balance <= totalSupply, no negative balances
2. **Use seeded fuzzing for reproducibility**: Set `seed` in FuzzConfig
3. **Prioritize edge cases**: Set `edge_case_probability` to 0.4-0.5
4. **Monitor gas usage**: Optimize functions with high gas consumption
5. **Deduplicate crashes**: Review unique crash signatures
6. **Combine with static analysis**: Use Slither, Mythril alongside fuzzing

## References

- **Echidna**: https://github.com/crytic/echidna (Haskell fuzzer)
- **Foundry Fuzz**: https://book.getfoundry.sh/forge/fuzz-testing
- **Mythril**: https://github.com/ConsenSys/mythril (Symbolic execution)
- **Manticore**: https://github.com/trailofbits/manticore (Symbolic EVM)
- **Trail of Bits**: https://blog.trailofbits.com/category/security/
- **Smart Contract Weakness Classification**: https://swcregistry.io/
- **Solidity Security**: https://docs.soliditylang.org/en/latest/security-considerations.html

## Extensions

### Potential Enhancements
- Symbolic execution integration (Z3 SMT solver)
- Code coverage tracking with EVM tracing
- Corpus management and seed minimization
- Parallel fuzzing for faster campaigns
- Integration with CI/CD pipelines
- Transaction sequence fuzzing (multi-call)
- Real transaction submission (not just simulation)
- Machine learning for smarter input generation

### Integration Ideas
- GitHub Actions for automated fuzzing on PR
- Hardhat/Foundry plugin
- VS Code extension for inline fuzzing
- Dashboard for visualization
- Slack/Discord notifications for critical issues

---

**Status**: Production Ready  
**Version**: 1.0.0  
**Last Updated**: 2024  
**Maintainer**: Spoon Awesome Skills Team

