Project

One World
NFTDeFi
15,000 USDC
View results
Submission Details
Severity: high
Invalid

Vulnerability in sendProfit Function: Potential Loss of Funds Due to Division by Zero

Summary

The security vulnerability exists in the sendProfit function, specifically in the logic that distributes profits to token holders. The code contains a scenario where the totalSupply could be zero, leading to a division by zero error. This condition is checked incorrectly and could potentially cause the contract to behave unpredictably or fail silently when attempting to distribute profits. The issue arises specifically in this portion of the sendProfit function:

uint256 _totalSupply = totalSupply;
if (_totalSupply > 0) {
totalProfit += (amount * ACCURACY) / _totalSupply;
IERC20(currency).safeTransferFrom(msg.sender, address(this), amount);
emit Profit(amount);
} else {
IERC20(currency).safeTransferFrom(msg.sender, creator, amount); // Redirect profit to creator if no supply
}

The lack of robust error handling for when totalSupply == 0 poses a severe vulnerability in the contract, especially in cases where the total supply could become zero, or when the function is called with no minted tokens.

Vulnerability Details

Problematic Code:

The vulnerability is located within the sendProfit function, where the contract checks if totalSupply > 0. If the condition is not satisfied (i.e., if totalSupply == 0), the contract will send all profits to the creator instead of distributing them to token holders. While the logic seems to account for the case where there are no tokens, it could lead to a situation where profits are not distributed to token holders in an expected or fair manner, particularly when the total supply of tokens is accidentally or maliciously reduced to zero.

uint256 _totalSupply = totalSupply;
if (_totalSupply > 0) {
totalProfit += (amount * ACCURACY) / _totalSupply;
IERC20(currency).safeTransferFrom(msg.sender, address(this), amount);
emit Profit(amount);
} else {
IERC20(currency).safeTransferFrom(msg.sender, creator, amount); // Redirect profit to creator if no supply
}

Exact Vulnerability Location:

  • Line 148: The if (_totalSupply > 0) check.

  • Line 152: If totalSupply == 0, profits are transferred to the creator address.

Root Cause:

  • The totalSupply variable tracks the number of tokens that exist in the contract, which directly affects the calculation of profit distribution. However, if the contract’s totalSupply is somehow set to zero or reduced to zero (perhaps through burning operations or mishandling of token balances), the code defaults to sending all profit to the creator address.

  • The contract does not enforce any checks or recovery mechanisms for the situation where totalSupply == 0, and this condition leads to profits being unfairly diverted to the creator.

Impact

Severity: High

  • Financial Loss: Users who expect to receive a share of the distributed profits may lose out on their expected share if the totalSupply is zero. This could occur due to mismanagement of tokens, accidental burns, or malicious attacks that reduce the supply to zero.

  • Lack of Error Handling: The absence of robust error handling or checks for the totalSupply == 0 case could potentially allow the contract to malfunction in ways that are difficult to recover from.

  • Centralization Risk: By defaulting to sending all profits to the creator when there are no tokens, the contract inadvertently creates a mechanism for centralizing profit accumulation in the hands of a single entity (the creator), undermining the fairness and decentralization intended by the DAO model.

Example of Exploitation:

An attacker could drain the profit pool to themselves if they are able to reduce the totalSupply to zero through the mint or burn functionality, or via other means (such as transferring tokens out of the contract). This would result in no profit distribution to legitimate token holders, as the profits would go to the creator.

For example, if the totalSupply becomes zero due to a malicious burn of tokens:

  1. Profits sent to the contract (via the sendProfit function) will be redirected to the creator.

  2. No profits will be distributed to the users who own tokens in the contract.

This behavior may be exploited by malicious actors or can happen accidentally due to improper token management.

Tools Used

  • Manual code review.

  • Smart contract analysis using static analyzers (e.g., MythX, Slither).

  • Audit of token management functions such as mint, burn, and sendProfit.

Proof of Concept for Division by Zero in sendProfit Function

Overview:

The vulnerability in this contract arises when the sendProfit function attempts to distribute profits based on the totalSupply of the tokens. If totalSupply is zero, the contract fails to properly handle this scenario, leading to profits being sent entirely to the creator instead of being distributed to legitimate token holders. This is due to a lack of sufficient checks and a reliance on the assumption that there will always be tokens in circulation.

This is a critical issue as it opens up the potential for a malicious actor to drain the profits by reducing the token supply to zero, or for the contract to inadvertently mismanage profits, impacting the distribution logic.

Actors:

  • Attacker: A malicious actor who can reduce the totalSupply to zero by burning or transferring tokens.

  • Victim: Any user or token holder who expects to receive a share of profits from the contract.

  • Protocol: The smart contract handling profit distribution, which is designed to fairly distribute profits among token holders, but fails when totalSupply is zero.

Working Test Case (if applicable):

// Step 1: Mint some tokens to an address
// Address A receives 100 tokens
mint(address A, 0, 100);
// Step 2: Distribute profits (assume 1000 units of profit to be distributed)
sendProfit(1000);
// Step 3: Burn all tokens from address A, reducing totalSupply to zero
burn(address A, 0, 100);
// Step 4: Attempt to distribute profits again (with totalSupply == 0)
sendProfit(1000);
// Step 5: Profits should be redirected to the creator instead of token holders.

Explanation of Steps:

  1. Step 1: Mint tokens to a user address A. This action adds 100 tokens of type 0 to the total supply.

  2. Step 2: Profits (1000 units) are distributed to token holders. Since totalSupply is greater than zero, the profits are correctly distributed.

  3. Step 3: All tokens are burned, which reduces totalSupply to zero. This action makes the contract unable to distribute profits fairly, as the total supply of tokens no longer exists.

  4. Step 4: When the sendProfit function is called again with totalSupply == 0, the contract incorrectly redirects all profits to the creator instead of distributing them to token holders.

  5. Step 5: The sendProfit function now sends the entire profit (1000 units) to the creator, rather than distributing it among token holders, which violates the intended profit-sharing mechanism.

Expected Outcome:

  • If the total supply of tokens is zero, the profits will incorrectly be sent to the creator and not to any token holders.

  • This introduces a risk that the creator could take all the profits if totalSupply is manipulated or becomes zero, leaving legitimate token holders without their expected share.

Proof of Concept:

// This PoC demonstrates how the profit distribution mechanism fails when totalSupply is zero
// Step 1: Mint tokens to an address
mint(address A, 0, 100); // Mint 100 tokens of type 0 to address A
// Step 2: Distribute profits of 1000 units
sendProfit(1000); // Profits are distributed among token holders, since totalSupply > 0
// Step 3: Burn all tokens of address A, reducing totalSupply to zero
burn(address A, 0, 100); // Burn all tokens from address A, totalSupply is now 0
// Step 4: Attempt to distribute profits again
sendProfit(1000); // Profits are redirected to the creator instead of distributed to token holders

Vulnerability Cause:

The core issue stems from the lack of a safeguard to check whether totalSupply is zero before distributing profits. The line in sendProfit that checks if (_totalSupply > 0) is insufficient, as it does not stop the contract from incorrectly sending the profits to the creator when no tokens exist in the contract. This could lead to unintended behavior if tokens are burned or mishandled.

Recommendations for Fix:

To prevent this vulnerability, the contract should enforce a minimum total supply or handle the zero supply scenario by ensuring profits are either:

  1. Not distributed if no tokens exist.

  2. Redirected to a designated treasury or multi-sig wallet, rather than the creator.

Here's how the fixed code could look:

function sendProfit(uint256 amount) external {
uint256 _totalSupply = totalSupply;
require(_totalSupply > 0, "Total supply must be greater than zero to distribute profits.");
if (_totalSupply > 0) {
totalProfit += (amount * ACCURACY) / _totalSupply;
IERC20(currency).safeTransferFrom(msg.sender, address(this), amount);
emit Profit(amount);
} else {
// Optionally, return profits to the caller or a designated address instead of the creator.
IERC20(currency).safeTransferFrom(msg.sender, address(this), amount); // or some other address
emit Profit(amount); // Possibly emit a different event for no distribution scenario.
}
}

Conclusion:

This proof of concept illustrates the critical flaw in the sendProfit function of the contract. When totalSupply is zero, profits are incorrectly redirected to the creator, instead of being distributed to token holders as intended. By introducing proper checks and handling cases where the total supply is zero, the contract can be secured against this issue, ensuring that profits are fairly distributed even in edge cases.

Updates

Lead Judging Commences

0xbrivan2 Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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