Tadle

Tadle
DeFiFoundry
27,750 USDC
View results
Submission Details
Severity: medium
Valid

Purchase commissions can be reduced to zero if the collaterall token is a low decimals token

Summary

When buying points, PreMarket::createTaker calculates the commissions to be paid by the user on the purchase.

Commissions are of two types:

uint256 platformFee = depositAmount.mulDiv(
platformFeeRate,
Constants.PLATFORM_FEE_DECIMAL_SCALER
);
uint256 tradeTax = depositAmount.mulDiv(
makerInfo.eachTradeTax,
Constants.EACH_TRADE_TAX_DECIMAL_SCALER
);

Problems occur c platformFee due to too large selected SCALER - 1_000_000 for lowDecimals tokens, e.g. USDC, where Decimals = 6.

Because of this, a user can deliberately avoid paying commissions when buying points by zeroing it out using rounding down when dividing if the number of tokens to be sold has the right degree of 10.

Vulnerability Details

Consider the case where the number of tokens sold (points = 100000). The price they want for all 100000 points is (amount = 10 USDC).

Let's show how a user can buy as many points (<=1000) as he wants, avoiding platform fee.

To do this, you just have to break your purchase into small 1 point purchases.

Consider the case when buy_points = 1, total_sell_points = 10000, amount = 10 USDC.

If we believe the test data from Premarkets.t.sol - platformFeeRate = 5000.

uint256 depositAmount = _points.mulDiv(
offerInfo.amount,
offerInfo.points,
Math.Rounding.Ceil
);
uint256 platformFee = depositAmount.mulDiv(
platformFeeRate,
Constants.PLATFORM_FEE_DECIMAL_SCALER // 1_000_000
);

depositAmount = (1 ** (10 ** 10 ^ 6)) / 100000 = 10 ^ 7 / 10 ^ 5 = 10 ^ 2 = 100

platformFee = 100 * 5000 / 10 ^ 6 = 0.

This way, the user can break their purchases into smaller purchases and avoid commission fees.

It should also be noted that platformFee is later used in the calculation of the referrerReferralBonusand authorityReferralBonusin Premarket::_updateReferralBonus. Where the platformFee order is once again divided by at least 10. So these commissions have an even greater chance of zeroing out.

uint256 referrerReferralBonus = platformFee.mulDiv(
referralInfo.referrerRate,
Constants.REFERRAL_RATE_DECIMAL_SCALER,
Math.Rounding.Floor
);
...
uint256 authorityReferralBonus = platformFee.mulDiv(
referralInfo.authorityRate,
Constants.REFERRAL_RATE_DECIMAL_SCALER,
Math.Rounding.Floor
);

Impact

The vulnerability breaks protocol functionality and leads to incorrect business logic. However, this does not happen in all situations. Here are the conditions that must be in place for this to work.

  1. Collaterall token - low decimals (most likely USDC)

  2. The number of sold points must be a multiple of the price. The more valuable 1 point is, the more unlikely this vulnerability is.

severity: medium

Tools Used

Manual Review

Recommendations

Add a WAD multiplier that would equalise the difference in multiplicity.

Updates

Lead Judging Commences

0xnevi Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-PreMarkets-tradeTax-round-down-low-decimal

Valid medium, this will indeed cause a leakage (albeit requires relatively small amount of collateral transacted, and is most significant for lower decimal tokens (does not break ERC20 specifications), resulting in platFormFee rounding to zero and creater of offers not sending fees to capitalPool when `_depositTokenWhenCreateTaker` is invoked. For issues noting rounding directions, it will be low severity given the impact is not proven sufficiently with a PoC/numerical example and most rounding will not result in significant losses. I believe the most appropriate solution here is to increase scale of platFormFees scalar, but to make sure that overflows are considered for higher decimal tokens.

Support

FAQs

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