Skip to content

ERC4626 Calculation Bugs

id: LS34H
title: ERC4626 Calculation Bugs 
baseSeverity: H
category: accounting
language: solidity
blockchain: [ethereum]
impact: Mispriced shares, loss of user funds, or broken vault logic
status: draft
complexity: medium
attack_vector: internal
mitigation_difficulty: medium
versions: [">=0.8.0", "<=0.8.25"]
cwe: CWE-682
swc: SWC-135

📝 Description

  • ERC-4626 is a standardized interface for yield-bearing vaults that tokenizes user deposits into shares. Implementing this standard incorrectly—particularly the conversion math between assets and shares—can lead to:
  • Rounding errors that compound over time
  • Unfair share issuance (underpricing or overpricing)
  • Incorrect redemption behavior (withdrawals exceeding vault assets)
  • Economic imbalances between early and late users
  • Common causes of bugs include:
  • Integer division without rounding control
  • Unchecked edge cases when totalSupply == 0
  • Asset/share misalignment during fee handling or rebasing

🚨 Vulnerable Code

pragma solidity ^0.8.0;

contract BrokenVault {
    uint256 public totalAssets;
    uint256 public totalShares;

    function convertToShares(uint256 assets) public view returns (uint256) {
        return (assets * totalShares) / totalAssets; // ❌ division by 0 if empty vault
    }

    function convertToAssets(uint256 shares) public view returns (uint256) {
        return (shares * totalAssets) / totalShares;
    }
}

🧪 Exploit Scenario

  1. Vault is freshly deployed with totalAssets == 0 and totalShares == 0.
  2. First user deposits 100 tokens.
  3. The vault incorrectly mints zero shares due to division rounding to zero.
  4. Subsequent users get full-value shares, and the initial depositor cannot withdraw.
  5. Alternatively, early users may get all shares, diluting future users unfairly.

Assumptions:

  • Vault does not implement ERC4626’s initialization safety check for zero supply.
  • No precision-aware rounding or safety guards are in place.

✅ Fixed Code

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol";

contract SafeVault is ERC4626 {
    constructor(IERC20 asset_) ERC4626(asset_) {}

    function convertToShares(uint256 assets) public view override returns (uint256) {
        uint256 _supply = totalSupply();
        return (_supply == 0) ? assets : (assets * _supply) / totalAssets();
    }

    function convertToAssets(uint256 shares) public view override returns (uint256) {
        uint256 _supply = totalSupply();
        return (_supply == 0) ? shares : (shares * totalAssets()) / _supply;
    }
}

🧭 Contextual Severity

- context: "Vault governs user deposits and redemptions without input validation"
  severity: H
  reasoning: "User funds may be trapped or extracted unfairly"
- context: "Vault uses OpenZeppelin 4626 with basic checks"
  severity: M
  reasoning: "Still prone to rounding and edge case bugs"
- context: "Vault includes floor liquidity, rounding protection, and unit tests"
  severity: L
  reasoning: "Risk minimized if fully hardened"

🛡️ Prevention

Primary Defenses

  • Always guard against totalAssets == 0 and totalShares == 0.
  • Use OpenZeppelin’s ERC4626 reference implementation unless there is a strong reason not to.

Additional Safeguards

  • Write fuzz tests for share/asset conversion functions (convertToAssets, convertToShares, previewDeposit, previewRedeem)
  • Validate initial minting behavior with property-based testing (e.g., Foundry, Echidna).

Detection Methods

  • Search for convertToShares and convertToAssets implementations without fallback logic.
  • Tools: Slither, MythX, invariant testing

🕰️ Historical Exploits

  • Name: Astaria ERC4626 Share Inflation Exploit
  • Date: 2023-01
  • Loss: Potential for significant user losses due to manipulated share price calculations
  • Post-mortem: Link to post-mortem
  • Name: OpenZeppelin ERC4626 Inflation Attack Discussion
  • Date: 2022-09
  • Loss: Identified vulnerabilities in early ERC4626 implementations leading to potential user losses
  • Post-mortem: Link to post-mortem

📚 Further Reading

✅ Vulnerability Report

id: LS34H
title: ERC4626 Calculation Bugs 
severity: H
score:
impact: 4   
exploitability: 3 
reachability: 4   
complexity: 2  
detectability: 4  
finalScore: 3.55

📄 Justifications & Analysis

  • Impact: Loss of user funds, broken accounting, unfair share ratios.
  • Exploitability: Can be triggered by any depositor if vault isn't protected.
  • Reachability: Applies to all vaults implementing custom ERC4626 logic.
  • Complexity: Not complex but easy to overlook.
  • Detectability: Detected via fuzzing, property testing, or static checks.