SCWE-135: ERC4626 Share Inflation via Donations
Stable Version v1.0
This content is in the version-(v1.0) and still under active development, so it is subject to change any time (e.g. structure, IDs, content, URLs, etc.).
Relationships¶
- CWE-682: Incorrect Calculation
https://cwe.mitre.org/data/definitions/682.html
Description¶
ERC4626 vaults that do not guard against free-asset donations can skew totalAssets and share price. Attackers can donate assets to inflate share value and then mint shares cheaply before normalization, extracting value from existing holders.
Remediation¶
- Normalize share price on every deposit/mint using current
totalAssets. - Optionally block unsolicited donations by reverting on direct transfers or sweeping them into reserves before new share mints.
- Add tests for donation and price-per-share edge cases.
Examples¶
Vulnerable¶
// totalAssets() uses balanceOf; donations inflate it and skew share price
function mint(uint256 shares) external {
uint256 assets = previewMint(shares);
asset.transferFrom(msg.sender, address(this), assets);
_mint(msg.sender, shares);
}
Fixed¶
uint256 private _accountedAssets; // internal balance; excludes direct transfers
function totalAssets() public view override returns (uint256) {
return _accountedAssets; // donations do not affect share price
}
function deposit(uint256 assets, address receiver) public override returns (uint256 shares) {
uint256 before = asset.balanceOf(address(this));
shares = super.deposit(assets, receiver);
_accountedAssets += (asset.balanceOf(address(this)) - before);
}
function withdraw(uint256 assets, address receiver, address owner) public override returns (uint256 shares) {
shares = super.withdraw(assets, receiver, owner);
_accountedAssets -= assets;
}