Tadle

Tadle
DeFi
30,000 USDC
View results
Submission Details
Severity: high
Valid

Buyer/Bider receives `0(zero)` collateralToken back when they `abortBidTaker()` due to wrong calculation of `depositAmount`

Summary

Buyer/Bider receives 0(zero) collateralToken back when they abortBidTaker() due to wrong calculation of depositAmount

Vulnerability Details

A user can create an ask offer using preMarket:createOffer(), then buyer/biders can buy those points using preMarket:createTaker() after paying collateralToken. Also offerOwner can abort the offer using preMarket:abortAskOffer().

Once the offer is aborted, buyer/bider can also abort their bidTaker using preMarket:abortBidTaker(), receiving their collateralToken back which they paid while creating taker. Now the problem is they receives 0(zero) collateralToken back due to wrong calculation of depositAmount in preMarket:abortBidTaker()

For calculating depostitAmount, stockInfo.points & preOfferInfo.points are multiplied(which are simple numbers) and divided by preOfferInfo.amount(which is in 18 decimals). As result, depositAmount becomes 0(zero) due to rounding

function abortBidTaker(address _stock, address _offer) external {
...
@> uint256 depositAmount = stockInfo.points.mulDiv(preOfferInfo.points, preOfferInfo.amount, Math.Rounding.Floor);
uint256 transferAmount = OfferLibraries.getDepositAmount(
preOfferInfo.offerType, preOfferInfo.collateralRate, depositAmount, false, Math.Rounding.Floor
);
//@audit here only buyer ko fund mil raha hai but maker ko uska initial Deposit kaha mila ie stuck kar jayega
MakerInfo storage makerInfo = makerInfoMap[preOfferInfo.maker];
ITokenManager tokenManager = tadleFactory.getTokenManager();
@> tokenManager.addTokenBalance(TokenBalanceType.MakerRefund, _msgSender(), makerInfo.tokenAddress, transferAmount);
...
}

//Here is PoC which shows the above situation

function test_buyerReceivesZeroCollateralToken() public {
//User created an ask offer for 1000e18 collateralToken
vm.startPrank(user);
preMarktes.createOffer(
CreateOfferParams(
marketPlace, address(mockUSDCToken), 1000, 1000e18, 10000, 300, OfferType.Ask, OfferSettleType.Turbo
)
);
vm.stopPrank();
//User2 bought all points paying 1000e18 collateralToken
vm.prank(user2);
address offerAddr = GenerateAddress.generateOfferAddress(0);
preMarktes.createTaker(offerAddr, 1000);
//User aborted the offer
vm.prank(user);
address stockAddr = GenerateAddress.generateStockAddress(0);
preMarktes.abortAskOffer(stockAddr, offerAddr);
//User2 also aborted his bidTaker
vm.prank(user2);
address stock1Addr = GenerateAddress.generateStockAddress(1);
preMarktes.abortBidTaker(stock1Addr, offerAddr);
//Refund of user2 is 0 instead of 1000e18
uint256 makerRefund =
tokenManager.userTokenBalanceMap(user2, address(mockUSDCToken), TokenBalanceType.MakerRefund);
assertEq(makerRefund, 0);
}

Impact

Buyer/Bider loss all his collateralToken if offer is aborted

Tools Used

Manual Review

Recommendations

Multiply preOfferInfo.amount & stockInfo.points then divide them with preOfferInfo.points

- uint256 depositAmount = stockInfo.points.mulDiv(preOfferInfo.points, preOfferInfo.amount, Math.Rounding.Floor);
+ uint256 depositAmount = preOfferInfo.amount.mulDiv(stockInfo.points, preOfferInfo.points, Math.Rounding.Floor);
Updates

Lead Judging Commences

0xnevi Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-PreMarkets-abortBidTaker-amount-wrong-StockInfo-points

Valid high severity, due to incorrect computation of `depositAmount` within `abortBidTaker`, when aborting bid offers created by takers, the collateral refund will be completely wrong for the taker, and depending on the difference between the value of `points` and `amount`, it can possibly even round down to zero, causing definite loss of funds. If not, if points were worth less than the collateral, this could instead be used to drain the CapitalPool contract instead.

Support

FAQs

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