Summary
User will lose their collaterals when they aborts bid taker, due to the incorrect calculation of refunding amount.
Vulnerability Details
When user buys an ask offer from a maker, they need to deposit collaterals to create taker. Later if the maker abort the offer, the user can also abort the taker by calls abortBidTaker() and the user's collaterals will be refunded.
tokenManager.addTokenBalance(
TokenBalanceType.MakerRefund,
_msgSender(),
makerInfo.tokenAddress,
@> transferAmount
);
Unfortunately, the transferAmount is not correctly calculated.
uint256 depositAmount = stockInfo.points.mulDiv(
preOfferInfo.points,
preOfferInfo.amount,
Math.Rounding.Floor
);
uint256 transferAmount = OfferLibraries.getDepositAmount(
preOfferInfo.offerType,
preOfferInfo.collateralRate,
depositAmount,
false,
Math.Rounding.Floor
);
transferAmount is calculated based on depositAmount, and depositAmount is calculated as stockInfo.points * preOfferInfo.points / preOfferInfo.amount. Suppose stockInfo.points is , preOfferInfo.points is , the depositAmount will be , resulting in transferAmount is and user will not receive anying refunding.
Please copy the PoC code into PreMarkets.t.sol to verify:
function testAudit_UserLossesCollateralsWhenAbortBidTaker() public {
address auditMarketPlace = GenerateAddress.generateMarketPlaceAddress("AuditMarket");
vm.startPrank(user1);
systemConfig.createMarketPlace("AuditMarket", false);
vm.stopPrank();
address alice = makeAddr("Alice");
deal(address(mockUSDCToken), alice, 1200e18);
address bob = makeAddr("Bob");
deal(address(mockUSDCToken), bob, 103.5e18);
uint256 offerId = preMarktes.offerId();
address offerAddr = GenerateAddress.generateOfferAddress(offerId);
address stockAddr = GenerateAddress.generateStockAddress(offerId);
vm.startPrank(alice);
mockUSDCToken.approve(address(tokenManager), type(uint256).max);
preMarktes.createOffer(CreateOfferParams({
marketPlace: auditMarketPlace,
tokenAddress: address(mockUSDCToken),
points: 1000,
amount: 1000e18,
collateralRate: 12000,
eachTradeTax: 300,
offerType: OfferType.Ask,
offerSettleType: OfferSettleType.Turbo
}));
vm.stopPrank();
vm.startPrank(bob);
mockUSDCToken.approve(address(tokenManager), type(uint256).max);
preMarktes.createTaker(offerAddr, 100);
vm.stopPrank();
vm.prank(alice);
preMarktes.abortAskOffer(stockAddr, offerAddr);
address bobStockAddr = GenerateAddress.generateStockAddress(preMarktes.offerId() - 1);
StockInfo memory stockInfo = preMarktes.getStockInfo(bobStockAddr);
vm.prank(bob);
preMarktes.abortBidTaker(bobStockAddr, stockInfo.preOffer);
assertEq(tokenManager.userTokenBalanceMap(bob, address(mockUSDCToken), TokenBalanceType.MakerRefund), 0);
}
Impact
User loses all their collaterals.
Tools Used
Manual Review
Recommendations
The correct calculation of `depositAmount` should be:
uint256 depositAmount = stockInfo.points.mulDiv(
- preOfferInfo.points,
- preOfferInfo.amount,
+ preOfferInfo.amount,
+ preOfferInfo.points,
Math.Rounding.Floor
);