Tadle

Tadle
DeFiFoundry
27,750 USDC
View results
Submission Details
Severity: low
Invalid

Inability of Last Taker to Retrieve Funds after Offer Cancellation

Summary

The PreMarktes::abortAskOffer function allows the original maker to cancel an offer and retrieve their deposited funds. However, a critical vulnerability has been identified in the system where, if the original maker cancels an offer, the last taker (the user who most recently bought a listed point token) is unable to retrieve their deposited funds. This issue arises because the abortBidTaker function, which is required to release the taker's funds, can only be called by the first taker (referred to as the stock authority). This vulnerability leads to the permanent loss of funds for the last taker, resulting in financial damage and a severe breach of trust in the platform.

Vulnerability Details

The last taker, who buys a listed point token, is unable to call the abortBidTaker function to retrieve their deposited funds if the original maker cancels the offer using abortAskOffer. The system design restricts the authority to call abortBidTaker only to the first taker (taker that listed the offer), leaving the last taker with no recourse to recover their funds.

The design flaw in the contract means that the last taker remains unable to retrieve their funds, despite the function being intended to handle bid cancellations.

POC

function test_Abort() public {
vm.startPrank(user);
preMarktes.createOffer(
CreateOfferParams(
marketPlace, address(mockUSDCToken), 1000, 1000 * 1e18, 12000, 300, OfferType.Ask, OfferSettleType.Turbo
)
);
address offerAddr = GenerateAddress.generateOfferAddress(0);
address stockAddr = GenerateAddress.generateStockAddress(0);
vm.stopPrank();
vm.startPrank(user3);
mockUSDCToken.approve(address(tokenManager), type(uint256).max);
preMarktes.createTaker(offerAddr, 1000);
address stock1Addr = GenerateAddress.generateStockAddress(1);
preMarktes.listOffer(stock1Addr, 2000 * 1e18, 12000);
vm.stopPrank();
vm.startPrank(user4);
mockUSDCToken.approve(address(tokenManager), type(uint256).max);
address offerAddr1 = GenerateAddress.generateOfferAddress(1);
preMarktes.createTaker(offerAddr1, 1000);
vm.stopPrank();
vm.startPrank(user);
preMarktes.abortAskOffer(stockAddr, offerAddr);
vm.stopPrank();
// this call returns an error - Unauthorized()
vm.startPrank(user4);
vm.expectRevert();
preMarktes.abortBidTaker(stock1Addr, offerAddr1);
vm.stopPrank();
}

Impact

This lack of authorization leads to a situation where the last taker’s funds are effectively trapped in the contract with no way to be retrieved. This presents a significant financial risk to users, especially those who are not the initial participants in the offer.

The last taker is placed in a precarious position where they are exposed to the risk of losing their entire deposited amount if the original maker cancels the offer.

Tools Used

Manual Review

Recommendations

Allow the last taker to be able to abortBidTaker, so the last taker can get back deposited funds

Updates

Lead Judging Commences

0xnevi Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

[invalid] finding-PreMarkets-abortBidTaker-wrong-stock-authority

Invalid. 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). Hence, we should verify `stockInfoMap`, regardless of the taker order being a ASK (selling points) or BID (buying points) taker order, so there is no issue here, other than documentation error

Support

FAQs

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