Tadle

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

Incorrect math in `PreMarkets::abortBidTaker` function may lead to user fund loss

Summary

A mathematical error in the PreMarkets::abortBidTaker function results in the incorrect calculation of the amount returned to bid takers when an offer is aborted. This miscalculation can either lead to excess funds being returned to the bid taker—causing a shortage of tokens for other users—or to an insufficient amount being returned, effectively reducing the bid taker's collateral.

Vulnerability Details

This function allows bid takers to reclaim their deposited amount when the associated offer is aborted. The returned amount is intended to be proportional to the bid taker's share of points relative to the total points in the offer. However, the current formula used to calculate this amount is flawed:

This formula is implemented in the following code snippet:

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

Impact

The incorrect formula results in disproportionate returns based on the offer's point-to-amount ratio. For offers with a high ratio (cheap offers), the function may return excess funds to the bid taker, leading to a deficit in the remaining tokens available for other users. Conversely, for offers with a low ratio (expensive offers), the bid taker may receive less than they are entitled to, effectively losing part of their collateral.

See example for a cheap offer:

function test_abort_turbo_offer() public {
vm.startPrank(user);
preMarktes.createOffer(
CreateOfferParams(
marketPlace,
address(mockUSDCToken),
1000,
0.01 * 1e18,
12000,
300,
OfferType.Ask,
OfferSettleType.Turbo
)
);
vm.stopPrank();
vm.startPrank(user1);
mockUSDCToken.approve(address(tokenManager), type(uint256).max);
address stockAddr = GenerateAddress.generateStockAddress(0);
address offerAddr = GenerateAddress.generateOfferAddress(0);
preMarktes.createTaker(offerAddr, 500);
vm.stopPrank();
vm.prank(user);
preMarktes.abortAskOffer(stockAddr, offerAddr);
vm.startPrank(user1);
address stock1Addr = GenerateAddress.generateStockAddress(1);
preMarktes.abortBidTaker(stock1Addr, offerAddr);
uint256 balanceUser1 = tokenManager.userTokenBalanceMap(
user1,
address(mockUSDCToken),
TokenBalanceType.MakerRefund
);
// 500*1000/1e16 = 0
assertEq(balanceUser1, 0);
vm.stopPrank();
}

Tools Used

Manual review.

Recommendations

Use correct formula:

Updates

Lead Judging Commences

0xnevi Lead Judge over 1 year 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.

Give us feedback!