Summary
The user who miscalculates and sends more ETH than necessary to list or relist their offer loses the unnecessary portion.
Vulnerability Details
During the listing or relisting of an offer, there is no check to verify if the amount of ETH sent is the necessary amount. As a result, a user who sends more ETH than required loses the surplus ETH they sent.
POC
Add the code below to the Test contract PreMarketsTest : PreMarketsTest.t.sol
function test_send_more_eth() public {
vm.startPrank(user);
preMarktes.createOffer{value: 0.012 * 1e18}(
CreateOfferParams(
marketPlace, address(weth9), 1000, 0.01 * 1e18, 12000, 300, OfferType.Ask, OfferSettleType.Protected
)
);
address offerAddr = GenerateAddress.generateOfferAddress(0);
preMarktes.createTaker{value: 0.005175 * 1e18}(offerAddr, 500);
address stock1Addr = GenerateAddress.generateStockAddress(1);
preMarktes.listOffer{value: 1.0072 * 1e18}(stock1Addr, 0.006 * 1e18, 12000);
address offer1Addr = GenerateAddress.generateOfferAddress(1);
preMarktes.closeOffer(stock1Addr, offer1Addr);
preMarktes.relistOffer{value: 1.0072 * 1e18}(stock1Addr, offer1Addr);
preMarktes.closeOffer(stock1Addr, offer1Addr);
uint256 balance = tokenManager.userTokenBalanceMap(user, address(weth9), TokenBalanceType.MakerRefund);
uint256 amountSent = 1.0072 * 1e18 + 1.0072 * 1e18;
assertEq(balance, amountSent,"Amount sent should be equal to the balance to refund");
}
Run the command
forge test --mc PreMarkets --mt test_send_more_eth
We get the result
[FAIL. Reason: Amount sent should be equal to the balance to refund: 14400000000000000 != 2014400000000000000] test_send_more_eth() (gas: 1262811)
Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 12.76ms (2.67ms CPU time)
Ran 1 test suite in 161.32ms (12.76ms CPU time): 0 tests passed, 1 failed, 0 skipped (1 total tests)
Failing tests:
Encountered 1 failing test in test/PreMarkets.t.sol:PreMarketsTest
[FAIL. Reason: Amount sent should be equal to the balance to refund: 14400000000000000 != 2014400000000000000] test_send_more_eth() (gas: 1262811)
Impact
If the user miscalculates the amount of ETH to send for listing or relisting their offer, the user loses the surplus amount.
Tools Used
Manual review et foundry
Recommendations
A check needs to be added to the code that rejects the transaction if the amount sent exceeds the necessary amount by more than 2 or 3 wei
function tillIn(address _accountAddress, address _tokenAddress, uint256 _amount, bool _isPointToken)
external
payable
onlyRelatedContracts(tadleFactory, _msgSender())
onlyInTokenWhiteList(_isPointToken, _tokenAddress)
{
/// @notice return if amount is 0
if (_amount == 0) {
return; //@audit check we could call it from Capital pool
}
address capitalPoolAddr = tadleFactory.relatedContracts(RelatedContractLibraries.CAPITAL_POOL);
if (capitalPoolAddr == address(0x0)) {
revert Errors.ContractIsNotDeployed();
}
if (_tokenAddress == wrappedNativeToken) {
/**
* @dev token is native token
* @notice check msg value
* @dev if msg value is less than _amount, revert
* @dev wrap native token and transfer to capital pool
*/
if (msg.value < _amount) {
revert Errors.NotEnoughMsgValue(msg.value, _amount);
}
+ if (msg.value > _amount + 3 ) {
+ revert("Too munch ETH");
+ }
IWrappedNativeToken(wrappedNativeToken).deposit{value: _amount}();
_safe_transfer(wrappedNativeToken, capitalPoolAddr, _amount);
} else {
/// @notice token is ERC20 token
_transfer(_tokenAddress, _accountAddress, capitalPoolAddr, _amount, capitalPoolAddr);
}
emit TillIn(_accountAddress, _tokenAddress, _amount, _isPointToken);
}