Company Simulator

First Flight #51
Beginner FriendlyDeFi
100 EXP
Submission Details
Impact: high
Likelihood: medium

Zero share price makes withdraw_shares burn investor equity with no payout

Author Revealed upon completion

Root + Impact

Description

  • Funding should always succeed by pricing new shares at the current net worth per share and minting proportionally.

  • When debt wipes out net worth, the share price calculation truncates to zero, so the subsequent floor division by share_price reverts and permanently bricks all new investments.

share_price: uint256 = (
@> net_worth // max(self.issued_shares, 1)
if self.issued_shares > 0
else INITIAL_SHARE_PRICE
)
@> new_shares: uint256 = msg.value // share_price

Risk

Likelihood:

  • _apply_holding_cost steadily increases holding_debt; once it catches up to company_balance, net worth collapses to zero while shares remain outstanding.

  • The protocol has no emergency recapitalization hook, so the first investor to rescue the project always hits the revert.

Impact:

  • Public funding is permanently disabled, preventing any recapitalization through investor deposits.

  • Without new capital the protocol remains insolvent and slides toward bankruptcy.

Proof of Concept

  1. Reduce the company net worth to zero or below while leaving issued_shares > 0 (for example, by calling set_holding_debt to exceed company_balance).

  2. Call fund_investor with any positive msg.value.

  3. The transaction reverts with a division-by-zero error, bricking further investments until the share price is repaired off-chain.

// After prolonged holding costs net_worth == 0 while issued_shares == 1000.
fund_investor{value: 1 ether}()
// reverts with division by zero before minting shares.

Recommended Mitigation

  • Check for net_worth == 0 and revert with a descriptive error instead of invoking the division operation.

  • Allow new capital injections at distressed prices by using fixed-point math and rounding up so the share price never reaches zero.

  • Provide an owner-only recovery function that recapitalizes the treasury and resets accounting when the share price cannot be computed.

share_price: uint256 = (
net_worth // max(self.issued_shares, 1)
if self.issued_shares > 0
else INITIAL_SHARE_PRICE
)
+ assert share_price > 0, "Share price underflow!!!"
new_shares: uint256 = msg.value // share_price

Support

FAQs

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