Tadle

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

Ask Taker is unable to settle bid offer, breaking protocol functionality

Summary

Once MarketPlaceStatus has been set to MarketPlaceStatus.AskSettling, an ask Taker should be able to call settleAskTaker() and transfer the points they've agreed to sell to a bid Maker.

A logical error in the code causes this to revert with the following error: Errors.Unauthorized();

Vulnerability Details

The logical error requires the msg.sender of settleAskTaker() to be the offer creator (i.e. maker):

function settleAskTaker(address _stock, uint256 _settledPoints) external {
...
if (status == MarketPlaceStatus.AskSettling) {
if (_msgSender() != offerInfo.authority) {
revert Errors.Unauthorized();
}
}
...
}

https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/DeliveryPlace.sol#L361C13-L362C46

Here's a POC (add to PreMarket.t.sol):

import {MarketPlaceStatus, MarketPlaceInfo, ReferralInfo, ISystemConfig} from "../src/interfaces/ISystemConfig.sol";
function testAskTakerCannotSettleBidOffer() public {
// 1. User creates a bid offer
vm.startPrank(user);
address offerAddr0 = GenerateAddress.generateOfferAddress(0);
preMarktes.createOffer(
CreateOfferParams(
marketPlace,
address(mockUSDCToken),
1000,
20_000_000e18,
12000,
300,
OfferType.Bid,
OfferSettleType.Protected
)
);
vm.stopPrank();
// 2. User2 (i.e. taker) takes the entire offer, agreeing to sell 1000 points to User
vm.startPrank(user2);
mockUSDCToken.approve(address(tokenManager), type(uint256).max);
address takerStockAddr = GenerateAddress.generateStockAddress(1);
preMarktes.createTaker(offerAddr0, 1000);
vm.stopPrank();
// 3. Markerplace status changes to settling (TGE date is reached)
vm.startPrank(user1); // admin
systemConfig.updateMarketPlaceStatus("Backpack", MarketPlaceStatus.AskSettling);
vm.stopPrank();
// 4. User2 (taker) tries to settle, but can't because of incorrect permission requirements
vm.startPrank(user2);
mockPointToken.approve(address(tokenManager), type(uint256).max);
bytes4 selector = bytes4(keccak256("Unauthorized()"));
vm.expectRevert(abi.encodeWithSelector(selector));
deliveryPlace.settleAskTaker(takerStockAddr, 1000);
vm.stopPrank();
}

Impact

Ask Takers are unable to settle bid offers severely disrupting the protocol's functionality.

Tools Used

Manual Review / Foundry

Recommendations

On line 361, update offerInfo.authority to stockInfo.authority

https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/DeliveryPlace.sol#L361

Updates

Lead Judging Commences

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

finding-PreMarkets-settleAskTaker-wrong-stock-authority

Valid high severity, when taker offers are created pointing to a `offer`, the relevant `stockInfoMap` offers are created with the owner of the offer aka `authority`, set as the creater of the offer, as seen [here](https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/PreMarkets.sol#L245). Because of the wrong check within settleAskTaker, it will permanently DoS the final settlement functionality for taker offers for the maker that listed the original offer, essentially bricking the whole functionality of the market i.e. maker will always get refunded the original collateral, and takers will never be able to transact the original points put up by the maker. This occurs regardless of market mode.

Support

FAQs

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