{
  "schemaVersion": 1,
  "article": {
    "wpId": 6040,
    "permalink": "/archives/6040",
    "sourceIssue": 182
  },
  "fixtureOnly": true,
  "checkedAt": "2026-08-31",
  "externalRpc": false,
  "realWallet": false,
  "publicTransaction": false,
  "realAsset": false,
  "environment": {
    "foundry": "1.8.0",
    "foundryCommit": "61ae26af36320d4fa1020f7db53785885e29eeb5",
    "solidity": "0.8.36",
    "openzeppelinContracts": "5.6.1",
    "openzeppelinCommit": "5fd1781b1454fd1ef8e722282f86f9293cacf256",
    "evmVersion": "prague",
    "optimizer": true,
    "optimizerRuns": 200
  },
  "campaign": {
    "seed": "0x6040604060406040604060406040604060406040604060406040604060406040",
    "fuzzRuns": 256,
    "invariantRuns": 64,
    "invariantDepth": 64,
    "invariantWorkers": 1,
    "failOnRevert": false,
    "calls": 4096,
    "reverts": 0
  },
  "tests": {
    "status": "pass",
    "unitTests": [
      "testAssetAndShareDecimalsDivergeWithOffset",
      "testFourOperationsUseOpposingRoundingDirections",
      "testConvertAndMaxFunctionsHaveSeparateRoles",
      "testVulnerableVaultInflationAttackGivesVictimZeroShares",
      "testDefaultVirtualUnitsMakeAttackUnprofitable",
      "testPositiveOffsetMakesAttackMoreExpensive",
      "testFeeVaultPreviewsMatchDepositMintWithdrawAndRedeem",
      "testLossReducesShareValueWithoutBurningShares",
      "testFeeOnTransferAssetBreaksNaiveDepositAccounting",
      "testDirectBalanceChangeModelsRebasingBoundary"
    ],
    "invariants": [
      "invariant_TotalAssetsMatchesUnderlyingBalance",
      "invariant_TotalSupplyMatchesKnownActorShares",
      "invariant_FullSupplyPreviewNeverExceedsAssets",
      "invariant_DepositRedeemRoundTripNeverCreatesAssets"
    ],
    "unitTestCount": 10,
    "invariantCount": 4
  },
  "roundingScenario": {
    "totalAssets": 3,
    "totalShares": 2,
    "requestedUnit": 1,
    "previewDepositSharesFloor": 0,
    "previewMintAssetsCeil": 2,
    "previewWithdrawSharesCeil": 1,
    "previewRedeemAssetsFloor": 1,
    "convertToSharesFloor": 0,
    "convertToAssetsFloor": 1
  },
  "inflationAttack": {
    "attackerDeposit": 1,
    "attackerDonation": 100,
    "victimDeposit": 100,
    "vulnerable": {
      "victimShares": 0,
      "attackerRecoveredAssets": 201
    },
    "openzeppelinDefaultOffsetZero": {
      "victimShares": 1,
      "attackerRecoveredAssets": 67
    },
    "openzeppelinOffsetThree": {
      "shareDecimals": 9,
      "attackerInitialShares": 1000,
      "victimShares": 1960,
      "attackerRecoveredAssets": 51
    }
  },
  "feeAndLoss": {
    "feeBasisPoints": 100,
    "depositAssets": 101,
    "depositShares": 100,
    "mintShares": 100,
    "mintAssets": 101,
    "withdrawAssets": 99,
    "withdrawShares": 100,
    "redeemShares": 100,
    "redeemAssets": 99,
    "lossBeforeAssets": 100,
    "lossAssets": 40,
    "lossAfterAssets": 60,
    "sharesAfterLoss": 100
  },
  "nonStandardAssets": {
    "feeOnTransferRequested": 100,
    "feeOnTransferReceivedByVault": 99,
    "feeOnTransferSharesMintedByNaiveVault": 100,
    "balanceIncreaseBefore": 100,
    "balanceIncreaseAfter": 125,
    "fullSharePreviewAfterIncrease": 124
  },
  "limits": [
    "The vulnerable vault is intentional test code and must never be deployed.",
    "A bounded invariant campaign tests only the modeled operations, actors, inputs, runs, and depth.",
    "Virtual assets and shares change attack economics but do not replace slippage limits or implementation review.",
    "The fee extension is educational and follows the documented preview relationships; it is not an audit result.",
    "Fee-on-transfer and balance-change cases expose integration boundaries, not universal behavior for every non-standard token.",
    "No public RPC, mainnet fork, wallet, signature, transaction broadcast, yield strategy, or real asset is used."
  ]
}
