Skip to content

Latest commit

 

History

History
35 lines (29 loc) · 1.98 KB

028.md

File metadata and controls

35 lines (29 loc) · 1.98 KB

Cheerful Lemon Leopard

High

Incorrect rounding direction inside calculateCurrencyAmount() allows free token purchase

Description

_calculateCurrencyAmount() fails to account for rounding up in protocol's favour when calculating the amount of currency required for a token purchase. The correct implementation ought to be:

  File: rova-contracts/src/Launch.sol

   595:              /// @notice Calculate currency payment amount based on bps and token amount
   596:              function _calculateCurrencyAmount(uint256 tokenPriceBps, uint256 tokenAmount) internal view returns (uint256) {
-  597:                  return Math.mulDiv(tokenPriceBps, tokenAmount, 10 ** tokenDecimals);
+  597:                  return Math.mulDiv(tokenPriceBps, tokenAmount, 10 ** tokenDecimals, Rounding.Ceil);
   598:              }

Consider:

  1. CurrencyConfig has tokenPriceBps set as 0.001 * 1e6 = 1000 i.e. 1 token being sold for 0.001 USDC as per docs here. Token has 8 decimals.
  2. User calls participate() with a small token amount:
    • token amount = 0.0005e8
    • _calculateCurrencyAmount() returns: (1000 * 0.0005e8) / 1e8 = 0.5e8 / 1e8 = 0 (rounded-down)
    • On Base chain where gas cost is low, this is an attack vector for the user to get tokens for free. Hence the rounding-up is necessary.

Impact

User pays less or zero on participation, updateParticipation():

    295:       IERC20(request.currency).safeTransferFrom(msg.sender, address(this), currencyAmount);

and

    376:       IERC20(request.currency).safeTransferFrom(msg.sender, address(this), additionalCurrencyAmount);