Summary
A critical issue has been identified in the `AbortBidTaker` function, where an incorrect deposit amount calculation results in users receiving the wrong amount of funds when they abort their order. This miscalculation could lead to users losing funds or receiving an incorrect refund.
Vulnerability Details
The vulnerability arises from an error in the formula used to calculate the deposit amount when returning funds to the user. The current implementation uses the following formula:
* @notice abort bid taker
* @param _stock stock address
* @param _offer offer address
* @notice Only offer owner can abort bid taker
* @dev Only offer abort status is aborted can be aborted
* @dev Update stock authority refund amount
*/
function abortBidTaker(address _stock, address _offer) external {
StockInfo storage stockInfo = stockInfoMap[_stock];
OfferInfo storage preOfferInfo = offerInfoMap[_offer];
if (stockInfo.authority != _msgSender()) {
revert Errors.Unauthorized();
}
if (stockInfo.preOffer != _offer) {
revert InvalidOfferAccount(stockInfo.preOffer, _offer);
}
if (stockInfo.stockStatus != StockStatus.Initialized) {
revert InvalidStockStatus(
StockStatus.Initialized,
stockInfo.stockStatus
);
}
if (preOfferInfo.abortOfferStatus != AbortOfferStatus.Aborted) {
revert InvalidAbortOfferStatus(
AbortOfferStatus.Aborted,
preOfferInfo.abortOfferStatus
);
}
@audit>> Wrong Application >>> uint256 depositAmount = stockInfo.points.mulDiv(
@audit>> Wrong Application >>> preOfferInfo.points,
@audit>> Wrong Application >>> preOfferInfo.amount,
Math.Rounding.Floor
);
uint256 transferAmount = OfferLibraries.getDepositAmount(
preOfferInfo.offerType,
preOfferInfo.collateralRate,
depositAmount,
false,
Math.Rounding.Floor
);
MakerInfo storage makerInfo = makerInfoMap[preOfferInfo.maker];
ITokenManager tokenManager = tadleFactory.getTokenManager();
tokenManager.addTokenBalance(
TokenBalanceType.MakerRefund,
_msgSender(),
makerInfo.tokenAddress,
transferAmount
);
stockInfo.stockStatus = StockStatus.Finished;
emit AbortBidTaker(_offer, _msgSender());
}
This formula incorrectly calculates the deposit amount as `(stockInfo.points * preOfferInfo.points) / preOfferInfo.amount`.
This leads to the user receiving an incorrect refund amount when they abort their order. The correct calculation should instead be based on obtaining the fraction of the amount to be added back to the taker’s balance, similar to the formula used when the user initially opened the order:
* @notice Create taker
* @param _offer offer address
* @param _points points
*/
function createTaker(address _offer, uint256 _points) external payable {
-------------------------------------
@audit>> Correct formula when user Opened the taker order >>>> uint256 depositAmount = _points.mulDiv(
@audit>> Correct formula when user Opened the taker order >>>> offerInfo.amount,
@audit>> Correct formula when user Opened the taker order >>>> offerInfo.points,
Math.Rounding.Ceil
);
```
The discrepancy between these two formulas leads to errors in the deposit amount calculation, impacting the accuracy of the refund sent back to the user.
Impact
This vulnerability could result in users receiving an incorrect amount of funds when they abort their `BidTakerOrder`.
Tools Used
- Manual code review
Recommendations
To resolve this issue, the deposit amount formula should be corrected to ensure accurate calculations when funds are returned to the user. The recommended formula is as follows:
* @notice abort bid taker
* @param _stock stock address
* @param _offer offer address
* @notice Only offer owner can abort bid taker
* @dev Only offer abort status is aborted can be aborted
* @dev Update stock authority refund amount
*/
function abortBidTaker(address _stock, address _offer) external {
StockInfo storage stockInfo = stockInfoMap[_stock];
OfferInfo storage preOfferInfo = offerInfoMap[_offer];
if (stockInfo.authority != _msgSender()) {
revert Errors.Unauthorized();
}
if (stockInfo.preOffer != _offer) {
revert InvalidOfferAccount(stockInfo.preOffer, _offer);
}
if (stockInfo.stockStatus != StockStatus.Initialized) {
revert InvalidStockStatus(
StockStatus.Initialized,
stockInfo.stockStatus
);
}
if (preOfferInfo.abortOfferStatus != AbortOfferStatus.Aborted) {
revert InvalidAbortOfferStatus(
AbortOfferStatus.Aborted,
preOfferInfo.abortOfferStatus
);
}
-- uint256 depositAmount = stockInfo.points.mulDiv(
-- preOfferInfo.points,
-- preOfferInfo.amount,
-- Math.Rounding.Floor
-- );
++ uint256 depositAmount = stockInfo.points.mulDiv(
++ preOfferInfo.amount,
++ preOfferInfo.points,
++ Math.Rounding.Floor
);
This correction will ensure that the correct fraction of the amount is added back to the taker’s balance, thereby preventing any discrepancies in the amount returned to the user.