fund_investor accepts ETH, computes new_shares, and only then caps the issuance. When integer division or trimming drives new_shares to zero, the call still completes: it credits the vault balance, emits SharesIssued, and even records a lockup timestamp, yet the caller receives no shares.
Likelihood: Fractional deposits or hard-cap trims are normal events. Any user sending less than one share-worth of ETH immediately triggers the bug. Attack complexity is low.
Depositors can lose the full amount sent because zero shares are minted.
share_received_time is still set, letting attackers skip the early withdrawal penalty later.
Audit logs mislead operators because SharesIssued fires for zero-amount share sales.
Call fund_cyfrin(1) with 0.0005 ETH.
Observe shares[attacker] == 0 while company_balance increased by 0.0005 ETH.
Later deposit a larger amount, mint shares, and immediately exit via withdraw_shares; the stored timestamp predates the lockup period so no penalty applies.
Forge-style reproduction outline:
Revert if new_shares == 0 before mutating state.
When trimming to available, refund msg.value - new_shares * share_price and only retain funds backing minted shares.
Update timestamps only when new_shares > 0 and clear them inside withdraw_shares.
Proposed patch (Vyper-like pseudocode):
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.