Cheerful Lemon Leopard
High
_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:
CurrencyConfig
hastokenPriceBps
set as0.001 * 1e6 = 1000
i.e. 1 token being sold for 0.001 USDC as per docs here. Token has 8 decimals.- 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.
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);