Property-Based Testing

Testing methodology that verifies general properties or invariants hold across randomly generated inputs rather than checking specific hard-coded examples.

Property-based testing is a testing methodology where developers define properties (invariants) that must always hold true, and the testing framework automatically generates thousands of random inputs to try to falsify those properties. Unlike unit tests that verify specific input-output pairs, property-based tests explore vast state spaces to find edge cases developers would never anticipate.

Property-based testing vs unit testing

AspectUnit testingProperty-based testing
Input selectionDeveloper chooses specific valuesFramework generates random values
CoverageTests known scenariosExplores unknown edge cases
Assertion style"Given X, result should be Y""For all inputs, property P holds"
Bug discoveryFinds bugs in anticipated scenariosFinds bugs in unanticipated scenarios
MaintenanceNew test per scenarioOne property covers infinite scenarios

How it works in smart contracts

1. Define a property

Identify a fundamental truth about your system:

1// Property: total supply must equal sum of all balances
2// Property: a user can always withdraw their deposited funds
3// Property: no single transfer can increase total supply

2. The fuzzer generates inputs

The testing framework (e.g., Foundry) generates random:

  • Function call sequences (mint, burn, transfer in random order)
  • Parameter values (amounts, addresses, timestamps)
  • Transaction orderings and state combinations

3. Check the property after each step

1function invariant_solvency() public view {
2 // After ANY sequence of random operations,
3 // the vault must always hold enough to cover deposits
4 assert(
5 address(vault).balance >= vault.totalDeposits()
6 );
7}

4. Report violations

If the fuzzer finds an input sequence that breaks the property, it reports the exact call sequence, enabling developers to reproduce and fix the bug.

Types of property-based tests

Stateless fuzzing

Each test run starts from a clean state. The fuzzer generates random inputs for a single function call:

1function testFuzz_transferNeverIncreasesSupply(
2 address from,
3 address to,
4 uint256 amount
5) public {
6 uint256 supplyBefore = token.totalSupply();
7 vm.prank(from);
8 token.transfer(to, amount);
9 assertEq(token.totalSupply(), supplyBefore);
10}

Stateful invariant testing

The fuzzer generates entire sequences of function calls, building up complex state over many operations. This catches bugs that only emerge after specific transaction orderings:

1function invariant_conservationOfValue() public view {
2 // Must hold after ANY sequence of deposits, withdrawals,
3 // transfers, and fee accruals
4 assertGe(vault.totalAssets(), vault.totalLiabilities());
5}

Stateful testing is significantly more powerful for finding composite vulnerabilities in DeFi protocols.

Common properties for DeFi protocols

Token properties:

  • Total supply equals sum of all balances
  • Transfers preserve total supply
  • Approve/transferFrom doesn't create tokens

Vault properties:

  • Users can always withdraw their entitled funds
  • Share price is monotonically non-decreasing (excluding losses)
  • Total assets always cover total liabilities

AMM properties:

  • The constant product formula holds after every swap
  • Reserves match actual token balances
  • Fees are always deducted, never added

Why it matters for security

Property-based testing catches vulnerability classes that unit tests systematically miss:

  • Rounding errors that compound over thousands of operations
  • State-dependent bugs that only trigger after specific operation sequences
  • Economic exploits where invariants break under extreme market conditions
  • Reentrancy paths through unexpected function call orderings

By translating security checklist items into testable properties, teams transform static documentation into active, automated verification—a core practice in defense-in-depth security workflows.

Need expert guidance on Property-Based Testing?

Our team at Zealynx has deep expertise in blockchain security and DeFi protocols. Whether you need an audit or consultation, we're here to help.

Get a Quote

oog
zealynx

Subscribe to Our Newsletter

Stay updated with our latest security insights and blog posts

© 2024 Zealynx