{
  "schema_version": "1.2",
  "scan_id": "7068b4ee-bedc-425f-8b12-cf72712ed18e",
  "status": "ok",
  "error": null,
  "input": {
    "kind": "source",
    "sha256": "765d7f5132127401ebfc23d625a8e3768d4a0191f83e022dc927ebd4f63829b0",
    "chain": null,
    "address": null,
    "contract_name": null,
    "compiler_version": "0.8.37",
    "compiler_version_source": "pragma",
    "files": [
      {
        "path": "erc4626_inflation.sol",
        "sha256": "a35dd1e6f2ebe26d887ae75a35fabbff7ea0636e404e7c014ed674dfb2bcdea6",
        "bytes": 1052,
        "lines": 33,
        "nsloc": 26
      }
    ],
    "nsloc": 26,
    "bytes": 1052
  },
  "findings": [
    {
      "id": "F-001",
      "detector": "erc4626-inflation",
      "source": "custom",
      "title": "ERC4626-style vault without virtual shares (first-depositor inflation)",
      "severity": "high",
      "confidence": "medium",
      "location": {
        "file": "erc4626_inflation.sol",
        "start_line": 22,
        "end_line": 25
      },
      "file_line": "erc4626_inflation.sol:22",
      "snippet": "    function convertToShares(uint256 assets) public view returns (uint256) {\n        uint256 supply = totalSupply;\n        return supply == 0 ? assets : assets * supply / totalAssets();\n    }",
      "description": "SimpleVault.convertToShares(uint256) (erc4626_inflation.sol#22-25) converts assets to shares without virtual shares/offset (vault SimpleVault (erc4626_inflation.sol#9-33)) while totalAssets() uses the token balance",
      "explanation": "The vault converts assets to shares with a plain ratio of totalSupply to totalAssets(), where totalAssets() comes from the vault's token balance, and has no virtual shares, virtual assets or decimals offset. The first depositor can mint 1 wei of shares and then donate a large amount of the asset directly to the vault, inflating the share price so that later deposits round down to zero (or very few) shares; the attacker then redeems and captures the victims' deposits. This is the classic ERC4626 inflation (donation) attack.",
      "recommendation": "Use OpenZeppelin ERC4626 v4.9+ (virtual shares and assets via _decimalsOffset), add a virtual offset to the conversion math, track deposited assets internally instead of using balanceOf, or seed the vault with dead shares at deployment.",
      "fingerprint": "3daaf769d5e85f57",
      "also_at": []
    },
    {
      "id": "F-002",
      "detector": "erc20-unsafe-transfer",
      "source": "custom",
      "title": "ERC20 transfer/transferFrom/approve called without SafeERC20",
      "severity": "medium",
      "confidence": "medium",
      "location": {
        "file": "erc4626_inflation.sol",
        "start_line": 29,
        "end_line": 29
      },
      "file_line": "erc4626_inflation.sol:29",
      "snippet": "        require(asset.transferFrom(msg.sender, address(this), assets), \"transfer\");",
      "description": "SimpleVault.deposit(uint256,address) (erc4626_inflation.sol#27-32) checks the return value of a raw ERC20 `transferFrom` (reverts for tokens that return nothing, e.g. USDT): require(bool,string)(asset.transferFrom(msg.sender,address(this),assets),transfer) (erc4626_inflation.sol#29)",
      "explanation": "The contract calls transfer, transferFrom or approve directly on an ERC20 token instead of going through SafeERC20 (or an equivalent low-level wrapper). When the boolean return value is ignored, a token that signals failure by returning false (rather than reverting) lets the call 'succeed' silently, so balances are credited for tokens that never moved. When the return value is checked through the interface, tokens that return nothing at all (USDT, BNB, OMG and others) make the ABI decoder revert, so every call fails and funds can be locked. Severity is high when the return value is ignored and medium when it is checked.",
      "recommendation": "Use OpenZeppelin SafeERC20 (safeTransfer, safeTransferFrom, forceApprove) or Solady SafeTransferLib for every interaction with an arbitrary ERC20 token.",
      "fingerprint": "8101becd0dd6a7cf",
      "also_at": []
    },
    {
      "id": "F-003",
      "detector": "reentrancy-no-eth",
      "source": "slither",
      "title": "Reentrancy vulnerabilities",
      "severity": "medium",
      "confidence": "medium",
      "location": {
        "file": "erc4626_inflation.sol",
        "start_line": 29,
        "end_line": 29
      },
      "file_line": "erc4626_inflation.sol:29",
      "snippet": "        require(asset.transferFrom(msg.sender, address(this), assets), \"transfer\");",
      "description": "Reentrancy in SimpleVault.deposit(uint256,address) (erc4626_inflation.sol#27-32):\n\tExternal calls:\n\t- require(bool,string)(asset.transferFrom(msg.sender,address(this),assets),transfer) (erc4626_inflation.sol#29)\n\tState variables written after the call(s):\n\t- totalSupply += shares (erc4626_inflation.sol#30)\n\tSimpleVault.totalSupply (erc4626_inflation.sol#11) can be used in cross function reentrancies:\n\t- SimpleVault.convertToShares(uint256) (erc4626_inflation.sol#22-25)\n\t- SimpleVault.deposit(uint256,address) (erc4626_inflation.sol#27-32)\n\t- SimpleVault.totalSupply (erc4626_inflation.sol#11)",
      "explanation": "\nDetection of the [reentrancy bug](https://github.com/trailofbits/not-so-smart-contracts/tree/master/reentrancy).\nDo not report reentrancies that involve Ether (see `reentrancy-eth`).",
      "recommendation": "Apply the [`check-effects-interactions` pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy).",
      "fingerprint": "66df151848f4e7fc",
      "also_at": []
    },
    {
      "id": "F-004",
      "detector": "incorrect-equality",
      "source": "slither",
      "title": "Dangerous strict equalities",
      "severity": "low",
      "confidence": "high",
      "location": {
        "file": "erc4626_inflation.sol",
        "start_line": 24,
        "end_line": 24
      },
      "file_line": "erc4626_inflation.sol:24",
      "snippet": "        return supply == 0 ? assets : assets * supply / totalAssets();",
      "description": "SimpleVault.convertToShares(uint256) (erc4626_inflation.sol#22-25) uses a dangerous strict equality:\n\t- supply == 0 (erc4626_inflation.sol#24)",
      "explanation": "Use of strict equalities that can be easily manipulated by an attacker.",
      "recommendation": "Don't use strict equality to determine if an account has enough Ether or tokens.",
      "fingerprint": "37d056c543324348",
      "also_at": []
    }
  ],
  "stats": {
    "raw_results": 6,
    "dropped_informational": 1,
    "dropped_noisy": 1,
    "dropped_out_of_scope": 0,
    "dropped_dependencies": 0,
    "duplicates_removed": 0,
    "results_truncated": false,
    "findings": 4,
    "findings_by_severity": {
      "high": 1,
      "medium": 2,
      "low": 1,
      "info": 0
    },
    "detectors_run": 111,
    "custom_detectors_run": 9,
    "contracts": 2
  },
  "timing": {
    "fetch_ms": 0,
    "queue_ms": 0,
    "solc_install_ms": 0,
    "sandbox_ms": 853,
    "compile_ms": 81,
    "detectors_ms": 17,
    "total_ms": 857,
    "started_at": "2026-10-06T13:23:46.874Z",
    "finished_at": "2026-10-06T13:23:47.731Z"
  },
  "engine": {
    "scanner_version": "0.1.0",
    "slither_version": "0.11.6",
    "sandbox": {
      "user": "scanner",
      "network_isolated": true,
      "notes": [],
      "memory_cgroup": true,
      "memory_max_bytes": 1572864000
    },
    "options": {
      "include_informational": false,
      "include_noisy": false,
      "include_dependencies": false
    }
  },
  "disclaimer": "Automated scan, not an audit. Findings may be false positives; absence of findings does not mean the code is safe."
}
