Company Simulator

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

Integer Underflow in Share Price Calculation Causes DoS When Company Has Debt

Description

The get_share_price function calculates the current share price based on the company's net worth (balance minus debt). The function attempts to use max() to handle negative net worth scenarios, but in Vyper, the subtraction operation will revert BEFORE the max() function can evaluate if holding_debt > company_balance.

This causes a permanent DoS for the withdraw_shares function whenever the company accumulates more debt than its available balance.

@view
@internal
def get_share_price() -> uint256:
"""
@notice Calculates the current share price based on net worth.
@dev Net worth = company_balance - holding_debt (capped at 0).
"""
if self.issued_shares == 0:
return INITIAL_SHARE_PRICE
@> net_worth: uint256 = max(self.company_balance - self.holding_debt, 0) # Line 375
return net_worth // self.issued_shares

In Vyper 0.4.1, arithmetic operations use checked math. If holding_debt > company_balance, the subtraction self.company_balance - self.holding_debt will revert with an underflow error before max(..., 0) can be evaluated.

Risk

Likelihood:

  • This occurs whenever holding costs accumulate faster than the company can pay them

  • The _apply_holding_cost function specifically adds unpaid costs to holding_debt (line 353)

  • Any period of low sales combined with high inventory will trigger this condition

Impact:

  • Investors cannot withdraw their shares when the company is in debt

  • The withdraw_shares function becomes permanently unusable until debt is paid

  • This locks investor funds even though they may have legitimate shares

  • Creates a griefing vector where the owner can intentionally let debt accumulate

Proof of Concept

# Initial state:
company_balance = 5 ETH
holding_debt = 0 ETH
inventory = 1000 items
# Time passes with no sales, holding costs accumulate:
# Holding cost = 1000 items * cost_per_second * seconds_passed
# Company cannot pay, so debt accumulates
# After some time:
company_balance = 0 ETH (depleted)
holding_debt = 10 ETH (accumulated)
# Investor tries to withdraw shares:
investor.withdraw_shares()
-> calls get_share_price()
-> calculates: net_worth = max(0 - 10 ETH, 0)
-> 0 - 10 ETH triggers underflow REVERT
# Transaction fails, investor cannot withdraw

Recommended Mitigation

@view
@internal
def get_share_price() -> uint256:
if self.issued_shares == 0:
return INITIAL_SHARE_PRICE
- net_worth: uint256 = max(self.company_balance - self.holding_debt, 0)
+ # Handle debt > balance case before subtraction
+ net_worth: uint256 = 0
+ if self.company_balance > self.holding_debt:
+ net_worth = self.company_balance - self.holding_debt
return net_worth // self.issued_shares
Updates

Lead Judging Commences

0xshaedyw Lead Judge
10 days ago
0xshaedyw Lead Judge 8 days ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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