DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Share Precision Loss May Lead to Small Deposits Being Ineffective

Summary

The vault's share calculation mechanism may lead to precision loss when small deposit amounts are involved. Specifically, when the deposit amount is small relative to the total vault balance, the calculated share amount may round down to zero, resulting in the depositor receiving no shares.

Vulnerability Details

Affected Code:

_shares = amount * totalShares / totalAmountBefore;

The share amount is calculated based on the ratio of the deposit amount to the total value of the vault. If the deposit amount is very small, integer division may result in _shares rounding down to zero.

Example:

  • Suppose totalShares = 1,000,000 and totalAmountBefore = 1,000,000 collateral tokens.

  • A deposit of 1 collateral token would result in:

_shares = 1 * 1,000,000 / 1,000,000 = 1 share

However, if the total vault amount is very large, and the deposit is extremely small (e.g., 0.000001 collateral tokens), the result would round down to 0 due to integer division.

This effectively means the depositor receives no shares, and their deposit is effectively lost.

Full Context in _mint Function:

function _mint(uint256 depositId, uint256 amount, bool refundFee, MarketPrices memory prices) internal {
uint256 _shares;
if (totalShares == 0) {
_shares = depositInfo[depositId].amount * 1e8;
} else {
uint256 totalAmountBefore;
if (positionIsClosed == false && _isLongOneLeverage(beenLong)) {
totalAmountBefore = IERC20(indexToken).balanceOf(address(this)) - amount;
} else {
totalAmountBefore = _totalAmount(prices) - amount;
}
if (totalAmountBefore == 0) totalAmountBefore = 1;
_shares = amount * totalShares / totalAmountBefore;
}
depositInfo[depositId].shares = _shares;
totalShares = totalShares + _shares;
if (refundFee) {
uint256 usedFee = callbackGasLimit * tx.gasprice;
if (depositInfo[counter].executionFee > usedFee) {
try IGmxProxy(gmxProxy).refundExecutionFee(depositInfo[counter].owner, depositInfo[counter].executionFee - usedFee) {} catch {}
}
}
emit Minted(depositId, depositInfo[depositId].owner, _shares, amount);
}

Impact

  • Low Impact: Affects only very small deposits. Users making such deposits may not receive shares corresponding to their deposit.

  • Likelihood: Low. Users are unlikely to deposit extremely small amounts compared to the vault's total balance.

Tools Used

Manual Code Review

Recommendations

  1. Document the Behavior: Clarify in user-facing documentation that extremely small deposits may result in precision loss and ineffective deposits.

  2. Set a Minimum Share Amount: Implement a minimum share amount threshold to ensure any deposit mints at least 1 share. For example:

if (_shares == 0 && amount > 0) {
_shares = 1;
}

Alternatively, reject deposits below a certain threshold that would result in zero shares.

Rationale

Setting a minimum share amount or documenting this behavior helps prevent user confusion and ensures that all deposits are meaningful.

Updates

Lead Judging Commences

n0kto Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelihood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Support

FAQs

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