Company Simulator

First Flight #51
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Division-by-zero in share pricing (fund_investor)

Division-by-zero in share pricing (fund_investor) causes investors to not be able to fund the contract

Description

  • The fund_investor logic calculates a share price from the contract net_worth divided by issued_shares. When net_worth == 0 the implementation allows a division-by-zero or produces a zero price which then leads to either a runtime revert or incorrect minting (e.g., infinite / zero-cost shares). The root cause is an unguarded integer division performed when no shares have been issued yet.

#Cyfrin_Hub::fund_investor
net_worth: uint256 = 0
if self.company_balance > self.holding_debt:
net_worth = self.company_balance - self.holding_debt
share_price: uint256 = (
net_worth // max(self.issued_shares, 1)
if self.issued_shares > 0
else INITIAL_SHARE_PRICE
)
# @audit-high cant ever fund if net_worth is 0?
new_shares: uint256 = msg.value // share_price # <@ reverts here

Risk

Likelihood: High

  • This is a likely state to be encountered in a freshly deployed contract: before any shares are issued, an investor may attempt to buy shares. Many real deployments begin with zero issued_shares, so this is easy to trigger during normal operation or tests.

Impact: High

  • DoS: the investor funding call can revert, blocking legitimate investor funding flows.

  • Funds loss or incorrect accounting: If zero-priced shares are minted (or a math error occurs), funds may be misallocated or shares incorrectly issued.

Proof of Concept

def test_FundInvestor_DivisionByZero_Reverts(industry_contract, OWNER, PATRICK):
# Make sure the caller has funds to send
boa.env.set_balance(PATRICK, FUND_VALUE)
# Expect a revert when PATRICK tries to fund as an investor before any
# shares have been issued by the contract.
with boa.reverts():
with boa.env.prank(PATRICK):
industry_contract.fund_cyfrin(1, value=FUND_VALUE)

Recommended Mitigation

- # compute share price from net worth / issued shares
- share_price: uint256 = net_worth // self.issued_shares
+ # compute share price from net worth / issued shares
+ # If net_worth == 0 (e.g., newly deployed or depleted), use INITIAL_SHARE_PRICE
+ share_price: uint256 = INITIAL_SHARE_PRICE
+ if self.issued_shares > 0:
+ if net_worth > 0:
+ share_price = net_worth // self.issued_shares
+ # ensure no zero price (prevent division-by-zero when computing new_shares)
+ if share_price == 0:
+ share_price = 1
+ new_shares: uint256 = msg.value // share_price
+ assert new_shares > 0, "Contribution too small for any shares"
Updates

Lead Judging Commences

0xshaedyw Lead Judge
6 days ago
0xshaedyw Lead Judge 5 days ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.