For the complete documentation index, see llms.txt. This page is also available as Markdown.

89290 sc low maxdeposit can advertise a positive amount that deposit deterministically rejects after legitimate rewards

Submitted on Aug 18th 2026 at 12:52:53 UTC by @CarlosMB for Audit Comp | Firelight

  • Report ID: #89290

  • Report Type: Smart Contract

  • Report severity: Low

  • Target: https://github.com/immunefi-team/audit-comp-firelight/blob/v1_audit_ready/contracts/core/FirelightVault.sol

  • Impacts:

    • Contract fails to deliver promised returns, but doesn't lose value

Description

Summary

FirelightVault.maxDeposit() returns the remaining asset capacity:

return depositLimit - totalAssets();

but deposit() has an additional executability constraint:

if (shares == 0) revert InvalidAmount();

Legitimate rewards increase totalAssets() without increasing totalSupply(). Near the deposit limit, this can leave a positive remaining capacity that is too small to mint one share.

As a result, maxDeposit(receiver) can return a positive value while an immediate deposit(maxDeposit(receiver), receiver) reverts with InvalidAmount, with no intervening state change.

ERC-4626 requires maxDeposit() not to return more assets than deposit() would currently accept without reverting.

Root Cause

maxDeposit() only checks the deposit limit and protocol-level guards:

However, deposit() also rejects deposits that round to zero shares:

VaultRewardDistributor can naturally increase the share price because it transfers vault assets directly into FirelightVault without minting shares.

Impact

Low — Contract fails to deliver promised returns without loss of value.

Integrations using maxDeposit() to construct the largest currently valid ERC-4626 deposit can receive a protocol-provided positive value that is guaranteed to revert.

No donation, privileged misuse, or exchange-rate manipulation is required.

Proof of Concept

Proof of Concept

Create:

with:

Run:

Expected security-relevant result:

Make maxDeposit() account for the same zero-share condition enforced by deposit():

This ensures the advertised maximum is actually executable under the current vault state.

Was this helpful?