Company Simulator

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

Holding Debt Accounting Can Cause Permanent Investment Lock

Root + Impact

Description

  • Normal behavior:

    The company should be able to operate and accept investments even after paying some debt, with company_balance and holding_debt correctly tracked.

  • Specific issue:

  • fund_investor() includes this check:

@internal

def fund_investor():

@> assert self.company_balance > self.holding_debt, "Company is insolvent!!!"

If holding_debt exceeds company_balance at any point (for example, after long unpaid holding costs), investors are permanently blocked from contributing more ETH — even if the owner later injects funds. The logic does not allow recovery unless debt is manually cleared. This can freeze funding and halt company operations.

// Root cause in the codebase with @> marks to highlight the relevant section
@internal
def fund_investor():
@> assert self.company_balance > self.holding_debt, "Company is insolvent!!!"

Risk

Likelihood:

Medium — Only occurs when accumulated holding_debt exceeds balance (long-term storage costs or delayed owner payments).


Impact:

Medium — Investors are unable to inject funds; share issuance and liquidity flows are blocked, potentially locking the company in a non-functional state.

Proof of Concept

Explanation:

Once holding_debt > company_balance, all investor funding attempts fail due to the assert in fund_investor(). Even small contributions are blocked, effectively freezing investment flows.


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
<br />
interface IVuln {
function fund\_cyfrin(uint256 action) external payable;
function pay\_holding\_debt() external payable;
}
<br />
contract DebtLockPoC {
IVuln target;
<br />
constructor(address \_target) { target = IVuln(\_target); }
<br />
function simulateLock() external payable {
// Suppose the company balance is 1 ETH, debt is 2 ETH
// Any further call to fund\_investor() will revert
// Example: attacker tries to invest 0.01 ETH
target.fund\_cyfrin{value: 0.01 ether}(1); // <-- reverts: "Company is insolvent!!!"
}
}
<br />

Recommended Mitigation

Explanation:

Instead of outright rejecting funding when debt exceeds balance, compute net worth and allow investors to buy shares proportional to remaining solvency. This avoids permanently blocking investors while maintaining accounting accuracy.

- remove this code
+ add this code
@@
- assert self.company_balance > self.holding_debt, "Company is insolvent!!!"
+ # Allow partial funding even if company balance < holding debt
+ # Ensure net worth calculation is correct and issue shares proportionally
+ net_worth: uint256 = max(self.company_balance - self.holding_debt, 0)
+ assert net_worth > 0, "Company has no net worth"
Updates

Lead Judging Commences

0xshaedyw Lead Judge
4 days ago
0xshaedyw Lead Judge 3 days ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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