# Security Process: Testing, Tools and Audits — Blockchain & Smart Contracts (Solidity)

Source: https://www.geekswithgeeks.com/en/solidity/x-audits

> Build a security process with fuzzing, static analysis, audits and monitoring.

## Defence in depth

Deployed contracts are usually immutable and hold real value, so security needs a **process**, not a final check. **Design**: keep contracts small and simple, reuse audited libraries, document invariants ("total shares equal the sum of balances") and threat models, and limit privileged roles. **Testing**: aim for thorough unit tests, **fuzz tests** that try random inputs, and **invariant (stateful) tests** that run random sequences of calls and check invariants always hold; Foundry and Echidna or Medusa support these. **Static analysis**: **Slither** detects many common bug patterns in seconds; Aderyn is another option. **Formal verification** tools (such as Certora and the SMTChecker) prove properties for critical code. **Audits** by experienced reviewers or **competitive audit** contests find issues that tools miss, but an audit is not a guarantee. After launch: **bug bounties** (for example on Immunefi), **monitoring** with alerts on unusual events, **pause** mechanisms and incident-response plans, **gradual rollouts** with deposit caps, and keeping keys in multisigs. Most losses come from logic errors, compromised keys and integration assumptions, not just famous bug classes.

## Fuzz and invariant tests with Foundry

Random inputs and sequences check properties, not just examples.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import {Test} from "forge-std/Test.sol";
import {Vault} from "../src/Vault.sol";

contract VaultFuzzTest is Test {
    Vault vault;
    address alice = makeAddr("alice");

    function setUp() public {
        vault = new Vault();
    }

    // Fuzz: any deposited amount can be fully withdrawn
    function testFuzz_DepositThenWithdraw(uint96 amount) public {
        vm.assume(amount > 0);
        vm.deal(alice, amount);
        vm.startPrank(alice);
        vault.deposit{value: amount}();
        vault.withdraw(amount);
        vm.stopPrank();
        assertEq(alice.balance, amount);
        assertEq(vault.balances(alice), 0);
    }

    function test_RevertWhen_WithdrawingMoreThanBalance() public {
        vm.prank(alice);
        vm.expectRevert(abi.encodeWithSelector(Vault.InsufficientBalance.selector, 0, 1 ether));
        vault.withdraw(1 ether);
    }
}

// Invariant testing: Foundry calls random handler functions in random order
// and checks the invariant after every call.
contract VaultHandler is Test {
    Vault public vault;
    uint256 public ghostDeposited;
    uint256 public ghostWithdrawn;

    constructor(Vault vault_) { vault = vault_; }

    function deposit(uint96 amount) external {
        vm.deal(address(this), amount);
        vault.deposit{value: amount}();
        ghostDeposited += amount;
    }

    function withdraw(uint256 amount) external {
        amount = bound(amount, 0, vault.balances(address(this)));
        vault.withdraw(amount);
        ghostWithdrawn += amount;
    }

    receive() external payable {}
}

contract VaultInvariantTest is Test {
    Vault vault;
    VaultHandler handler;

    function setUp() public {
        vault = new Vault();
        handler = new VaultHandler(vault);
        targetContract(address(handler));
    }

    function invariant_EtherMatchesAccounting() public view {
        assertEq(address(vault).balance, handler.ghostDeposited() - handler.ghostWithdrawn());
        assertEq(vault.balances(address(handler)), address(vault).balance);
    }
}

// Static analysis: slither .   (run from the project root)
```

## Write invariants before code

Listing properties such as "nobody can withdraw more than they deposited" and "the sum of balances equals the contract's ether" clarifies the design and gives you ready-made invariant tests.

**Quiz:** What does an invariant (stateful fuzz) test do?

- [x] Runs random sequences of function calls and checks that stated properties always hold
- [ ] Tests one fixed input
- [ ] Formats code
- [ ] Deploys to mainnet

*Answer:* Runs random sequences of function calls and checks that stated properties always hold. Invariant tests explore many call sequences looking for property violations.
