Tadle

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

Unused collateral for liquidating ask-offer makers remains stuck in the contract

Summary

If ask-offer makers fail to settle their points, the collateral corresponding to the unused points remains stuck in the contract and cannot be withdrawn or utilized because the liquidation process only addresses the collateral tied to used points, leaving the unused portion permanently inaccessible.

Vulnerability Details

Ask-offer makers deposit collateral equal to at least 100% of the offer amount. This collateral acts as a security measure and will be liquidated if the makers fail to settle their points to the buyers.

If an ask-offer maker does not settle their points during the settlement period, the contract owner can call settleAskMaker to forcefully settle the offer, allowing buyers to liquidate the offer maker's collateral:

function settleAskMaker(address _offer, uint256 _settledPoints) external {
// ...
if (status == MarketPlaceStatus.AskSettling) {
if (_msgSender() != offerInfo.authority) {
revert Errors.Unauthorized();
}
>>> } else {
if (_msgSender() != owner()) {
revert Errors.Unauthorized();
}
if (_settledPoints > 0) {
revert InvalidPoints();
}
}
if (_settledPoints == offerInfo.usedPoints) {// ...} // @audit will not enter this block
IPerMarkets perMarkets = tadleFactory.getPerMarkets();
>>> perMarkets.settledAskOffer( // @audit making the offer's status settled
_offer,
_settledPoints,
settledPointTokenAmount
);
}

Subsequently, offer takers can call closeBidTaker to liquidate the offer's collateral and be refunded the value they deposited to buy the points:

function closeBidTaker(address _stock) external {
// ...
if (offerInfo.offerStatus != OfferStatus.Settled) { // @audit the offer is already settled by the owner
revert InvalidOfferStatus();
}
// ...
uint256 collateralFee;
if (offerInfo.usedPoints > offerInfo.settledPoints) {
if (offerInfo.offerStatus == OfferStatus.Virgin) {//...} // @audit useless block, as status is already settled
else {
uint256 usedAmount = offerInfo.amount.mulDiv(
offerInfo.usedPoints,
offerInfo.points,
Math.Rounding.Floor
);
>>> collateralFee = OfferLibraries.getDepositAmount(
offerInfo.offerType,
offerInfo.collateralRate,
usedAmount,
true,
Math.Rounding.Floor
);
}
}
>>> uint256 userCollateralFee = collateralFee.mulDiv(
userRemainingPoints,
offerInfo.usedPoints,
Math.Rounding.Floor
);
>>> tokenManager.addTokenBalance(
TokenBalanceType.RemainingCash,
_msgSender(),
makerInfo.tokenAddress,
userCollateralFee
);
// ...
}

In the case that an ask-offer maker does not settle their points, the function calculates the collateral amount to be liquidated based on the offer's used points:

uint256 usedAmount = offerInfo.amount.mulDiv(
offerInfo.usedPoints,
offerInfo.points,
Math.Rounding.Floor
);
collateralFee = OfferLibraries.getDepositAmount(
offerInfo.offerType,
offerInfo.collateralRate,
usedAmount,
true,
Math.Rounding.Floor
);

The buyer is then refunded proportionally to the total collateral amount to be liquidated, based on his deposit:

uint256 userCollateralFee = collateralFee.mulDiv(
userRemainingPoints,
offerInfo.usedPoints,
Math.Rounding.Floor
);
tokenManager.addTokenBalance(
TokenBalanceType.RemainingCash,
_msgSender(),
makerInfo.tokenAddress,
userCollateralFee
);

The problem is that neither the contract nor the offer maker can withdraw or use the collateral corresponding to the unused points, as this collateral will never be liquidated. Consequently, if offer makers do not settle their points, the portion of the collateral corresponding to the unused points will remain stuck in the contract and can never be withdrawn.

Note that the ask-offer maker can not call PreMarket::closeOffer to reclaim the collateral associated with the unused points because the offer status is already Settled

Proof Of Concept

Consider the following example:

  1. Alice, a market maker, lists 1,000 points for sale at 1,000` as collateral.

  2. Bob, a buyer, purchases 500 points from Alice for $500.

  3. Cathy buys 200 points from Alice for $200.

  4. The market owner updates the market and sets the TGE, initiating the settlement period.

  5. Alice, for whatever reason, fails to settle her points during the settlement period.

  6. After the settlement period ends, the owner calls settleAskMaker to forcefully settle Alice's offer. This action updates the offer's status without actually settling the points.

  7. As a result of Alice’s failure to settle her points, only $700 of her collateral is used for liquidation according to the following logic:

    uint256 usedAmount = offerInfo.amount.mulDiv(
    offerInfo.usedPoints,
    offerInfo.points,
    Math.Rounding.Floor
    );
    collateralFee = OfferLibraries.getDepositAmount(
    offerInfo.offerType,
    offerInfo.collateralRate,
    usedAmount,
    true,
    Math.Rounding.Floor
    )

    7.1 Bob and Cathy then call closeBidTaker to receive refunds of $500 and $200 respectively, as calculated by:

    uint256 userCollateralFee = collateralFee.mulDiv(
    userRemainingPoints,
    offerInfo.usedPoints,
    Math.Rounding.Floor
    );
    tokenManager.addTokenBalance(
    TokenBalanceType.RemainingCash,
    _msgSender(),
    makerInfo.tokenAddress,
    userCollateralFee
    );

However, the collateral corresponding to the unused points ($300) is now stuck in the contract. Neither Alice nor the contract can withdraw or utilize this amount, rendering it inaccessible.

Impact

If offer makers do not settle their points, the collateral corresponding to the unused points will remain stuck in the contract and cannot be withdrawn or used.

Tools Used

Manual Review

Recommendations

For cases where ask-offer points are not settled, consider adding a function that allows ask-offer makers or the contract owner to withdraw and utilize the collateral corresponding to the unused points.

Updates

Lead Judging Commences

0xnevi Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Design choice
Assigned finding tags:

[invalid] finding-DeliveryPlace-owner-do-not-call-settleAskMaker

Invalid, the makers are incentivized to settle offers to earn maker bonuses when subsequent takers and makers make trade using the original collateral put up for points as well as get back their initial collateral. Additionally, if they do not settle on time, they will lose all their initial collateral, forcing the `owner` to come in and perform the settlement and retrieving that collateral. This is noted as a design decision [here](https://tadle.gitbook.io/tadle/how-tadle-works/features-and-terminologies/settlement-and-collateral-rate) If all else fails, the `owner` can come in to settle as seen [here](https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/DeliveryPlace.sol#L254-L256) and [here](https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/DeliveryPlace.sol#L365-L367) offers to allow closing offers and subsequently allowing refunds. I acknowledge that perhaps a more decentralized

Appeal created

0xbrivan2 Submitter
12 months ago
0xnevi Lead Judge
11 months ago
0xnevi Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Design choice
Assigned finding tags:

[invalid] finding-DeliveryPlace-owner-do-not-call-settleAskMaker

Invalid, the makers are incentivized to settle offers to earn maker bonuses when subsequent takers and makers make trade using the original collateral put up for points as well as get back their initial collateral. Additionally, if they do not settle on time, they will lose all their initial collateral, forcing the `owner` to come in and perform the settlement and retrieving that collateral. This is noted as a design decision [here](https://tadle.gitbook.io/tadle/how-tadle-works/features-and-terminologies/settlement-and-collateral-rate) If all else fails, the `owner` can come in to settle as seen [here](https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/DeliveryPlace.sol#L254-L256) and [here](https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/DeliveryPlace.sol#L365-L367) offers to allow closing offers and subsequently allowing refunds. I acknowledge that perhaps a more decentralized

Support

FAQs

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