Zero Shares Issued Despite ETH Payment in fund_investor
The fund_investor() function is designed to allow public users to invest ETH in exchange for proportional shares based on the current share price.
Normal Behavior: The number of shares granted is calculated using integer division: new_shares = msg.value // share_price. The protocol expects to either issue a non-zero amount of shares or to revert.
Issue: When an investor's payment (msg.value) is less than the calculated share_price, Vyper's integer division rounds the result down to zero (new_shares = 0). The function checks if new_shares > available but does not check if new_shares > 0. Consequently, the code executes the following:
new_shares is set to 0.
The full msg.value amount is added to self.company_balance.
The investor receives 0 shares (self.shares[msg.sender] += 0).
This breaks the fundamental economic invariant: A non-zero payment must yield non-zero equity or be fully refunded. An investor can lose up to the full price of one share (minus a tiny epsilon) in a single transaction, unjustly inflating the company's internal balance at the expense of the investor.
Likelihood: High
This occurs whenever an investor's contribution is slightly less than the current share price.
Impact: High
Economic Loss to Investor: An investor can lose the entire value of their investment (up to the full price of a single share) without receiving any equity.
Unjust Enrichment: The company's company_balance increases without corresponding issuance of shares, breaking the fundamental economic fairness model of the protocol.
Note on Test Environment Setup (Addressing Vyper's Internal Visibility):
The core logic for calculating
share_priceresides in theinternalfunctionget_share_price()withinCyfrin_Hub.vy. To accurately calculate the required attack amount () and provide irrefutable evidence for the PoC, we must read this internal value.To enable this without modifying the core logic of the vulnerability, a temporary external helper function,
get_current_share_price(), was added to the public interface ofCyfrin_Hub.vysolely for testing purposes. This allows the test environment to access the preciseshare_priceand correctly execute the scenario where Investment Amount < Share Price.
Place this function in the empty space on line 395.
This test confirms that an investment of nearly the full share price results in 0 shares being issued, and the substantial payment is fully and unjustly retained by the company.
Verified Test Output:
The function should revert if the calculated new_shares is zero. This guarantees that for every payment, the investor either receives equity or has their funds returned automatically. Furthermore, implement an explicit check for a full cap to reject payments when no shares are available.
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.