Tadle

Tadle
DeFi
30,000 USDC
View results
Submission Details
Severity: low
Invalid

Inconsistency in deposited amount and refund amount in DeliveryPlace.settleAskTaker leads to loss of funds

Summary

The DeliveryPlace.settleAskTaker function is called by the taker who has been matched with a bid maker to provide the necessary tokens to complete the transaction. When this happens, the taker receives their collateral back. The problem is that there is an inconsistency between the amount of collateral that is deposited and the amount that is refunded. The amount refunded during settleAskOffer is multiplied by the collateralRate and is therefore larger than the amount deposited in createTaker(), which is not multiplied by the collateral rate. As a result, the ask taker receives more than they deposited and can drain the tokens locked in the protocol.

Vulnerability Details

I am attaching the two code fragments where the described calculations are made, along with a POC that demonstrates the described scenario.

uint256 collateralFee = OfferLibraries.getDepositAmount(
offerInfo.offerType,
offerInfo.collateralRate,
stockInfo.amount,
false,
Math.Rounding.Floor
);

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

uint256 depositAmount = _points.mulDiv(
offerInfo.amount,
offerInfo.points,
Math.Rounding.Ceil
);

https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/PreMarkets.sol#L212-L216

It is important to also consider the OfferLibraries.getDepositAmount function, as it returns different values depending on the value of the maker flag and the type of offer (bid/ask).

POC

function test_wrong_balance_create_bid_offer_turbo_usdc() public {
vm.startPrank(user);
preMarktes.createOffer(
CreateOfferParams(
marketPlace,
address(mockUSDCToken),
1000,
0.01 * 1e18,
12000,
300,
OfferType.Bid,
OfferSettleType.Turbo
)
);
vm.stopPrank();
vm.prank(user2);
address offerAddr = GenerateAddress.generateOfferAddress(0);
preMarktes.createTaker(offerAddr, 500);
address stock1Addr = GenerateAddress.generateStockAddress(1);
vm.stopPrank();
vm.prank(user1);
systemConfig.updateMarket(
"Backpack",
address(mockPointToken),
0.01 * 1e18,
block.timestamp - 1,
3600
);
vm.startPrank(user2);
mockPointToken.approve(address(tokenManager), 10000 * 10 ** 18);
deliveryPlace.settleAskTaker(stock1Addr, 500);
vm.stopPrank();
uint256 user2BalanceAfter = mockUSDCToken.balanceOf(user2);
uint256 remainingBalance = tokenManager.userTokenBalanceMap(
address(user2),
address(mockUSDCToken),
TokenBalanceType.RemainingCash
);
(,,,,,,,uint256 depositAmount,) = preMarktes.stockInfoMap(stock1Addr);
console.log("User 2 deposit amount: %d", depositAmount);
console.log("User 2 TokenBalanceType.RemainingCash: %d", remainingBalance);
}
User 2 deposit amount: 5000000000000000
User 2 TokenBalanceType.RemainingCash: 6000000000000000

As you can see both values are different as explained in the report. To make this report work it is necessary to fix the issue from one of my other reports named "Broken access control in DeliveryPlace.settleAskTaker() leads to loss of funds".

Impact

Loss of funds for the protocol and its users

Tools Used

Manual review

Recommendations

This inconsistency needs to be fixed by either using collateralRate in both cases or not using it in either case.

Updates

Lead Judging Commences

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

[invalid] finding-PreMarkets-collateralRate-unupdated-balance

Valid high, the additional collateral based on collateralRate is not updated to taker balance for protected mode. This results in incorrect collateral refunded to taker during settlement.

Appeal created

cryptomoon Auditor
10 months ago
0xnevi Lead Judge
10 months ago
0xnevi Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

[invalid] finding-PreMarkets-collateralRate-unupdated-balance

Valid high, the additional collateral based on collateralRate is not updated to taker balance for protected mode. This results in incorrect collateral refunded to taker during settlement.

Support

FAQs

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