Tadle

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

Missing check in `DeliveryPlace.settleAskMaker()` for `Turbo` markets allow fund exploitation from protocol.

Summary

There is a missing check in the DeliveryPlace.settleAskMaker() function that rechecks if the offer's settlement type is Protected or if the offer is a Turbo market origin offer.

Without this check, anyone can trick the system into extracting collateral from an offer created from a Turbo original offer.

Vulnerability Details

Offers created from a Turbo offer are not required to deposit collateral in the same way as offers in a Protected market. This is important to remember when a function within a system is performing a refund of collateral during its execution.

As seen in the PreMarkets.closeOffer() function, the check to not refund for non-origin Turbo offers is in place:

File: PreMarkets.sol
433: /**
434: * @dev update refund token from capital pool to balance
435: * @dev offer settle type is protected or original offer
436: */
437: if (
438: makerInfo.offerSettleType == OfferSettleType.Protected ||
439: stockInfo.preOffer == address(0x0)
440: ) {

But this important check is missed in the DeliveryPlace.settleAskMaker() function. This can be leveraged by an attacker; here's how:

  1. An attacker, as a Taker, takes an Ask offer from a Turbo market for 1 USDC.

  2. The attacker relists that offer with an unrealistic valuation of 10,000 USDC. They are not obligated to deposit any collateral, and no one will take such an offer from them.

  3. When the time of TGE arrives, they will leverage the issue in the DeliveryPlace.settleAskMaker() function.

  4. After calling it, as shown in the code below, they will be refunded:

File: DeliveryPlace.sol
276: if (_settledPoints == offerInfo.usedPoints) { // <== attacker will settle for usedPoints amount
277: if (offerInfo.offerStatus == OfferStatus.Virgin) {
278: makerRefundAmount = OfferLibraries.getDepositAmount(
279: offerInfo.offerType,
280: offerInfo.collateralRate,
281: offerInfo.amount, // <== inflated amount
282: true,
283: Math.Rounding.Floor
284: );
285: } else {
...
301: tokenManager.addTokenBalance( // <== attacker refunded for offer without collateral
302: TokenBalanceType.SalesRevenue,
303: _msgSender(),
304: makerInfo.tokenAddress,
305: makerRefundAmount
306: );

As can be seen, the attacker can wait right before any TGE, craft a Turbo market, create Ask offers as a Maker, and take them as a Taker with inflated collateral in the relisted offers. They can reproduce this for any whitelisted token and, after the TGE, drain all funds from the CapitalPool contract.

Impact

This vulnerability can result in the loss of all funds from the CapitalPool contract.

Tools Used

Manual review.

Recommendations

Add a check in the DeliveryPlace.settleAskMaker() function to ensure that offers are not Turbo and, if they are, only allow the settlement of the original offer.

if (offerInfo.offerType == OfferType.Bid) {
revert InvalidOfferType(OfferType.Ask, OfferType.Bid);
}
+
+ if (
+ makerInfo.offerSettleType == OfferSettleType.Turbo &&
+ _offer != makerInfo.originOffer
+ ) {
+ revert InvalidOffer();
+ }
+
if (
Updates

Lead Judging Commences

0xnevi Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-Premarkets-listOffer-turbo-settleAskMaker-exploit-settlement

Valid high severity, this allows resellers listing offers via `listOffer/relistOffer` to game the system. Based on the inherent design of Turbo mode not requiring takers making ask offers for the original maker offer to deposit collateral, the wrong refund of collateral to takers even when they did not deposit collateral due to turbo mode during settleAskMaker allows possible draining of pools.

Support

FAQs

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