Github link
https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/PreMarkets.sol#L607
Summary
The PreMarkets.abortAskOffer
function calculates the totalDepositAmount
incorrectly.
As a result, more collateral is refunded to offer authority.
Vulnerability Details
In the PreMarkets.abortAskOffer
function, it refunds collaterals for unused points from L624.
transferAmount
is the seller deposited collateral from L595 and totalDepositAmount
must be collateral amount for used points.
https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/PreMarkets.sol#L595-L630
L595: uint256 transferAmount = OfferLibraries.getDepositAmount(
offerInfo.offerType,
offerInfo.collateralRate,
remainingAmount,
true,
Math.Rounding.Floor
);
uint256 totalUsedAmount = offerInfo.amount.mulDiv(
offerInfo.usedPoints,
offerInfo.points,
Math.Rounding.Ceil
);
uint256 totalDepositAmount = OfferLibraries.getDepositAmount(
offerInfo.offerType,
offerInfo.collateralRate,
totalUsedAmount,
L611: false,
Math.Rounding.Ceil
);
uint256 makerRefundAmount;
if (transferAmount > totalDepositAmount) {
makerRefundAmount = transferAmount - totalDepositAmount;
} else {
makerRefundAmount = 0;
}
ITokenManager tokenManager = tadleFactory.getTokenManager();
L624: tokenManager.addTokenBalance(
TokenBalanceType.MakerRefund,
_msgSender(),
makerInfo.tokenAddress,
makerRefundAmount
);
totalDepositAmount
is calculated using _offerType
parameter as OfferType.Ask
and _isMaker
parameter as false
from L611.
Thus, the OfferLibraries.getDepositAmount
function returns _amount
and this means that totalDepositAmount
is just same as totalUsedAmount
, not collateral amount for used points.
https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/libraries/OfferLibraries.sol#L27-L51
function getDepositAmount(
OfferType _offerType,
uint256 _collateralRate,
uint256 _amount,
bool _isMaker,
Math.Rounding _rounding
) internal pure returns (uint256) {
if (_offerType == OfferType.Bid && _isMaker) {
return _amount;
}
L40: if (_offerType == OfferType.Ask && !_isMaker) {
return _amount;
}
return
Math.mulDiv(
_amount,
_collateralRate,
Constants.COLLATERAL_RATE_DECIMAL_SCALER,
_rounding
);
}
As a result, makerRefundAmount
is greater than collateral amount for unused points.
Impact
This causes the protocol's loss of funds.
Tools Used
Manual Review
Recommendations
It is recommended to change the code as following:
https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/PreMarkets.sol#L349
uint256 totalDepositAmount = OfferLibraries.getDepositAmount(
offerInfo.offerType,
offerInfo.collateralRate,
totalUsedAmount,
- false,
+ true,
Math.Rounding.Ceil
);