Summary
Wrong token is added to userTokenBalanceMap
due to incorrect argument in tokenManager::addTokenBalance()
call.
Vulnerability Details
The DeliveryPlace::settleAskTaker()
is supposed to called by a Ask type stock owner to settle points for a bid offer [that offer for which this stock was created]. This settleAskTaker()
is responsible to take pointTokens from the stock owner and add that in userTokenBalanceMap
for TokenBalanceType.PointToken. However while adding the balance in the mapping USDC token was used instead of Point token, as a result USDC token will be added in the mapping instead of Point token.
NOTE: To execute the PoC given below we need to fix a issue of this code, I already submitted the report regarding that issue, you can find that issue with this title: Call to settleAskTaker() will fail every time due to wrong authority check. In short you need to correct the authority check in settleAskTaker()
by changing it from offerInfo.authority
to stockInfo.authority
, here.I hope you fixed that issue, now lets run the PoC in Premarkets.t.sol contract:
function test_wrongToken() public {
deal(address(mockPointToken), address(user4), 100e18);
vm.startPrank(user);
preMarktes.createOffer(
CreateOfferParams(
marketPlace,
address(mockUSDCToken),
1000,
0.01 * 1e18,
12000,
300,
OfferType.Bid,
OfferSettleType.Turbo
)
);
vm.stopPrank();
vm.startPrank(user4);
address offerAddr = GenerateAddress.generateOfferAddress(0);
preMarktes.createTaker(offerAddr, 500);
address stock1Addr = GenerateAddress.generateStockAddress(1);
vm.stopPrank();
vm.startPrank(user1);
systemConfig.updateMarket(
"Backpack",
address(mockPointToken),
0.01 * 1e18,
block.timestamp - 1,
3600
);
systemConfig.updateMarketPlaceStatus(
"Backpack",
MarketPlaceStatus.AskSettling
);
vm.stopPrank();
vm.prank(user);
deliveryPlace.closeBidOffer(offerAddr);
vm.startPrank(user4);
mockPointToken.approve(address(tokenManager), 10000 * 10 ** 18);
console2.log(
"USDC token balance of user before settling: ",
mockUSDCToken.balanceOf(address(user))
);
console2.log(
"Point token balance of user before settling: ",
mockPointToken.balanceOf(address(user))
);
deliveryPlace.settleAskTaker(stock1Addr, 300);
vm.stopPrank();
uint ownerMakerRefund = tokenManager.userTokenBalanceMap(
address(user),
address(mockUSDCToken),
TokenBalanceType.MakerRefund
);
uint totalUSDCTokenForUser = ownerMakerRefund +
mockUSDCToken.balanceOf(address(user));
uint ownerPointToken = tokenManager.userTokenBalanceMap(
address(user),
address(mockPointToken),
TokenBalanceType.PointToken
);
uint totalPointTokenForUser = ownerPointToken +
mockPointToken.balanceOf(address(user));
console2.log(
"USDC token balance of user after settling: ",
totalUSDCTokenForUser
);
console2.log(
"Point token balance of user after settling: ",
totalPointTokenForUser
);
}
Logs:
USDC token balance of user before settling: 99999999990000000000000000
Point token balance of user before settling: 100000000000000000000000000
USDC token balance of user after settling: 100000000001000000000000000
Point token balance of user after settling: 100000000000000000000000000
As you can USDC balance was increased instead of Point token.
Impact
Wrong token will added to userTokenBalanceMap
mapping.
Tool Used
Manual review, Foundry
Recommendation
tokenManager.addTokenBalance(
TokenBalanceType.PointToken,
offerInfo.authority,
- makerInfo.tokenAddress,
+ marketPlaceInfo.tokenAddress,
settledPointTokenAmount
);
This is the log of same test after editing the code as above:
USDC token balance of user before settling: 99999999990000000000000000
Point token balance of user before settling: 100000000000000000000000000
USDC token balance of user after settling: 100000000001000000000000000
Point token balance of user after settling: 100000003000000000000000000
You can see the Point token balance was increased.
Related Links
https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/DeliveryPlace.sol#L384-L389