Tadle

Tadle
DeFi
30,000 USDC
View results
Submission Details
Severity: medium
Invalid

Platform Fees Can Be Evaded

Summary

Since platform fees are computed before applying an OfferInfo's collateralRate, users can craft offers which accrue negligible platform fees meanwhile evaluate to a rational getDepositAmount(OfferType,uint256,uint256,bool,Math.Rounding).

Vulnerability Details

The PreMarkets contract compute both the platformFee and tradeTax based upon the raw inbound depositAmount parameter:

/// @dev Transfer token from user to capital pool as collateral
uint256 depositAmount = _points.mulDiv(
offerInfo.amount,
offerInfo.points,
Math.Rounding.Ceil
);
uint256 platformFee = depositAmount.mulDiv(
platformFeeRate,
Constants.PLATFORM_FEE_DECIMAL_SCALER
);
uint256 tradeTax = depositAmount.mulDiv(
makerInfo.eachTradeTax,
Constants.EACH_TRADE_TAX_DECIMAL_SCALER
);

However, this depositAmount does not represent the value of the entire transaction, which can be amplified later.

In the call to _depositTokenWhenCreateTaker(uint256,uint256,uint256,MakerInfo,OfferInfo,ITokenManager) which follows immediately after computing the platform fees, we can see the inbound deposit amount can be amplified based upon the OfferInfo's collateralRate in the subsequent call to getDepositAmount(OfferType,uint256,uint256,bool,Math.Rounding):

uint256 transferAmount = OfferLibraries.getDepositAmount(
offerInfo.offerType,
offerInfo.collateralRate,
depositAmount,
false,
Math.Rounding.Ceil
); /// @audit transferAmount_can_be_amplified_by_collateralRate
transferAmount = transferAmount + platformFee + tradeTax;

Specifically:

function getDepositAmount(
OfferType _offerType,
uint256 _collateralRate,
uint256 _amount,
bool _isMaker,
Math.Rounding _rounding
) internal pure returns (uint256) {
/// @dev bid offer
if (_offerType == OfferType.Bid && _isMaker) {
return _amount; /// @audit returned_amount_equals_depositAmount
}
/// @dev ask order
if (_offerType == OfferType.Ask && !_isMaker) {
return _amount; /// @audit returned_amount_equals_depositAmount
}
return
Math.mulDiv(
_amount,
_collateralRate,
Constants.COLLATERAL_RATE_DECIMAL_SCALER,
_rounding
); /// @audit returned_amount_is_bigger_depositAmount
}

Note, it is important to emphasize that collateralRate expressly increases _amount, since when creating an offer:

if (params.collateralRate < Constants.COLLATERAL_RATE_DECIMAL_SCALER) { /// @audit must_be_over_unity
revert InvalidCollateralRate();
}

This means a user can express an extremely high collateralRate with a comparatively low (i.e. 1 wei) offer amount to reduce the protocol's fees at no intrinsic loss. This allows the user to procure a greater claim to the share of overall transaction value at expense of the protocol.

Impact

Users can subvert platform fees to gain an unfair share of overall transaction value.

Tools Used

Manual Review

Recommendations

Platform fees should be computed as a function of the evaluated transferAmount instead of the initial depositAmount:

uint256 transferAmount = OfferLibraries.getDepositAmount(
offerInfo.offerType,
offerInfo.collateralRate,
depositAmount,
false,
Math.Rounding.Ceil
);
uint256 platformFee = transferAmount.mulDiv( /// @audit guarantee_platformFee_has_fair_share
platformFeeRate,
Constants.PLATFORM_FEE_DECIMAL_SCALER
);
uint256 tradeTax = transferAmount.mulDiv( /// @audit guarantee_tradeTax_has_fair_share
makerInfo.eachTradeTax,
Constants.EACH_TRADE_TAX_DECIMAL_SCALER
);
Updates

Lead Judging Commences

0xnevi Lead Judge
10 months ago
0xnevi Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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